diff --git a/LICENSE b/LICENSE index 203c7c9036..60540d7853 100644 --- a/LICENSE +++ b/LICENSE @@ -26,9 +26,7 @@ are: Michael Tokarev . Released under the GNU Lesser General Public License version 2.1. -Additionally deps/http_parser is based on Zed Shaw's Mongrel. Mongrel is -copyrighted by Zed Shaw and distributed under GPL2 or a permissive open -licence. See deps/http_parser/LICENCE for more information. +Other external libraries are my own and all use the same license as Node. Node's license follows: diff --git a/deps/http_parser/LICENSE b/deps/http_parser/LICENSE deleted file mode 100644 index 7fb7fcd191..0000000000 --- a/deps/http_parser/LICENSE +++ /dev/null @@ -1,79 +0,0 @@ -Copyright 2009, Ryan Lienhart Dahl. 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 -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. - - - - -http_parser is based on Zed Shaw's Mongrel. Mongrel's license is as follows. - --- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT -- -Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw - and contributors. You can redistribute it -and/or modify it under either the terms of the GPL2 or the conditions below: - -1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - -2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or an - equivalent medium, or by allowing the author to include your - modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) rename any non-standard executables so the names do not conflict with - standard executables, which must also be provided. - - d) make other distribution arrangements with the author. - -3. You may distribute the software in object code or executable - form, provided that you do at least ONE of the following: - - a) distribute the executables and library files of the software, - together with instructions (in the manual page or equivalent) on where - to get the original distribution. - - b) accompany the distribution with the machine-readable source of the - software. - - c) give non-standard executables non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - -4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under this terms. - -5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - -6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. --- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT ---- CUT -- diff --git a/deps/http_parser/LICENSE-MIT b/deps/http_parser/LICENSE-MIT new file mode 100644 index 0000000000..cb938cd089 --- /dev/null +++ b/deps/http_parser/LICENSE-MIT @@ -0,0 +1,19 @@ +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. diff --git a/deps/http_parser/Makefile b/deps/http_parser/Makefile index afe7229222..d0a17dd50b 100644 --- a/deps/http_parser/Makefile +++ b/deps/http_parser/Makefile @@ -1,27 +1,31 @@ -#OPT=-O0 -g -Wall -Wextra -Werror -OPT=-O2 +OPT_DEBUG=-O0 -g -Wall -Wextra -Werror +OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 + + +http_parser_g.o: http_parser.c http_parser.h Makefile + gcc $(OPT_DEBUG) -c http_parser.c + +test_g: http_parser_g.o test.c + gcc $(OPT_DEBUG) http_parser.o test.c -o $@ + +test-run: test_g + ./test_g -test: http_parser.o test.c - gcc $(OPT) http_parser.o test.c -o $@ http_parser.o: http_parser.c http_parser.h Makefile - gcc $(OPT) -c http_parser.c + gcc $(OPT_FAST) -c http_parser.c -http_parser.c: http_parser.rl Makefile - ragel -s -G2 http_parser.rl -o $@ +test: http_parser.o test.c + gcc $(OPT_FAST) http_parser.o test.c -o $@ -tags: http_parser.rl http_parser.h test.c +test-run-timed: test + while(true) do time ./test > /dev/null; done + + +tags: http_parser.c http_parser.h test.c ctags $^ clean: - rm -f *.o http_parser.c test http_parser.tar - -package: http_parser.c - @rm -rf /tmp/http_parser && mkdir /tmp/http_parser && \ - cp LICENSE README.md Makefile http_parser.c http_parser.rl \ - http_parser.h test.c /tmp/http_parser && \ - cd /tmp && \ - tar -cf http_parser.tar http_parser/ - @echo /tmp/http_parser.tar + rm -f *.o test test_g http_parser.tar -.PHONY: clean package +.PHONY: clean package test-run test-run-timed diff --git a/deps/http_parser/README.md b/deps/http_parser/README.md index d60473ef1b..8218f36ead 100644 --- a/deps/http_parser/README.md +++ b/deps/http_parser/README.md @@ -5,13 +5,13 @@ This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP applications. It does not make any allocations, it does not buffer data, and it can be interrupted at anytime. It only requires about 128 bytes of data -per message stream (in a web server that is per connection). +per message stream (in a web server that is per connection). Features: - * No dependencies + * No dependencies * Parses both requests and responses. - * Handles keep-alive streams. + * Handles perstent streams. * Decodes chunked encoding. * Extracts the following data from a message * header fields and values @@ -32,32 +32,47 @@ using `http_parser_init()` and set the callbacks. That might look something like this: http_parser *parser = malloc(sizeof(http_parser)); - http_parser_init(parser, HTTP_REQUEST); + http_parser_init(parser); parser->on_path = my_path_callback; parser->on_header_field = my_header_field_callback; + /* ... */ parser->data = my_socket; When data is received on the socket execute the parser and check for errors. - size_t len = 80*1024; + size_t len = 80*1024, nparsed; char buf[len]; ssize_t recved; - recved = read(fd, buf, len); - if (recved != 0) // handle error + recved = recv(fd, buf, len, 0); - http_parser_execute(parser, buf, recved); + if (recved < 0) { + /* Handle error. */ + } + + /* Start up / continue the parser. + * Note we pass the recved==0 to http_parse_requests to signal + * that EOF has been recieved. + */ + nparsed = http_parse_requests(parser, buf, recved); - if (http_parser_has_error(parser)) { - // handle error. usually just close the connection + if (nparsed != recved) { + /* Handle error. Usually just close the connection. */ } +HTTP needs to know where the end of the stream is. For example, sometimes +servers send responses without Content-Length and expect the client to +consume input (for the body) until EOF. To tell http_parser about EOF, give +`0` as the third parameter to `http_parse_requests()`. Callbacks and errors +can still be encountered during an EOF, so one must still be prepared +to receive them. + Scalar valued message information such as `status_code`, `method`, and the HTTP version are stored in the parser structure. This data is only temporarlly stored in `http_parser` and gets reset on each new message. If this information is needed later, copy it out of the structure during the `headers_complete` callback. - + The parser decodes the transfer-encoding for both requests and responses transparently. That is, a chunked encoding is decoded before being sent to the on_body callback. @@ -70,7 +85,7 @@ parser, for example, would not want such a feature. Callbacks --------- -During the `http_parser_execute()` call, the callbacks set in `http_parser` +During the `http_parse_requests()` call, the callbacks set in `http_parser` will be executed. The parser maintains state and never looks behind, so buffering the data is not necessary. If you need to save certain data for later usage, you can do that from the callbacks. @@ -93,7 +108,7 @@ Reading headers may be a tricky task if you read/parse headers partially. Basically, you need to remember whether last header callback was field or value and apply following logic: - /* on_header_field and on_header_value shortened to on_h_* + (on_header_field and on_header_value shortened to on_h_*) ------------------------ ------------ -------------------------------------------- | State (prev. callback) | Callback | Description/action | ------------------------ ------------ -------------------------------------------- @@ -113,19 +128,9 @@ and apply following logic: | value | on_h_value | Value continues. Reallocate value buffer | | | | and append callback data to it | ------------------------ ------------ -------------------------------------------- - */ See examples of reading in headers: * [partial example](http://gist.github.com/155877) in C * [from http-parser tests](http://github.com/ry/http-parser/blob/37a0ff8928fb0d83cec0d0d8909c5a4abcd221af/test.c#L403) in C * [from Node library](http://github.com/ry/node/blob/842eaf446d2fdcb33b296c67c911c32a0dabc747/src/http.js#L284) in Javascript - -Releases --------- - - * [0.2](http://s3.amazonaws.com/four.livejournal/20090807/http_parser-0.2.tar.gz) - - * [0.1](http://s3.amazonaws.com/four.livejournal/20090427/http_parser-0.1.tar.gz) - -The source repo is at [github](http://github.com/ry/http-parser). diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index b0e4b564e5..3c7b72769e 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -1,6058 +1,1473 @@ -#line 1 "http_parser.rl" -/* Copyright (c) 2008, 2009 Ryan Dahl (ry@tinyclouds.org) - * Based on Zed Shaw's Mongrel, copyright (c) Zed A. Shaw +/* Copyright 2009 Ryan Dahl * - * All rights reserved. + * Some parts of this source file were taken from NGINX + * (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: + * 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 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. + * 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. */ -#include "http_parser.h" -#include +#include +#include #include -static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; -#define TRUE 1 -#define FALSE 0 -#define MIN(a,b) (a < b ? a : b) -#define NULL (void*)(0) - -#define MAX_FIELD_SIZE 80*1024 - -#define REMAINING (unsigned long)(pe - p) +#ifndef NULL +# define NULL ((void*)0) +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define MAX_FIELD_SIZE (80*1024) + + +#define MARK(FOR) \ +do { \ + parser->FOR##_mark = p; \ + parser->FOR##_size = 0; \ +} while (0) + #define CALLBACK(FOR) \ do { \ - if (parser->FOR##_mark) { \ - parser->FOR##_size += p - parser->FOR##_mark; \ - if (parser->FOR##_size > MAX_FIELD_SIZE) { \ - parser->error = TRUE; \ - return 0; \ - } \ - if (parser->on_##FOR) { \ - callback_return_value = parser->on_##FOR(parser, \ - parser->FOR##_mark, \ - p - parser->FOR##_mark); \ - } \ - } \ -} while(0) - -#define RESET_PARSER(parser) \ - parser->chunk_size = 0; \ - parser->eating = 0; \ - parser->header_field_mark = NULL; \ - parser->header_value_mark = NULL; \ - parser->query_string_mark = NULL; \ - parser->path_mark = NULL; \ - parser->uri_mark = NULL; \ - parser->fragment_mark = NULL; \ - parser->status_code = 0; \ - parser->method = 0; \ - parser->transfer_encoding = HTTP_IDENTITY; \ - parser->version_major = 0; \ - parser->version_minor = 0; \ - parser->keep_alive = -1; \ - parser->content_length = 0; \ - parser->body_read = 0; - -#define END_REQUEST \ + if (0 != FOR##_callback(parser, p)) return (p - data); \ + parser->FOR##_mark = NULL; \ +} while (0) + +#define CALLBACK_NOCLEAR(FOR) \ do { \ - if (parser->on_message_complete) { \ - callback_return_value = \ - parser->on_message_complete(parser); \ - } \ - RESET_PARSER(parser); \ + if (0 != FOR##_callback(parser, p)) return (p - data); \ } while (0) -#define SKIP_BODY(nskip) \ +#define CALLBACK2(FOR) \ do { \ - tmp = (nskip); \ - if (parser->on_body && tmp > 0) { \ - callback_return_value = parser->on_body(parser, p, tmp); \ - } \ - if (callback_return_value == 0) { \ - p += tmp; \ - parser->body_read += tmp; \ - parser->chunk_size -= tmp; \ - if (0 == parser->chunk_size) { \ - parser->eating = FALSE; \ - if (parser->transfer_encoding == HTTP_IDENTITY) { \ - END_REQUEST; \ - } \ - } else { \ - parser->eating = TRUE; \ - } \ - } \ + if (0 != FOR##_callback(parser)) return (p - data); \ } while (0) -#line 413 "http_parser.rl" +#define DEFINE_CALLBACK(FOR) \ +static inline int FOR##_callback (http_parser *parser, const char *p) \ +{ \ + if (!parser->FOR##_mark) return 0; \ + assert(parser->FOR##_mark); \ + const char *mark = parser->FOR##_mark; \ + parser->FOR##_size += p - mark; \ + if (parser->FOR##_size > MAX_FIELD_SIZE) return -1; \ + int r = 0; \ + if (parser->on_##FOR) r = parser->on_##FOR(parser, mark, p - mark); \ + return r; \ +} +DEFINE_CALLBACK(url) +DEFINE_CALLBACK(path) +DEFINE_CALLBACK(query_string) +DEFINE_CALLBACK(fragment) +DEFINE_CALLBACK(header_field) +DEFINE_CALLBACK(header_value) +static inline int headers_complete_callback (http_parser *parser) +{ + if (parser->on_headers_complete == NULL) return 0; + return parser->on_headers_complete(parser); +} + +static inline int message_begin_callback (http_parser *parser) +{ + if (parser->on_message_begin == NULL) return 0; + return parser->on_message_begin(parser); +} -#line 116 "http_parser.c" -static const int http_parser_start = 1; -static const int http_parser_first_final = 266; -static const int http_parser_error = 0; +static inline int message_complete_callback (http_parser *parser) +{ + if (parser->on_message_complete == NULL) return 0; + return parser->on_message_complete(parser); +} -static const int http_parser_en_ChunkedBody = 2; -static const int http_parser_en_ChunkedBody_chunk_chunk_end = 12; -static const int http_parser_en_Requests = 268; -static const int http_parser_en_Responses = 269; -static const int http_parser_en_main = 1; +#define CONNECTION "connection" +#define CONTENT_LENGTH "content-length" +#define TRANSFER_ENCODING "transfer-encoding" -#line 416 "http_parser.rl" +#define CHUNKED "chunked" +#define KEEP_ALIVE "keep-alive" +#define CLOSE "close" -void -http_parser_init (http_parser *parser, enum http_parser_type type) -{ - int cs = 0; - -#line 134 "http_parser.c" - { - cs = http_parser_start; - } -#line 422 "http_parser.rl" - parser->cs = cs; - parser->type = type; - parser->error = 0; - parser->on_message_begin = NULL; - parser->on_path = NULL; - parser->on_query_string = NULL; - parser->on_uri = NULL; - parser->on_fragment = NULL; - parser->on_header_field = NULL; - parser->on_header_value = NULL; - parser->on_headers_complete = NULL; - parser->on_body = NULL; - parser->on_message_complete = NULL; +static const unsigned char lowcase[] = + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - RESET_PARSER(parser); -} +static const int unhex[] = + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; -/** exec **/ -size_t -http_parser_execute (http_parser *parser, const char *buffer, size_t len) + +static const uint32_t usual[] = { + 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x7ffffff6, /* 0111 1111 1111 1111 1111 1111 1111 0110 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ +}; + +enum state + { s_dead = 1 /* important that this is > 0 */ + + , s_start_res + , s_res_H + , s_res_HT + , s_res_HTT + , s_res_HTTP + , s_res_first_http_major + , s_res_http_major + , s_res_first_http_minor + , s_res_http_minor + , s_res_first_status_code + , s_res_status_code + , s_res_status + , s_res_line_almost_done + + , s_start_req + , s_req_method_G + , s_req_method_GE + , s_req_method_P + , s_req_method_PU + , s_req_method_PO + , s_req_method_POS + , s_req_method_H + , s_req_method_HE + , s_req_method_HEA + , s_req_method_D + , s_req_method_DE + , s_req_method_DEL + , s_req_method_DELE + , s_req_method_DELET + , s_req_spaces_before_url + , s_req_schema + , s_req_schema_slash + , s_req_schema_slash_slash + , s_req_host + , s_req_port + , s_req_path + , s_req_query_string_start + , s_req_query_string + , s_req_fragment_start + , s_req_fragment + , s_req_http_start + , s_req_http_H + , s_req_http_HT + , s_req_http_HTT + , s_req_http_HTTP + , s_req_first_http_major + , s_req_http_major + , s_req_first_http_minor + , s_req_http_minor + , s_req_line_almost_done + + , s_header_field_start + , s_header_field + , s_header_value_start + , s_header_value + + , s_header_almost_done + + , s_headers_almost_done + , s_headers_done + + , 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 + + , s_body_identity + , s_body_identity_eof + }; + +enum header_states + { h_general = 0 + , h_C + , h_CO + , h_CON + + , h_matching_connection + , h_matching_content_length + , h_matching_transfer_encoding + + , h_connection + , h_content_length + , h_transfer_encoding + + , h_matching_transfer_encoding_chunked + , h_matching_connection_keep_alive + , h_matching_connection_close + + , h_transfer_encoding_chunked + , h_connection_keep_alive + , h_connection_close + }; + +enum flags + { F_CHUNKED = 0x0001 + , F_CONNECTION_KEEP_ALIVE = 0x0002 + , F_CONNECTION_CLOSE = 0x0004 + , F_TRAILING = 0x0010 + }; + +#define ERROR (p - data) +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) + +#if HTTP_PARSER_STRICT +# define STRICT_CHECK(cond) if (cond) return ERROR +#else +# define STRICT_CHECK(cond) +#endif + +static inline +size_t parse (http_parser *parser, const char *data, size_t len, int start_state) { - size_t tmp; // REMOVE ME this is extremely hacky - int callback_return_value = 0; + char c, ch; const char *p, *pe; - int cs = parser->cs; + ssize_t to_read; - p = buffer; - pe = buffer+len; + enum state state = parser->state; + enum header_states header_state = parser->header_state; + size_t header_index = parser->header_index; - if (0 < parser->chunk_size && parser->eating) { - /* eat body */ - SKIP_BODY(MIN(len, parser->chunk_size)); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + if (len == 0) { + if (state == s_body_identity_eof) { + CALLBACK2(message_complete); } + return 0; } - if (parser->header_field_mark) parser->header_field_mark = buffer; - if (parser->header_value_mark) parser->header_value_mark = buffer; - if (parser->fragment_mark) parser->fragment_mark = buffer; - if (parser->query_string_mark) parser->query_string_mark = buffer; - if (parser->path_mark) parser->path_mark = buffer; - if (parser->uri_mark) parser->uri_mark = buffer; - - -#line 186 "http_parser.c" - { - if ( p == pe ) - goto _test_eof; - goto _resume; - -_again: - switch ( cs ) { - case 1: goto st1; - case 266: goto st266; - case 0: goto st0; - case 2: goto st2; - case 3: goto st3; - case 4: goto st4; - case 5: goto st5; - case 6: goto st6; - case 267: goto st267; - case 7: goto st7; - case 8: goto st8; - case 9: goto st9; - case 10: goto st10; - case 11: goto st11; - case 12: goto st12; - case 13: goto st13; - case 14: goto st14; - case 15: goto st15; - case 16: goto st16; - case 17: goto st17; - case 18: goto st18; - case 19: goto st19; - case 268: goto st268; - case 20: goto st20; - case 21: goto st21; - case 22: goto st22; - case 23: goto st23; - case 24: goto st24; - case 25: goto st25; - case 26: goto st26; - case 27: goto st27; - case 28: goto st28; - case 29: goto st29; - case 30: goto st30; - case 31: goto st31; - case 32: goto st32; - case 33: goto st33; - case 34: goto st34; - case 35: goto st35; - case 36: goto st36; - case 37: goto st37; - case 38: goto st38; - case 39: goto st39; - case 40: goto st40; - case 41: goto st41; - case 42: goto st42; - case 43: goto st43; - case 44: goto st44; - case 45: goto st45; - case 46: goto st46; - case 47: goto st47; - case 48: goto st48; - case 49: goto st49; - case 50: goto st50; - case 51: goto st51; - case 52: goto st52; - case 53: goto st53; - case 54: goto st54; - case 55: goto st55; - case 56: goto st56; - case 57: goto st57; - case 58: goto st58; - case 59: goto st59; - case 60: goto st60; - case 61: goto st61; - case 62: goto st62; - case 63: goto st63; - case 64: goto st64; - case 65: goto st65; - case 66: goto st66; - case 67: goto st67; - case 68: goto st68; - case 69: goto st69; - case 70: goto st70; - case 71: goto st71; - case 72: goto st72; - case 73: goto st73; - case 74: goto st74; - case 75: goto st75; - case 76: goto st76; - case 77: goto st77; - case 78: goto st78; - case 79: goto st79; - case 80: goto st80; - case 81: goto st81; - case 82: goto st82; - case 83: goto st83; - case 84: goto st84; - case 85: goto st85; - case 86: goto st86; - case 87: goto st87; - case 88: goto st88; - case 89: goto st89; - case 90: goto st90; - case 91: goto st91; - case 92: goto st92; - case 93: goto st93; - case 94: goto st94; - case 95: goto st95; - case 96: goto st96; - case 97: goto st97; - case 98: goto st98; - case 99: goto st99; - case 100: goto st100; - case 101: goto st101; - case 102: goto st102; - case 103: goto st103; - case 104: goto st104; - case 105: goto st105; - case 106: goto st106; - case 107: goto st107; - case 108: goto st108; - case 109: goto st109; - case 110: goto st110; - case 111: goto st111; - case 112: goto st112; - case 113: goto st113; - case 114: goto st114; - case 115: goto st115; - case 116: goto st116; - case 117: goto st117; - case 118: goto st118; - case 119: goto st119; - case 120: goto st120; - case 121: goto st121; - case 122: goto st122; - case 123: goto st123; - case 124: goto st124; - case 125: goto st125; - case 126: goto st126; - case 127: goto st127; - case 128: goto st128; - case 129: goto st129; - case 130: goto st130; - case 131: goto st131; - case 132: goto st132; - case 133: goto st133; - case 134: goto st134; - case 135: goto st135; - case 136: goto st136; - case 137: goto st137; - case 138: goto st138; - case 139: goto st139; - case 140: goto st140; - case 141: goto st141; - case 142: goto st142; - case 143: goto st143; - case 144: goto st144; - case 145: goto st145; - case 146: goto st146; - case 147: goto st147; - case 148: goto st148; - case 149: goto st149; - case 150: goto st150; - case 151: goto st151; - case 152: goto st152; - case 153: goto st153; - case 154: goto st154; - case 155: goto st155; - case 156: goto st156; - case 157: goto st157; - case 158: goto st158; - case 159: goto st159; - case 160: goto st160; - case 161: goto st161; - case 162: goto st162; - case 163: goto st163; - case 164: goto st164; - case 165: goto st165; - case 166: goto st166; - case 167: goto st167; - case 168: goto st168; - case 169: goto st169; - case 170: goto st170; - case 171: goto st171; - case 172: goto st172; - case 173: goto st173; - case 174: goto st174; - case 175: goto st175; - case 176: goto st176; - case 177: goto st177; - case 178: goto st178; - case 179: goto st179; - case 180: goto st180; - case 181: goto st181; - case 269: goto st269; - case 182: goto st182; - case 183: goto st183; - case 184: goto st184; - case 185: goto st185; - case 186: goto st186; - case 187: goto st187; - case 188: goto st188; - case 189: goto st189; - case 190: goto st190; - case 191: goto st191; - case 192: goto st192; - case 193: goto st193; - case 194: goto st194; - case 195: goto st195; - case 196: goto st196; - case 197: goto st197; - case 198: goto st198; - case 199: goto st199; - case 200: goto st200; - case 201: goto st201; - case 202: goto st202; - case 203: goto st203; - case 204: goto st204; - case 205: goto st205; - case 206: goto st206; - case 207: goto st207; - case 208: goto st208; - case 209: goto st209; - case 210: goto st210; - case 211: goto st211; - case 212: goto st212; - case 213: goto st213; - case 214: goto st214; - case 215: goto st215; - case 216: goto st216; - case 217: goto st217; - case 218: goto st218; - case 219: goto st219; - case 220: goto st220; - case 221: goto st221; - case 222: goto st222; - case 223: goto st223; - case 224: goto st224; - case 225: goto st225; - case 226: goto st226; - case 227: goto st227; - case 228: goto st228; - case 229: goto st229; - case 230: goto st230; - case 231: goto st231; - case 232: goto st232; - case 233: goto st233; - case 234: goto st234; - case 235: goto st235; - case 236: goto st236; - case 237: goto st237; - case 238: goto st238; - case 239: goto st239; - case 240: goto st240; - case 241: goto st241; - case 242: goto st242; - case 243: goto st243; - case 244: goto st244; - case 245: goto st245; - case 246: goto st246; - case 247: goto st247; - case 248: goto st248; - case 249: goto st249; - case 250: goto st250; - case 251: goto st251; - case 252: goto st252; - case 253: goto st253; - case 254: goto st254; - case 255: goto st255; - case 256: goto st256; - case 257: goto st257; - case 258: goto st258; - case 259: goto st259; - case 260: goto st260; - case 261: goto st261; - case 262: goto st262; - case 263: goto st263; - case 264: goto st264; - case 265: goto st265; - default: break; - } - - if ( ++p == pe ) - goto _test_eof; -_resume: - switch ( cs ) - { -st1: - if ( ++p == pe ) - goto _test_eof1; -case 1: - goto tr0; -tr0: -#line 404 "http_parser.rl" - { - p--; - if (parser->type == HTTP_REQUEST) { - {goto st268;} - } else { - {goto st269;} - } - } - goto st266; -st266: - if ( ++p == pe ) - goto _test_eof266; -case 266: -#line 492 "http_parser.c" - goto st0; -st0: -cs = 0; - goto _out; -st2: - if ( ++p == pe ) - goto _test_eof2; -case 2: - if ( (*p) == 48 ) - goto tr1; - if ( (*p) < 65 ) { - if ( 49 <= (*p) && (*p) <= 57 ) - goto tr3; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto tr3; - } else - goto tr3; - goto st0; -tr1: -#line 253 "http_parser.rl" - { - parser->chunk_size *= 16; - parser->chunk_size += unhex[(int)*p]; - } - goto st3; -st3: - if ( ++p == pe ) - goto _test_eof3; -case 3: -#line 523 "http_parser.c" - switch( (*p) ) { - case 13: goto st4; - case 48: goto tr1; - case 59: goto st17; - } - if ( (*p) < 65 ) { - if ( 49 <= (*p) && (*p) <= 57 ) - goto tr3; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto tr3; - } else - goto tr3; - goto st0; -st4: - if ( ++p == pe ) - goto _test_eof4; -case 4: - if ( (*p) == 10 ) - goto st5; - goto st0; -st5: - if ( ++p == pe ) - goto _test_eof5; -case 5: - switch( (*p) ) { - case 13: goto st6; - case 33: goto st7; - case 124: goto st7; - case 126: goto st7; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st7; - } else if ( (*p) >= 35 ) - goto st7; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st7; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st7; - } else - goto st7; - } else - goto st7; - goto st0; -st6: - if ( ++p == pe ) - goto _test_eof6; -case 6: - if ( (*p) == 10 ) - goto tr9; - goto st0; -tr9: - cs = 267; -#line 273 "http_parser.rl" - { - END_REQUEST; - if (parser->type == HTTP_REQUEST) { - cs = 268; - } else { - cs = 269; - } - } - goto _again; -st267: - if ( ++p == pe ) - goto _test_eof267; -case 267: -#line 596 "http_parser.c" - goto st0; -st7: - if ( ++p == pe ) - goto _test_eof7; -case 7: - switch( (*p) ) { - case 33: goto st7; - case 58: goto st8; - case 124: goto st7; - case 126: goto st7; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st7; - } else if ( (*p) >= 35 ) - goto st7; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st7; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st7; - } else - goto st7; - } else - goto st7; - goto st0; -st8: - if ( ++p == pe ) - goto _test_eof8; -case 8: - if ( (*p) == 13 ) - goto st4; - goto st8; -tr3: -#line 253 "http_parser.rl" - { - parser->chunk_size *= 16; - parser->chunk_size += unhex[(int)*p]; - } - goto st9; -st9: - if ( ++p == pe ) - goto _test_eof9; -case 9: -#line 644 "http_parser.c" - switch( (*p) ) { - case 13: goto st10; - case 59: goto st14; - } - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr3; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto tr3; - } else - goto tr3; - goto st0; -st10: - if ( ++p == pe ) - goto _test_eof10; -case 10: - if ( (*p) == 10 ) - goto st11; - goto st0; -st11: - if ( ++p == pe ) - goto _test_eof11; -case 11: - goto tr14; -tr14: -#line 258 "http_parser.rl" - { - SKIP_BODY(MIN(parser->chunk_size, REMAINING)); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } + if (parser->header_field_mark) parser->header_field_mark = data; + if (parser->header_value_mark) parser->header_value_mark = data; + if (parser->fragment_mark) parser->fragment_mark = data; + if (parser->query_string_mark) parser->query_string_mark = data; + if (parser->path_mark) parser->path_mark = data; + if (parser->url_mark) parser->url_mark = data; - p--; - if (parser->chunk_size > REMAINING) { - {p++; cs = 12; goto _out;} - } else { - {goto st12;} - } - } - goto st12; -st12: - if ( ++p == pe ) - goto _test_eof12; -case 12: -#line 691 "http_parser.c" - if ( (*p) == 13 ) - goto st13; - goto st0; -st13: - if ( ++p == pe ) - goto _test_eof13; -case 13: - if ( (*p) == 10 ) - goto st2; - goto st0; -st14: - if ( ++p == pe ) - goto _test_eof14; -case 14: - switch( (*p) ) { - case 13: goto st10; - case 32: goto st14; - case 33: goto st15; - case 59: goto st14; - case 61: goto st16; - case 124: goto st15; - case 126: goto st15; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st15; - } else if ( (*p) >= 35 ) - goto st15; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st15; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st15; - } else - goto st15; - } else - goto st15; - goto st0; -st15: - if ( ++p == pe ) - goto _test_eof15; -case 15: - switch( (*p) ) { - case 13: goto st10; - case 33: goto st15; - case 59: goto st14; - case 61: goto st16; - case 124: goto st15; - case 126: goto st15; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st15; - } else if ( (*p) >= 35 ) - goto st15; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st15; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st15; - } else - goto st15; - } else - goto st15; - goto st0; -st16: - if ( ++p == pe ) - goto _test_eof16; -case 16: - switch( (*p) ) { - case 13: goto st10; - case 33: goto st16; - case 59: goto st14; - case 124: goto st16; - case 126: goto st16; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st16; - } else if ( (*p) >= 35 ) - goto st16; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st16; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st16; - } else - goto st16; - } else - goto st16; - goto st0; -st17: - if ( ++p == pe ) - goto _test_eof17; -case 17: - switch( (*p) ) { - case 13: goto st4; - case 32: goto st17; - case 33: goto st18; - case 59: goto st17; - case 61: goto st19; - case 124: goto st18; - case 126: goto st18; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st18; - } else if ( (*p) >= 35 ) - goto st18; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st18; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st18; - } else - goto st18; - } else - goto st18; - goto st0; -st18: - if ( ++p == pe ) - goto _test_eof18; -case 18: - switch( (*p) ) { - case 13: goto st4; - case 33: goto st18; - case 59: goto st17; - case 61: goto st19; - case 124: goto st18; - case 126: goto st18; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st18; - } else if ( (*p) >= 35 ) - goto st18; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st18; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st18; - } else - goto st18; - } else - goto st18; - goto st0; -st19: - if ( ++p == pe ) - goto _test_eof19; -case 19: - switch( (*p) ) { - case 13: goto st4; - case 33: goto st19; - case 59: goto st17; - case 124: goto st19; - case 126: goto st19; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st19; - } else if ( (*p) >= 35 ) - goto st19; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st19; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st19; - } else - goto st19; - } else - goto st19; - goto st0; -tr45: - cs = 268; -#line 203 "http_parser.rl" - { - if(parser->on_headers_complete) { - callback_return_value = parser->on_headers_complete(parser); - if (callback_return_value != 0) { - parser->error = TRUE; + for (p=data, pe=data+len; p != pe; p++) { + ch = *p; + switch (state) { + + case s_dead: + /* this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ return 0; + + case s_start_res: + { + parser->flags = 0; + parser->content_length = -1; + + CALLBACK2(message_begin); + + switch (ch) { + case 'H': + state = s_res_H; + break; + + case CR: + case LF: + break; + + default: + return ERROR; + } + break; } - } - } -#line 282 "http_parser.rl" - { - if (parser->transfer_encoding == HTTP_CHUNKED) { - cs = 2; - } else { - /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ - parser->chunk_size = parser->content_length; - p += 1; - SKIP_BODY(MIN(REMAINING, parser->content_length)); + case s_res_H: + STRICT_CHECK(ch != 'T'); + state = s_res_HT; + break; - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + case s_res_HT: + STRICT_CHECK(ch != 'T'); + state = s_res_HTT; + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + state = s_res_HTTP; + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + state = s_res_first_http_major; + break; + + case s_res_first_http_major: + if (ch < '1' || ch > '9') return ERROR; + parser->http_major = ch - '0'; + state = s_res_http_major; + break; + + /* major HTTP version or dot */ + case s_res_http_major: + { + if (ch == '.') { + state = s_res_first_http_minor; + break; + } + + if (ch < '0' || ch > '9') return ERROR; + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) return ERROR; + break; } + + /* first digit of minor HTTP version */ + case s_res_first_http_minor: + if (ch < '0' || ch > '9') return ERROR; + parser->http_minor = ch - '0'; + state = s_res_http_minor; + break; - p--; - if(parser->chunk_size > REMAINING) { - {p++; goto _out;} + /* minor HTTP version or end of request line */ + case s_res_http_minor: + { + if (ch == ' ') { + state = s_res_first_status_code; + break; + } + + if (ch < '0' || ch > '9') return ERROR; + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) return ERROR; + break; } - } - } - goto _again; -st268: - if ( ++p == pe ) - goto _test_eof268; -case 268: -#line 921 "http_parser.c" - switch( (*p) ) { - case 67: goto tr310; - case 68: goto tr311; - case 71: goto tr312; - case 72: goto tr313; - case 76: goto tr314; - case 77: goto tr315; - case 79: goto tr316; - case 80: goto tr317; - case 84: goto tr318; - case 85: goto tr319; - } - goto st0; -tr310: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_res_first_status_code: + { + if (ch < '0' || ch > '9') { + if (ch == ' ') { + break; + } + return ERROR; + } + parser->status_code = ch - '0'; + state = s_res_status_code; + break; } - } - } - goto st20; -st20: - if ( ++p == pe ) - goto _test_eof20; -case 20: -#line 951 "http_parser.c" - if ( (*p) == 79 ) - goto st21; - goto st0; -st21: - if ( ++p == pe ) - goto _test_eof21; -case 21: - if ( (*p) == 80 ) - goto st22; - goto st0; -st22: - if ( ++p == pe ) - goto _test_eof22; -case 22: - if ( (*p) == 89 ) - goto st23; - goto st0; -st23: - if ( ++p == pe ) - goto _test_eof23; -case 23: - if ( (*p) == 32 ) - goto tr24; - goto st0; -tr24: -#line 329 "http_parser.rl" - { parser->method = HTTP_COPY; } - goto st24; -tr154: -#line 330 "http_parser.rl" - { parser->method = HTTP_DELETE; } - goto st24; -tr157: -#line 331 "http_parser.rl" - { parser->method = HTTP_GET; } - goto st24; -tr161: -#line 332 "http_parser.rl" - { parser->method = HTTP_HEAD; } - goto st24; -tr165: -#line 333 "http_parser.rl" - { parser->method = HTTP_LOCK; } - goto st24; -tr171: -#line 334 "http_parser.rl" - { parser->method = HTTP_MKCOL; } - goto st24; -tr174: -#line 335 "http_parser.rl" - { parser->method = HTTP_MOVE; } - goto st24; -tr181: -#line 336 "http_parser.rl" - { parser->method = HTTP_OPTIONS; } - goto st24; -tr187: -#line 337 "http_parser.rl" - { parser->method = HTTP_POST; } - goto st24; -tr195: -#line 338 "http_parser.rl" - { parser->method = HTTP_PROPFIND; } - goto st24; -tr200: -#line 339 "http_parser.rl" - { parser->method = HTTP_PROPPATCH; } - goto st24; -tr202: -#line 340 "http_parser.rl" - { parser->method = HTTP_PUT; } - goto st24; -tr207: -#line 341 "http_parser.rl" - { parser->method = HTTP_TRACE; } - goto st24; -tr213: -#line 342 "http_parser.rl" - { parser->method = HTTP_UNLOCK; } - goto st24; -st24: - if ( ++p == pe ) - goto _test_eof24; -case 24: -#line 1036 "http_parser.c" - switch( (*p) ) { - case 42: goto tr25; - case 43: goto tr26; - case 47: goto tr27; - case 58: goto tr28; - } - if ( (*p) < 65 ) { - if ( 45 <= (*p) && (*p) <= 57 ) - goto tr26; - } else if ( (*p) > 90 ) { - if ( 97 <= (*p) && (*p) <= 122 ) - goto tr26; - } else - goto tr26; - goto st0; -tr25: -#line 138 "http_parser.rl" - { - parser->uri_mark = p; - parser->uri_size = 0; - } - goto st25; -st25: - if ( ++p == pe ) - goto _test_eof25; -case 25: -#line 1063 "http_parser.c" - switch( (*p) ) { - case 32: goto tr29; - case 35: goto tr30; - } - goto st0; -tr29: -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st26; -tr124: -#line 123 "http_parser.rl" - { - parser->fragment_mark = p; - parser->fragment_size = 0; - } -#line 173 "http_parser.rl" - { - CALLBACK(fragment); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->fragment_mark = NULL; - parser->fragment_size = 0; - } - goto st26; -tr127: -#line 173 "http_parser.rl" - { - CALLBACK(fragment); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->fragment_mark = NULL; - parser->fragment_size = 0; - } - goto st26; -tr135: -#line 193 "http_parser.rl" - { - CALLBACK(path); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->path_mark = NULL; - parser->path_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st26; -tr141: -#line 128 "http_parser.rl" - { - parser->query_string_mark = p; - parser->query_string_size = 0; - } -#line 183 "http_parser.rl" - { - CALLBACK(query_string); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->query_string_mark = NULL; - parser->query_string_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st26; -tr145: -#line 183 "http_parser.rl" - { - CALLBACK(query_string); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->query_string_mark = NULL; - parser->query_string_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st26; -st26: - if ( ++p == pe ) - goto _test_eof26; -case 26: -#line 1185 "http_parser.c" - if ( (*p) == 72 ) - goto st27; - goto st0; -st27: - if ( ++p == pe ) - goto _test_eof27; -case 27: - if ( (*p) == 84 ) - goto st28; - goto st0; -st28: - if ( ++p == pe ) - goto _test_eof28; -case 28: - if ( (*p) == 84 ) - goto st29; - goto st0; -st29: - if ( ++p == pe ) - goto _test_eof29; -case 29: - if ( (*p) == 80 ) - goto st30; - goto st0; -st30: - if ( ++p == pe ) - goto _test_eof30; -case 30: - if ( (*p) == 47 ) - goto st31; - goto st0; -st31: - if ( ++p == pe ) - goto _test_eof31; -case 31: - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr36; - goto st0; -tr36: -#line 243 "http_parser.rl" - { - parser->version_major *= 10; - parser->version_major += *p - '0'; - } - goto st32; -st32: - if ( ++p == pe ) - goto _test_eof32; -case 32: -#line 1235 "http_parser.c" - if ( (*p) == 46 ) - goto st33; - goto st0; -st33: - if ( ++p == pe ) - goto _test_eof33; -case 33: - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr38; - goto st0; -tr38: -#line 248 "http_parser.rl" - { - parser->version_minor *= 10; - parser->version_minor += *p - '0'; - } - goto st34; -st34: - if ( ++p == pe ) - goto _test_eof34; -case 34: -#line 1257 "http_parser.c" - if ( (*p) == 13 ) - goto st35; - goto st0; -tr49: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st35; -tr52: -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st35; -tr71: -#line 241 "http_parser.rl" - { parser->keep_alive = FALSE; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st35; -tr81: -#line 240 "http_parser.rl" - { parser->keep_alive = TRUE; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st35; -tr122: -#line 237 "http_parser.rl" - { parser->transfer_encoding = HTTP_IDENTITY; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st35; -st35: - if ( ++p == pe ) - goto _test_eof35; -case 35: -#line 1336 "http_parser.c" - if ( (*p) == 10 ) - goto st36; - goto st0; -st36: - if ( ++p == pe ) - goto _test_eof36; -case 36: - switch( (*p) ) { - case 13: goto st37; - case 33: goto tr42; - case 67: goto tr43; - case 84: goto tr44; - case 99: goto tr43; - case 116: goto tr44; - case 124: goto tr42; - case 126: goto tr42; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto tr42; - } else if ( (*p) >= 35 ) - goto tr42; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr42; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto tr42; - } else - goto tr42; - } else - goto tr42; - goto st0; -st37: - if ( ++p == pe ) - goto _test_eof37; -case 37: - if ( (*p) == 10 ) - goto tr45; - goto st0; -tr42: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st38; -st38: - if ( ++p == pe ) - goto _test_eof38; -case 38: -#line 1390 "http_parser.c" - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -tr47: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st39; -st39: - if ( ++p == pe ) - goto _test_eof39; -case 39: -#line 1431 "http_parser.c" - switch( (*p) ) { - case 13: goto tr49; - case 32: goto st39; - } - goto tr48; -tr48: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st40; -st40: - if ( ++p == pe ) - goto _test_eof40; -case 40: -#line 1448 "http_parser.c" - if ( (*p) == 13 ) - goto tr52; - goto st40; -tr43: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st41; -st41: - if ( ++p == pe ) - goto _test_eof41; -case 41: -#line 1463 "http_parser.c" - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 79: goto st42; - case 111: goto st42; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st42: - if ( ++p == pe ) - goto _test_eof42; -case 42: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st43; - case 110: goto st43; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st43: - if ( ++p == pe ) - goto _test_eof43; -case 43: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st44; - case 84: goto st67; - case 110: goto st44; - case 116: goto st67; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st44: - if ( ++p == pe ) - goto _test_eof44; -case 44: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 69: goto st45; - case 101: goto st45; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st45: - if ( ++p == pe ) - goto _test_eof45; -case 45: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 67: goto st46; - case 99: goto st46; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st46: - if ( ++p == pe ) - goto _test_eof46; -case 46: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 84: goto st47; - case 116: goto st47; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st47: - if ( ++p == pe ) - goto _test_eof47; -case 47: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 73: goto st48; - case 105: goto st48; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st48: - if ( ++p == pe ) - goto _test_eof48; -case 48: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 79: goto st49; - case 111: goto st49; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st49: - if ( ++p == pe ) - goto _test_eof49; -case 49: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st50; - case 110: goto st50; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st50: - if ( ++p == pe ) - goto _test_eof50; -case 50: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr63; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -tr63: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st51; -st51: - if ( ++p == pe ) - goto _test_eof51; -case 51: -#line 1776 "http_parser.c" - switch( (*p) ) { - case 13: goto tr49; - case 32: goto st51; - case 67: goto tr65; - case 75: goto tr66; - case 99: goto tr65; - case 107: goto tr66; - } - goto tr48; -tr65: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st52; -st52: - if ( ++p == pe ) - goto _test_eof52; -case 52: -#line 1797 "http_parser.c" - switch( (*p) ) { - case 13: goto tr52; - case 76: goto st53; - case 108: goto st53; - } - goto st40; -st53: - if ( ++p == pe ) - goto _test_eof53; -case 53: - switch( (*p) ) { - case 13: goto tr52; - case 79: goto st54; - case 111: goto st54; - } - goto st40; -st54: - if ( ++p == pe ) - goto _test_eof54; -case 54: - switch( (*p) ) { - case 13: goto tr52; - case 83: goto st55; - case 115: goto st55; - } - goto st40; -st55: - if ( ++p == pe ) - goto _test_eof55; -case 55: - switch( (*p) ) { - case 13: goto tr52; - case 69: goto st56; - case 101: goto st56; - } - goto st40; -st56: - if ( ++p == pe ) - goto _test_eof56; -case 56: - if ( (*p) == 13 ) - goto tr71; - goto st40; -tr66: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st57; -st57: - if ( ++p == pe ) - goto _test_eof57; -case 57: -#line 1852 "http_parser.c" - switch( (*p) ) { - case 13: goto tr52; - case 69: goto st58; - case 101: goto st58; - } - goto st40; -st58: - if ( ++p == pe ) - goto _test_eof58; -case 58: - switch( (*p) ) { - case 13: goto tr52; - case 69: goto st59; - case 101: goto st59; - } - goto st40; -st59: - if ( ++p == pe ) - goto _test_eof59; -case 59: - switch( (*p) ) { - case 13: goto tr52; - case 80: goto st60; - case 112: goto st60; - } - goto st40; -st60: - if ( ++p == pe ) - goto _test_eof60; -case 60: - switch( (*p) ) { - case 13: goto tr52; - case 45: goto st61; - } - goto st40; -st61: - if ( ++p == pe ) - goto _test_eof61; -case 61: - switch( (*p) ) { - case 13: goto tr52; - case 65: goto st62; - case 97: goto st62; - } - goto st40; -st62: - if ( ++p == pe ) - goto _test_eof62; -case 62: - switch( (*p) ) { - case 13: goto tr52; - case 76: goto st63; - case 108: goto st63; - } - goto st40; -st63: - if ( ++p == pe ) - goto _test_eof63; -case 63: - switch( (*p) ) { - case 13: goto tr52; - case 73: goto st64; - case 105: goto st64; - } - goto st40; -st64: - if ( ++p == pe ) - goto _test_eof64; -case 64: - switch( (*p) ) { - case 13: goto tr52; - case 86: goto st65; - case 118: goto st65; - } - goto st40; -st65: - if ( ++p == pe ) - goto _test_eof65; -case 65: - switch( (*p) ) { - case 13: goto tr52; - case 69: goto st66; - case 101: goto st66; - } - goto st40; -st66: - if ( ++p == pe ) - goto _test_eof66; -case 66: - if ( (*p) == 13 ) - goto tr81; - goto st40; -st67: - if ( ++p == pe ) - goto _test_eof67; -case 67: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 69: goto st68; - case 101: goto st68; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st68: - if ( ++p == pe ) - goto _test_eof68; -case 68: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st69; - case 110: goto st69; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st69: - if ( ++p == pe ) - goto _test_eof69; -case 69: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 84: goto st70; - case 116: goto st70; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st70: - if ( ++p == pe ) - goto _test_eof70; -case 70: - switch( (*p) ) { - case 33: goto st38; - case 45: goto st71; - case 46: goto st38; - case 58: goto tr47; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 48 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 57 ) { - if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else if ( (*p) >= 65 ) - goto st38; - } else - goto st38; - goto st0; -st71: - if ( ++p == pe ) - goto _test_eof71; -case 71: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 76: goto st72; - case 108: goto st72; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st72: - if ( ++p == pe ) - goto _test_eof72; -case 72: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 69: goto st73; - case 101: goto st73; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st73: - if ( ++p == pe ) - goto _test_eof73; -case 73: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st74; - case 110: goto st74; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st74: - if ( ++p == pe ) - goto _test_eof74; -case 74: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 71: goto st75; - case 103: goto st75; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st75: - if ( ++p == pe ) - goto _test_eof75; -case 75: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 84: goto st76; - case 116: goto st76; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st76: - if ( ++p == pe ) - goto _test_eof76; -case 76: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 72: goto st77; - case 104: goto st77; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st77: - if ( ++p == pe ) - goto _test_eof77; -case 77: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr92; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -tr92: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st78; -st78: - if ( ++p == pe ) - goto _test_eof78; -case 78: -#line 2286 "http_parser.c" - switch( (*p) ) { - case 13: goto tr49; - case 32: goto st78; - } - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr94; - goto tr48; -tr94: -#line 223 "http_parser.rl" - { - if (parser->content_length > INT_MAX) { - parser->error = TRUE; - return 0; - } - parser->content_length *= 10; - parser->content_length += *p - '0'; - } -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st79; -tr95: -#line 223 "http_parser.rl" - { - if (parser->content_length > INT_MAX) { - parser->error = TRUE; - return 0; - } - parser->content_length *= 10; - parser->content_length += *p - '0'; - } - goto st79; -st79: - if ( ++p == pe ) - goto _test_eof79; -case 79: -#line 2325 "http_parser.c" - if ( (*p) == 13 ) - goto tr52; - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr95; - goto st40; -tr44: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st80; -st80: - if ( ++p == pe ) - goto _test_eof80; -case 80: -#line 2342 "http_parser.c" - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 82: goto st81; - case 114: goto st81; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st81: - if ( ++p == pe ) - goto _test_eof81; -case 81: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 65: goto st82; - case 97: goto st82; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 66 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st82: - if ( ++p == pe ) - goto _test_eof82; -case 82: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st83; - case 110: goto st83; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st83: - if ( ++p == pe ) - goto _test_eof83; -case 83: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 83: goto st84; - case 115: goto st84; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st84: - if ( ++p == pe ) - goto _test_eof84; -case 84: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 70: goto st85; - case 102: goto st85; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st85: - if ( ++p == pe ) - goto _test_eof85; -case 85: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 69: goto st86; - case 101: goto st86; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st86: - if ( ++p == pe ) - goto _test_eof86; -case 86: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 82: goto st87; - case 114: goto st87; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st87: - if ( ++p == pe ) - goto _test_eof87; -case 87: - switch( (*p) ) { - case 33: goto st38; - case 45: goto st88; - case 46: goto st38; - case 58: goto tr47; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 48 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 57 ) { - if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else if ( (*p) >= 65 ) - goto st38; - } else - goto st38; - goto st0; -st88: - if ( ++p == pe ) - goto _test_eof88; -case 88: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 69: goto st89; - case 101: goto st89; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st89: - if ( ++p == pe ) - goto _test_eof89; -case 89: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st90; - case 110: goto st90; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st90: - if ( ++p == pe ) - goto _test_eof90; -case 90: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 67: goto st91; - case 99: goto st91; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st91: - if ( ++p == pe ) - goto _test_eof91; -case 91: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 79: goto st92; - case 111: goto st92; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st92: - if ( ++p == pe ) - goto _test_eof92; -case 92: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 68: goto st93; - case 100: goto st93; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st93: - if ( ++p == pe ) - goto _test_eof93; -case 93: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 73: goto st94; - case 105: goto st94; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st94: - if ( ++p == pe ) - goto _test_eof94; -case 94: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 78: goto st95; - case 110: goto st95; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st95: - if ( ++p == pe ) - goto _test_eof95; -case 95: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr47; - case 71: goto st96; - case 103: goto st96; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -st96: - if ( ++p == pe ) - goto _test_eof96; -case 96: - switch( (*p) ) { - case 33: goto st38; - case 58: goto tr112; - case 124: goto st38; - case 126: goto st38; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st38; - } else if ( (*p) >= 35 ) - goto st38; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st38; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st38; - } else - goto st38; - } else - goto st38; - goto st0; -tr112: -#line 238 "http_parser.rl" - { parser->transfer_encoding = HTTP_CHUNKED; } -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st97; -st97: - if ( ++p == pe ) - goto _test_eof97; -case 97: -#line 2862 "http_parser.c" - switch( (*p) ) { - case 13: goto tr49; - case 32: goto st97; - case 105: goto tr114; - } - goto tr48; -tr114: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st98; -st98: - if ( ++p == pe ) - goto _test_eof98; -case 98: -#line 2880 "http_parser.c" - switch( (*p) ) { - case 13: goto tr52; - case 100: goto st99; - } - goto st40; -st99: - if ( ++p == pe ) - goto _test_eof99; -case 99: - switch( (*p) ) { - case 13: goto tr52; - case 101: goto st100; - } - goto st40; -st100: - if ( ++p == pe ) - goto _test_eof100; -case 100: - switch( (*p) ) { - case 13: goto tr52; - case 110: goto st101; - } - goto st40; -st101: - if ( ++p == pe ) - goto _test_eof101; -case 101: - switch( (*p) ) { - case 13: goto tr52; - case 116: goto st102; - } - goto st40; -st102: - if ( ++p == pe ) - goto _test_eof102; -case 102: - switch( (*p) ) { - case 13: goto tr52; - case 105: goto st103; - } - goto st40; -st103: - if ( ++p == pe ) - goto _test_eof103; -case 103: - switch( (*p) ) { - case 13: goto tr52; - case 116: goto st104; - } - goto st40; -st104: - if ( ++p == pe ) - goto _test_eof104; -case 104: - switch( (*p) ) { - case 13: goto tr52; - case 121: goto st105; - } - goto st40; -st105: - if ( ++p == pe ) - goto _test_eof105; -case 105: - if ( (*p) == 13 ) - goto tr122; - goto st40; -tr30: -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st106; -tr136: -#line 193 "http_parser.rl" - { - CALLBACK(path); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->path_mark = NULL; - parser->path_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st106; -tr142: -#line 128 "http_parser.rl" - { - parser->query_string_mark = p; - parser->query_string_size = 0; - } -#line 183 "http_parser.rl" - { - CALLBACK(query_string); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->query_string_mark = NULL; - parser->query_string_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st106; -tr146: -#line 183 "http_parser.rl" - { - CALLBACK(query_string); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->query_string_mark = NULL; - parser->query_string_size = 0; - } -#line 163 "http_parser.rl" - { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - goto st106; -st106: - if ( ++p == pe ) - goto _test_eof106; -case 106: -#line 3034 "http_parser.c" - switch( (*p) ) { - case 32: goto tr124; - case 35: goto st0; - case 37: goto tr125; - case 60: goto st0; - case 62: goto st0; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto tr123; -tr123: -#line 123 "http_parser.rl" - { - parser->fragment_mark = p; - parser->fragment_size = 0; - } - goto st107; -st107: - if ( ++p == pe ) - goto _test_eof107; -case 107: -#line 3057 "http_parser.c" - switch( (*p) ) { - case 32: goto tr127; - case 35: goto st0; - case 37: goto st108; - case 60: goto st0; - case 62: goto st0; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto st107; -tr125: -#line 123 "http_parser.rl" - { - parser->fragment_mark = p; - parser->fragment_size = 0; - } - goto st108; -st108: - if ( ++p == pe ) - goto _test_eof108; -case 108: -#line 3080 "http_parser.c" - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st109; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st109; - } else - goto st109; - goto st0; -st109: - if ( ++p == pe ) - goto _test_eof109; -case 109: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st107; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st107; - } else - goto st107; - goto st0; -tr26: -#line 138 "http_parser.rl" - { - parser->uri_mark = p; - parser->uri_size = 0; - } - goto st110; -st110: - if ( ++p == pe ) - goto _test_eof110; -case 110: -#line 3114 "http_parser.c" - switch( (*p) ) { - case 43: goto st110; - case 58: goto st111; - } - if ( (*p) < 48 ) { - if ( 45 <= (*p) && (*p) <= 46 ) - goto st110; - } else if ( (*p) > 57 ) { - if ( (*p) > 90 ) { - if ( 97 <= (*p) && (*p) <= 122 ) - goto st110; - } else if ( (*p) >= 65 ) - goto st110; - } else - goto st110; - goto st0; -tr28: -#line 138 "http_parser.rl" - { - parser->uri_mark = p; - parser->uri_size = 0; - } - goto st111; -st111: - if ( ++p == pe ) - goto _test_eof111; -case 111: -#line 3142 "http_parser.c" - switch( (*p) ) { - case 32: goto tr29; - case 35: goto tr30; - case 37: goto st112; - case 60: goto st0; - case 62: goto st0; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto st111; -st112: - if ( ++p == pe ) - goto _test_eof112; -case 112: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st113; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st113; - } else - goto st113; - goto st0; -st113: - if ( ++p == pe ) - goto _test_eof113; -case 113: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st111; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st111; - } else - goto st111; - goto st0; -tr27: -#line 138 "http_parser.rl" - { - parser->uri_mark = p; - parser->uri_size = 0; - } -#line 133 "http_parser.rl" - { - parser->path_mark = p; - parser->path_size = 0; - } - goto st114; -st114: - if ( ++p == pe ) - goto _test_eof114; -case 114: -#line 3196 "http_parser.c" - switch( (*p) ) { - case 32: goto tr135; - case 35: goto tr136; - case 37: goto st115; - case 60: goto st0; - case 62: goto st0; - case 63: goto tr138; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto st114; -st115: - if ( ++p == pe ) - goto _test_eof115; -case 115: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st116; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st116; - } else - goto st116; - goto st0; -st116: - if ( ++p == pe ) - goto _test_eof116; -case 116: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st114; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st114; - } else - goto st114; - goto st0; -tr138: -#line 193 "http_parser.rl" - { - CALLBACK(path); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->path_mark = NULL; - parser->path_size = 0; - } - goto st117; -st117: - if ( ++p == pe ) - goto _test_eof117; -case 117: -#line 3251 "http_parser.c" - switch( (*p) ) { - case 32: goto tr141; - case 35: goto tr142; - case 37: goto tr143; - case 60: goto st0; - case 62: goto st0; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto tr140; -tr140: -#line 128 "http_parser.rl" - { - parser->query_string_mark = p; - parser->query_string_size = 0; - } - goto st118; -st118: - if ( ++p == pe ) - goto _test_eof118; -case 118: -#line 3274 "http_parser.c" - switch( (*p) ) { - case 32: goto tr145; - case 35: goto tr146; - case 37: goto st119; - case 60: goto st0; - case 62: goto st0; - case 127: goto st0; - } - if ( 0 <= (*p) && (*p) <= 31 ) - goto st0; - goto st118; -tr143: -#line 128 "http_parser.rl" - { - parser->query_string_mark = p; - parser->query_string_size = 0; - } - goto st119; -st119: - if ( ++p == pe ) - goto _test_eof119; -case 119: -#line 3297 "http_parser.c" - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st120; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st120; - } else - goto st120; - goto st0; -st120: - if ( ++p == pe ) - goto _test_eof120; -case 120: - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st118; - } else if ( (*p) > 70 ) { - if ( 97 <= (*p) && (*p) <= 102 ) - goto st118; - } else - goto st118; - goto st0; -tr311: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_res_status_code: + { + if (ch < '0' || ch > '9') { + switch (ch) { + case ' ': + state = s_res_status; + break; + case CR: + state = s_res_line_almost_done; + break; + case LF: + state = s_header_field_start; + break; + default: + return ERROR; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (parser->status_code > 999) return ERROR; + break; } - } - } - goto st121; -st121: - if ( ++p == pe ) - goto _test_eof121; -case 121: -#line 3336 "http_parser.c" - if ( (*p) == 69 ) - goto st122; - goto st0; -st122: - if ( ++p == pe ) - goto _test_eof122; -case 122: - if ( (*p) == 76 ) - goto st123; - goto st0; -st123: - if ( ++p == pe ) - goto _test_eof123; -case 123: - if ( (*p) == 69 ) - goto st124; - goto st0; -st124: - if ( ++p == pe ) - goto _test_eof124; -case 124: - if ( (*p) == 84 ) - goto st125; - goto st0; -st125: - if ( ++p == pe ) - goto _test_eof125; -case 125: - if ( (*p) == 69 ) - goto st126; - goto st0; -st126: - if ( ++p == pe ) - goto _test_eof126; -case 126: - if ( (*p) == 32 ) - goto tr154; - goto st0; -tr312: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_res_status: + /* the human readable status. e.g. "NOT FOUND" + * we are not humans so just ignore this */ + if (ch == CR) { + state = s_res_line_almost_done; + break; + } + + if (ch == LF) { + state = s_header_field_start; + break; + } + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + state = s_header_field_start; + break; + + case s_start_req: + { + parser->flags = 0; + parser->content_length = -1; + + CALLBACK2(message_begin); + + switch (ch) { + /* GET */ + case 'G': + state = s_req_method_G; + break; + + /* POST, PUT */ + case 'P': + state = s_req_method_P; + break; + + /* HEAD */ + case 'H': + state = s_req_method_H; + break; + + /* DELETE */ + case 'D': + state = s_req_method_D; + break; + + case CR: + case LF: + break; + + default: + return ERROR; + } + break; } - } - } - goto st127; -st127: - if ( ++p == pe ) - goto _test_eof127; -case 127: -#line 3391 "http_parser.c" - if ( (*p) == 69 ) - goto st128; - goto st0; -st128: - if ( ++p == pe ) - goto _test_eof128; -case 128: - if ( (*p) == 84 ) - goto st129; - goto st0; -st129: - if ( ++p == pe ) - goto _test_eof129; -case 129: - if ( (*p) == 32 ) - goto tr157; - goto st0; -tr313: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + /* GET */ + + case s_req_method_G: + STRICT_CHECK(ch != 'E'); + state = s_req_method_GE; + break; + + case s_req_method_GE: + STRICT_CHECK(ch != 'T'); + parser->method = HTTP_GET; + state = s_req_spaces_before_url; + break; + + /* HEAD */ + + case s_req_method_H: + STRICT_CHECK(ch != 'E'); + state = s_req_method_HE; + break; + + case s_req_method_HE: + STRICT_CHECK(ch != 'A'); + state = s_req_method_HEA; + break; + + case s_req_method_HEA: + STRICT_CHECK(ch != 'D'); + parser->method = HTTP_HEAD; + state = s_req_spaces_before_url; + break; + + /* POST, PUT */ + + case s_req_method_P: + switch (ch) { + case 'O': + state = s_req_method_PO; + break; + + case 'U': + state = s_req_method_PU; + break; + + default: + return ERROR; + } + break; + + /* PUT */ + + case s_req_method_PU: + STRICT_CHECK(ch != 'T'); + parser->method = HTTP_PUT; + state = s_req_spaces_before_url; + break; + + /* POST */ + + case s_req_method_PO: + STRICT_CHECK(ch != 'S'); + state = s_req_method_POS; + break; + + case s_req_method_POS: + STRICT_CHECK(ch != 'T'); + parser->method = HTTP_POST; + state = s_req_spaces_before_url; + break; + + /* DELETE */ + + case s_req_method_D: + STRICT_CHECK(ch != 'E'); + state = s_req_method_DE; + break; + + case s_req_method_DE: + STRICT_CHECK(ch != 'L'); + state = s_req_method_DEL; + break; + + case s_req_method_DEL: + STRICT_CHECK(ch != 'E'); + state = s_req_method_DELE; + break; + + case s_req_method_DELE: + STRICT_CHECK(ch != 'T'); + state = s_req_method_DELET; + break; + + case s_req_method_DELET: + STRICT_CHECK(ch != 'E'); + parser->method = HTTP_DELETE; + state = s_req_spaces_before_url; + break; + + + case s_req_spaces_before_url: + { + if (ch == ' ') break; + + if (ch == '/') { + MARK(url); + MARK(path); + state = s_req_path; + break; + } + + c = LOWER(ch); + + if (c >= 'a' && c <= 'z') { + MARK(url); + state = s_req_schema; + break; + } + + return ERROR; } - } - } - goto st130; -st130: - if ( ++p == pe ) - goto _test_eof130; -case 130: -#line 3425 "http_parser.c" - if ( (*p) == 69 ) - goto st131; - goto st0; -st131: - if ( ++p == pe ) - goto _test_eof131; -case 131: - if ( (*p) == 65 ) - goto st132; - goto st0; -st132: - if ( ++p == pe ) - goto _test_eof132; -case 132: - if ( (*p) == 68 ) - goto st133; - goto st0; -st133: - if ( ++p == pe ) - goto _test_eof133; -case 133: - if ( (*p) == 32 ) - goto tr161; - goto st0; -tr314: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_schema: + { + c = LOWER(ch); + + if (c >= 'a' && c <= 'z') break; + + if (ch == ':') { + state = s_req_schema_slash; + break; + } + + return ERROR; } - } - } - goto st134; -st134: - if ( ++p == pe ) - goto _test_eof134; -case 134: -#line 3466 "http_parser.c" - if ( (*p) == 79 ) - goto st135; - goto st0; -st135: - if ( ++p == pe ) - goto _test_eof135; -case 135: - if ( (*p) == 67 ) - goto st136; - goto st0; -st136: - if ( ++p == pe ) - goto _test_eof136; -case 136: - if ( (*p) == 75 ) - goto st137; - goto st0; -st137: - if ( ++p == pe ) - goto _test_eof137; -case 137: - if ( (*p) == 32 ) - goto tr165; - goto st0; -tr315: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_schema_slash: + STRICT_CHECK(ch != '/'); + state = s_req_schema_slash_slash; + break; + + case s_req_schema_slash_slash: + STRICT_CHECK(ch != '/'); + state = s_req_host; + break; + + case s_req_host: + { + c = LOWER(ch); + if (c >= 'a' && c <= 'z') break; + if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break; + switch (ch) { + case ':': + state = s_req_port; + break; + case '/': + MARK(path); + state = s_req_path; + break; + case ' ': + /* The request line looks like: + * "GET http://foo.bar.com HTTP/1.1" + * That is, there is no path. + */ + CALLBACK(url); + state = s_req_http_start; + break; + default: + return ERROR; + } + break; } - } - } - goto st138; -st138: - if ( ++p == pe ) - goto _test_eof138; -case 138: -#line 3507 "http_parser.c" - switch( (*p) ) { - case 75: goto st139; - case 79: goto st143; - } - goto st0; -st139: - if ( ++p == pe ) - goto _test_eof139; -case 139: - if ( (*p) == 67 ) - goto st140; - goto st0; -st140: - if ( ++p == pe ) - goto _test_eof140; -case 140: - if ( (*p) == 79 ) - goto st141; - goto st0; -st141: - if ( ++p == pe ) - goto _test_eof141; -case 141: - if ( (*p) == 76 ) - goto st142; - goto st0; -st142: - if ( ++p == pe ) - goto _test_eof142; -case 142: - if ( (*p) == 32 ) - goto tr171; - goto st0; -st143: - if ( ++p == pe ) - goto _test_eof143; -case 143: - if ( (*p) == 86 ) - goto st144; - goto st0; -st144: - if ( ++p == pe ) - goto _test_eof144; -case 144: - if ( (*p) == 69 ) - goto st145; - goto st0; -st145: - if ( ++p == pe ) - goto _test_eof145; -case 145: - if ( (*p) == 32 ) - goto tr174; - goto st0; -tr316: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_port: + { + if (ch >= '0' && ch <= '9') break; + switch (ch) { + case '/': + MARK(path); + state = s_req_path; + break; + case ' ': + /* The request line looks like: + * "GET http://foo.bar.com:1234 HTTP/1.1" + * That is, there is no path. + */ + CALLBACK(url); + state = s_req_http_start; + break; + default: + return ERROR; + } + break; } - } - } - goto st146; -st146: - if ( ++p == pe ) - goto _test_eof146; -case 146: -#line 3578 "http_parser.c" - if ( (*p) == 80 ) - goto st147; - goto st0; -st147: - if ( ++p == pe ) - goto _test_eof147; -case 147: - if ( (*p) == 84 ) - goto st148; - goto st0; -st148: - if ( ++p == pe ) - goto _test_eof148; -case 148: - if ( (*p) == 73 ) - goto st149; - goto st0; -st149: - if ( ++p == pe ) - goto _test_eof149; -case 149: - if ( (*p) == 79 ) - goto st150; - goto st0; -st150: - if ( ++p == pe ) - goto _test_eof150; -case 150: - if ( (*p) == 78 ) - goto st151; - goto st0; -st151: - if ( ++p == pe ) - goto _test_eof151; -case 151: - if ( (*p) == 83 ) - goto st152; - goto st0; -st152: - if ( ++p == pe ) - goto _test_eof152; -case 152: - if ( (*p) == 32 ) - goto tr181; - goto st0; -tr317: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_path: + { + if (usual[ch >> 5] & (1 << (ch & 0x1f))) break; + + switch (ch) { + case ' ': + CALLBACK(url); + CALLBACK(path); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(path); + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(path); + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + CALLBACK(path); + state = s_req_query_string_start; + break; + case '#': + CALLBACK(path); + state = s_req_fragment_start; + break; + default: + return ERROR; + } + break; } - } - } - goto st153; -st153: - if ( ++p == pe ) - goto _test_eof153; -case 153: -#line 3640 "http_parser.c" - switch( (*p) ) { - case 79: goto st154; - case 82: goto st157; - case 85: goto st169; - } - goto st0; -st154: - if ( ++p == pe ) - goto _test_eof154; -case 154: - if ( (*p) == 83 ) - goto st155; - goto st0; -st155: - if ( ++p == pe ) - goto _test_eof155; -case 155: - if ( (*p) == 84 ) - goto st156; - goto st0; -st156: - if ( ++p == pe ) - goto _test_eof156; -case 156: - if ( (*p) == 32 ) - goto tr187; - goto st0; -st157: - if ( ++p == pe ) - goto _test_eof157; -case 157: - if ( (*p) == 79 ) - goto st158; - goto st0; -st158: - if ( ++p == pe ) - goto _test_eof158; -case 158: - if ( (*p) == 80 ) - goto st159; - goto st0; -st159: - if ( ++p == pe ) - goto _test_eof159; -case 159: - switch( (*p) ) { - case 70: goto st160; - case 80: goto st164; - } - goto st0; -st160: - if ( ++p == pe ) - goto _test_eof160; -case 160: - if ( (*p) == 73 ) - goto st161; - goto st0; -st161: - if ( ++p == pe ) - goto _test_eof161; -case 161: - if ( (*p) == 78 ) - goto st162; - goto st0; -st162: - if ( ++p == pe ) - goto _test_eof162; -case 162: - if ( (*p) == 68 ) - goto st163; - goto st0; -st163: - if ( ++p == pe ) - goto _test_eof163; -case 163: - if ( (*p) == 32 ) - goto tr195; - goto st0; -st164: - if ( ++p == pe ) - goto _test_eof164; -case 164: - if ( (*p) == 65 ) - goto st165; - goto st0; -st165: - if ( ++p == pe ) - goto _test_eof165; -case 165: - if ( (*p) == 84 ) - goto st166; - goto st0; -st166: - if ( ++p == pe ) - goto _test_eof166; -case 166: - if ( (*p) == 67 ) - goto st167; - goto st0; -st167: - if ( ++p == pe ) - goto _test_eof167; -case 167: - if ( (*p) == 72 ) - goto st168; - goto st0; -st168: - if ( ++p == pe ) - goto _test_eof168; -case 168: - if ( (*p) == 32 ) - goto tr200; - goto st0; -st169: - if ( ++p == pe ) - goto _test_eof169; -case 169: - if ( (*p) == 84 ) - goto st170; - goto st0; -st170: - if ( ++p == pe ) - goto _test_eof170; -case 170: - if ( (*p) == 32 ) - goto tr202; - goto st0; -tr318: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_query_string_start: + { + if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + MARK(query_string); + state = s_req_query_string; + break; + } + + switch (ch) { + case '?': + break; // XXX ignore extra '?' ... is this right? + case ' ': + CALLBACK(url); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + parser->http_minor = 9; + state = s_header_field_start; + break; + case '#': + state = s_req_fragment_start; + break; + default: + return ERROR; + } + break; } - } - } - goto st171; -st171: - if ( ++p == pe ) - goto _test_eof171; -case 171: -#line 3784 "http_parser.c" - if ( (*p) == 82 ) - goto st172; - goto st0; -st172: - if ( ++p == pe ) - goto _test_eof172; -case 172: - if ( (*p) == 65 ) - goto st173; - goto st0; -st173: - if ( ++p == pe ) - goto _test_eof173; -case 173: - if ( (*p) == 67 ) - goto st174; - goto st0; -st174: - if ( ++p == pe ) - goto _test_eof174; -case 174: - if ( (*p) == 69 ) - goto st175; - goto st0; -st175: - if ( ++p == pe ) - goto _test_eof175; -case 175: - if ( (*p) == 32 ) - goto tr207; - goto st0; -tr319: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_query_string: + { + if (usual[ch >> 5] & (1 << (ch & 0x1f))) break; + + switch (ch) { + case ' ': + CALLBACK(url); + CALLBACK(query_string); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(query_string); + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(query_string); + parser->http_minor = 9; + state = s_header_field_start; + break; + case '#': + CALLBACK(query_string); + state = s_req_fragment_start; + break; + default: + return ERROR; + } + break; } - } - } - goto st176; -st176: - if ( ++p == pe ) - goto _test_eof176; -case 176: -#line 3832 "http_parser.c" - if ( (*p) == 78 ) - goto st177; - goto st0; -st177: - if ( ++p == pe ) - goto _test_eof177; -case 177: - if ( (*p) == 76 ) - goto st178; - goto st0; -st178: - if ( ++p == pe ) - goto _test_eof178; -case 178: - if ( (*p) == 79 ) - goto st179; - goto st0; -st179: - if ( ++p == pe ) - goto _test_eof179; -case 179: - if ( (*p) == 67 ) - goto st180; - goto st0; -st180: - if ( ++p == pe ) - goto _test_eof180; -case 180: - if ( (*p) == 75 ) - goto st181; - goto st0; -st181: - if ( ++p == pe ) - goto _test_eof181; -case 181: - if ( (*p) == 32 ) - goto tr213; - goto st0; -tr232: - cs = 269; -#line 203 "http_parser.rl" - { - if(parser->on_headers_complete) { - callback_return_value = parser->on_headers_complete(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + case s_req_fragment_start: + { + if (usual[ch >> 5] & (1 << (ch & 0x1f))) { + MARK(fragment); + state = s_req_fragment; + break; + } + + switch (ch) { + case ' ': + CALLBACK(url); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + MARK(fragment); + state = s_req_fragment; + break; + case '#': + break; + default: + return ERROR; + } + break; } - } - } -#line 282 "http_parser.rl" - { - if (parser->transfer_encoding == HTTP_CHUNKED) { - cs = 2; - } else { - /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ - parser->chunk_size = parser->content_length; - p += 1; - SKIP_BODY(MIN(REMAINING, parser->content_length)); + case s_req_fragment: + { + if (usual[ch >> 5] & (1 << (ch & 0x1f))) break; - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + switch (ch) { + case ' ': + CALLBACK(url); + CALLBACK(fragment); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(fragment); + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(fragment); + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + case '#': + break; + default: + return ERROR; + } + break; } - p--; - if(parser->chunk_size > REMAINING) { - {p++; goto _out;} + case s_req_http_start: + switch (ch) { + case 'H': + state = s_req_http_H; + break; + case ' ': + break; + default: + return ERROR; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + state = s_req_http_HT; + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + state = s_req_http_HTT; + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + state = s_req_http_HTTP; + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + state = s_req_first_http_major; + break; + + /* first digit of major HTTP version */ + case s_req_first_http_major: + if (ch < '1' || ch > '9') return ERROR; + parser->http_major = ch - '0'; + state = s_req_http_major; + break; + + /* major HTTP version or dot */ + case s_req_http_major: + { + if (ch == '.') { + state = s_req_first_http_minor; + break; + } + + if (ch < '0' || ch > '9') return ERROR; + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) return ERROR; + break; } - } - } - goto _again; -st269: - if ( ++p == pe ) - goto _test_eof269; -case 269: -#line 3910 "http_parser.c" - if ( (*p) == 72 ) - goto tr320; - goto st0; -tr320: -#line 213 "http_parser.rl" - { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; + + /* first digit of minor HTTP version */ + case s_req_first_http_minor: + if (ch < '0' || ch > '9') return ERROR; + parser->http_minor = ch - '0'; + state = s_req_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_req_http_minor: + { + if (ch == CR) { + state = s_req_line_almost_done; + break; + } + + if (ch == LF) { + state = s_header_field_start; + break; + } + + /* XXX allow spaces after digit? */ + + if (ch < '0' || ch > '9') return ERROR; + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) return ERROR; + break; } + + /* end of request line */ + case s_req_line_almost_done: + { + if (ch != LF) return ERROR; + state = s_header_field_start; + break; + } + + case s_header_field_start: + { + if (ch == CR) { + state = s_headers_almost_done; + break; + } + + if (ch == LF) { + state = s_headers_done; + break; + } + + c = LOWER(ch); + + if (c < 'a' || 'z' < c) return ERROR; + + MARK(header_field); + + header_index = 0; + state = s_header_field; + + switch (c) { + case 'c': + header_state = h_C; + break; + + case 't': + header_state = h_matching_transfer_encoding; + break; + + default: + header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + c = lowcase[(int)ch]; + + if (c) { + switch (header_state) { + case h_general: + break; + + case h_C: + header_index++; + header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + header_index++; + header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + header_index++; + switch (c) { + case 'n': + header_state = h_matching_connection; + break; + case 't': + header_state = h_matching_content_length; + break; + default: + header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + header_index++; + if (header_index > sizeof(CONNECTION)-1 + || c != CONNECTION[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(CONNECTION)-2) { + header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + header_index++; + if (header_index > sizeof(CONTENT_LENGTH)-1 + || c != CONTENT_LENGTH[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(CONTENT_LENGTH)-2) { + header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + header_index++; + if (header_index > sizeof(TRANSFER_ENCODING)-1 + || c != TRANSFER_ENCODING[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(TRANSFER_ENCODING)-2) { + header_state = h_transfer_encoding; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + if (ch != ' ') header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + break; + } + + if (ch == ':') { + CALLBACK(header_field); + state = s_header_value_start; + break; + } + + if (ch == CR) { + state = s_header_almost_done; + CALLBACK(header_field); + break; + } + + if (ch == LF) { + CALLBACK(header_field); + state = s_header_field_start; + break; + } + + return ERROR; + } + + case s_header_value_start: + { + if (ch == ' ') break; + + MARK(header_value); + + state = s_header_value; + header_index = 0; + + c = lowcase[(int)ch]; + + if (!c) { + if (ch == CR) { + header_state = h_general; + state = s_header_almost_done; + break; + } + + if (ch == LF) { + state = s_header_field_start; + break; + } + + header_state = h_general; + break; + } + + switch (header_state) { + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) { + header_state = h_matching_transfer_encoding_chunked; + } else { + header_state = h_general; + } + break; + + case h_content_length: + if (ch < '0' || ch > '9') return ERROR; + parser->content_length = ch - '0'; + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + header_state = h_matching_connection_close; + } else { + header_state = h_general; + } + break; + + default: + header_state = h_general; + break; + } + break; + } + + case s_header_value: + { + c = lowcase[(int)ch]; + + if (!c) { + if (ch == CR) { + CALLBACK(header_value); + state = s_header_almost_done; + break; + } + + if (ch == LF) { + CALLBACK(header_value); + state = s_header_field_start; + break; + } + break; + } + + switch (header_state) { + case h_general: + break; + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + if (ch < '0' || ch > '9') return ERROR; + parser->content_length *= 10; + parser->content_length += ch - '0'; + break; + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + header_index++; + if (header_index > sizeof(CHUNKED)-1 + || c != CHUNKED[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(CHUNKED)-2) { + header_state = h_transfer_encoding_chunked; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + header_index++; + if (header_index > sizeof(KEEP_ALIVE)-1 + || c != KEEP_ALIVE[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(KEEP_ALIVE)-2) { + header_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + header_index++; + if (header_index > sizeof(CLOSE)-1 || c != CLOSE[header_index]) { + header_state = h_general; + } else if (header_index == sizeof(CLOSE)-2) { + header_state = h_connection_close; + } + break; + + case h_transfer_encoding_chunked: + case h_connection_keep_alive: + case h_connection_close: + if (ch != ' ') header_state = h_general; + break; + + default: + state = s_header_value; + header_state = h_general; + break; + } + break; + } + + case s_header_almost_done: + { + STRICT_CHECK(ch != LF); + + state = s_header_field_start; + + switch (header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + default: + break; + } + break; + } + + case s_headers_almost_done: + { + STRICT_CHECK(ch != LF); + + if (parser->flags & F_TRAILING) { + /* End of a chunked request */ + CALLBACK2(message_complete); + state = http_should_keep_alive(parser) ? start_state : s_dead; + break; + } + + parser->body_read = 0; + + CALLBACK2(headers_complete); + + if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + state = s_chunk_size_start; + } else { + if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + CALLBACK2(message_complete); + state = http_should_keep_alive(parser) ? start_state : s_dead; + } else if (parser->content_length > 0) { + /* Content-Length header given and non-zero */ + state = s_body_identity; + } else { + if (start_state == s_start_req || http_should_keep_alive(parser)) { + /* Assume content-length 0 - read the next */ + CALLBACK2(message_complete); + state = http_should_keep_alive(parser) ? start_state : s_dead; + } else { + /* Read body until EOF */ + state = s_body_identity_eof; + } + } + } + + break; + } + + case s_body_identity: + to_read = MIN(pe - p, (ssize_t)(parser->content_length - parser->body_read)); + if (to_read > 0) { + if (parser->on_body) parser->on_body(parser, p, to_read); + p += to_read - 1; + parser->body_read += to_read; + if (parser->body_read == parser->content_length) { + CALLBACK2(message_complete); + state = http_should_keep_alive(parser) ? start_state : s_dead; + } + } + break; + + /* read until EOF */ + case s_body_identity_eof: + to_read = pe - p; + if (to_read > 0) { + if (parser->on_body) parser->on_body(parser, p, to_read); + p += to_read - 1; + parser->body_read += to_read; + } + break; + + case s_chunk_size_start: + { + assert(parser->flags & F_CHUNKED); + + c = unhex[(int)ch]; + if (c == -1) return ERROR; + parser->content_length = c; + state = s_chunk_size; + break; + } + + case s_chunk_size: + { + assert(parser->flags & F_CHUNKED); + + if (ch == CR) { + state = s_chunk_size_almost_done; + break; + } + + c = unhex[(int)ch]; + + if (c == -1) { + if (ch == ';' || ch == ' ') { + state = s_chunk_parameters; + break; + } + return ERROR; + } + + parser->content_length *= 16; + parser->content_length += c; + break; + } + + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) { + state = s_chunk_size_almost_done; + break; + } + break; + } + + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + + if (parser->content_length == 0) { + parser->flags |= F_TRAILING; + state = s_header_field_start; + } else { + state = s_chunk_data; + } + break; + } + + case s_chunk_data: + { + assert(parser->flags & F_CHUNKED); + + to_read = MIN(pe - p, (ssize_t)(parser->content_length)); + + if (to_read > 0) { + if (parser->on_body) parser->on_body(parser, p, to_read); + p += to_read - 1; + } + + if (to_read == parser->content_length) { + state = s_chunk_data_almost_done; + } + + parser->content_length -= to_read; + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != CR); + state = s_chunk_data_done; + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + state = s_chunk_size_start; + break; + + default: + assert(0 && "unhandled state"); + return ERROR; } } - goto st182; -st182: - if ( ++p == pe ) - goto _test_eof182; -case 182: -#line 3930 "http_parser.c" - if ( (*p) == 84 ) - goto st183; - goto st0; -st183: - if ( ++p == pe ) - goto _test_eof183; -case 183: - if ( (*p) == 84 ) - goto st184; - goto st0; -st184: - if ( ++p == pe ) - goto _test_eof184; -case 184: - if ( (*p) == 80 ) - goto st185; - goto st0; -st185: - if ( ++p == pe ) - goto _test_eof185; -case 185: - if ( (*p) == 47 ) - goto st186; - goto st0; -st186: - if ( ++p == pe ) - goto _test_eof186; -case 186: - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr218; - goto st0; -tr218: -#line 243 "http_parser.rl" - { - parser->version_major *= 10; - parser->version_major += *p - '0'; - } - goto st187; -st187: - if ( ++p == pe ) - goto _test_eof187; -case 187: -#line 3973 "http_parser.c" - if ( (*p) == 46 ) - goto st188; - goto st0; -st188: - if ( ++p == pe ) - goto _test_eof188; -case 188: - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr220; - goto st0; -tr220: -#line 248 "http_parser.rl" - { - parser->version_minor *= 10; - parser->version_minor += *p - '0'; - } - goto st189; -st189: - if ( ++p == pe ) - goto _test_eof189; -case 189: -#line 3995 "http_parser.c" - if ( (*p) == 32 ) - goto st190; - goto st0; -st190: - if ( ++p == pe ) - goto _test_eof190; -case 190: - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr222; - goto st0; -tr222: -#line 232 "http_parser.rl" - { - parser->status_code *= 10; - parser->status_code += *p - '0'; - } - goto st191; -st191: - if ( ++p == pe ) - goto _test_eof191; -case 191: -#line 4017 "http_parser.c" - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr223; - goto st0; -tr223: -#line 232 "http_parser.rl" - { - parser->status_code *= 10; - parser->status_code += *p - '0'; - } - goto st192; -st192: - if ( ++p == pe ) - goto _test_eof192; -case 192: -#line 4032 "http_parser.c" - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr224; - goto st0; -tr224: -#line 232 "http_parser.rl" - { - parser->status_code *= 10; - parser->status_code += *p - '0'; - } - goto st193; -st193: - if ( ++p == pe ) - goto _test_eof193; -case 193: -#line 4047 "http_parser.c" - switch( (*p) ) { - case 13: goto st194; - case 32: goto st265; - } - goto st0; -tr236: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st194; -tr239: -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st194; -tr258: -#line 241 "http_parser.rl" - { parser->keep_alive = FALSE; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st194; -tr268: -#line 240 "http_parser.rl" - { parser->keep_alive = TRUE; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st194; -tr309: -#line 237 "http_parser.rl" - { parser->transfer_encoding = HTTP_IDENTITY; } -#line 153 "http_parser.rl" - { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - goto st194; -st194: - if ( ++p == pe ) - goto _test_eof194; -case 194: -#line 4128 "http_parser.c" - if ( (*p) == 10 ) - goto st195; - goto st0; -st195: - if ( ++p == pe ) - goto _test_eof195; -case 195: - switch( (*p) ) { - case 13: goto st196; - case 33: goto tr229; - case 67: goto tr230; - case 84: goto tr231; - case 99: goto tr230; - case 116: goto tr231; - case 124: goto tr229; - case 126: goto tr229; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto tr229; - } else if ( (*p) >= 35 ) - goto tr229; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr229; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto tr229; - } else - goto tr229; - } else - goto tr229; - goto st0; -st196: - if ( ++p == pe ) - goto _test_eof196; -case 196: - if ( (*p) == 10 ) - goto tr232; - goto st0; -tr229: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st197; -st197: - if ( ++p == pe ) - goto _test_eof197; -case 197: -#line 4182 "http_parser.c" - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -tr234: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st198; -st198: - if ( ++p == pe ) - goto _test_eof198; -case 198: -#line 4223 "http_parser.c" - switch( (*p) ) { - case 13: goto tr236; - case 32: goto st198; - } - goto tr235; -tr235: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st199; -st199: - if ( ++p == pe ) - goto _test_eof199; -case 199: -#line 4240 "http_parser.c" - if ( (*p) == 13 ) - goto tr239; - goto st199; -tr230: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st200; -st200: - if ( ++p == pe ) - goto _test_eof200; -case 200: -#line 4255 "http_parser.c" - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 79: goto st201; - case 111: goto st201; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st201: - if ( ++p == pe ) - goto _test_eof201; -case 201: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st202; - case 110: goto st202; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st202: - if ( ++p == pe ) - goto _test_eof202; -case 202: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st203; - case 84: goto st226; - case 110: goto st203; - case 116: goto st226; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st203: - if ( ++p == pe ) - goto _test_eof203; -case 203: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 69: goto st204; - case 101: goto st204; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st204: - if ( ++p == pe ) - goto _test_eof204; -case 204: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 67: goto st205; - case 99: goto st205; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st205: - if ( ++p == pe ) - goto _test_eof205; -case 205: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 84: goto st206; - case 116: goto st206; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st206: - if ( ++p == pe ) - goto _test_eof206; -case 206: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 73: goto st207; - case 105: goto st207; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st207: - if ( ++p == pe ) - goto _test_eof207; -case 207: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 79: goto st208; - case 111: goto st208; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st208: - if ( ++p == pe ) - goto _test_eof208; -case 208: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st209; - case 110: goto st209; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st209: - if ( ++p == pe ) - goto _test_eof209; -case 209: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr250; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -tr250: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st210; -st210: - if ( ++p == pe ) - goto _test_eof210; -case 210: -#line 4568 "http_parser.c" - switch( (*p) ) { - case 13: goto tr236; - case 32: goto st210; - case 67: goto tr252; - case 75: goto tr253; - case 99: goto tr252; - case 107: goto tr253; - } - goto tr235; -tr252: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st211; -st211: - if ( ++p == pe ) - goto _test_eof211; -case 211: -#line 4589 "http_parser.c" - switch( (*p) ) { - case 13: goto tr239; - case 76: goto st212; - case 108: goto st212; - } - goto st199; -st212: - if ( ++p == pe ) - goto _test_eof212; -case 212: - switch( (*p) ) { - case 13: goto tr239; - case 79: goto st213; - case 111: goto st213; - } - goto st199; -st213: - if ( ++p == pe ) - goto _test_eof213; -case 213: - switch( (*p) ) { - case 13: goto tr239; - case 83: goto st214; - case 115: goto st214; - } - goto st199; -st214: - if ( ++p == pe ) - goto _test_eof214; -case 214: - switch( (*p) ) { - case 13: goto tr239; - case 69: goto st215; - case 101: goto st215; - } - goto st199; -st215: - if ( ++p == pe ) - goto _test_eof215; -case 215: - if ( (*p) == 13 ) - goto tr258; - goto st199; -tr253: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st216; -st216: - if ( ++p == pe ) - goto _test_eof216; -case 216: -#line 4644 "http_parser.c" - switch( (*p) ) { - case 13: goto tr239; - case 69: goto st217; - case 101: goto st217; - } - goto st199; -st217: - if ( ++p == pe ) - goto _test_eof217; -case 217: - switch( (*p) ) { - case 13: goto tr239; - case 69: goto st218; - case 101: goto st218; - } - goto st199; -st218: - if ( ++p == pe ) - goto _test_eof218; -case 218: - switch( (*p) ) { - case 13: goto tr239; - case 80: goto st219; - case 112: goto st219; - } - goto st199; -st219: - if ( ++p == pe ) - goto _test_eof219; -case 219: - switch( (*p) ) { - case 13: goto tr239; - case 45: goto st220; - } - goto st199; -st220: - if ( ++p == pe ) - goto _test_eof220; -case 220: - switch( (*p) ) { - case 13: goto tr239; - case 65: goto st221; - case 97: goto st221; - } - goto st199; -st221: - if ( ++p == pe ) - goto _test_eof221; -case 221: - switch( (*p) ) { - case 13: goto tr239; - case 76: goto st222; - case 108: goto st222; - } - goto st199; -st222: - if ( ++p == pe ) - goto _test_eof222; -case 222: - switch( (*p) ) { - case 13: goto tr239; - case 73: goto st223; - case 105: goto st223; - } - goto st199; -st223: - if ( ++p == pe ) - goto _test_eof223; -case 223: - switch( (*p) ) { - case 13: goto tr239; - case 86: goto st224; - case 118: goto st224; - } - goto st199; -st224: - if ( ++p == pe ) - goto _test_eof224; -case 224: - switch( (*p) ) { - case 13: goto tr239; - case 69: goto st225; - case 101: goto st225; - } - goto st199; -st225: - if ( ++p == pe ) - goto _test_eof225; -case 225: - if ( (*p) == 13 ) - goto tr268; - goto st199; -st226: - if ( ++p == pe ) - goto _test_eof226; -case 226: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 69: goto st227; - case 101: goto st227; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st227: - if ( ++p == pe ) - goto _test_eof227; -case 227: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st228; - case 110: goto st228; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st228: - if ( ++p == pe ) - goto _test_eof228; -case 228: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 84: goto st229; - case 116: goto st229; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st229: - if ( ++p == pe ) - goto _test_eof229; -case 229: - switch( (*p) ) { - case 33: goto st197; - case 45: goto st230; - case 46: goto st197; - case 58: goto tr234; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 48 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 57 ) { - if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else if ( (*p) >= 65 ) - goto st197; - } else - goto st197; - goto st0; -st230: - if ( ++p == pe ) - goto _test_eof230; -case 230: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 76: goto st231; - case 108: goto st231; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st231: - if ( ++p == pe ) - goto _test_eof231; -case 231: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 69: goto st232; - case 101: goto st232; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st232: - if ( ++p == pe ) - goto _test_eof232; -case 232: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st233; - case 110: goto st233; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st233: - if ( ++p == pe ) - goto _test_eof233; -case 233: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 71: goto st234; - case 103: goto st234; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st234: - if ( ++p == pe ) - goto _test_eof234; -case 234: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 84: goto st235; - case 116: goto st235; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st235: - if ( ++p == pe ) - goto _test_eof235; -case 235: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 72: goto st236; - case 104: goto st236; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st236: - if ( ++p == pe ) - goto _test_eof236; -case 236: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr279; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -tr279: -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st237; -st237: - if ( ++p == pe ) - goto _test_eof237; -case 237: -#line 5078 "http_parser.c" - switch( (*p) ) { - case 13: goto tr236; - case 32: goto st237; - } - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr281; - goto tr235; -tr281: -#line 223 "http_parser.rl" - { - if (parser->content_length > INT_MAX) { - parser->error = TRUE; - return 0; - } - parser->content_length *= 10; - parser->content_length += *p - '0'; - } -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - goto st238; -tr282: -#line 223 "http_parser.rl" - { - if (parser->content_length > INT_MAX) { - parser->error = TRUE; + + CALLBACK_NOCLEAR(header_field); + CALLBACK_NOCLEAR(header_value); + CALLBACK_NOCLEAR(fragment); + CALLBACK_NOCLEAR(query_string); + CALLBACK_NOCLEAR(path); + CALLBACK_NOCLEAR(url); + + parser->state = state; + parser->header_state = header_state; + parser->header_index = header_index; + + return len; +} + + +size_t +http_parse_requests (http_parser *parser, const char *data, size_t len) +{ + if (!parser->state) parser->state = s_start_req; + return parse(parser, data, len, s_start_req); +} + + +size_t +http_parse_responses (http_parser *parser, const char *data, size_t len) +{ + if (!parser->state) parser->state = s_start_res; + return parse(parser, data, len, s_start_res); +} + + +int +http_should_keep_alive (http_parser *parser) +{ + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { return 0; + } else { + return 1; } - parser->content_length *= 10; - parser->content_length += *p - '0'; - } - goto st238; -st238: - if ( ++p == pe ) - goto _test_eof238; -case 238: -#line 5117 "http_parser.c" - if ( (*p) == 13 ) - goto tr239; - if ( 48 <= (*p) && (*p) <= 57 ) - goto tr282; - goto st199; -tr231: -#line 113 "http_parser.rl" - { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - goto st239; -st239: - if ( ++p == pe ) - goto _test_eof239; -case 239: -#line 5134 "http_parser.c" - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 82: goto st240; - case 114: goto st240; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st240: - if ( ++p == pe ) - goto _test_eof240; -case 240: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 65: goto st241; - case 97: goto st241; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 66 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st241: - if ( ++p == pe ) - goto _test_eof241; -case 241: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st242; - case 110: goto st242; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st242: - if ( ++p == pe ) - goto _test_eof242; -case 242: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 83: goto st243; - case 115: goto st243; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st243: - if ( ++p == pe ) - goto _test_eof243; -case 243: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 70: goto st244; - case 102: goto st244; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st244: - if ( ++p == pe ) - goto _test_eof244; -case 244: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 69: goto st245; - case 101: goto st245; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st245: - if ( ++p == pe ) - goto _test_eof245; -case 245: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 82: goto st246; - case 114: goto st246; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st246: - if ( ++p == pe ) - goto _test_eof246; -case 246: - switch( (*p) ) { - case 33: goto st197; - case 45: goto st247; - case 46: goto st197; - case 58: goto tr234; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 48 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 57 ) { - if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else if ( (*p) >= 65 ) - goto st197; - } else - goto st197; - goto st0; -st247: - if ( ++p == pe ) - goto _test_eof247; -case 247: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 69: goto st248; - case 101: goto st248; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st248: - if ( ++p == pe ) - goto _test_eof248; -case 248: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st249; - case 110: goto st249; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st249: - if ( ++p == pe ) - goto _test_eof249; -case 249: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 67: goto st250; - case 99: goto st250; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st250: - if ( ++p == pe ) - goto _test_eof250; -case 250: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 79: goto st251; - case 111: goto st251; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st251: - if ( ++p == pe ) - goto _test_eof251; -case 251: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 68: goto st252; - case 100: goto st252; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st252: - if ( ++p == pe ) - goto _test_eof252; -case 252: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 73: goto st253; - case 105: goto st253; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st253: - if ( ++p == pe ) - goto _test_eof253; -case 253: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 78: goto st254; - case 110: goto st254; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st254: - if ( ++p == pe ) - goto _test_eof254; -case 254: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr234; - case 71: goto st255; - case 103: goto st255; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -st255: - if ( ++p == pe ) - goto _test_eof255; -case 255: - switch( (*p) ) { - case 33: goto st197; - case 58: goto tr299; - case 124: goto st197; - case 126: goto st197; - } - if ( (*p) < 45 ) { - if ( (*p) > 39 ) { - if ( 42 <= (*p) && (*p) <= 43 ) - goto st197; - } else if ( (*p) >= 35 ) - goto st197; - } else if ( (*p) > 46 ) { - if ( (*p) < 65 ) { - if ( 48 <= (*p) && (*p) <= 57 ) - goto st197; - } else if ( (*p) > 90 ) { - if ( 94 <= (*p) && (*p) <= 122 ) - goto st197; - } else - goto st197; - } else - goto st197; - goto st0; -tr299: -#line 238 "http_parser.rl" - { parser->transfer_encoding = HTTP_CHUNKED; } -#line 143 "http_parser.rl" - { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; + } else { + /* HTTP/1.0 or earlier */ + if (parser->flags & F_CONNECTION_KEEP_ALIVE) { + return 1; + } else { return 0; } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - goto st256; -st256: - if ( ++p == pe ) - goto _test_eof256; -case 256: -#line 5654 "http_parser.c" - switch( (*p) ) { - case 13: goto tr236; - case 32: goto st256; - case 105: goto tr301; - } - goto tr235; -tr301: -#line 118 "http_parser.rl" - { - parser->header_value_mark = p; - parser->header_value_size = 0; } - goto st257; -st257: - if ( ++p == pe ) - goto _test_eof257; -case 257: -#line 5672 "http_parser.c" - switch( (*p) ) { - case 13: goto tr239; - case 100: goto st258; - } - goto st199; -st258: - if ( ++p == pe ) - goto _test_eof258; -case 258: - switch( (*p) ) { - case 13: goto tr239; - case 101: goto st259; - } - goto st199; -st259: - if ( ++p == pe ) - goto _test_eof259; -case 259: - switch( (*p) ) { - case 13: goto tr239; - case 110: goto st260; - } - goto st199; -st260: - if ( ++p == pe ) - goto _test_eof260; -case 260: - switch( (*p) ) { - case 13: goto tr239; - case 116: goto st261; - } - goto st199; -st261: - if ( ++p == pe ) - goto _test_eof261; -case 261: - switch( (*p) ) { - case 13: goto tr239; - case 105: goto st262; - } - goto st199; -st262: - if ( ++p == pe ) - goto _test_eof262; -case 262: - switch( (*p) ) { - case 13: goto tr239; - case 116: goto st263; - } - goto st199; -st263: - if ( ++p == pe ) - goto _test_eof263; -case 263: - switch( (*p) ) { - case 13: goto tr239; - case 121: goto st264; - } - goto st199; -st264: - if ( ++p == pe ) - goto _test_eof264; -case 264: - if ( (*p) == 13 ) - goto tr309; - goto st199; -st265: - if ( ++p == pe ) - goto _test_eof265; -case 265: - if ( (*p) == 13 ) - goto st194; - if ( (*p) > 9 ) { - if ( 11 <= (*p) ) - goto st265; - } else if ( (*p) >= 0 ) - goto st265; - goto st0; - } - _test_eof1: cs = 1; goto _test_eof; - _test_eof266: cs = 266; goto _test_eof; - _test_eof2: cs = 2; goto _test_eof; - _test_eof3: cs = 3; goto _test_eof; - _test_eof4: cs = 4; goto _test_eof; - _test_eof5: cs = 5; goto _test_eof; - _test_eof6: cs = 6; goto _test_eof; - _test_eof267: cs = 267; goto _test_eof; - _test_eof7: cs = 7; goto _test_eof; - _test_eof8: cs = 8; goto _test_eof; - _test_eof9: cs = 9; goto _test_eof; - _test_eof10: cs = 10; goto _test_eof; - _test_eof11: cs = 11; goto _test_eof; - _test_eof12: cs = 12; goto _test_eof; - _test_eof13: cs = 13; goto _test_eof; - _test_eof14: cs = 14; goto _test_eof; - _test_eof15: cs = 15; goto _test_eof; - _test_eof16: cs = 16; goto _test_eof; - _test_eof17: cs = 17; goto _test_eof; - _test_eof18: cs = 18; goto _test_eof; - _test_eof19: cs = 19; goto _test_eof; - _test_eof268: cs = 268; goto _test_eof; - _test_eof20: cs = 20; goto _test_eof; - _test_eof21: cs = 21; goto _test_eof; - _test_eof22: cs = 22; goto _test_eof; - _test_eof23: cs = 23; goto _test_eof; - _test_eof24: cs = 24; goto _test_eof; - _test_eof25: cs = 25; goto _test_eof; - _test_eof26: cs = 26; goto _test_eof; - _test_eof27: cs = 27; goto _test_eof; - _test_eof28: cs = 28; goto _test_eof; - _test_eof29: cs = 29; goto _test_eof; - _test_eof30: cs = 30; goto _test_eof; - _test_eof31: cs = 31; goto _test_eof; - _test_eof32: cs = 32; goto _test_eof; - _test_eof33: cs = 33; goto _test_eof; - _test_eof34: cs = 34; goto _test_eof; - _test_eof35: cs = 35; goto _test_eof; - _test_eof36: cs = 36; goto _test_eof; - _test_eof37: cs = 37; goto _test_eof; - _test_eof38: cs = 38; goto _test_eof; - _test_eof39: cs = 39; goto _test_eof; - _test_eof40: cs = 40; goto _test_eof; - _test_eof41: cs = 41; goto _test_eof; - _test_eof42: cs = 42; goto _test_eof; - _test_eof43: cs = 43; goto _test_eof; - _test_eof44: cs = 44; goto _test_eof; - _test_eof45: cs = 45; goto _test_eof; - _test_eof46: cs = 46; goto _test_eof; - _test_eof47: cs = 47; goto _test_eof; - _test_eof48: cs = 48; goto _test_eof; - _test_eof49: cs = 49; goto _test_eof; - _test_eof50: cs = 50; goto _test_eof; - _test_eof51: cs = 51; goto _test_eof; - _test_eof52: cs = 52; goto _test_eof; - _test_eof53: cs = 53; goto _test_eof; - _test_eof54: cs = 54; goto _test_eof; - _test_eof55: cs = 55; goto _test_eof; - _test_eof56: cs = 56; goto _test_eof; - _test_eof57: cs = 57; goto _test_eof; - _test_eof58: cs = 58; goto _test_eof; - _test_eof59: cs = 59; goto _test_eof; - _test_eof60: cs = 60; goto _test_eof; - _test_eof61: cs = 61; goto _test_eof; - _test_eof62: cs = 62; goto _test_eof; - _test_eof63: cs = 63; goto _test_eof; - _test_eof64: cs = 64; goto _test_eof; - _test_eof65: cs = 65; goto _test_eof; - _test_eof66: cs = 66; goto _test_eof; - _test_eof67: cs = 67; goto _test_eof; - _test_eof68: cs = 68; goto _test_eof; - _test_eof69: cs = 69; goto _test_eof; - _test_eof70: cs = 70; goto _test_eof; - _test_eof71: cs = 71; goto _test_eof; - _test_eof72: cs = 72; goto _test_eof; - _test_eof73: cs = 73; goto _test_eof; - _test_eof74: cs = 74; goto _test_eof; - _test_eof75: cs = 75; goto _test_eof; - _test_eof76: cs = 76; goto _test_eof; - _test_eof77: cs = 77; goto _test_eof; - _test_eof78: cs = 78; goto _test_eof; - _test_eof79: cs = 79; goto _test_eof; - _test_eof80: cs = 80; goto _test_eof; - _test_eof81: cs = 81; goto _test_eof; - _test_eof82: cs = 82; goto _test_eof; - _test_eof83: cs = 83; goto _test_eof; - _test_eof84: cs = 84; goto _test_eof; - _test_eof85: cs = 85; goto _test_eof; - _test_eof86: cs = 86; goto _test_eof; - _test_eof87: cs = 87; goto _test_eof; - _test_eof88: cs = 88; goto _test_eof; - _test_eof89: cs = 89; goto _test_eof; - _test_eof90: cs = 90; goto _test_eof; - _test_eof91: cs = 91; goto _test_eof; - _test_eof92: cs = 92; goto _test_eof; - _test_eof93: cs = 93; goto _test_eof; - _test_eof94: cs = 94; goto _test_eof; - _test_eof95: cs = 95; goto _test_eof; - _test_eof96: cs = 96; goto _test_eof; - _test_eof97: cs = 97; goto _test_eof; - _test_eof98: cs = 98; goto _test_eof; - _test_eof99: cs = 99; goto _test_eof; - _test_eof100: cs = 100; goto _test_eof; - _test_eof101: cs = 101; goto _test_eof; - _test_eof102: cs = 102; goto _test_eof; - _test_eof103: cs = 103; goto _test_eof; - _test_eof104: cs = 104; goto _test_eof; - _test_eof105: cs = 105; goto _test_eof; - _test_eof106: cs = 106; goto _test_eof; - _test_eof107: cs = 107; goto _test_eof; - _test_eof108: cs = 108; goto _test_eof; - _test_eof109: cs = 109; goto _test_eof; - _test_eof110: cs = 110; goto _test_eof; - _test_eof111: cs = 111; goto _test_eof; - _test_eof112: cs = 112; goto _test_eof; - _test_eof113: cs = 113; goto _test_eof; - _test_eof114: cs = 114; goto _test_eof; - _test_eof115: cs = 115; goto _test_eof; - _test_eof116: cs = 116; goto _test_eof; - _test_eof117: cs = 117; goto _test_eof; - _test_eof118: cs = 118; goto _test_eof; - _test_eof119: cs = 119; goto _test_eof; - _test_eof120: cs = 120; goto _test_eof; - _test_eof121: cs = 121; goto _test_eof; - _test_eof122: cs = 122; goto _test_eof; - _test_eof123: cs = 123; goto _test_eof; - _test_eof124: cs = 124; goto _test_eof; - _test_eof125: cs = 125; goto _test_eof; - _test_eof126: cs = 126; goto _test_eof; - _test_eof127: cs = 127; goto _test_eof; - _test_eof128: cs = 128; goto _test_eof; - _test_eof129: cs = 129; goto _test_eof; - _test_eof130: cs = 130; goto _test_eof; - _test_eof131: cs = 131; goto _test_eof; - _test_eof132: cs = 132; goto _test_eof; - _test_eof133: cs = 133; goto _test_eof; - _test_eof134: cs = 134; goto _test_eof; - _test_eof135: cs = 135; goto _test_eof; - _test_eof136: cs = 136; goto _test_eof; - _test_eof137: cs = 137; goto _test_eof; - _test_eof138: cs = 138; goto _test_eof; - _test_eof139: cs = 139; goto _test_eof; - _test_eof140: cs = 140; goto _test_eof; - _test_eof141: cs = 141; goto _test_eof; - _test_eof142: cs = 142; goto _test_eof; - _test_eof143: cs = 143; goto _test_eof; - _test_eof144: cs = 144; goto _test_eof; - _test_eof145: cs = 145; goto _test_eof; - _test_eof146: cs = 146; goto _test_eof; - _test_eof147: cs = 147; goto _test_eof; - _test_eof148: cs = 148; goto _test_eof; - _test_eof149: cs = 149; goto _test_eof; - _test_eof150: cs = 150; goto _test_eof; - _test_eof151: cs = 151; goto _test_eof; - _test_eof152: cs = 152; goto _test_eof; - _test_eof153: cs = 153; goto _test_eof; - _test_eof154: cs = 154; goto _test_eof; - _test_eof155: cs = 155; goto _test_eof; - _test_eof156: cs = 156; goto _test_eof; - _test_eof157: cs = 157; goto _test_eof; - _test_eof158: cs = 158; goto _test_eof; - _test_eof159: cs = 159; goto _test_eof; - _test_eof160: cs = 160; goto _test_eof; - _test_eof161: cs = 161; goto _test_eof; - _test_eof162: cs = 162; goto _test_eof; - _test_eof163: cs = 163; goto _test_eof; - _test_eof164: cs = 164; goto _test_eof; - _test_eof165: cs = 165; goto _test_eof; - _test_eof166: cs = 166; goto _test_eof; - _test_eof167: cs = 167; goto _test_eof; - _test_eof168: cs = 168; goto _test_eof; - _test_eof169: cs = 169; goto _test_eof; - _test_eof170: cs = 170; goto _test_eof; - _test_eof171: cs = 171; goto _test_eof; - _test_eof172: cs = 172; goto _test_eof; - _test_eof173: cs = 173; goto _test_eof; - _test_eof174: cs = 174; goto _test_eof; - _test_eof175: cs = 175; goto _test_eof; - _test_eof176: cs = 176; goto _test_eof; - _test_eof177: cs = 177; goto _test_eof; - _test_eof178: cs = 178; goto _test_eof; - _test_eof179: cs = 179; goto _test_eof; - _test_eof180: cs = 180; goto _test_eof; - _test_eof181: cs = 181; goto _test_eof; - _test_eof269: cs = 269; goto _test_eof; - _test_eof182: cs = 182; goto _test_eof; - _test_eof183: cs = 183; goto _test_eof; - _test_eof184: cs = 184; goto _test_eof; - _test_eof185: cs = 185; goto _test_eof; - _test_eof186: cs = 186; goto _test_eof; - _test_eof187: cs = 187; goto _test_eof; - _test_eof188: cs = 188; goto _test_eof; - _test_eof189: cs = 189; goto _test_eof; - _test_eof190: cs = 190; goto _test_eof; - _test_eof191: cs = 191; goto _test_eof; - _test_eof192: cs = 192; goto _test_eof; - _test_eof193: cs = 193; goto _test_eof; - _test_eof194: cs = 194; goto _test_eof; - _test_eof195: cs = 195; goto _test_eof; - _test_eof196: cs = 196; goto _test_eof; - _test_eof197: cs = 197; goto _test_eof; - _test_eof198: cs = 198; goto _test_eof; - _test_eof199: cs = 199; goto _test_eof; - _test_eof200: cs = 200; goto _test_eof; - _test_eof201: cs = 201; goto _test_eof; - _test_eof202: cs = 202; goto _test_eof; - _test_eof203: cs = 203; goto _test_eof; - _test_eof204: cs = 204; goto _test_eof; - _test_eof205: cs = 205; goto _test_eof; - _test_eof206: cs = 206; goto _test_eof; - _test_eof207: cs = 207; goto _test_eof; - _test_eof208: cs = 208; goto _test_eof; - _test_eof209: cs = 209; goto _test_eof; - _test_eof210: cs = 210; goto _test_eof; - _test_eof211: cs = 211; goto _test_eof; - _test_eof212: cs = 212; goto _test_eof; - _test_eof213: cs = 213; goto _test_eof; - _test_eof214: cs = 214; goto _test_eof; - _test_eof215: cs = 215; goto _test_eof; - _test_eof216: cs = 216; goto _test_eof; - _test_eof217: cs = 217; goto _test_eof; - _test_eof218: cs = 218; goto _test_eof; - _test_eof219: cs = 219; goto _test_eof; - _test_eof220: cs = 220; goto _test_eof; - _test_eof221: cs = 221; goto _test_eof; - _test_eof222: cs = 222; goto _test_eof; - _test_eof223: cs = 223; goto _test_eof; - _test_eof224: cs = 224; goto _test_eof; - _test_eof225: cs = 225; goto _test_eof; - _test_eof226: cs = 226; goto _test_eof; - _test_eof227: cs = 227; goto _test_eof; - _test_eof228: cs = 228; goto _test_eof; - _test_eof229: cs = 229; goto _test_eof; - _test_eof230: cs = 230; goto _test_eof; - _test_eof231: cs = 231; goto _test_eof; - _test_eof232: cs = 232; goto _test_eof; - _test_eof233: cs = 233; goto _test_eof; - _test_eof234: cs = 234; goto _test_eof; - _test_eof235: cs = 235; goto _test_eof; - _test_eof236: cs = 236; goto _test_eof; - _test_eof237: cs = 237; goto _test_eof; - _test_eof238: cs = 238; goto _test_eof; - _test_eof239: cs = 239; goto _test_eof; - _test_eof240: cs = 240; goto _test_eof; - _test_eof241: cs = 241; goto _test_eof; - _test_eof242: cs = 242; goto _test_eof; - _test_eof243: cs = 243; goto _test_eof; - _test_eof244: cs = 244; goto _test_eof; - _test_eof245: cs = 245; goto _test_eof; - _test_eof246: cs = 246; goto _test_eof; - _test_eof247: cs = 247; goto _test_eof; - _test_eof248: cs = 248; goto _test_eof; - _test_eof249: cs = 249; goto _test_eof; - _test_eof250: cs = 250; goto _test_eof; - _test_eof251: cs = 251; goto _test_eof; - _test_eof252: cs = 252; goto _test_eof; - _test_eof253: cs = 253; goto _test_eof; - _test_eof254: cs = 254; goto _test_eof; - _test_eof255: cs = 255; goto _test_eof; - _test_eof256: cs = 256; goto _test_eof; - _test_eof257: cs = 257; goto _test_eof; - _test_eof258: cs = 258; goto _test_eof; - _test_eof259: cs = 259; goto _test_eof; - _test_eof260: cs = 260; goto _test_eof; - _test_eof261: cs = 261; goto _test_eof; - _test_eof262: cs = 262; goto _test_eof; - _test_eof263: cs = 263; goto _test_eof; - _test_eof264: cs = 264; goto _test_eof; - _test_eof265: cs = 265; goto _test_eof; - - _test_eof: {} - _out: {} - } -#line 469 "http_parser.rl" - - parser->cs = cs; - - CALLBACK(header_field); - CALLBACK(header_value); - CALLBACK(fragment); - CALLBACK(query_string); - CALLBACK(path); - CALLBACK(uri); - - assert(p <= pe && "buffer overflow after parsing execute"); - return(p - buffer); } -int -http_parser_has_error (http_parser *parser) -{ - if (parser->error) return TRUE; - return parser->cs == http_parser_error; -} -int -http_parser_should_keep_alive (http_parser *parser) +void +http_parser_init (http_parser *parser) { - if (parser->keep_alive == -1) - if (parser->version_major == 1) - return (parser->version_minor != 0); - else if (parser->version_major == 0) - return FALSE; - else - return TRUE; - else - return parser->keep_alive; + parser->state = 0; + parser->on_message_begin = NULL; + parser->on_path = NULL; + parser->on_query_string = NULL; + parser->on_url = NULL; + parser->on_fragment = NULL; + parser->on_header_field = NULL; + parser->on_header_value = NULL; + parser->on_headers_complete = NULL; + parser->on_body = NULL; + parser->on_message_complete = NULL; } + diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index 9b699dc483..018f970fcc 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -1,40 +1,48 @@ -/* Copyright (c) 2008, 2009 Ryan Dahl (ry@tinyclouds.org) - * Based on Zed Shaw's Mongrel, copyright (c) Zed A. Shaw - * - * All rights reserved. +/* 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: + * 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 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. + * 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. */ #ifndef http_parser_h #define http_parser_h #ifdef __cplusplus extern "C" { -#endif +#endif -#include +#ifdef _MSC_VER +# include +#endif +#include + +/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run + * faster + */ +#ifndef HTTP_PARSER_STRICT +# define HTTP_PARSER_STRICT 1 +#else +# define HTTP_PARSER_STRICT 0 +#endif typedef struct http_parser http_parser; /* Callbacks should return non-zero to indicate an error. The parse will - * then halt execution. - * + * then halt execution. + * * 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. @@ -43,75 +51,43 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); typedef int (*http_cb) (http_parser*); /* Request Methods */ -#define HTTP_COPY 0x0001 -#define HTTP_DELETE 0x0002 -#define HTTP_GET 0x0004 -#define HTTP_HEAD 0x0008 -#define HTTP_LOCK 0x0010 -#define HTTP_MKCOL 0x0020 -#define HTTP_MOVE 0x0040 -#define HTTP_OPTIONS 0x0080 -#define HTTP_POST 0x0100 -#define HTTP_PROPFIND 0x0200 -#define HTTP_PROPPATCH 0x0400 -#define HTTP_PUT 0x0800 -#define HTTP_TRACE 0x1000 -#define HTTP_UNLOCK 0x2000 - -/* Transfer Encodings */ -#define HTTP_IDENTITY 0x01 -#define HTTP_CHUNKED 0x02 - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE }; +enum http_method + { HTTP_DELETE = 0x0002 + , HTTP_GET = 0x0004 + , HTTP_HEAD = 0x0008 + , HTTP_POST = 0x0100 + , HTTP_PUT = 0x0800 + }; struct http_parser { /** PRIVATE **/ - int cs; - enum http_parser_type type; - - size_t chunk_size; - - /** - XXX - do this so no other code has to change, but make the field only 1 byte wide - instead of 2 (on x86/x86_64). - - doing this not only shrinks the sizeof this struct by a byte but it ALSO - makes wrapping this in FFI way easier. - */ - union { - struct { - unsigned eating:1; - unsigned error:1; - }; - struct { - unsigned char _flags; - }; - }; - - size_t body_read; - - const char *header_field_mark; - size_t header_field_size; - const char *header_value_mark; - size_t header_value_size; - const char *query_string_mark; - size_t query_string_size; - const char *path_mark; - size_t path_size; - const char *uri_mark; - size_t uri_size; - const char *fragment_mark; - size_t fragment_size; + unsigned short state; + unsigned short header_state; + size_t header_index; + + char flags; + + ssize_t body_read; + ssize_t content_length; + + const char *header_field_mark; + size_t header_field_size; + const char *header_value_mark; + size_t header_value_size; + const char *query_string_mark; + size_t query_string_size; + const char *path_mark; + size_t path_size; + const char *url_mark; + size_t url_size; + const char *fragment_mark; + size_t fragment_size; /** READ-ONLY **/ unsigned short status_code; /* responses only */ - unsigned short method; /* requests only */ - short transfer_encoding; - unsigned short version_major; - unsigned short version_minor; - short keep_alive; - size_t content_length; + enum http_method method; /* requests only */ + unsigned short http_major; + unsigned short http_minor; /** PUBLIC **/ void *data; /* A pointer to get hook to the "connection" or "socket" object */ @@ -123,7 +99,7 @@ struct http_parser { /* requests only */ http_data_cb on_path; http_data_cb on_query_string; - http_data_cb on_uri; + http_data_cb on_url; http_data_cb on_fragment; http_data_cb on_header_field; @@ -133,18 +109,17 @@ struct http_parser { http_cb on_message_complete; }; -/* Initializes an http_parser structure. The second argument specifies if - * it will be parsing requests or responses. +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. + * If you are the server, respond with the "Connection: close" header + * if you are the client, close the connection. */ -void http_parser_init (http_parser *parser, enum http_parser_type); - -size_t http_parser_execute (http_parser *parser, const char *data, size_t len); - -int http_parser_has_error (http_parser *parser); - -int http_parser_should_keep_alive (http_parser *parser); +int http_should_keep_alive(http_parser *parser); #ifdef __cplusplus } -#endif +#endif #endif diff --git a/deps/http_parser/http_parser.rl b/deps/http_parser/http_parser.rl deleted file mode 100644 index bf2da13fd2..0000000000 --- a/deps/http_parser/http_parser.rl +++ /dev/null @@ -1,502 +0,0 @@ -/* Copyright (c) 2008, 2009 Ryan Dahl (ry@tinyclouds.org) - * Based on Zed Shaw's Mongrel, copyright (c) Zed A. Shaw - * - * 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 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. - */ -#include "http_parser.h" -#include -#include - -static int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; -#define TRUE 1 -#define FALSE 0 -#define MIN(a,b) (a < b ? a : b) -#define NULL (void*)(0) - -#define MAX_FIELD_SIZE 80*1024 - -#define REMAINING (unsigned long)(pe - p) -#define CALLBACK(FOR) \ -do { \ - if (parser->FOR##_mark) { \ - parser->FOR##_size += p - parser->FOR##_mark; \ - if (parser->FOR##_size > MAX_FIELD_SIZE) { \ - parser->error = TRUE; \ - return 0; \ - } \ - if (parser->on_##FOR) { \ - callback_return_value = parser->on_##FOR(parser, \ - parser->FOR##_mark, \ - p - parser->FOR##_mark); \ - } \ - } \ -} while(0) - -#define RESET_PARSER(parser) \ - parser->chunk_size = 0; \ - parser->eating = 0; \ - parser->header_field_mark = NULL; \ - parser->header_value_mark = NULL; \ - parser->query_string_mark = NULL; \ - parser->path_mark = NULL; \ - parser->uri_mark = NULL; \ - parser->fragment_mark = NULL; \ - parser->status_code = 0; \ - parser->method = 0; \ - parser->transfer_encoding = HTTP_IDENTITY; \ - parser->version_major = 0; \ - parser->version_minor = 0; \ - parser->keep_alive = -1; \ - parser->content_length = 0; \ - parser->body_read = 0; - -#define END_REQUEST \ -do { \ - if (parser->on_message_complete) { \ - callback_return_value = \ - parser->on_message_complete(parser); \ - } \ - RESET_PARSER(parser); \ -} while (0) - -#define SKIP_BODY(nskip) \ -do { \ - tmp = (nskip); \ - if (parser->on_body && tmp > 0) { \ - callback_return_value = parser->on_body(parser, p, tmp); \ - } \ - if (callback_return_value == 0) { \ - p += tmp; \ - parser->body_read += tmp; \ - parser->chunk_size -= tmp; \ - if (0 == parser->chunk_size) { \ - parser->eating = FALSE; \ - if (parser->transfer_encoding == HTTP_IDENTITY) { \ - END_REQUEST; \ - } \ - } else { \ - parser->eating = TRUE; \ - } \ - } \ -} while (0) - -%%{ - machine http_parser; - - action mark_header_field { - parser->header_field_mark = p; - parser->header_field_size = 0; - } - - action mark_header_value { - parser->header_value_mark = p; - parser->header_value_size = 0; - } - - action mark_fragment { - parser->fragment_mark = p; - parser->fragment_size = 0; - } - - action mark_query_string { - parser->query_string_mark = p; - parser->query_string_size = 0; - } - - action mark_request_path { - parser->path_mark = p; - parser->path_size = 0; - } - - action mark_request_uri { - parser->uri_mark = p; - parser->uri_size = 0; - } - - action header_field { - CALLBACK(header_field); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_field_mark = NULL; - parser->header_field_size = 0; - } - - action header_value { - CALLBACK(header_value); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->header_value_mark = NULL; - parser->header_value_size = 0; - } - - action request_uri { - CALLBACK(uri); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->uri_mark = NULL; - parser->uri_size = 0; - } - - action fragment { - CALLBACK(fragment); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->fragment_mark = NULL; - parser->fragment_size = 0; - } - - action query_string { - CALLBACK(query_string); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->query_string_mark = NULL; - parser->query_string_size = 0; - } - - action request_path { - CALLBACK(path); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - parser->path_mark = NULL; - parser->path_size = 0; - } - - action headers_complete { - if(parser->on_headers_complete) { - callback_return_value = parser->on_headers_complete(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - } - } - - action begin_message { - if(parser->on_message_begin) { - callback_return_value = parser->on_message_begin(parser); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - } - } - - action content_length { - if (parser->content_length > INT_MAX) { - parser->error = TRUE; - return 0; - } - parser->content_length *= 10; - parser->content_length += *p - '0'; - } - - action status_code { - parser->status_code *= 10; - parser->status_code += *p - '0'; - } - - action use_identity_encoding { parser->transfer_encoding = HTTP_IDENTITY; } - action use_chunked_encoding { parser->transfer_encoding = HTTP_CHUNKED; } - - action set_keep_alive { parser->keep_alive = TRUE; } - action set_not_keep_alive { parser->keep_alive = FALSE; } - - action version_major { - parser->version_major *= 10; - parser->version_major += *p - '0'; - } - - action version_minor { - parser->version_minor *= 10; - parser->version_minor += *p - '0'; - } - - action add_to_chunk_size { - parser->chunk_size *= 16; - parser->chunk_size += unhex[(int)*p]; - } - - action skip_chunk_data { - SKIP_BODY(MIN(parser->chunk_size, REMAINING)); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - - fhold; - if (parser->chunk_size > REMAINING) { - fbreak; - } else { - fgoto chunk_end; - } - } - - action end_chunked_body { - END_REQUEST; - if (parser->type == HTTP_REQUEST) { - fnext Requests; - } else { - fnext Responses; - } - } - - action body_logic { - if (parser->transfer_encoding == HTTP_CHUNKED) { - fnext ChunkedBody; - } else { - /* this is pretty stupid. i'd prefer to combine this with skip_chunk_data */ - parser->chunk_size = parser->content_length; - p += 1; - - SKIP_BODY(MIN(REMAINING, parser->content_length)); - - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - - fhold; - if(parser->chunk_size > REMAINING) { - fbreak; - } - } - } - - CRLF = "\r\n"; - -# character types - CTL = (cntrl | 127); - safe = ("$" | "-" | "_" | "."); - extra = ("!" | "*" | "'" | "(" | ")" | ","); - reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+"); - unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">"); - national = any -- (alpha | digit | reserved | extra | safe | unsafe); - unreserved = (alpha | digit | safe | extra | national); - escape = ("%" xdigit xdigit); - uchar = (unreserved | escape | "\""); - pchar = (uchar | ":" | "@" | "&" | "=" | "+"); - tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" - | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t"); - -# elements - token = (ascii -- (CTL | tspecials)); - quote = "\""; -# qdtext = token -- "\""; -# quoted_pair = "\" ascii; -# quoted_string = "\"" (qdtext | quoted_pair )* "\""; - -# headers - - Method = ( "COPY" %{ parser->method = HTTP_COPY; } - | "DELETE" %{ parser->method = HTTP_DELETE; } - | "GET" %{ parser->method = HTTP_GET; } - | "HEAD" %{ parser->method = HTTP_HEAD; } - | "LOCK" %{ parser->method = HTTP_LOCK; } - | "MKCOL" %{ parser->method = HTTP_MKCOL; } - | "MOVE" %{ parser->method = HTTP_MOVE; } - | "OPTIONS" %{ parser->method = HTTP_OPTIONS; } - | "POST" %{ parser->method = HTTP_POST; } - | "PROPFIND" %{ parser->method = HTTP_PROPFIND; } - | "PROPPATCH" %{ parser->method = HTTP_PROPPATCH; } - | "PUT" %{ parser->method = HTTP_PUT; } - | "TRACE" %{ parser->method = HTTP_TRACE; } - | "UNLOCK" %{ parser->method = HTTP_UNLOCK; } - ); # Not allowing extension methods - - HTTP_Version = "HTTP/" digit $version_major "." digit $version_minor; - - scheme = ( alpha | digit | "+" | "-" | "." )* ; - absolute_uri = (scheme ":" (uchar | reserved )*); - path = ( pchar+ ( "/" pchar* )* ) ; - query = ( uchar | reserved )* >mark_query_string %query_string ; - param = ( pchar | "/" )* ; - params = ( param ( ";" param )* ) ; - rel_path = ( path? (";" params)? ) ; - absolute_path = ( "/"+ rel_path ) >mark_request_path %request_path ("?" query)?; - Request_URI = ( "*" | absolute_uri | absolute_path ) >mark_request_uri %request_uri; - Fragment = ( uchar | reserved )* >mark_fragment %fragment; - - field_name = ( token -- ":" )+; - Field_Name = field_name >mark_header_field %header_field; - - field_value = ((any - " ") any*)?; - Field_Value = field_value >mark_header_value %header_value; - - hsep = ":" " "*; - header = (field_name hsep field_value) :> CRLF; - Header = ( ("Content-Length"i hsep digit+ $content_length) - | ("Connection"i hsep - ( "Keep-Alive"i %set_keep_alive - | "close"i %set_not_keep_alive - ) - ) - | ("Transfer-Encoding"i %use_chunked_encoding hsep "identity" %use_identity_encoding) - | (Field_Name hsep Field_Value) - ) :> CRLF; - - Headers = (Header)* :> CRLF @headers_complete; - - Request_Line = ( Method " " Request_URI ("#" Fragment)? " " HTTP_Version CRLF ) ; - - StatusCode = (digit digit digit) $status_code; - ReasonPhrase = ascii* -- ("\r" | "\n"); - StatusLine = HTTP_Version " " StatusCode (" " ReasonPhrase)? CRLF; - -# chunked message - trailing_headers = header*; - #chunk_ext_val = token | quoted_string; - chunk_ext_val = token*; - chunk_ext_name = token*; - chunk_extension = ( ";" " "* chunk_ext_name ("=" chunk_ext_val)? )*; - last_chunk = "0"+ chunk_extension CRLF; - chunk_size = (xdigit* [1-9a-fA-F] xdigit*) $add_to_chunk_size; - chunk_end = CRLF; - chunk_body = any >skip_chunk_data; - chunk_begin = chunk_size chunk_extension CRLF; - chunk = chunk_begin chunk_body chunk_end; - ChunkedBody := chunk* last_chunk trailing_headers CRLF @end_chunked_body; - - Request = (Request_Line Headers) >begin_message @body_logic; - Response = (StatusLine Headers) >begin_message @body_logic; - - Requests := Request*; - Responses := Response*; - - main := any >{ - fhold; - if (parser->type == HTTP_REQUEST) { - fgoto Requests; - } else { - fgoto Responses; - } - }; - -}%% - -%% write data; - -void -http_parser_init (http_parser *parser, enum http_parser_type type) -{ - int cs = 0; - %% write init; - parser->cs = cs; - parser->type = type; - parser->error = 0; - - parser->on_message_begin = NULL; - parser->on_path = NULL; - parser->on_query_string = NULL; - parser->on_uri = NULL; - parser->on_fragment = NULL; - parser->on_header_field = NULL; - parser->on_header_value = NULL; - parser->on_headers_complete = NULL; - parser->on_body = NULL; - parser->on_message_complete = NULL; - - RESET_PARSER(parser); -} - -/** exec **/ -size_t -http_parser_execute (http_parser *parser, const char *buffer, size_t len) -{ - size_t tmp; // REMOVE ME this is extremely hacky - int callback_return_value = 0; - const char *p, *pe; - int cs = parser->cs; - - p = buffer; - pe = buffer+len; - - if (0 < parser->chunk_size && parser->eating) { - /* eat body */ - SKIP_BODY(MIN(len, parser->chunk_size)); - if (callback_return_value != 0) { - parser->error = TRUE; - return 0; - } - } - - if (parser->header_field_mark) parser->header_field_mark = buffer; - if (parser->header_value_mark) parser->header_value_mark = buffer; - if (parser->fragment_mark) parser->fragment_mark = buffer; - if (parser->query_string_mark) parser->query_string_mark = buffer; - if (parser->path_mark) parser->path_mark = buffer; - if (parser->uri_mark) parser->uri_mark = buffer; - - %% write exec; - - parser->cs = cs; - - CALLBACK(header_field); - CALLBACK(header_value); - CALLBACK(fragment); - CALLBACK(query_string); - CALLBACK(path); - CALLBACK(uri); - - assert(p <= pe && "buffer overflow after parsing execute"); - return(p - buffer); -} - -int -http_parser_has_error (http_parser *parser) -{ - if (parser->error) return TRUE; - return parser->cs == http_parser_error; -} - -int -http_parser_should_keep_alive (http_parser *parser) -{ - if (parser->keep_alive == -1) - if (parser->version_major == 1) - return (parser->version_minor != 0); - else if (parser->version_major == 0) - return FALSE; - else - return TRUE; - else - return parser->keep_alive; -} diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index 5405f639e0..16d0b52507 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -1,3 +1,23 @@ +/* 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. + */ #include "http_parser.h" #include #include @@ -13,15 +33,17 @@ #define MAX_HEADERS 10 #define MAX_ELEMENT_SIZE 500 +enum message_type { REQUEST, RESPONSE }; + static http_parser parser; struct message { const char *name; // for debugging purposes const char *raw; - enum http_parser_type type; - int method; + enum message_type type; + enum http_method method; int status_code; char request_path[MAX_ELEMENT_SIZE]; - char request_uri[MAX_ELEMENT_SIZE]; + char request_url[MAX_ELEMENT_SIZE]; char fragment[MAX_ELEMENT_SIZE]; char query_string[MAX_ELEMENT_SIZE]; char body[MAX_ELEMENT_SIZE]; @@ -30,32 +52,50 @@ struct message { char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; int should_keep_alive; + unsigned short http_major; + unsigned short http_minor; + int message_begin_cb_called; int headers_complete_cb_called; int message_complete_cb_called; + int message_complete_on_eof; }; +static int currently_parsing_eof; + +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) + : http_parse_responses(&parser, buf, len)); + return nparsed; +} + static struct message messages[5]; static int num_messages; -/* * R E Q U E S T S * */ +/* * R E Q U E S T S * */ const struct message requests[] = #define CURL_GET 0 { {.name= "curl get" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /test HTTP/1.1\r\n" "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" "Host: 0.0.0.0=5000\r\n" "Accept: */*\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= "/test" - ,.request_uri= "/test" + ,.request_url= "/test" ,.num_headers= 3 - ,.headers= + ,.headers= { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } , { "Host", "0.0.0.0=5000" } , { "Accept", "*/*" } @@ -65,7 +105,7 @@ const struct message requests[] = #define FIREFOX_GET 1 , {.name= "firefox get" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /favicon.ico HTTP/1.1\r\n" "Host: 0.0.0.0=5000\r\n" "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" @@ -77,13 +117,16 @@ const struct message requests[] = "Connection: keep-alive\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= "/favicon.ico" - ,.request_uri= "/favicon.ico" + ,.request_url= "/favicon.ico" ,.num_headers= 8 - ,.headers= + ,.headers= { { "Host", "0.0.0.0=5000" } , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } @@ -98,68 +141,80 @@ const struct message requests[] = #define DUMBFUCK 2 , {.name= "dumbfuck" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /dumbfuck HTTP/1.1\r\n" "aaaaaaaaaaaaa:++++++++++\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= "/dumbfuck" - ,.request_uri= "/dumbfuck" + ,.request_url= "/dumbfuck" ,.num_headers= 1 - ,.headers= + ,.headers= { { "aaaaaaaaaaaaa", "++++++++++" } } ,.body= "" } #define FRAGMENT_IN_URI 3 -, {.name= "fragment in uri" - ,.type= HTTP_REQUEST +, {.name= "fragment in url" + ,.type= REQUEST ,.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 + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_GET ,.query_string= "page=1" ,.fragment= "posts-17408" ,.request_path= "/forums/1/topics/2375" - /* XXX request uri does not include fragment? */ - ,.request_uri= "/forums/1/topics/2375?page=1" + /* XXX request url does include fragment? */ + ,.request_url= "/forums/1/topics/2375?page=1#posts-17408" ,.num_headers= 0 ,.body= "" } #define GET_NO_HEADERS_NO_BODY 4 , {.name= "get no headers no body" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_GET ,.query_string= "" ,.fragment= "" ,.request_path= "/get_no_headers_no_body/world" - ,.request_uri= "/get_no_headers_no_body/world" + ,.request_url= "/get_no_headers_no_body/world" ,.num_headers= 0 ,.body= "" } #define GET_ONE_HEADER_NO_BODY 5 , {.name= "get one header no body" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" "Accept: */*\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_GET ,.query_string= "" ,.fragment= "" ,.request_path= "/get_one_header_no_body" - ,.request_uri= "/get_one_header_no_body" + ,.request_url= "/get_one_header_no_body" ,.num_headers= 1 - ,.headers= + ,.headers= { { "Accept" , "*/*" } } ,.body= "" @@ -167,19 +222,22 @@ const struct message requests[] = #define GET_FUNKY_CONTENT_LENGTH 6 , {.name= "get funky content length body hello" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" "conTENT-Length: 5\r\n" "\r\n" "HELLO" ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 ,.method= HTTP_GET ,.query_string= "" ,.fragment= "" ,.request_path= "/get_funky_content_length_body_hello" - ,.request_uri= "/get_funky_content_length_body_hello" + ,.request_url= "/get_funky_content_length_body_hello" ,.num_headers= 1 - ,.headers= + ,.headers= { { "conTENT-Length" , "5" } } ,.body= "HELLO" @@ -187,7 +245,7 @@ const struct message requests[] = #define POST_IDENTITY_BODY_WORLD 7 , {.name= "post identity body world" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" "Accept: */*\r\n" "Transfer-Encoding: identity\r\n" @@ -195,23 +253,26 @@ const struct message requests[] = "\r\n" "World" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_POST ,.query_string= "q=search" ,.fragment= "hey" ,.request_path= "/post_identity_body_world" - ,.request_uri= "/post_identity_body_world?q=search" + ,.request_url= "/post_identity_body_world?q=search#hey" ,.num_headers= 3 - ,.headers= + ,.headers= { { "Accept", "*/*" } , { "Transfer-Encoding", "identity" } - , { "Content-Length", "5" } + , { "Content-Length", "5" } } ,.body= "World" } #define POST_CHUNKED_ALL_YOUR_BASE 8 , {.name= "post - chunked body: all your base are belong to us" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" @@ -219,13 +280,16 @@ const struct message requests[] = "0\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_POST ,.query_string= "" ,.fragment= "" ,.request_path= "/post_chunked_all_your_base" - ,.request_uri= "/post_chunked_all_your_base" + ,.request_url= "/post_chunked_all_your_base" ,.num_headers= 1 - ,.headers= + ,.headers= { { "Transfer-Encoding" , "chunked" } } ,.body= "all your base are belong to us" @@ -233,7 +297,7 @@ const struct message requests[] = #define TWO_CHUNKS_MULT_ZERO_END 9 , {.name= "two chunks ; triple zero ending" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" @@ -242,21 +306,24 @@ const struct message requests[] = "000\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_POST ,.query_string= "" ,.fragment= "" ,.request_path= "/two_chunks_mult_zero_end" - ,.request_uri= "/two_chunks_mult_zero_end" + ,.request_url= "/two_chunks_mult_zero_end" ,.num_headers= 1 - ,.headers= + ,.headers= { { "Transfer-Encoding", "chunked" } } ,.body= "hello world" } -#define CHUNKED_W_TRAILING_HEADERS 10 +#define CHUNKED_W_TRAILING_HEADERS 10 , {.name= "chunked with trailing headers. blech." - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" @@ -267,21 +334,26 @@ const struct message requests[] = "Content-Type: text/plain\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_POST ,.query_string= "" ,.fragment= "" ,.request_path= "/chunked_w_trailing_headers" - ,.request_uri= "/chunked_w_trailing_headers" - ,.num_headers= 1 - ,.headers= + ,.request_url= "/chunked_w_trailing_headers" + ,.num_headers= 3 + ,.headers= { { "Transfer-Encoding", "chunked" } + , { "Vary", "*" } + , { "Content-Type", "text/plain" } } ,.body= "hello world" } -#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 +#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 , {.name= "with bullshit after the length" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" @@ -290,13 +362,16 @@ const struct message requests[] = "0\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.method= HTTP_POST ,.query_string= "" ,.fragment= "" ,.request_path= "/chunked_w_bullshit_after_length" - ,.request_uri= "/chunked_w_bullshit_after_length" + ,.request_url= "/chunked_w_bullshit_after_length" ,.num_headers= 1 - ,.headers= + ,.headers= { { "Transfer-Encoding", "chunked" } } ,.body= "hello world" @@ -304,26 +379,59 @@ const struct message requests[] = #define WITH_QUOTES 12 , {.name= "with quotes" - ,.type= HTTP_REQUEST + ,.type= REQUEST ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" 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= "foo=\"bar\"" ,.fragment= "" ,.request_path= "/with_\"stupid\"_quotes" - ,.request_uri= "/with_\"stupid\"_quotes?foo=\"bar\"" + ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\"" ,.num_headers= 0 ,.headers= { } ,.body= "" } +#define APACHEBENCH_GET 13 +/* The server receiving this request SHOULD NOT wait for EOF + * to know that content-length == 0. + * How to represent this in a unit test? message_complete_on_eof + * Compare with NO_CONTENT_LENGTH_RESPONSE. + */ +, {.name = "apachebench get" + ,.type= REQUEST + ,.raw= "GET /test HTTP/1.0\r\n" + "Host: 0.0.0.0:5000\r\n" + "User-Agent: ApacheBench/2.3\r\n" + "Accept: */*\r\n\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= { { "Host", "0.0.0.0:5000" } + , { "User-Agent", "ApacheBench/2.3" } + , { "Accept", "*/*" } + } + ,.body= "" + } + , {.name= NULL } /* sentinel */ }; -/* * R E S P O N S E S * */ -const struct message responses[] = +/* * R E S P O N S E S * */ +const struct message responses[] = +#define GOOGLE_301 0 { {.name= "google 301" - ,.type= HTTP_RESPONSE + ,.type= RESPONSE ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" "Location: http://www.google.com/\r\n" "Content-Type: text/html; charset=UTF-8\r\n" @@ -340,9 +448,12 @@ const struct message responses[] = "here.\r\n" "\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.status_code= 301 ,.num_headers= 7 - ,.headers= + ,.headers= { { "Location", "http://www.google.com/" } , { "Content-Type", "text/html; charset=UTF-8" } , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } @@ -359,25 +470,112 @@ const struct message responses[] = "\r\n" } +#define NO_CONTENT_LENGTH_RESPONSE 1 +/* The client should wait for the server's EOF. That is, when content-length + * is not specified, and "Connection: close", the end of body is specified + * by the EOF. + * Compare with APACHEBENCH_GET + */ +, {.name= "no content-length response" + ,.type= RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" + "Server: Apache\r\n" + "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Connection: close\r\n" + "\r\n" + "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 5 + ,.headers= + { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" } + , { "Server", "Apache" } + , { "X-Powered-By", "Servlet/2.5 JSP/2.1" } + , { "Content-Type", "text/xml; charset=utf-8" } + , { "Connection", "close" } + } + ,.body= "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + } + +#define NO_HEADERS_NO_BODY_404 2 , {.name= "404 no headers no body" - ,.type= HTTP_RESPONSE + ,.type= RESPONSE ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.status_code= 404 ,.num_headers= 0 ,.headers= {} ,.body= "" } +#define NO_REASON_PHRASE 3 , {.name= "301 no response phrase" - ,.type= HTTP_RESPONSE + ,.type= RESPONSE ,.raw= "HTTP/1.1 301\r\n\r\n" ,.should_keep_alive = TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 ,.status_code= 301 ,.num_headers= 0 ,.headers= {} ,.body= "" -} + } + +#define TRAILING_SPACE_ON_CHUNKED_BODY 4 +, {.name="200 trailing space on chunked body" + ,.type= RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "25 \r\n" + "This is the data in the first chunk\r\n" + "\r\n" + "1C\r\n" + "and this is the second one\r\n" + "\r\n" + "0 \r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/plain" } + , {"Transfer-Encoding", "chunked" } + } + ,.body = + "This is the data in the first chunk\r\n" + "and this is the second one\r\n" + + } , {.name= NULL } /* sentinel */ }; @@ -391,10 +589,10 @@ request_path_cb (http_parser *parser, const char *p, size_t len) } int -request_uri_cb (http_parser *parser, const char *p, size_t len) +request_url_cb (http_parser *parser, const char *p, size_t len) { assert(parser); - strncat(messages[num_messages].request_uri, p, len); + strncat(messages[num_messages].request_url, p, len); return 0; } @@ -453,39 +651,51 @@ body_cb (http_parser *parser, const char *p, size_t len) } int -message_complete_cb (http_parser *parser) +message_begin_cb (http_parser *parser) { - messages[num_messages].method = parser->method; - messages[num_messages].status_code = parser->status_code; - - messages[num_messages].message_complete_cb_called = TRUE; - - num_messages++; + assert(parser); + messages[num_messages].message_begin_cb_called = TRUE; return 0; } int -message_begin_cb (http_parser *parser) +headers_complete_cb (http_parser *parser) { - assert(parser); - messages[num_messages].message_begin_cb_called = TRUE; + messages[num_messages].method = parser->method; + messages[num_messages].status_code = parser->status_code; + messages[num_messages].http_major = parser->http_major; + messages[num_messages].http_minor = parser->http_minor; + messages[num_messages].headers_complete_cb_called = TRUE; + messages[num_messages].should_keep_alive = http_should_keep_alive(parser); return 0; } int -headers_complete_cb (http_parser *parser) +message_complete_cb (http_parser *parser) { assert(parser); - messages[num_messages].headers_complete_cb_called = TRUE; + if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser)) + { + fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same " + "value in both on_message_complete and on_headers_complete " + "but it doesn't! ***\n\n"); + assert(0); + exit(1); + } + messages[num_messages].message_complete_cb_called = TRUE; + + messages[num_messages].message_complete_on_eof = currently_parsing_eof; + + num_messages++; return 0; } void -parser_init (enum http_parser_type type) +parser_init () { num_messages = 0; - http_parser_init(&parser, type); + http_parser_init(&parser); memset(&messages, 0, sizeof messages); @@ -493,7 +703,7 @@ parser_init (enum http_parser_type type) parser.on_header_field = header_field_cb; parser.on_header_value = header_value_cb; parser.on_path = request_path_cb; - parser.on_uri = request_uri_cb; + parser.on_url = request_url_cb; parser.on_fragment = fragment_cb; parser.on_query_string = query_string_cb; parser.on_body = body_cb; @@ -501,113 +711,211 @@ parser_init (enum http_parser_type type) parser.on_message_complete = message_complete_cb; } -void +static inline int +check_str_eq (const struct message *m, + const char *prop, + const char *expected, + const char *found) { + if (0 != strcmp(expected, found)) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected '%s'\n", expected); + printf(" found '%s'\n", found); + return 0; + } + return 1; +} + +static inline int +check_num_eq (const struct message *m, + const char *prop, + int expected, + int found) { + if (expected != found) { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %d\n", expected); + printf(" found %d\n", found); + return 0; + } + return 1; +} + +#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \ + if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \ + if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0 + + +int message_eq (int index, const struct message *expected) { int i; struct message *m = &messages[index]; - assert(m->method == expected->method); - assert(m->status_code == expected->status_code); + MESSAGE_CHECK_NUM_EQ(expected, m, http_major); + MESSAGE_CHECK_NUM_EQ(expected, m, http_minor); + + if (expected->type == REQUEST) { + MESSAGE_CHECK_NUM_EQ(expected, m, method); + } else { + MESSAGE_CHECK_NUM_EQ(expected, m, status_code); + } + + MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); + MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); assert(m->message_begin_cb_called); assert(m->headers_complete_cb_called); assert(m->message_complete_cb_called); - assert(0 == strcmp(m->body, expected->body)); - assert(0 == strcmp(m->fragment, expected->fragment)); - assert(0 == strcmp(m->query_string, expected->query_string)); - assert(0 == strcmp(m->request_path, expected->request_path)); - assert(0 == strcmp(m->request_uri, expected->request_uri)); - assert(m->num_headers == expected->num_headers); + + MESSAGE_CHECK_STR_EQ(expected, m, request_path); + MESSAGE_CHECK_STR_EQ(expected, m, query_string); + MESSAGE_CHECK_STR_EQ(expected, m, fragment); + MESSAGE_CHECK_STR_EQ(expected, m, request_url); + MESSAGE_CHECK_STR_EQ(expected, m, body); + + MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); + + int r; for (i = 0; i < m->num_headers; i++) { - assert(0 == strcmp(m->headers[i][0], expected->headers[i][0])); - assert(0 == strcmp(m->headers[i][1], expected->headers[i][1])); + r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]); + if (!r) return 0; + r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]); + if (!r) return 0; } + + return 1; } -void -parse_messages (int message_count, const struct message *input_messages[]) +static void +print_error (const char *raw, size_t error_location) { - // Concat the input messages - size_t length = 0; - int i; - for (i = 0; i < message_count; i++) { - length += strlen(input_messages[i]->raw); - } - char total[length + 1]; - total[0] = '\0'; - - for (i = 0; i < message_count; i++) { - strcat(total, input_messages[i]->raw); + 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++) { + if (i == error_location) this_line = 1; + switch (raw[i]) { + case '\r': + char_len = 2; + fprintf(stderr, "\\r"); + break; + + case '\n': + char_len = 2; + fprintf(stderr, "\\n\n"); + + if (this_line) goto print; + + error_location_line = 0; + continue; + + default: + char_len = 1; + fputc(raw[i], stderr); + break; + } + if (!this_line) error_location_line += char_len; } - // Parse the stream - size_t traversed = 0; - parser_init(HTTP_REQUEST); - - traversed = http_parser_execute(&parser, total, length); - - assert(!http_parser_has_error(&parser)); - assert(num_messages == message_count); + fprintf(stderr, "[eof]\n"); - for (i = 0; i < message_count; i++) { - message_eq(i, input_messages[i]); + print: + for (j = 0; j < error_location_line; j++) { + fputc(' ', stderr); } + fprintf(stderr, "^\n\nerror location: %d\n", error_location); } void test_message (const struct message *message) { - size_t traversed = 0; - parser_init(message->type); + parser_init(); - traversed = http_parser_execute(&parser, message->raw, strlen(message->raw)); - assert(!http_parser_has_error(&parser)); - assert(num_messages == 1); + size_t read; - message_eq(0, message); + read = parse(message->type, message->raw, strlen(message->raw)); + if (read != strlen(message->raw)) { + print_error(message->raw, read); + exit(1); + } + + read = parse(message->type, NULL, 0); + if (read != 0) { + print_error(message->raw, read); + exit(1); + } + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + exit(1); + } + + if(!message_eq(0, message)) exit(1); } -void +int test_error (const char *buf) { - size_t traversed = 0; - parser_init(HTTP_REQUEST); + parser_init(); - traversed = http_parser_execute(&parser, buf, strlen(buf)); + size_t parsed; - assert(http_parser_has_error(&parser)); + parsed = parse(REQUEST, buf, strlen(buf)); + if (parsed != strlen(buf)) return 1; + parsed = parse(REQUEST, NULL, 0); + if (parsed != 0) return 1; + + fprintf(stderr, "\n*** Error expected but none found ***\n\n%s", buf); + exit(1); + + return 0; } void test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3) { - char total[ strlen(r1->raw) - + strlen(r2->raw) - + strlen(r3->raw) + char total[ strlen(r1->raw) + + strlen(r2->raw) + + strlen(r3->raw) + 1 ]; total[0] = '\0'; - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + parser_init(); - size_t traversed = 0; - parser_init(HTTP_REQUEST); + size_t read; + + read = parse(r1->type, total, strlen(total)); + if (read != strlen(total)) { + print_error(total, read); + exit(1); + } + + read = parse(REQUEST, NULL, 0); + if (read != 0) { + print_error(total, read); + exit(1); + } - traversed = http_parser_execute(&parser, total, strlen(total)); + if (3 != num_messages) { + fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages); + exit(1); + } - assert(! http_parser_has_error(&parser) ); - assert(num_messages == 3); - message_eq(0, r1); - message_eq(1, r2); - message_eq(2, r3); + if (!message_eq(0, r1)) exit(1); + if (!message_eq(1, r2)) exit(1); + if (!message_eq(2, r3)) exit(1); } -/* SCAN through every possible breaking to make sure the +/* SCAN through every possible breaking to make sure the * parser can handle getting the content in any chunks that * might come from the socket */ @@ -619,15 +927,19 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess char buf2[80*1024] = "\0"; char buf3[80*1024] = "\0"; - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + size_t read; int total_len = strlen(total); - int total_ops = (total_len - 1) * (total_len - 2) / 2; + int total_ops = (total_len - 1) * (total_len - 2) / 2; int ops = 0 ; + size_t buf1_len, buf2_len, buf3_len; + int i,j; for (j = 2; j < total_len; j ++ ) { for (i = 1; i < j; i ++ ) { @@ -638,74 +950,110 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess } ops += 1; - parser_init(HTTP_REQUEST); + parser_init(); - int buf1_len = i; + buf1_len = i; strncpy(buf1, total, buf1_len); buf1[buf1_len] = 0; - int buf2_len = j - i; + buf2_len = j - i; strncpy(buf2, total+i, buf2_len); buf2[buf2_len] = 0; - int buf3_len = total_len - j; + buf3_len = total_len - j; strncpy(buf3, total+j, buf3_len); buf3[buf3_len] = 0; - /* - printf("buf1: %s - %d\n", buf1, buf1_len); - printf("buf2: %s - %d \n", buf2, buf2_len ); - printf("buf3: %s - %d\n\n", buf3, buf3_len); - */ - - http_parser_execute(&parser, buf1, buf1_len); + read = parse(r1->type, buf1, buf1_len); + if (read != buf1_len) { + print_error(buf1, read); + goto error; + } - assert(!http_parser_has_error(&parser)); + read = parse(r1->type, buf2, buf2_len); + if (read != buf2_len) { + print_error(buf2, read); + goto error; + } - http_parser_execute(&parser, buf2, buf2_len); + read = parse(r1->type, buf3, buf3_len); + if (read != buf3_len) { + print_error(buf3, read); + goto error; + } - assert(!http_parser_has_error(&parser)); + parse(r1->type, NULL, 0); - http_parser_execute(&parser, buf3, buf3_len); + if (3 != num_messages) { + fprintf(stderr, "\n\nParser didn't see 3 messages only %d\n", num_messages); + goto error; + } - assert(! http_parser_has_error(&parser)); + if (!message_eq(0, r1)) { + fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); + goto error; + } - assert(3 == num_messages); + if (!message_eq(1, r2)) { + fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); + goto error; + } - message_eq(0, r1); - message_eq(1, r2); - message_eq(2, r3); + if (!message_eq(2, r3)) { + fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); + goto error; + } } } puts("\b\b\b\b100%"); + return; + +error: + fprintf(stderr, "i=%d j=%d\n", i, j); + fprintf(stderr, "buf1 (%d) %s\n\n", buf1_len, buf1); + fprintf(stderr, "buf2 (%d) %s\n\n", buf2_len , buf2); + fprintf(stderr, "buf3 (%d) %s\n", buf3_len, buf3); + exit(1); } int main (void) { int i, j, k; + int request_count; + int response_count; printf("sizeof(http_parser) = %d\n", sizeof(http_parser)); - int request_count; for (request_count = 0; requests[request_count].name; request_count++); - - int response_count; for (response_count = 0; responses[response_count].name; response_count++); - //// RESPONSES + //// RESPONSES for (i = 0; i < response_count; i++) { test_message(&responses[i]); } + for (i = 0; i < response_count; i++) { + if (!responses[i].should_keep_alive) continue; + for (j = 0; j < response_count; j++) { + if (!responses[j].should_keep_alive) continue; + for (k = 0; k < response_count; k++) { + test_multiple3(&responses[i], &responses[j], &responses[k]); + } + } + } + printf("response scan 1/1 "); + test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] + , &responses[NO_HEADERS_NO_BODY_404] + , &responses[NO_REASON_PHRASE] + ); puts("responses okay"); - /// REQUESTS @@ -749,15 +1097,18 @@ main (void) "\r\n"; test_error(dumbfuck2); +#if 0 + // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body + // until EOF. + // // no content-length // error if there is a body without content length const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" "Accept: */*\r\n" "\r\n" "HELLO"; - test_error(bad_get_no_headers_no_body); - - + test_error(bad_get_no_headers_no_body); +#endif /* TODO sending junk and large headers gets rejected */ @@ -766,10 +1117,13 @@ main (void) test_message(&requests[i]); } + + for (i = 0; i < request_count; i++) { + if (!requests[i].should_keep_alive) continue; for (j = 0; j < request_count; j++) { + if (!requests[j].should_keep_alive) continue; for (k = 0; k < request_count; k++) { - //printf("%d %d %d\n", i, j, k); test_multiple3(&requests[i], &requests[j], &requests[k]); } } @@ -782,9 +1136,9 @@ main (void) ); printf("request scan 2/3 "); - test_scan( &requests[GET_FUNKY_CONTENT_LENGTH] + test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE] , &requests[POST_IDENTITY_BODY_WORLD] - , &requests[POST_CHUNKED_ALL_YOUR_BASE] + , &requests[GET_FUNKY_CONTENT_LENGTH] ); printf("request scan 3/3 "); @@ -795,6 +1149,5 @@ main (void) puts("requests okay"); - return 0; } diff --git a/lib/http.js b/lib/http.js index e43e79815f..4729608097 100644 --- a/lib/http.js +++ b/lib/http.js @@ -363,7 +363,7 @@ function createIncomingMessageStream (connection, incoming_listener) { }); // Only servers will get URI events. - connection.addListener("uri", function (data) { + connection.addListener("url", function (data) { incoming.uri.full += data; }); @@ -441,7 +441,7 @@ function flushMessageQueue (connection, queue) { while (message.output.length > 0) { if (connection.readyState !== "open" && connection.readyState !== "writeOnly") { - return false; + return true; } var data = message.output.shift(); @@ -474,6 +474,8 @@ function connectionListener (connection) { // we need to keep track of the order they were sent. var responses = []; + connection.resetParser(); + // is this really needed? connection.addListener("eof", function () { if (responses.length == 0) { @@ -520,6 +522,7 @@ exports.createClient = function (port, host) { }; client.addListener("connect", function () { + client.resetParser(); requests[0].flush(); }); diff --git a/src/node_http.cc b/src/node_http.cc index 46bb6b4d34..f047ec948e 100644 --- a/src/node_http.cc +++ b/src/node_http.cc @@ -25,12 +25,14 @@ HTTPConnection::Initialize (Handle target) client_constructor_template->Inherit(Connection::constructor_template); client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); client_constructor_template->SetClassName(String::NewSymbol("Client")); + NODE_SET_PROTOTYPE_METHOD(client_constructor_template, "resetParser", ResetParser); target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction()); t = FunctionTemplate::New(NewServer); server_constructor_template = Persistent::New(t); server_constructor_template->Inherit(Connection::constructor_template); server_constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + NODE_SET_PROTOTYPE_METHOD(server_constructor_template, "resetParser", ResetParser); server_constructor_template->SetClassName(String::NewSymbol("ServerSideConnection")); } @@ -56,12 +58,46 @@ HTTPConnection::NewServer (const Arguments& args) return args.This(); } + +Handle HTTPConnection::ResetParser(const Arguments& args) { + HandleScope scope; + HTTPConnection *connection = ObjectWrap::Unwrap(args.Holder()); + connection->ResetParser(); + return Undefined(); +} + + void HTTPConnection::OnReceive (const void *buf, size_t len) { + HandleScope scope; + + assert(attached_); + size_t nparsed; + + if (type_ == HTTP_REQUEST) { + nparsed = http_parse_requests(&parser_, static_cast(buf), len); + } else { + nparsed = http_parse_responses(&parser_, static_cast(buf), len); + } + + if (nparsed != len) { + ForceClose(); + } +} + +void +HTTPConnection::OnEOF () +{ + HandleScope scope; assert(attached_); - http_parser_execute(&parser_, static_cast(buf), len); - if (http_parser_has_error(&parser_)) ForceClose(); + printf("(node) HTTP EOF!\n"); + if (type_ == HTTP_REQUEST) { + http_parse_requests(&parser_, NULL, 0); + } else { + http_parse_responses(&parser_, NULL, 0); + } + Emit("eof", 0, NULL); } int @@ -83,13 +119,13 @@ HTTPConnection::on_message_complete (http_parser *parser) } int -HTTPConnection::on_uri (http_parser *parser, const char *buf, size_t len) +HTTPConnection::on_url (http_parser *parser, const char *buf, size_t len) { HandleScope scope; HTTPConnection *connection = static_cast(parser->data); assert(connection->attached_); Local argv[1] = { String::New(buf, len) }; - connection->Emit("uri", 1, argv); + connection->Emit("url", 1, argv); return 0; } @@ -170,20 +206,11 @@ GetMethod (int method) { const char *s; switch (method) { - case HTTP_COPY: s = "COPY"; break; case HTTP_DELETE: s = "DELETE"; break; case HTTP_GET: s = "GET"; break; case HTTP_HEAD: s = "HEAD"; break; - case HTTP_LOCK: s = "LOCK"; break; - case HTTP_MKCOL: s = "MKCOL"; break; - case HTTP_MOVE: s = "MOVE"; break; - case HTTP_OPTIONS: s = "OPTIONS"; break; case HTTP_POST: s = "POST"; break; - case HTTP_PROPFIND: s = "PROPFIND"; break; - case HTTP_PROPPATCH: s = "PROPPATCH"; break; case HTTP_PUT: s = "PUT"; break; - case HTTP_TRACE: s = "TRACE"; break; - case HTTP_UNLOCK: s = "UNLOCK"; break; } HandleScope scope; Local method = String::NewSymbol(s); @@ -200,26 +227,28 @@ HTTPConnection::on_headers_complete (http_parser *parser) Local message_info = Object::New(); // METHOD - if (connection->parser_.type == HTTP_REQUEST) + if (connection->type_ == HTTP_REQUEST) { message_info->Set(METHOD_SYMBOL, GetMethod(connection->parser_.method)); + } // STATUS - if (connection->parser_.type == HTTP_RESPONSE) + if (connection->type_ == HTTP_RESPONSE) { message_info->Set(STATUS_CODE_SYMBOL, Integer::New(connection->parser_.status_code)); + } // VERSION char version[10]; snprintf( version , 10 , "%d.%d" - , connection->parser_.version_major - , connection->parser_.version_minor + , connection->parser_.http_major + , connection->parser_.http_minor ); message_info->Set(HTTP_VERSION_SYMBOL, String::New(version)); message_info->Set(SHOULD_KEEP_ALIVE_SYMBOL, - http_parser_should_keep_alive(&connection->parser_) ? True() : False()); + http_should_keep_alive(&connection->parser_) ? True() : False()); Local argv[1] = { message_info }; diff --git a/src/node_http.h b/src/node_http.h index a66b881682..1e36df0fab 100644 --- a/src/node_http.h +++ b/src/node_http.h @@ -7,6 +7,8 @@ namespace node { +enum http_connection_type { HTTP_RESPONSE, HTTP_REQUEST }; + class HTTPConnection : public Connection { public: static void Initialize (v8::Handle target); @@ -17,13 +19,19 @@ public: protected: static v8::Handle NewClient (const v8::Arguments& args); static v8::Handle NewServer (const v8::Arguments& args); + static v8::Handle ResetParser(const v8::Arguments& args); - HTTPConnection (enum http_parser_type type) + HTTPConnection (enum http_connection_type t) : Connection() { - http_parser_init (&parser_, type); + type_ = t; + ResetParser(); + } + + void ResetParser() { + http_parser_init (&parser_); parser_.on_message_begin = on_message_begin; - parser_.on_uri = on_uri; + parser_.on_url = on_url; parser_.on_path = on_path; parser_.on_fragment = on_fragment; parser_.on_query_string = on_query_string; @@ -36,9 +44,10 @@ protected: } void OnReceive (const void *buf, size_t len); + void OnEOF (); static int on_message_begin (http_parser *parser); - static int on_uri (http_parser *parser, const char *at, size_t length); + static int on_url (http_parser *parser, const char *at, size_t length); static int on_query_string (http_parser *parser, const char *at, size_t length); static int on_path (http_parser *parser, const char *at, size_t length); static int on_fragment (http_parser *parser, const char *at, size_t length); @@ -49,7 +58,9 @@ protected: static int on_message_complete (http_parser *parser); http_parser parser_; - + enum http_connection_type type_; // should probably use subclass + // but going to refactor this all soon + // so won't worry about it. friend class HTTPServer; };