From 75e6c397331fde8cd9895ff761dbdcac6a7028a0 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 7 Jan 2010 18:36:28 -0800 Subject: [PATCH] Upgrade http-parser Fixes \n problem that psanford reported. --- deps/http_parser/http_parser.c | 56 ++++++++++++++++++---------------- deps/http_parser/http_parser.h | 36 +++++----------------- deps/http_parser/test.c | 46 +++++++++++++++++++--------- 3 files changed, 68 insertions(+), 70 deletions(-) diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index 8cd8d5ba98..9088af72c1 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -1,25 +1,25 @@ /* Copyright 2009 Ryan Dahl * * Some parts of this source file were taken from NGINX - * (src/http/ngx_http_parser.c) copyright (C) 2002-2009 Igor Sysoev. - * + * (src/http/ngx_http_parser.c) copyright (C) 2002-2009 Igor Sysoev. + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. + * IN THE SOFTWARE. */ #include #include @@ -148,7 +148,7 @@ static const uint32_t usual[] = { #define USUAL(c) (usual[c >> 5] & (1 << (c & 0x1f))) -enum state +enum state { s_dead = 1 /* important that this is > 0 */ , s_start_res @@ -198,7 +198,6 @@ enum state , s_header_almost_done , s_headers_almost_done - , s_headers_done , s_chunk_size_start , s_chunk_size @@ -212,7 +211,7 @@ enum state , s_body_identity_eof }; -enum header_states +enum header_states { h_general = 0 , h_C , h_CO @@ -236,10 +235,10 @@ enum header_states }; enum flags - { F_CHUNKED = 0x0001 - , F_CONNECTION_KEEP_ALIVE = 0x0002 - , F_CONNECTION_CLOSE = 0x0004 - , F_TRAILING = 0x0010 + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_TRAILING = 1 << 3 }; #define CR '\r' @@ -249,15 +248,15 @@ enum flags #if HTTP_PARSER_STRICT # define STRICT_CHECK(cond) if (cond) goto error # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) +#else +# define STRICT_CHECK(cond) # define NEW_MESSAGE() start_state #endif static inline size_t parse (http_parser *parser, const char *data, size_t len, int start_state) { - char c, ch; + char c, ch; const char *p, *pe; ssize_t to_read; @@ -298,7 +297,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state switch (ch) { case 'H': - state = s_res_H; + state = s_res_H; break; case CR: @@ -321,7 +320,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state state = s_res_HTT; break; - case s_res_HTT: + case s_res_HTT: STRICT_CHECK(ch != 'P'); state = s_res_HTTP; break; @@ -353,7 +352,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state if (parser->http_major > 999) goto error; break; } - + /* first digit of minor HTTP version */ case s_res_first_http_minor: if (ch < '0' || ch > '9') goto error; @@ -464,7 +463,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state if (strncmp(parser->buffer, "GET", 3) == 0) { parser->method = HTTP_GET; break; - } + } if (strncmp(parser->buffer, "PUT", 3) == 0) { parser->method = HTTP_PUT; @@ -706,7 +705,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state switch (ch) { case '?': - break; // XXX ignore extra '?' ... is this right? + break; // XXX ignore extra '?' ... is this right? case ' ': CALLBACK(url); state = s_req_http_start; @@ -931,8 +930,10 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state } if (ch == LF) { - state = s_headers_done; - break; + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + state = s_headers_almost_done; + goto headers_almost_done; } c = LOWER(ch); @@ -1089,7 +1090,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state header_state = h_general; break; - } + } switch (header_state) { case h_transfer_encoding: @@ -1138,8 +1139,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state if (ch == LF) { CALLBACK(header_value); - state = s_header_field_start; - break; + goto header_almost_done; } break; } @@ -1162,7 +1162,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state /* Transfer-Encoding: chunked */ case h_matching_transfer_encoding_chunked: index++; - if (index > sizeof(CHUNKED)-1 + if (index > sizeof(CHUNKED)-1 || c != CHUNKED[index]) { header_state = h_general; } else if (index == sizeof(CHUNKED)-2) { @@ -1206,6 +1206,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state } case s_header_almost_done: + header_almost_done: { STRICT_CHECK(ch != LF); @@ -1228,6 +1229,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state } case s_headers_almost_done: + headers_almost_done: { STRICT_CHECK(ch != LF); @@ -1241,7 +1243,7 @@ size_t parse (http_parser *parser, const char *data, size_t len, int start_state parser->body_read = 0; CALLBACK2(headers_complete); - + if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header */ state = s_chunk_size_start; diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index 9d14bbf5bf..5855e89405 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -1,22 +1,22 @@ /* Copyright 2009 Ryan Dahl - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. + * IN THE SOFTWARE. */ #ifndef http_parser_h #define http_parser_h @@ -30,8 +30,8 @@ extern "C" { #include /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ + * faster + */ #ifndef HTTP_PARSER_STRICT # define HTTP_PARSER_STRICT 1 #else @@ -129,34 +129,12 @@ void http_parser_init(http_parser *parser); size_t http_parse_requests(http_parser *parser, const char *data, size_t len); size_t http_parse_responses(http_parser *parser, const char *data, size_t len); /* Call this in the on_headers_complete or on_message_complete callback to - * determine if this will be the last message on the connection. + * determine if this will be the last message on the connection. * If you are the server, respond with the "Connection: close" header * if you are the client, close the connection. */ int http_should_keep_alive(http_parser *parser); -static inline const char * http_method_str (enum http_method method) -{ - switch (method) { - case HTTP_DELETE: return "DELETE"; - case HTTP_GET: return "GET"; - case HTTP_HEAD: return "HEAD"; - case HTTP_POST: return "POST"; - case HTTP_PUT: return "PUT"; - case HTTP_CONNECT: return "CONNECT"; - case HTTP_OPTIONS: return "OPTIONS"; - case HTTP_TRACE: return "TRACE"; - case HTTP_COPY: return "COPY"; - case HTTP_LOCK: return "LOCK"; - case HTTP_MKCOL: return "MKCOL"; - case HTTP_MOVE: return "MOVE"; - case HTTP_PROPFIND: return "PROPFIND"; - case HTTP_PROPPATCH: return "PROPPATCH"; - case HTTP_UNLOCK: return "UNLOCK"; - default: return (const char*)0; - } -} - #ifdef __cplusplus } #endif diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index f8cf268dc5..5f4c418f09 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -1,22 +1,22 @@ /* Copyright 2009 Ryan Dahl - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. + * IN THE SOFTWARE. */ #include "http_parser.h" #include @@ -69,7 +69,7 @@ inline size_t parse (enum message_type t, const char *buf, size_t len) { size_t nparsed; currently_parsing_eof = (len == 0); - nparsed = (t == REQUEST ? http_parse_requests(parser, buf, len) + nparsed = (t == REQUEST ? http_parse_requests(parser, buf, len) : http_parse_responses(parser, buf, len)); return nparsed; } @@ -88,7 +88,7 @@ const struct message requests[] = "Accept: */*\r\n" "\r\n" ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE + ,.message_complete_on_eof= FALSE ,.http_major= 1 ,.http_minor= 1 ,.method= HTTP_GET @@ -119,7 +119,7 @@ const struct message requests[] = "Connection: keep-alive\r\n" "\r\n" ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE + ,.message_complete_on_eof= FALSE ,.http_major= 1 ,.http_minor= 1 ,.method= HTTP_GET @@ -148,7 +148,7 @@ const struct message requests[] = "aaaaaaaaaaaaa:++++++++++\r\n" "\r\n" ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE + ,.message_complete_on_eof= FALSE ,.http_major= 1 ,.http_minor= 1 ,.method= HTTP_GET @@ -169,7 +169,7 @@ const struct message requests[] = ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" "\r\n" ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE + ,.message_complete_on_eof= FALSE ,.http_major= 1 ,.http_minor= 1 ,.method= HTTP_GET @@ -579,6 +579,27 @@ const struct message responses[] = } +#define NO_CARRIAGE_RET 5 +, {.name="no carriage ret" + ,.type= RESPONSE + ,.raw= "HTTP/1.1 200 OK\n" + "Content-Type: text/html; charset=utf-8\n" + "Connection: close\n" + "\n" + "these headers are from http://news.ycombinator.com/" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/html; charset=utf-8" } + , {"Connection", "close" } + } + ,.body= "these headers are from http://news.ycombinator.com/" + } + , {.name= NULL } /* sentinel */ }; @@ -688,7 +709,7 @@ message_complete_cb (http_parser *p) messages[num_messages].message_complete_cb_called = TRUE; messages[num_messages].message_complete_on_eof = currently_parsing_eof; - + num_messages++; return 0; } @@ -807,7 +828,7 @@ static void print_error (const char *raw, size_t error_location) { fprintf(stderr, "\n*** parse error ***\n\n"); - + int this_line = 0, char_len = 0; size_t i, j, len = strlen(raw), error_location_line = 0; for (i = 0; i < len; i++) { @@ -1049,9 +1070,6 @@ main (void) printf("sizeof(http_parser) = %d\n", sizeof(http_parser)); - assert(strcmp(http_method_str(HTTP_GET), "GET") == 0); - assert(strcmp(http_method_str(HTTP_CONNECT), "CONNECT") == 0); - for (request_count = 0; requests[request_count].name; request_count++); for (response_count = 0; responses[response_count].name; response_count++);