Exemple #1
0
static int new_writer(lua_State* L)
{
	void* handle;
	writer_api api; 	
	
	int type = lua_type(L, 1);
	switch(type)
	{
		case LUA_TUSERDATA:	
			handle = luaL_testudata(L, 1, OUT_MEMORY_STREAM);
			if(handle)
			{
				api.write = (stream_write_t)&outmemory_stream_write;
				api.flush = (stream_flush_t)&outmemory_stream_flush;
				api.close = (stream_close_t)&outmemory_stream_close;
				break;
			}
			
			handle = luaL_testudata(L, 1, LUA_FILEHANDLE);
			if(handle)
			{
				luaL_Stream* stream = handle;
				handle	  = stream->f;
				api.write = (stream_write_t)&fwrite;
				api.flush = (stream_flush_t)&fflush;
				api.close = (stream_close_t)&fclose;				
				break;
			}

			luaL_error(L, "Inputstream expected");	
		case LUA_TTABLE: 
			luaL_error(L, "Cannot yet use lua table writers");
		break;
		default:
			luaL_error(L, "Inputstream expected");
			break;
	}
		
	//First get the stream data.
	char* udata	= create_userdata(L, sizeof(writer_t) + 4096, WRITER_META_TABLE);
	writer_t* writer = (writer_t*)udata;
	uint8_t* buffer = udata + sizeof(writer_t);
	*writer = writer_create(handle, buffer, 4096, api);
		
	return 1;
}
Exemple #2
0
int client_create(Client *client, const char *name, IO *io,
                  uint32_t authentication_nonce,
                  ClientDestroyDoneFunction destroy_done) {
    log_debug("Creating client from %s (handle: %d)", io->type, io->handle);

    string_copy(client->name, sizeof(client->name), name);

    client->io = io;
    client->disconnected = false;
    client->request_used = 0;
    client->request_header_checked = false;
    client->pending_request_count = 0;
    client->authentication_state = CLIENT_AUTHENTICATION_STATE_DISABLED;
    client->authentication_nonce = authentication_nonce;
    client->destroy_done = destroy_done;

    if (config_get_option_value("authentication.secret")->string != NULL) {
        client->authentication_state = CLIENT_AUTHENTICATION_STATE_ENABLED;
    }

    node_reset(&client->pending_request_sentinel);

    // create response writer
    if (writer_create(&client->response_writer, client->io,
                      "response", packet_get_response_signature,
                      "client", client_get_recipient_signature,
                      client_recipient_disconnect, client) < 0) {
        log_error("Could not create response writer: %s (%d)",
                  get_errno_name(errno), errno);

        return -1;
    }

    // add I/O object as event source
    return event_add_source(client->io->handle, EVENT_SOURCE_TYPE_GENERIC,
                            EVENT_READ, client_handle_read, client);
}
Exemple #3
0
/*(*** http_connection_handler */
void http_connection_handler(void *svd, connection *cn, short events)
{
  server *sv;
  http *ht;

  sv = svd;
  ht = cn->cn_data;

  log_msg(sv->sv_log, LOG_DEBUG, "Event mask on FD %d is 0x%04x", cn->cn_fd, events);
  if(events & POLLERR) {
    demux_delete_connection(sv->sv_demux, cn);
    log_msg(sv->sv_log, LOG_WARN, "Deleting connection on FD %d", cn->cn_fd);
    return;
  }
  if(events & POLLIN) {
    int fd;
    int r;
    char buf[PARAM_READ_BUFFER_SIZE];

    fd = cn->cn_fd;
    r = read(fd, buf, sizeof(buf));
    if(r < 0) {
     log_msg(sv->sv_log, LOG_DEBUG, "Read error on FD %d (%s)", cn->cn_fd, strerror(errno));
    } else {
      if(r > 0) {
        log_msg(sv->sv_log, LOG_DEBUG, "Read %d bytes on FD %d", r, cn->cn_fd);
        http_add_bytes(ht, buf, r);
      } else {
       log_msg(sv->sv_log, LOG_INFO, "Connection closed on FD %d", cn->cn_fd);
       if(close(fd) < 0) {
         log_msg(sv->sv_log, LOG_ERROR, "Error closing FD %d (%s)", cn->cn_fd, strerror(errno));
       }
       demux_delete_connection(sv->sv_demux, cn);
      }
    }
  }
  if(events & POLLOUT) {
    switch(ht->ht_state) {
      case HTTP_SERVING:

      case HTTP_RESPONDING:
      case HTTP_RESPONSE_ONLY:
        switch(writer_work(ht->ht_writer, cn->cn_fd)) {
          case WRITER_WORKING:
            break;
          case WRITER_DONE:
            switch(ht->ht_state) {
              case HTTP_RESPONDING:
                ht->ht_state = HTTP_SERVING;
                writer_delete(ht->ht_writer);
                ht->ht_writer = writer_create(ht->ht_resource->rs_start, ht->ht_resource->rs_length, 0);
                break;
              case HTTP_RESPONSE_ONLY:
              default:
                demux_delete_connection(sv->sv_demux, cn);
                break;
            }
            break;
          case WRITER_ERROR:
            log_msg(sv->sv_log, LOG_ERROR, "Error writing to FD %d (%s)", cn->cn_fd, strerror(errno));
            demux_delete_connection(sv->sv_demux, cn);
            break;
        }
        break;
      default:
        break;
    }
  }
}
Exemple #4
0
/*(*** http_eater */
void http_eater(void *htd, char *p, int m)
{
  http *ht;
  server *sv;

  ht = htd;
  sv = ht->ht_server;

#if DEBUG
  {
    char buf[75];
    int i;
    for(i = 0; i < m && i < sizeof(buf) - 1; i ++) {
      buf[i] = isprint(p[i]) ? p[i] : '?';
    }
    buf[i] = 0;
    log_msg(sv->sv_log, LOG_DEBUG, "Got line [%s]", buf);
  }
#endif

reswitch:
  switch(ht->ht_state) {
    case HTTP_REQUEST:
      /* XXX: parse request */
      {
        if(!http_parse_request_line(&ht->ht_hrl, p, m)) goto violation; /* MEMORY LEAK */

        log_msg(sv->sv_log,
                LOG_DEBUG,
                "Method is [%s] URI is [%s] major is [%s] minor is [%s]",
                ht->ht_hrl.hrl_method,
                ht->ht_hrl.hrl_uri,
                ht->ht_hrl.hrl_major,
                ht->ht_hrl.hrl_minor);

        ht->ht_state = HTTP_HEADER;
      }
      break;
    case HTTP_HEADER:
      if(m) {
        /* Non-empty header lines */
        http_release_header_line(&ht->ht_hhl);
        if(http_parse_header_line(&ht->ht_hhl, p, m)) {
          /* This is a nice header */
          ht->ht_state = HTTP_MORE_HEADERS;
        } else goto violation;
      } else {
        /* Empty line : headers finished */
        if(!http_process_header(ht)) goto violation;
        ht->ht_state = HTTP_BUILD_RESPONSE;
        goto reswitch;
      }
      break;
    case HTTP_MORE_HEADERS:
      if(m) {
        if(http_parse_header_continuation_line(&ht->ht_hhl, p, m))
          break; /* Stay in this state. */
        else {
          /* Not a continuation header. */
          /* Post current header. */
          if(!http_process_header(ht)) goto violation;
          ht->ht_state = HTTP_HEADER;
          goto reswitch;
        }
      } else {
        /* Empty line : headers finished */
        if(!http_process_header(ht)) goto violation;
        ht->ht_state = HTTP_BUILD_RESPONSE;
        goto reswitch;
      }
      break;
    case HTTP_BUILD_RESPONSE:
      /* Build response */
      {
        char *response;
        int response_length;
        char *content_type;
        size_t content_length;
        resource *rs;
        char *fn;

        if(!strcmp(ht->ht_hrl.hrl_method, "GET")) {
          fn = http_uri_to_filename(ht, ht->ht_hrl.hrl_uri);

          rs = resource_obtain(fn);
          if(!rs) {
            log_msg(sv->sv_log, LOG_ERROR, "Can't obtain %s (%s)", fn, strerror(errno));

            response_length =
              xasprintf(
                &response,
                "HTTP/1.1 404 Not Found\r\n"
                  "Content-Type: text/html\r\n"
                  "Connection: close\r\n"
                  "\r\n"
                  "<html>"
                  "<head><title>404 Not Found</title></head><body>"
                  "Unable to find resource %s (%s)."
                  "</body></html>", 
                fn,
                strerror(errno));
            ht->ht_state = HTTP_RESPONSE_ONLY;
          } else {
            content_type = rs->rs_mime_type;
            content_length = rs->rs_length;

            if(ht->ht_writer) { 
              writer_delete(ht->ht_writer);
              ht->ht_writer = 0;
            }
            ht->ht_resource = rs;

            response_length =
              xasprintf(
                &response,
                "HTTP/1.1 200 OK\r\n"
                  "Content-Type: %s\r\n"
                  "Connection: close\r\n"
                  "Content-Length: %d\r\n"
                  "\r\n",
                content_type,
                content_length);
            ht->ht_state = HTTP_RESPONDING;
          }
          xfree(fn);
        } else {
          response_length =
            xasprintf(
              &response,
              "HTTP/1.1 501 Not implemented\r\n"
                "Content-Type: text/html\r\n"
                "Connection: close\r\n"
                "\r\n"
                "<html>"
                "<head><title>501 Not implemented</title></head><body>"
                "Method %s is not supported by this server."
                "</body></html>", 
              ht->ht_hrl.hrl_method);
          ht->ht_state = HTTP_RESPONSE_ONLY;
        }
        ht->ht_response = response;
        ht->ht_writer = writer_create(response, response_length, response);
        demux_set_event_mask(sv->sv_demux, ht->ht_connection, POLLOUT); /* Stop reading */
      }
      break;
    case HTTP_RESPONSE_ONLY:
    case HTTP_RESPONDING:
      break;
    case HTTP_SERVING:
      break;
  }
  return;

violation:
  log_msg(sv->sv_log, LOG_ERROR, "HTTP protocol violation");
  demux_delete_connection(sv->sv_demux, ht->ht_connection);
  return;
}