From 83d9ee1fd18b07d42f6e8dc8da3234d35db7dcfa Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 20 Feb 2015 19:51:41 +0900 Subject: [PATCH] Update http-parser --- third-party/http-parser/AUTHORS | 15 +++++- third-party/http-parser/http_parser.c | 22 ++++++--- third-party/http-parser/http_parser.h | 13 +++-- third-party/http-parser/test.c | 68 +++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/third-party/http-parser/AUTHORS b/third-party/http-parser/AUTHORS index 51b53b12..29cdbb16 100644 --- a/third-party/http-parser/AUTHORS +++ b/third-party/http-parser/AUTHORS @@ -39,12 +39,25 @@ BogDan Vatra Peter Faiman Corey Richardson Tóth Tamás -Patrik Stutz Cam Swords Chris Dickinson Uli Köhler Charlie Somerville +Patrik Stutz Fedor Indutny runner Alexis Campailla David Wragg +Vinnie Falco +Alex Butum +Rex Feng +Alex Kocharin +Mark Koopman +Helge Heß +Alexis La Goutte +George Miroshnykov +Maciej Małecki +Marc O'Morain +Jeff Pinner +Timothy J Fontaine +Akagi201 diff --git a/third-party/http-parser/http_parser.c b/third-party/http-parser/http_parser.c index 23077d1d..aa6310f7 100644 --- a/third-party/http-parser/http_parser.c +++ b/third-party/http-parser/http_parser.c @@ -57,15 +57,14 @@ do { \ } while(0) #define CURRENT_STATE() p_state -#define UPDATE_STATE(V) p_state = (V); +#define UPDATE_STATE(V) p_state = (enum state) (V); #define RETURN(V) \ do { \ parser->state = CURRENT_STATE(); \ return (V); \ } while (0); #define REEXECUTE() \ - --p; \ - break; + goto reexecute; \ #ifdef __GNUC__ @@ -637,7 +636,7 @@ size_t http_parser_execute (http_parser *parser, const char *url_mark = 0; const char *body_mark = 0; const char *status_mark = 0; - enum state p_state = parser->state; + enum state p_state = (enum state) parser->state; /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { @@ -697,6 +696,7 @@ size_t http_parser_execute (http_parser *parser, if (PARSING_HEADER(CURRENT_STATE())) COUNT_HEADER_SIZE(1); +reexecute: switch (CURRENT_STATE()) { case s_dead: @@ -1518,7 +1518,7 @@ size_t http_parser_execute (http_parser *parser, case s_header_value: { const char* start = p; - enum header_states h_state = parser->header_state; + enum header_states h_state = (enum header_states) parser->header_state; for (; p != data + len; p++) { ch = *p; if (ch == CR) { @@ -1547,8 +1547,8 @@ size_t http_parser_execute (http_parser *parser, limit = MIN(limit, HTTP_MAX_HEADER_SIZE); - p_cr = memchr(p, CR, limit); - p_lf = memchr(p, LF, limit); + p_cr = (const char*) memchr(p, CR, limit); + p_lf = (const char*) memchr(p, LF, limit); if (p_cr != NULL) { if (p_lf != NULL && p_cr >= p_lf) p = p_lf; @@ -1618,6 +1618,8 @@ size_t http_parser_execute (http_parser *parser, h_state = h_matching_connection_upgrade; } else if (STRICT_TOKEN(c)) { h_state = h_matching_connection_token; + } else if (c == ' ' || c == '\t') { + /* Skip lws */ } else { h_state = h_general; } @@ -2134,6 +2136,12 @@ http_parser_init (http_parser *parser, enum http_parser_type t) parser->http_errno = HPE_OK; } +void +http_parser_settings_init(http_parser_settings *settings) +{ + memset(settings, 0, sizeof(*settings)); +} + const char * http_errno_name(enum http_errno err) { assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); diff --git a/third-party/http-parser/http_parser.h b/third-party/http-parser/http_parser.h index 936cddb1..99c533ae 100644 --- a/third-party/http-parser/http_parser.h +++ b/third-party/http-parser/http_parser.h @@ -26,8 +26,8 @@ extern "C" { /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 3 -#define HTTP_PARSER_VERSION_PATCH 0 +#define HTTP_PARSER_VERSION_MINOR 4 +#define HTTP_PARSER_VERSION_PATCH 2 #include #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) @@ -204,8 +204,8 @@ enum http_errno { struct http_parser { /** PRIVATE **/ unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 8; /* enum state from http_parser.c */ + unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */ + unsigned int state : 7; /* enum state from http_parser.c */ unsigned int header_state : 8; /* enum header_state from http_parser.c */ unsigned int index : 8; /* index into current matcher */ @@ -288,6 +288,11 @@ unsigned long http_parser_version(void); void http_parser_init(http_parser *parser, enum http_parser_type type); +/* Initialize http_parser_settings members to 0 + */ +void http_parser_settings_init(http_parser_settings *settings); + + /* Executes the parser. Returns number of parsed bytes. Sets * `parser->http_errno` on error. */ size_t http_parser_execute(http_parser *parser, diff --git a/third-party/http-parser/test.c b/third-party/http-parser/test.c index 6c45d59d..58c1955a 100644 --- a/third-party/http-parser/test.c +++ b/third-party/http-parser/test.c @@ -986,6 +986,55 @@ const struct message requests[] = ,.body= "" } +#define CONNECTION_MULTI_LWS 36 +, {.name = "multiple connection header values with folding and lws" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Connection: keep-alive, upgrade\r\n" + "Upgrade: WebSocket\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 2 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Connection", "keep-alive, upgrade" } + , { "Upgrade", "WebSocket" } + } + ,.body= "" + } + +#define CONNECTION_MULTI_LWS_CRLF 37 +, {.name = "multiple connection header values with folding and lws" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Connection: keep-alive, \r\n upgrade\r\n" + "Upgrade: WebSocket\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 2 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Connection", "keep-alive, upgrade" } + , { "Upgrade", "WebSocket" } + } + ,.body= "" + } , {.name= NULL } /* sentinel */ }; @@ -2995,6 +3044,22 @@ test_header_overflow_error (int req) abort(); } + +void +test_header_nread_value () +{ + http_parser parser; + http_parser_init(&parser, HTTP_REQUEST); + size_t parsed; + const char *buf; + buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n"; + parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf)); + assert(parsed == strlen(buf)); + + assert(parser.nread == strlen(buf)); +} + + static void test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) { @@ -3361,6 +3426,9 @@ main (void) test_parse_url(); test_method_str(); + //// NREAD + test_header_nread_value(); + //// OVERFLOW CONDITIONS test_header_overflow_error(HTTP_REQUEST);