On Sat, Nov 10, 2012 at 3:44 PM, Dhruv Matani <
dhru...@gmail.com> wrote:
> Hello,
>
> I'm trying to implement a custom http/1.1 in-process web server using libuv
> & http-parser and wanted to know the best way to handle pipelined requests.
>
> Currently, I am calling http_parser_execute() every time the on_read
> callback is fired, but I realize that the data in the on_read callback might
> include 2 or more HTTP requests. How do things work out in that case? Is the
> on_message_complete callback called synchronously before the on_read
> callback returns? If so, then does the http parser buffer any data itself in
> case of paused requests (see below)?
No, http_parser never buffers and yes, the on_message_complete
callback is called synchronously. In fact, all callbacks are.
It's something of an API design flaw. Callbacks only make sense when
invoked asynchronously. If http_parser used return values instead of
callbacks, we wouldn't have a need for http_parser_pause(). But I
digress...
> Subsequently, in the on_message_complete callback, I call uv_read_stop(),
> which supposedly stops invoking callbacks. However, the thing I am unable to
> understand is what happens when data for multiple HTTP requests is passed to
> the http parser since I reinitialize the parser using http_parser_init() in
> the after_write callback. I am pretty sure that there can be cases where the
> parser has parsed 2 requests, but the on_message_complete handler has been
> invoked for just 1 (since I return 1 from that callback), and once I
> re-initialize the parser, the 2nd request is lost.
You check the 'bytes parsed' count that http_parser_execute() returns.
If it's less than the size of the input but there's no error, the
buffer contains a message boundary. The basic logic looks something
like this:
void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf)
{
const http_parser_settings* settings = ...;
http_parser* parser = ...;
const char* data = buf.data;
size_t len = buf.len;
if (nread == -1) {
// handle read error / EOF
return;
}
for (;;) {
size_t nparsed = http_parser_execute(parser, settings, data, len);
if (nparsed == len)
return; // ok
if (parser->http_errno != HPE_OK) {
// handle parse error
return;
}
// buffer contains two messages, we've parsed
// the first one, now start on the next one
http_parser_init(parser, HTTP_BOTH);
data += nparsed;
len -= nparsed;