From 2fca40e44f1a5d1f7f5285649760eb5ab7c96935 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 25 May 2010 18:41:31 -0700 Subject: [PATCH] Upgrade http-parser --- deps/http_parser/http_parser.c | 42 ++++++++++++++++++++++++++-------- deps/http_parser/http_parser.h | 8 ++++++- deps/http_parser/test.c | 4 ++-- src/node_http_parser.cc | 4 ++-- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index 7823dd0e87..8ecc94c2ee 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -37,8 +37,8 @@ #define CALLBACK2(FOR) \ do { \ - if (settings.on_##FOR) { \ - if (0 != settings.on_##FOR(parser)) return (p - data); \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser)) return (p - data); \ } \ } while (0) @@ -55,8 +55,8 @@ do { \ if (parser->FOR##_mark) { \ parser->FOR##_size += p - parser->FOR##_mark; \ if (parser->FOR##_size > MAX_FIELD_SIZE) return (p - data); \ - if (settings.on_##FOR) { \ - if (0 != settings.on_##FOR(parser, \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser, \ parser->FOR##_mark, \ p - parser->FOR##_mark)) \ { \ @@ -232,6 +232,7 @@ enum flags , F_CONNECTION_CLOSE = 1 << 2 , F_TRAILING = 1 << 3 , F_UPGRADE = 1 << 4 + , F_SKIPBODY = 1 << 5 }; @@ -282,7 +283,7 @@ enum flags size_t http_parser_execute (http_parser *parser, - http_parser_settings settings, + const http_parser_settings *settings, const char *data, size_t len) { @@ -1327,7 +1328,25 @@ size_t http_parser_execute (http_parser *parser, if (parser->flags & F_UPGRADE) parser->upgrade = 1; - CALLBACK2(headers_complete); + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of recieving a response to a HEAD + * request. + */ + if (settings->on_headers_complete) { + switch (settings->on_headers_complete(parser)) { + case 0: + break; + + case 1: + parser->flags |= F_SKIPBODY; + break; + + default: + return p - data; /* Error */ + } + } // Exit, the rest of the connect is in a different protocol. if (parser->flags & F_UPGRADE) { @@ -1335,7 +1354,10 @@ size_t http_parser_execute (http_parser *parser, return (p - data); } - if (parser->flags & F_CHUNKED) { + if (parser->flags & F_SKIPBODY) { + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + } else if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header */ state = s_chunk_size_start; } else { @@ -1364,7 +1386,7 @@ size_t http_parser_execute (http_parser *parser, case s_body_identity: to_read = MIN(pe - p, (ssize_t)(parser->content_length - parser->body_read)); if (to_read > 0) { - if (settings.on_body) settings.on_body(parser, p, to_read); + if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; parser->body_read += to_read; if (parser->body_read == parser->content_length) { @@ -1378,7 +1400,7 @@ size_t http_parser_execute (http_parser *parser, case s_body_identity_eof: to_read = pe - p; if (to_read > 0) { - if (settings.on_body) settings.on_body(parser, p, to_read); + if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; parser->body_read += to_read; } @@ -1451,7 +1473,7 @@ size_t http_parser_execute (http_parser *parser, to_read = MIN(pe - p, (ssize_t)(parser->content_length)); if (to_read > 0) { - if (settings.on_body) settings.on_body(parser, p, to_read); + if (settings->on_body) settings->on_body(parser, p, to_read); p += to_read - 1; } diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index f367872a66..977ecdfa00 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -49,6 +49,12 @@ typedef struct http_parser_settings http_parser_settings; /* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * + * The one exception is on_headers_complete. In a HTTP_RESPONSE parser + * returning '1' from on_headers_complete will tell the parser that it + * should not expect a body. This is used when receiving a response to a + * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: + * chunked' headers that indicate the presence of a body. + * * http_data_cb does not return data chunks. It will be call arbitrarally * many times for each string. E.G. you might get 10 callbacks for "on_path" * each providing just a few characters more data. @@ -149,7 +155,7 @@ void http_parser_init(http_parser *parser, enum http_parser_type type); size_t http_parser_execute(http_parser *parser, - http_parser_settings settings, + const http_parser_settings *settings, const char *data, size_t len); diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index 9accabdc1d..03a98ff2a3 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -898,7 +898,7 @@ inline size_t parse (const char *buf, size_t len) { size_t nparsed; currently_parsing_eof = (len == 0); - nparsed = http_parser_execute(parser, settings, buf, len); + nparsed = http_parser_execute(parser, &settings, buf, len); return nparsed; } @@ -906,7 +906,7 @@ inline size_t parse_count_body (const char *buf, size_t len) { size_t nparsed; currently_parsing_eof = (len == 0); - nparsed = http_parser_execute(parser, settings_count_body, buf, len); + nparsed = http_parser_execute(parser, &settings_count_body, buf, len); return nparsed; } diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 0f8d1b5e4b..3473686941 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -245,7 +245,7 @@ class Parser : public ObjectWrap { parser->got_exception_ = false; size_t nparsed = - http_parser_execute(&parser->parser_, settings, buffer->data()+off, len); + http_parser_execute(&parser->parser_, &settings, buffer->data()+off, len); // Unassign the 'buffer_' variable assert(parser->buffer_); @@ -275,7 +275,7 @@ class Parser : public ObjectWrap { assert(!parser->buffer_); parser->got_exception_ = false; - http_parser_execute(&(parser->parser_), settings, NULL, 0); + http_parser_execute(&(parser->parser_), &settings, NULL, 0); if (parser->got_exception_) return Local();