deps: upgrade to npm 2.14.18
[platform/upstream/nodejs.git] / deps / http_parser / test.c
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 #if defined(__APPLE__)
30 # undef strlcat
31 # undef strlncpy
32 # undef strlcpy
33 #endif  /* defined(__APPLE__) */
34
35 #undef TRUE
36 #define TRUE 1
37 #undef FALSE
38 #define FALSE 0
39
40 #define MAX_HEADERS 13
41 #define MAX_ELEMENT_SIZE 2048
42 #define MAX_CHUNKS 16
43
44 #define MIN(a,b) ((a) < (b) ? (a) : (b))
45
46 static http_parser *parser;
47
48 struct message {
49   const char *name; // for debugging purposes
50   const char *raw;
51   enum http_parser_type type;
52   enum http_method method;
53   int status_code;
54   char response_status[MAX_ELEMENT_SIZE];
55   char request_path[MAX_ELEMENT_SIZE];
56   char request_url[MAX_ELEMENT_SIZE];
57   char fragment[MAX_ELEMENT_SIZE];
58   char query_string[MAX_ELEMENT_SIZE];
59   char body[MAX_ELEMENT_SIZE];
60   size_t body_size;
61   const char *host;
62   const char *userinfo;
63   uint16_t port;
64   int num_headers;
65   enum { NONE=0, FIELD, VALUE } last_header_element;
66   char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
67   int should_keep_alive;
68
69   int num_chunks;
70   int num_chunks_complete;
71   int chunk_lengths[MAX_CHUNKS];
72
73   const char *upgrade; // upgraded body
74
75   unsigned short http_major;
76   unsigned short http_minor;
77
78   int message_begin_cb_called;
79   int headers_complete_cb_called;
80   int message_complete_cb_called;
81   int message_complete_on_eof;
82   int body_is_final;
83 };
84
85 static int currently_parsing_eof;
86
87 static struct message messages[5];
88 static int num_messages;
89 static http_parser_settings *current_pause_parser;
90
91 /* * R E Q U E S T S * */
92 const struct message requests[] =
93 #define CURL_GET 0
94 { {.name= "curl get"
95   ,.type= HTTP_REQUEST
96   ,.raw= "GET /test HTTP/1.1\r\n"
97          "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"
98          "Host: 0.0.0.0=5000\r\n"
99          "Accept: */*\r\n"
100          "\r\n"
101   ,.should_keep_alive= TRUE
102   ,.message_complete_on_eof= FALSE
103   ,.http_major= 1
104   ,.http_minor= 1
105   ,.method= HTTP_GET
106   ,.query_string= ""
107   ,.fragment= ""
108   ,.request_path= "/test"
109   ,.request_url= "/test"
110   ,.num_headers= 3
111   ,.headers=
112     { { "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" }
113     , { "Host", "0.0.0.0=5000" }
114     , { "Accept", "*/*" }
115     }
116   ,.body= ""
117   }
118
119 #define FIREFOX_GET 1
120 , {.name= "firefox get"
121   ,.type= HTTP_REQUEST
122   ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
123          "Host: 0.0.0.0=5000\r\n"
124          "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
125          "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
126          "Accept-Language: en-us,en;q=0.5\r\n"
127          "Accept-Encoding: gzip,deflate\r\n"
128          "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
129          "Keep-Alive: 300\r\n"
130          "Connection: keep-alive\r\n"
131          "\r\n"
132   ,.should_keep_alive= TRUE
133   ,.message_complete_on_eof= FALSE
134   ,.http_major= 1
135   ,.http_minor= 1
136   ,.method= HTTP_GET
137   ,.query_string= ""
138   ,.fragment= ""
139   ,.request_path= "/favicon.ico"
140   ,.request_url= "/favicon.ico"
141   ,.num_headers= 8
142   ,.headers=
143     { { "Host", "0.0.0.0=5000" }
144     , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" }
145     , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }
146     , { "Accept-Language", "en-us,en;q=0.5" }
147     , { "Accept-Encoding", "gzip,deflate" }
148     , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" }
149     , { "Keep-Alive", "300" }
150     , { "Connection", "keep-alive" }
151     }
152   ,.body= ""
153   }
154
155 #define DUMBFUCK 2
156 , {.name= "dumbfuck"
157   ,.type= HTTP_REQUEST
158   ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
159          "aaaaaaaaaaaaa:++++++++++\r\n"
160          "\r\n"
161   ,.should_keep_alive= TRUE
162   ,.message_complete_on_eof= FALSE
163   ,.http_major= 1
164   ,.http_minor= 1
165   ,.method= HTTP_GET
166   ,.query_string= ""
167   ,.fragment= ""
168   ,.request_path= "/dumbfuck"
169   ,.request_url= "/dumbfuck"
170   ,.num_headers= 1
171   ,.headers=
172     { { "aaaaaaaaaaaaa",  "++++++++++" }
173     }
174   ,.body= ""
175   }
176
177 #define FRAGMENT_IN_URI 3
178 , {.name= "fragment in url"
179   ,.type= HTTP_REQUEST
180   ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
181          "\r\n"
182   ,.should_keep_alive= TRUE
183   ,.message_complete_on_eof= FALSE
184   ,.http_major= 1
185   ,.http_minor= 1
186   ,.method= HTTP_GET
187   ,.query_string= "page=1"
188   ,.fragment= "posts-17408"
189   ,.request_path= "/forums/1/topics/2375"
190   /* XXX request url does include fragment? */
191   ,.request_url= "/forums/1/topics/2375?page=1#posts-17408"
192   ,.num_headers= 0
193   ,.body= ""
194   }
195
196 #define GET_NO_HEADERS_NO_BODY 4
197 , {.name= "get no headers no body"
198   ,.type= HTTP_REQUEST
199   ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
200          "\r\n"
201   ,.should_keep_alive= TRUE
202   ,.message_complete_on_eof= FALSE /* would need Connection: close */
203   ,.http_major= 1
204   ,.http_minor= 1
205   ,.method= HTTP_GET
206   ,.query_string= ""
207   ,.fragment= ""
208   ,.request_path= "/get_no_headers_no_body/world"
209   ,.request_url= "/get_no_headers_no_body/world"
210   ,.num_headers= 0
211   ,.body= ""
212   }
213
214 #define GET_ONE_HEADER_NO_BODY 5
215 , {.name= "get one header no body"
216   ,.type= HTTP_REQUEST
217   ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
218          "Accept: */*\r\n"
219          "\r\n"
220   ,.should_keep_alive= TRUE
221   ,.message_complete_on_eof= FALSE /* would need Connection: close */
222   ,.http_major= 1
223   ,.http_minor= 1
224   ,.method= HTTP_GET
225   ,.query_string= ""
226   ,.fragment= ""
227   ,.request_path= "/get_one_header_no_body"
228   ,.request_url= "/get_one_header_no_body"
229   ,.num_headers= 1
230   ,.headers=
231     { { "Accept" , "*/*" }
232     }
233   ,.body= ""
234   }
235
236 #define GET_FUNKY_CONTENT_LENGTH 6
237 , {.name= "get funky content length body hello"
238   ,.type= HTTP_REQUEST
239   ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
240          "conTENT-Length: 5\r\n"
241          "\r\n"
242          "HELLO"
243   ,.should_keep_alive= FALSE
244   ,.message_complete_on_eof= FALSE
245   ,.http_major= 1
246   ,.http_minor= 0
247   ,.method= HTTP_GET
248   ,.query_string= ""
249   ,.fragment= ""
250   ,.request_path= "/get_funky_content_length_body_hello"
251   ,.request_url= "/get_funky_content_length_body_hello"
252   ,.num_headers= 1
253   ,.headers=
254     { { "conTENT-Length" , "5" }
255     }
256   ,.body= "HELLO"
257   }
258
259 #define POST_IDENTITY_BODY_WORLD 7
260 , {.name= "post identity body world"
261   ,.type= HTTP_REQUEST
262   ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
263          "Accept: */*\r\n"
264          "Transfer-Encoding: identity\r\n"
265          "Content-Length: 5\r\n"
266          "\r\n"
267          "World"
268   ,.should_keep_alive= TRUE
269   ,.message_complete_on_eof= FALSE
270   ,.http_major= 1
271   ,.http_minor= 1
272   ,.method= HTTP_POST
273   ,.query_string= "q=search"
274   ,.fragment= "hey"
275   ,.request_path= "/post_identity_body_world"
276   ,.request_url= "/post_identity_body_world?q=search#hey"
277   ,.num_headers= 3
278   ,.headers=
279     { { "Accept", "*/*" }
280     , { "Transfer-Encoding", "identity" }
281     , { "Content-Length", "5" }
282     }
283   ,.body= "World"
284   }
285
286 #define POST_CHUNKED_ALL_YOUR_BASE 8
287 , {.name= "post - chunked body: all your base are belong to us"
288   ,.type= HTTP_REQUEST
289   ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
290          "Transfer-Encoding: chunked\r\n"
291          "\r\n"
292          "1e\r\nall your base are belong to us\r\n"
293          "0\r\n"
294          "\r\n"
295   ,.should_keep_alive= TRUE
296   ,.message_complete_on_eof= FALSE
297   ,.http_major= 1
298   ,.http_minor= 1
299   ,.method= HTTP_POST
300   ,.query_string= ""
301   ,.fragment= ""
302   ,.request_path= "/post_chunked_all_your_base"
303   ,.request_url= "/post_chunked_all_your_base"
304   ,.num_headers= 1
305   ,.headers=
306     { { "Transfer-Encoding" , "chunked" }
307     }
308   ,.body= "all your base are belong to us"
309   ,.num_chunks_complete= 2
310   ,.chunk_lengths= { 0x1e }
311   }
312
313 #define TWO_CHUNKS_MULT_ZERO_END 9
314 , {.name= "two chunks ; triple zero ending"
315   ,.type= HTTP_REQUEST
316   ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
317          "Transfer-Encoding: chunked\r\n"
318          "\r\n"
319          "5\r\nhello\r\n"
320          "6\r\n world\r\n"
321          "000\r\n"
322          "\r\n"
323   ,.should_keep_alive= TRUE
324   ,.message_complete_on_eof= FALSE
325   ,.http_major= 1
326   ,.http_minor= 1
327   ,.method= HTTP_POST
328   ,.query_string= ""
329   ,.fragment= ""
330   ,.request_path= "/two_chunks_mult_zero_end"
331   ,.request_url= "/two_chunks_mult_zero_end"
332   ,.num_headers= 1
333   ,.headers=
334     { { "Transfer-Encoding", "chunked" }
335     }
336   ,.body= "hello world"
337   ,.num_chunks_complete= 3
338   ,.chunk_lengths= { 5, 6 }
339   }
340
341 #define CHUNKED_W_TRAILING_HEADERS 10
342 , {.name= "chunked with trailing headers. blech."
343   ,.type= HTTP_REQUEST
344   ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
345          "Transfer-Encoding: chunked\r\n"
346          "\r\n"
347          "5\r\nhello\r\n"
348          "6\r\n world\r\n"
349          "0\r\n"
350          "Vary: *\r\n"
351          "Content-Type: text/plain\r\n"
352          "\r\n"
353   ,.should_keep_alive= TRUE
354   ,.message_complete_on_eof= FALSE
355   ,.http_major= 1
356   ,.http_minor= 1
357   ,.method= HTTP_POST
358   ,.query_string= ""
359   ,.fragment= ""
360   ,.request_path= "/chunked_w_trailing_headers"
361   ,.request_url= "/chunked_w_trailing_headers"
362   ,.num_headers= 3
363   ,.headers=
364     { { "Transfer-Encoding",  "chunked" }
365     , { "Vary", "*" }
366     , { "Content-Type", "text/plain" }
367     }
368   ,.body= "hello world"
369   ,.num_chunks_complete= 3
370   ,.chunk_lengths= { 5, 6 }
371   }
372
373 #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
374 , {.name= "with bullshit after the length"
375   ,.type= HTTP_REQUEST
376   ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
377          "Transfer-Encoding: chunked\r\n"
378          "\r\n"
379          "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
380          "6; blahblah; blah\r\n world\r\n"
381          "0\r\n"
382          "\r\n"
383   ,.should_keep_alive= TRUE
384   ,.message_complete_on_eof= FALSE
385   ,.http_major= 1
386   ,.http_minor= 1
387   ,.method= HTTP_POST
388   ,.query_string= ""
389   ,.fragment= ""
390   ,.request_path= "/chunked_w_bullshit_after_length"
391   ,.request_url= "/chunked_w_bullshit_after_length"
392   ,.num_headers= 1
393   ,.headers=
394     { { "Transfer-Encoding", "chunked" }
395     }
396   ,.body= "hello world"
397   ,.num_chunks_complete= 3
398   ,.chunk_lengths= { 5, 6 }
399   }
400
401 #define WITH_QUOTES 12
402 , {.name= "with quotes"
403   ,.type= HTTP_REQUEST
404   ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
405   ,.should_keep_alive= TRUE
406   ,.message_complete_on_eof= FALSE
407   ,.http_major= 1
408   ,.http_minor= 1
409   ,.method= HTTP_GET
410   ,.query_string= "foo=\"bar\""
411   ,.fragment= ""
412   ,.request_path= "/with_\"stupid\"_quotes"
413   ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\""
414   ,.num_headers= 0
415   ,.headers= { }
416   ,.body= ""
417   }
418
419 #define APACHEBENCH_GET 13
420 /* The server receiving this request SHOULD NOT wait for EOF
421  * to know that content-length == 0.
422  * How to represent this in a unit test? message_complete_on_eof
423  * Compare with NO_CONTENT_LENGTH_RESPONSE.
424  */
425 , {.name = "apachebench get"
426   ,.type= HTTP_REQUEST
427   ,.raw= "GET /test HTTP/1.0\r\n"
428          "Host: 0.0.0.0:5000\r\n"
429          "User-Agent: ApacheBench/2.3\r\n"
430          "Accept: */*\r\n\r\n"
431   ,.should_keep_alive= FALSE
432   ,.message_complete_on_eof= FALSE
433   ,.http_major= 1
434   ,.http_minor= 0
435   ,.method= HTTP_GET
436   ,.query_string= ""
437   ,.fragment= ""
438   ,.request_path= "/test"
439   ,.request_url= "/test"
440   ,.num_headers= 3
441   ,.headers= { { "Host", "0.0.0.0:5000" }
442              , { "User-Agent", "ApacheBench/2.3" }
443              , { "Accept", "*/*" }
444              }
445   ,.body= ""
446   }
447
448 #define QUERY_URL_WITH_QUESTION_MARK_GET 14
449 /* Some clients include '?' characters in query strings.
450  */
451 , {.name = "query url with question mark"
452   ,.type= HTTP_REQUEST
453   ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n"
454   ,.should_keep_alive= TRUE
455   ,.message_complete_on_eof= FALSE
456   ,.http_major= 1
457   ,.http_minor= 1
458   ,.method= HTTP_GET
459   ,.query_string= "foo=bar?baz"
460   ,.fragment= ""
461   ,.request_path= "/test.cgi"
462   ,.request_url= "/test.cgi?foo=bar?baz"
463   ,.num_headers= 0
464   ,.headers= {}
465   ,.body= ""
466   }
467
468 #define PREFIX_NEWLINE_GET 15
469 /* Some clients, especially after a POST in a keep-alive connection,
470  * will send an extra CRLF before the next request
471  */
472 , {.name = "newline prefix get"
473   ,.type= HTTP_REQUEST
474   ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n"
475   ,.should_keep_alive= TRUE
476   ,.message_complete_on_eof= FALSE
477   ,.http_major= 1
478   ,.http_minor= 1
479   ,.method= HTTP_GET
480   ,.query_string= ""
481   ,.fragment= ""
482   ,.request_path= "/test"
483   ,.request_url= "/test"
484   ,.num_headers= 0
485   ,.headers= { }
486   ,.body= ""
487   }
488
489 #define UPGRADE_REQUEST 16
490 , {.name = "upgrade request"
491   ,.type= HTTP_REQUEST
492   ,.raw= "GET /demo HTTP/1.1\r\n"
493          "Host: example.com\r\n"
494          "Connection: Upgrade\r\n"
495          "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
496          "Sec-WebSocket-Protocol: sample\r\n"
497          "Upgrade: WebSocket\r\n"
498          "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
499          "Origin: http://example.com\r\n"
500          "\r\n"
501          "Hot diggity dogg"
502   ,.should_keep_alive= TRUE
503   ,.message_complete_on_eof= FALSE
504   ,.http_major= 1
505   ,.http_minor= 1
506   ,.method= HTTP_GET
507   ,.query_string= ""
508   ,.fragment= ""
509   ,.request_path= "/demo"
510   ,.request_url= "/demo"
511   ,.num_headers= 7
512   ,.upgrade="Hot diggity dogg"
513   ,.headers= { { "Host", "example.com" }
514              , { "Connection", "Upgrade" }
515              , { "Sec-WebSocket-Key2", "12998 5 Y3 1  .P00" }
516              , { "Sec-WebSocket-Protocol", "sample" }
517              , { "Upgrade", "WebSocket" }
518              , { "Sec-WebSocket-Key1", "4 @1  46546xW%0l 1 5" }
519              , { "Origin", "http://example.com" }
520              }
521   ,.body= ""
522   }
523
524 #define CONNECT_REQUEST 17
525 , {.name = "connect request"
526   ,.type= HTTP_REQUEST
527   ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
528          "User-agent: Mozilla/1.1N\r\n"
529          "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
530          "\r\n"
531          "some data\r\n"
532          "and yet even more data"
533   ,.should_keep_alive= FALSE
534   ,.message_complete_on_eof= FALSE
535   ,.http_major= 1
536   ,.http_minor= 0
537   ,.method= HTTP_CONNECT
538   ,.query_string= ""
539   ,.fragment= ""
540   ,.request_path= ""
541   ,.request_url= "0-home0.netscape.com:443"
542   ,.num_headers= 2
543   ,.upgrade="some data\r\nand yet even more data"
544   ,.headers= { { "User-agent", "Mozilla/1.1N" }
545              , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
546              }
547   ,.body= ""
548   }
549
550 #define REPORT_REQ 18
551 , {.name= "report request"
552   ,.type= HTTP_REQUEST
553   ,.raw= "REPORT /test HTTP/1.1\r\n"
554          "\r\n"
555   ,.should_keep_alive= TRUE
556   ,.message_complete_on_eof= FALSE
557   ,.http_major= 1
558   ,.http_minor= 1
559   ,.method= HTTP_REPORT
560   ,.query_string= ""
561   ,.fragment= ""
562   ,.request_path= "/test"
563   ,.request_url= "/test"
564   ,.num_headers= 0
565   ,.headers= {}
566   ,.body= ""
567   }
568
569 #define NO_HTTP_VERSION 19
570 , {.name= "request with no http version"
571   ,.type= HTTP_REQUEST
572   ,.raw= "GET /\r\n"
573          "\r\n"
574   ,.should_keep_alive= FALSE
575   ,.message_complete_on_eof= FALSE
576   ,.http_major= 0
577   ,.http_minor= 9
578   ,.method= HTTP_GET
579   ,.query_string= ""
580   ,.fragment= ""
581   ,.request_path= "/"
582   ,.request_url= "/"
583   ,.num_headers= 0
584   ,.headers= {}
585   ,.body= ""
586   }
587
588 #define MSEARCH_REQ 20
589 , {.name= "m-search request"
590   ,.type= HTTP_REQUEST
591   ,.raw= "M-SEARCH * HTTP/1.1\r\n"
592          "HOST: 239.255.255.250:1900\r\n"
593          "MAN: \"ssdp:discover\"\r\n"
594          "ST: \"ssdp:all\"\r\n"
595          "\r\n"
596   ,.should_keep_alive= TRUE
597   ,.message_complete_on_eof= FALSE
598   ,.http_major= 1
599   ,.http_minor= 1
600   ,.method= HTTP_MSEARCH
601   ,.query_string= ""
602   ,.fragment= ""
603   ,.request_path= "*"
604   ,.request_url= "*"
605   ,.num_headers= 3
606   ,.headers= { { "HOST", "239.255.255.250:1900" }
607              , { "MAN", "\"ssdp:discover\"" }
608              , { "ST", "\"ssdp:all\"" }
609              }
610   ,.body= ""
611   }
612
613 #define LINE_FOLDING_IN_HEADER 21
614 , {.name= "line folding in header value"
615   ,.type= HTTP_REQUEST
616   ,.raw= "GET / HTTP/1.1\r\n"
617          "Line1:   abc\r\n"
618          "\tdef\r\n"
619          " ghi\r\n"
620          "\t\tjkl\r\n"
621          "  mno \r\n"
622          "\t \tqrs\r\n"
623          "Line2: \t line2\t\r\n"
624          "Line3:\r\n"
625          " line3\r\n"
626          "Line4: \r\n"
627          " \r\n"
628          "Connection:\r\n"
629          " close\r\n"
630          "\r\n"
631   ,.should_keep_alive= FALSE
632   ,.message_complete_on_eof= FALSE
633   ,.http_major= 1
634   ,.http_minor= 1
635   ,.method= HTTP_GET
636   ,.query_string= ""
637   ,.fragment= ""
638   ,.request_path= "/"
639   ,.request_url= "/"
640   ,.num_headers= 5
641   ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl  mno \t \tqrs" }
642              , { "Line2", "line2\t" }
643              , { "Line3", "line3" }
644              , { "Line4", "" }
645              , { "Connection", "close" },
646              }
647   ,.body= ""
648   }
649
650
651 #define QUERY_TERMINATED_HOST 22
652 , {.name= "host terminated by a query string"
653   ,.type= HTTP_REQUEST
654   ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
655          "\r\n"
656   ,.should_keep_alive= TRUE
657   ,.message_complete_on_eof= FALSE
658   ,.http_major= 1
659   ,.http_minor= 1
660   ,.method= HTTP_GET
661   ,.query_string= "hail=all"
662   ,.fragment= ""
663   ,.request_path= ""
664   ,.request_url= "http://hypnotoad.org?hail=all"
665   ,.host= "hypnotoad.org"
666   ,.num_headers= 0
667   ,.headers= { }
668   ,.body= ""
669   }
670
671 #define QUERY_TERMINATED_HOSTPORT 23
672 , {.name= "host:port terminated by a query string"
673   ,.type= HTTP_REQUEST
674   ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
675          "\r\n"
676   ,.should_keep_alive= TRUE
677   ,.message_complete_on_eof= FALSE
678   ,.http_major= 1
679   ,.http_minor= 1
680   ,.method= HTTP_GET
681   ,.query_string= "hail=all"
682   ,.fragment= ""
683   ,.request_path= ""
684   ,.request_url= "http://hypnotoad.org:1234?hail=all"
685   ,.host= "hypnotoad.org"
686   ,.port= 1234
687   ,.num_headers= 0
688   ,.headers= { }
689   ,.body= ""
690   }
691
692 #define SPACE_TERMINATED_HOSTPORT 24
693 , {.name= "host:port terminated by a space"
694   ,.type= HTTP_REQUEST
695   ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
696          "\r\n"
697   ,.should_keep_alive= TRUE
698   ,.message_complete_on_eof= FALSE
699   ,.http_major= 1
700   ,.http_minor= 1
701   ,.method= HTTP_GET
702   ,.query_string= ""
703   ,.fragment= ""
704   ,.request_path= ""
705   ,.request_url= "http://hypnotoad.org:1234"
706   ,.host= "hypnotoad.org"
707   ,.port= 1234
708   ,.num_headers= 0
709   ,.headers= { }
710   ,.body= ""
711   }
712
713 #define PATCH_REQ 25
714 , {.name = "PATCH request"
715   ,.type= HTTP_REQUEST
716   ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
717          "Host: www.example.com\r\n"
718          "Content-Type: application/example\r\n"
719          "If-Match: \"e0023aa4e\"\r\n"
720          "Content-Length: 10\r\n"
721          "\r\n"
722          "cccccccccc"
723   ,.should_keep_alive= TRUE
724   ,.message_complete_on_eof= FALSE
725   ,.http_major= 1
726   ,.http_minor= 1
727   ,.method= HTTP_PATCH
728   ,.query_string= ""
729   ,.fragment= ""
730   ,.request_path= "/file.txt"
731   ,.request_url= "/file.txt"
732   ,.num_headers= 4
733   ,.headers= { { "Host", "www.example.com" }
734              , { "Content-Type", "application/example" }
735              , { "If-Match", "\"e0023aa4e\"" }
736              , { "Content-Length", "10" }
737              }
738   ,.body= "cccccccccc"
739   }
740
741 #define CONNECT_CAPS_REQUEST 26
742 , {.name = "connect caps request"
743   ,.type= HTTP_REQUEST
744   ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
745          "User-agent: Mozilla/1.1N\r\n"
746          "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
747          "\r\n"
748   ,.should_keep_alive= FALSE
749   ,.message_complete_on_eof= FALSE
750   ,.http_major= 1
751   ,.http_minor= 0
752   ,.method= HTTP_CONNECT
753   ,.query_string= ""
754   ,.fragment= ""
755   ,.request_path= ""
756   ,.request_url= "HOME0.NETSCAPE.COM:443"
757   ,.num_headers= 2
758   ,.upgrade=""
759   ,.headers= { { "User-agent", "Mozilla/1.1N" }
760              , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
761              }
762   ,.body= ""
763   }
764
765 #if !HTTP_PARSER_STRICT
766 #define UTF8_PATH_REQ 27
767 , {.name= "utf-8 path request"
768   ,.type= HTTP_REQUEST
769   ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
770          "Host: github.com\r\n"
771          "\r\n"
772   ,.should_keep_alive= TRUE
773   ,.message_complete_on_eof= FALSE
774   ,.http_major= 1
775   ,.http_minor= 1
776   ,.method= HTTP_GET
777   ,.query_string= "q=1"
778   ,.fragment= "narf"
779   ,.request_path= "/δ¶/δt/pope"
780   ,.request_url= "/δ¶/δt/pope?q=1#narf"
781   ,.num_headers= 1
782   ,.headers= { {"Host", "github.com" }
783              }
784   ,.body= ""
785   }
786
787 #define HOSTNAME_UNDERSCORE 28
788 , {.name = "hostname underscore"
789   ,.type= HTTP_REQUEST
790   ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
791          "User-agent: Mozilla/1.1N\r\n"
792          "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
793          "\r\n"
794   ,.should_keep_alive= FALSE
795   ,.message_complete_on_eof= FALSE
796   ,.http_major= 1
797   ,.http_minor= 0
798   ,.method= HTTP_CONNECT
799   ,.query_string= ""
800   ,.fragment= ""
801   ,.request_path= ""
802   ,.request_url= "home_0.netscape.com:443"
803   ,.num_headers= 2
804   ,.upgrade=""
805   ,.headers= { { "User-agent", "Mozilla/1.1N" }
806              , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
807              }
808   ,.body= ""
809   }
810 #endif  /* !HTTP_PARSER_STRICT */
811
812 /* see https://github.com/ry/http-parser/issues/47 */
813 #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
814 , {.name = "eat CRLF between requests, no \"Connection: close\" header"
815   ,.raw= "POST / HTTP/1.1\r\n"
816          "Host: www.example.com\r\n"
817          "Content-Type: application/x-www-form-urlencoded\r\n"
818          "Content-Length: 4\r\n"
819          "\r\n"
820          "q=42\r\n" /* note the trailing CRLF */
821   ,.should_keep_alive= TRUE
822   ,.message_complete_on_eof= FALSE
823   ,.http_major= 1
824   ,.http_minor= 1
825   ,.method= HTTP_POST
826   ,.query_string= ""
827   ,.fragment= ""
828   ,.request_path= "/"
829   ,.request_url= "/"
830   ,.num_headers= 3
831   ,.upgrade= 0
832   ,.headers= { { "Host", "www.example.com" }
833              , { "Content-Type", "application/x-www-form-urlencoded" }
834              , { "Content-Length", "4" }
835              }
836   ,.body= "q=42"
837   }
838
839 /* see https://github.com/ry/http-parser/issues/47 */
840 #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
841 , {.name = "eat CRLF between requests even if \"Connection: close\" is set"
842   ,.raw= "POST / HTTP/1.1\r\n"
843          "Host: www.example.com\r\n"
844          "Content-Type: application/x-www-form-urlencoded\r\n"
845          "Content-Length: 4\r\n"
846          "Connection: close\r\n"
847          "\r\n"
848          "q=42\r\n" /* note the trailing CRLF */
849   ,.should_keep_alive= FALSE
850   ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
851   ,.http_major= 1
852   ,.http_minor= 1
853   ,.method= HTTP_POST
854   ,.query_string= ""
855   ,.fragment= ""
856   ,.request_path= "/"
857   ,.request_url= "/"
858   ,.num_headers= 4
859   ,.upgrade= 0
860   ,.headers= { { "Host", "www.example.com" }
861              , { "Content-Type", "application/x-www-form-urlencoded" }
862              , { "Content-Length", "4" }
863              , { "Connection", "close" }
864              }
865   ,.body= "q=42"
866   }
867
868 #define PURGE_REQ 31
869 , {.name = "PURGE request"
870   ,.type= HTTP_REQUEST
871   ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
872          "Host: www.example.com\r\n"
873          "\r\n"
874   ,.should_keep_alive= TRUE
875   ,.message_complete_on_eof= FALSE
876   ,.http_major= 1
877   ,.http_minor= 1
878   ,.method= HTTP_PURGE
879   ,.query_string= ""
880   ,.fragment= ""
881   ,.request_path= "/file.txt"
882   ,.request_url= "/file.txt"
883   ,.num_headers= 1
884   ,.headers= { { "Host", "www.example.com" } }
885   ,.body= ""
886   }
887
888 #define SEARCH_REQ 32
889 , {.name = "SEARCH request"
890   ,.type= HTTP_REQUEST
891   ,.raw= "SEARCH / HTTP/1.1\r\n"
892          "Host: www.example.com\r\n"
893          "\r\n"
894   ,.should_keep_alive= TRUE
895   ,.message_complete_on_eof= FALSE
896   ,.http_major= 1
897   ,.http_minor= 1
898   ,.method= HTTP_SEARCH
899   ,.query_string= ""
900   ,.fragment= ""
901   ,.request_path= "/"
902   ,.request_url= "/"
903   ,.num_headers= 1
904   ,.headers= { { "Host", "www.example.com" } }
905   ,.body= ""
906   }
907
908 #define PROXY_WITH_BASIC_AUTH 33
909 , {.name= "host:port and basic_auth"
910   ,.type= HTTP_REQUEST
911   ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
912          "\r\n"
913   ,.should_keep_alive= TRUE
914   ,.message_complete_on_eof= FALSE
915   ,.http_major= 1
916   ,.http_minor= 1
917   ,.method= HTTP_GET
918   ,.fragment= ""
919   ,.request_path= "/toto"
920   ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
921   ,.host= "hypnotoad.org"
922   ,.userinfo= "a%12:b!&*$"
923   ,.port= 1234
924   ,.num_headers= 0
925   ,.headers= { }
926   ,.body= ""
927   }
928
929 #define LINE_FOLDING_IN_HEADER_WITH_LF 34
930 , {.name= "line folding in header value"
931   ,.type= HTTP_REQUEST
932   ,.raw= "GET / HTTP/1.1\n"
933          "Line1:   abc\n"
934          "\tdef\n"
935          " ghi\n"
936          "\t\tjkl\n"
937          "  mno \n"
938          "\t \tqrs\n"
939          "Line2: \t line2\t\n"
940          "Line3:\n"
941          " line3\n"
942          "Line4: \n"
943          " \n"
944          "Connection:\n"
945          " close\n"
946          "\n"
947   ,.should_keep_alive= FALSE
948   ,.message_complete_on_eof= FALSE
949   ,.http_major= 1
950   ,.http_minor= 1
951   ,.method= HTTP_GET
952   ,.query_string= ""
953   ,.fragment= ""
954   ,.request_path= "/"
955   ,.request_url= "/"
956   ,.num_headers= 5
957   ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl  mno \t \tqrs" }
958              , { "Line2", "line2\t" }
959              , { "Line3", "line3" }
960              , { "Line4", "" }
961              , { "Connection", "close" },
962              }
963   ,.body= ""
964   }
965
966 #define CONNECTION_MULTI 35
967 , {.name = "multiple connection header values with folding"
968   ,.type= HTTP_REQUEST
969   ,.raw= "GET /demo HTTP/1.1\r\n"
970          "Host: example.com\r\n"
971          "Connection: Something,\r\n"
972          " Upgrade, ,Keep-Alive\r\n"
973          "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
974          "Sec-WebSocket-Protocol: sample\r\n"
975          "Upgrade: WebSocket\r\n"
976          "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
977          "Origin: http://example.com\r\n"
978          "\r\n"
979          "Hot diggity dogg"
980   ,.should_keep_alive= TRUE
981   ,.message_complete_on_eof= FALSE
982   ,.http_major= 1
983   ,.http_minor= 1
984   ,.method= HTTP_GET
985   ,.query_string= ""
986   ,.fragment= ""
987   ,.request_path= "/demo"
988   ,.request_url= "/demo"
989   ,.num_headers= 7
990   ,.upgrade="Hot diggity dogg"
991   ,.headers= { { "Host", "example.com" }
992              , { "Connection", "Something, Upgrade, ,Keep-Alive" }
993              , { "Sec-WebSocket-Key2", "12998 5 Y3 1  .P00" }
994              , { "Sec-WebSocket-Protocol", "sample" }
995              , { "Upgrade", "WebSocket" }
996              , { "Sec-WebSocket-Key1", "4 @1  46546xW%0l 1 5" }
997              , { "Origin", "http://example.com" }
998              }
999   ,.body= ""
1000   }
1001
1002 #define CONNECTION_MULTI_LWS 36
1003 , {.name = "multiple connection header values with folding and lws"
1004   ,.type= HTTP_REQUEST
1005   ,.raw= "GET /demo HTTP/1.1\r\n"
1006          "Connection: keep-alive, upgrade\r\n"
1007          "Upgrade: WebSocket\r\n"
1008          "\r\n"
1009          "Hot diggity dogg"
1010   ,.should_keep_alive= TRUE
1011   ,.message_complete_on_eof= FALSE
1012   ,.http_major= 1
1013   ,.http_minor= 1
1014   ,.method= HTTP_GET
1015   ,.query_string= ""
1016   ,.fragment= ""
1017   ,.request_path= "/demo"
1018   ,.request_url= "/demo"
1019   ,.num_headers= 2
1020   ,.upgrade="Hot diggity dogg"
1021   ,.headers= { { "Connection", "keep-alive, upgrade" }
1022              , { "Upgrade", "WebSocket" }
1023              }
1024   ,.body= ""
1025   }
1026
1027 #define CONNECTION_MULTI_LWS_CRLF 37
1028 , {.name = "multiple connection header values with folding and lws"
1029   ,.type= HTTP_REQUEST
1030   ,.raw= "GET /demo HTTP/1.1\r\n"
1031          "Connection: keep-alive, \r\n upgrade\r\n"
1032          "Upgrade: WebSocket\r\n"
1033          "\r\n"
1034          "Hot diggity dogg"
1035   ,.should_keep_alive= TRUE
1036   ,.message_complete_on_eof= FALSE
1037   ,.http_major= 1
1038   ,.http_minor= 1
1039   ,.method= HTTP_GET
1040   ,.query_string= ""
1041   ,.fragment= ""
1042   ,.request_path= "/demo"
1043   ,.request_url= "/demo"
1044   ,.num_headers= 2
1045   ,.upgrade="Hot diggity dogg"
1046   ,.headers= { { "Connection", "keep-alive,  upgrade" }
1047              , { "Upgrade", "WebSocket" }
1048              }
1049   ,.body= ""
1050   }
1051
1052 #define UPGRADE_POST_REQUEST 38
1053 , {.name = "upgrade post request"
1054   ,.type= HTTP_REQUEST
1055   ,.raw= "POST /demo HTTP/1.1\r\n"
1056          "Host: example.com\r\n"
1057          "Connection: Upgrade\r\n"
1058          "Upgrade: HTTP/2.0\r\n"
1059          "Content-Length: 15\r\n"
1060          "\r\n"
1061          "sweet post body"
1062          "Hot diggity dogg"
1063   ,.should_keep_alive= TRUE
1064   ,.message_complete_on_eof= FALSE
1065   ,.http_major= 1
1066   ,.http_minor= 1
1067   ,.method= HTTP_POST
1068   ,.request_path= "/demo"
1069   ,.request_url= "/demo"
1070   ,.num_headers= 4
1071   ,.upgrade="Hot diggity dogg"
1072   ,.headers= { { "Host", "example.com" }
1073              , { "Connection", "Upgrade" }
1074              , { "Upgrade", "HTTP/2.0" }
1075              , { "Content-Length", "15" }
1076              }
1077   ,.body= "sweet post body"
1078   }
1079
1080 #define CONNECT_WITH_BODY_REQUEST 39
1081 , {.name = "connect with body request"
1082   ,.type= HTTP_REQUEST
1083   ,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
1084          "User-agent: Mozilla/1.1N\r\n"
1085          "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
1086          "Content-Length: 10\r\n"
1087          "\r\n"
1088          "blarfcicle"
1089   ,.should_keep_alive= FALSE
1090   ,.message_complete_on_eof= FALSE
1091   ,.http_major= 1
1092   ,.http_minor= 0
1093   ,.method= HTTP_CONNECT
1094   ,.request_url= "foo.bar.com:443"
1095   ,.num_headers= 3
1096   ,.upgrade="blarfcicle"
1097   ,.headers= { { "User-agent", "Mozilla/1.1N" }
1098              , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
1099              , { "Content-Length", "10" }
1100              }
1101   ,.body= ""
1102   }
1103
1104 , {.name= NULL } /* sentinel */
1105 };
1106
1107 /* * R E S P O N S E S * */
1108 const struct message responses[] =
1109 #define GOOGLE_301 0
1110 { {.name= "google 301"
1111   ,.type= HTTP_RESPONSE
1112   ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
1113          "Location: http://www.google.com/\r\n"
1114          "Content-Type: text/html; charset=UTF-8\r\n"
1115          "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
1116          "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
1117          "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
1118          "Cache-Control: public, max-age=2592000\r\n"
1119          "Server: gws\r\n"
1120          "Content-Length:  219  \r\n"
1121          "\r\n"
1122          "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
1123          "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
1124          "<H1>301 Moved</H1>\n"
1125          "The document has moved\n"
1126          "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
1127          "</BODY></HTML>\r\n"
1128   ,.should_keep_alive= TRUE
1129   ,.message_complete_on_eof= FALSE
1130   ,.http_major= 1
1131   ,.http_minor= 1
1132   ,.status_code= 301
1133   ,.response_status= "Moved Permanently"
1134   ,.num_headers= 8
1135   ,.headers=
1136     { { "Location", "http://www.google.com/" }
1137     , { "Content-Type", "text/html; charset=UTF-8" }
1138     , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
1139     , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
1140     , { "X-$PrototypeBI-Version", "1.6.0.3" }
1141     , { "Cache-Control", "public, max-age=2592000" }
1142     , { "Server", "gws" }
1143     , { "Content-Length", "219  " }
1144     }
1145   ,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
1146           "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
1147           "<H1>301 Moved</H1>\n"
1148           "The document has moved\n"
1149           "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
1150           "</BODY></HTML>\r\n"
1151   }
1152
1153 #define NO_CONTENT_LENGTH_RESPONSE 1
1154 /* The client should wait for the server's EOF. That is, when content-length
1155  * is not specified, and "Connection: close", the end of body is specified
1156  * by the EOF.
1157  * Compare with APACHEBENCH_GET
1158  */
1159 , {.name= "no content-length response"
1160   ,.type= HTTP_RESPONSE
1161   ,.raw= "HTTP/1.1 200 OK\r\n"
1162          "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
1163          "Server: Apache\r\n"
1164          "X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
1165          "Content-Type: text/xml; charset=utf-8\r\n"
1166          "Connection: close\r\n"
1167          "\r\n"
1168          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1169          "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
1170          "  <SOAP-ENV:Body>\n"
1171          "    <SOAP-ENV:Fault>\n"
1172          "       <faultcode>SOAP-ENV:Client</faultcode>\n"
1173          "       <faultstring>Client Error</faultstring>\n"
1174          "    </SOAP-ENV:Fault>\n"
1175          "  </SOAP-ENV:Body>\n"
1176          "</SOAP-ENV:Envelope>"
1177   ,.should_keep_alive= FALSE
1178   ,.message_complete_on_eof= TRUE
1179   ,.http_major= 1
1180   ,.http_minor= 1
1181   ,.status_code= 200
1182   ,.response_status= "OK"
1183   ,.num_headers= 5
1184   ,.headers=
1185     { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
1186     , { "Server", "Apache" }
1187     , { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
1188     , { "Content-Type", "text/xml; charset=utf-8" }
1189     , { "Connection", "close" }
1190     }
1191   ,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1192           "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
1193           "  <SOAP-ENV:Body>\n"
1194           "    <SOAP-ENV:Fault>\n"
1195           "       <faultcode>SOAP-ENV:Client</faultcode>\n"
1196           "       <faultstring>Client Error</faultstring>\n"
1197           "    </SOAP-ENV:Fault>\n"
1198           "  </SOAP-ENV:Body>\n"
1199           "</SOAP-ENV:Envelope>"
1200   }
1201
1202 #define NO_HEADERS_NO_BODY_404 2
1203 , {.name= "404 no headers no body"
1204   ,.type= HTTP_RESPONSE
1205   ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
1206   ,.should_keep_alive= FALSE
1207   ,.message_complete_on_eof= TRUE
1208   ,.http_major= 1
1209   ,.http_minor= 1
1210   ,.status_code= 404
1211   ,.response_status= "Not Found"
1212   ,.num_headers= 0
1213   ,.headers= {}
1214   ,.body_size= 0
1215   ,.body= ""
1216   }
1217
1218 #define NO_REASON_PHRASE 3
1219 , {.name= "301 no response phrase"
1220   ,.type= HTTP_RESPONSE
1221   ,.raw= "HTTP/1.1 301\r\n\r\n"
1222   ,.should_keep_alive = FALSE
1223   ,.message_complete_on_eof= TRUE
1224   ,.http_major= 1
1225   ,.http_minor= 1
1226   ,.status_code= 301
1227   ,.response_status= ""
1228   ,.num_headers= 0
1229   ,.headers= {}
1230   ,.body= ""
1231   }
1232
1233 #define TRAILING_SPACE_ON_CHUNKED_BODY 4
1234 , {.name="200 trailing space on chunked body"
1235   ,.type= HTTP_RESPONSE
1236   ,.raw= "HTTP/1.1 200 OK\r\n"
1237          "Content-Type: text/plain\r\n"
1238          "Transfer-Encoding: chunked\r\n"
1239          "\r\n"
1240          "25  \r\n"
1241          "This is the data in the first chunk\r\n"
1242          "\r\n"
1243          "1C\r\n"
1244          "and this is the second one\r\n"
1245          "\r\n"
1246          "0  \r\n"
1247          "\r\n"
1248   ,.should_keep_alive= TRUE
1249   ,.message_complete_on_eof= FALSE
1250   ,.http_major= 1
1251   ,.http_minor= 1
1252   ,.status_code= 200
1253   ,.response_status= "OK"
1254   ,.num_headers= 2
1255   ,.headers=
1256     { {"Content-Type", "text/plain" }
1257     , {"Transfer-Encoding", "chunked" }
1258     }
1259   ,.body_size = 37+28
1260   ,.body =
1261          "This is the data in the first chunk\r\n"
1262          "and this is the second one\r\n"
1263   ,.num_chunks_complete= 3
1264   ,.chunk_lengths= { 0x25, 0x1c }
1265   }
1266
1267 #define NO_CARRIAGE_RET 5
1268 , {.name="no carriage ret"
1269   ,.type= HTTP_RESPONSE
1270   ,.raw= "HTTP/1.1 200 OK\n"
1271          "Content-Type: text/html; charset=utf-8\n"
1272          "Connection: close\n"
1273          "\n"
1274          "these headers are from http://news.ycombinator.com/"
1275   ,.should_keep_alive= FALSE
1276   ,.message_complete_on_eof= TRUE
1277   ,.http_major= 1
1278   ,.http_minor= 1
1279   ,.status_code= 200
1280   ,.response_status= "OK"
1281   ,.num_headers= 2
1282   ,.headers=
1283     { {"Content-Type", "text/html; charset=utf-8" }
1284     , {"Connection", "close" }
1285     }
1286   ,.body= "these headers are from http://news.ycombinator.com/"
1287   }
1288
1289 #define PROXY_CONNECTION 6
1290 , {.name="proxy connection"
1291   ,.type= HTTP_RESPONSE
1292   ,.raw= "HTTP/1.1 200 OK\r\n"
1293          "Content-Type: text/html; charset=UTF-8\r\n"
1294          "Content-Length: 11\r\n"
1295          "Proxy-Connection: close\r\n"
1296          "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
1297          "\r\n"
1298          "hello world"
1299   ,.should_keep_alive= FALSE
1300   ,.message_complete_on_eof= FALSE
1301   ,.http_major= 1
1302   ,.http_minor= 1
1303   ,.status_code= 200
1304   ,.response_status= "OK"
1305   ,.num_headers= 4
1306   ,.headers=
1307     { {"Content-Type", "text/html; charset=UTF-8" }
1308     , {"Content-Length", "11" }
1309     , {"Proxy-Connection", "close" }
1310     , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
1311     }
1312   ,.body= "hello world"
1313   }
1314
1315 #define UNDERSTORE_HEADER_KEY 7
1316   // shown by
1317   // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;"
1318 , {.name="underscore header key"
1319   ,.type= HTTP_RESPONSE
1320   ,.raw= "HTTP/1.1 200 OK\r\n"
1321          "Server: DCLK-AdSvr\r\n"
1322          "Content-Type: text/xml\r\n"
1323          "Content-Length: 0\r\n"
1324          "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
1325   ,.should_keep_alive= TRUE
1326   ,.message_complete_on_eof= FALSE
1327   ,.http_major= 1
1328   ,.http_minor= 1
1329   ,.status_code= 200
1330   ,.response_status= "OK"
1331   ,.num_headers= 4
1332   ,.headers=
1333     { {"Server", "DCLK-AdSvr" }
1334     , {"Content-Type", "text/xml" }
1335     , {"Content-Length", "0" }
1336     , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" }
1337     }
1338   ,.body= ""
1339   }
1340
1341 #define BONJOUR_MADAME_FR 8
1342 /* The client should not merge two headers fields when the first one doesn't
1343  * have a value.
1344  */
1345 , {.name= "bonjourmadame.fr"
1346   ,.type= HTTP_RESPONSE
1347   ,.raw= "HTTP/1.0 301 Moved Permanently\r\n"
1348          "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n"
1349          "Server: Apache/2.2.3 (Red Hat)\r\n"
1350          "Cache-Control: public\r\n"
1351          "Pragma: \r\n"
1352          "Location: http://www.bonjourmadame.fr/\r\n"
1353          "Vary: Accept-Encoding\r\n"
1354          "Content-Length: 0\r\n"
1355          "Content-Type: text/html; charset=UTF-8\r\n"
1356          "Connection: keep-alive\r\n"
1357          "\r\n"
1358   ,.should_keep_alive= TRUE
1359   ,.message_complete_on_eof= FALSE
1360   ,.http_major= 1
1361   ,.http_minor= 0
1362   ,.status_code= 301
1363   ,.response_status= "Moved Permanently"
1364   ,.num_headers= 9
1365   ,.headers=
1366     { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
1367     , { "Server", "Apache/2.2.3 (Red Hat)" }
1368     , { "Cache-Control", "public" }
1369     , { "Pragma", "" }
1370     , { "Location", "http://www.bonjourmadame.fr/" }
1371     , { "Vary",  "Accept-Encoding" }
1372     , { "Content-Length", "0" }
1373     , { "Content-Type", "text/html; charset=UTF-8" }
1374     , { "Connection", "keep-alive" }
1375     }
1376   ,.body= ""
1377   }
1378
1379 #define RES_FIELD_UNDERSCORE 9
1380 /* Should handle spaces in header fields */
1381 , {.name= "field underscore"
1382   ,.type= HTTP_RESPONSE
1383   ,.raw= "HTTP/1.1 200 OK\r\n"
1384          "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
1385          "Server: Apache\r\n"
1386          "Cache-Control: no-cache, must-revalidate\r\n"
1387          "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
1388          ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
1389          "Vary: Accept-Encoding\r\n"
1390          "_eep-Alive: timeout=45\r\n" /* semantic value ignored */
1391          "_onnection: Keep-Alive\r\n" /* semantic value ignored */
1392          "Transfer-Encoding: chunked\r\n"
1393          "Content-Type: text/html\r\n"
1394          "Connection: close\r\n"
1395          "\r\n"
1396          "0\r\n\r\n"
1397   ,.should_keep_alive= FALSE
1398   ,.message_complete_on_eof= FALSE
1399   ,.http_major= 1
1400   ,.http_minor= 1
1401   ,.status_code= 200
1402   ,.response_status= "OK"
1403   ,.num_headers= 11
1404   ,.headers=
1405     { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
1406     , { "Server", "Apache" }
1407     , { "Cache-Control", "no-cache, must-revalidate" }
1408     , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
1409     , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
1410     , { "Vary", "Accept-Encoding" }
1411     , { "_eep-Alive", "timeout=45" }
1412     , { "_onnection", "Keep-Alive" }
1413     , { "Transfer-Encoding", "chunked" }
1414     , { "Content-Type", "text/html" }
1415     , { "Connection", "close" }
1416     }
1417   ,.body= ""
1418   ,.num_chunks_complete= 1
1419   ,.chunk_lengths= {}
1420   }
1421
1422 #define NON_ASCII_IN_STATUS_LINE 10
1423 /* Should handle non-ASCII in status line */
1424 , {.name= "non-ASCII in status line"
1425   ,.type= HTTP_RESPONSE
1426   ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
1427          "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
1428          "Content-Length: 0\r\n"
1429          "Connection: close\r\n"
1430          "\r\n"
1431   ,.should_keep_alive= FALSE
1432   ,.message_complete_on_eof= FALSE
1433   ,.http_major= 1
1434   ,.http_minor= 1
1435   ,.status_code= 500
1436   ,.response_status= "Oriëntatieprobleem"
1437   ,.num_headers= 3
1438   ,.headers=
1439     { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
1440     , { "Content-Length", "0" }
1441     , { "Connection", "close" }
1442     }
1443   ,.body= ""
1444   }
1445
1446 #define HTTP_VERSION_0_9 11
1447 /* Should handle HTTP/0.9 */
1448 , {.name= "http version 0.9"
1449   ,.type= HTTP_RESPONSE
1450   ,.raw= "HTTP/0.9 200 OK\r\n"
1451          "\r\n"
1452   ,.should_keep_alive= FALSE
1453   ,.message_complete_on_eof= TRUE
1454   ,.http_major= 0
1455   ,.http_minor= 9
1456   ,.status_code= 200
1457   ,.response_status= "OK"
1458   ,.num_headers= 0
1459   ,.headers=
1460     {}
1461   ,.body= ""
1462   }
1463
1464 #define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
1465 /* The client should wait for the server's EOF. That is, when neither
1466  * content-length nor transfer-encoding is specified, the end of body
1467  * is specified by the EOF.
1468  */
1469 , {.name= "neither content-length nor transfer-encoding response"
1470   ,.type= HTTP_RESPONSE
1471   ,.raw= "HTTP/1.1 200 OK\r\n"
1472          "Content-Type: text/plain\r\n"
1473          "\r\n"
1474          "hello world"
1475   ,.should_keep_alive= FALSE
1476   ,.message_complete_on_eof= TRUE
1477   ,.http_major= 1
1478   ,.http_minor= 1
1479   ,.status_code= 200
1480   ,.response_status= "OK"
1481   ,.num_headers= 1
1482   ,.headers=
1483     { { "Content-Type", "text/plain" }
1484     }
1485   ,.body= "hello world"
1486   }
1487
1488 #define NO_BODY_HTTP10_KA_200 13
1489 , {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
1490   ,.type= HTTP_RESPONSE
1491   ,.raw= "HTTP/1.0 200 OK\r\n"
1492          "Connection: keep-alive\r\n"
1493          "\r\n"
1494   ,.should_keep_alive= FALSE
1495   ,.message_complete_on_eof= TRUE
1496   ,.http_major= 1
1497   ,.http_minor= 0
1498   ,.status_code= 200
1499   ,.response_status= "OK"
1500   ,.num_headers= 1
1501   ,.headers=
1502     { { "Connection", "keep-alive" }
1503     }
1504   ,.body_size= 0
1505   ,.body= ""
1506   }
1507
1508 #define NO_BODY_HTTP10_KA_204 14
1509 , {.name= "HTTP/1.0 with keep-alive and a 204 status"
1510   ,.type= HTTP_RESPONSE
1511   ,.raw= "HTTP/1.0 204 No content\r\n"
1512          "Connection: keep-alive\r\n"
1513          "\r\n"
1514   ,.should_keep_alive= TRUE
1515   ,.message_complete_on_eof= FALSE
1516   ,.http_major= 1
1517   ,.http_minor= 0
1518   ,.status_code= 204
1519   ,.response_status= "No content"
1520   ,.num_headers= 1
1521   ,.headers=
1522     { { "Connection", "keep-alive" }
1523     }
1524   ,.body_size= 0
1525   ,.body= ""
1526   }
1527
1528 #define NO_BODY_HTTP11_KA_200 15
1529 , {.name= "HTTP/1.1 with an EOF-terminated 200 status"
1530   ,.type= HTTP_RESPONSE
1531   ,.raw= "HTTP/1.1 200 OK\r\n"
1532          "\r\n"
1533   ,.should_keep_alive= FALSE
1534   ,.message_complete_on_eof= TRUE
1535   ,.http_major= 1
1536   ,.http_minor= 1
1537   ,.status_code= 200
1538   ,.response_status= "OK"
1539   ,.num_headers= 0
1540   ,.headers={}
1541   ,.body_size= 0
1542   ,.body= ""
1543   }
1544
1545 #define NO_BODY_HTTP11_KA_204 16
1546 , {.name= "HTTP/1.1 with a 204 status"
1547   ,.type= HTTP_RESPONSE
1548   ,.raw= "HTTP/1.1 204 No content\r\n"
1549          "\r\n"
1550   ,.should_keep_alive= TRUE
1551   ,.message_complete_on_eof= FALSE
1552   ,.http_major= 1
1553   ,.http_minor= 1
1554   ,.status_code= 204
1555   ,.response_status= "No content"
1556   ,.num_headers= 0
1557   ,.headers={}
1558   ,.body_size= 0
1559   ,.body= ""
1560   }
1561
1562 #define NO_BODY_HTTP11_NOKA_204 17
1563 , {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
1564   ,.type= HTTP_RESPONSE
1565   ,.raw= "HTTP/1.1 204 No content\r\n"
1566          "Connection: close\r\n"
1567          "\r\n"
1568   ,.should_keep_alive= FALSE
1569   ,.message_complete_on_eof= FALSE
1570   ,.http_major= 1
1571   ,.http_minor= 1
1572   ,.status_code= 204
1573   ,.response_status= "No content"
1574   ,.num_headers= 1
1575   ,.headers=
1576     { { "Connection", "close" }
1577     }
1578   ,.body_size= 0
1579   ,.body= ""
1580   }
1581
1582 #define NO_BODY_HTTP11_KA_CHUNKED_200 18
1583 , {.name= "HTTP/1.1 with chunked endocing and a 200 response"
1584   ,.type= HTTP_RESPONSE
1585   ,.raw= "HTTP/1.1 200 OK\r\n"
1586          "Transfer-Encoding: chunked\r\n"
1587          "\r\n"
1588          "0\r\n"
1589          "\r\n"
1590   ,.should_keep_alive= TRUE
1591   ,.message_complete_on_eof= FALSE
1592   ,.http_major= 1
1593   ,.http_minor= 1
1594   ,.status_code= 200
1595   ,.response_status= "OK"
1596   ,.num_headers= 1
1597   ,.headers=
1598     { { "Transfer-Encoding", "chunked" }
1599     }
1600   ,.body_size= 0
1601   ,.body= ""
1602   ,.num_chunks_complete= 1
1603   }
1604
1605 #if !HTTP_PARSER_STRICT
1606 #define SPACE_IN_FIELD_RES 19
1607 /* Should handle spaces in header fields */
1608 , {.name= "field space"
1609   ,.type= HTTP_RESPONSE
1610   ,.raw= "HTTP/1.1 200 OK\r\n"
1611          "Server: Microsoft-IIS/6.0\r\n"
1612          "X-Powered-By: ASP.NET\r\n"
1613          "en-US Content-Type: text/xml\r\n" /* this is the problem */
1614          "Content-Type: text/xml\r\n"
1615          "Content-Length: 16\r\n"
1616          "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
1617          "Connection: keep-alive\r\n"
1618          "\r\n"
1619          "<xml>hello</xml>" /* fake body */
1620   ,.should_keep_alive= TRUE
1621   ,.message_complete_on_eof= FALSE
1622   ,.http_major= 1
1623   ,.http_minor= 1
1624   ,.status_code= 200
1625   ,.response_status= "OK"
1626   ,.num_headers= 7
1627   ,.headers=
1628     { { "Server",  "Microsoft-IIS/6.0" }
1629     , { "X-Powered-By", "ASP.NET" }
1630     , { "en-US Content-Type", "text/xml" }
1631     , { "Content-Type", "text/xml" }
1632     , { "Content-Length", "16" }
1633     , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
1634     , { "Connection", "keep-alive" }
1635     }
1636   ,.body= "<xml>hello</xml>"
1637   }
1638 #endif /* !HTTP_PARSER_STRICT */
1639
1640 #define AMAZON_COM 20
1641 , {.name= "amazon.com"
1642   ,.type= HTTP_RESPONSE
1643   ,.raw= "HTTP/1.1 301 MovedPermanently\r\n"
1644          "Date: Wed, 15 May 2013 17:06:33 GMT\r\n"
1645          "Server: Server\r\n"
1646          "x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n"
1647          "p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n"
1648          "x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n"
1649          "Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n"
1650          "Vary: Accept-Encoding,User-Agent\r\n"
1651          "Content-Type: text/html; charset=ISO-8859-1\r\n"
1652          "Transfer-Encoding: chunked\r\n"
1653          "\r\n"
1654          "1\r\n"
1655          "\n\r\n"
1656          "0\r\n"
1657          "\r\n"
1658   ,.should_keep_alive= TRUE
1659   ,.message_complete_on_eof= FALSE
1660   ,.http_major= 1
1661   ,.http_minor= 1
1662   ,.status_code= 301
1663   ,.response_status= "MovedPermanently"
1664   ,.num_headers= 9
1665   ,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
1666              , { "Server", "Server" }
1667              , { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" }
1668              , { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" }
1669              , { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" }
1670              , { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" }
1671              , { "Vary", "Accept-Encoding,User-Agent" }
1672              , { "Content-Type", "text/html; charset=ISO-8859-1" }
1673              , { "Transfer-Encoding", "chunked" }
1674              }
1675   ,.body= "\n"
1676   ,.num_chunks_complete= 2
1677   ,.chunk_lengths= { 1 }
1678   }
1679
1680 #define EMPTY_REASON_PHRASE_AFTER_SPACE 20
1681 , {.name= "empty reason phrase after space"
1682   ,.type= HTTP_RESPONSE
1683   ,.raw= "HTTP/1.1 200 \r\n"
1684          "\r\n"
1685   ,.should_keep_alive= FALSE
1686   ,.message_complete_on_eof= TRUE
1687   ,.http_major= 1
1688   ,.http_minor= 1
1689   ,.status_code= 200
1690   ,.response_status= ""
1691   ,.num_headers= 0
1692   ,.headers= {}
1693   ,.body= ""
1694   }
1695
1696 , {.name= NULL } /* sentinel */
1697 };
1698
1699 /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
1700  * define it ourselves.
1701  */
1702 size_t
1703 strnlen(const char *s, size_t maxlen)
1704 {
1705   const char *p;
1706
1707   p = memchr(s, '\0', maxlen);
1708   if (p == NULL)
1709     return maxlen;
1710
1711   return p - s;
1712 }
1713
1714 size_t
1715 strlncat(char *dst, size_t len, const char *src, size_t n)
1716 {
1717   size_t slen;
1718   size_t dlen;
1719   size_t rlen;
1720   size_t ncpy;
1721
1722   slen = strnlen(src, n);
1723   dlen = strnlen(dst, len);
1724
1725   if (dlen < len) {
1726     rlen = len - dlen;
1727     ncpy = slen < rlen ? slen : (rlen - 1);
1728     memcpy(dst + dlen, src, ncpy);
1729     dst[dlen + ncpy] = '\0';
1730   }
1731
1732   assert(len > slen + dlen);
1733   return slen + dlen;
1734 }
1735
1736 size_t
1737 strlcat(char *dst, const char *src, size_t len)
1738 {
1739   return strlncat(dst, len, src, (size_t) -1);
1740 }
1741
1742 size_t
1743 strlncpy(char *dst, size_t len, const char *src, size_t n)
1744 {
1745   size_t slen;
1746   size_t ncpy;
1747
1748   slen = strnlen(src, n);
1749
1750   if (len > 0) {
1751     ncpy = slen < len ? slen : (len - 1);
1752     memcpy(dst, src, ncpy);
1753     dst[ncpy] = '\0';
1754   }
1755
1756   assert(len > slen);
1757   return slen;
1758 }
1759
1760 size_t
1761 strlcpy(char *dst, const char *src, size_t len)
1762 {
1763   return strlncpy(dst, len, src, (size_t) -1);
1764 }
1765
1766 int
1767 request_url_cb (http_parser *p, const char *buf, size_t len)
1768 {
1769   assert(p == parser);
1770   strlncat(messages[num_messages].request_url,
1771            sizeof(messages[num_messages].request_url),
1772            buf,
1773            len);
1774   return 0;
1775 }
1776
1777 int
1778 header_field_cb (http_parser *p, const char *buf, size_t len)
1779 {
1780   assert(p == parser);
1781   struct message *m = &messages[num_messages];
1782
1783   if (m->last_header_element != FIELD)
1784     m->num_headers++;
1785
1786   strlncat(m->headers[m->num_headers-1][0],
1787            sizeof(m->headers[m->num_headers-1][0]),
1788            buf,
1789            len);
1790
1791   m->last_header_element = FIELD;
1792
1793   return 0;
1794 }
1795
1796 int
1797 header_value_cb (http_parser *p, const char *buf, size_t len)
1798 {
1799   assert(p == parser);
1800   struct message *m = &messages[num_messages];
1801
1802   strlncat(m->headers[m->num_headers-1][1],
1803            sizeof(m->headers[m->num_headers-1][1]),
1804            buf,
1805            len);
1806
1807   m->last_header_element = VALUE;
1808
1809   return 0;
1810 }
1811
1812 void
1813 check_body_is_final (const http_parser *p)
1814 {
1815   if (messages[num_messages].body_is_final) {
1816     fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1817                     "on last on_body callback call "
1818                     "but it doesn't! ***\n\n");
1819     assert(0);
1820     abort();
1821   }
1822   messages[num_messages].body_is_final = http_body_is_final(p);
1823 }
1824
1825 int
1826 body_cb (http_parser *p, const char *buf, size_t len)
1827 {
1828   assert(p == parser);
1829   strlncat(messages[num_messages].body,
1830            sizeof(messages[num_messages].body),
1831            buf,
1832            len);
1833   messages[num_messages].body_size += len;
1834   check_body_is_final(p);
1835  // printf("body_cb: '%s'\n", requests[num_messages].body);
1836   return 0;
1837 }
1838
1839 int
1840 count_body_cb (http_parser *p, const char *buf, size_t len)
1841 {
1842   assert(p == parser);
1843   assert(buf);
1844   messages[num_messages].body_size += len;
1845   check_body_is_final(p);
1846   return 0;
1847 }
1848
1849 int
1850 message_begin_cb (http_parser *p)
1851 {
1852   assert(p == parser);
1853   messages[num_messages].message_begin_cb_called = TRUE;
1854   return 0;
1855 }
1856
1857 int
1858 headers_complete_cb (http_parser *p)
1859 {
1860   assert(p == parser);
1861   messages[num_messages].method = parser->method;
1862   messages[num_messages].status_code = parser->status_code;
1863   messages[num_messages].http_major = parser->http_major;
1864   messages[num_messages].http_minor = parser->http_minor;
1865   messages[num_messages].headers_complete_cb_called = TRUE;
1866   messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
1867   return 0;
1868 }
1869
1870 int
1871 message_complete_cb (http_parser *p)
1872 {
1873   assert(p == parser);
1874   if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
1875   {
1876     fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
1877                     "value in both on_message_complete and on_headers_complete "
1878                     "but it doesn't! ***\n\n");
1879     assert(0);
1880     abort();
1881   }
1882
1883   if (messages[num_messages].body_size &&
1884       http_body_is_final(p) &&
1885       !messages[num_messages].body_is_final)
1886   {
1887     fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1888                     "on last on_body callback call "
1889                     "but it doesn't! ***\n\n");
1890     assert(0);
1891     abort();
1892   }
1893
1894   messages[num_messages].message_complete_cb_called = TRUE;
1895
1896   messages[num_messages].message_complete_on_eof = currently_parsing_eof;
1897
1898   num_messages++;
1899   return 0;
1900 }
1901
1902 int
1903 response_status_cb (http_parser *p, const char *buf, size_t len)
1904 {
1905   assert(p == parser);
1906   strlncat(messages[num_messages].response_status,
1907            sizeof(messages[num_messages].response_status),
1908            buf,
1909            len);
1910   return 0;
1911 }
1912
1913 int
1914 chunk_header_cb (http_parser *p)
1915 {
1916   assert(p == parser);
1917   int chunk_idx = messages[num_messages].num_chunks;
1918   messages[num_messages].num_chunks++;
1919   if (chunk_idx < MAX_CHUNKS) {
1920     messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
1921   }
1922
1923   return 0;
1924 }
1925
1926 int
1927 chunk_complete_cb (http_parser *p)
1928 {
1929   assert(p == parser);
1930
1931   /* Here we want to verify that each chunk_header_cb is matched by a
1932    * chunk_complete_cb, so not only should the total number of calls to
1933    * both callbacks be the same, but they also should be interleaved
1934    * properly */
1935   assert(messages[num_messages].num_chunks ==
1936          messages[num_messages].num_chunks_complete + 1);
1937
1938   messages[num_messages].num_chunks_complete++;
1939   return 0;
1940 }
1941
1942 /* These dontcall_* callbacks exist so that we can verify that when we're
1943  * paused, no additional callbacks are invoked */
1944 int
1945 dontcall_message_begin_cb (http_parser *p)
1946 {
1947   if (p) { } // gcc
1948   fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
1949   abort();
1950 }
1951
1952 int
1953 dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
1954 {
1955   if (p || buf || len) { } // gcc
1956   fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
1957   abort();
1958 }
1959
1960 int
1961 dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
1962 {
1963   if (p || buf || len) { } // gcc
1964   fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
1965   abort();
1966 }
1967
1968 int
1969 dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
1970 {
1971   if (p || buf || len) { } // gcc
1972   fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
1973   abort();
1974 }
1975
1976 int
1977 dontcall_body_cb (http_parser *p, const char *buf, size_t len)
1978 {
1979   if (p || buf || len) { } // gcc
1980   fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
1981   abort();
1982 }
1983
1984 int
1985 dontcall_headers_complete_cb (http_parser *p)
1986 {
1987   if (p) { } // gcc
1988   fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
1989                   "parser ***\n\n");
1990   abort();
1991 }
1992
1993 int
1994 dontcall_message_complete_cb (http_parser *p)
1995 {
1996   if (p) { } // gcc
1997   fprintf(stderr, "\n\n*** on_message_complete() called on paused "
1998                   "parser ***\n\n");
1999   abort();
2000 }
2001
2002 int
2003 dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
2004 {
2005   if (p || buf || len) { } // gcc
2006   fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
2007   abort();
2008 }
2009
2010 int
2011 dontcall_chunk_header_cb (http_parser *p)
2012 {
2013   if (p) { } // gcc
2014   fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
2015   exit(1);
2016 }
2017
2018 int
2019 dontcall_chunk_complete_cb (http_parser *p)
2020 {
2021   if (p) { } // gcc
2022   fprintf(stderr, "\n\n*** on_chunk_complete() "
2023           "called on paused parser ***\n\n");
2024   exit(1);
2025 }
2026
2027 static http_parser_settings settings_dontcall =
2028   {.on_message_begin = dontcall_message_begin_cb
2029   ,.on_header_field = dontcall_header_field_cb
2030   ,.on_header_value = dontcall_header_value_cb
2031   ,.on_url = dontcall_request_url_cb
2032   ,.on_status = dontcall_response_status_cb
2033   ,.on_body = dontcall_body_cb
2034   ,.on_headers_complete = dontcall_headers_complete_cb
2035   ,.on_message_complete = dontcall_message_complete_cb
2036   ,.on_chunk_header = dontcall_chunk_header_cb
2037   ,.on_chunk_complete = dontcall_chunk_complete_cb
2038   };
2039
2040 /* These pause_* callbacks always pause the parser and just invoke the regular
2041  * callback that tracks content. Before returning, we overwrite the parser
2042  * settings to point to the _dontcall variety so that we can verify that
2043  * the pause actually did, you know, pause. */
2044 int
2045 pause_message_begin_cb (http_parser *p)
2046 {
2047   http_parser_pause(p, 1);
2048   *current_pause_parser = settings_dontcall;
2049   return message_begin_cb(p);
2050 }
2051
2052 int
2053 pause_header_field_cb (http_parser *p, const char *buf, size_t len)
2054 {
2055   http_parser_pause(p, 1);
2056   *current_pause_parser = settings_dontcall;
2057   return header_field_cb(p, buf, len);
2058 }
2059
2060 int
2061 pause_header_value_cb (http_parser *p, const char *buf, size_t len)
2062 {
2063   http_parser_pause(p, 1);
2064   *current_pause_parser = settings_dontcall;
2065   return header_value_cb(p, buf, len);
2066 }
2067
2068 int
2069 pause_request_url_cb (http_parser *p, const char *buf, size_t len)
2070 {
2071   http_parser_pause(p, 1);
2072   *current_pause_parser = settings_dontcall;
2073   return request_url_cb(p, buf, len);
2074 }
2075
2076 int
2077 pause_body_cb (http_parser *p, const char *buf, size_t len)
2078 {
2079   http_parser_pause(p, 1);
2080   *current_pause_parser = settings_dontcall;
2081   return body_cb(p, buf, len);
2082 }
2083
2084 int
2085 pause_headers_complete_cb (http_parser *p)
2086 {
2087   http_parser_pause(p, 1);
2088   *current_pause_parser = settings_dontcall;
2089   return headers_complete_cb(p);
2090 }
2091
2092 int
2093 pause_message_complete_cb (http_parser *p)
2094 {
2095   http_parser_pause(p, 1);
2096   *current_pause_parser = settings_dontcall;
2097   return message_complete_cb(p);
2098 }
2099
2100 int
2101 pause_response_status_cb (http_parser *p, const char *buf, size_t len)
2102 {
2103   http_parser_pause(p, 1);
2104   *current_pause_parser = settings_dontcall;
2105   return response_status_cb(p, buf, len);
2106 }
2107
2108 int
2109 pause_chunk_header_cb (http_parser *p)
2110 {
2111   http_parser_pause(p, 1);
2112   *current_pause_parser = settings_dontcall;
2113   return chunk_header_cb(p);
2114 }
2115
2116 int
2117 pause_chunk_complete_cb (http_parser *p)
2118 {
2119   http_parser_pause(p, 1);
2120   *current_pause_parser = settings_dontcall;
2121   return chunk_complete_cb(p);
2122 }
2123
2124 static http_parser_settings settings_pause =
2125   {.on_message_begin = pause_message_begin_cb
2126   ,.on_header_field = pause_header_field_cb
2127   ,.on_header_value = pause_header_value_cb
2128   ,.on_url = pause_request_url_cb
2129   ,.on_status = pause_response_status_cb
2130   ,.on_body = pause_body_cb
2131   ,.on_headers_complete = pause_headers_complete_cb
2132   ,.on_message_complete = pause_message_complete_cb
2133   ,.on_chunk_header = pause_chunk_header_cb
2134   ,.on_chunk_complete = pause_chunk_complete_cb
2135   };
2136
2137 static http_parser_settings settings =
2138   {.on_message_begin = message_begin_cb
2139   ,.on_header_field = header_field_cb
2140   ,.on_header_value = header_value_cb
2141   ,.on_url = request_url_cb
2142   ,.on_status = response_status_cb
2143   ,.on_body = body_cb
2144   ,.on_headers_complete = headers_complete_cb
2145   ,.on_message_complete = message_complete_cb
2146   ,.on_chunk_header = chunk_header_cb
2147   ,.on_chunk_complete = chunk_complete_cb
2148   };
2149
2150 static http_parser_settings settings_count_body =
2151   {.on_message_begin = message_begin_cb
2152   ,.on_header_field = header_field_cb
2153   ,.on_header_value = header_value_cb
2154   ,.on_url = request_url_cb
2155   ,.on_status = response_status_cb
2156   ,.on_body = count_body_cb
2157   ,.on_headers_complete = headers_complete_cb
2158   ,.on_message_complete = message_complete_cb
2159   ,.on_chunk_header = chunk_header_cb
2160   ,.on_chunk_complete = chunk_complete_cb
2161   };
2162
2163 static http_parser_settings settings_null =
2164   {.on_message_begin = 0
2165   ,.on_header_field = 0
2166   ,.on_header_value = 0
2167   ,.on_url = 0
2168   ,.on_status = 0
2169   ,.on_body = 0
2170   ,.on_headers_complete = 0
2171   ,.on_message_complete = 0
2172   ,.on_chunk_header = 0
2173   ,.on_chunk_complete = 0
2174   };
2175
2176 void
2177 parser_init (enum http_parser_type type)
2178 {
2179   num_messages = 0;
2180
2181   assert(parser == NULL);
2182
2183   parser = malloc(sizeof(http_parser));
2184
2185   http_parser_init(parser, type);
2186
2187   memset(&messages, 0, sizeof messages);
2188
2189 }
2190
2191 void
2192 parser_free ()
2193 {
2194   assert(parser);
2195   free(parser);
2196   parser = NULL;
2197 }
2198
2199 size_t parse (const char *buf, size_t len)
2200 {
2201   size_t nparsed;
2202   currently_parsing_eof = (len == 0);
2203   nparsed = http_parser_execute(parser, &settings, buf, len);
2204   return nparsed;
2205 }
2206
2207 size_t parse_count_body (const char *buf, size_t len)
2208 {
2209   size_t nparsed;
2210   currently_parsing_eof = (len == 0);
2211   nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
2212   return nparsed;
2213 }
2214
2215 size_t parse_pause (const char *buf, size_t len)
2216 {
2217   size_t nparsed;
2218   http_parser_settings s = settings_pause;
2219
2220   currently_parsing_eof = (len == 0);
2221   current_pause_parser = &s;
2222   nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
2223   return nparsed;
2224 }
2225
2226 static inline int
2227 check_str_eq (const struct message *m,
2228               const char *prop,
2229               const char *expected,
2230               const char *found) {
2231   if ((expected == NULL) != (found == NULL)) {
2232     printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
2233     printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
2234     printf("   found %s\n", (found == NULL) ? "NULL" : found);
2235     return 0;
2236   }
2237   if (expected != NULL && 0 != strcmp(expected, found)) {
2238     printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
2239     printf("expected '%s'\n", expected);
2240     printf("   found '%s'\n", found);
2241     return 0;
2242   }
2243   return 1;
2244 }
2245
2246 static inline int
2247 check_num_eq (const struct message *m,
2248               const char *prop,
2249               int expected,
2250               int found) {
2251   if (expected != found) {
2252     printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
2253     printf("expected %d\n", expected);
2254     printf("   found %d\n", found);
2255     return 0;
2256   }
2257   return 1;
2258 }
2259
2260 #define MESSAGE_CHECK_STR_EQ(expected, found, prop) \
2261   if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0
2262
2263 #define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
2264   if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
2265
2266 #define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn)           \
2267 do {                                                                 \
2268   char ubuf[256];                                                    \
2269                                                                      \
2270   if ((u)->field_set & (1 << (fn))) {                                \
2271     memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off,   \
2272       (u)->field_data[(fn)].len);                                    \
2273     ubuf[(u)->field_data[(fn)].len] = '\0';                          \
2274   } else {                                                           \
2275     ubuf[0] = '\0';                                                  \
2276   }                                                                  \
2277                                                                      \
2278   check_str_eq(expected, #prop, expected->prop, ubuf);               \
2279 } while(0)
2280
2281 int
2282 message_eq (int index, const struct message *expected)
2283 {
2284   int i;
2285   struct message *m = &messages[index];
2286
2287   MESSAGE_CHECK_NUM_EQ(expected, m, http_major);
2288   MESSAGE_CHECK_NUM_EQ(expected, m, http_minor);
2289
2290   if (expected->type == HTTP_REQUEST) {
2291     MESSAGE_CHECK_NUM_EQ(expected, m, method);
2292   } else {
2293     MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
2294     MESSAGE_CHECK_STR_EQ(expected, m, response_status);
2295   }
2296
2297   MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
2298   MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
2299
2300   assert(m->message_begin_cb_called);
2301   assert(m->headers_complete_cb_called);
2302   assert(m->message_complete_cb_called);
2303
2304
2305   MESSAGE_CHECK_STR_EQ(expected, m, request_url);
2306
2307   /* Check URL components; we can't do this w/ CONNECT since it doesn't
2308    * send us a well-formed URL.
2309    */
2310   if (*m->request_url && m->method != HTTP_CONNECT) {
2311     struct http_parser_url u;
2312
2313     if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
2314       fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
2315         m->request_url);
2316       abort();
2317     }
2318
2319     if (expected->host) {
2320       MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
2321     }
2322
2323     if (expected->userinfo) {
2324       MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
2325     }
2326
2327     m->port = (u.field_set & (1 << UF_PORT)) ?
2328       u.port : 0;
2329
2330     MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
2331     MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
2332     MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
2333     MESSAGE_CHECK_NUM_EQ(expected, m, port);
2334   }
2335
2336   if (expected->body_size) {
2337     MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
2338   } else {
2339     MESSAGE_CHECK_STR_EQ(expected, m, body);
2340   }
2341
2342   assert(m->num_chunks == m->num_chunks_complete);
2343   MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
2344   for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
2345     MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
2346   }
2347
2348   MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
2349
2350   int r;
2351   for (i = 0; i < m->num_headers; i++) {
2352     r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]);
2353     if (!r) return 0;
2354     r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
2355     if (!r) return 0;
2356   }
2357
2358   MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
2359
2360   return 1;
2361 }
2362
2363 /* Given a sequence of varargs messages, return the number of them that the
2364  * parser should successfully parse, taking into account that upgraded
2365  * messages prevent all subsequent messages from being parsed.
2366  */
2367 size_t
2368 count_parsed_messages(const size_t nmsgs, ...) {
2369   size_t i;
2370   va_list ap;
2371
2372   va_start(ap, nmsgs);
2373
2374   for (i = 0; i < nmsgs; i++) {
2375     struct message *m = va_arg(ap, struct message *);
2376
2377     if (m->upgrade) {
2378       va_end(ap);
2379       return i + 1;
2380     }
2381   }
2382
2383   va_end(ap);
2384   return nmsgs;
2385 }
2386
2387 /* Given a sequence of bytes and the number of these that we were able to
2388  * parse, verify that upgrade bodies are correct.
2389  */
2390 void
2391 upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
2392   va_list ap;
2393   size_t i;
2394   size_t off = 0;
2395  
2396   va_start(ap, nmsgs);
2397
2398   for (i = 0; i < nmsgs; i++) {
2399     struct message *m = va_arg(ap, struct message *);
2400
2401     off += strlen(m->raw);
2402
2403     if (m->upgrade) {
2404       off -= strlen(m->upgrade);
2405
2406       /* Check the portion of the response after its specified upgrade */
2407       if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
2408         abort();
2409       }
2410
2411       /* Fix up the response so that message_eq() will verify the beginning
2412        * of the upgrade */
2413       *(body + nread + strlen(m->upgrade)) = '\0';
2414       messages[num_messages -1 ].upgrade = body + nread;
2415
2416       va_end(ap);
2417       return;
2418     }
2419   }
2420
2421   va_end(ap);
2422   printf("\n\n*** Error: expected a message with upgrade ***\n");
2423
2424   abort();
2425 }
2426
2427 static void
2428 print_error (const char *raw, size_t error_location)
2429 {
2430   fprintf(stderr, "\n*** %s ***\n\n",
2431           http_errno_description(HTTP_PARSER_ERRNO(parser)));
2432
2433   int this_line = 0, char_len = 0;
2434   size_t i, j, len = strlen(raw), error_location_line = 0;
2435   for (i = 0; i < len; i++) {
2436     if (i == error_location) this_line = 1;
2437     switch (raw[i]) {
2438       case '\r':
2439         char_len = 2;
2440         fprintf(stderr, "\\r");
2441         break;
2442
2443       case '\n':
2444         fprintf(stderr, "\\n\n");
2445
2446         if (this_line) goto print;
2447
2448         error_location_line = 0;
2449         continue;
2450
2451       default:
2452         char_len = 1;
2453         fputc(raw[i], stderr);
2454         break;
2455     }
2456     if (!this_line) error_location_line += char_len;
2457   }
2458
2459   fprintf(stderr, "[eof]\n");
2460
2461  print:
2462   for (j = 0; j < error_location_line; j++) {
2463     fputc(' ', stderr);
2464   }
2465   fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
2466 }
2467
2468 void
2469 test_preserve_data (void)
2470 {
2471   char my_data[] = "application-specific data";
2472   http_parser parser;
2473   parser.data = my_data;
2474   http_parser_init(&parser, HTTP_REQUEST);
2475   if (parser.data != my_data) {
2476     printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
2477     abort();
2478   }
2479 }
2480
2481 struct url_test {
2482   const char *name;
2483   const char *url;
2484   int is_connect;
2485   struct http_parser_url u;
2486   int rv;
2487 };
2488
2489 const struct url_test url_tests[] =
2490 { {.name="proxy request"
2491   ,.url="http://hostname/"
2492   ,.is_connect=0
2493   ,.u=
2494     {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2495     ,.port=0
2496     ,.field_data=
2497       {{  0,  4 } /* UF_SCHEMA */
2498       ,{  7,  8 } /* UF_HOST */
2499       ,{  0,  0 } /* UF_PORT */
2500       ,{ 15,  1 } /* UF_PATH */
2501       ,{  0,  0 } /* UF_QUERY */
2502       ,{  0,  0 } /* UF_FRAGMENT */
2503       ,{  0,  0 } /* UF_USERINFO */
2504       }
2505     }
2506   ,.rv=0
2507   }
2508
2509 , {.name="proxy request with port"
2510   ,.url="http://hostname:444/"
2511   ,.is_connect=0
2512   ,.u=
2513     {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2514     ,.port=444
2515     ,.field_data=
2516       {{  0,  4 } /* UF_SCHEMA */
2517       ,{  7,  8 } /* UF_HOST */
2518       ,{ 16,  3 } /* UF_PORT */
2519       ,{ 19,  1 } /* UF_PATH */
2520       ,{  0,  0 } /* UF_QUERY */
2521       ,{  0,  0 } /* UF_FRAGMENT */
2522       ,{  0,  0 } /* UF_USERINFO */
2523       }
2524     }
2525   ,.rv=0
2526   }
2527
2528 , {.name="CONNECT request"
2529   ,.url="hostname:443"
2530   ,.is_connect=1
2531   ,.u=
2532     {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2533     ,.port=443
2534     ,.field_data=
2535       {{  0,  0 } /* UF_SCHEMA */
2536       ,{  0,  8 } /* UF_HOST */
2537       ,{  9,  3 } /* UF_PORT */
2538       ,{  0,  0 } /* UF_PATH */
2539       ,{  0,  0 } /* UF_QUERY */
2540       ,{  0,  0 } /* UF_FRAGMENT */
2541       ,{  0,  0 } /* UF_USERINFO */
2542       }
2543     }
2544   ,.rv=0
2545   }
2546
2547 , {.name="CONNECT request but not connect"
2548   ,.url="hostname:443"
2549   ,.is_connect=0
2550   ,.rv=1
2551   }
2552
2553 , {.name="proxy ipv6 request"
2554   ,.url="http://[1:2::3:4]/"
2555   ,.is_connect=0
2556   ,.u=
2557     {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2558     ,.port=0
2559     ,.field_data=
2560       {{  0,  4 } /* UF_SCHEMA */
2561       ,{  8,  8 } /* UF_HOST */
2562       ,{  0,  0 } /* UF_PORT */
2563       ,{ 17,  1 } /* UF_PATH */
2564       ,{  0,  0 } /* UF_QUERY */
2565       ,{  0,  0 } /* UF_FRAGMENT */
2566       ,{  0,  0 } /* UF_USERINFO */
2567       }
2568     }
2569   ,.rv=0
2570   }
2571
2572 , {.name="proxy ipv6 request with port"
2573   ,.url="http://[1:2::3:4]:67/"
2574   ,.is_connect=0
2575   ,.u=
2576     {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2577     ,.port=67
2578     ,.field_data=
2579       {{  0,  4 } /* UF_SCHEMA */
2580       ,{  8,  8 } /* UF_HOST */
2581       ,{ 18,  2 } /* UF_PORT */
2582       ,{ 20,  1 } /* UF_PATH */
2583       ,{  0,  0 } /* UF_QUERY */
2584       ,{  0,  0 } /* UF_FRAGMENT */
2585       ,{  0,  0 } /* UF_USERINFO */
2586       }
2587     }
2588   ,.rv=0
2589   }
2590
2591 , {.name="CONNECT ipv6 address"
2592   ,.url="[1:2::3:4]:443"
2593   ,.is_connect=1
2594   ,.u=
2595     {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2596     ,.port=443
2597     ,.field_data=
2598       {{  0,  0 } /* UF_SCHEMA */
2599       ,{  1,  8 } /* UF_HOST */
2600       ,{ 11,  3 } /* UF_PORT */
2601       ,{  0,  0 } /* UF_PATH */
2602       ,{  0,  0 } /* UF_QUERY */
2603       ,{  0,  0 } /* UF_FRAGMENT */
2604       ,{  0,  0 } /* UF_USERINFO */
2605       }
2606     }
2607   ,.rv=0
2608   }
2609
2610 , {.name="ipv4 in ipv6 address"
2611   ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
2612   ,.is_connect=0
2613   ,.u=
2614     {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2615     ,.port=0
2616     ,.field_data=
2617       {{  0,  4 } /* UF_SCHEMA */
2618       ,{  8, 37 } /* UF_HOST */
2619       ,{  0,  0 } /* UF_PORT */
2620       ,{ 46,  1 } /* UF_PATH */
2621       ,{  0,  0 } /* UF_QUERY */
2622       ,{  0,  0 } /* UF_FRAGMENT */
2623       ,{  0,  0 } /* UF_USERINFO */
2624       }
2625     }
2626   ,.rv=0
2627   }
2628
2629 , {.name="extra ? in query string"
2630   ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
2631   "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
2632   "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
2633   ,.is_connect=0
2634   ,.u=
2635     {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
2636     ,.port=0
2637     ,.field_data=
2638       {{  0,  4 } /* UF_SCHEMA */
2639       ,{  7, 10 } /* UF_HOST */
2640       ,{  0,  0 } /* UF_PORT */
2641       ,{ 17, 12 } /* UF_PATH */
2642       ,{ 30,187 } /* UF_QUERY */
2643       ,{  0,  0 } /* UF_FRAGMENT */
2644       ,{  0,  0 } /* UF_USERINFO */
2645       }
2646     }
2647   ,.rv=0
2648   }
2649
2650 , {.name="space URL encoded"
2651   ,.url="/toto.html?toto=a%20b"
2652   ,.is_connect=0
2653   ,.u=
2654     {.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
2655     ,.port=0
2656     ,.field_data=
2657       {{  0,  0 } /* UF_SCHEMA */
2658       ,{  0,  0 } /* UF_HOST */
2659       ,{  0,  0 } /* UF_PORT */
2660       ,{  0, 10 } /* UF_PATH */
2661       ,{ 11, 10 } /* UF_QUERY */
2662       ,{  0,  0 } /* UF_FRAGMENT */
2663       ,{  0,  0 } /* UF_USERINFO */
2664       }
2665     }
2666   ,.rv=0
2667   }
2668
2669
2670 , {.name="URL fragment"
2671   ,.url="/toto.html#titi"
2672   ,.is_connect=0
2673   ,.u=
2674     {.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
2675     ,.port=0
2676     ,.field_data=
2677       {{  0,  0 } /* UF_SCHEMA */
2678       ,{  0,  0 } /* UF_HOST */
2679       ,{  0,  0 } /* UF_PORT */
2680       ,{  0, 10 } /* UF_PATH */
2681       ,{  0,  0 } /* UF_QUERY */
2682       ,{ 11,  4 } /* UF_FRAGMENT */
2683       ,{  0,  0 } /* UF_USERINFO */
2684       }
2685     }
2686   ,.rv=0
2687   }
2688
2689 , {.name="complex URL fragment"
2690   ,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
2691     "http://www.example.com/index.html?foo=bar&hello=world#midpage"
2692   ,.is_connect=0
2693   ,.u=
2694     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
2695       (1<<UF_FRAGMENT)
2696     ,.port=0
2697     ,.field_data=
2698       {{  0,  4 } /* UF_SCHEMA */
2699       ,{  7, 22 } /* UF_HOST */
2700       ,{  0,  0 } /* UF_PORT */
2701       ,{ 29,  6 } /* UF_PATH */
2702       ,{ 36, 69 } /* UF_QUERY */
2703       ,{106,  7 } /* UF_FRAGMENT */
2704       ,{  0,  0 } /* UF_USERINFO */
2705       }
2706     }
2707   ,.rv=0
2708   }
2709
2710 , {.name="complex URL from node js url parser doc"
2711   ,.url="http://host.com:8080/p/a/t/h?query=string#hash"
2712   ,.is_connect=0
2713   ,.u=
2714     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2715       (1<<UF_QUERY) | (1<<UF_FRAGMENT)
2716     ,.port=8080
2717     ,.field_data=
2718       {{  0,  4 } /* UF_SCHEMA */
2719       ,{  7,  8 } /* UF_HOST */
2720       ,{ 16,  4 } /* UF_PORT */
2721       ,{ 20,  8 } /* UF_PATH */
2722       ,{ 29, 12 } /* UF_QUERY */
2723       ,{ 42,  4 } /* UF_FRAGMENT */
2724       ,{  0,  0 } /* UF_USERINFO */
2725       }
2726     }
2727   ,.rv=0
2728   }
2729
2730 , {.name="complex URL with basic auth from node js url parser doc"
2731   ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
2732   ,.is_connect=0
2733   ,.u=
2734     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2735       (1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
2736     ,.port=8080
2737     ,.field_data=
2738       {{  0,  4 } /* UF_SCHEMA */
2739       ,{ 11,  8 } /* UF_HOST */
2740       ,{ 20,  4 } /* UF_PORT */
2741       ,{ 24,  8 } /* UF_PATH */
2742       ,{ 33, 12 } /* UF_QUERY */
2743       ,{ 46,  4 } /* UF_FRAGMENT */
2744       ,{  7,  3 } /* UF_USERINFO */
2745       }
2746     }
2747   ,.rv=0
2748   }
2749
2750 , {.name="double @"
2751   ,.url="http://a:b@@hostname:443/"
2752   ,.is_connect=0
2753   ,.rv=1
2754   }
2755
2756 , {.name="proxy empty host"
2757   ,.url="http://:443/"
2758   ,.is_connect=0
2759   ,.rv=1
2760   }
2761
2762 , {.name="proxy empty port"
2763   ,.url="http://hostname:/"
2764   ,.is_connect=0
2765   ,.rv=1
2766   }
2767
2768 , {.name="CONNECT with basic auth"
2769   ,.url="a:b@hostname:443"
2770   ,.is_connect=1
2771   ,.rv=1
2772   }
2773
2774 , {.name="CONNECT empty host"
2775   ,.url=":443"
2776   ,.is_connect=1
2777   ,.rv=1
2778   }
2779
2780 , {.name="CONNECT empty port"
2781   ,.url="hostname:"
2782   ,.is_connect=1
2783   ,.rv=1
2784   }
2785
2786 , {.name="CONNECT with extra bits"
2787   ,.url="hostname:443/"
2788   ,.is_connect=1
2789   ,.rv=1
2790   }
2791
2792 , {.name="space in URL"
2793   ,.url="/foo bar/"
2794   ,.rv=1 /* s_dead */
2795   }
2796
2797 , {.name="proxy basic auth with space url encoded"
2798   ,.url="http://a%20:b@host.com/"
2799   ,.is_connect=0
2800   ,.u=
2801     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2802     ,.port=0
2803     ,.field_data=
2804       {{  0,  4 } /* UF_SCHEMA */
2805       ,{ 14,  8 } /* UF_HOST */
2806       ,{  0,  0 } /* UF_PORT */
2807       ,{ 22,  1 } /* UF_PATH */
2808       ,{  0,  0 } /* UF_QUERY */
2809       ,{  0,  0 } /* UF_FRAGMENT */
2810       ,{  7,  6 } /* UF_USERINFO */
2811       }
2812     }
2813   ,.rv=0
2814   }
2815
2816 , {.name="carriage return in URL"
2817   ,.url="/foo\rbar/"
2818   ,.rv=1 /* s_dead */
2819   }
2820
2821 , {.name="proxy double : in URL"
2822   ,.url="http://hostname::443/"
2823   ,.rv=1 /* s_dead */
2824   }
2825
2826 , {.name="proxy basic auth with double :"
2827   ,.url="http://a::b@host.com/"
2828   ,.is_connect=0
2829   ,.u=
2830     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2831     ,.port=0
2832     ,.field_data=
2833       {{  0,  4 } /* UF_SCHEMA */
2834       ,{ 12,  8 } /* UF_HOST */
2835       ,{  0,  0 } /* UF_PORT */
2836       ,{ 20,  1 } /* UF_PATH */
2837       ,{  0,  0 } /* UF_QUERY */
2838       ,{  0,  0 } /* UF_FRAGMENT */
2839       ,{  7,  4 } /* UF_USERINFO */
2840       }
2841     }
2842   ,.rv=0
2843   }
2844
2845 , {.name="line feed in URL"
2846   ,.url="/foo\nbar/"
2847   ,.rv=1 /* s_dead */
2848   }
2849
2850 , {.name="proxy empty basic auth"
2851   ,.url="http://@hostname/fo"
2852   ,.u=
2853     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
2854     ,.port=0
2855     ,.field_data=
2856       {{  0,  4 } /* UF_SCHEMA */
2857       ,{  8,  8 } /* UF_HOST */
2858       ,{  0,  0 } /* UF_PORT */
2859       ,{ 16,  3 } /* UF_PATH */
2860       ,{  0,  0 } /* UF_QUERY */
2861       ,{  0,  0 } /* UF_FRAGMENT */
2862       ,{  0,  0 } /* UF_USERINFO */
2863       }
2864     }
2865   ,.rv=0
2866   }
2867 , {.name="proxy line feed in hostname"
2868   ,.url="http://host\name/fo"
2869   ,.rv=1 /* s_dead */
2870   }
2871
2872 , {.name="proxy % in hostname"
2873   ,.url="http://host%name/fo"
2874   ,.rv=1 /* s_dead */
2875   }
2876
2877 , {.name="proxy ; in hostname"
2878   ,.url="http://host;ame/fo"
2879   ,.rv=1 /* s_dead */
2880   }
2881
2882 , {.name="proxy basic auth with unreservedchars"
2883   ,.url="http://a!;-_!=+$@host.com/"
2884   ,.is_connect=0
2885   ,.u=
2886     {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2887     ,.port=0
2888     ,.field_data=
2889       {{  0,  4 } /* UF_SCHEMA */
2890       ,{ 17,  8 } /* UF_HOST */
2891       ,{  0,  0 } /* UF_PORT */
2892       ,{ 25,  1 } /* UF_PATH */
2893       ,{  0,  0 } /* UF_QUERY */
2894       ,{  0,  0 } /* UF_FRAGMENT */
2895       ,{  7,  9 } /* UF_USERINFO */
2896       }
2897     }
2898   ,.rv=0
2899   }
2900
2901 , {.name="proxy only empty basic auth"
2902   ,.url="http://@/fo"
2903   ,.rv=1 /* s_dead */
2904   }
2905
2906 , {.name="proxy only basic auth"
2907   ,.url="http://toto@/fo"
2908   ,.rv=1 /* s_dead */
2909   }
2910
2911 , {.name="proxy emtpy hostname"
2912   ,.url="http:///fo"
2913   ,.rv=1 /* s_dead */
2914   }
2915
2916 , {.name="proxy = in URL"
2917   ,.url="http://host=ame/fo"
2918   ,.rv=1 /* s_dead */
2919   }
2920
2921 #if HTTP_PARSER_STRICT
2922
2923 , {.name="tab in URL"
2924   ,.url="/foo\tbar/"
2925   ,.rv=1 /* s_dead */
2926   }
2927
2928 , {.name="form feed in URL"
2929   ,.url="/foo\fbar/"
2930   ,.rv=1 /* s_dead */
2931   }
2932
2933 #else /* !HTTP_PARSER_STRICT */
2934
2935 , {.name="tab in URL"
2936   ,.url="/foo\tbar/"
2937   ,.u=
2938     {.field_set=(1 << UF_PATH)
2939     ,.field_data=
2940       {{  0,  0 } /* UF_SCHEMA */
2941       ,{  0,  0 } /* UF_HOST */
2942       ,{  0,  0 } /* UF_PORT */
2943       ,{  0,  9 } /* UF_PATH */
2944       ,{  0,  0 } /* UF_QUERY */
2945       ,{  0,  0 } /* UF_FRAGMENT */
2946       ,{  0,  0 } /* UF_USERINFO */
2947       }
2948     }
2949   ,.rv=0
2950   }
2951
2952 , {.name="form feed in URL"
2953   ,.url="/foo\fbar/"
2954   ,.u=
2955     {.field_set=(1 << UF_PATH)
2956     ,.field_data=
2957       {{  0,  0 } /* UF_SCHEMA */
2958       ,{  0,  0 } /* UF_HOST */
2959       ,{  0,  0 } /* UF_PORT */
2960       ,{  0,  9 } /* UF_PATH */
2961       ,{  0,  0 } /* UF_QUERY */
2962       ,{  0,  0 } /* UF_FRAGMENT */
2963       ,{  0,  0 } /* UF_USERINFO */
2964       }
2965     }
2966   ,.rv=0
2967   }
2968 #endif
2969 };
2970
2971 void
2972 dump_url (const char *url, const struct http_parser_url *u)
2973 {
2974   unsigned int i;
2975
2976   printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
2977   for (i = 0; i < UF_MAX; i++) {
2978     if ((u->field_set & (1 << i)) == 0) {
2979       printf("\tfield_data[%u]: unset\n", i);
2980       continue;
2981     }
2982
2983     printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
2984            i,
2985            u->field_data[i].off,
2986            u->field_data[i].len,
2987            u->field_data[i].len,
2988            url + u->field_data[i].off);
2989   }
2990 }
2991
2992 void
2993 test_parse_url (void)
2994 {
2995   struct http_parser_url u;
2996   const struct url_test *test;
2997   unsigned int i;
2998   int rv;
2999
3000   for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
3001     test = &url_tests[i];
3002     memset(&u, 0, sizeof(u));
3003
3004     rv = http_parser_parse_url(test->url,
3005                                strlen(test->url),
3006                                test->is_connect,
3007                                &u);
3008
3009     if (test->rv == 0) {
3010       if (rv != 0) {
3011         printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
3012                "unexpected rv %d ***\n\n", test->url, test->name, rv);
3013         abort();
3014       }
3015
3016       if (memcmp(&u, &test->u, sizeof(u)) != 0) {
3017         printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
3018                test->url, test->name);
3019
3020         printf("target http_parser_url:\n");
3021         dump_url(test->url, &test->u);
3022         printf("result http_parser_url:\n");
3023         dump_url(test->url, &u);
3024
3025         abort();
3026       }
3027     } else {
3028       /* test->rv != 0 */
3029       if (rv == 0) {
3030         printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
3031                "unexpected rv %d ***\n\n", test->url, test->name, rv);
3032         abort();
3033       }
3034     }
3035   }
3036 }
3037
3038 void
3039 test_method_str (void)
3040 {
3041   assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
3042   assert(0 == strcmp("<unknown>", http_method_str(1337)));
3043 }
3044
3045 void
3046 test_message (const struct message *message)
3047 {
3048   size_t raw_len = strlen(message->raw);
3049   size_t msg1len;
3050   for (msg1len = 0; msg1len < raw_len; msg1len++) {
3051     parser_init(message->type);
3052
3053     size_t read;
3054     const char *msg1 = message->raw;
3055     const char *msg2 = msg1 + msg1len;
3056     size_t msg2len = raw_len - msg1len;
3057
3058     if (msg1len) {
3059       read = parse(msg1, msg1len);
3060
3061       if (message->upgrade && parser->upgrade && num_messages > 0) {
3062         messages[num_messages - 1].upgrade = msg1 + read;
3063         goto test;
3064       }
3065
3066       if (read != msg1len) {
3067         print_error(msg1, read);
3068         abort();
3069       }
3070     }
3071
3072
3073     read = parse(msg2, msg2len);
3074
3075     if (message->upgrade && parser->upgrade) {
3076       messages[num_messages - 1].upgrade = msg2 + read;
3077       goto test;
3078     }
3079
3080     if (read != msg2len) {
3081       print_error(msg2, read);
3082       abort();
3083     }
3084
3085     read = parse(NULL, 0);
3086
3087     if (read != 0) {
3088       print_error(message->raw, read);
3089       abort();
3090     }
3091
3092   test:
3093
3094     if (num_messages != 1) {
3095       printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
3096       abort();
3097     }
3098
3099     if(!message_eq(0, message)) abort();
3100
3101     parser_free();
3102   }
3103 }
3104
3105 void
3106 test_message_count_body (const struct message *message)
3107 {
3108   parser_init(message->type);
3109
3110   size_t read;
3111   size_t l = strlen(message->raw);
3112   size_t i, toread;
3113   size_t chunk = 4024;
3114
3115   for (i = 0; i < l; i+= chunk) {
3116     toread = MIN(l-i, chunk);
3117     read = parse_count_body(message->raw + i, toread);
3118     if (read != toread) {
3119       print_error(message->raw, read);
3120       abort();
3121     }
3122   }
3123
3124
3125   read = parse_count_body(NULL, 0);
3126   if (read != 0) {
3127     print_error(message->raw, read);
3128     abort();
3129   }
3130
3131   if (num_messages != 1) {
3132     printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
3133     abort();
3134   }
3135
3136   if(!message_eq(0, message)) abort();
3137
3138   parser_free();
3139 }
3140
3141 void
3142 test_simple (const char *buf, enum http_errno err_expected)
3143 {
3144   parser_init(HTTP_REQUEST);
3145
3146   enum http_errno err;
3147
3148   parse(buf, strlen(buf));
3149   err = HTTP_PARSER_ERRNO(parser);
3150   parse(NULL, 0);
3151
3152   parser_free();
3153
3154   /* In strict mode, allow us to pass with an unexpected HPE_STRICT as
3155    * long as the caller isn't expecting success.
3156    */
3157 #if HTTP_PARSER_STRICT
3158   if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
3159 #else
3160   if (err_expected != err) {
3161 #endif
3162     fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
3163         http_errno_name(err_expected), http_errno_name(err), buf);
3164     abort();
3165   }
3166 }
3167
3168 void
3169 test_invalid_header_content (int req, const char* str)
3170 {
3171   http_parser parser;
3172   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3173   size_t parsed;
3174   const char *buf;
3175   buf = req ?
3176     "GET / HTTP/1.1\r\n" :
3177     "HTTP/1.1 200 OK\r\n";
3178   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3179   assert(parsed == strlen(buf));
3180
3181   buf = str;
3182   size_t buflen = strlen(buf);
3183
3184   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3185   if (parsed != buflen) {
3186     assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
3187     return;
3188   }
3189
3190   fprintf(stderr,
3191           "\n*** Error expected but none in invalid header content test ***\n");
3192   abort();
3193 }
3194
3195 void
3196 test_invalid_header_field_content_error (int req)
3197 {
3198   test_invalid_header_content(req, "Foo: F\01ailure");
3199   test_invalid_header_content(req, "Foo: B\02ar");
3200 }
3201
3202 void
3203 test_invalid_header_field (int req, const char* str)
3204 {
3205   http_parser parser;
3206   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3207   size_t parsed;
3208   const char *buf;
3209   buf = req ?
3210     "GET / HTTP/1.1\r\n" :
3211     "HTTP/1.1 200 OK\r\n";
3212   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3213   assert(parsed == strlen(buf));
3214
3215   buf = str;
3216   size_t buflen = strlen(buf);
3217
3218   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3219   if (parsed != buflen) {
3220     assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
3221     return;
3222   }
3223
3224   fprintf(stderr,
3225           "\n*** Error expected but none in invalid header token test ***\n");
3226   abort();
3227 }
3228
3229 void
3230 test_invalid_header_field_token_error (int req)
3231 {
3232   test_invalid_header_field(req, "Fo@: Failure");
3233   test_invalid_header_field(req, "Foo\01\test: Bar");
3234 }
3235
3236 void
3237 test_double_content_length_error (int req)
3238 {
3239   http_parser parser;
3240   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3241   size_t parsed;
3242   const char *buf;
3243   buf = req ?
3244     "GET / HTTP/1.1\r\n" :
3245     "HTTP/1.1 200 OK\r\n";
3246   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3247   assert(parsed == strlen(buf));
3248
3249   buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
3250   size_t buflen = strlen(buf);
3251
3252   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3253   if (parsed != buflen) {
3254     assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
3255     return;
3256   }
3257
3258   fprintf(stderr,
3259           "\n*** Error expected but none in double content-length test ***\n");
3260   abort();
3261 }
3262
3263 void
3264 test_chunked_content_length_error (int req)
3265 {
3266   http_parser parser;
3267   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3268   size_t parsed;
3269   const char *buf;
3270   buf = req ?
3271     "GET / HTTP/1.1\r\n" :
3272     "HTTP/1.1 200 OK\r\n";
3273   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3274   assert(parsed == strlen(buf));
3275
3276   buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
3277   size_t buflen = strlen(buf);
3278
3279   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3280   if (parsed != buflen) {
3281     assert(HTTP_PARSER_ERRNO(&parser) == HPE_CHUNKED_WITH_CONTENT_LENGTH);
3282     return;
3283   }
3284
3285   fprintf(stderr,
3286           "\n*** Error expected but none in chunked content-length test ***\n");
3287   abort();
3288 }
3289
3290 void
3291 test_header_cr_no_lf_error (int req)
3292 {
3293   http_parser parser;
3294   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3295   size_t parsed;
3296   const char *buf;
3297   buf = req ?
3298     "GET / HTTP/1.1\r\n" :
3299     "HTTP/1.1 200 OK\r\n";
3300   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3301   assert(parsed == strlen(buf));
3302
3303   buf = "Foo: 1\rBar: 1\r\n\r\n";
3304   size_t buflen = strlen(buf);
3305
3306   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3307   if (parsed != buflen) {
3308     assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
3309     return;
3310   }
3311
3312   fprintf(stderr,
3313           "\n*** Error expected but none in header whitespace test ***\n");
3314   abort();
3315 }
3316
3317 void
3318 test_header_overflow_error (int req)
3319 {
3320   http_parser parser;
3321   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3322   size_t parsed;
3323   const char *buf;
3324   buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n";
3325   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3326   assert(parsed == strlen(buf));
3327
3328   buf = "header-key: header-value\r\n";
3329   size_t buflen = strlen(buf);
3330
3331   int i;
3332   for (i = 0; i < 10000; i++) {
3333     parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3334     if (parsed != buflen) {
3335       //fprintf(stderr, "error found on iter %d\n", i);
3336       assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
3337       return;
3338     }
3339   }
3340
3341   fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
3342   abort();
3343 }
3344
3345
3346 void
3347 test_header_nread_value ()
3348 {
3349   http_parser parser;
3350   http_parser_init(&parser, HTTP_REQUEST);
3351   size_t parsed;
3352   const char *buf;
3353   buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
3354   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3355   assert(parsed == strlen(buf));
3356
3357   assert(parser.nread == strlen(buf));
3358 }
3359
3360
3361 static void
3362 test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
3363 {
3364   http_parser parser;
3365   http_parser_init(&parser, HTTP_RESPONSE);
3366   http_parser_execute(&parser, &settings_null, buf, buflen);
3367
3368   if (expect_ok)
3369     assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
3370   else
3371     assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
3372 }
3373
3374 void
3375 test_header_content_length_overflow_error (void)
3376 {
3377 #define X(size)                                                               \
3378   "HTTP/1.1 200 OK\r\n"                                                       \
3379   "Content-Length: " #size "\r\n"                                             \
3380   "\r\n"
3381   const char a[] = X(1844674407370955160);  /* 2^64 / 10 - 1 */
3382   const char b[] = X(18446744073709551615); /* 2^64-1 */
3383   const char c[] = X(18446744073709551616); /* 2^64   */
3384 #undef X
3385   test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok      */
3386   test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
3387   test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
3388 }
3389
3390 void
3391 test_chunk_content_length_overflow_error (void)
3392 {
3393 #define X(size)                                                               \
3394     "HTTP/1.1 200 OK\r\n"                                                     \
3395     "Transfer-Encoding: chunked\r\n"                                          \
3396     "\r\n"                                                                    \
3397     #size "\r\n"                                                              \
3398     "..."
3399   const char a[] = X(FFFFFFFFFFFFFFE);   /* 2^64 / 16 - 1 */
3400   const char b[] = X(FFFFFFFFFFFFFFFF);  /* 2^64-1 */
3401   const char c[] = X(10000000000000000); /* 2^64   */
3402 #undef X
3403   test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok      */
3404   test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
3405   test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
3406 }
3407
3408 void
3409 test_no_overflow_long_body (int req, size_t length)
3410 {
3411   http_parser parser;
3412   http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3413   size_t parsed;
3414   size_t i;
3415   char buf1[3000];
3416   size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
3417       req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
3418   parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
3419   if (parsed != buf1len)
3420     goto err;
3421
3422   for (i = 0; i < length; i++) {
3423     char foo = 'a';
3424     parsed = http_parser_execute(&parser, &settings_null, &foo, 1);
3425     if (parsed != 1)
3426       goto err;
3427   }
3428
3429   parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
3430   if (parsed != buf1len) goto err;
3431   return;
3432
3433  err:
3434   fprintf(stderr,
3435           "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
3436           req ? "REQUEST" : "RESPONSE",
3437           (unsigned long)length);
3438   abort();
3439 }
3440
3441 void
3442 test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
3443 {
3444   int message_count = count_parsed_messages(3, r1, r2, r3);
3445
3446   char total[ strlen(r1->raw)
3447             + strlen(r2->raw)
3448             + strlen(r3->raw)
3449             + 1
3450             ];
3451   total[0] = '\0';
3452
3453   strcat(total, r1->raw);
3454   strcat(total, r2->raw);
3455   strcat(total, r3->raw);
3456
3457   parser_init(r1->type);
3458
3459   size_t read;
3460
3461   read = parse(total, strlen(total));
3462
3463   if (parser->upgrade) {
3464     upgrade_message_fix(total, read, 3, r1, r2, r3);
3465     goto test;
3466   }
3467
3468   if (read != strlen(total)) {
3469     print_error(total, read);
3470     abort();
3471   }
3472
3473   read = parse(NULL, 0);
3474
3475   if (read != 0) {
3476     print_error(total, read);
3477     abort();
3478   }
3479
3480 test:
3481
3482   if (message_count != num_messages) {
3483     fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
3484     abort();
3485   }
3486
3487   if (!message_eq(0, r1)) abort();
3488   if (message_count > 1 && !message_eq(1, r2)) abort();
3489   if (message_count > 2 && !message_eq(2, r3)) abort();
3490
3491   parser_free();
3492 }
3493
3494 /* SCAN through every possible breaking to make sure the
3495  * parser can handle getting the content in any chunks that
3496  * might come from the socket
3497  */
3498 void
3499 test_scan (const struct message *r1, const struct message *r2, const struct message *r3)
3500 {
3501   char total[80*1024] = "\0";
3502   char buf1[80*1024] = "\0";
3503   char buf2[80*1024] = "\0";
3504   char buf3[80*1024] = "\0";
3505
3506   strcat(total, r1->raw);
3507   strcat(total, r2->raw);
3508   strcat(total, r3->raw);
3509
3510   size_t read;
3511
3512   int total_len = strlen(total);
3513
3514   int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2;
3515   int ops = 0 ;
3516
3517   size_t buf1_len, buf2_len, buf3_len;
3518   int message_count = count_parsed_messages(3, r1, r2, r3);
3519
3520   int i,j,type_both;
3521   for (type_both = 0; type_both < 2; type_both ++ ) {
3522     for (j = 2; j < total_len; j ++ ) {
3523       for (i = 1; i < j; i ++ ) {
3524
3525         if (ops % 1000 == 0)  {
3526           printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops);
3527           fflush(stdout);
3528         }
3529         ops += 1;
3530
3531         parser_init(type_both ? HTTP_BOTH : r1->type);
3532
3533         buf1_len = i;
3534         strlncpy(buf1, sizeof(buf1), total, buf1_len);
3535         buf1[buf1_len] = 0;
3536
3537         buf2_len = j - i;
3538         strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
3539         buf2[buf2_len] = 0;
3540
3541         buf3_len = total_len - j;
3542         strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
3543         buf3[buf3_len] = 0;
3544
3545         read = parse(buf1, buf1_len);
3546
3547         if (parser->upgrade) goto test;
3548
3549         if (read != buf1_len) {
3550           print_error(buf1, read);
3551           goto error;
3552         }
3553
3554         read += parse(buf2, buf2_len);
3555
3556         if (parser->upgrade) goto test;
3557
3558         if (read != buf1_len + buf2_len) {
3559           print_error(buf2, read);
3560           goto error;
3561         }
3562
3563         read += parse(buf3, buf3_len);
3564
3565         if (parser->upgrade) goto test;
3566
3567         if (read != buf1_len + buf2_len + buf3_len) {
3568           print_error(buf3, read);
3569           goto error;
3570         }
3571
3572         parse(NULL, 0);
3573
3574 test:
3575         if (parser->upgrade) {
3576           upgrade_message_fix(total, read, 3, r1, r2, r3);
3577         }
3578
3579         if (message_count != num_messages) {
3580           fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
3581             message_count, num_messages);
3582           goto error;
3583         }
3584
3585         if (!message_eq(0, r1)) {
3586           fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
3587           goto error;
3588         }
3589
3590         if (message_count > 1 && !message_eq(1, r2)) {
3591           fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
3592           goto error;
3593         }
3594
3595         if (message_count > 2 && !message_eq(2, r3)) {
3596           fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
3597           goto error;
3598         }
3599
3600         parser_free();
3601       }
3602     }
3603   }
3604   puts("\b\b\b\b100%");
3605   return;
3606
3607  error:
3608   fprintf(stderr, "i=%d  j=%d\n", i, j);
3609   fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
3610   fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
3611   fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
3612   abort();
3613 }
3614
3615 // user required to free the result
3616 // string terminated by \0
3617 char *
3618 create_large_chunked_message (int body_size_in_kb, const char* headers)
3619 {
3620   int i;
3621   size_t wrote = 0;
3622   size_t headers_len = strlen(headers);
3623   size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6;
3624   char * buf = malloc(bufsize);
3625
3626   memcpy(buf, headers, headers_len);
3627   wrote += headers_len;
3628
3629   for (i = 0; i < body_size_in_kb; i++) {
3630     // write 1kb chunk into the body.
3631     memcpy(buf + wrote, "400\r\n", 5);
3632     wrote += 5;
3633     memset(buf + wrote, 'C', 1024);
3634     wrote += 1024;
3635     strcpy(buf + wrote, "\r\n");
3636     wrote += 2;
3637   }
3638
3639   memcpy(buf + wrote, "0\r\n\r\n", 6);
3640   wrote += 6;
3641   assert(wrote == bufsize);
3642
3643   return buf;
3644 }
3645
3646 /* Verify that we can pause parsing at any of the bytes in the
3647  * message and still get the result that we're expecting. */
3648 void
3649 test_message_pause (const struct message *msg)
3650 {
3651   char *buf = (char*) msg->raw;
3652   size_t buflen = strlen(msg->raw);
3653   size_t nread;
3654
3655   parser_init(msg->type);
3656
3657   do {
3658     nread = parse_pause(buf, buflen);
3659
3660     // We can only set the upgrade buffer once we've gotten our message
3661     // completion callback.
3662     if (messages[0].message_complete_cb_called &&
3663         msg->upgrade &&
3664         parser->upgrade) {
3665       messages[0].upgrade = buf + nread;
3666       goto test;
3667     }
3668
3669     if (nread < buflen) {
3670
3671       // Not much do to if we failed a strict-mode check
3672       if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
3673         parser_free();
3674         return;
3675       }
3676
3677       assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
3678     }
3679
3680     buf += nread;
3681     buflen -= nread;
3682     http_parser_pause(parser, 0);
3683   } while (buflen > 0);
3684
3685   nread = parse_pause(NULL, 0);
3686   assert (nread == 0);
3687
3688 test:
3689   if (num_messages != 1) {
3690     printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
3691     abort();
3692   }
3693
3694   if(!message_eq(0, msg)) abort();
3695
3696   parser_free();
3697 }
3698
3699 int
3700 main (void)
3701 {
3702   parser = NULL;
3703   int i, j, k;
3704   int request_count;
3705   int response_count;
3706   unsigned long version;
3707   unsigned major;
3708   unsigned minor;
3709   unsigned patch;
3710
3711   version = http_parser_version();
3712   major = (version >> 16) & 255;
3713   minor = (version >> 8) & 255;
3714   patch = version & 255;
3715   printf("http_parser v%u.%u.%u (0x%06lx)\n", major, minor, patch, version);
3716
3717   printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
3718
3719   for (request_count = 0; requests[request_count].name; request_count++);
3720   for (response_count = 0; responses[response_count].name; response_count++);
3721
3722   //// API
3723   test_preserve_data();
3724   test_parse_url();
3725   test_method_str();
3726
3727   //// NREAD
3728   test_header_nread_value();
3729
3730   //// OVERFLOW CONDITIONS
3731
3732   test_header_overflow_error(HTTP_REQUEST);
3733   test_no_overflow_long_body(HTTP_REQUEST, 1000);
3734   test_no_overflow_long_body(HTTP_REQUEST, 100000);
3735
3736   test_header_overflow_error(HTTP_RESPONSE);
3737   test_no_overflow_long_body(HTTP_RESPONSE, 1000);
3738   test_no_overflow_long_body(HTTP_RESPONSE, 100000);
3739
3740   test_header_content_length_overflow_error();
3741   test_chunk_content_length_overflow_error();
3742
3743   //// HEADER FIELD CONDITIONS
3744   test_double_content_length_error(HTTP_REQUEST);
3745   test_chunked_content_length_error(HTTP_REQUEST);
3746   test_header_cr_no_lf_error(HTTP_REQUEST);
3747   test_invalid_header_field_token_error(HTTP_REQUEST);
3748   test_invalid_header_field_content_error(HTTP_REQUEST);
3749   test_double_content_length_error(HTTP_RESPONSE);
3750   test_chunked_content_length_error(HTTP_RESPONSE);
3751   test_header_cr_no_lf_error(HTTP_RESPONSE);
3752   test_invalid_header_field_token_error(HTTP_RESPONSE);
3753   test_invalid_header_field_content_error(HTTP_RESPONSE);
3754
3755   //// RESPONSES
3756
3757   for (i = 0; i < response_count; i++) {
3758     test_message(&responses[i]);
3759   }
3760
3761   for (i = 0; i < response_count; i++) {
3762     test_message_pause(&responses[i]);
3763   }
3764
3765   for (i = 0; i < response_count; i++) {
3766     if (!responses[i].should_keep_alive) continue;
3767     for (j = 0; j < response_count; j++) {
3768       if (!responses[j].should_keep_alive) continue;
3769       for (k = 0; k < response_count; k++) {
3770         test_multiple3(&responses[i], &responses[j], &responses[k]);
3771       }
3772     }
3773   }
3774
3775   test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
3776   test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
3777
3778   // test very large chunked response
3779   {
3780     char * msg = create_large_chunked_message(31337,
3781       "HTTP/1.0 200 OK\r\n"
3782       "Transfer-Encoding: chunked\r\n"
3783       "Content-Type: text/plain\r\n"
3784       "\r\n");
3785     struct message large_chunked =
3786       {.name= "large chunked"
3787       ,.type= HTTP_RESPONSE
3788       ,.raw= msg
3789       ,.should_keep_alive= FALSE
3790       ,.message_complete_on_eof= FALSE
3791       ,.http_major= 1
3792       ,.http_minor= 0
3793       ,.status_code= 200
3794       ,.response_status= "OK"
3795       ,.num_headers= 2
3796       ,.headers=
3797         { { "Transfer-Encoding", "chunked" }
3798         , { "Content-Type", "text/plain" }
3799         }
3800       ,.body_size= 31337*1024
3801       ,.num_chunks_complete= 31338
3802       };
3803     for (i = 0; i < MAX_CHUNKS; i++) {
3804       large_chunked.chunk_lengths[i] = 1024;
3805     }
3806     test_message_count_body(&large_chunked);
3807     free(msg);
3808   }
3809
3810
3811
3812   printf("response scan 1/2      ");
3813   test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
3814            , &responses[NO_BODY_HTTP10_KA_204]
3815            , &responses[NO_REASON_PHRASE]
3816            );
3817
3818   printf("response scan 2/2      ");
3819   test_scan( &responses[BONJOUR_MADAME_FR]
3820            , &responses[UNDERSTORE_HEADER_KEY]
3821            , &responses[NO_CARRIAGE_RET]
3822            );
3823
3824   puts("responses okay");
3825
3826
3827   /// REQUESTS
3828
3829   test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
3830
3831   // Well-formed but incomplete
3832   test_simple("GET / HTTP/1.1\r\n"
3833               "Content-Type: text/plain\r\n"
3834               "Content-Length: 6\r\n"
3835               "\r\n"
3836               "fooba",
3837               HPE_OK);
3838
3839   static const char *all_methods[] = {
3840     "DELETE",
3841     "GET",
3842     "HEAD",
3843     "POST",
3844     "PUT",
3845     //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel
3846     "OPTIONS",
3847     "TRACE",
3848     "COPY",
3849     "LOCK",
3850     "MKCOL",
3851     "MOVE",
3852     "PROPFIND",
3853     "PROPPATCH",
3854     "UNLOCK",
3855     "REPORT",
3856     "MKACTIVITY",
3857     "CHECKOUT",
3858     "MERGE",
3859     "M-SEARCH",
3860     "NOTIFY",
3861     "SUBSCRIBE",
3862     "UNSUBSCRIBE",
3863     "PATCH",
3864     0 };
3865   const char **this_method;
3866   for (this_method = all_methods; *this_method; this_method++) {
3867     char buf[200];
3868     sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
3869     test_simple(buf, HPE_OK);
3870   }
3871
3872   static const char *bad_methods[] = {
3873       "ASDF",
3874       "C******",
3875       "COLA",
3876       "GEM",
3877       "GETA",
3878       "M****",
3879       "MKCOLA",
3880       "PROPPATCHA",
3881       "PUN",
3882       "PX",
3883       "SA",
3884       "hello world",
3885       0 };
3886   for (this_method = bad_methods; *this_method; this_method++) {
3887     char buf[200];
3888     sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
3889     test_simple(buf, HPE_INVALID_METHOD);
3890   }
3891
3892   // illegal header field name line folding
3893   test_simple("GET / HTTP/1.1\r\n"
3894               "name\r\n"
3895               " : value\r\n"
3896               "\r\n",
3897               HPE_INVALID_HEADER_TOKEN);
3898
3899   const char *dumbfuck2 =
3900     "GET / HTTP/1.1\r\n"
3901     "X-SSL-Bullshit:   -----BEGIN CERTIFICATE-----\r\n"
3902     "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
3903     "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
3904     "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
3905     "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n"
3906     "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n"
3907     "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n"
3908     "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n"
3909     "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n"
3910     "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n"
3911     "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n"
3912     "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n"
3913     "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n"
3914     "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n"
3915     "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n"
3916     "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n"
3917     "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n"
3918     "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n"
3919     "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n"
3920     "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n"
3921     "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n"
3922     "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n"
3923     "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n"
3924     "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n"
3925     "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n"
3926     "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n"
3927     "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n"
3928     "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n"
3929     "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n"
3930     "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n"
3931     "\tRA==\r\n"
3932     "\t-----END CERTIFICATE-----\r\n"
3933     "\r\n";
3934   test_simple(dumbfuck2, HPE_OK);
3935
3936   const char *corrupted_connection =
3937     "GET / HTTP/1.1\r\n"
3938     "Host: www.example.com\r\n"
3939     "Connection\r\033\065\325eep-Alive\r\n"
3940     "Accept-Encoding: gzip\r\n"
3941     "\r\n";
3942   test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
3943
3944   const char *corrupted_header_name =
3945     "GET / HTTP/1.1\r\n"
3946     "Host: www.example.com\r\n"
3947     "X-Some-Header\r\033\065\325eep-Alive\r\n"
3948     "Accept-Encoding: gzip\r\n"
3949     "\r\n";
3950   test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
3951
3952 #if 0
3953   // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
3954   // until EOF.
3955   //
3956   // no content-length
3957   // error if there is a body without content length
3958   const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n"
3959                                            "Accept: */*\r\n"
3960                                            "\r\n"
3961                                            "HELLO";
3962   test_simple(bad_get_no_headers_no_body, 0);
3963 #endif
3964   /* TODO sending junk and large headers gets rejected */
3965
3966
3967   /* check to make sure our predefined requests are okay */
3968   for (i = 0; requests[i].name; i++) {
3969     test_message(&requests[i]);
3970   }
3971
3972   for (i = 0; i < request_count; i++) {
3973     test_message_pause(&requests[i]);
3974   }
3975
3976   for (i = 0; i < request_count; i++) {
3977     if (!requests[i].should_keep_alive) continue;
3978     for (j = 0; j < request_count; j++) {
3979       if (!requests[j].should_keep_alive) continue;
3980       for (k = 0; k < request_count; k++) {
3981         test_multiple3(&requests[i], &requests[j], &requests[k]);
3982       }
3983     }
3984   }
3985
3986   printf("request scan 1/4      ");
3987   test_scan( &requests[GET_NO_HEADERS_NO_BODY]
3988            , &requests[GET_ONE_HEADER_NO_BODY]
3989            , &requests[GET_NO_HEADERS_NO_BODY]
3990            );
3991
3992   printf("request scan 2/4      ");
3993   test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE]
3994            , &requests[POST_IDENTITY_BODY_WORLD]
3995            , &requests[GET_FUNKY_CONTENT_LENGTH]
3996            );
3997
3998   printf("request scan 3/4      ");
3999   test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
4000            , &requests[CHUNKED_W_TRAILING_HEADERS]
4001            , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
4002            );
4003
4004   printf("request scan 4/4      ");
4005   test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET]
4006            , &requests[PREFIX_NEWLINE_GET ]
4007            , &requests[CONNECT_REQUEST]
4008            );
4009
4010   puts("requests okay");
4011
4012   return 0;
4013 }