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