diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-06-03 14:12:14 +0200 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-06-03 14:12:14 +0200 |
commit | 4956e3c0a25992bfa454a43c377ac120e0ff7727 (patch) | |
tree | fb6a746861bce297024c1a2da701e49a9a9c6efc /deps/http_parser | |
parent | 0cb4484d433ce0dc27015f18159c2e9d0c601081 (diff) | |
download | android-node-v8-4956e3c0a25992bfa454a43c377ac120e0ff7727.tar.gz android-node-v8-4956e3c0a25992bfa454a43c377ac120e0ff7727.tar.bz2 android-node-v8-4956e3c0a25992bfa454a43c377ac120e0ff7727.zip |
Upgrade http-parser to eee60127c0df551be085cc8e7983e36d7700d885
Diffstat (limited to 'deps/http_parser')
-rw-r--r-- | deps/http_parser/.gitignore | 1 | ||||
-rw-r--r-- | deps/http_parser/LICENSE-MIT | 6 | ||||
-rw-r--r-- | deps/http_parser/Makefile | 13 | ||||
-rw-r--r-- | deps/http_parser/http_parser.c | 118 | ||||
-rw-r--r-- | deps/http_parser/http_parser.h | 21 | ||||
-rw-r--r-- | deps/http_parser/test.c | 141 |
6 files changed, 238 insertions, 62 deletions
diff --git a/deps/http_parser/.gitignore b/deps/http_parser/.gitignore index 73fe6a4cef..04b7a1fee6 100644 --- a/deps/http_parser/.gitignore +++ b/deps/http_parser/.gitignore @@ -2,3 +2,4 @@ tags *.o test test_g +test_fast diff --git a/deps/http_parser/LICENSE-MIT b/deps/http_parser/LICENSE-MIT index f30a31de94..58010b3889 100644 --- a/deps/http_parser/LICENSE-MIT +++ b/deps/http_parser/LICENSE-MIT @@ -1,4 +1,8 @@ -Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org> +http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright +Igor Sysoev. + +Additional changes are licensed under the same terms as NGINX and +copyright Joyent, Inc. and other Node contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to diff --git a/deps/http_parser/Makefile b/deps/http_parser/Makefile index 2b945c16b0..4eceeaae75 100644 --- a/deps/http_parser/Makefile +++ b/deps/http_parser/Makefile @@ -1,11 +1,14 @@ -OPT_DEBUG=-O0 -g -Wall -Wextra -Werror -I. -OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I. +CPPFLAGS?=-Wall -Wextra -Werror -I. +OPT_DEBUG=$(CPPFLAGS) -O0 -g -DHTTP_PARSER_STRICT=1 +OPT_FAST=$(CPPFLAGS) -O3 -DHTTP_PARSER_STRICT=0 CC?=gcc +AR?=ar -test: test_g +test: test_g test_fast ./test_g + ./test_fast test_g: http_parser_g.o test_g.o $(CC) $(OPT_DEBUG) http_parser_g.o test_g.o -o $@ @@ -31,11 +34,13 @@ test_fast: http_parser.o test.c http_parser.h test-run-timed: test_fast while(true) do time ./test_fast > /dev/null; done +package: http_parser.o + $(AR) rcs libhttp_parser.a http_parser.o tags: http_parser.c http_parser.h test.c ctags $^ clean: - rm -f *.o test test_fast test_g http_parser.tar tags + rm -f *.o *.a test test_fast test_g http_parser.tar tags .PHONY: clean package test-run test-run-timed test-valgrind diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index 9c5640f6d4..1453d411b0 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -1,4 +1,7 @@ -/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org> +/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev + * + * Additional changes are licensed under the same terms as NGINX and + * copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -97,6 +100,7 @@ static const char *method_strings[] = , "NOTIFY" , "SUBSCRIBE" , "UNSUBSCRIBE" + , "PATCH" }; @@ -186,7 +190,7 @@ static const uint8_t normal_url_char[256] = { /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 1, 1, 1, 1, 1, 1, 1, 1, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1, 1, 1, 1, 1, 1, 1, 0 }; + 1, 1, 1, 1, 1, 1, 1, 0, }; enum state @@ -240,15 +244,17 @@ enum state , s_header_almost_done + , s_chunk_size_start + , s_chunk_size + , s_chunk_parameters + , s_chunk_size_almost_done + , s_headers_almost_done /* Important: 's_headers_almost_done' must be the last 'header' state. All * states beyond this must be 'body' states. It is used for overflow * checking. See the PARSING_HEADER() macro. */ - , s_chunk_size_start - , s_chunk_size - , s_chunk_size_almost_done - , s_chunk_parameters + , s_chunk_data , s_chunk_data_almost_done , s_chunk_data_done @@ -258,7 +264,7 @@ enum state }; -#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING)) +#define PARSING_HEADER(state) (state <= s_headers_almost_done) enum header_states @@ -288,20 +294,24 @@ enum header_states }; -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; +/* Macros for character classes; depends on strict-mode */ +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) +#define TOKEN(c) (tokens[(unsigned char)c]) +#define IS_ALPHA(c) ((c) >= 'a' && (c) <= 'z') +#define IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) - -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define TOKEN(c) tokens[(unsigned char)c] +#if HTTP_PARSER_STRICT +#define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)]) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') +#else +#define IS_URL_CHAR(c) \ + (normal_url_char[(unsigned char) (c)] || ((c) & 0x80)) +#define IS_HOST_CHAR(c) \ + (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') +#endif #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) @@ -478,7 +488,7 @@ size_t http_parser_execute (http_parser *parser, break; } - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_major *= 10; parser->http_major += ch - '0'; @@ -489,7 +499,7 @@ size_t http_parser_execute (http_parser *parser, /* first digit of minor HTTP version */ case s_res_first_http_minor: - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_minor = ch - '0'; state = s_res_http_minor; break; @@ -502,7 +512,7 @@ size_t http_parser_execute (http_parser *parser, break; } - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_minor *= 10; parser->http_minor += ch - '0'; @@ -513,7 +523,7 @@ size_t http_parser_execute (http_parser *parser, case s_res_first_status_code: { - if (ch < '0' || ch > '9') { + if (!IS_NUM(ch)) { if (ch == ' ') { break; } @@ -526,7 +536,7 @@ size_t http_parser_execute (http_parser *parser, case s_res_status_code: { - if (ch < '0' || ch > '9') { + if (!IS_NUM(ch)) { switch (ch) { case ' ': state = s_res_status; @@ -578,7 +588,7 @@ size_t http_parser_execute (http_parser *parser, CALLBACK2(message_begin); - if (ch < 'A' || 'Z' < ch) goto error; + if (!IS_ALPHA(LOWER(ch))) goto error; start_req_method_assign: parser->method = (enum http_method) 0; @@ -592,7 +602,9 @@ size_t http_parser_execute (http_parser *parser, case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; case 'N': parser->method = HTTP_NOTIFY; break; case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break; + case 'P': parser->method = HTTP_POST; + /* or PROPFIND or PROPPATCH or PUT or PATCH */ + break; case 'R': parser->method = HTTP_REPORT; break; case 'S': parser->method = HTTP_SUBSCRIBE; break; case 'T': parser->method = HTTP_TRACE; break; @@ -633,6 +645,8 @@ size_t http_parser_execute (http_parser *parser, parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') { parser->method = HTTP_PUT; + } else if (index == 1 && parser->method == HTTP_POST && ch == 'A') { + parser->method = HTTP_PATCH; } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') { parser->method = HTTP_UNSUBSCRIBE; } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { @@ -657,9 +671,13 @@ size_t http_parser_execute (http_parser *parser, c = LOWER(ch); - if (c >= 'a' && c <= 'z') { + /* Proxied requests are followed by scheme of an absolute URI (alpha). + * CONNECT is followed by a hostname, which begins with alphanum. + * All other methods are followed by '/' or '*' (handled above). + */ + if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) { MARK(url); - state = s_req_schema; + state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema; break; } @@ -670,17 +688,11 @@ size_t http_parser_execute (http_parser *parser, { c = LOWER(ch); - if (c >= 'a' && c <= 'z') break; + if (IS_ALPHA(c)) break; if (ch == ':') { state = s_req_schema_slash; break; - } else if (ch == '.') { - state = s_req_host; - break; - } else if ('0' <= ch && ch <= '9') { - state = s_req_host; - break; } goto error; @@ -699,8 +711,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_host: { c = LOWER(ch); - if (c >= 'a' && c <= 'z') break; - if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break; + if (IS_HOST_CHAR(ch)) break; switch (ch) { case ':': state = s_req_port; @@ -717,6 +728,9 @@ size_t http_parser_execute (http_parser *parser, CALLBACK(url); state = s_req_http_start; break; + case '?': + state = s_req_query_string_start; + break; default: goto error; } @@ -725,7 +739,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_port: { - if (ch >= '0' && ch <= '9') break; + if (IS_NUM(ch)) break; switch (ch) { case '/': MARK(path); @@ -739,6 +753,9 @@ size_t http_parser_execute (http_parser *parser, CALLBACK(url); state = s_req_http_start; break; + case '?': + state = s_req_query_string_start; + break; default: goto error; } @@ -747,7 +764,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_path: { - if (normal_url_char[(unsigned char)ch]) break; + if (IS_URL_CHAR(ch)) break; switch (ch) { case ' ': @@ -785,7 +802,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_query_string_start: { - if (normal_url_char[(unsigned char)ch]) { + if (IS_URL_CHAR(ch)) { MARK(query_string); state = s_req_query_string; break; @@ -821,7 +838,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_query_string: { - if (normal_url_char[(unsigned char)ch]) break; + if (IS_URL_CHAR(ch)) break; switch (ch) { case '?': @@ -858,7 +875,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_fragment_start: { - if (normal_url_char[(unsigned char)ch]) { + if (IS_URL_CHAR(ch)) { MARK(fragment); state = s_req_fragment; break; @@ -895,7 +912,7 @@ size_t http_parser_execute (http_parser *parser, case s_req_fragment: { - if (normal_url_char[(unsigned char)ch]) break; + if (IS_URL_CHAR(ch)) break; switch (ch) { case ' ': @@ -973,7 +990,7 @@ size_t http_parser_execute (http_parser *parser, break; } - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_major *= 10; parser->http_major += ch - '0'; @@ -984,7 +1001,7 @@ size_t http_parser_execute (http_parser *parser, /* first digit of minor HTTP version */ case s_req_first_http_minor: - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_minor = ch - '0'; state = s_req_http_minor; break; @@ -1004,7 +1021,7 @@ size_t http_parser_execute (http_parser *parser, /* XXX allow spaces after digit? */ - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->http_minor *= 10; parser->http_minor += ch - '0'; @@ -1237,7 +1254,7 @@ size_t http_parser_execute (http_parser *parser, break; case h_content_length: - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->content_length = ch - '0'; break; @@ -1286,7 +1303,7 @@ size_t http_parser_execute (http_parser *parser, case h_content_length: if (ch == ' ') break; - if (ch < '0' || ch > '9') goto error; + if (!IS_NUM(ch)) goto error; parser->content_length *= 10; parser->content_length += ch - '0'; break; @@ -1458,6 +1475,7 @@ size_t http_parser_execute (http_parser *parser, case s_chunk_size_start: { + assert(nread == 1); assert(parser->flags & F_CHUNKED); c = unhex[(unsigned char)ch]; @@ -1507,6 +1525,8 @@ size_t http_parser_execute (http_parser *parser, assert(parser->flags & F_CHUNKED); STRICT_CHECK(ch != LF); + nread = 0; + if (parser->content_length == 0) { parser->flags |= F_TRAILING; state = s_header_field_start; diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index c03ec05783..6a54a2d635 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -1,4 +1,4 @@ -/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org> +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -24,6 +24,8 @@ extern "C" { #endif +#define HTTP_PARSER_VERSION_MAJOR 1 +#define HTTP_PARSER_VERSION_MINOR 0 #include <sys/types.h> #if defined(_WIN32) && !defined(__MINGW32__) @@ -47,8 +49,6 @@ typedef int ssize_t; */ #ifndef HTTP_PARSER_STRICT # define HTTP_PARSER_STRICT 1 -#else -# define HTTP_PARSER_STRICT 0 #endif @@ -106,16 +106,29 @@ enum http_method , HTTP_NOTIFY , HTTP_SUBSCRIBE , HTTP_UNSUBSCRIBE + /* RFC-5789 */ + , HTTP_PATCH }; enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; +/* Flag values for http_parser.flags field */ +enum flags + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_TRAILING = 1 << 3 + , F_UPGRADE = 1 << 4 + , F_SKIPBODY = 1 << 5 + }; + + struct http_parser { /** PRIVATE **/ unsigned char type : 2; - unsigned char flags : 6; + unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ unsigned char state; unsigned char header_state; unsigned char index; diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index 2d1d8bd5da..a4b80a2e60 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -1,4 +1,4 @@ -/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org> +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -498,7 +498,7 @@ const struct message requests[] = #define CONNECT_REQUEST 17 , {.name = "connect request" ,.type= HTTP_REQUEST - ,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n" + ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n" "User-agent: Mozilla/1.1N\r\n" "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" "\r\n" @@ -510,7 +510,7 @@ const struct message requests[] = ,.query_string= "" ,.fragment= "" ,.request_path= "" - ,.request_url= "home0.netscape.com:443" + ,.request_url= "0-home0.netscape.com:443" ,.num_headers= 2 ,.upgrade=1 ,.headers= { { "User-agent", "Mozilla/1.1N" } @@ -557,7 +557,7 @@ const struct message requests[] = ,.body= "" } -#define MSEARCH_REQ 19 +#define MSEARCH_REQ 20 , {.name= "m-search request" ,.type= HTTP_REQUEST ,.raw= "M-SEARCH * HTTP/1.1\r\n" @@ -582,6 +582,139 @@ const struct message requests[] = ,.body= "" } +#define QUERY_TERMINATED_HOST 21 +, {.name= "host terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org?hail=all" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define QUERY_TERMINATED_HOSTPORT 22 +, {.name= "host:port terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234?hail=all" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#define SPACE_TERMINATED_HOSTPORT 23 +, {.name= "host:port terminated by a space" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +#if !HTTP_PARSER_STRICT +#define UTF8_PATH_REQ 24 +, {.name= "utf-8 path request" + ,.type= HTTP_REQUEST + ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n" + "Host: github.com\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "q=1" + ,.fragment= "narf" + ,.request_path= "/δ¶/δt/pope" + ,.request_url= "/δ¶/δt/pope?q=1#narf" + ,.num_headers= 1 + ,.headers= { {"Host", "github.com" } + } + ,.body= "" + } + +#define HOSTNAME_UNDERSCORE 25 +, {.name = "hostname underscore" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "home_0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade=1 + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } +#endif /* !HTTP_PARSER_STRICT */ + +#define PATCH_REQ 26 +, {.name = "PATCH request" + ,.type= HTTP_REQUEST + ,.raw= "PATCH /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/example\r\n" + "If-Match: \"e0023aa4e\"\r\n" + "Content-Length: 10\r\n" + "\r\n" + "cccccccccc" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PATCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 4 + ,.upgrade=0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/example" } + , { "If-Match", "\"e0023aa4e\"" } + , { "Content-Length", "10" } + } + ,.body= "cccccccccc" + } + , {.name= NULL } /* sentinel */ }; |