Hi
1.Initialization

   - Setting "http_parser_setting"
   - Init TCP for listening Port 80
   - Call uv_run
   
2.On "uv_connection_cb"

   - Call uv_tcp_init for Client handle
   - Call uv_accept
   - Call http_parser_init
   - Call uv_read_start
   
3.On "uv_read_cb"

   - Call http_parser_execute
   
4.On HTTP Parser "on_message_complete"

   - Call uv_queue_work
   
5.On uv_work_cb

   - Create new buffer and call uv_write HTTP Header with 
   "Transfer-Encoding: chunked" field and Data Part 1 (Free Buffer in 
   uv_write_cb callback)
   - Create new buffer and call uv_write for Data Part 2 (Free Buffer in 
   uv_write_cb callback)
   - Create new buffer and call uv_write for Data Part 3 (Free Buffer in 
   uv_write_cb callback)
   - Create new buffer and call uv_write for Data Part 4 (Free Buffer in 
   uv_write_cb callback)
   
6.On uv_after_work_cb

   - Call uv_close for Client handle
   
is this cycle right ?
Call uv_close for client handle in uv_after_work_cb callback is OK ? 

static uv_loop_t* _http_loop;
static uv_tcp_t _http_handle;
static http_parser_settings _http_parser_settings;


#define MAX_HTTP_HEADERS 20


/**
* Represents a single http header.
*/
typedef struct {
  const char* field;
  const char* value;
  size_t field_length;
  size_t value_length;
} HttpHeader;


/**
* Represents a http request with internal dependencies.
*
* - write request for sending the response
* - reference to tcp socket as write stream
* - instance of http_parser parser
* - string of the http url
* - string of the http method
* - amount of total header lines
* - http header array
* - body content
*/
typedef struct {
  uv_tcp_t handle;
  http_parser parser;
  char* url;
  char* method;
  int header_lines;
  HttpHeader headers[MAX_HTTP_HEADERS];
  const char* body;
} HttpRequest, *PHttpRequest;


typedef struct {
  uv_work_t work;
  uv_write_t write;
  HttpRequest* http_request;
  bool error;
} HttpResponse, *PHttpResponse;


typedef struct {
  vString buf;
  uv_tcp_t* handle;
  uv_write_t write;
}HttpWrite, *PHttpWrite;


void DoClose(uv_handle_t* handle) {
  free((HttpRequest*)handle->data);
}


void DoAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
  *buf = uv_buf_init((char*)malloc(suggested_size), suggested_size);
}


void DoRead(uv_stream_t* tcp, ssize_t nread, const uv_buf_t * buf) {
  ssize_t parsed;
  HttpRequest* http_request = (HttpRequest*)tcp->data;
  if (nread >= 0) {
    parsed = (ssize_t)http_parser_execute(&http_request->parser, &
_http_parser_settings, buf->base, nread);
    if (parsed < nread) {
      uv_close((uv_handle_t*)&http_request->handle, DoClose);
    }
  } else {
    if (nread != UV_EOF) {
      UVERR(nread, "read");
    }
    uv_close((uv_handle_t*)&http_request->handle, DoClose);
  }
  free(buf->base);
}


void DoAfterWrite(uv_write_t* req, int status) {
  CHECK(status, "write");
  if (!uv_is_closing((uv_handle_t*)req->handle)) {
    HttpResponse* http_response = (HttpResponse*)req->data;
    uv_close((uv_handle_t*)req->handle, DoClose);
    free(http_response);
  }
}


void DoConnect(uv_stream_t* server_handle, int status) {


  assert((uv_tcp_t*)server_handle == &_http_handle);
  CHECK(status, "Connect");


  HttpRequest* http_request = (HttpRequest*)malloc(sizeof(HttpRequest));


  uv_tcp_init(_http_loop, &http_request->handle);
  http_request->handle.data = http_request;
  http_request->parser.data = http_request;
  /* accept the created http_request */
  if (uv_accept(server_handle, (uv_stream_t*)&http_request->handle) == 0) {
    /* initialize our http parser */
    http_parser_init(&http_request->parser, HTTP_REQUEST);
    /* start reading from the tcp http_request socket */
    uv_read_start((uv_stream_t*)&http_request->handle, DoAlloc, DoRead);
  } else {
    /* we seem to have an error and quit */
    uv_close((uv_handle_t*)&http_request->handle, DoClose);
  }
}


int DoMessageBegin(http_parser* parser) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  http_request->header_lines = 0;
  return 0;
}


int DoURL(http_parser* parser, const char* at, size_t length) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  http_request->url = (char*)malloc(length + 1);
  strncpy((char*)http_request->url, at, length);
  http_request->url[length] = '\0';
  return 0;
}


int DoHeaderField(http_parser* parser, const char* at, size_t length) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  HttpHeader* header = &http_request->headers[http_request->header_lines];
  header->field = (char*)malloc(length + 1);
  header->field_length = length;
  strncpy((char*)header->field, at, length);
  return 0;
}


int DoHeaderValue(http_parser* parser, const char* at, size_t length) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  HttpHeader* header = &http_request->headers[http_request->header_lines];
  header->value_length = length;
  header->value = (char*)malloc(length + 1);
  strncpy((char*)header->value, at, length);
  ++http_request->header_lines;
  return 0;
}


int DoHeadersComplete(http_parser* parser) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  const char* method = http_method_str((enum http_method)parser->method);
  http_request->method = (char*)malloc(sizeof(method));
  strncpy(http_request->method, method, strlen(method));
  return 0;
}


int DoBody(http_parser* parser, const char* at, size_t length) {
  HttpRequest* http_request = (HttpRequest*)parser->data;
  http_request->body = (char*)malloc(length + 1);
  http_request->body = at;
  return 0;
}


void DoWorkWriteAfter(uv_write_t* req, int status) {
  CHECK(status, "write");
 PHttpWrite http_writer = (PHttpResponse)req->data;
 vStrFree(http_writer->buf);
 free(http_writer);
}


void DoWork(uv_work_t* req) {
  PHttpResponse http_response = (PHttpResponse)req->data;
  PHttpWrite http_write;
 uv_buf_t buf;


  // Write Part 1
  http_write = (PHttpWrite)malloc(sizeof(HttpWrite));
  http_write->handle = &http_response->http_request->handle;
  http_write->buf = vStrNew("");
  vStrAdd(http_write->buf, "HTTP/1.1 200 OK\r\nContent-Type: text/html; 
charset=UTF-8\r\nKeep-Alive: timeout=10, max=100\r\nConnection: 
keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n");
  vStrAdd(http_write->buf, "c\r\n<h1>go1</h1>\r\n");
  http_write->write.data = http_write;
  buf.base = http_write->buf;
  buf.len = vStrLen(http_write->buf);
  uv_write(&http_write->write,
           (uv_stream_t*)http_write->handle,
           &buf,
           1,
           DoWorkWriteAfter);


  // Write Part 2
  http_write = (PHttpWrite)malloc(sizeof(HttpWrite));
  http_write->handle = &http_response->http_request->handle;
  http_write->buf = vStrNew("");
  vStrAdd(http_write->buf, "c\r\n<h1>go2</h1>\r\n");
  http_write->write.data = http_write;
  buf.base = http_write->buf;
  buf.len = vStrLen(http_write->buf);
  uv_write(&http_write->write,
           (uv_stream_t*)http_write->handle,
           &buf,
           1,
           DoWorkWriteAfter);


  // Write Part 3
  http_write = (PHttpWrite)malloc(sizeof(HttpWrite));
  http_write->handle = &http_response->http_request->handle;
  http_write->buf = vStrNew("");
  vStrAdd(http_write->buf, "f\r\n<h1>go2.5</h1>\r\n");
  http_write->write.data = http_write;
  buf.base = http_write->buf;
  buf.len = vStrLen(http_write->buf);
  uv_write(&http_write->write,
           (uv_stream_t*)http_write->handle,
           &buf,
           1,
           DoWorkWriteAfter);


  // Write Part 4
  http_write = (PHttpWrite)malloc(sizeof(HttpWrite));
  http_write->handle = &http_response->http_request->handle;
  http_write->buf = vStrNew("");
  vStrAdd(http_write->buf, "c\r\n<h1>go3</h1>\r\n0\r\n\r\n");
  http_write->write.data = http_write;
  buf.base = http_write->buf;
  buf.len = vStrLen(http_write->buf);
  uv_write(&http_write->write,
           (uv_stream_t*)http_write->handle,
           &buf,
           1,
           DoWorkWriteAfter);
}


void DoAfterWork(uv_work_t* req, int status) {
  HttpResponse* http_response = (HttpResponse*)req->data;
  if (!uv_is_closing((uv_handle_t*)&http_response->http_request->handle)) {
    HttpResponse* http_response = (HttpResponse*)req->data;
    uv_close((uv_handle_t*)&http_response->http_request->handle, DoClose);
    free(http_response);
  }
}


int DoMessageComplete(http_parser* parser) {
  HttpResponse* http_response = (HttpResponse*)malloc(sizeof(HttpResponse));
  http_response->work.data = http_response;
  http_response->error = false;
  http_response->http_request = (HttpRequest*)parser->data;
  int status = uv_queue_work(_http_loop, &http_response->work, DoWork, 
DoAfterWork);
  CHECK(status, "uv_queue_work");
  assert(status == 0);
  return 0;
}


void vStartHttpServer(int Port) {
  int r;
  struct sockaddr_in address;


  _http_parser_settings.on_message_begin = DoMessageBegin;
  _http_parser_settings.on_url = DoURL;
  _http_parser_settings.on_header_field = DoHeaderField;
  _http_parser_settings.on_header_value = DoHeaderValue;
  _http_parser_settings.on_headers_complete = DoHeadersComplete;
  _http_parser_settings.on_body = DoBody;
  _http_parser_settings.on_message_complete = DoMessageComplete;
  
  _http_loop = uv_default_loop();
  r = uv_tcp_init(_http_loop, &_http_handle);
  CHECK(r, "TCP Init");


  r = uv_tcp_keepalive(&_http_handle, 1, 60);
  CHECK(r, "TCP KeepAlive");


  r = uv_ip4_addr("0.0.0.0", Port, &address);
  CHECK(r, "IPv4 Address");


  r = uv_tcp_bind(&_http_handle, (const struct sockaddr*)&address, 0);
  CHECK(r, "TCP Bind");


  r = uv_listen((uv_stream_t*)&_http_handle, 128, DoConnect);
  CHECK(r, "Listen");


  async_write = (uv_async_t*)malloc(sizeof(uv_async_t));
  uv_async_init(_http_loop, async_write, DoWorkWrite);


  LOGF("Listening on port %d", Port);
  uv_run(_http_loop, UV_RUN_DEFAULT);
}

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to