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