Commit 6f90f78bc0f6f503d2ac749dc5be7c01162efb1d

Authored by Josh Klontz
1 parent 2d6ccbf1

removed http-parser

3rdparty/http-parser-2.1/.gitignore deleted
1   -/out/
2   -core
3   -tags
4   -*.o
5   -test
6   -test_g
7   -test_fast
8   -url_parser
9   -parsertrace
10   -parsertrace_g
11   -*.mk
12   -*.Makefile
13   -*.so
14   -*.a
3rdparty/http-parser-2.1/.mailmap deleted
1   -# update AUTHORS with:
2   -# git log --all --reverse --format='%aN <%aE>' | perl -ne 'BEGIN{print "# Authors ordered by first contribution.\n"} print unless $h{$_}; $h{$_} = 1' > AUTHORS
3   -Ryan Dahl <ry@tinyclouds.org>
4   -Salman Haq <salman.haq@asti-usa.com>
5   -Simon Zimmermann <simonz05@gmail.com>
6   -Thomas LE ROUX <thomas@november-eleven.fr> LE ROUX Thomas <thomas@procheo.fr>
7   -Thomas LE ROUX <thomas@november-eleven.fr> Thomas LE ROUX <thomas@procheo.fr>
3rdparty/http-parser-2.1/.travis.yml deleted
1   -language: c
2   -
3   -compiler:
4   - - clang
5   - - gcc
6   -
7   -script:
8   - - "make"
9   -
10   -notifications:
11   - email: false
12   - irc:
13   - - "irc.freenode.net#libuv"
3rdparty/http-parser-2.1/AUTHORS deleted
1   -# Authors ordered by first contribution.
2   -Ryan Dahl <ry@tinyclouds.org>
3   -Jeremy Hinegardner <jeremy@hinegardner.org>
4   -Sergey Shepelev <temotor@gmail.com>
5   -Joe Damato <ice799@gmail.com>
6   -tomika <tomika_nospam@freemail.hu>
7   -Phoenix Sol <phoenix@burninglabs.com>
8   -Cliff Frey <cliff@meraki.com>
9   -Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
10   -Santiago Gala <sgala@apache.org>
11   -Tim Becker <tim.becker@syngenio.de>
12   -Jeff Terrace <jterrace@gmail.com>
13   -Ben Noordhuis <info@bnoordhuis.nl>
14   -Nathan Rajlich <nathan@tootallnate.net>
15   -Mark Nottingham <mnot@mnot.net>
16   -Aman Gupta <aman@tmm1.net>
17   -Tim Becker <tim.becker@kuriositaet.de>
18   -Sean Cunningham <sean.cunningham@mandiant.com>
19   -Peter Griess <pg@std.in>
20   -Salman Haq <salman.haq@asti-usa.com>
21   -Cliff Frey <clifffrey@gmail.com>
22   -Jon Kolb <jon@b0g.us>
23   -Fouad Mardini <f.mardini@gmail.com>
24   -Paul Querna <pquerna@apache.org>
25   -Felix Geisendörfer <felix@debuggable.com>
26   -koichik <koichik@improvement.jp>
27   -Andre Caron <andre.l.caron@gmail.com>
28   -Ivo Raisr <ivosh@ivosh.net>
29   -James McLaughlin <jamie@lacewing-project.org>
30   -David Gwynne <loki@animata.net>
31   -Thomas LE ROUX <thomas@november-eleven.fr>
32   -Randy Rizun <rrizun@ortivawireless.com>
33   -Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
34   -Simon Zimmermann <simonz05@gmail.com>
35   -Erik Dubbelboer <erik@dubbelboer.com>
36   -Martell Malone <martellmalone@gmail.com>
37   -Bertrand Paquet <bpaquet@octo.com>
38   -BogDan Vatra <bogdan@kde.org>
39   -Peter Faiman <peter@thepicard.org>
40   -Corey Richardson <corey@octayn.net>
41   -Tóth Tamás <tomika_nospam@freemail.hu>
3rdparty/http-parser-2.1/CONTRIBUTIONS deleted
1   -Contributors must agree to the Contributor License Agreement before patches
2   -can be accepted.
3   -
4   -http://spreadsheets2.google.com/viewform?hl=en&formkey=dDJXOGUwbzlYaWM4cHN1MERwQS1CSnc6MQ
3rdparty/http-parser-2.1/LICENSE-MIT deleted
1   -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
2   -Igor Sysoev.
3   -
4   -Additional changes are licensed under the same terms as NGINX and
5   -copyright Joyent, Inc. and other Node contributors. All rights reserved.
6   -
7   -Permission is hereby granted, free of charge, to any person obtaining a copy
8   -of this software and associated documentation files (the "Software"), to
9   -deal in the Software without restriction, including without limitation the
10   -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11   -sell copies of the Software, and to permit persons to whom the Software is
12   -furnished to do so, subject to the following conditions:
13   -
14   -The above copyright notice and this permission notice shall be included in
15   -all copies or substantial portions of the Software.
16   -
17   -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22   -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23   -IN THE SOFTWARE.
3rdparty/http-parser-2.1/Makefile deleted
1   -CC?=gcc
2   -AR?=ar
3   -
4   -CPPFLAGS += -I.
5   -CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_STRICT=1
6   -CPPFLAGS_DEBUG += $(CPPFLAGS_DEBUG_EXTRA)
7   -CPPFLAGS_FAST = $(CPPFLAGS) -DHTTP_PARSER_STRICT=0
8   -CPPFLAGS_FAST += $(CPPFLAGS_FAST_EXTRA)
9   -
10   -CFLAGS += -Wall -Wextra -Werror
11   -CFLAGS_DEBUG = $(CFLAGS) -O0 -g $(CFLAGS_DEBUG_EXTRA)
12   -CFLAGS_FAST = $(CFLAGS) -O3 $(CFLAGS_FAST_EXTRA)
13   -CFLAGS_LIB = $(CFLAGS_FAST) -fPIC
14   -
15   -test: test_g test_fast
16   - ./test_g
17   - ./test_fast
18   -
19   -test_g: http_parser_g.o test_g.o
20   - $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@
21   -
22   -test_g.o: test.c http_parser.h Makefile
23   - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c test.c -o $@
24   -
25   -http_parser_g.o: http_parser.c http_parser.h Makefile
26   - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c http_parser.c -o $@
27   -
28   -test_fast: http_parser.o test.o http_parser.h
29   - $(CC) $(CFLAGS_FAST) $(LDFLAGS) http_parser.o test.o -o $@
30   -
31   -test.o: test.c http_parser.h Makefile
32   - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@
33   -
34   -http_parser.o: http_parser.c http_parser.h Makefile
35   - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c
36   -
37   -test-run-timed: test_fast
38   - while(true) do time ./test_fast > /dev/null; done
39   -
40   -test-valgrind: test_g
41   - valgrind ./test_g
42   -
43   -libhttp_parser.o: http_parser.c http_parser.h Makefile
44   - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_LIB) -c http_parser.c -o libhttp_parser.o
45   -
46   -library: libhttp_parser.o
47   - $(CC) -shared -o libhttp_parser.so libhttp_parser.o
48   -
49   -package: http_parser.o
50   - $(AR) rcs libhttp_parser.a http_parser.o
51   -
52   -url_parser: http_parser.o contrib/url_parser.c
53   - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o $@
54   -
55   -url_parser_g: http_parser_g.o contrib/url_parser.c
56   - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@
57   -
58   -parsertrace: http_parser.o contrib/parsertrace.c
59   - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace
60   -
61   -parsertrace_g: http_parser_g.o contrib/parsertrace.c
62   - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g
63   -
64   -tags: http_parser.c http_parser.h test.c
65   - ctags $^
66   -
67   -clean:
68   - rm -f *.o *.a tags test test_fast test_g \
69   - http_parser.tar libhttp_parser.so \
70   - url_parser url_parser_g parsertrace parsertrace_g
71   -
72   -contrib/url_parser.c: http_parser.h
73   -contrib/parsertrace.c: http_parser.h
74   -
75   -.PHONY: clean package test-run test-run-timed test-valgrind
3rdparty/http-parser-2.1/README.md deleted
1   -HTTP Parser
2   -===========
3   -
4   -[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/http-parser)
5   -
6   -This is a parser for HTTP messages written in C. It parses both requests and
7   -responses. The parser is designed to be used in performance HTTP
8   -applications. It does not make any syscalls nor allocations, it does not
9   -buffer data, it can be interrupted at anytime. Depending on your
10   -architecture, it only requires about 40 bytes of data per message
11   -stream (in a web server that is per connection).
12   -
13   -Features:
14   -
15   - * No dependencies
16   - * Handles persistent streams (keep-alive).
17   - * Decodes chunked encoding.
18   - * Upgrade support
19   - * Defends against buffer overflow attacks.
20   -
21   -The parser extracts the following information from HTTP messages:
22   -
23   - * Header fields and values
24   - * Content-Length
25   - * Request method
26   - * Response status code
27   - * Transfer-Encoding
28   - * HTTP version
29   - * Request URL
30   - * Message body
31   -
32   -
33   -Usage
34   ------
35   -
36   -One `http_parser` object is used per TCP connection. Initialize the struct
37   -using `http_parser_init()` and set the callbacks. That might look something
38   -like this for a request parser:
39   -
40   - http_parser_settings settings;
41   - settings.on_url = my_url_callback;
42   - settings.on_header_field = my_header_field_callback;
43   - /* ... */
44   -
45   - http_parser *parser = malloc(sizeof(http_parser));
46   - http_parser_init(parser, HTTP_REQUEST);
47   - parser->data = my_socket;
48   -
49   -When data is received on the socket execute the parser and check for errors.
50   -
51   - size_t len = 80*1024, nparsed;
52   - char buf[len];
53   - ssize_t recved;
54   -
55   - recved = recv(fd, buf, len, 0);
56   -
57   - if (recved < 0) {
58   - /* Handle error. */
59   - }
60   -
61   - /* Start up / continue the parser.
62   - * Note we pass recved==0 to signal that EOF has been recieved.
63   - */
64   - nparsed = http_parser_execute(parser, &settings, buf, recved);
65   -
66   - if (parser->upgrade) {
67   - /* handle new protocol */
68   - } else if (nparsed != recved) {
69   - /* Handle error. Usually just close the connection. */
70   - }
71   -
72   -HTTP needs to know where the end of the stream is. For example, sometimes
73   -servers send responses without Content-Length and expect the client to
74   -consume input (for the body) until EOF. To tell http_parser about EOF, give
75   -`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors
76   -can still be encountered during an EOF, so one must still be prepared
77   -to receive them.
78   -
79   -Scalar valued message information such as `status_code`, `method`, and the
80   -HTTP version are stored in the parser structure. This data is only
81   -temporally stored in `http_parser` and gets reset on each new message. If
82   -this information is needed later, copy it out of the structure during the
83   -`headers_complete` callback.
84   -
85   -The parser decodes the transfer-encoding for both requests and responses
86   -transparently. That is, a chunked encoding is decoded before being sent to
87   -the on_body callback.
88   -
89   -
90   -The Special Problem of Upgrade
91   -------------------------------
92   -
93   -HTTP supports upgrading the connection to a different protocol. An
94   -increasingly common example of this is the Web Socket protocol which sends
95   -a request like
96   -
97   - GET /demo HTTP/1.1
98   - Upgrade: WebSocket
99   - Connection: Upgrade
100   - Host: example.com
101   - Origin: http://example.com
102   - WebSocket-Protocol: sample
103   -
104   -followed by non-HTTP data.
105   -
106   -(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more
107   -information the Web Socket protocol.)
108   -
109   -To support this, the parser will treat this as a normal HTTP message without a
110   -body. Issuing both on_headers_complete and on_message_complete callbacks. However
111   -http_parser_execute() will stop parsing at the end of the headers and return.
112   -
113   -The user is expected to check if `parser->upgrade` has been set to 1 after
114   -`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
115   -offset by the return value of `http_parser_execute()`.
116   -
117   -
118   -Callbacks
119   ----------
120   -
121   -During the `http_parser_execute()` call, the callbacks set in
122   -`http_parser_settings` will be executed. The parser maintains state and
123   -never looks behind, so buffering the data is not necessary. If you need to
124   -save certain data for later usage, you can do that from the callbacks.
125   -
126   -There are two types of callbacks:
127   -
128   -* notification `typedef int (*http_cb) (http_parser*);`
129   - Callbacks: on_message_begin, on_headers_complete, on_message_complete.
130   -* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
131   - Callbacks: (requests only) on_uri,
132   - (common) on_header_field, on_header_value, on_body;
133   -
134   -Callbacks must return 0 on success. Returning a non-zero value indicates
135   -error to the parser, making it exit immediately.
136   -
137   -In case you parse HTTP message in chunks (i.e. `read()` request line
138   -from socket, parse, read half headers, parse, etc) your data callbacks
139   -may be called more than once. Http-parser guarantees that data pointer is only
140   -valid for the lifetime of callback. You can also `read()` into a heap allocated
141   -buffer to avoid copying memory around if this fits your application.
142   -
143   -Reading headers may be a tricky task if you read/parse headers partially.
144   -Basically, you need to remember whether last header callback was field or value
145   -and apply following logic:
146   -
147   - (on_header_field and on_header_value shortened to on_h_*)
148   - ------------------------ ------------ --------------------------------------------
149   - | State (prev. callback) | Callback | Description/action |
150   - ------------------------ ------------ --------------------------------------------
151   - | nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
152   - | | | into it |
153   - ------------------------ ------------ --------------------------------------------
154   - | value | on_h_field | New header started. |
155   - | | | Copy current name,value buffers to headers |
156   - | | | list and allocate new buffer for new name |
157   - ------------------------ ------------ --------------------------------------------
158   - | field | on_h_field | Previous name continues. Reallocate name |
159   - | | | buffer and append callback data to it |
160   - ------------------------ ------------ --------------------------------------------
161   - | field | on_h_value | Value for current header started. Allocate |
162   - | | | new buffer and copy callback data to it |
163   - ------------------------ ------------ --------------------------------------------
164   - | value | on_h_value | Value continues. Reallocate value buffer |
165   - | | | and append callback data to it |
166   - ------------------------ ------------ --------------------------------------------
167   -
168   -
169   -Parsing URLs
170   -------------
171   -
172   -A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
173   -Users of this library may wish to use it to parse URLs constructed from
174   -consecutive `on_url` callbacks.
175   -
176   -See examples of reading in headers:
177   -
178   -* [partial example](http://gist.github.com/155877) in C
179   -* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
180   -* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
3rdparty/http-parser-2.1/contrib/parsertrace.c deleted
1   -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2   - *
3   - * Additional changes are licensed under the same terms as NGINX and
4   - * copyright Joyent, Inc. and other Node contributors. All rights reserved.
5   - *
6   - * Permission is hereby granted, free of charge, to any person obtaining a copy
7   - * of this software and associated documentation files (the "Software"), to
8   - * deal in the Software without restriction, including without limitation the
9   - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10   - * sell copies of the Software, and to permit persons to whom the Software is
11   - * furnished to do so, subject to the following conditions:
12   - *
13   - * The above copyright notice and this permission notice shall be included in
14   - * all copies or substantial portions of the Software.
15   - *
16   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21   - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22   - * IN THE SOFTWARE.
23   - */
24   -
25   -/* Dump what the parser finds to stdout as it happen */
26   -
27   -#include "http_parser.h"
28   -#include <stdio.h>
29   -#include <stdlib.h>
30   -#include <string.h>
31   -
32   -int on_message_begin(http_parser* _) {
33   - (void)_;
34   - printf("\n***MESSAGE BEGIN***\n\n");
35   - return 0;
36   -}
37   -
38   -int on_headers_complete(http_parser* _) {
39   - (void)_;
40   - printf("\n***HEADERS COMPLETE***\n\n");
41   - return 0;
42   -}
43   -
44   -int on_message_complete(http_parser* _) {
45   - (void)_;
46   - printf("\n***MESSAGE COMPLETE***\n\n");
47   - return 0;
48   -}
49   -
50   -int on_url(http_parser* _, const char* at, size_t length) {
51   - (void)_;
52   - printf("Url: %.*s\n", (int)length, at);
53   - return 0;
54   -}
55   -
56   -int on_header_field(http_parser* _, const char* at, size_t length) {
57   - (void)_;
58   - printf("Header field: %.*s\n", (int)length, at);
59   - return 0;
60   -}
61   -
62   -int on_header_value(http_parser* _, const char* at, size_t length) {
63   - (void)_;
64   - printf("Header value: %.*s\n", (int)length, at);
65   - return 0;
66   -}
67   -
68   -int on_body(http_parser* _, const char* at, size_t length) {
69   - (void)_;
70   - printf("Body: %.*s\n", (int)length, at);
71   - return 0;
72   -}
73   -
74   -void usage(const char* name) {
75   - fprintf(stderr,
76   - "Usage: %s $type $filename\n"
77   - " type: -x, where x is one of {r,b,q}\n"
78   - " parses file as a Response, reQuest, or Both\n",
79   - name);
80   - exit(EXIT_FAILURE);
81   -}
82   -
83   -int main(int argc, char* argv[]) {
84   - enum http_parser_type file_type;
85   -
86   - if (argc != 3) {
87   - usage(argv[0]);
88   - }
89   -
90   - char* type = argv[1];
91   - if (type[0] != '-') {
92   - usage(argv[0]);
93   - }
94   -
95   - switch (type[1]) {
96   - /* in the case of "-", type[1] will be NUL */
97   - case 'r':
98   - file_type = HTTP_RESPONSE;
99   - break;
100   - case 'q':
101   - file_type = HTTP_REQUEST;
102   - break;
103   - case 'b':
104   - file_type = HTTP_BOTH;
105   - break;
106   - default:
107   - usage(argv[0]);
108   - }
109   -
110   - char* filename = argv[2];
111   - FILE* file = fopen(filename, "r");
112   - if (file == NULL) {
113   - perror("fopen");
114   - return EXIT_FAILURE;
115   - }
116   -
117   - fseek(file, 0, SEEK_END);
118   - long file_length = ftell(file);
119   - if (file_length == -1) {
120   - perror("ftell");
121   - return EXIT_FAILURE;
122   - }
123   - fseek(file, 0, SEEK_SET);
124   -
125   - char* data = malloc(file_length);
126   - if (fread(data, 1, file_length, file) != (size_t)file_length) {
127   - fprintf(stderr, "couldn't read entire file\n");
128   - free(data);
129   - return EXIT_FAILURE;
130   - }
131   -
132   - http_parser_settings settings;
133   - memset(&settings, 0, sizeof(settings));
134   - settings.on_message_begin = on_message_begin;
135   - settings.on_url = on_url;
136   - settings.on_header_field = on_header_field;
137   - settings.on_header_value = on_header_value;
138   - settings.on_headers_complete = on_headers_complete;
139   - settings.on_body = on_body;
140   - settings.on_message_complete = on_message_complete;
141   -
142   - http_parser parser;
143   - http_parser_init(&parser, file_type);
144   - size_t nparsed = http_parser_execute(&parser, &settings, data, file_length);
145   - free(data);
146   -
147   - if (nparsed != (size_t)file_length) {
148   - fprintf(stderr,
149   - "Error: %s (%s)\n",
150   - http_errno_description(HTTP_PARSER_ERRNO(&parser)),
151   - http_errno_name(HTTP_PARSER_ERRNO(&parser)));
152   - return EXIT_FAILURE;
153   - }
154   -
155   - return EXIT_SUCCESS;
156   -}
3rdparty/http-parser-2.1/contrib/url_parser.c deleted
1   -#include "http_parser.h"
2   -#include <stdio.h>
3   -#include <string.h>
4   -
5   -void
6   -dump_url (const char *url, const struct http_parser_url *u)
7   -{
8   - unsigned int i;
9   -
10   - printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
11   - for (i = 0; i < UF_MAX; i++) {
12   - if ((u->field_set & (1 << i)) == 0) {
13   - printf("\tfield_data[%u]: unset\n", i);
14   - continue;
15   - }
16   -
17   - printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n",
18   - i,
19   - u->field_data[i].off,
20   - u->field_data[i].len,
21   - u->field_data[i].len,
22   - url + u->field_data[i].off);
23   - }
24   -}
25   -
26   -int main(int argc, char ** argv) {
27   - if (argc != 3) {
28   - printf("Syntax : %s connect|get url\n", argv[0]);
29   - return 1;
30   - }
31   - struct http_parser_url u;
32   - int len = strlen(argv[2]);
33   - int connect = strcmp("connect", argv[1]) == 0 ? 1 : 0;
34   - printf("Parsing %s, connect %d\n", argv[2], connect);
35   -
36   - int result = http_parser_parse_url(argv[2], len, connect, &u);
37   - if (result != 0) {
38   - printf("Parse error : %d\n", result);
39   - return result;
40   - }
41   - printf("Parse ok, result : \n");
42   - dump_url(argv[2], &u);
43   - return 0;
44   -}
45 0 \ No newline at end of file
3rdparty/http-parser-2.1/http_parser.c deleted
1   -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2   - *
3   - * Additional changes are licensed under the same terms as NGINX and
4   - * copyright Joyent, Inc. and other Node contributors. All rights reserved.
5   - *
6   - * Permission is hereby granted, free of charge, to any person obtaining a copy
7   - * of this software and associated documentation files (the "Software"), to
8   - * deal in the Software without restriction, including without limitation the
9   - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10   - * sell copies of the Software, and to permit persons to whom the Software is
11   - * furnished to do so, subject to the following conditions:
12   - *
13   - * The above copyright notice and this permission notice shall be included in
14   - * all copies or substantial portions of the Software.
15   - *
16   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21   - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22   - * IN THE SOFTWARE.
23   - */
24   -#include "http_parser.h"
25   -#include <assert.h>
26   -#include <stddef.h>
27   -#include <ctype.h>
28   -#include <stdlib.h>
29   -#include <string.h>
30   -#include <limits.h>
31   -
32   -#ifndef ULLONG_MAX
33   -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
34   -#endif
35   -
36   -#ifndef MIN
37   -# define MIN(a,b) ((a) < (b) ? (a) : (b))
38   -#endif
39   -
40   -#ifndef ARRAY_SIZE
41   -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
42   -#endif
43   -
44   -#ifndef BIT_AT
45   -# define BIT_AT(a, i) \
46   - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
47   - (1 << ((unsigned int) (i) & 7))))
48   -#endif
49   -
50   -#ifndef ELEM_AT
51   -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
52   -#endif
53   -
54   -#define SET_ERRNO(e) \
55   -do { \
56   - parser->http_errno = (e); \
57   -} while(0)
58   -
59   -
60   -/* Run the notify callback FOR, returning ER if it fails */
61   -#define CALLBACK_NOTIFY_(FOR, ER) \
62   -do { \
63   - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
64   - \
65   - if (settings->on_##FOR) { \
66   - if (0 != settings->on_##FOR(parser)) { \
67   - SET_ERRNO(HPE_CB_##FOR); \
68   - } \
69   - \
70   - /* We either errored above or got paused; get out */ \
71   - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
72   - return (ER); \
73   - } \
74   - } \
75   -} while (0)
76   -
77   -/* Run the notify callback FOR and consume the current byte */
78   -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
79   -
80   -/* Run the notify callback FOR and don't consume the current byte */
81   -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
82   -
83   -/* Run data callback FOR with LEN bytes, returning ER if it fails */
84   -#define CALLBACK_DATA_(FOR, LEN, ER) \
85   -do { \
86   - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
87   - \
88   - if (FOR##_mark) { \
89   - if (settings->on_##FOR) { \
90   - if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \
91   - SET_ERRNO(HPE_CB_##FOR); \
92   - } \
93   - \
94   - /* We either errored above or got paused; get out */ \
95   - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \
96   - return (ER); \
97   - } \
98   - } \
99   - FOR##_mark = NULL; \
100   - } \
101   -} while (0)
102   -
103   -/* Run the data callback FOR and consume the current byte */
104   -#define CALLBACK_DATA(FOR) \
105   - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
106   -
107   -/* Run the data callback FOR and don't consume the current byte */
108   -#define CALLBACK_DATA_NOADVANCE(FOR) \
109   - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
110   -
111   -/* Set the mark FOR; non-destructive if mark is already set */
112   -#define MARK(FOR) \
113   -do { \
114   - if (!FOR##_mark) { \
115   - FOR##_mark = p; \
116   - } \
117   -} while (0)
118   -
119   -
120   -#define PROXY_CONNECTION "proxy-connection"
121   -#define CONNECTION "connection"
122   -#define CONTENT_LENGTH "content-length"
123   -#define TRANSFER_ENCODING "transfer-encoding"
124   -#define UPGRADE "upgrade"
125   -#define CHUNKED "chunked"
126   -#define KEEP_ALIVE "keep-alive"
127   -#define CLOSE "close"
128   -
129   -
130   -static const char *method_strings[] =
131   - {
132   -#define XX(num, name, string) #string,
133   - HTTP_METHOD_MAP(XX)
134   -#undef XX
135   - };
136   -
137   -
138   -/* Tokens as defined by rfc 2616. Also lowercases them.
139   - * token = 1*<any CHAR except CTLs or separators>
140   - * separators = "(" | ")" | "<" | ">" | "@"
141   - * | "," | ";" | ":" | "\" | <">
142   - * | "/" | "[" | "]" | "?" | "="
143   - * | "{" | "}" | SP | HT
144   - */
145   -static const char tokens[256] = {
146   -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
147   - 0, 0, 0, 0, 0, 0, 0, 0,
148   -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
149   - 0, 0, 0, 0, 0, 0, 0, 0,
150   -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
151   - 0, 0, 0, 0, 0, 0, 0, 0,
152   -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
153   - 0, 0, 0, 0, 0, 0, 0, 0,
154   -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
155   - 0, '!', 0, '#', '$', '%', '&', '\'',
156   -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
157   - 0, 0, '*', '+', 0, '-', '.', 0,
158   -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
159   - '0', '1', '2', '3', '4', '5', '6', '7',
160   -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
161   - '8', '9', 0, 0, 0, 0, 0, 0,
162   -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
163   - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
164   -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
165   - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
166   -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
167   - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
168   -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
169   - 'x', 'y', 'z', 0, 0, 0, '^', '_',
170   -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
171   - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
172   -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
173   - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
174   -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
175   - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
176   -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
177   - 'x', 'y', 'z', 0, '|', 0, '~', 0 };
178   -
179   -
180   -static const int8_t unhex[256] =
181   - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
182   - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
183   - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
184   - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
185   - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
186   - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
187   - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
188   - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
189   - };
190   -
191   -
192   -#if HTTP_PARSER_STRICT
193   -# define T(v) 0
194   -#else
195   -# define T(v) v
196   -#endif
197   -
198   -
199   -static const uint8_t normal_url_char[32] = {
200   -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
201   - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
202   -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
203   - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
204   -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
205   - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
206   -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
207   - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
208   -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
209   - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
210   -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
211   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
212   -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
213   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
214   -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
215   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
216   -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
217   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
218   -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
219   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
220   -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
221   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
222   -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
223   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
224   -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
225   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
226   -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
227   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
228   -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
229   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
230   -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
231   - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
232   -
233   -#undef T
234   -
235   -enum state
236   - { s_dead = 1 /* important that this is > 0 */
237   -
238   - , s_start_req_or_res
239   - , s_res_or_resp_H
240   - , s_start_res
241   - , s_res_H
242   - , s_res_HT
243   - , s_res_HTT
244   - , s_res_HTTP
245   - , s_res_first_http_major
246   - , s_res_http_major
247   - , s_res_first_http_minor
248   - , s_res_http_minor
249   - , s_res_first_status_code
250   - , s_res_status_code
251   - , s_res_status
252   - , s_res_line_almost_done
253   -
254   - , s_start_req
255   -
256   - , s_req_method
257   - , s_req_spaces_before_url
258   - , s_req_schema
259   - , s_req_schema_slash
260   - , s_req_schema_slash_slash
261   - , s_req_server_start
262   - , s_req_server
263   - , s_req_server_with_at
264   - , s_req_path
265   - , s_req_query_string_start
266   - , s_req_query_string
267   - , s_req_fragment_start
268   - , s_req_fragment
269   - , s_req_http_start
270   - , s_req_http_H
271   - , s_req_http_HT
272   - , s_req_http_HTT
273   - , s_req_http_HTTP
274   - , s_req_first_http_major
275   - , s_req_http_major
276   - , s_req_first_http_minor
277   - , s_req_http_minor
278   - , s_req_line_almost_done
279   -
280   - , s_header_field_start
281   - , s_header_field
282   - , s_header_value_start
283   - , s_header_value
284   - , s_header_value_lws
285   -
286   - , s_header_almost_done
287   -
288   - , s_chunk_size_start
289   - , s_chunk_size
290   - , s_chunk_parameters
291   - , s_chunk_size_almost_done
292   -
293   - , s_headers_almost_done
294   - , s_headers_done
295   -
296   - /* Important: 's_headers_done' must be the last 'header' state. All
297   - * states beyond this must be 'body' states. It is used for overflow
298   - * checking. See the PARSING_HEADER() macro.
299   - */
300   -
301   - , s_chunk_data
302   - , s_chunk_data_almost_done
303   - , s_chunk_data_done
304   -
305   - , s_body_identity
306   - , s_body_identity_eof
307   -
308   - , s_message_done
309   - };
310   -
311   -
312   -#define PARSING_HEADER(state) (state <= s_headers_done)
313   -
314   -
315   -enum header_states
316   - { h_general = 0
317   - , h_C
318   - , h_CO
319   - , h_CON
320   -
321   - , h_matching_connection
322   - , h_matching_proxy_connection
323   - , h_matching_content_length
324   - , h_matching_transfer_encoding
325   - , h_matching_upgrade
326   -
327   - , h_connection
328   - , h_content_length
329   - , h_transfer_encoding
330   - , h_upgrade
331   -
332   - , h_matching_transfer_encoding_chunked
333   - , h_matching_connection_keep_alive
334   - , h_matching_connection_close
335   -
336   - , h_transfer_encoding_chunked
337   - , h_connection_keep_alive
338   - , h_connection_close
339   - };
340   -
341   -enum http_host_state
342   - {
343   - s_http_host_dead = 1
344   - , s_http_userinfo_start
345   - , s_http_userinfo
346   - , s_http_host_start
347   - , s_http_host_v6_start
348   - , s_http_host
349   - , s_http_host_v6
350   - , s_http_host_v6_end
351   - , s_http_host_port_start
352   - , s_http_host_port
353   -};
354   -
355   -/* Macros for character classes; depends on strict-mode */
356   -#define CR '\r'
357   -#define LF '\n'
358   -#define LOWER(c) (unsigned char)(c | 0x20)
359   -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
360   -#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
361   -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
362   -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
363   -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
364   - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
365   - (c) == ')')
366   -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
367   - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
368   - (c) == '$' || (c) == ',')
369   -
370   -#if HTTP_PARSER_STRICT
371   -#define TOKEN(c) (tokens[(unsigned char)c])
372   -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
373   -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
374   -#else
375   -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
376   -#define IS_URL_CHAR(c) \
377   - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
378   -#define IS_HOST_CHAR(c) \
379   - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
380   -#endif
381   -
382   -
383   -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
384   -
385   -
386   -#if HTTP_PARSER_STRICT
387   -# define STRICT_CHECK(cond) \
388   -do { \
389   - if (cond) { \
390   - SET_ERRNO(HPE_STRICT); \
391   - goto error; \
392   - } \
393   -} while (0)
394   -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
395   -#else
396   -# define STRICT_CHECK(cond)
397   -# define NEW_MESSAGE() start_state
398   -#endif
399   -
400   -
401   -/* Map errno values to strings for human-readable output */
402   -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
403   -static struct {
404   - const char *name;
405   - const char *description;
406   -} http_strerror_tab[] = {
407   - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
408   -};
409   -#undef HTTP_STRERROR_GEN
410   -
411   -int http_message_needs_eof(const http_parser *parser);
412   -
413   -/* Our URL parser.
414   - *
415   - * This is designed to be shared by http_parser_execute() for URL validation,
416   - * hence it has a state transition + byte-for-byte interface. In addition, it
417   - * is meant to be embedded in http_parser_parse_url(), which does the dirty
418   - * work of turning state transitions URL components for its API.
419   - *
420   - * This function should only be invoked with non-space characters. It is
421   - * assumed that the caller cares about (and can detect) the transition between
422   - * URL and non-URL states by looking for these.
423   - */
424   -static enum state
425   -parse_url_char(enum state s, const char ch)
426   -{
427   - if (ch == ' ' || ch == '\r' || ch == '\n') {
428   - return s_dead;
429   - }
430   -
431   -#if HTTP_PARSER_STRICT
432   - if (ch == '\t' || ch == '\f') {
433   - return s_dead;
434   - }
435   -#endif
436   -
437   - switch (s) {
438   - case s_req_spaces_before_url:
439   - /* Proxied requests are followed by scheme of an absolute URI (alpha).
440   - * All methods except CONNECT are followed by '/' or '*'.
441   - */
442   -
443   - if (ch == '/' || ch == '*') {
444   - return s_req_path;
445   - }
446   -
447   - if (IS_ALPHA(ch)) {
448   - return s_req_schema;
449   - }
450   -
451   - break;
452   -
453   - case s_req_schema:
454   - if (IS_ALPHA(ch)) {
455   - return s;
456   - }
457   -
458   - if (ch == ':') {
459   - return s_req_schema_slash;
460   - }
461   -
462   - break;
463   -
464   - case s_req_schema_slash:
465   - if (ch == '/') {
466   - return s_req_schema_slash_slash;
467   - }
468   -
469   - break;
470   -
471   - case s_req_schema_slash_slash:
472   - if (ch == '/') {
473   - return s_req_server_start;
474   - }
475   -
476   - break;
477   -
478   - case s_req_server_with_at:
479   - if (ch == '@') {
480   - return s_dead;
481   - }
482   -
483   - /* FALLTHROUGH */
484   - case s_req_server_start:
485   - case s_req_server:
486   - if (ch == '/') {
487   - return s_req_path;
488   - }
489   -
490   - if (ch == '?') {
491   - return s_req_query_string_start;
492   - }
493   -
494   - if (ch == '@') {
495   - return s_req_server_with_at;
496   - }
497   -
498   - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
499   - return s_req_server;
500   - }
501   -
502   - break;
503   -
504   - case s_req_path:
505   - if (IS_URL_CHAR(ch)) {
506   - return s;
507   - }
508   -
509   - switch (ch) {
510   - case '?':
511   - return s_req_query_string_start;
512   -
513   - case '#':
514   - return s_req_fragment_start;
515   - }
516   -
517   - break;
518   -
519   - case s_req_query_string_start:
520   - case s_req_query_string:
521   - if (IS_URL_CHAR(ch)) {
522   - return s_req_query_string;
523   - }
524   -
525   - switch (ch) {
526   - case '?':
527   - /* allow extra '?' in query string */
528   - return s_req_query_string;
529   -
530   - case '#':
531   - return s_req_fragment_start;
532   - }
533   -
534   - break;
535   -
536   - case s_req_fragment_start:
537   - if (IS_URL_CHAR(ch)) {
538   - return s_req_fragment;
539   - }
540   -
541   - switch (ch) {
542   - case '?':
543   - return s_req_fragment;
544   -
545   - case '#':
546   - return s;
547   - }
548   -
549   - break;
550   -
551   - case s_req_fragment:
552   - if (IS_URL_CHAR(ch)) {
553   - return s;
554   - }
555   -
556   - switch (ch) {
557   - case '?':
558   - case '#':
559   - return s;
560   - }
561   -
562   - break;
563   -
564   - default:
565   - break;
566   - }
567   -
568   - /* We should never fall out of the switch above unless there's an error */
569   - return s_dead;
570   -}
571   -
572   -size_t http_parser_execute (http_parser *parser,
573   - const http_parser_settings *settings,
574   - const char *data,
575   - size_t len)
576   -{
577   - char c, ch;
578   - int8_t unhex_val;
579   - const char *p = data;
580   - const char *header_field_mark = 0;
581   - const char *header_value_mark = 0;
582   - const char *url_mark = 0;
583   - const char *body_mark = 0;
584   -
585   - /* We're in an error state. Don't bother doing anything. */
586   - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
587   - return 0;
588   - }
589   -
590   - if (len == 0) {
591   - switch (parser->state) {
592   - case s_body_identity_eof:
593   - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
594   - * we got paused.
595   - */
596   - CALLBACK_NOTIFY_NOADVANCE(message_complete);
597   - return 0;
598   -
599   - case s_dead:
600   - case s_start_req_or_res:
601   - case s_start_res:
602   - case s_start_req:
603   - return 0;
604   -
605   - default:
606   - SET_ERRNO(HPE_INVALID_EOF_STATE);
607   - return 1;
608   - }
609   - }
610   -
611   -
612   - if (parser->state == s_header_field)
613   - header_field_mark = data;
614   - if (parser->state == s_header_value)
615   - header_value_mark = data;
616   - switch (parser->state) {
617   - case s_req_path:
618   - case s_req_schema:
619   - case s_req_schema_slash:
620   - case s_req_schema_slash_slash:
621   - case s_req_server_start:
622   - case s_req_server:
623   - case s_req_server_with_at:
624   - case s_req_query_string_start:
625   - case s_req_query_string:
626   - case s_req_fragment_start:
627   - case s_req_fragment:
628   - url_mark = data;
629   - break;
630   - }
631   -
632   - for (p=data; p != data + len; p++) {
633   - ch = *p;
634   -
635   - if (PARSING_HEADER(parser->state)) {
636   - ++parser->nread;
637   - /* Buffer overflow attack */
638   - if (parser->nread > HTTP_MAX_HEADER_SIZE) {
639   - SET_ERRNO(HPE_HEADER_OVERFLOW);
640   - goto error;
641   - }
642   - }
643   -
644   - reexecute_byte:
645   - switch (parser->state) {
646   -
647   - case s_dead:
648   - /* this state is used after a 'Connection: close' message
649   - * the parser will error out if it reads another message
650   - */
651   - if (ch == CR || ch == LF)
652   - break;
653   -
654   - SET_ERRNO(HPE_CLOSED_CONNECTION);
655   - goto error;
656   -
657   - case s_start_req_or_res:
658   - {
659   - if (ch == CR || ch == LF)
660   - break;
661   - parser->flags = 0;
662   - parser->content_length = ULLONG_MAX;
663   -
664   - if (ch == 'H') {
665   - parser->state = s_res_or_resp_H;
666   -
667   - CALLBACK_NOTIFY(message_begin);
668   - } else {
669   - parser->type = HTTP_REQUEST;
670   - parser->state = s_start_req;
671   - goto reexecute_byte;
672   - }
673   -
674   - break;
675   - }
676   -
677   - case s_res_or_resp_H:
678   - if (ch == 'T') {
679   - parser->type = HTTP_RESPONSE;
680   - parser->state = s_res_HT;
681   - } else {
682   - if (ch != 'E') {
683   - SET_ERRNO(HPE_INVALID_CONSTANT);
684   - goto error;
685   - }
686   -
687   - parser->type = HTTP_REQUEST;
688   - parser->method = HTTP_HEAD;
689   - parser->index = 2;
690   - parser->state = s_req_method;
691   - }
692   - break;
693   -
694   - case s_start_res:
695   - {
696   - parser->flags = 0;
697   - parser->content_length = ULLONG_MAX;
698   -
699   - switch (ch) {
700   - case 'H':
701   - parser->state = s_res_H;
702   - break;
703   -
704   - case CR:
705   - case LF:
706   - break;
707   -
708   - default:
709   - SET_ERRNO(HPE_INVALID_CONSTANT);
710   - goto error;
711   - }
712   -
713   - CALLBACK_NOTIFY(message_begin);
714   - break;
715   - }
716   -
717   - case s_res_H:
718   - STRICT_CHECK(ch != 'T');
719   - parser->state = s_res_HT;
720   - break;
721   -
722   - case s_res_HT:
723   - STRICT_CHECK(ch != 'T');
724   - parser->state = s_res_HTT;
725   - break;
726   -
727   - case s_res_HTT:
728   - STRICT_CHECK(ch != 'P');
729   - parser->state = s_res_HTTP;
730   - break;
731   -
732   - case s_res_HTTP:
733   - STRICT_CHECK(ch != '/');
734   - parser->state = s_res_first_http_major;
735   - break;
736   -
737   - case s_res_first_http_major:
738   - if (ch < '0' || ch > '9') {
739   - SET_ERRNO(HPE_INVALID_VERSION);
740   - goto error;
741   - }
742   -
743   - parser->http_major = ch - '0';
744   - parser->state = s_res_http_major;
745   - break;
746   -
747   - /* major HTTP version or dot */
748   - case s_res_http_major:
749   - {
750   - if (ch == '.') {
751   - parser->state = s_res_first_http_minor;
752   - break;
753   - }
754   -
755   - if (!IS_NUM(ch)) {
756   - SET_ERRNO(HPE_INVALID_VERSION);
757   - goto error;
758   - }
759   -
760   - parser->http_major *= 10;
761   - parser->http_major += ch - '0';
762   -
763   - if (parser->http_major > 999) {
764   - SET_ERRNO(HPE_INVALID_VERSION);
765   - goto error;
766   - }
767   -
768   - break;
769   - }
770   -
771   - /* first digit of minor HTTP version */
772   - case s_res_first_http_minor:
773   - if (!IS_NUM(ch)) {
774   - SET_ERRNO(HPE_INVALID_VERSION);
775   - goto error;
776   - }
777   -
778   - parser->http_minor = ch - '0';
779   - parser->state = s_res_http_minor;
780   - break;
781   -
782   - /* minor HTTP version or end of request line */
783   - case s_res_http_minor:
784   - {
785   - if (ch == ' ') {
786   - parser->state = s_res_first_status_code;
787   - break;
788   - }
789   -
790   - if (!IS_NUM(ch)) {
791   - SET_ERRNO(HPE_INVALID_VERSION);
792   - goto error;
793   - }
794   -
795   - parser->http_minor *= 10;
796   - parser->http_minor += ch - '0';
797   -
798   - if (parser->http_minor > 999) {
799   - SET_ERRNO(HPE_INVALID_VERSION);
800   - goto error;
801   - }
802   -
803   - break;
804   - }
805   -
806   - case s_res_first_status_code:
807   - {
808   - if (!IS_NUM(ch)) {
809   - if (ch == ' ') {
810   - break;
811   - }
812   -
813   - SET_ERRNO(HPE_INVALID_STATUS);
814   - goto error;
815   - }
816   - parser->status_code = ch - '0';
817   - parser->state = s_res_status_code;
818   - break;
819   - }
820   -
821   - case s_res_status_code:
822   - {
823   - if (!IS_NUM(ch)) {
824   - switch (ch) {
825   - case ' ':
826   - parser->state = s_res_status;
827   - break;
828   - case CR:
829   - parser->state = s_res_line_almost_done;
830   - break;
831   - case LF:
832   - parser->state = s_header_field_start;
833   - break;
834   - default:
835   - SET_ERRNO(HPE_INVALID_STATUS);
836   - goto error;
837   - }
838   - break;
839   - }
840   -
841   - parser->status_code *= 10;
842   - parser->status_code += ch - '0';
843   -
844   - if (parser->status_code > 999) {
845   - SET_ERRNO(HPE_INVALID_STATUS);
846   - goto error;
847   - }
848   -
849   - break;
850   - }
851   -
852   - case s_res_status:
853   - /* the human readable status. e.g. "NOT FOUND"
854   - * we are not humans so just ignore this */
855   - if (ch == CR) {
856   - parser->state = s_res_line_almost_done;
857   - break;
858   - }
859   -
860   - if (ch == LF) {
861   - parser->state = s_header_field_start;
862   - break;
863   - }
864   - break;
865   -
866   - case s_res_line_almost_done:
867   - STRICT_CHECK(ch != LF);
868   - parser->state = s_header_field_start;
869   - CALLBACK_NOTIFY(status_complete);
870   - break;
871   -
872   - case s_start_req:
873   - {
874   - if (ch == CR || ch == LF)
875   - break;
876   - parser->flags = 0;
877   - parser->content_length = ULLONG_MAX;
878   -
879   - if (!IS_ALPHA(ch)) {
880   - SET_ERRNO(HPE_INVALID_METHOD);
881   - goto error;
882   - }
883   -
884   - parser->method = (enum http_method) 0;
885   - parser->index = 1;
886   - switch (ch) {
887   - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
888   - case 'D': parser->method = HTTP_DELETE; break;
889   - case 'G': parser->method = HTTP_GET; break;
890   - case 'H': parser->method = HTTP_HEAD; break;
891   - case 'L': parser->method = HTTP_LOCK; break;
892   - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
893   - case 'N': parser->method = HTTP_NOTIFY; break;
894   - case 'O': parser->method = HTTP_OPTIONS; break;
895   - case 'P': parser->method = HTTP_POST;
896   - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
897   - break;
898   - case 'R': parser->method = HTTP_REPORT; break;
899   - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
900   - case 'T': parser->method = HTTP_TRACE; break;
901   - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
902   - default:
903   - SET_ERRNO(HPE_INVALID_METHOD);
904   - goto error;
905   - }
906   - parser->state = s_req_method;
907   -
908   - CALLBACK_NOTIFY(message_begin);
909   -
910   - break;
911   - }
912   -
913   - case s_req_method:
914   - {
915   - const char *matcher;
916   - if (ch == '\0') {
917   - SET_ERRNO(HPE_INVALID_METHOD);
918   - goto error;
919   - }
920   -
921   - matcher = method_strings[parser->method];
922   - if (ch == ' ' && matcher[parser->index] == '\0') {
923   - parser->state = s_req_spaces_before_url;
924   - } else if (ch == matcher[parser->index]) {
925   - ; /* nada */
926   - } else if (parser->method == HTTP_CONNECT) {
927   - if (parser->index == 1 && ch == 'H') {
928   - parser->method = HTTP_CHECKOUT;
929   - } else if (parser->index == 2 && ch == 'P') {
930   - parser->method = HTTP_COPY;
931   - } else {
932   - goto error;
933   - }
934   - } else if (parser->method == HTTP_MKCOL) {
935   - if (parser->index == 1 && ch == 'O') {
936   - parser->method = HTTP_MOVE;
937   - } else if (parser->index == 1 && ch == 'E') {
938   - parser->method = HTTP_MERGE;
939   - } else if (parser->index == 1 && ch == '-') {
940   - parser->method = HTTP_MSEARCH;
941   - } else if (parser->index == 2 && ch == 'A') {
942   - parser->method = HTTP_MKACTIVITY;
943   - } else {
944   - goto error;
945   - }
946   - } else if (parser->method == HTTP_SUBSCRIBE) {
947   - if (parser->index == 1 && ch == 'E') {
948   - parser->method = HTTP_SEARCH;
949   - } else {
950   - goto error;
951   - }
952   - } else if (parser->index == 1 && parser->method == HTTP_POST) {
953   - if (ch == 'R') {
954   - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
955   - } else if (ch == 'U') {
956   - parser->method = HTTP_PUT; /* or HTTP_PURGE */
957   - } else if (ch == 'A') {
958   - parser->method = HTTP_PATCH;
959   - } else {
960   - goto error;
961   - }
962   - } else if (parser->index == 2) {
963   - if (parser->method == HTTP_PUT) {
964   - if (ch == 'R') parser->method = HTTP_PURGE;
965   - } else if (parser->method == HTTP_UNLOCK) {
966   - if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE;
967   - }
968   - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
969   - parser->method = HTTP_PROPPATCH;
970   - } else {
971   - SET_ERRNO(HPE_INVALID_METHOD);
972   - goto error;
973   - }
974   -
975   - ++parser->index;
976   - break;
977   - }
978   -
979   - case s_req_spaces_before_url:
980   - {
981   - if (ch == ' ') break;
982   -
983   - MARK(url);
984   - if (parser->method == HTTP_CONNECT) {
985   - parser->state = s_req_server_start;
986   - }
987   -
988   - parser->state = parse_url_char((enum state)parser->state, ch);
989   - if (parser->state == s_dead) {
990   - SET_ERRNO(HPE_INVALID_URL);
991   - goto error;
992   - }
993   -
994   - break;
995   - }
996   -
997   - case s_req_schema:
998   - case s_req_schema_slash:
999   - case s_req_schema_slash_slash:
1000   - case s_req_server_start:
1001   - {
1002   - switch (ch) {
1003   - /* No whitespace allowed here */
1004   - case ' ':
1005   - case CR:
1006   - case LF:
1007   - SET_ERRNO(HPE_INVALID_URL);
1008   - goto error;
1009   - default:
1010   - parser->state = parse_url_char((enum state)parser->state, ch);
1011   - if (parser->state == s_dead) {
1012   - SET_ERRNO(HPE_INVALID_URL);
1013   - goto error;
1014   - }
1015   - }
1016   -
1017   - break;
1018   - }
1019   -
1020   - case s_req_server:
1021   - case s_req_server_with_at:
1022   - case s_req_path:
1023   - case s_req_query_string_start:
1024   - case s_req_query_string:
1025   - case s_req_fragment_start:
1026   - case s_req_fragment:
1027   - {
1028   - switch (ch) {
1029   - case ' ':
1030   - parser->state = s_req_http_start;
1031   - CALLBACK_DATA(url);
1032   - break;
1033   - case CR:
1034   - case LF:
1035   - parser->http_major = 0;
1036   - parser->http_minor = 9;
1037   - parser->state = (ch == CR) ?
1038   - s_req_line_almost_done :
1039   - s_header_field_start;
1040   - CALLBACK_DATA(url);
1041   - break;
1042   - default:
1043   - parser->state = parse_url_char((enum state)parser->state, ch);
1044   - if (parser->state == s_dead) {
1045   - SET_ERRNO(HPE_INVALID_URL);
1046   - goto error;
1047   - }
1048   - }
1049   - break;
1050   - }
1051   -
1052   - case s_req_http_start:
1053   - switch (ch) {
1054   - case 'H':
1055   - parser->state = s_req_http_H;
1056   - break;
1057   - case ' ':
1058   - break;
1059   - default:
1060   - SET_ERRNO(HPE_INVALID_CONSTANT);
1061   - goto error;
1062   - }
1063   - break;
1064   -
1065   - case s_req_http_H:
1066   - STRICT_CHECK(ch != 'T');
1067   - parser->state = s_req_http_HT;
1068   - break;
1069   -
1070   - case s_req_http_HT:
1071   - STRICT_CHECK(ch != 'T');
1072   - parser->state = s_req_http_HTT;
1073   - break;
1074   -
1075   - case s_req_http_HTT:
1076   - STRICT_CHECK(ch != 'P');
1077   - parser->state = s_req_http_HTTP;
1078   - break;
1079   -
1080   - case s_req_http_HTTP:
1081   - STRICT_CHECK(ch != '/');
1082   - parser->state = s_req_first_http_major;
1083   - break;
1084   -
1085   - /* first digit of major HTTP version */
1086   - case s_req_first_http_major:
1087   - if (ch < '1' || ch > '9') {
1088   - SET_ERRNO(HPE_INVALID_VERSION);
1089   - goto error;
1090   - }
1091   -
1092   - parser->http_major = ch - '0';
1093   - parser->state = s_req_http_major;
1094   - break;
1095   -
1096   - /* major HTTP version or dot */
1097   - case s_req_http_major:
1098   - {
1099   - if (ch == '.') {
1100   - parser->state = s_req_first_http_minor;
1101   - break;
1102   - }
1103   -
1104   - if (!IS_NUM(ch)) {
1105   - SET_ERRNO(HPE_INVALID_VERSION);
1106   - goto error;
1107   - }
1108   -
1109   - parser->http_major *= 10;
1110   - parser->http_major += ch - '0';
1111   -
1112   - if (parser->http_major > 999) {
1113   - SET_ERRNO(HPE_INVALID_VERSION);
1114   - goto error;
1115   - }
1116   -
1117   - break;
1118   - }
1119   -
1120   - /* first digit of minor HTTP version */
1121   - case s_req_first_http_minor:
1122   - if (!IS_NUM(ch)) {
1123   - SET_ERRNO(HPE_INVALID_VERSION);
1124   - goto error;
1125   - }
1126   -
1127   - parser->http_minor = ch - '0';
1128   - parser->state = s_req_http_minor;
1129   - break;
1130   -
1131   - /* minor HTTP version or end of request line */
1132   - case s_req_http_minor:
1133   - {
1134   - if (ch == CR) {
1135   - parser->state = s_req_line_almost_done;
1136   - break;
1137   - }
1138   -
1139   - if (ch == LF) {
1140   - parser->state = s_header_field_start;
1141   - break;
1142   - }
1143   -
1144   - /* XXX allow spaces after digit? */
1145   -
1146   - if (!IS_NUM(ch)) {
1147   - SET_ERRNO(HPE_INVALID_VERSION);
1148   - goto error;
1149   - }
1150   -
1151   - parser->http_minor *= 10;
1152   - parser->http_minor += ch - '0';
1153   -
1154   - if (parser->http_minor > 999) {
1155   - SET_ERRNO(HPE_INVALID_VERSION);
1156   - goto error;
1157   - }
1158   -
1159   - break;
1160   - }
1161   -
1162   - /* end of request line */
1163   - case s_req_line_almost_done:
1164   - {
1165   - if (ch != LF) {
1166   - SET_ERRNO(HPE_LF_EXPECTED);
1167   - goto error;
1168   - }
1169   -
1170   - parser->state = s_header_field_start;
1171   - break;
1172   - }
1173   -
1174   - case s_header_field_start:
1175   - {
1176   - if (ch == CR) {
1177   - parser->state = s_headers_almost_done;
1178   - break;
1179   - }
1180   -
1181   - if (ch == LF) {
1182   - /* they might be just sending \n instead of \r\n so this would be
1183   - * the second \n to denote the end of headers*/
1184   - parser->state = s_headers_almost_done;
1185   - goto reexecute_byte;
1186   - }
1187   -
1188   - c = TOKEN(ch);
1189   -
1190   - if (!c) {
1191   - SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1192   - goto error;
1193   - }
1194   -
1195   - MARK(header_field);
1196   -
1197   - parser->index = 0;
1198   - parser->state = s_header_field;
1199   -
1200   - switch (c) {
1201   - case 'c':
1202   - parser->header_state = h_C;
1203   - break;
1204   -
1205   - case 'p':
1206   - parser->header_state = h_matching_proxy_connection;
1207   - break;
1208   -
1209   - case 't':
1210   - parser->header_state = h_matching_transfer_encoding;
1211   - break;
1212   -
1213   - case 'u':
1214   - parser->header_state = h_matching_upgrade;
1215   - break;
1216   -
1217   - default:
1218   - parser->header_state = h_general;
1219   - break;
1220   - }
1221   - break;
1222   - }
1223   -
1224   - case s_header_field:
1225   - {
1226   - c = TOKEN(ch);
1227   -
1228   - if (c) {
1229   - switch (parser->header_state) {
1230   - case h_general:
1231   - break;
1232   -
1233   - case h_C:
1234   - parser->index++;
1235   - parser->header_state = (c == 'o' ? h_CO : h_general);
1236   - break;
1237   -
1238   - case h_CO:
1239   - parser->index++;
1240   - parser->header_state = (c == 'n' ? h_CON : h_general);
1241   - break;
1242   -
1243   - case h_CON:
1244   - parser->index++;
1245   - switch (c) {
1246   - case 'n':
1247   - parser->header_state = h_matching_connection;
1248   - break;
1249   - case 't':
1250   - parser->header_state = h_matching_content_length;
1251   - break;
1252   - default:
1253   - parser->header_state = h_general;
1254   - break;
1255   - }
1256   - break;
1257   -
1258   - /* connection */
1259   -
1260   - case h_matching_connection:
1261   - parser->index++;
1262   - if (parser->index > sizeof(CONNECTION)-1
1263   - || c != CONNECTION[parser->index]) {
1264   - parser->header_state = h_general;
1265   - } else if (parser->index == sizeof(CONNECTION)-2) {
1266   - parser->header_state = h_connection;
1267   - }
1268   - break;
1269   -
1270   - /* proxy-connection */
1271   -
1272   - case h_matching_proxy_connection:
1273   - parser->index++;
1274   - if (parser->index > sizeof(PROXY_CONNECTION)-1
1275   - || c != PROXY_CONNECTION[parser->index]) {
1276   - parser->header_state = h_general;
1277   - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
1278   - parser->header_state = h_connection;
1279   - }
1280   - break;
1281   -
1282   - /* content-length */
1283   -
1284   - case h_matching_content_length:
1285   - parser->index++;
1286   - if (parser->index > sizeof(CONTENT_LENGTH)-1
1287   - || c != CONTENT_LENGTH[parser->index]) {
1288   - parser->header_state = h_general;
1289   - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
1290   - parser->header_state = h_content_length;
1291   - }
1292   - break;
1293   -
1294   - /* transfer-encoding */
1295   -
1296   - case h_matching_transfer_encoding:
1297   - parser->index++;
1298   - if (parser->index > sizeof(TRANSFER_ENCODING)-1
1299   - || c != TRANSFER_ENCODING[parser->index]) {
1300   - parser->header_state = h_general;
1301   - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
1302   - parser->header_state = h_transfer_encoding;
1303   - }
1304   - break;
1305   -
1306   - /* upgrade */
1307   -
1308   - case h_matching_upgrade:
1309   - parser->index++;
1310   - if (parser->index > sizeof(UPGRADE)-1
1311   - || c != UPGRADE[parser->index]) {
1312   - parser->header_state = h_general;
1313   - } else if (parser->index == sizeof(UPGRADE)-2) {
1314   - parser->header_state = h_upgrade;
1315   - }
1316   - break;
1317   -
1318   - case h_connection:
1319   - case h_content_length:
1320   - case h_transfer_encoding:
1321   - case h_upgrade:
1322   - if (ch != ' ') parser->header_state = h_general;
1323   - break;
1324   -
1325   - default:
1326   - assert(0 && "Unknown header_state");
1327   - break;
1328   - }
1329   - break;
1330   - }
1331   -
1332   - if (ch == ':') {
1333   - parser->state = s_header_value_start;
1334   - CALLBACK_DATA(header_field);
1335   - break;
1336   - }
1337   -
1338   - if (ch == CR) {
1339   - parser->state = s_header_almost_done;
1340   - CALLBACK_DATA(header_field);
1341   - break;
1342   - }
1343   -
1344   - if (ch == LF) {
1345   - parser->state = s_header_field_start;
1346   - CALLBACK_DATA(header_field);
1347   - break;
1348   - }
1349   -
1350   - SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1351   - goto error;
1352   - }
1353   -
1354   - case s_header_value_start:
1355   - {
1356   - if (ch == ' ' || ch == '\t') break;
1357   -
1358   - MARK(header_value);
1359   -
1360   - parser->state = s_header_value;
1361   - parser->index = 0;
1362   -
1363   - if (ch == CR) {
1364   - parser->header_state = h_general;
1365   - parser->state = s_header_almost_done;
1366   - CALLBACK_DATA(header_value);
1367   - break;
1368   - }
1369   -
1370   - if (ch == LF) {
1371   - parser->state = s_header_field_start;
1372   - CALLBACK_DATA(header_value);
1373   - break;
1374   - }
1375   -
1376   - c = LOWER(ch);
1377   -
1378   - switch (parser->header_state) {
1379   - case h_upgrade:
1380   - parser->flags |= F_UPGRADE;
1381   - parser->header_state = h_general;
1382   - break;
1383   -
1384   - case h_transfer_encoding:
1385   - /* looking for 'Transfer-Encoding: chunked' */
1386   - if ('c' == c) {
1387   - parser->header_state = h_matching_transfer_encoding_chunked;
1388   - } else {
1389   - parser->header_state = h_general;
1390   - }
1391   - break;
1392   -
1393   - case h_content_length:
1394   - if (!IS_NUM(ch)) {
1395   - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1396   - goto error;
1397   - }
1398   -
1399   - parser->content_length = ch - '0';
1400   - break;
1401   -
1402   - case h_connection:
1403   - /* looking for 'Connection: keep-alive' */
1404   - if (c == 'k') {
1405   - parser->header_state = h_matching_connection_keep_alive;
1406   - /* looking for 'Connection: close' */
1407   - } else if (c == 'c') {
1408   - parser->header_state = h_matching_connection_close;
1409   - } else {
1410   - parser->header_state = h_general;
1411   - }
1412   - break;
1413   -
1414   - default:
1415   - parser->header_state = h_general;
1416   - break;
1417   - }
1418   - break;
1419   - }
1420   -
1421   - case s_header_value:
1422   - {
1423   -
1424   - if (ch == CR) {
1425   - parser->state = s_header_almost_done;
1426   - CALLBACK_DATA(header_value);
1427   - break;
1428   - }
1429   -
1430   - if (ch == LF) {
1431   - parser->state = s_header_almost_done;
1432   - CALLBACK_DATA_NOADVANCE(header_value);
1433   - goto reexecute_byte;
1434   - }
1435   -
1436   - c = LOWER(ch);
1437   -
1438   - switch (parser->header_state) {
1439   - case h_general:
1440   - break;
1441   -
1442   - case h_connection:
1443   - case h_transfer_encoding:
1444   - assert(0 && "Shouldn't get here.");
1445   - break;
1446   -
1447   - case h_content_length:
1448   - {
1449   - uint64_t t;
1450   -
1451   - if (ch == ' ') break;
1452   -
1453   - if (!IS_NUM(ch)) {
1454   - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1455   - goto error;
1456   - }
1457   -
1458   - t = parser->content_length;
1459   - t *= 10;
1460   - t += ch - '0';
1461   -
1462   - /* Overflow? */
1463   - if (t < parser->content_length || t == ULLONG_MAX) {
1464   - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1465   - goto error;
1466   - }
1467   -
1468   - parser->content_length = t;
1469   - break;
1470   - }
1471   -
1472   - /* Transfer-Encoding: chunked */
1473   - case h_matching_transfer_encoding_chunked:
1474   - parser->index++;
1475   - if (parser->index > sizeof(CHUNKED)-1
1476   - || c != CHUNKED[parser->index]) {
1477   - parser->header_state = h_general;
1478   - } else if (parser->index == sizeof(CHUNKED)-2) {
1479   - parser->header_state = h_transfer_encoding_chunked;
1480   - }
1481   - break;
1482   -
1483   - /* looking for 'Connection: keep-alive' */
1484   - case h_matching_connection_keep_alive:
1485   - parser->index++;
1486   - if (parser->index > sizeof(KEEP_ALIVE)-1
1487   - || c != KEEP_ALIVE[parser->index]) {
1488   - parser->header_state = h_general;
1489   - } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
1490   - parser->header_state = h_connection_keep_alive;
1491   - }
1492   - break;
1493   -
1494   - /* looking for 'Connection: close' */
1495   - case h_matching_connection_close:
1496   - parser->index++;
1497   - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
1498   - parser->header_state = h_general;
1499   - } else if (parser->index == sizeof(CLOSE)-2) {
1500   - parser->header_state = h_connection_close;
1501   - }
1502   - break;
1503   -
1504   - case h_transfer_encoding_chunked:
1505   - case h_connection_keep_alive:
1506   - case h_connection_close:
1507   - if (ch != ' ') parser->header_state = h_general;
1508   - break;
1509   -
1510   - default:
1511   - parser->state = s_header_value;
1512   - parser->header_state = h_general;
1513   - break;
1514   - }
1515   - break;
1516   - }
1517   -
1518   - case s_header_almost_done:
1519   - {
1520   - STRICT_CHECK(ch != LF);
1521   -
1522   - parser->state = s_header_value_lws;
1523   -
1524   - switch (parser->header_state) {
1525   - case h_connection_keep_alive:
1526   - parser->flags |= F_CONNECTION_KEEP_ALIVE;
1527   - break;
1528   - case h_connection_close:
1529   - parser->flags |= F_CONNECTION_CLOSE;
1530   - break;
1531   - case h_transfer_encoding_chunked:
1532   - parser->flags |= F_CHUNKED;
1533   - break;
1534   - default:
1535   - break;
1536   - }
1537   -
1538   - break;
1539   - }
1540   -
1541   - case s_header_value_lws:
1542   - {
1543   - if (ch == ' ' || ch == '\t')
1544   - parser->state = s_header_value_start;
1545   - else
1546   - {
1547   - parser->state = s_header_field_start;
1548   - goto reexecute_byte;
1549   - }
1550   - break;
1551   - }
1552   -
1553   - case s_headers_almost_done:
1554   - {
1555   - STRICT_CHECK(ch != LF);
1556   -
1557   - if (parser->flags & F_TRAILING) {
1558   - /* End of a chunked request */
1559   - parser->state = NEW_MESSAGE();
1560   - CALLBACK_NOTIFY(message_complete);
1561   - break;
1562   - }
1563   -
1564   - parser->state = s_headers_done;
1565   -
1566   - /* Set this here so that on_headers_complete() callbacks can see it */
1567   - parser->upgrade =
1568   - (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT);
1569   -
1570   - /* Here we call the headers_complete callback. This is somewhat
1571   - * different than other callbacks because if the user returns 1, we
1572   - * will interpret that as saying that this message has no body. This
1573   - * is needed for the annoying case of recieving a response to a HEAD
1574   - * request.
1575   - *
1576   - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
1577   - * we have to simulate it by handling a change in errno below.
1578   - */
1579   - if (settings->on_headers_complete) {
1580   - switch (settings->on_headers_complete(parser)) {
1581   - case 0:
1582   - break;
1583   -
1584   - case 1:
1585   - parser->flags |= F_SKIPBODY;
1586   - break;
1587   -
1588   - default:
1589   - SET_ERRNO(HPE_CB_headers_complete);
1590   - return p - data; /* Error */
1591   - }
1592   - }
1593   -
1594   - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
1595   - return p - data;
1596   - }
1597   -
1598   - goto reexecute_byte;
1599   - }
1600   -
1601   - case s_headers_done:
1602   - {
1603   - STRICT_CHECK(ch != LF);
1604   -
1605   - parser->nread = 0;
1606   -
1607   - /* Exit, the rest of the connect is in a different protocol. */
1608   - if (parser->upgrade) {
1609   - parser->state = NEW_MESSAGE();
1610   - CALLBACK_NOTIFY(message_complete);
1611   - return (p - data) + 1;
1612   - }
1613   -
1614   - if (parser->flags & F_SKIPBODY) {
1615   - parser->state = NEW_MESSAGE();
1616   - CALLBACK_NOTIFY(message_complete);
1617   - } else if (parser->flags & F_CHUNKED) {
1618   - /* chunked encoding - ignore Content-Length header */
1619   - parser->state = s_chunk_size_start;
1620   - } else {
1621   - if (parser->content_length == 0) {
1622   - /* Content-Length header given but zero: Content-Length: 0\r\n */
1623   - parser->state = NEW_MESSAGE();
1624   - CALLBACK_NOTIFY(message_complete);
1625   - } else if (parser->content_length != ULLONG_MAX) {
1626   - /* Content-Length header given and non-zero */
1627   - parser->state = s_body_identity;
1628   - } else {
1629   - if (parser->type == HTTP_REQUEST ||
1630   - !http_message_needs_eof(parser)) {
1631   - /* Assume content-length 0 - read the next */
1632   - parser->state = NEW_MESSAGE();
1633   - CALLBACK_NOTIFY(message_complete);
1634   - } else {
1635   - /* Read body until EOF */
1636   - parser->state = s_body_identity_eof;
1637   - }
1638   - }
1639   - }
1640   -
1641   - break;
1642   - }
1643   -
1644   - case s_body_identity:
1645   - {
1646   - uint64_t to_read = MIN(parser->content_length,
1647   - (uint64_t) ((data + len) - p));
1648   -
1649   - assert(parser->content_length != 0
1650   - && parser->content_length != ULLONG_MAX);
1651   -
1652   - /* The difference between advancing content_length and p is because
1653   - * the latter will automaticaly advance on the next loop iteration.
1654   - * Further, if content_length ends up at 0, we want to see the last
1655   - * byte again for our message complete callback.
1656   - */
1657   - MARK(body);
1658   - parser->content_length -= to_read;
1659   - p += to_read - 1;
1660   -
1661   - if (parser->content_length == 0) {
1662   - parser->state = s_message_done;
1663   -
1664   - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1665   - *
1666   - * The alternative to doing this is to wait for the next byte to
1667   - * trigger the data callback, just as in every other case. The
1668   - * problem with this is that this makes it difficult for the test
1669   - * harness to distinguish between complete-on-EOF and
1670   - * complete-on-length. It's not clear that this distinction is
1671   - * important for applications, but let's keep it for now.
1672   - */
1673   - CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1674   - goto reexecute_byte;
1675   - }
1676   -
1677   - break;
1678   - }
1679   -
1680   - /* read until EOF */
1681   - case s_body_identity_eof:
1682   - MARK(body);
1683   - p = data + len - 1;
1684   -
1685   - break;
1686   -
1687   - case s_message_done:
1688   - parser->state = NEW_MESSAGE();
1689   - CALLBACK_NOTIFY(message_complete);
1690   - break;
1691   -
1692   - case s_chunk_size_start:
1693   - {
1694   - assert(parser->nread == 1);
1695   - assert(parser->flags & F_CHUNKED);
1696   -
1697   - unhex_val = unhex[(unsigned char)ch];
1698   - if (unhex_val == -1) {
1699   - SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1700   - goto error;
1701   - }
1702   -
1703   - parser->content_length = unhex_val;
1704   - parser->state = s_chunk_size;
1705   - break;
1706   - }
1707   -
1708   - case s_chunk_size:
1709   - {
1710   - uint64_t t;
1711   -
1712   - assert(parser->flags & F_CHUNKED);
1713   -
1714   - if (ch == CR) {
1715   - parser->state = s_chunk_size_almost_done;
1716   - break;
1717   - }
1718   -
1719   - unhex_val = unhex[(unsigned char)ch];
1720   -
1721   - if (unhex_val == -1) {
1722   - if (ch == ';' || ch == ' ') {
1723   - parser->state = s_chunk_parameters;
1724   - break;
1725   - }
1726   -
1727   - SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1728   - goto error;
1729   - }
1730   -
1731   - t = parser->content_length;
1732   - t *= 16;
1733   - t += unhex_val;
1734   -
1735   - /* Overflow? */
1736   - if (t < parser->content_length || t == ULLONG_MAX) {
1737   - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1738   - goto error;
1739   - }
1740   -
1741   - parser->content_length = t;
1742   - break;
1743   - }
1744   -
1745   - case s_chunk_parameters:
1746   - {
1747   - assert(parser->flags & F_CHUNKED);
1748   - /* just ignore this shit. TODO check for overflow */
1749   - if (ch == CR) {
1750   - parser->state = s_chunk_size_almost_done;
1751   - break;
1752   - }
1753   - break;
1754   - }
1755   -
1756   - case s_chunk_size_almost_done:
1757   - {
1758   - assert(parser->flags & F_CHUNKED);
1759   - STRICT_CHECK(ch != LF);
1760   -
1761   - parser->nread = 0;
1762   -
1763   - if (parser->content_length == 0) {
1764   - parser->flags |= F_TRAILING;
1765   - parser->state = s_header_field_start;
1766   - } else {
1767   - parser->state = s_chunk_data;
1768   - }
1769   - break;
1770   - }
1771   -
1772   - case s_chunk_data:
1773   - {
1774   - uint64_t to_read = MIN(parser->content_length,
1775   - (uint64_t) ((data + len) - p));
1776   -
1777   - assert(parser->flags & F_CHUNKED);
1778   - assert(parser->content_length != 0
1779   - && parser->content_length != ULLONG_MAX);
1780   -
1781   - /* See the explanation in s_body_identity for why the content
1782   - * length and data pointers are managed this way.
1783   - */
1784   - MARK(body);
1785   - parser->content_length -= to_read;
1786   - p += to_read - 1;
1787   -
1788   - if (parser->content_length == 0) {
1789   - parser->state = s_chunk_data_almost_done;
1790   - }
1791   -
1792   - break;
1793   - }
1794   -
1795   - case s_chunk_data_almost_done:
1796   - assert(parser->flags & F_CHUNKED);
1797   - assert(parser->content_length == 0);
1798   - STRICT_CHECK(ch != CR);
1799   - parser->state = s_chunk_data_done;
1800   - CALLBACK_DATA(body);
1801   - break;
1802   -
1803   - case s_chunk_data_done:
1804   - assert(parser->flags & F_CHUNKED);
1805   - STRICT_CHECK(ch != LF);
1806   - parser->nread = 0;
1807   - parser->state = s_chunk_size_start;
1808   - break;
1809   -
1810   - default:
1811   - assert(0 && "unhandled state");
1812   - SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
1813   - goto error;
1814   - }
1815   - }
1816   -
1817   - /* Run callbacks for any marks that we have leftover after we ran our of
1818   - * bytes. There should be at most one of these set, so it's OK to invoke
1819   - * them in series (unset marks will not result in callbacks).
1820   - *
1821   - * We use the NOADVANCE() variety of callbacks here because 'p' has already
1822   - * overflowed 'data' and this allows us to correct for the off-by-one that
1823   - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
1824   - * value that's in-bounds).
1825   - */
1826   -
1827   - assert(((header_field_mark ? 1 : 0) +
1828   - (header_value_mark ? 1 : 0) +
1829   - (url_mark ? 1 : 0) +
1830   - (body_mark ? 1 : 0)) <= 1);
1831   -
1832   - CALLBACK_DATA_NOADVANCE(header_field);
1833   - CALLBACK_DATA_NOADVANCE(header_value);
1834   - CALLBACK_DATA_NOADVANCE(url);
1835   - CALLBACK_DATA_NOADVANCE(body);
1836   -
1837   - return len;
1838   -
1839   -error:
1840   - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
1841   - SET_ERRNO(HPE_UNKNOWN);
1842   - }
1843   -
1844   - return (p - data);
1845   -}
1846   -
1847   -
1848   -/* Does the parser need to see an EOF to find the end of the message? */
1849   -int
1850   -http_message_needs_eof (const http_parser *parser)
1851   -{
1852   - if (parser->type == HTTP_REQUEST) {
1853   - return 0;
1854   - }
1855   -
1856   - /* See RFC 2616 section 4.4 */
1857   - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
1858   - parser->status_code == 204 || /* No Content */
1859   - parser->status_code == 304 || /* Not Modified */
1860   - parser->flags & F_SKIPBODY) { /* response to a HEAD request */
1861   - return 0;
1862   - }
1863   -
1864   - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
1865   - return 0;
1866   - }
1867   -
1868   - return 1;
1869   -}
1870   -
1871   -
1872   -int
1873   -http_should_keep_alive (const http_parser *parser)
1874   -{
1875   - if (parser->http_major > 0 && parser->http_minor > 0) {
1876   - /* HTTP/1.1 */
1877   - if (parser->flags & F_CONNECTION_CLOSE) {
1878   - return 0;
1879   - }
1880   - } else {
1881   - /* HTTP/1.0 or earlier */
1882   - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
1883   - return 0;
1884   - }
1885   - }
1886   -
1887   - return !http_message_needs_eof(parser);
1888   -}
1889   -
1890   -
1891   -const char *
1892   -http_method_str (enum http_method m)
1893   -{
1894   - return ELEM_AT(method_strings, m, "<unknown>");
1895   -}
1896   -
1897   -
1898   -void
1899   -http_parser_init (http_parser *parser, enum http_parser_type t)
1900   -{
1901   - void *data = parser->data; /* preserve application data */
1902   - memset(parser, 0, sizeof(*parser));
1903   - parser->data = data;
1904   - parser->type = t;
1905   - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
1906   - parser->http_errno = HPE_OK;
1907   -}
1908   -
1909   -const char *
1910   -http_errno_name(enum http_errno err) {
1911   - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1912   - return http_strerror_tab[err].name;
1913   -}
1914   -
1915   -const char *
1916   -http_errno_description(enum http_errno err) {
1917   - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
1918   - return http_strerror_tab[err].description;
1919   -}
1920   -
1921   -static enum http_host_state
1922   -http_parse_host_char(enum http_host_state s, const char ch) {
1923   - switch(s) {
1924   - case s_http_userinfo:
1925   - case s_http_userinfo_start:
1926   - if (ch == '@') {
1927   - return s_http_host_start;
1928   - }
1929   -
1930   - if (IS_USERINFO_CHAR(ch)) {
1931   - return s_http_userinfo;
1932   - }
1933   - break;
1934   -
1935   - case s_http_host_start:
1936   - if (ch == '[') {
1937   - return s_http_host_v6_start;
1938   - }
1939   -
1940   - if (IS_HOST_CHAR(ch)) {
1941   - return s_http_host;
1942   - }
1943   -
1944   - break;
1945   -
1946   - case s_http_host:
1947   - if (IS_HOST_CHAR(ch)) {
1948   - return s_http_host;
1949   - }
1950   -
1951   - /* FALLTHROUGH */
1952   - case s_http_host_v6_end:
1953   - if (ch == ':') {
1954   - return s_http_host_port_start;
1955   - }
1956   -
1957   - break;
1958   -
1959   - case s_http_host_v6:
1960   - if (ch == ']') {
1961   - return s_http_host_v6_end;
1962   - }
1963   -
1964   - /* FALLTHROUGH */
1965   - case s_http_host_v6_start:
1966   - if (IS_HEX(ch) || ch == ':' || ch == '.') {
1967   - return s_http_host_v6;
1968   - }
1969   -
1970   - break;
1971   -
1972   - case s_http_host_port:
1973   - case s_http_host_port_start:
1974   - if (IS_NUM(ch)) {
1975   - return s_http_host_port;
1976   - }
1977   -
1978   - break;
1979   -
1980   - default:
1981   - break;
1982   - }
1983   - return s_http_host_dead;
1984   -}
1985   -
1986   -static int
1987   -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
1988   - enum http_host_state s;
1989   -
1990   - const char *p;
1991   - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
1992   -
1993   - u->field_data[UF_HOST].len = 0;
1994   -
1995   - s = found_at ? s_http_userinfo_start : s_http_host_start;
1996   -
1997   - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
1998   - enum http_host_state new_s = http_parse_host_char(s, *p);
1999   -
2000   - if (new_s == s_http_host_dead) {
2001   - return 1;
2002   - }
2003   -
2004   - switch(new_s) {
2005   - case s_http_host:
2006   - if (s != s_http_host) {
2007   - u->field_data[UF_HOST].off = (uint16_t) (p - buf);
2008   - }
2009   - u->field_data[UF_HOST].len++;
2010   - break;
2011   -
2012   - case s_http_host_v6:
2013   - if (s != s_http_host_v6) {
2014   - u->field_data[UF_HOST].off = (uint16_t) (p - buf);
2015   - }
2016   - u->field_data[UF_HOST].len++;
2017   - break;
2018   -
2019   - case s_http_host_port:
2020   - if (s != s_http_host_port) {
2021   - u->field_data[UF_PORT].off = (uint16_t) (p - buf);
2022   - u->field_data[UF_PORT].len = 0;
2023   - u->field_set |= (1 << UF_PORT);
2024   - }
2025   - u->field_data[UF_PORT].len++;
2026   - break;
2027   -
2028   - case s_http_userinfo:
2029   - if (s != s_http_userinfo) {
2030   - u->field_data[UF_USERINFO].off = (uint16_t) (p - buf) ;
2031   - u->field_data[UF_USERINFO].len = 0;
2032   - u->field_set |= (1 << UF_USERINFO);
2033   - }
2034   - u->field_data[UF_USERINFO].len++;
2035   - break;
2036   -
2037   - default:
2038   - break;
2039   - }
2040   - s = new_s;
2041   - }
2042   -
2043   - /* Make sure we don't end somewhere unexpected */
2044   - switch (s) {
2045   - case s_http_host_start:
2046   - case s_http_host_v6_start:
2047   - case s_http_host_v6:
2048   - case s_http_host_port_start:
2049   - case s_http_userinfo:
2050   - case s_http_userinfo_start:
2051   - return 1;
2052   - default:
2053   - break;
2054   - }
2055   -
2056   - return 0;
2057   -}
2058   -
2059   -int
2060   -http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2061   - struct http_parser_url *u)
2062   -{
2063   - enum state s;
2064   - const char *p;
2065   - enum http_parser_url_fields uf, old_uf;
2066   - int found_at = 0;
2067   -
2068   - u->port = u->field_set = 0;
2069   - s = is_connect ? s_req_server_start : s_req_spaces_before_url;
2070   - uf = old_uf = UF_MAX;
2071   -
2072   - for (p = buf; p < buf + buflen; p++) {
2073   - s = parse_url_char(s, *p);
2074   -
2075   - /* Figure out the next field that we're operating on */
2076   - switch (s) {
2077   - case s_dead:
2078   - return 1;
2079   -
2080   - /* Skip delimeters */
2081   - case s_req_schema_slash:
2082   - case s_req_schema_slash_slash:
2083   - case s_req_server_start:
2084   - case s_req_query_string_start:
2085   - case s_req_fragment_start:
2086   - continue;
2087   -
2088   - case s_req_schema:
2089   - uf = UF_SCHEMA;
2090   - break;
2091   -
2092   - case s_req_server_with_at:
2093   - found_at = 1;
2094   -
2095   - /* FALLTROUGH */
2096   - case s_req_server:
2097   - uf = UF_HOST;
2098   - break;
2099   -
2100   - case s_req_path:
2101   - uf = UF_PATH;
2102   - break;
2103   -
2104   - case s_req_query_string:
2105   - uf = UF_QUERY;
2106   - break;
2107   -
2108   - case s_req_fragment:
2109   - uf = UF_FRAGMENT;
2110   - break;
2111   -
2112   - default:
2113   - assert(!"Unexpected state");
2114   - return 1;
2115   - }
2116   -
2117   - /* Nothing's changed; soldier on */
2118   - if (uf == old_uf) {
2119   - u->field_data[uf].len++;
2120   - continue;
2121   - }
2122   -
2123   - u->field_data[uf].off = (uint16_t) (p - buf);
2124   - u->field_data[uf].len = 1;
2125   -
2126   - u->field_set |= (1 << uf);
2127   - old_uf = uf;
2128   - }
2129   -
2130   - /* host must be present if there is a schema */
2131   - /* parsing http:///toto will fail */
2132   - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) {
2133   - if (http_parse_host(buf, u, found_at) != 0) {
2134   - return 1;
2135   - }
2136   - }
2137   -
2138   - /* CONNECT requests can only contain "hostname:port" */
2139   - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
2140   - return 1;
2141   - }
2142   -
2143   - if (u->field_set & (1 << UF_PORT)) {
2144   - /* Don't bother with endp; we've already validated the string */
2145   - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
2146   -
2147   - /* Ports have a max value of 2^16 */
2148   - if (v > 0xffff) {
2149   - return 1;
2150   - }
2151   -
2152   - u->port = (uint16_t) v;
2153   - }
2154   -
2155   - return 0;
2156   -}
2157   -
2158   -void
2159   -http_parser_pause(http_parser *parser, int paused) {
2160   - /* Users should only be pausing/unpausing a parser that is not in an error
2161   - * state. In non-debug builds, there's not much that we can do about this
2162   - * other than ignore it.
2163   - */
2164   - if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2165   - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2166   - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2167   - } else {
2168   - assert(0 && "Attempting to pause parser in error state");
2169   - }
2170   -}
2171   -
2172   -int
2173   -http_body_is_final(const struct http_parser *parser) {
2174   - return parser->state == s_message_done;
2175   -}
3rdparty/http-parser-2.1/http_parser.gyp deleted
1   -# This file is used with the GYP meta build system.
2   -# http://code.google.com/p/gyp/
3   -# To build try this:
4   -# svn co http://gyp.googlecode.com/svn/trunk gyp
5   -# ./gyp/gyp -f make --depth=`pwd` http_parser.gyp
6   -# ./out/Debug/test
7   -{
8   - 'target_defaults': {
9   - 'default_configuration': 'Debug',
10   - 'configurations': {
11   - # TODO: hoist these out and put them somewhere common, because
12   - # RuntimeLibrary MUST MATCH across the entire project
13   - 'Debug': {
14   - 'defines': [ 'DEBUG', '_DEBUG' ],
15   - 'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ],
16   - 'msvs_settings': {
17   - 'VCCLCompilerTool': {
18   - 'RuntimeLibrary': 1, # static debug
19   - },
20   - },
21   - },
22   - 'Release': {
23   - 'defines': [ 'NDEBUG' ],
24   - 'cflags': [ '-Wall', '-Wextra', '-O3' ],
25   - 'msvs_settings': {
26   - 'VCCLCompilerTool': {
27   - 'RuntimeLibrary': 0, # static release
28   - },
29   - },
30   - }
31   - },
32   - 'msvs_settings': {
33   - 'VCCLCompilerTool': {
34   - },
35   - 'VCLibrarianTool': {
36   - },
37   - 'VCLinkerTool': {
38   - 'GenerateDebugInformation': 'true',
39   - },
40   - },
41   - 'conditions': [
42   - ['OS == "win"', {
43   - 'defines': [
44   - 'WIN32'
45   - ],
46   - }]
47   - ],
48   - },
49   -
50   - 'targets': [
51   - {
52   - 'target_name': 'http_parser',
53   - 'type': 'static_library',
54   - 'include_dirs': [ '.' ],
55   - 'direct_dependent_settings': {
56   - 'defines': [ 'HTTP_PARSER_STRICT=0' ],
57   - 'include_dirs': [ '.' ],
58   - },
59   - 'defines': [ 'HTTP_PARSER_STRICT=0' ],
60   - 'sources': [ './http_parser.c', ],
61   - 'conditions': [
62   - ['OS=="win"', {
63   - 'msvs_settings': {
64   - 'VCCLCompilerTool': {
65   - # Compile as C++. http_parser.c is actually C99, but C++ is
66   - # close enough in this case.
67   - 'CompileAs': 2,
68   - },
69   - },
70   - }]
71   - ],
72   - },
73   -
74   - {
75   - 'target_name': 'http_parser_strict',
76   - 'type': 'static_library',
77   - 'include_dirs': [ '.' ],
78   - 'direct_dependent_settings': {
79   - 'defines': [ 'HTTP_PARSER_STRICT=1' ],
80   - 'include_dirs': [ '.' ],
81   - },
82   - 'defines': [ 'HTTP_PARSER_STRICT=1' ],
83   - 'sources': [ './http_parser.c', ],
84   - 'conditions': [
85   - ['OS=="win"', {
86   - 'msvs_settings': {
87   - 'VCCLCompilerTool': {
88   - # Compile as C++. http_parser.c is actually C99, but C++ is
89   - # close enough in this case.
90   - 'CompileAs': 2,
91   - },
92   - },
93   - }]
94   - ],
95   - },
96   -
97   - {
98   - 'target_name': 'test-nonstrict',
99   - 'type': 'executable',
100   - 'dependencies': [ 'http_parser' ],
101   - 'sources': [ 'test.c' ]
102   - },
103   -
104   - {
105   - 'target_name': 'test-strict',
106   - 'type': 'executable',
107   - 'dependencies': [ 'http_parser_strict' ],
108   - 'sources': [ 'test.c' ]
109   - }
110   - ]
111   -}
3rdparty/http-parser-2.1/http_parser.h deleted
1   -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2   - *
3   - * Permission is hereby granted, free of charge, to any person obtaining a copy
4   - * of this software and associated documentation files (the "Software"), to
5   - * deal in the Software without restriction, including without limitation the
6   - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7   - * sell copies of the Software, and to permit persons to whom the Software is
8   - * furnished to do so, subject to the following conditions:
9   - *
10   - * The above copyright notice and this permission notice shall be included in
11   - * all copies or substantial portions of the Software.
12   - *
13   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16   - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18   - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19   - * IN THE SOFTWARE.
20   - */
21   -#ifndef http_parser_h
22   -#define http_parser_h
23   -#ifdef __cplusplus
24   -extern "C" {
25   -#endif
26   -
27   -#define HTTP_PARSER_VERSION_MAJOR 2
28   -#define HTTP_PARSER_VERSION_MINOR 1
29   -
30   -#include <sys/types.h>
31   -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
32   -#include <BaseTsd.h>
33   -#include <stddef.h>
34   -typedef __int8 int8_t;
35   -typedef unsigned __int8 uint8_t;
36   -typedef __int16 int16_t;
37   -typedef unsigned __int16 uint16_t;
38   -typedef __int32 int32_t;
39   -typedef unsigned __int32 uint32_t;
40   -typedef __int64 int64_t;
41   -typedef unsigned __int64 uint64_t;
42   -#else
43   -#include <stdint.h>
44   -#endif
45   -
46   -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
47   - * faster
48   - */
49   -#ifndef HTTP_PARSER_STRICT
50   -# define HTTP_PARSER_STRICT 1
51   -#endif
52   -
53   -/* Maximium header size allowed */
54   -#define HTTP_MAX_HEADER_SIZE (80*1024)
55   -
56   -
57   -typedef struct http_parser http_parser;
58   -typedef struct http_parser_settings http_parser_settings;
59   -
60   -
61   -/* Callbacks should return non-zero to indicate an error. The parser will
62   - * then halt execution.
63   - *
64   - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
65   - * returning '1' from on_headers_complete will tell the parser that it
66   - * should not expect a body. This is used when receiving a response to a
67   - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
68   - * chunked' headers that indicate the presence of a body.
69   - *
70   - * http_data_cb does not return data chunks. It will be call arbitrarally
71   - * many times for each string. E.G. you might get 10 callbacks for "on_url"
72   - * each providing just a few characters more data.
73   - */
74   -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
75   -typedef int (*http_cb) (http_parser*);
76   -
77   -
78   -/* Request Methods */
79   -#define HTTP_METHOD_MAP(XX) \
80   - XX(0, DELETE, DELETE) \
81   - XX(1, GET, GET) \
82   - XX(2, HEAD, HEAD) \
83   - XX(3, POST, POST) \
84   - XX(4, PUT, PUT) \
85   - /* pathological */ \
86   - XX(5, CONNECT, CONNECT) \
87   - XX(6, OPTIONS, OPTIONS) \
88   - XX(7, TRACE, TRACE) \
89   - /* webdav */ \
90   - XX(8, COPY, COPY) \
91   - XX(9, LOCK, LOCK) \
92   - XX(10, MKCOL, MKCOL) \
93   - XX(11, MOVE, MOVE) \
94   - XX(12, PROPFIND, PROPFIND) \
95   - XX(13, PROPPATCH, PROPPATCH) \
96   - XX(14, SEARCH, SEARCH) \
97   - XX(15, UNLOCK, UNLOCK) \
98   - /* subversion */ \
99   - XX(16, REPORT, REPORT) \
100   - XX(17, MKACTIVITY, MKACTIVITY) \
101   - XX(18, CHECKOUT, CHECKOUT) \
102   - XX(19, MERGE, MERGE) \
103   - /* upnp */ \
104   - XX(20, MSEARCH, M-SEARCH) \
105   - XX(21, NOTIFY, NOTIFY) \
106   - XX(22, SUBSCRIBE, SUBSCRIBE) \
107   - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
108   - /* RFC-5789 */ \
109   - XX(24, PATCH, PATCH) \
110   - XX(25, PURGE, PURGE) \
111   -
112   -enum http_method
113   - {
114   -#define XX(num, name, string) HTTP_##name = num,
115   - HTTP_METHOD_MAP(XX)
116   -#undef XX
117   - };
118   -
119   -
120   -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
121   -
122   -
123   -/* Flag values for http_parser.flags field */
124   -enum flags
125   - { F_CHUNKED = 1 << 0
126   - , F_CONNECTION_KEEP_ALIVE = 1 << 1
127   - , F_CONNECTION_CLOSE = 1 << 2
128   - , F_TRAILING = 1 << 3
129   - , F_UPGRADE = 1 << 4
130   - , F_SKIPBODY = 1 << 5
131   - };
132   -
133   -
134   -/* Map for errno-related constants
135   - *
136   - * The provided argument should be a macro that takes 2 arguments.
137   - */
138   -#define HTTP_ERRNO_MAP(XX) \
139   - /* No error */ \
140   - XX(OK, "success") \
141   - \
142   - /* Callback-related errors */ \
143   - XX(CB_message_begin, "the on_message_begin callback failed") \
144   - XX(CB_status_complete, "the on_status_complete callback failed") \
145   - XX(CB_url, "the on_url callback failed") \
146   - XX(CB_header_field, "the on_header_field callback failed") \
147   - XX(CB_header_value, "the on_header_value callback failed") \
148   - XX(CB_headers_complete, "the on_headers_complete callback failed") \
149   - XX(CB_body, "the on_body callback failed") \
150   - XX(CB_message_complete, "the on_message_complete callback failed") \
151   - \
152   - /* Parsing-related errors */ \
153   - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
154   - XX(HEADER_OVERFLOW, \
155   - "too many header bytes seen; overflow detected") \
156   - XX(CLOSED_CONNECTION, \
157   - "data received after completed connection: close message") \
158   - XX(INVALID_VERSION, "invalid HTTP version") \
159   - XX(INVALID_STATUS, "invalid HTTP status code") \
160   - XX(INVALID_METHOD, "invalid HTTP method") \
161   - XX(INVALID_URL, "invalid URL") \
162   - XX(INVALID_HOST, "invalid host") \
163   - XX(INVALID_PORT, "invalid port") \
164   - XX(INVALID_PATH, "invalid path") \
165   - XX(INVALID_QUERY_STRING, "invalid query string") \
166   - XX(INVALID_FRAGMENT, "invalid fragment") \
167   - XX(LF_EXPECTED, "LF character expected") \
168   - XX(INVALID_HEADER_TOKEN, "invalid character in header") \
169   - XX(INVALID_CONTENT_LENGTH, \
170   - "invalid character in content-length header") \
171   - XX(INVALID_CHUNK_SIZE, \
172   - "invalid character in chunk size header") \
173   - XX(INVALID_CONSTANT, "invalid constant string") \
174   - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
175   - XX(STRICT, "strict mode assertion failed") \
176   - XX(PAUSED, "parser is paused") \
177   - XX(UNKNOWN, "an unknown error occurred")
178   -
179   -
180   -/* Define HPE_* values for each errno value above */
181   -#define HTTP_ERRNO_GEN(n, s) HPE_##n,
182   -enum http_errno {
183   - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
184   -};
185   -#undef HTTP_ERRNO_GEN
186   -
187   -
188   -/* Get an http_errno value from an http_parser */
189   -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
190   -
191   -
192   -struct http_parser {
193   - /** PRIVATE **/
194   - unsigned char type : 2; /* enum http_parser_type */
195   - unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
196   - unsigned char state; /* enum state from http_parser.c */
197   - unsigned char header_state; /* enum header_state from http_parser.c */
198   - unsigned char index; /* index into current matcher */
199   -
200   - uint32_t nread; /* # bytes read in various scenarios */
201   - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
202   -
203   - /** READ-ONLY **/
204   - unsigned short http_major;
205   - unsigned short http_minor;
206   - unsigned short status_code; /* responses only */
207   - unsigned char method; /* requests only */
208   - unsigned char http_errno : 7;
209   -
210   - /* 1 = Upgrade header was present and the parser has exited because of that.
211   - * 0 = No upgrade header present.
212   - * Should be checked when http_parser_execute() returns in addition to
213   - * error checking.
214   - */
215   - unsigned char upgrade : 1;
216   -
217   - /** PUBLIC **/
218   - void *data; /* A pointer to get hook to the "connection" or "socket" object */
219   -};
220   -
221   -
222   -struct http_parser_settings {
223   - http_cb on_message_begin;
224   - http_data_cb on_url;
225   - http_cb on_status_complete;
226   - http_data_cb on_header_field;
227   - http_data_cb on_header_value;
228   - http_cb on_headers_complete;
229   - http_data_cb on_body;
230   - http_cb on_message_complete;
231   -};
232   -
233   -
234   -enum http_parser_url_fields
235   - { UF_SCHEMA = 0
236   - , UF_HOST = 1
237   - , UF_PORT = 2
238   - , UF_PATH = 3
239   - , UF_QUERY = 4
240   - , UF_FRAGMENT = 5
241   - , UF_USERINFO = 6
242   - , UF_MAX = 7
243   - };
244   -
245   -
246   -/* Result structure for http_parser_parse_url().
247   - *
248   - * Callers should index into field_data[] with UF_* values iff field_set
249   - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
250   - * because we probably have padding left over), we convert any port to
251   - * a uint16_t.
252   - */
253   -struct http_parser_url {
254   - uint16_t field_set; /* Bitmask of (1 << UF_*) values */
255   - uint16_t port; /* Converted UF_PORT string */
256   -
257   - struct {
258   - uint16_t off; /* Offset into buffer in which field starts */
259   - uint16_t len; /* Length of run in buffer */
260   - } field_data[UF_MAX];
261   -};
262   -
263   -
264   -void http_parser_init(http_parser *parser, enum http_parser_type type);
265   -
266   -
267   -size_t http_parser_execute(http_parser *parser,
268   - const http_parser_settings *settings,
269   - const char *data,
270   - size_t len);
271   -
272   -
273   -/* If http_should_keep_alive() in the on_headers_complete or
274   - * on_message_complete callback returns 0, then this should be
275   - * the last message on the connection.
276   - * If you are the server, respond with the "Connection: close" header.
277   - * If you are the client, close the connection.
278   - */
279   -int http_should_keep_alive(const http_parser *parser);
280   -
281   -/* Returns a string version of the HTTP method. */
282   -const char *http_method_str(enum http_method m);
283   -
284   -/* Return a string name of the given error */
285   -const char *http_errno_name(enum http_errno err);
286   -
287   -/* Return a string description of the given error */
288   -const char *http_errno_description(enum http_errno err);
289   -
290   -/* Parse a URL; return nonzero on failure */
291   -int http_parser_parse_url(const char *buf, size_t buflen,
292   - int is_connect,
293   - struct http_parser_url *u);
294   -
295   -/* Pause or un-pause the parser; a nonzero value pauses */
296   -void http_parser_pause(http_parser *parser, int paused);
297   -
298   -/* Checks if this is the final chunk of the body. */
299   -int http_body_is_final(const http_parser *parser);
300   -
301   -#ifdef __cplusplus
302   -}
303   -#endif
304   -#endif
3rdparty/http-parser-2.1/test.c deleted
1   -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2   - *
3   - * Permission is hereby granted, free of charge, to any person obtaining a copy
4   - * of this software and associated documentation files (the "Software"), to
5   - * deal in the Software without restriction, including without limitation the
6   - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7   - * sell copies of the Software, and to permit persons to whom the Software is
8   - * furnished to do so, subject to the following conditions:
9   - *
10   - * The above copyright notice and this permission notice shall be included in
11   - * all copies or substantial portions of the Software.
12   - *
13   - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14   - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15   - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16   - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17   - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18   - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19   - * IN THE SOFTWARE.
20   - */
21   -#include "http_parser.h"
22   -#include <stdlib.h>
23   -#include <assert.h>
24   -#include <stdio.h>
25   -#include <stdlib.h> /* rand */
26   -#include <string.h>
27   -#include <stdarg.h>
28   -
29   -#undef TRUE
30   -#define TRUE 1
31   -#undef FALSE
32   -#define FALSE 0
33   -
34   -#define MAX_HEADERS 13
35   -#define MAX_ELEMENT_SIZE 2048
36   -
37   -#define MIN(a,b) ((a) < (b) ? (a) : (b))
38   -
39   -static http_parser *parser;
40   -
41   -struct message {
42   - const char *name; // for debugging purposes
43   - const char *raw;
44   - enum http_parser_type type;
45   - enum http_method method;
46   - int status_code;
47   - char request_path[MAX_ELEMENT_SIZE];
48   - char request_url[MAX_ELEMENT_SIZE];
49   - char fragment[MAX_ELEMENT_SIZE];
50   - char query_string[MAX_ELEMENT_SIZE];
51   - char body[MAX_ELEMENT_SIZE];
52   - size_t body_size;
53   - const char *host;
54   - const char *userinfo;
55   - uint16_t port;
56   - int num_headers;
57   - enum { NONE=0, FIELD, VALUE } last_header_element;
58   - char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
59   - int should_keep_alive;
60   -
61   - const char *upgrade; // upgraded body
62   -
63   - unsigned short http_major;
64   - unsigned short http_minor;
65   -
66   - int message_begin_cb_called;
67   - int headers_complete_cb_called;
68   - int message_complete_cb_called;
69   - int message_complete_on_eof;
70   - int body_is_final;
71   -};
72   -
73   -static int currently_parsing_eof;
74   -
75   -static struct message messages[5];
76   -static int num_messages;
77   -static http_parser_settings *current_pause_parser;
78   -
79   -/* * R E Q U E S T S * */
80   -const struct message requests[] =
81   -#define CURL_GET 0
82   -{ {.name= "curl get"
83   - ,.type= HTTP_REQUEST
84   - ,.raw= "GET /test HTTP/1.1\r\n"
85   - "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"
86   - "Host: 0.0.0.0=5000\r\n"
87   - "Accept: */*\r\n"
88   - "\r\n"
89   - ,.should_keep_alive= TRUE
90   - ,.message_complete_on_eof= FALSE
91   - ,.http_major= 1
92   - ,.http_minor= 1
93   - ,.method= HTTP_GET
94   - ,.query_string= ""
95   - ,.fragment= ""
96   - ,.request_path= "/test"
97   - ,.request_url= "/test"
98   - ,.num_headers= 3
99   - ,.headers=
100   - { { "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" }
101   - , { "Host", "0.0.0.0=5000" }
102   - , { "Accept", "*/*" }
103   - }
104   - ,.body= ""
105   - }
106   -
107   -#define FIREFOX_GET 1
108   -, {.name= "firefox get"
109   - ,.type= HTTP_REQUEST
110   - ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
111   - "Host: 0.0.0.0=5000\r\n"
112   - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
113   - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
114   - "Accept-Language: en-us,en;q=0.5\r\n"
115   - "Accept-Encoding: gzip,deflate\r\n"
116   - "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
117   - "Keep-Alive: 300\r\n"
118   - "Connection: keep-alive\r\n"
119   - "\r\n"
120   - ,.should_keep_alive= TRUE
121   - ,.message_complete_on_eof= FALSE
122   - ,.http_major= 1
123   - ,.http_minor= 1
124   - ,.method= HTTP_GET
125   - ,.query_string= ""
126   - ,.fragment= ""
127   - ,.request_path= "/favicon.ico"
128   - ,.request_url= "/favicon.ico"
129   - ,.num_headers= 8
130   - ,.headers=
131   - { { "Host", "0.0.0.0=5000" }
132   - , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" }
133   - , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }
134   - , { "Accept-Language", "en-us,en;q=0.5" }
135   - , { "Accept-Encoding", "gzip,deflate" }
136   - , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" }
137   - , { "Keep-Alive", "300" }
138   - , { "Connection", "keep-alive" }
139   - }
140   - ,.body= ""
141   - }
142   -
143   -#define DUMBFUCK 2
144   -, {.name= "dumbfuck"
145   - ,.type= HTTP_REQUEST
146   - ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
147   - "aaaaaaaaaaaaa:++++++++++\r\n"
148   - "\r\n"
149   - ,.should_keep_alive= TRUE
150   - ,.message_complete_on_eof= FALSE
151   - ,.http_major= 1
152   - ,.http_minor= 1
153   - ,.method= HTTP_GET
154   - ,.query_string= ""
155   - ,.fragment= ""
156   - ,.request_path= "/dumbfuck"
157   - ,.request_url= "/dumbfuck"
158   - ,.num_headers= 1
159   - ,.headers=
160   - { { "aaaaaaaaaaaaa", "++++++++++" }
161   - }
162   - ,.body= ""
163   - }
164   -
165   -#define FRAGMENT_IN_URI 3
166   -, {.name= "fragment in url"
167   - ,.type= HTTP_REQUEST
168   - ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
169   - "\r\n"
170   - ,.should_keep_alive= TRUE
171   - ,.message_complete_on_eof= FALSE
172   - ,.http_major= 1
173   - ,.http_minor= 1
174   - ,.method= HTTP_GET
175   - ,.query_string= "page=1"
176   - ,.fragment= "posts-17408"
177   - ,.request_path= "/forums/1/topics/2375"
178   - /* XXX request url does include fragment? */
179   - ,.request_url= "/forums/1/topics/2375?page=1#posts-17408"
180   - ,.num_headers= 0
181   - ,.body= ""
182   - }
183   -
184   -#define GET_NO_HEADERS_NO_BODY 4
185   -, {.name= "get no headers no body"
186   - ,.type= HTTP_REQUEST
187   - ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
188   - "\r\n"
189   - ,.should_keep_alive= TRUE
190   - ,.message_complete_on_eof= FALSE /* would need Connection: close */
191   - ,.http_major= 1
192   - ,.http_minor= 1
193   - ,.method= HTTP_GET
194   - ,.query_string= ""
195   - ,.fragment= ""
196   - ,.request_path= "/get_no_headers_no_body/world"
197   - ,.request_url= "/get_no_headers_no_body/world"
198   - ,.num_headers= 0
199   - ,.body= ""
200   - }
201   -
202   -#define GET_ONE_HEADER_NO_BODY 5
203   -, {.name= "get one header no body"
204   - ,.type= HTTP_REQUEST
205   - ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
206   - "Accept: */*\r\n"
207   - "\r\n"
208   - ,.should_keep_alive= TRUE
209   - ,.message_complete_on_eof= FALSE /* would need Connection: close */
210   - ,.http_major= 1
211   - ,.http_minor= 1
212   - ,.method= HTTP_GET
213   - ,.query_string= ""
214   - ,.fragment= ""
215   - ,.request_path= "/get_one_header_no_body"
216   - ,.request_url= "/get_one_header_no_body"
217   - ,.num_headers= 1
218   - ,.headers=
219   - { { "Accept" , "*/*" }
220   - }
221   - ,.body= ""
222   - }
223   -
224   -#define GET_FUNKY_CONTENT_LENGTH 6
225   -, {.name= "get funky content length body hello"
226   - ,.type= HTTP_REQUEST
227   - ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
228   - "conTENT-Length: 5\r\n"
229   - "\r\n"
230   - "HELLO"
231   - ,.should_keep_alive= FALSE
232   - ,.message_complete_on_eof= FALSE
233   - ,.http_major= 1
234   - ,.http_minor= 0
235   - ,.method= HTTP_GET
236   - ,.query_string= ""
237   - ,.fragment= ""
238   - ,.request_path= "/get_funky_content_length_body_hello"
239   - ,.request_url= "/get_funky_content_length_body_hello"
240   - ,.num_headers= 1
241   - ,.headers=
242   - { { "conTENT-Length" , "5" }
243   - }
244   - ,.body= "HELLO"
245   - }
246   -
247   -#define POST_IDENTITY_BODY_WORLD 7
248   -, {.name= "post identity body world"
249   - ,.type= HTTP_REQUEST
250   - ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
251   - "Accept: */*\r\n"
252   - "Transfer-Encoding: identity\r\n"
253   - "Content-Length: 5\r\n"
254   - "\r\n"
255   - "World"
256   - ,.should_keep_alive= TRUE
257   - ,.message_complete_on_eof= FALSE
258   - ,.http_major= 1
259   - ,.http_minor= 1
260   - ,.method= HTTP_POST
261   - ,.query_string= "q=search"
262   - ,.fragment= "hey"
263   - ,.request_path= "/post_identity_body_world"
264   - ,.request_url= "/post_identity_body_world?q=search#hey"
265   - ,.num_headers= 3
266   - ,.headers=
267   - { { "Accept", "*/*" }
268   - , { "Transfer-Encoding", "identity" }
269   - , { "Content-Length", "5" }
270   - }
271   - ,.body= "World"
272   - }
273   -
274   -#define POST_CHUNKED_ALL_YOUR_BASE 8
275   -, {.name= "post - chunked body: all your base are belong to us"
276   - ,.type= HTTP_REQUEST
277   - ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
278   - "Transfer-Encoding: chunked\r\n"
279   - "\r\n"
280   - "1e\r\nall your base are belong to us\r\n"
281   - "0\r\n"
282   - "\r\n"
283   - ,.should_keep_alive= TRUE
284   - ,.message_complete_on_eof= FALSE
285   - ,.http_major= 1
286   - ,.http_minor= 1
287   - ,.method= HTTP_POST
288   - ,.query_string= ""
289   - ,.fragment= ""
290   - ,.request_path= "/post_chunked_all_your_base"
291   - ,.request_url= "/post_chunked_all_your_base"
292   - ,.num_headers= 1
293   - ,.headers=
294   - { { "Transfer-Encoding" , "chunked" }
295   - }
296   - ,.body= "all your base are belong to us"
297   - }
298   -
299   -#define TWO_CHUNKS_MULT_ZERO_END 9
300   -, {.name= "two chunks ; triple zero ending"
301   - ,.type= HTTP_REQUEST
302   - ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
303   - "Transfer-Encoding: chunked\r\n"
304   - "\r\n"
305   - "5\r\nhello\r\n"
306   - "6\r\n world\r\n"
307   - "000\r\n"
308   - "\r\n"
309   - ,.should_keep_alive= TRUE
310   - ,.message_complete_on_eof= FALSE
311   - ,.http_major= 1
312   - ,.http_minor= 1
313   - ,.method= HTTP_POST
314   - ,.query_string= ""
315   - ,.fragment= ""
316   - ,.request_path= "/two_chunks_mult_zero_end"
317   - ,.request_url= "/two_chunks_mult_zero_end"
318   - ,.num_headers= 1
319   - ,.headers=
320   - { { "Transfer-Encoding", "chunked" }
321   - }
322   - ,.body= "hello world"
323   - }
324   -
325   -#define CHUNKED_W_TRAILING_HEADERS 10
326   -, {.name= "chunked with trailing headers. blech."
327   - ,.type= HTTP_REQUEST
328   - ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
329   - "Transfer-Encoding: chunked\r\n"
330   - "\r\n"
331   - "5\r\nhello\r\n"
332   - "6\r\n world\r\n"
333   - "0\r\n"
334   - "Vary: *\r\n"
335   - "Content-Type: text/plain\r\n"
336   - "\r\n"
337   - ,.should_keep_alive= TRUE
338   - ,.message_complete_on_eof= FALSE
339   - ,.http_major= 1
340   - ,.http_minor= 1
341   - ,.method= HTTP_POST
342   - ,.query_string= ""
343   - ,.fragment= ""
344   - ,.request_path= "/chunked_w_trailing_headers"
345   - ,.request_url= "/chunked_w_trailing_headers"
346   - ,.num_headers= 3
347   - ,.headers=
348   - { { "Transfer-Encoding", "chunked" }
349   - , { "Vary", "*" }
350   - , { "Content-Type", "text/plain" }
351   - }
352   - ,.body= "hello world"
353   - }
354   -
355   -#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
356   -, {.name= "with bullshit after the length"
357   - ,.type= HTTP_REQUEST
358   - ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
359   - "Transfer-Encoding: chunked\r\n"
360   - "\r\n"
361   - "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
362   - "6; blahblah; blah\r\n world\r\n"
363   - "0\r\n"
364   - "\r\n"
365   - ,.should_keep_alive= TRUE
366   - ,.message_complete_on_eof= FALSE
367   - ,.http_major= 1
368   - ,.http_minor= 1
369   - ,.method= HTTP_POST
370   - ,.query_string= ""
371   - ,.fragment= ""
372   - ,.request_path= "/chunked_w_bullshit_after_length"
373   - ,.request_url= "/chunked_w_bullshit_after_length"
374   - ,.num_headers= 1
375   - ,.headers=
376   - { { "Transfer-Encoding", "chunked" }
377   - }
378   - ,.body= "hello world"
379   - }
380   -
381   -#define WITH_QUOTES 12
382   -, {.name= "with quotes"
383   - ,.type= HTTP_REQUEST
384   - ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
385   - ,.should_keep_alive= TRUE
386   - ,.message_complete_on_eof= FALSE
387   - ,.http_major= 1
388   - ,.http_minor= 1
389   - ,.method= HTTP_GET
390   - ,.query_string= "foo=\"bar\""
391   - ,.fragment= ""
392   - ,.request_path= "/with_\"stupid\"_quotes"
393   - ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\""
394   - ,.num_headers= 0
395   - ,.headers= { }
396   - ,.body= ""
397   - }
398   -
399   -#define APACHEBENCH_GET 13
400   -/* The server receiving this request SHOULD NOT wait for EOF
401   - * to know that content-length == 0.
402   - * How to represent this in a unit test? message_complete_on_eof
403   - * Compare with NO_CONTENT_LENGTH_RESPONSE.
404   - */
405   -, {.name = "apachebench get"
406   - ,.type= HTTP_REQUEST
407   - ,.raw= "GET /test HTTP/1.0\r\n"
408   - "Host: 0.0.0.0:5000\r\n"
409   - "User-Agent: ApacheBench/2.3\r\n"
410   - "Accept: */*\r\n\r\n"
411   - ,.should_keep_alive= FALSE
412   - ,.message_complete_on_eof= FALSE
413   - ,.http_major= 1
414   - ,.http_minor= 0
415   - ,.method= HTTP_GET
416   - ,.query_string= ""
417   - ,.fragment= ""
418   - ,.request_path= "/test"
419   - ,.request_url= "/test"
420   - ,.num_headers= 3
421   - ,.headers= { { "Host", "0.0.0.0:5000" }
422   - , { "User-Agent", "ApacheBench/2.3" }
423   - , { "Accept", "*/*" }
424   - }
425   - ,.body= ""
426   - }
427   -
428   -#define QUERY_URL_WITH_QUESTION_MARK_GET 14
429   -/* Some clients include '?' characters in query strings.
430   - */
431   -, {.name = "query url with question mark"
432   - ,.type= HTTP_REQUEST
433   - ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n"
434   - ,.should_keep_alive= TRUE
435   - ,.message_complete_on_eof= FALSE
436   - ,.http_major= 1
437   - ,.http_minor= 1
438   - ,.method= HTTP_GET
439   - ,.query_string= "foo=bar?baz"
440   - ,.fragment= ""
441   - ,.request_path= "/test.cgi"
442   - ,.request_url= "/test.cgi?foo=bar?baz"
443   - ,.num_headers= 0
444   - ,.headers= {}
445   - ,.body= ""
446   - }
447   -
448   -#define PREFIX_NEWLINE_GET 15
449   -/* Some clients, especially after a POST in a keep-alive connection,
450   - * will send an extra CRLF before the next request
451   - */
452   -, {.name = "newline prefix get"
453   - ,.type= HTTP_REQUEST
454   - ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n"
455   - ,.should_keep_alive= TRUE
456   - ,.message_complete_on_eof= FALSE
457   - ,.http_major= 1
458   - ,.http_minor= 1
459   - ,.method= HTTP_GET
460   - ,.query_string= ""
461   - ,.fragment= ""
462   - ,.request_path= "/test"
463   - ,.request_url= "/test"
464   - ,.num_headers= 0
465   - ,.headers= { }
466   - ,.body= ""
467   - }
468   -
469   -#define UPGRADE_REQUEST 16
470   -, {.name = "upgrade request"
471   - ,.type= HTTP_REQUEST
472   - ,.raw= "GET /demo HTTP/1.1\r\n"
473   - "Host: example.com\r\n"
474   - "Connection: Upgrade\r\n"
475   - "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
476   - "Sec-WebSocket-Protocol: sample\r\n"
477   - "Upgrade: WebSocket\r\n"
478   - "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
479   - "Origin: http://example.com\r\n"
480   - "\r\n"
481   - "Hot diggity dogg"
482   - ,.should_keep_alive= TRUE
483   - ,.message_complete_on_eof= FALSE
484   - ,.http_major= 1
485   - ,.http_minor= 1
486   - ,.method= HTTP_GET
487   - ,.query_string= ""
488   - ,.fragment= ""
489   - ,.request_path= "/demo"
490   - ,.request_url= "/demo"
491   - ,.num_headers= 7
492   - ,.upgrade="Hot diggity dogg"
493   - ,.headers= { { "Host", "example.com" }
494   - , { "Connection", "Upgrade" }
495   - , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
496   - , { "Sec-WebSocket-Protocol", "sample" }
497   - , { "Upgrade", "WebSocket" }
498   - , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
499   - , { "Origin", "http://example.com" }
500   - }
501   - ,.body= ""
502   - }
503   -
504   -#define CONNECT_REQUEST 17
505   -, {.name = "connect request"
506   - ,.type= HTTP_REQUEST
507   - ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
508   - "User-agent: Mozilla/1.1N\r\n"
509   - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
510   - "\r\n"
511   - "some data\r\n"
512   - "and yet even more data"
513   - ,.should_keep_alive= FALSE
514   - ,.message_complete_on_eof= FALSE
515   - ,.http_major= 1
516   - ,.http_minor= 0
517   - ,.method= HTTP_CONNECT
518   - ,.query_string= ""
519   - ,.fragment= ""
520   - ,.request_path= ""
521   - ,.request_url= "0-home0.netscape.com:443"
522   - ,.num_headers= 2
523   - ,.upgrade="some data\r\nand yet even more data"
524   - ,.headers= { { "User-agent", "Mozilla/1.1N" }
525   - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
526   - }
527   - ,.body= ""
528   - }
529   -
530   -#define REPORT_REQ 18
531   -, {.name= "report request"
532   - ,.type= HTTP_REQUEST
533   - ,.raw= "REPORT /test HTTP/1.1\r\n"
534   - "\r\n"
535   - ,.should_keep_alive= TRUE
536   - ,.message_complete_on_eof= FALSE
537   - ,.http_major= 1
538   - ,.http_minor= 1
539   - ,.method= HTTP_REPORT
540   - ,.query_string= ""
541   - ,.fragment= ""
542   - ,.request_path= "/test"
543   - ,.request_url= "/test"
544   - ,.num_headers= 0
545   - ,.headers= {}
546   - ,.body= ""
547   - }
548   -
549   -#define NO_HTTP_VERSION 19
550   -, {.name= "request with no http version"
551   - ,.type= HTTP_REQUEST
552   - ,.raw= "GET /\r\n"
553   - "\r\n"
554   - ,.should_keep_alive= FALSE
555   - ,.message_complete_on_eof= FALSE
556   - ,.http_major= 0
557   - ,.http_minor= 9
558   - ,.method= HTTP_GET
559   - ,.query_string= ""
560   - ,.fragment= ""
561   - ,.request_path= "/"
562   - ,.request_url= "/"
563   - ,.num_headers= 0
564   - ,.headers= {}
565   - ,.body= ""
566   - }
567   -
568   -#define MSEARCH_REQ 20
569   -, {.name= "m-search request"
570   - ,.type= HTTP_REQUEST
571   - ,.raw= "M-SEARCH * HTTP/1.1\r\n"
572   - "HOST: 239.255.255.250:1900\r\n"
573   - "MAN: \"ssdp:discover\"\r\n"
574   - "ST: \"ssdp:all\"\r\n"
575   - "\r\n"
576   - ,.should_keep_alive= TRUE
577   - ,.message_complete_on_eof= FALSE
578   - ,.http_major= 1
579   - ,.http_minor= 1
580   - ,.method= HTTP_MSEARCH
581   - ,.query_string= ""
582   - ,.fragment= ""
583   - ,.request_path= "*"
584   - ,.request_url= "*"
585   - ,.num_headers= 3
586   - ,.headers= { { "HOST", "239.255.255.250:1900" }
587   - , { "MAN", "\"ssdp:discover\"" }
588   - , { "ST", "\"ssdp:all\"" }
589   - }
590   - ,.body= ""
591   - }
592   -
593   -#define LINE_FOLDING_IN_HEADER 21
594   -, {.name= "line folding in header value"
595   - ,.type= HTTP_REQUEST
596   - ,.raw= "GET / HTTP/1.1\r\n"
597   - "Line1: abc\r\n"
598   - "\tdef\r\n"
599   - " ghi\r\n"
600   - "\t\tjkl\r\n"
601   - " mno \r\n"
602   - "\t \tqrs\r\n"
603   - "Line2: \t line2\t\r\n"
604   - "\r\n"
605   - ,.should_keep_alive= TRUE
606   - ,.message_complete_on_eof= FALSE
607   - ,.http_major= 1
608   - ,.http_minor= 1
609   - ,.method= HTTP_GET
610   - ,.query_string= ""
611   - ,.fragment= ""
612   - ,.request_path= "/"
613   - ,.request_url= "/"
614   - ,.num_headers= 2
615   - ,.headers= { { "Line1", "abcdefghijklmno qrs" }
616   - , { "Line2", "line2\t" }
617   - }
618   - ,.body= ""
619   - }
620   -
621   -
622   -#define QUERY_TERMINATED_HOST 22
623   -, {.name= "host terminated by a query string"
624   - ,.type= HTTP_REQUEST
625   - ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
626   - "\r\n"
627   - ,.should_keep_alive= TRUE
628   - ,.message_complete_on_eof= FALSE
629   - ,.http_major= 1
630   - ,.http_minor= 1
631   - ,.method= HTTP_GET
632   - ,.query_string= "hail=all"
633   - ,.fragment= ""
634   - ,.request_path= ""
635   - ,.request_url= "http://hypnotoad.org?hail=all"
636   - ,.host= "hypnotoad.org"
637   - ,.num_headers= 0
638   - ,.headers= { }
639   - ,.body= ""
640   - }
641   -
642   -#define QUERY_TERMINATED_HOSTPORT 23
643   -, {.name= "host:port terminated by a query string"
644   - ,.type= HTTP_REQUEST
645   - ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
646   - "\r\n"
647   - ,.should_keep_alive= TRUE
648   - ,.message_complete_on_eof= FALSE
649   - ,.http_major= 1
650   - ,.http_minor= 1
651   - ,.method= HTTP_GET
652   - ,.query_string= "hail=all"
653   - ,.fragment= ""
654   - ,.request_path= ""
655   - ,.request_url= "http://hypnotoad.org:1234?hail=all"
656   - ,.host= "hypnotoad.org"
657   - ,.port= 1234
658   - ,.num_headers= 0
659   - ,.headers= { }
660   - ,.body= ""
661   - }
662   -
663   -#define SPACE_TERMINATED_HOSTPORT 24
664   -, {.name= "host:port terminated by a space"
665   - ,.type= HTTP_REQUEST
666   - ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
667   - "\r\n"
668   - ,.should_keep_alive= TRUE
669   - ,.message_complete_on_eof= FALSE
670   - ,.http_major= 1
671   - ,.http_minor= 1
672   - ,.method= HTTP_GET
673   - ,.query_string= ""
674   - ,.fragment= ""
675   - ,.request_path= ""
676   - ,.request_url= "http://hypnotoad.org:1234"
677   - ,.host= "hypnotoad.org"
678   - ,.port= 1234
679   - ,.num_headers= 0
680   - ,.headers= { }
681   - ,.body= ""
682   - }
683   -
684   -#define PATCH_REQ 25
685   -, {.name = "PATCH request"
686   - ,.type= HTTP_REQUEST
687   - ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
688   - "Host: www.example.com\r\n"
689   - "Content-Type: application/example\r\n"
690   - "If-Match: \"e0023aa4e\"\r\n"
691   - "Content-Length: 10\r\n"
692   - "\r\n"
693   - "cccccccccc"
694   - ,.should_keep_alive= TRUE
695   - ,.message_complete_on_eof= FALSE
696   - ,.http_major= 1
697   - ,.http_minor= 1
698   - ,.method= HTTP_PATCH
699   - ,.query_string= ""
700   - ,.fragment= ""
701   - ,.request_path= "/file.txt"
702   - ,.request_url= "/file.txt"
703   - ,.num_headers= 4
704   - ,.headers= { { "Host", "www.example.com" }
705   - , { "Content-Type", "application/example" }
706   - , { "If-Match", "\"e0023aa4e\"" }
707   - , { "Content-Length", "10" }
708   - }
709   - ,.body= "cccccccccc"
710   - }
711   -
712   -#define CONNECT_CAPS_REQUEST 26
713   -, {.name = "connect caps request"
714   - ,.type= HTTP_REQUEST
715   - ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
716   - "User-agent: Mozilla/1.1N\r\n"
717   - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
718   - "\r\n"
719   - ,.should_keep_alive= FALSE
720   - ,.message_complete_on_eof= FALSE
721   - ,.http_major= 1
722   - ,.http_minor= 0
723   - ,.method= HTTP_CONNECT
724   - ,.query_string= ""
725   - ,.fragment= ""
726   - ,.request_path= ""
727   - ,.request_url= "HOME0.NETSCAPE.COM:443"
728   - ,.num_headers= 2
729   - ,.upgrade=""
730   - ,.headers= { { "User-agent", "Mozilla/1.1N" }
731   - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
732   - }
733   - ,.body= ""
734   - }
735   -
736   -#if !HTTP_PARSER_STRICT
737   -#define UTF8_PATH_REQ 27
738   -, {.name= "utf-8 path request"
739   - ,.type= HTTP_REQUEST
740   - ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
741   - "Host: github.com\r\n"
742   - "\r\n"
743   - ,.should_keep_alive= TRUE
744   - ,.message_complete_on_eof= FALSE
745   - ,.http_major= 1
746   - ,.http_minor= 1
747   - ,.method= HTTP_GET
748   - ,.query_string= "q=1"
749   - ,.fragment= "narf"
750   - ,.request_path= "/δ¶/δt/pope"
751   - ,.request_url= "/δ¶/δt/pope?q=1#narf"
752   - ,.num_headers= 1
753   - ,.headers= { {"Host", "github.com" }
754   - }
755   - ,.body= ""
756   - }
757   -
758   -#define HOSTNAME_UNDERSCORE 28
759   -, {.name = "hostname underscore"
760   - ,.type= HTTP_REQUEST
761   - ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
762   - "User-agent: Mozilla/1.1N\r\n"
763   - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
764   - "\r\n"
765   - ,.should_keep_alive= FALSE
766   - ,.message_complete_on_eof= FALSE
767   - ,.http_major= 1
768   - ,.http_minor= 0
769   - ,.method= HTTP_CONNECT
770   - ,.query_string= ""
771   - ,.fragment= ""
772   - ,.request_path= ""
773   - ,.request_url= "home_0.netscape.com:443"
774   - ,.num_headers= 2
775   - ,.upgrade=""
776   - ,.headers= { { "User-agent", "Mozilla/1.1N" }
777   - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
778   - }
779   - ,.body= ""
780   - }
781   -#endif /* !HTTP_PARSER_STRICT */
782   -
783   -/* see https://github.com/ry/http-parser/issues/47 */
784   -#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
785   -, {.name = "eat CRLF between requests, no \"Connection: close\" header"
786   - ,.raw= "POST / HTTP/1.1\r\n"
787   - "Host: www.example.com\r\n"
788   - "Content-Type: application/x-www-form-urlencoded\r\n"
789   - "Content-Length: 4\r\n"
790   - "\r\n"
791   - "q=42\r\n" /* note the trailing CRLF */
792   - ,.should_keep_alive= TRUE
793   - ,.message_complete_on_eof= FALSE
794   - ,.http_major= 1
795   - ,.http_minor= 1
796   - ,.method= HTTP_POST
797   - ,.query_string= ""
798   - ,.fragment= ""
799   - ,.request_path= "/"
800   - ,.request_url= "/"
801   - ,.num_headers= 3
802   - ,.upgrade= 0
803   - ,.headers= { { "Host", "www.example.com" }
804   - , { "Content-Type", "application/x-www-form-urlencoded" }
805   - , { "Content-Length", "4" }
806   - }
807   - ,.body= "q=42"
808   - }
809   -
810   -/* see https://github.com/ry/http-parser/issues/47 */
811   -#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
812   -, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
813   - ,.raw= "POST / HTTP/1.1\r\n"
814   - "Host: www.example.com\r\n"
815   - "Content-Type: application/x-www-form-urlencoded\r\n"
816   - "Content-Length: 4\r\n"
817   - "Connection: close\r\n"
818   - "\r\n"
819   - "q=42\r\n" /* note the trailing CRLF */
820   - ,.should_keep_alive= FALSE
821   - ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
822   - ,.http_major= 1
823   - ,.http_minor= 1
824   - ,.method= HTTP_POST
825   - ,.query_string= ""
826   - ,.fragment= ""
827   - ,.request_path= "/"
828   - ,.request_url= "/"
829   - ,.num_headers= 4
830   - ,.upgrade= 0
831   - ,.headers= { { "Host", "www.example.com" }
832   - , { "Content-Type", "application/x-www-form-urlencoded" }
833   - , { "Content-Length", "4" }
834   - , { "Connection", "close" }
835   - }
836   - ,.body= "q=42"
837   - }
838   -
839   -#define PURGE_REQ 31
840   -, {.name = "PURGE request"
841   - ,.type= HTTP_REQUEST
842   - ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
843   - "Host: www.example.com\r\n"
844   - "\r\n"
845   - ,.should_keep_alive= TRUE
846   - ,.message_complete_on_eof= FALSE
847   - ,.http_major= 1
848   - ,.http_minor= 1
849   - ,.method= HTTP_PURGE
850   - ,.query_string= ""
851   - ,.fragment= ""
852   - ,.request_path= "/file.txt"
853   - ,.request_url= "/file.txt"
854   - ,.num_headers= 1
855   - ,.headers= { { "Host", "www.example.com" } }
856   - ,.body= ""
857   - }
858   -
859   -#define SEARCH_REQ 32
860   -, {.name = "SEARCH request"
861   - ,.type= HTTP_REQUEST
862   - ,.raw= "SEARCH / HTTP/1.1\r\n"
863   - "Host: www.example.com\r\n"
864   - "\r\n"
865   - ,.should_keep_alive= TRUE
866   - ,.message_complete_on_eof= FALSE
867   - ,.http_major= 1
868   - ,.http_minor= 1
869   - ,.method= HTTP_SEARCH
870   - ,.query_string= ""
871   - ,.fragment= ""
872   - ,.request_path= "/"
873   - ,.request_url= "/"
874   - ,.num_headers= 1
875   - ,.headers= { { "Host", "www.example.com" } }
876   - ,.body= ""
877   - }
878   -
879   -#define PROXY_WITH_BASIC_AUTH 33
880   -, {.name= "host:port and basic_auth"
881   - ,.type= HTTP_REQUEST
882   - ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
883   - "\r\n"
884   - ,.should_keep_alive= TRUE
885   - ,.message_complete_on_eof= FALSE
886   - ,.http_major= 1
887   - ,.http_minor= 1
888   - ,.method= HTTP_GET
889   - ,.fragment= ""
890   - ,.request_path= "/toto"
891   - ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
892   - ,.host= "hypnotoad.org"
893   - ,.userinfo= "a%12:b!&*$"
894   - ,.port= 1234
895   - ,.num_headers= 0
896   - ,.headers= { }
897   - ,.body= ""
898   - }
899   -
900   -
901   -, {.name= NULL } /* sentinel */
902   -};
903   -
904   -/* * R E S P O N S E S * */
905   -const struct message responses[] =
906   -#define GOOGLE_301 0
907   -{ {.name= "google 301"
908   - ,.type= HTTP_RESPONSE
909   - ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
910   - "Location: http://www.google.com/\r\n"
911   - "Content-Type: text/html; charset=UTF-8\r\n"
912   - "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
913   - "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
914   - "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
915   - "Cache-Control: public, max-age=2592000\r\n"
916   - "Server: gws\r\n"
917   - "Content-Length: 219 \r\n"
918   - "\r\n"
919   - "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
920   - "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
921   - "<H1>301 Moved</H1>\n"
922   - "The document has moved\n"
923   - "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
924   - "</BODY></HTML>\r\n"
925   - ,.should_keep_alive= TRUE
926   - ,.message_complete_on_eof= FALSE
927   - ,.http_major= 1
928   - ,.http_minor= 1
929   - ,.status_code= 301
930   - ,.num_headers= 8
931   - ,.headers=
932   - { { "Location", "http://www.google.com/" }
933   - , { "Content-Type", "text/html; charset=UTF-8" }
934   - , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
935   - , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
936   - , { "X-$PrototypeBI-Version", "1.6.0.3" }
937   - , { "Cache-Control", "public, max-age=2592000" }
938   - , { "Server", "gws" }
939   - , { "Content-Length", "219 " }
940   - }
941   - ,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
942   - "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
943   - "<H1>301 Moved</H1>\n"
944   - "The document has moved\n"
945   - "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
946   - "</BODY></HTML>\r\n"
947   - }
948   -
949   -#define NO_CONTENT_LENGTH_RESPONSE 1
950   -/* The client should wait for the server's EOF. That is, when content-length
951   - * is not specified, and "Connection: close", the end of body is specified
952   - * by the EOF.
953   - * Compare with APACHEBENCH_GET
954   - */
955   -, {.name= "no content-length response"
956   - ,.type= HTTP_RESPONSE
957   - ,.raw= "HTTP/1.1 200 OK\r\n"
958   - "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
959   - "Server: Apache\r\n"
960   - "X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
961   - "Content-Type: text/xml; charset=utf-8\r\n"
962   - "Connection: close\r\n"
963   - "\r\n"
964   - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
965   - "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
966   - " <SOAP-ENV:Body>\n"
967   - " <SOAP-ENV:Fault>\n"
968   - " <faultcode>SOAP-ENV:Client</faultcode>\n"
969   - " <faultstring>Client Error</faultstring>\n"
970   - " </SOAP-ENV:Fault>\n"
971   - " </SOAP-ENV:Body>\n"
972   - "</SOAP-ENV:Envelope>"
973   - ,.should_keep_alive= FALSE
974   - ,.message_complete_on_eof= TRUE
975   - ,.http_major= 1
976   - ,.http_minor= 1
977   - ,.status_code= 200
978   - ,.num_headers= 5
979   - ,.headers=
980   - { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
981   - , { "Server", "Apache" }
982   - , { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
983   - , { "Content-Type", "text/xml; charset=utf-8" }
984   - , { "Connection", "close" }
985   - }
986   - ,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
987   - "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
988   - " <SOAP-ENV:Body>\n"
989   - " <SOAP-ENV:Fault>\n"
990   - " <faultcode>SOAP-ENV:Client</faultcode>\n"
991   - " <faultstring>Client Error</faultstring>\n"
992   - " </SOAP-ENV:Fault>\n"
993   - " </SOAP-ENV:Body>\n"
994   - "</SOAP-ENV:Envelope>"
995   - }
996   -
997   -#define NO_HEADERS_NO_BODY_404 2
998   -, {.name= "404 no headers no body"
999   - ,.type= HTTP_RESPONSE
1000   - ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
1001   - ,.should_keep_alive= FALSE
1002   - ,.message_complete_on_eof= TRUE
1003   - ,.http_major= 1
1004   - ,.http_minor= 1
1005   - ,.status_code= 404
1006   - ,.num_headers= 0
1007   - ,.headers= {}
1008   - ,.body_size= 0
1009   - ,.body= ""
1010   - }
1011   -
1012   -#define NO_REASON_PHRASE 3
1013   -, {.name= "301 no response phrase"
1014   - ,.type= HTTP_RESPONSE
1015   - ,.raw= "HTTP/1.1 301\r\n\r\n"
1016   - ,.should_keep_alive = FALSE
1017   - ,.message_complete_on_eof= TRUE
1018   - ,.http_major= 1
1019   - ,.http_minor= 1
1020   - ,.status_code= 301
1021   - ,.num_headers= 0
1022   - ,.headers= {}
1023   - ,.body= ""
1024   - }
1025   -
1026   -#define TRAILING_SPACE_ON_CHUNKED_BODY 4
1027   -, {.name="200 trailing space on chunked body"
1028   - ,.type= HTTP_RESPONSE
1029   - ,.raw= "HTTP/1.1 200 OK\r\n"
1030   - "Content-Type: text/plain\r\n"
1031   - "Transfer-Encoding: chunked\r\n"
1032   - "\r\n"
1033   - "25 \r\n"
1034   - "This is the data in the first chunk\r\n"
1035   - "\r\n"
1036   - "1C\r\n"
1037   - "and this is the second one\r\n"
1038   - "\r\n"
1039   - "0 \r\n"
1040   - "\r\n"
1041   - ,.should_keep_alive= TRUE
1042   - ,.message_complete_on_eof= FALSE
1043   - ,.http_major= 1
1044   - ,.http_minor= 1
1045   - ,.status_code= 200
1046   - ,.num_headers= 2
1047   - ,.headers=
1048   - { {"Content-Type", "text/plain" }
1049   - , {"Transfer-Encoding", "chunked" }
1050   - }
1051   - ,.body_size = 37+28
1052   - ,.body =
1053   - "This is the data in the first chunk\r\n"
1054   - "and this is the second one\r\n"
1055   -
1056   - }
1057   -
1058   -#define NO_CARRIAGE_RET 5
1059   -, {.name="no carriage ret"
1060   - ,.type= HTTP_RESPONSE
1061   - ,.raw= "HTTP/1.1 200 OK\n"
1062   - "Content-Type: text/html; charset=utf-8\n"
1063   - "Connection: close\n"
1064   - "\n"
1065   - "these headers are from http://news.ycombinator.com/"
1066   - ,.should_keep_alive= FALSE
1067   - ,.message_complete_on_eof= TRUE
1068   - ,.http_major= 1
1069   - ,.http_minor= 1
1070   - ,.status_code= 200
1071   - ,.num_headers= 2
1072   - ,.headers=
1073   - { {"Content-Type", "text/html; charset=utf-8" }
1074   - , {"Connection", "close" }
1075   - }
1076   - ,.body= "these headers are from http://news.ycombinator.com/"
1077   - }
1078   -
1079   -#define PROXY_CONNECTION 6
1080   -, {.name="proxy connection"
1081   - ,.type= HTTP_RESPONSE
1082   - ,.raw= "HTTP/1.1 200 OK\r\n"
1083   - "Content-Type: text/html; charset=UTF-8\r\n"
1084   - "Content-Length: 11\r\n"
1085   - "Proxy-Connection: close\r\n"
1086   - "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
1087   - "\r\n"
1088   - "hello world"
1089   - ,.should_keep_alive= FALSE
1090   - ,.message_complete_on_eof= FALSE
1091   - ,.http_major= 1
1092   - ,.http_minor= 1
1093   - ,.status_code= 200
1094   - ,.num_headers= 4
1095   - ,.headers=
1096   - { {"Content-Type", "text/html; charset=UTF-8" }
1097   - , {"Content-Length", "11" }
1098   - , {"Proxy-Connection", "close" }
1099   - , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
1100   - }
1101   - ,.body= "hello world"
1102   - }
1103   -
1104   -#define UNDERSTORE_HEADER_KEY 7
1105   - // shown by
1106   - // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;"
1107   -, {.name="underscore header key"
1108   - ,.type= HTTP_RESPONSE
1109   - ,.raw= "HTTP/1.1 200 OK\r\n"
1110   - "Server: DCLK-AdSvr\r\n"
1111   - "Content-Type: text/xml\r\n"
1112   - "Content-Length: 0\r\n"
1113   - "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
1114   - ,.should_keep_alive= TRUE
1115   - ,.message_complete_on_eof= FALSE
1116   - ,.http_major= 1
1117   - ,.http_minor= 1
1118   - ,.status_code= 200
1119   - ,.num_headers= 4
1120   - ,.headers=
1121   - { {"Server", "DCLK-AdSvr" }
1122   - , {"Content-Type", "text/xml" }
1123   - , {"Content-Length", "0" }
1124   - , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" }
1125   - }
1126   - ,.body= ""
1127   - }
1128   -
1129   -#define BONJOUR_MADAME_FR 8
1130   -/* The client should not merge two headers fields when the first one doesn't
1131   - * have a value.
1132   - */
1133   -, {.name= "bonjourmadame.fr"
1134   - ,.type= HTTP_RESPONSE
1135   - ,.raw= "HTTP/1.0 301 Moved Permanently\r\n"
1136   - "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n"
1137   - "Server: Apache/2.2.3 (Red Hat)\r\n"
1138   - "Cache-Control: public\r\n"
1139   - "Pragma: \r\n"
1140   - "Location: http://www.bonjourmadame.fr/\r\n"
1141   - "Vary: Accept-Encoding\r\n"
1142   - "Content-Length: 0\r\n"
1143   - "Content-Type: text/html; charset=UTF-8\r\n"
1144   - "Connection: keep-alive\r\n"
1145   - "\r\n"
1146   - ,.should_keep_alive= TRUE
1147   - ,.message_complete_on_eof= FALSE
1148   - ,.http_major= 1
1149   - ,.http_minor= 0
1150   - ,.status_code= 301
1151   - ,.num_headers= 9
1152   - ,.headers=
1153   - { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
1154   - , { "Server", "Apache/2.2.3 (Red Hat)" }
1155   - , { "Cache-Control", "public" }
1156   - , { "Pragma", "" }
1157   - , { "Location", "http://www.bonjourmadame.fr/" }
1158   - , { "Vary", "Accept-Encoding" }
1159   - , { "Content-Length", "0" }
1160   - , { "Content-Type", "text/html; charset=UTF-8" }
1161   - , { "Connection", "keep-alive" }
1162   - }
1163   - ,.body= ""
1164   - }
1165   -
1166   -#define RES_FIELD_UNDERSCORE 9
1167   -/* Should handle spaces in header fields */
1168   -, {.name= "field underscore"
1169   - ,.type= HTTP_RESPONSE
1170   - ,.raw= "HTTP/1.1 200 OK\r\n"
1171   - "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
1172   - "Server: Apache\r\n"
1173   - "Cache-Control: no-cache, must-revalidate\r\n"
1174   - "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
1175   - ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
1176   - "Vary: Accept-Encoding\r\n"
1177   - "_eep-Alive: timeout=45\r\n" /* semantic value ignored */
1178   - "_onnection: Keep-Alive\r\n" /* semantic value ignored */
1179   - "Transfer-Encoding: chunked\r\n"
1180   - "Content-Type: text/html\r\n"
1181   - "Connection: close\r\n"
1182   - "\r\n"
1183   - "0\r\n\r\n"
1184   - ,.should_keep_alive= FALSE
1185   - ,.message_complete_on_eof= FALSE
1186   - ,.http_major= 1
1187   - ,.http_minor= 1
1188   - ,.status_code= 200
1189   - ,.num_headers= 11
1190   - ,.headers=
1191   - { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
1192   - , { "Server", "Apache" }
1193   - , { "Cache-Control", "no-cache, must-revalidate" }
1194   - , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
1195   - , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
1196   - , { "Vary", "Accept-Encoding" }
1197   - , { "_eep-Alive", "timeout=45" }
1198   - , { "_onnection", "Keep-Alive" }
1199   - , { "Transfer-Encoding", "chunked" }
1200   - , { "Content-Type", "text/html" }
1201   - , { "Connection", "close" }
1202   - }
1203   - ,.body= ""
1204   - }
1205   -
1206   -#define NON_ASCII_IN_STATUS_LINE 10
1207   -/* Should handle non-ASCII in status line */
1208   -, {.name= "non-ASCII in status line"
1209   - ,.type= HTTP_RESPONSE
1210   - ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
1211   - "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
1212   - "Content-Length: 0\r\n"
1213   - "Connection: close\r\n"
1214   - "\r\n"
1215   - ,.should_keep_alive= FALSE
1216   - ,.message_complete_on_eof= FALSE
1217   - ,.http_major= 1
1218   - ,.http_minor= 1
1219   - ,.status_code= 500
1220   - ,.num_headers= 3
1221   - ,.headers=
1222   - { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
1223   - , { "Content-Length", "0" }
1224   - , { "Connection", "close" }
1225   - }
1226   - ,.body= ""
1227   - }
1228   -
1229   -#define HTTP_VERSION_0_9 11
1230   -/* Should handle HTTP/0.9 */
1231   -, {.name= "http version 0.9"
1232   - ,.type= HTTP_RESPONSE
1233   - ,.raw= "HTTP/0.9 200 OK\r\n"
1234   - "\r\n"
1235   - ,.should_keep_alive= FALSE
1236   - ,.message_complete_on_eof= TRUE
1237   - ,.http_major= 0
1238   - ,.http_minor= 9
1239   - ,.status_code= 200
1240   - ,.num_headers= 0
1241   - ,.headers=
1242   - {}
1243   - ,.body= ""
1244   - }
1245   -
1246   -#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
1247   -/* The client should wait for the server's EOF. That is, when neither
1248   - * content-length nor transfer-encoding is specified, the end of body
1249   - * is specified by the EOF.
1250   - */
1251   -, {.name= "neither content-length nor transfer-encoding response"
1252   - ,.type= HTTP_RESPONSE
1253   - ,.raw= "HTTP/1.1 200 OK\r\n"
1254   - "Content-Type: text/plain\r\n"
1255   - "\r\n"
1256   - "hello world"
1257   - ,.should_keep_alive= FALSE
1258   - ,.message_complete_on_eof= TRUE
1259   - ,.http_major= 1
1260   - ,.http_minor= 1
1261   - ,.status_code= 200
1262   - ,.num_headers= 1
1263   - ,.headers=
1264   - { { "Content-Type", "text/plain" }
1265   - }
1266   - ,.body= "hello world"
1267   - }
1268   -
1269   -#define NO_BODY_HTTP10_KA_200 13
1270   -, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
1271   - ,.type= HTTP_RESPONSE
1272   - ,.raw= "HTTP/1.0 200 OK\r\n"
1273   - "Connection: keep-alive\r\n"
1274   - "\r\n"
1275   - ,.should_keep_alive= FALSE
1276   - ,.message_complete_on_eof= TRUE
1277   - ,.http_major= 1
1278   - ,.http_minor= 0
1279   - ,.status_code= 200
1280   - ,.num_headers= 1
1281   - ,.headers=
1282   - { { "Connection", "keep-alive" }
1283   - }
1284   - ,.body_size= 0
1285   - ,.body= ""
1286   - }
1287   -
1288   -#define NO_BODY_HTTP10_KA_204 14
1289   -, {.name= "HTTP/1.0 with keep-alive and a 204 status"
1290   - ,.type= HTTP_RESPONSE
1291   - ,.raw= "HTTP/1.0 204 No content\r\n"
1292   - "Connection: keep-alive\r\n"
1293   - "\r\n"
1294   - ,.should_keep_alive= TRUE
1295   - ,.message_complete_on_eof= FALSE
1296   - ,.http_major= 1
1297   - ,.http_minor= 0
1298   - ,.status_code= 204
1299   - ,.num_headers= 1
1300   - ,.headers=
1301   - { { "Connection", "keep-alive" }
1302   - }
1303   - ,.body_size= 0
1304   - ,.body= ""
1305   - }
1306   -
1307   -#define NO_BODY_HTTP11_KA_200 15
1308   -, {.name= "HTTP/1.1 with an EOF-terminated 200 status"
1309   - ,.type= HTTP_RESPONSE
1310   - ,.raw= "HTTP/1.1 200 OK\r\n"
1311   - "\r\n"
1312   - ,.should_keep_alive= FALSE
1313   - ,.message_complete_on_eof= TRUE
1314   - ,.http_major= 1
1315   - ,.http_minor= 1
1316   - ,.status_code= 200
1317   - ,.num_headers= 0
1318   - ,.headers={}
1319   - ,.body_size= 0
1320   - ,.body= ""
1321   - }
1322   -
1323   -#define NO_BODY_HTTP11_KA_204 16
1324   -, {.name= "HTTP/1.1 with a 204 status"
1325   - ,.type= HTTP_RESPONSE
1326   - ,.raw= "HTTP/1.1 204 No content\r\n"
1327   - "\r\n"
1328   - ,.should_keep_alive= TRUE
1329   - ,.message_complete_on_eof= FALSE
1330   - ,.http_major= 1
1331   - ,.http_minor= 1
1332   - ,.status_code= 204
1333   - ,.num_headers= 0
1334   - ,.headers={}
1335   - ,.body_size= 0
1336   - ,.body= ""
1337   - }
1338   -
1339   -#define NO_BODY_HTTP11_NOKA_204 17
1340   -, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
1341   - ,.type= HTTP_RESPONSE
1342   - ,.raw= "HTTP/1.1 204 No content\r\n"
1343   - "Connection: close\r\n"
1344   - "\r\n"
1345   - ,.should_keep_alive= FALSE
1346   - ,.message_complete_on_eof= FALSE
1347   - ,.http_major= 1
1348   - ,.http_minor= 1
1349   - ,.status_code= 204
1350   - ,.num_headers= 1
1351   - ,.headers=
1352   - { { "Connection", "close" }
1353   - }
1354   - ,.body_size= 0
1355   - ,.body= ""
1356   - }
1357   -
1358   -#define NO_BODY_HTTP11_KA_CHUNKED_200 18
1359   -, {.name= "HTTP/1.1 with chunked endocing and a 200 response"
1360   - ,.type= HTTP_RESPONSE
1361   - ,.raw= "HTTP/1.1 200 OK\r\n"
1362   - "Transfer-Encoding: chunked\r\n"
1363   - "\r\n"
1364   - "0\r\n"
1365   - "\r\n"
1366   - ,.should_keep_alive= TRUE
1367   - ,.message_complete_on_eof= FALSE
1368   - ,.http_major= 1
1369   - ,.http_minor= 1
1370   - ,.status_code= 200
1371   - ,.num_headers= 1
1372   - ,.headers=
1373   - { { "Transfer-Encoding", "chunked" }
1374   - }
1375   - ,.body_size= 0
1376   - ,.body= ""
1377   - }
1378   -
1379   -#if !HTTP_PARSER_STRICT
1380   -#define SPACE_IN_FIELD_RES 19
1381   -/* Should handle spaces in header fields */
1382   -, {.name= "field space"
1383   - ,.type= HTTP_RESPONSE
1384   - ,.raw= "HTTP/1.1 200 OK\r\n"
1385   - "Server: Microsoft-IIS/6.0\r\n"
1386   - "X-Powered-By: ASP.NET\r\n"
1387   - "en-US Content-Type: text/xml\r\n" /* this is the problem */
1388   - "Content-Type: text/xml\r\n"
1389   - "Content-Length: 16\r\n"
1390   - "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
1391   - "Connection: keep-alive\r\n"
1392   - "\r\n"
1393   - "<xml>hello</xml>" /* fake body */
1394   - ,.should_keep_alive= TRUE
1395   - ,.message_complete_on_eof= FALSE
1396   - ,.http_major= 1
1397   - ,.http_minor= 1
1398   - ,.status_code= 200
1399   - ,.num_headers= 7
1400   - ,.headers=
1401   - { { "Server", "Microsoft-IIS/6.0" }
1402   - , { "X-Powered-By", "ASP.NET" }
1403   - , { "en-US Content-Type", "text/xml" }
1404   - , { "Content-Type", "text/xml" }
1405   - , { "Content-Length", "16" }
1406   - , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
1407   - , { "Connection", "keep-alive" }
1408   - }
1409   - ,.body= "<xml>hello</xml>"
1410   - }
1411   -#endif /* !HTTP_PARSER_STRICT */
1412   -
1413   -, {.name= NULL } /* sentinel */
1414   -};
1415   -
1416   -/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
1417   - * define it ourselves.
1418   - */
1419   -size_t
1420   -strnlen(const char *s, size_t maxlen)
1421   -{
1422   - const char *p;
1423   -
1424   - p = memchr(s, '\0', maxlen);
1425   - if (p == NULL)
1426   - return maxlen;
1427   -
1428   - return p - s;
1429   -}
1430   -
1431   -size_t
1432   -strlncat(char *dst, size_t len, const char *src, size_t n)
1433   -{
1434   - size_t slen;
1435   - size_t dlen;
1436   - size_t rlen;
1437   - size_t ncpy;
1438   -
1439   - slen = strnlen(src, n);
1440   - dlen = strnlen(dst, len);
1441   -
1442   - if (dlen < len) {
1443   - rlen = len - dlen;
1444   - ncpy = slen < rlen ? slen : (rlen - 1);
1445   - memcpy(dst + dlen, src, ncpy);
1446   - dst[dlen + ncpy] = '\0';
1447   - }
1448   -
1449   - assert(len > slen + dlen);
1450   - return slen + dlen;
1451   -}
1452   -
1453   -size_t
1454   -strlcat(char *dst, const char *src, size_t len)
1455   -{
1456   - return strlncat(dst, len, src, (size_t) -1);
1457   -}
1458   -
1459   -size_t
1460   -strlncpy(char *dst, size_t len, const char *src, size_t n)
1461   -{
1462   - size_t slen;
1463   - size_t ncpy;
1464   -
1465   - slen = strnlen(src, n);
1466   -
1467   - if (len > 0) {
1468   - ncpy = slen < len ? slen : (len - 1);
1469   - memcpy(dst, src, ncpy);
1470   - dst[ncpy] = '\0';
1471   - }
1472   -
1473   - assert(len > slen);
1474   - return slen;
1475   -}
1476   -
1477   -size_t
1478   -strlcpy(char *dst, const char *src, size_t len)
1479   -{
1480   - return strlncpy(dst, len, src, (size_t) -1);
1481   -}
1482   -
1483   -int
1484   -request_url_cb (http_parser *p, const char *buf, size_t len)
1485   -{
1486   - assert(p == parser);
1487   - strlncat(messages[num_messages].request_url,
1488   - sizeof(messages[num_messages].request_url),
1489   - buf,
1490   - len);
1491   - return 0;
1492   -}
1493   -
1494   -int
1495   -status_complete_cb (http_parser *p) {
1496   - assert(p == parser);
1497   - p->data++;
1498   - return 0;
1499   -}
1500   -
1501   -int
1502   -header_field_cb (http_parser *p, const char *buf, size_t len)
1503   -{
1504   - assert(p == parser);
1505   - struct message *m = &messages[num_messages];
1506   -
1507   - if (m->last_header_element != FIELD)
1508   - m->num_headers++;
1509   -
1510   - strlncat(m->headers[m->num_headers-1][0],
1511   - sizeof(m->headers[m->num_headers-1][0]),
1512   - buf,
1513   - len);
1514   -
1515   - m->last_header_element = FIELD;
1516   -
1517   - return 0;
1518   -}
1519   -
1520   -int
1521   -header_value_cb (http_parser *p, const char *buf, size_t len)
1522   -{
1523   - assert(p == parser);
1524   - struct message *m = &messages[num_messages];
1525   -
1526   - strlncat(m->headers[m->num_headers-1][1],
1527   - sizeof(m->headers[m->num_headers-1][1]),
1528   - buf,
1529   - len);
1530   -
1531   - m->last_header_element = VALUE;
1532   -
1533   - return 0;
1534   -}
1535   -
1536   -void
1537   -check_body_is_final (const http_parser *p)
1538   -{
1539   - if (messages[num_messages].body_is_final) {
1540   - fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1541   - "on last on_body callback call "
1542   - "but it doesn't! ***\n\n");
1543   - assert(0);
1544   - abort();
1545   - }
1546   - messages[num_messages].body_is_final = http_body_is_final(p);
1547   -}
1548   -
1549   -int
1550   -body_cb (http_parser *p, const char *buf, size_t len)
1551   -{
1552   - assert(p == parser);
1553   - strlncat(messages[num_messages].body,
1554   - sizeof(messages[num_messages].body),
1555   - buf,
1556   - len);
1557   - messages[num_messages].body_size += len;
1558   - check_body_is_final(p);
1559   - // printf("body_cb: '%s'\n", requests[num_messages].body);
1560   - return 0;
1561   -}
1562   -
1563   -int
1564   -count_body_cb (http_parser *p, const char *buf, size_t len)
1565   -{
1566   - assert(p == parser);
1567   - assert(buf);
1568   - messages[num_messages].body_size += len;
1569   - check_body_is_final(p);
1570   - return 0;
1571   -}
1572   -
1573   -int
1574   -message_begin_cb (http_parser *p)
1575   -{
1576   - assert(p == parser);
1577   - messages[num_messages].message_begin_cb_called = TRUE;
1578   - return 0;
1579   -}
1580   -
1581   -int
1582   -headers_complete_cb (http_parser *p)
1583   -{
1584   - assert(p == parser);
1585   - messages[num_messages].method = parser->method;
1586   - messages[num_messages].status_code = parser->status_code;
1587   - messages[num_messages].http_major = parser->http_major;
1588   - messages[num_messages].http_minor = parser->http_minor;
1589   - messages[num_messages].headers_complete_cb_called = TRUE;
1590   - messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
1591   - return 0;
1592   -}
1593   -
1594   -int
1595   -message_complete_cb (http_parser *p)
1596   -{
1597   - assert(p == parser);
1598   - if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
1599   - {
1600   - fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
1601   - "value in both on_message_complete and on_headers_complete "
1602   - "but it doesn't! ***\n\n");
1603   - assert(0);
1604   - abort();
1605   - }
1606   -
1607   - if (messages[num_messages].body_size &&
1608   - http_body_is_final(p) &&
1609   - !messages[num_messages].body_is_final)
1610   - {
1611   - fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1612   - "on last on_body callback call "
1613   - "but it doesn't! ***\n\n");
1614   - assert(0);
1615   - abort();
1616   - }
1617   -
1618   - messages[num_messages].message_complete_cb_called = TRUE;
1619   -
1620   - messages[num_messages].message_complete_on_eof = currently_parsing_eof;
1621   -
1622   - num_messages++;
1623   - return 0;
1624   -}
1625   -
1626   -/* These dontcall_* callbacks exist so that we can verify that when we're
1627   - * paused, no additional callbacks are invoked */
1628   -int
1629   -dontcall_message_begin_cb (http_parser *p)
1630   -{
1631   - if (p) { } // gcc
1632   - fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
1633   - abort();
1634   -}
1635   -
1636   -int
1637   -dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
1638   -{
1639   - if (p || buf || len) { } // gcc
1640   - fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
1641   - abort();
1642   -}
1643   -
1644   -int
1645   -dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
1646   -{
1647   - if (p || buf || len) { } // gcc
1648   - fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
1649   - abort();
1650   -}
1651   -
1652   -int
1653   -dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
1654   -{
1655   - if (p || buf || len) { } // gcc
1656   - fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
1657   - abort();
1658   -}
1659   -
1660   -int
1661   -dontcall_body_cb (http_parser *p, const char *buf, size_t len)
1662   -{
1663   - if (p || buf || len) { } // gcc
1664   - fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
1665   - abort();
1666   -}
1667   -
1668   -int
1669   -dontcall_headers_complete_cb (http_parser *p)
1670   -{
1671   - if (p) { } // gcc
1672   - fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
1673   - "parser ***\n\n");
1674   - abort();
1675   -}
1676   -
1677   -int
1678   -dontcall_message_complete_cb (http_parser *p)
1679   -{
1680   - if (p) { } // gcc
1681   - fprintf(stderr, "\n\n*** on_message_complete() called on paused "
1682   - "parser ***\n\n");
1683   - abort();
1684   -}
1685   -
1686   -static http_parser_settings settings_dontcall =
1687   - {.on_message_begin = dontcall_message_begin_cb
1688   - ,.on_header_field = dontcall_header_field_cb
1689   - ,.on_header_value = dontcall_header_value_cb
1690   - ,.on_url = dontcall_request_url_cb
1691   - ,.on_body = dontcall_body_cb
1692   - ,.on_headers_complete = dontcall_headers_complete_cb
1693   - ,.on_message_complete = dontcall_message_complete_cb
1694   - };
1695   -
1696   -/* These pause_* callbacks always pause the parser and just invoke the regular
1697   - * callback that tracks content. Before returning, we overwrite the parser
1698   - * settings to point to the _dontcall variety so that we can verify that
1699   - * the pause actually did, you know, pause. */
1700   -int
1701   -pause_message_begin_cb (http_parser *p)
1702   -{
1703   - http_parser_pause(p, 1);
1704   - *current_pause_parser = settings_dontcall;
1705   - return message_begin_cb(p);
1706   -}
1707   -
1708   -int
1709   -pause_header_field_cb (http_parser *p, const char *buf, size_t len)
1710   -{
1711   - http_parser_pause(p, 1);
1712   - *current_pause_parser = settings_dontcall;
1713   - return header_field_cb(p, buf, len);
1714   -}
1715   -
1716   -int
1717   -pause_header_value_cb (http_parser *p, const char *buf, size_t len)
1718   -{
1719   - http_parser_pause(p, 1);
1720   - *current_pause_parser = settings_dontcall;
1721   - return header_value_cb(p, buf, len);
1722   -}
1723   -
1724   -int
1725   -pause_request_url_cb (http_parser *p, const char *buf, size_t len)
1726   -{
1727   - http_parser_pause(p, 1);
1728   - *current_pause_parser = settings_dontcall;
1729   - return request_url_cb(p, buf, len);
1730   -}
1731   -
1732   -int
1733   -pause_body_cb (http_parser *p, const char *buf, size_t len)
1734   -{
1735   - http_parser_pause(p, 1);
1736   - *current_pause_parser = settings_dontcall;
1737   - return body_cb(p, buf, len);
1738   -}
1739   -
1740   -int
1741   -pause_headers_complete_cb (http_parser *p)
1742   -{
1743   - http_parser_pause(p, 1);
1744   - *current_pause_parser = settings_dontcall;
1745   - return headers_complete_cb(p);
1746   -}
1747   -
1748   -int
1749   -pause_message_complete_cb (http_parser *p)
1750   -{
1751   - http_parser_pause(p, 1);
1752   - *current_pause_parser = settings_dontcall;
1753   - return message_complete_cb(p);
1754   -}
1755   -
1756   -static http_parser_settings settings_pause =
1757   - {.on_message_begin = pause_message_begin_cb
1758   - ,.on_header_field = pause_header_field_cb
1759   - ,.on_header_value = pause_header_value_cb
1760   - ,.on_url = pause_request_url_cb
1761   - ,.on_body = pause_body_cb
1762   - ,.on_headers_complete = pause_headers_complete_cb
1763   - ,.on_message_complete = pause_message_complete_cb
1764   - };
1765   -
1766   -static http_parser_settings settings =
1767   - {.on_message_begin = message_begin_cb
1768   - ,.on_header_field = header_field_cb
1769   - ,.on_header_value = header_value_cb
1770   - ,.on_url = request_url_cb
1771   - ,.on_body = body_cb
1772   - ,.on_headers_complete = headers_complete_cb
1773   - ,.on_message_complete = message_complete_cb
1774   - };
1775   -
1776   -static http_parser_settings settings_count_body =
1777   - {.on_message_begin = message_begin_cb
1778   - ,.on_header_field = header_field_cb
1779   - ,.on_header_value = header_value_cb
1780   - ,.on_url = request_url_cb
1781   - ,.on_body = count_body_cb
1782   - ,.on_headers_complete = headers_complete_cb
1783   - ,.on_message_complete = message_complete_cb
1784   - };
1785   -
1786   -static http_parser_settings settings_null =
1787   - {.on_message_begin = 0
1788   - ,.on_header_field = 0
1789   - ,.on_header_value = 0
1790   - ,.on_url = 0
1791   - ,.on_body = 0
1792   - ,.on_headers_complete = 0
1793   - ,.on_message_complete = 0
1794   - };
1795   -
1796   -void
1797   -parser_init (enum http_parser_type type)
1798   -{
1799   - num_messages = 0;
1800   -
1801   - assert(parser == NULL);
1802   -
1803   - parser = malloc(sizeof(http_parser));
1804   -
1805   - http_parser_init(parser, type);
1806   -
1807   - memset(&messages, 0, sizeof messages);
1808   -
1809   -}
1810   -
1811   -void
1812   -parser_free ()
1813   -{
1814   - assert(parser);
1815   - free(parser);
1816   - parser = NULL;
1817   -}
1818   -
1819   -size_t parse (const char *buf, size_t len)
1820   -{
1821   - size_t nparsed;
1822   - currently_parsing_eof = (len == 0);
1823   - nparsed = http_parser_execute(parser, &settings, buf, len);
1824   - return nparsed;
1825   -}
1826   -
1827   -size_t parse_count_body (const char *buf, size_t len)
1828   -{
1829   - size_t nparsed;
1830   - currently_parsing_eof = (len == 0);
1831   - nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
1832   - return nparsed;
1833   -}
1834   -
1835   -size_t parse_pause (const char *buf, size_t len)
1836   -{
1837   - size_t nparsed;
1838   - http_parser_settings s = settings_pause;
1839   -
1840   - currently_parsing_eof = (len == 0);
1841   - current_pause_parser = &s;
1842   - nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
1843   - return nparsed;
1844   -}
1845   -
1846   -static inline int
1847   -check_str_eq (const struct message *m,
1848   - const char *prop,
1849   - const char *expected,
1850   - const char *found) {
1851   - if ((expected == NULL) != (found == NULL)) {
1852   - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1853   - printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
1854   - printf(" found %s\n", (found == NULL) ? "NULL" : found);
1855   - return 0;
1856   - }
1857   - if (expected != NULL && 0 != strcmp(expected, found)) {
1858   - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1859   - printf("expected '%s'\n", expected);
1860   - printf(" found '%s'\n", found);
1861   - return 0;
1862   - }
1863   - return 1;
1864   -}
1865   -
1866   -static inline int
1867   -check_num_eq (const struct message *m,
1868   - const char *prop,
1869   - int expected,
1870   - int found) {
1871   - if (expected != found) {
1872   - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1873   - printf("expected %d\n", expected);
1874   - printf(" found %d\n", found);
1875   - return 0;
1876   - }
1877   - return 1;
1878   -}
1879   -
1880   -#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \
1881   - if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0
1882   -
1883   -#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
1884   - if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
1885   -
1886   -#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
1887   -do { \
1888   - char ubuf[256]; \
1889   - \
1890   - if ((u)->field_set & (1 << (fn))) { \
1891   - memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
1892   - (u)->field_data[(fn)].len); \
1893   - ubuf[(u)->field_data[(fn)].len] = '\0'; \
1894   - } else { \
1895   - ubuf[0] = '\0'; \
1896   - } \
1897   - \
1898   - check_str_eq(expected, #prop, expected->prop, ubuf); \
1899   -} while(0)
1900   -
1901   -int
1902   -message_eq (int index, const struct message *expected)
1903   -{
1904   - int i;
1905   - struct message *m = &messages[index];
1906   -
1907   - MESSAGE_CHECK_NUM_EQ(expected, m, http_major);
1908   - MESSAGE_CHECK_NUM_EQ(expected, m, http_minor);
1909   -
1910   - if (expected->type == HTTP_REQUEST) {
1911   - MESSAGE_CHECK_NUM_EQ(expected, m, method);
1912   - } else {
1913   - MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
1914   - }
1915   -
1916   - MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
1917   - MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
1918   -
1919   - assert(m->message_begin_cb_called);
1920   - assert(m->headers_complete_cb_called);
1921   - assert(m->message_complete_cb_called);
1922   -
1923   -
1924   - MESSAGE_CHECK_STR_EQ(expected, m, request_url);
1925   -
1926   - /* Check URL components; we can't do this w/ CONNECT since it doesn't
1927   - * send us a well-formed URL.
1928   - */
1929   - if (*m->request_url && m->method != HTTP_CONNECT) {
1930   - struct http_parser_url u;
1931   -
1932   - if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
1933   - fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
1934   - m->request_url);
1935   - abort();
1936   - }
1937   -
1938   - if (expected->host) {
1939   - MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
1940   - }
1941   -
1942   - if (expected->userinfo) {
1943   - MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
1944   - }
1945   -
1946   - m->port = (u.field_set & (1 << UF_PORT)) ?
1947   - u.port : 0;
1948   -
1949   - MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
1950   - MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
1951   - MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
1952   - MESSAGE_CHECK_NUM_EQ(expected, m, port);
1953   - }
1954   -
1955   - if (expected->body_size) {
1956   - MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
1957   - } else {
1958   - MESSAGE_CHECK_STR_EQ(expected, m, body);
1959   - }
1960   -
1961   - MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
1962   -
1963   - int r;
1964   - for (i = 0; i < m->num_headers; i++) {
1965   - r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]);
1966   - if (!r) return 0;
1967   - r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
1968   - if (!r) return 0;
1969   - }
1970   -
1971   - MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
1972   -
1973   - return 1;
1974   -}
1975   -
1976   -/* Given a sequence of varargs messages, return the number of them that the
1977   - * parser should successfully parse, taking into account that upgraded
1978   - * messages prevent all subsequent messages from being parsed.
1979   - */
1980   -size_t
1981   -count_parsed_messages(const size_t nmsgs, ...) {
1982   - size_t i;
1983   - va_list ap;
1984   -
1985   - va_start(ap, nmsgs);
1986   -
1987   - for (i = 0; i < nmsgs; i++) {
1988   - struct message *m = va_arg(ap, struct message *);
1989   -
1990   - if (m->upgrade) {
1991   - va_end(ap);
1992   - return i + 1;
1993   - }
1994   - }
1995   -
1996   - va_end(ap);
1997   - return nmsgs;
1998   -}
1999   -
2000   -/* Given a sequence of bytes and the number of these that we were able to
2001   - * parse, verify that upgrade bodies are correct.
2002   - */
2003   -void
2004   -upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
2005   - va_list ap;
2006   - size_t i;
2007   - size_t off = 0;
2008   -
2009   - va_start(ap, nmsgs);
2010   -
2011   - for (i = 0; i < nmsgs; i++) {
2012   - struct message *m = va_arg(ap, struct message *);
2013   -
2014   - off += strlen(m->raw);
2015   -
2016   - if (m->upgrade) {
2017   - off -= strlen(m->upgrade);
2018   -
2019   - /* Check the portion of the response after its specified upgrade */
2020   - if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
2021   - abort();
2022   - }
2023   -
2024   - /* Fix up the response so that message_eq() will verify the beginning
2025   - * of the upgrade */
2026   - *(body + nread + strlen(m->upgrade)) = '\0';
2027   - messages[num_messages -1 ].upgrade = body + nread;
2028   -
2029   - va_end(ap);
2030   - return;
2031   - }
2032   - }
2033   -
2034   - va_end(ap);
2035   - printf("\n\n*** Error: expected a message with upgrade ***\n");
2036   -
2037   - abort();
2038   -}
2039   -
2040   -static void
2041   -print_error (const char *raw, size_t error_location)
2042   -{
2043   - fprintf(stderr, "\n*** %s ***\n\n",
2044   - http_errno_description(HTTP_PARSER_ERRNO(parser)));
2045   -
2046   - int this_line = 0, char_len = 0;
2047   - size_t i, j, len = strlen(raw), error_location_line = 0;
2048   - for (i = 0; i < len; i++) {
2049   - if (i == error_location) this_line = 1;
2050   - switch (raw[i]) {
2051   - case '\r':
2052   - char_len = 2;
2053   - fprintf(stderr, "\\r");
2054   - break;
2055   -
2056   - case '\n':
2057   - char_len = 2;
2058   - fprintf(stderr, "\\n\n");
2059   -
2060   - if (this_line) goto print;
2061   -
2062   - error_location_line = 0;
2063   - continue;
2064   -
2065   - default:
2066   - char_len = 1;
2067   - fputc(raw[i], stderr);
2068   - break;
2069   - }
2070   - if (!this_line) error_location_line += char_len;
2071   - }
2072   -
2073   - fprintf(stderr, "[eof]\n");
2074   -
2075   - print:
2076   - for (j = 0; j < error_location_line; j++) {
2077   - fputc(' ', stderr);
2078   - }
2079   - fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
2080   -}
2081   -
2082   -void
2083   -test_preserve_data (void)
2084   -{
2085   - char my_data[] = "application-specific data";
2086   - http_parser parser;
2087   - parser.data = my_data;
2088   - http_parser_init(&parser, HTTP_REQUEST);
2089   - if (parser.data != my_data) {
2090   - printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
2091   - abort();
2092   - }
2093   -}
2094   -
2095   -struct url_test {
2096   - const char *name;
2097   - const char *url;
2098   - int is_connect;
2099   - struct http_parser_url u;
2100   - int rv;
2101   -};
2102   -
2103   -const struct url_test url_tests[] =
2104   -{ {.name="proxy request"
2105   - ,.url="http://hostname/"
2106   - ,.is_connect=0
2107   - ,.u=
2108   - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2109   - ,.port=0
2110   - ,.field_data=
2111   - {{ 0, 4 } /* UF_SCHEMA */
2112   - ,{ 7, 8 } /* UF_HOST */
2113   - ,{ 0, 0 } /* UF_PORT */
2114   - ,{ 15, 1 } /* UF_PATH */
2115   - ,{ 0, 0 } /* UF_QUERY */
2116   - ,{ 0, 0 } /* UF_FRAGMENT */
2117   - ,{ 0, 0 } /* UF_USERINFO */
2118   - }
2119   - }
2120   - ,.rv=0
2121   - }
2122   -
2123   -, {.name="proxy request with port"
2124   - ,.url="http://hostname:444/"
2125   - ,.is_connect=0
2126   - ,.u=
2127   - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2128   - ,.port=444
2129   - ,.field_data=
2130   - {{ 0, 4 } /* UF_SCHEMA */
2131   - ,{ 7, 8 } /* UF_HOST */
2132   - ,{ 16, 3 } /* UF_PORT */
2133   - ,{ 19, 1 } /* UF_PATH */
2134   - ,{ 0, 0 } /* UF_QUERY */
2135   - ,{ 0, 0 } /* UF_FRAGMENT */
2136   - ,{ 0, 0 } /* UF_USERINFO */
2137   - }
2138   - }
2139   - ,.rv=0
2140   - }
2141   -
2142   -, {.name="CONNECT request"
2143   - ,.url="hostname:443"
2144   - ,.is_connect=1
2145   - ,.u=
2146   - {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2147   - ,.port=443
2148   - ,.field_data=
2149   - {{ 0, 0 } /* UF_SCHEMA */
2150   - ,{ 0, 8 } /* UF_HOST */
2151   - ,{ 9, 3 } /* UF_PORT */
2152   - ,{ 0, 0 } /* UF_PATH */
2153   - ,{ 0, 0 } /* UF_QUERY */
2154   - ,{ 0, 0 } /* UF_FRAGMENT */
2155   - ,{ 0, 0 } /* UF_USERINFO */
2156   - }
2157   - }
2158   - ,.rv=0
2159   - }
2160   -
2161   -, {.name="CONNECT request but not connect"
2162   - ,.url="hostname:443"
2163   - ,.is_connect=0
2164   - ,.rv=1
2165   - }
2166   -
2167   -, {.name="proxy ipv6 request"
2168   - ,.url="http://[1:2::3:4]/"
2169   - ,.is_connect=0
2170   - ,.u=
2171   - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2172   - ,.port=0
2173   - ,.field_data=
2174   - {{ 0, 4 } /* UF_SCHEMA */
2175   - ,{ 8, 8 } /* UF_HOST */
2176   - ,{ 0, 0 } /* UF_PORT */
2177   - ,{ 17, 1 } /* UF_PATH */
2178   - ,{ 0, 0 } /* UF_QUERY */
2179   - ,{ 0, 0 } /* UF_FRAGMENT */
2180   - ,{ 0, 0 } /* UF_USERINFO */
2181   - }
2182   - }
2183   - ,.rv=0
2184   - }
2185   -
2186   -, {.name="proxy ipv6 request with port"
2187   - ,.url="http://[1:2::3:4]:67/"
2188   - ,.is_connect=0
2189   - ,.u=
2190   - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2191   - ,.port=67
2192   - ,.field_data=
2193   - {{ 0, 4 } /* UF_SCHEMA */
2194   - ,{ 8, 8 } /* UF_HOST */
2195   - ,{ 18, 2 } /* UF_PORT */
2196   - ,{ 20, 1 } /* UF_PATH */
2197   - ,{ 0, 0 } /* UF_QUERY */
2198   - ,{ 0, 0 } /* UF_FRAGMENT */
2199   - ,{ 0, 0 } /* UF_USERINFO */
2200   - }
2201   - }
2202   - ,.rv=0
2203   - }
2204   -
2205   -, {.name="CONNECT ipv6 address"
2206   - ,.url="[1:2::3:4]:443"
2207   - ,.is_connect=1
2208   - ,.u=
2209   - {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2210   - ,.port=443
2211   - ,.field_data=
2212   - {{ 0, 0 } /* UF_SCHEMA */
2213   - ,{ 1, 8 } /* UF_HOST */
2214   - ,{ 11, 3 } /* UF_PORT */
2215   - ,{ 0, 0 } /* UF_PATH */
2216   - ,{ 0, 0 } /* UF_QUERY */
2217   - ,{ 0, 0 } /* UF_FRAGMENT */
2218   - ,{ 0, 0 } /* UF_USERINFO */
2219   - }
2220   - }
2221   - ,.rv=0
2222   - }
2223   -
2224   -, {.name="ipv4 in ipv6 address"
2225   - ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
2226   - ,.is_connect=0
2227   - ,.u=
2228   - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2229   - ,.port=0
2230   - ,.field_data=
2231   - {{ 0, 4 } /* UF_SCHEMA */
2232   - ,{ 8, 37 } /* UF_HOST */
2233   - ,{ 0, 0 } /* UF_PORT */
2234   - ,{ 46, 1 } /* UF_PATH */
2235   - ,{ 0, 0 } /* UF_QUERY */
2236   - ,{ 0, 0 } /* UF_FRAGMENT */
2237   - ,{ 0, 0 } /* UF_USERINFO */
2238   - }
2239   - }
2240   - ,.rv=0
2241   - }
2242   -
2243   -, {.name="extra ? in query string"
2244   - ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
2245   - "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
2246   - "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
2247   - ,.is_connect=0
2248   - ,.u=
2249   - {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
2250   - ,.port=0
2251   - ,.field_data=
2252   - {{ 0, 4 } /* UF_SCHEMA */
2253   - ,{ 7, 10 } /* UF_HOST */
2254   - ,{ 0, 0 } /* UF_PORT */
2255   - ,{ 17, 12 } /* UF_PATH */
2256   - ,{ 30,187 } /* UF_QUERY */
2257   - ,{ 0, 0 } /* UF_FRAGMENT */
2258   - ,{ 0, 0 } /* UF_USERINFO */
2259   - }
2260   - }
2261   - ,.rv=0
2262   - }
2263   -
2264   -, {.name="space URL encoded"
2265   - ,.url="/toto.html?toto=a%20b"
2266   - ,.is_connect=0
2267   - ,.u=
2268   - {.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
2269   - ,.port=0
2270   - ,.field_data=
2271   - {{ 0, 0 } /* UF_SCHEMA */
2272   - ,{ 0, 0 } /* UF_HOST */
2273   - ,{ 0, 0 } /* UF_PORT */
2274   - ,{ 0, 10 } /* UF_PATH */
2275   - ,{ 11, 10 } /* UF_QUERY */
2276   - ,{ 0, 0 } /* UF_FRAGMENT */
2277   - ,{ 0, 0 } /* UF_USERINFO */
2278   - }
2279   - }
2280   - ,.rv=0
2281   - }
2282   -
2283   -
2284   -, {.name="URL fragment"
2285   - ,.url="/toto.html#titi"
2286   - ,.is_connect=0
2287   - ,.u=
2288   - {.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
2289   - ,.port=0
2290   - ,.field_data=
2291   - {{ 0, 0 } /* UF_SCHEMA */
2292   - ,{ 0, 0 } /* UF_HOST */
2293   - ,{ 0, 0 } /* UF_PORT */
2294   - ,{ 0, 10 } /* UF_PATH */
2295   - ,{ 0, 0 } /* UF_QUERY */
2296   - ,{ 11, 4 } /* UF_FRAGMENT */
2297   - ,{ 0, 0 } /* UF_USERINFO */
2298   - }
2299   - }
2300   - ,.rv=0
2301   - }
2302   -
2303   -, {.name="complex URL fragment"
2304   - ,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
2305   - "http://www.example.com/index.html?foo=bar&hello=world#midpage"
2306   - ,.is_connect=0
2307   - ,.u=
2308   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
2309   - (1<<UF_FRAGMENT)
2310   - ,.port=0
2311   - ,.field_data=
2312   - {{ 0, 4 } /* UF_SCHEMA */
2313   - ,{ 7, 22 } /* UF_HOST */
2314   - ,{ 0, 0 } /* UF_PORT */
2315   - ,{ 29, 6 } /* UF_PATH */
2316   - ,{ 36, 69 } /* UF_QUERY */
2317   - ,{106, 7 } /* UF_FRAGMENT */
2318   - ,{ 0, 0 } /* UF_USERINFO */
2319   - }
2320   - }
2321   - ,.rv=0
2322   - }
2323   -
2324   -, {.name="complex URL from node js url parser doc"
2325   - ,.url="http://host.com:8080/p/a/t/h?query=string#hash"
2326   - ,.is_connect=0
2327   - ,.u=
2328   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2329   - (1<<UF_QUERY) | (1<<UF_FRAGMENT)
2330   - ,.port=8080
2331   - ,.field_data=
2332   - {{ 0, 4 } /* UF_SCHEMA */
2333   - ,{ 7, 8 } /* UF_HOST */
2334   - ,{ 16, 4 } /* UF_PORT */
2335   - ,{ 20, 8 } /* UF_PATH */
2336   - ,{ 29, 12 } /* UF_QUERY */
2337   - ,{ 42, 4 } /* UF_FRAGMENT */
2338   - ,{ 0, 0 } /* UF_USERINFO */
2339   - }
2340   - }
2341   - ,.rv=0
2342   - }
2343   -
2344   -, {.name="complex URL with basic auth from node js url parser doc"
2345   - ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
2346   - ,.is_connect=0
2347   - ,.u=
2348   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2349   - (1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
2350   - ,.port=8080
2351   - ,.field_data=
2352   - {{ 0, 4 } /* UF_SCHEMA */
2353   - ,{ 11, 8 } /* UF_HOST */
2354   - ,{ 20, 4 } /* UF_PORT */
2355   - ,{ 24, 8 } /* UF_PATH */
2356   - ,{ 33, 12 } /* UF_QUERY */
2357   - ,{ 46, 4 } /* UF_FRAGMENT */
2358   - ,{ 7, 3 } /* UF_USERINFO */
2359   - }
2360   - }
2361   - ,.rv=0
2362   - }
2363   -
2364   -, {.name="double @"
2365   - ,.url="http://a:b@@hostname:443/"
2366   - ,.is_connect=0
2367   - ,.rv=1
2368   - }
2369   -
2370   -, {.name="proxy empty host"
2371   - ,.url="http://:443/"
2372   - ,.is_connect=0
2373   - ,.rv=1
2374   - }
2375   -
2376   -, {.name="proxy empty port"
2377   - ,.url="http://hostname:/"
2378   - ,.is_connect=0
2379   - ,.rv=1
2380   - }
2381   -
2382   -, {.name="CONNECT with basic auth"
2383   - ,.url="a:b@hostname:443"
2384   - ,.is_connect=1
2385   - ,.rv=1
2386   - }
2387   -
2388   -, {.name="CONNECT empty host"
2389   - ,.url=":443"
2390   - ,.is_connect=1
2391   - ,.rv=1
2392   - }
2393   -
2394   -, {.name="CONNECT empty port"
2395   - ,.url="hostname:"
2396   - ,.is_connect=1
2397   - ,.rv=1
2398   - }
2399   -
2400   -, {.name="CONNECT with extra bits"
2401   - ,.url="hostname:443/"
2402   - ,.is_connect=1
2403   - ,.rv=1
2404   - }
2405   -
2406   -, {.name="space in URL"
2407   - ,.url="/foo bar/"
2408   - ,.rv=1 /* s_dead */
2409   - }
2410   -
2411   -, {.name="proxy basic auth with space url encoded"
2412   - ,.url="http://a%20:b@host.com/"
2413   - ,.is_connect=0
2414   - ,.u=
2415   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2416   - ,.port=0
2417   - ,.field_data=
2418   - {{ 0, 4 } /* UF_SCHEMA */
2419   - ,{ 14, 8 } /* UF_HOST */
2420   - ,{ 0, 0 } /* UF_PORT */
2421   - ,{ 22, 1 } /* UF_PATH */
2422   - ,{ 0, 0 } /* UF_QUERY */
2423   - ,{ 0, 0 } /* UF_FRAGMENT */
2424   - ,{ 7, 6 } /* UF_USERINFO */
2425   - }
2426   - }
2427   - ,.rv=0
2428   - }
2429   -
2430   -, {.name="carriage return in URL"
2431   - ,.url="/foo\rbar/"
2432   - ,.rv=1 /* s_dead */
2433   - }
2434   -
2435   -, {.name="proxy double : in URL"
2436   - ,.url="http://hostname::443/"
2437   - ,.rv=1 /* s_dead */
2438   - }
2439   -
2440   -, {.name="proxy basic auth with double :"
2441   - ,.url="http://a::b@host.com/"
2442   - ,.is_connect=0
2443   - ,.u=
2444   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2445   - ,.port=0
2446   - ,.field_data=
2447   - {{ 0, 4 } /* UF_SCHEMA */
2448   - ,{ 12, 8 } /* UF_HOST */
2449   - ,{ 0, 0 } /* UF_PORT */
2450   - ,{ 20, 1 } /* UF_PATH */
2451   - ,{ 0, 0 } /* UF_QUERY */
2452   - ,{ 0, 0 } /* UF_FRAGMENT */
2453   - ,{ 7, 4 } /* UF_USERINFO */
2454   - }
2455   - }
2456   - ,.rv=0
2457   - }
2458   -
2459   -, {.name="line feed in URL"
2460   - ,.url="/foo\nbar/"
2461   - ,.rv=1 /* s_dead */
2462   - }
2463   -
2464   -, {.name="proxy empty basic auth"
2465   - ,.url="http://@hostname/fo"
2466   - ,.u=
2467   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
2468   - ,.port=0
2469   - ,.field_data=
2470   - {{ 0, 4 } /* UF_SCHEMA */
2471   - ,{ 8, 8 } /* UF_HOST */
2472   - ,{ 0, 0 } /* UF_PORT */
2473   - ,{ 16, 3 } /* UF_PATH */
2474   - ,{ 0, 0 } /* UF_QUERY */
2475   - ,{ 0, 0 } /* UF_FRAGMENT */
2476   - ,{ 0, 0 } /* UF_USERINFO */
2477   - }
2478   - }
2479   - ,.rv=0
2480   - }
2481   -, {.name="proxy line feed in hostname"
2482   - ,.url="http://host\name/fo"
2483   - ,.rv=1 /* s_dead */
2484   - }
2485   -
2486   -, {.name="proxy % in hostname"
2487   - ,.url="http://host%name/fo"
2488   - ,.rv=1 /* s_dead */
2489   - }
2490   -
2491   -, {.name="proxy ; in hostname"
2492   - ,.url="http://host;ame/fo"
2493   - ,.rv=1 /* s_dead */
2494   - }
2495   -
2496   -, {.name="proxy basic auth with unreservedchars"
2497   - ,.url="http://a!;-_!=+$@host.com/"
2498   - ,.is_connect=0
2499   - ,.u=
2500   - {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2501   - ,.port=0
2502   - ,.field_data=
2503   - {{ 0, 4 } /* UF_SCHEMA */
2504   - ,{ 17, 8 } /* UF_HOST */
2505   - ,{ 0, 0 } /* UF_PORT */
2506   - ,{ 25, 1 } /* UF_PATH */
2507   - ,{ 0, 0 } /* UF_QUERY */
2508   - ,{ 0, 0 } /* UF_FRAGMENT */
2509   - ,{ 7, 9 } /* UF_USERINFO */
2510   - }
2511   - }
2512   - ,.rv=0
2513   - }
2514   -
2515   -, {.name="proxy only empty basic auth"
2516   - ,.url="http://@/fo"
2517   - ,.rv=1 /* s_dead */
2518   - }
2519   -
2520   -, {.name="proxy only basic auth"
2521   - ,.url="http://toto@/fo"
2522   - ,.rv=1 /* s_dead */
2523   - }
2524   -
2525   -, {.name="proxy emtpy hostname"
2526   - ,.url="http:///fo"
2527   - ,.rv=1 /* s_dead */
2528   - }
2529   -
2530   -, {.name="proxy = in URL"
2531   - ,.url="http://host=ame/fo"
2532   - ,.rv=1 /* s_dead */
2533   - }
2534   -
2535   -#if HTTP_PARSER_STRICT
2536   -
2537   -, {.name="tab in URL"
2538   - ,.url="/foo\tbar/"
2539   - ,.rv=1 /* s_dead */
2540   - }
2541   -
2542   -, {.name="form feed in URL"
2543   - ,.url="/foo\fbar/"
2544   - ,.rv=1 /* s_dead */
2545   - }
2546   -
2547   -#else /* !HTTP_PARSER_STRICT */
2548   -
2549   -, {.name="tab in URL"
2550   - ,.url="/foo\tbar/"
2551   - ,.u=
2552   - {.field_set=(1 << UF_PATH)
2553   - ,.field_data=
2554   - {{ 0, 0 } /* UF_SCHEMA */
2555   - ,{ 0, 0 } /* UF_HOST */
2556   - ,{ 0, 0 } /* UF_PORT */
2557   - ,{ 0, 9 } /* UF_PATH */
2558   - ,{ 0, 0 } /* UF_QUERY */
2559   - ,{ 0, 0 } /* UF_FRAGMENT */
2560   - ,{ 0, 0 } /* UF_USERINFO */
2561   - }
2562   - }
2563   - ,.rv=0
2564   - }
2565   -
2566   -, {.name="form feed in URL"
2567   - ,.url="/foo\fbar/"
2568   - ,.u=
2569   - {.field_set=(1 << UF_PATH)
2570   - ,.field_data=
2571   - {{ 0, 0 } /* UF_SCHEMA */
2572   - ,{ 0, 0 } /* UF_HOST */
2573   - ,{ 0, 0 } /* UF_PORT */
2574   - ,{ 0, 9 } /* UF_PATH */
2575   - ,{ 0, 0 } /* UF_QUERY */
2576   - ,{ 0, 0 } /* UF_FRAGMENT */
2577   - ,{ 0, 0 } /* UF_USERINFO */
2578   - }
2579   - }
2580   - ,.rv=0
2581   - }
2582   -#endif
2583   -};
2584   -
2585   -void
2586   -dump_url (const char *url, const struct http_parser_url *u)
2587   -{
2588   - unsigned int i;
2589   -
2590   - printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
2591   - for (i = 0; i < UF_MAX; i++) {
2592   - if ((u->field_set & (1 << i)) == 0) {
2593   - printf("\tfield_data[%u]: unset\n", i);
2594   - continue;
2595   - }
2596   -
2597   - printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
2598   - i,
2599   - u->field_data[i].off,
2600   - u->field_data[i].len,
2601   - u->field_data[i].len,
2602   - url + u->field_data[i].off);
2603   - }
2604   -}
2605   -
2606   -void
2607   -test_parse_url (void)
2608   -{
2609   - struct http_parser_url u;
2610   - const struct url_test *test;
2611   - unsigned int i;
2612   - int rv;
2613   -
2614   - for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
2615   - test = &url_tests[i];
2616   - memset(&u, 0, sizeof(u));
2617   -
2618   - rv = http_parser_parse_url(test->url,
2619   - strlen(test->url),
2620   - test->is_connect,
2621   - &u);
2622   -
2623   - if (test->rv == 0) {
2624   - if (rv != 0) {
2625   - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2626   - "unexpected rv %d ***\n\n", test->url, test->name, rv);
2627   - abort();
2628   - }
2629   -
2630   - if (memcmp(&u, &test->u, sizeof(u)) != 0) {
2631   - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
2632   - test->url, test->name);
2633   -
2634   - printf("target http_parser_url:\n");
2635   - dump_url(test->url, &test->u);
2636   - printf("result http_parser_url:\n");
2637   - dump_url(test->url, &u);
2638   -
2639   - abort();
2640   - }
2641   - } else {
2642   - /* test->rv != 0 */
2643   - if (rv == 0) {
2644   - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2645   - "unexpected rv %d ***\n\n", test->url, test->name, rv);
2646   - abort();
2647   - }
2648   - }
2649   - }
2650   -}
2651   -
2652   -void
2653   -test_method_str (void)
2654   -{
2655   - assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
2656   - assert(0 == strcmp("<unknown>", http_method_str(1337)));
2657   -}
2658   -
2659   -void
2660   -test_message (const struct message *message)
2661   -{
2662   - size_t raw_len = strlen(message->raw);
2663   - size_t msg1len;
2664   - for (msg1len = 0; msg1len < raw_len; msg1len++) {
2665   - parser_init(message->type);
2666   -
2667   - size_t read;
2668   - const char *msg1 = message->raw;
2669   - const char *msg2 = msg1 + msg1len;
2670   - size_t msg2len = raw_len - msg1len;
2671   -
2672   - if (msg1len) {
2673   - read = parse(msg1, msg1len);
2674   -
2675   - if (message->upgrade && parser->upgrade) {
2676   - messages[num_messages - 1].upgrade = msg1 + read;
2677   - goto test;
2678   - }
2679   -
2680   - if (read != msg1len) {
2681   - print_error(msg1, read);
2682   - abort();
2683   - }
2684   - }
2685   -
2686   -
2687   - read = parse(msg2, msg2len);
2688   -
2689   - if (message->upgrade && parser->upgrade) {
2690   - messages[num_messages - 1].upgrade = msg2 + read;
2691   - goto test;
2692   - }
2693   -
2694   - if (read != msg2len) {
2695   - print_error(msg2, read);
2696   - abort();
2697   - }
2698   -
2699   - read = parse(NULL, 0);
2700   -
2701   - if (read != 0) {
2702   - print_error(message->raw, read);
2703   - abort();
2704   - }
2705   -
2706   - test:
2707   -
2708   - if (num_messages != 1) {
2709   - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2710   - abort();
2711   - }
2712   -
2713   - if(!message_eq(0, message)) abort();
2714   -
2715   - parser_free();
2716   - }
2717   -}
2718   -
2719   -void
2720   -test_message_count_body (const struct message *message)
2721   -{
2722   - parser_init(message->type);
2723   -
2724   - size_t read;
2725   - size_t l = strlen(message->raw);
2726   - size_t i, toread;
2727   - size_t chunk = 4024;
2728   -
2729   - for (i = 0; i < l; i+= chunk) {
2730   - toread = MIN(l-i, chunk);
2731   - read = parse_count_body(message->raw + i, toread);
2732   - if (read != toread) {
2733   - print_error(message->raw, read);
2734   - abort();
2735   - }
2736   - }
2737   -
2738   -
2739   - read = parse_count_body(NULL, 0);
2740   - if (read != 0) {
2741   - print_error(message->raw, read);
2742   - abort();
2743   - }
2744   -
2745   - if (num_messages != 1) {
2746   - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2747   - abort();
2748   - }
2749   -
2750   - if(!message_eq(0, message)) abort();
2751   -
2752   - parser_free();
2753   -}
2754   -
2755   -void
2756   -test_simple (const char *buf, enum http_errno err_expected)
2757   -{
2758   - parser_init(HTTP_REQUEST);
2759   -
2760   - size_t parsed;
2761   - int pass;
2762   - enum http_errno err;
2763   -
2764   - parsed = parse(buf, strlen(buf));
2765   - pass = (parsed == strlen(buf));
2766   - err = HTTP_PARSER_ERRNO(parser);
2767   - parsed = parse(NULL, 0);
2768   - pass &= (parsed == 0);
2769   -
2770   - parser_free();
2771   -
2772   - /* In strict mode, allow us to pass with an unexpected HPE_STRICT as
2773   - * long as the caller isn't expecting success.
2774   - */
2775   -#if HTTP_PARSER_STRICT
2776   - if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
2777   -#else
2778   - if (err_expected != err) {
2779   -#endif
2780   - fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
2781   - http_errno_name(err_expected), http_errno_name(err), buf);
2782   - abort();
2783   - }
2784   -}
2785   -
2786   -void
2787   -test_header_overflow_error (int req)
2788   -{
2789   - http_parser parser;
2790   - http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
2791   - size_t parsed;
2792   - const char *buf;
2793   - buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n";
2794   - parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
2795   - assert(parsed == strlen(buf));
2796   -
2797   - buf = "header-key: header-value\r\n";
2798   - size_t buflen = strlen(buf);
2799   -
2800   - int i;
2801   - for (i = 0; i < 10000; i++) {
2802   - parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
2803   - if (parsed != buflen) {
2804   - //fprintf(stderr, "error found on iter %d\n", i);
2805   - assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
2806   - return;
2807   - }
2808   - }
2809   -
2810   - fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
2811   - abort();
2812   -}
2813   -
2814   -static void
2815   -test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
2816   -{
2817   - http_parser parser;
2818   - http_parser_init(&parser, HTTP_RESPONSE);
2819   - http_parser_execute(&parser, &settings_null, buf, buflen);
2820   -
2821   - if (expect_ok)
2822   - assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
2823   - else
2824   - assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
2825   -}
2826   -
2827   -void
2828   -test_header_content_length_overflow_error (void)
2829   -{
2830   -#define X(size) \
2831   - "HTTP/1.1 200 OK\r\n" \
2832   - "Content-Length: " #size "\r\n" \
2833   - "\r\n"
2834   - const char a[] = X(18446744073709551614); /* 2^64-2 */
2835   - const char b[] = X(18446744073709551615); /* 2^64-1 */
2836   - const char c[] = X(18446744073709551616); /* 2^64 */
2837   -#undef X
2838   - test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
2839   - test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
2840   - test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
2841   -}
2842   -
2843   -void
2844   -test_chunk_content_length_overflow_error (void)
2845   -{
2846   -#define X(size) \
2847   - "HTTP/1.1 200 OK\r\n" \
2848   - "Transfer-Encoding: chunked\r\n" \
2849   - "\r\n" \
2850   - #size "\r\n" \
2851   - "..."
2852   - const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
2853   - const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
2854   - const char c[] = X(10000000000000000); /* 2^64 */
2855   -#undef X
2856   - test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
2857   - test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
2858   - test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
2859   -}
2860   -
2861   -void
2862   -test_no_overflow_long_body (int req, size_t length)
2863   -{
2864   - http_parser parser;
2865   - http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
2866   - size_t parsed;
2867   - size_t i;
2868   - char buf1[3000];
2869   - size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
2870   - req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
2871   - parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2872   - if (parsed != buf1len)
2873   - goto err;
2874   -
2875   - for (i = 0; i < length; i++) {
2876   - char foo = 'a';
2877   - parsed = http_parser_execute(&parser, &settings_null, &foo, 1);
2878   - if (parsed != 1)
2879   - goto err;
2880   - }
2881   -
2882   - parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2883   - if (parsed != buf1len) goto err;
2884   - return;
2885   -
2886   - err:
2887   - fprintf(stderr,
2888   - "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
2889   - req ? "REQUEST" : "RESPONSE",
2890   - (unsigned long)length);
2891   - abort();
2892   -}
2893   -
2894   -void
2895   -test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
2896   -{
2897   - int message_count = count_parsed_messages(3, r1, r2, r3);
2898   -
2899   - char total[ strlen(r1->raw)
2900   - + strlen(r2->raw)
2901   - + strlen(r3->raw)
2902   - + 1
2903   - ];
2904   - total[0] = '\0';
2905   -
2906   - strcat(total, r1->raw);
2907   - strcat(total, r2->raw);
2908   - strcat(total, r3->raw);
2909   -
2910   - parser_init(r1->type);
2911   -
2912   - size_t read;
2913   -
2914   - read = parse(total, strlen(total));
2915   -
2916   - if (parser->upgrade) {
2917   - upgrade_message_fix(total, read, 3, r1, r2, r3);
2918   - goto test;
2919   - }
2920   -
2921   - if (read != strlen(total)) {
2922   - print_error(total, read);
2923   - abort();
2924   - }
2925   -
2926   - read = parse(NULL, 0);
2927   -
2928   - if (read != 0) {
2929   - print_error(total, read);
2930   - abort();
2931   - }
2932   -
2933   -test:
2934   -
2935   - if (message_count != num_messages) {
2936   - fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
2937   - abort();
2938   - }
2939   -
2940   - if (!message_eq(0, r1)) abort();
2941   - if (message_count > 1 && !message_eq(1, r2)) abort();
2942   - if (message_count > 2 && !message_eq(2, r3)) abort();
2943   -
2944   - parser_free();
2945   -}
2946   -
2947   -/* SCAN through every possible breaking to make sure the
2948   - * parser can handle getting the content in any chunks that
2949   - * might come from the socket
2950   - */
2951   -void
2952   -test_scan (const struct message *r1, const struct message *r2, const struct message *r3)
2953   -{
2954   - char total[80*1024] = "\0";
2955   - char buf1[80*1024] = "\0";
2956   - char buf2[80*1024] = "\0";
2957   - char buf3[80*1024] = "\0";
2958   -
2959   - strcat(total, r1->raw);
2960   - strcat(total, r2->raw);
2961   - strcat(total, r3->raw);
2962   -
2963   - size_t read;
2964   -
2965   - int total_len = strlen(total);
2966   -
2967   - int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2;
2968   - int ops = 0 ;
2969   -
2970   - size_t buf1_len, buf2_len, buf3_len;
2971   - int message_count = count_parsed_messages(3, r1, r2, r3);
2972   -
2973   - int i,j,type_both;
2974   - for (type_both = 0; type_both < 2; type_both ++ ) {
2975   - for (j = 2; j < total_len; j ++ ) {
2976   - for (i = 1; i < j; i ++ ) {
2977   -
2978   - if (ops % 1000 == 0) {
2979   - printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops);
2980   - fflush(stdout);
2981   - }
2982   - ops += 1;
2983   -
2984   - parser_init(type_both ? HTTP_BOTH : r1->type);
2985   -
2986   - buf1_len = i;
2987   - strlncpy(buf1, sizeof(buf1), total, buf1_len);
2988   - buf1[buf1_len] = 0;
2989   -
2990   - buf2_len = j - i;
2991   - strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
2992   - buf2[buf2_len] = 0;
2993   -
2994   - buf3_len = total_len - j;
2995   - strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
2996   - buf3[buf3_len] = 0;
2997   -
2998   - read = parse(buf1, buf1_len);
2999   -
3000   - if (parser->upgrade) goto test;
3001   -
3002   - if (read != buf1_len) {
3003   - print_error(buf1, read);
3004   - goto error;
3005   - }
3006   -
3007   - read += parse(buf2, buf2_len);
3008   -
3009   - if (parser->upgrade) goto test;
3010   -
3011   - if (read != buf1_len + buf2_len) {
3012   - print_error(buf2, read);
3013   - goto error;
3014   - }
3015   -
3016   - read += parse(buf3, buf3_len);
3017   -
3018   - if (parser->upgrade) goto test;
3019   -
3020   - if (read != buf1_len + buf2_len + buf3_len) {
3021   - print_error(buf3, read);
3022   - goto error;
3023   - }
3024   -
3025   - parse(NULL, 0);
3026   -
3027   -test:
3028   - if (parser->upgrade) {
3029   - upgrade_message_fix(total, read, 3, r1, r2, r3);
3030   - }
3031   -
3032   - if (message_count != num_messages) {
3033   - fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
3034   - message_count, num_messages);
3035   - goto error;
3036   - }
3037   -
3038   - if (!message_eq(0, r1)) {
3039   - fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
3040   - goto error;
3041   - }
3042   -
3043   - if (message_count > 1 && !message_eq(1, r2)) {
3044   - fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
3045   - goto error;
3046   - }
3047   -
3048   - if (message_count > 2 && !message_eq(2, r3)) {
3049   - fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
3050   - goto error;
3051   - }
3052   -
3053   - parser_free();
3054   - }
3055   - }
3056   - }
3057   - puts("\b\b\b\b100%");
3058   - return;
3059   -
3060   - error:
3061   - fprintf(stderr, "i=%d j=%d\n", i, j);
3062   - fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
3063   - fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
3064   - fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
3065   - abort();
3066   -}
3067   -
3068   -// user required to free the result
3069   -// string terminated by \0
3070   -char *
3071   -create_large_chunked_message (int body_size_in_kb, const char* headers)
3072   -{
3073   - int i;
3074   - size_t wrote = 0;
3075   - size_t headers_len = strlen(headers);
3076   - size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6;
3077   - char * buf = malloc(bufsize);
3078   -
3079   - memcpy(buf, headers, headers_len);
3080   - wrote += headers_len;
3081   -
3082   - for (i = 0; i < body_size_in_kb; i++) {
3083   - // write 1kb chunk into the body.
3084   - memcpy(buf + wrote, "400\r\n", 5);
3085   - wrote += 5;
3086   - memset(buf + wrote, 'C', 1024);
3087   - wrote += 1024;
3088   - strcpy(buf + wrote, "\r\n");
3089   - wrote += 2;
3090   - }
3091   -
3092   - memcpy(buf + wrote, "0\r\n\r\n", 6);
3093   - wrote += 6;
3094   - assert(wrote == bufsize);
3095   -
3096   - return buf;
3097   -}
3098   -
3099   -void
3100   -test_status_complete (void)
3101   -{
3102   - parser_init(HTTP_RESPONSE);
3103   - parser->data = 0;
3104   - http_parser_settings settings = settings_null;
3105   - settings.on_status_complete = status_complete_cb;
3106   -
3107   - char *response = "don't mind me, just a simple response";
3108   - http_parser_execute(parser, &settings, response, strlen(response));
3109   - assert(parser->data == (void*)0); // the status_complete callback was never called
3110   - assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line
3111   -}
3112   -
3113   -/* Verify that we can pause parsing at any of the bytes in the
3114   - * message and still get the result that we're expecting. */
3115   -void
3116   -test_message_pause (const struct message *msg)
3117   -{
3118   - char *buf = (char*) msg->raw;
3119   - size_t buflen = strlen(msg->raw);
3120   - size_t nread;
3121   -
3122   - parser_init(msg->type);
3123   -
3124   - do {
3125   - nread = parse_pause(buf, buflen);
3126   -
3127   - // We can only set the upgrade buffer once we've gotten our message
3128   - // completion callback.
3129   - if (messages[0].message_complete_cb_called &&
3130   - msg->upgrade &&
3131   - parser->upgrade) {
3132   - messages[0].upgrade = buf + nread;
3133   - goto test;
3134   - }
3135   -
3136   - if (nread < buflen) {
3137   -
3138   - // Not much do to if we failed a strict-mode check
3139   - if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
3140   - parser_free();
3141   - return;
3142   - }
3143   -
3144   - assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
3145   - }
3146   -
3147   - buf += nread;
3148   - buflen -= nread;
3149   - http_parser_pause(parser, 0);
3150   - } while (buflen > 0);
3151   -
3152   - nread = parse_pause(NULL, 0);
3153   - assert (nread == 0);
3154   -
3155   -test:
3156   - if (num_messages != 1) {
3157   - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
3158   - abort();
3159   - }
3160   -
3161   - if(!message_eq(0, msg)) abort();
3162   -
3163   - parser_free();
3164   -}
3165   -
3166   -int
3167   -main (void)
3168   -{
3169   - parser = NULL;
3170   - int i, j, k;
3171   - int request_count;
3172   - int response_count;
3173   -
3174   - printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
3175   -
3176   - for (request_count = 0; requests[request_count].name; request_count++);
3177   - for (response_count = 0; responses[response_count].name; response_count++);
3178   -
3179   - //// API
3180   - test_preserve_data();
3181   - test_parse_url();
3182   - test_method_str();
3183   -
3184   - //// OVERFLOW CONDITIONS
3185   -
3186   - test_header_overflow_error(HTTP_REQUEST);
3187   - test_no_overflow_long_body(HTTP_REQUEST, 1000);
3188   - test_no_overflow_long_body(HTTP_REQUEST, 100000);
3189   -
3190   - test_header_overflow_error(HTTP_RESPONSE);
3191   - test_no_overflow_long_body(HTTP_RESPONSE, 1000);
3192   - test_no_overflow_long_body(HTTP_RESPONSE, 100000);
3193   -
3194   - test_header_content_length_overflow_error();
3195   - test_chunk_content_length_overflow_error();
3196   -
3197   - //// RESPONSES
3198   -
3199   - for (i = 0; i < response_count; i++) {
3200   - test_message(&responses[i]);
3201   - }
3202   -
3203   - for (i = 0; i < response_count; i++) {
3204   - test_message_pause(&responses[i]);
3205   - }
3206   -
3207   - for (i = 0; i < response_count; i++) {
3208   - if (!responses[i].should_keep_alive) continue;
3209   - for (j = 0; j < response_count; j++) {
3210   - if (!responses[j].should_keep_alive) continue;
3211   - for (k = 0; k < response_count; k++) {
3212   - test_multiple3(&responses[i], &responses[j], &responses[k]);
3213   - }
3214   - }
3215   - }
3216   -
3217   - test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
3218   - test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
3219   -
3220   - // test very large chunked response
3221   - {
3222   - char * msg = create_large_chunked_message(31337,
3223   - "HTTP/1.0 200 OK\r\n"
3224   - "Transfer-Encoding: chunked\r\n"
3225   - "Content-Type: text/plain\r\n"
3226   - "\r\n");
3227   - struct message large_chunked =
3228   - {.name= "large chunked"
3229   - ,.type= HTTP_RESPONSE
3230   - ,.raw= msg
3231   - ,.should_keep_alive= FALSE
3232   - ,.message_complete_on_eof= FALSE
3233   - ,.http_major= 1
3234   - ,.http_minor= 0
3235   - ,.status_code= 200
3236   - ,.num_headers= 2
3237   - ,.headers=
3238   - { { "Transfer-Encoding", "chunked" }
3239   - , { "Content-Type", "text/plain" }
3240   - }
3241   - ,.body_size= 31337*1024
3242   - };
3243   - test_message_count_body(&large_chunked);
3244   - free(msg);
3245   - }
3246   -
3247   -
3248   -
3249   - printf("response scan 1/2 ");
3250   - test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
3251   - , &responses[NO_BODY_HTTP10_KA_204]
3252   - , &responses[NO_REASON_PHRASE]
3253   - );
3254   -
3255   - printf("response scan 2/2 ");
3256   - test_scan( &responses[BONJOUR_MADAME_FR]
3257   - , &responses[UNDERSTORE_HEADER_KEY]
3258   - , &responses[NO_CARRIAGE_RET]
3259   - );
3260   -
3261   - puts("responses okay");
3262   -
3263   -
3264   - /// REQUESTS
3265   -
3266   - test_simple("hello world", HPE_INVALID_METHOD);
3267   - test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
3268   -
3269   -
3270   - test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
3271   - test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
3272   - test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
3273   -
3274   - // Well-formed but incomplete
3275   - test_simple("GET / HTTP/1.1\r\n"
3276   - "Content-Type: text/plain\r\n"
3277   - "Content-Length: 6\r\n"
3278   - "\r\n"
3279   - "fooba",
3280   - HPE_OK);
3281   -
3282   - static const char *all_methods[] = {
3283   - "DELETE",
3284   - "GET",
3285   - "HEAD",
3286   - "POST",
3287   - "PUT",
3288   - //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel
3289   - "OPTIONS",
3290   - "TRACE",
3291   - "COPY",
3292   - "LOCK",
3293   - "MKCOL",
3294   - "MOVE",
3295   - "PROPFIND",
3296   - "PROPPATCH",
3297   - "UNLOCK",
3298   - "REPORT",
3299   - "MKACTIVITY",
3300   - "CHECKOUT",
3301   - "MERGE",
3302   - "M-SEARCH",
3303   - "NOTIFY",
3304   - "SUBSCRIBE",
3305   - "UNSUBSCRIBE",
3306   - "PATCH",
3307   - 0 };
3308   - const char **this_method;
3309   - for (this_method = all_methods; *this_method; this_method++) {
3310   - char buf[200];
3311   - sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
3312   - test_simple(buf, HPE_OK);
3313   - }
3314   -
3315   - static const char *bad_methods[] = {
3316   - "C******",
3317   - "M****",
3318   - 0 };
3319   - for (this_method = bad_methods; *this_method; this_method++) {
3320   - char buf[200];
3321   - sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
3322   - test_simple(buf, HPE_UNKNOWN);
3323   - }
3324   -
3325   - const char *dumbfuck2 =
3326   - "GET / HTTP/1.1\r\n"
3327   - "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
3328   - "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
3329   - "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
3330   - "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
3331   - "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n"
3332   - "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n"
3333   - "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n"
3334   - "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n"
3335   - "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n"
3336   - "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n"
3337   - "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n"
3338   - "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n"
3339   - "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n"
3340   - "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n"
3341   - "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n"
3342   - "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n"
3343   - "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n"
3344   - "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n"
3345   - "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n"
3346   - "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n"
3347   - "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n"
3348   - "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n"
3349   - "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n"
3350   - "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n"
3351   - "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n"
3352   - "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n"
3353   - "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n"
3354   - "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n"
3355   - "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n"
3356   - "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n"
3357   - "\tRA==\r\n"
3358   - "\t-----END CERTIFICATE-----\r\n"
3359   - "\r\n";
3360   - test_simple(dumbfuck2, HPE_OK);
3361   -
3362   -#if 0
3363   - // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
3364   - // until EOF.
3365   - //
3366   - // no content-length
3367   - // error if there is a body without content length
3368   - const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n"
3369   - "Accept: */*\r\n"
3370   - "\r\n"
3371   - "HELLO";
3372   - test_simple(bad_get_no_headers_no_body, 0);
3373   -#endif
3374   - /* TODO sending junk and large headers gets rejected */
3375   -
3376   -
3377   - /* check to make sure our predefined requests are okay */
3378   - for (i = 0; requests[i].name; i++) {
3379   - test_message(&requests[i]);
3380   - }
3381   -
3382   - for (i = 0; i < request_count; i++) {
3383   - test_message_pause(&requests[i]);
3384   - }
3385   -
3386   - for (i = 0; i < request_count; i++) {
3387   - if (!requests[i].should_keep_alive) continue;
3388   - for (j = 0; j < request_count; j++) {
3389   - if (!requests[j].should_keep_alive) continue;
3390   - for (k = 0; k < request_count; k++) {
3391   - test_multiple3(&requests[i], &requests[j], &requests[k]);
3392   - }
3393   - }
3394   - }
3395   -
3396   - printf("request scan 1/4 ");
3397   - test_scan( &requests[GET_NO_HEADERS_NO_BODY]
3398   - , &requests[GET_ONE_HEADER_NO_BODY]
3399   - , &requests[GET_NO_HEADERS_NO_BODY]
3400   - );
3401   -
3402   - printf("request scan 2/4 ");
3403   - test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE]
3404   - , &requests[POST_IDENTITY_BODY_WORLD]
3405   - , &requests[GET_FUNKY_CONTENT_LENGTH]
3406   - );
3407   -
3408   - printf("request scan 3/4 ");
3409   - test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
3410   - , &requests[CHUNKED_W_TRAILING_HEADERS]
3411   - , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
3412   - );
3413   -
3414   - printf("request scan 4/4 ");
3415   - test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET]
3416   - , &requests[PREFIX_NEWLINE_GET ]
3417   - , &requests[CONNECT_REQUEST]
3418   - );
3419   -
3420   - test_status_complete();
3421   -
3422   - puts("requests okay");
3423   -
3424   - return 0;
3425   -}