http_parser.rb 0.5.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/linux.yml +23 -0
- data/.github/workflows/windows.yml +23 -0
- data/.gitignore +5 -4
- data/.gitmodules +4 -4
- data/Gemfile +1 -1
- data/README.md +52 -47
- data/Rakefile +1 -0
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/extconf.rb +1 -1
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
- data/ext/ruby_http_parser/ruby_http_parser.c +40 -41
- data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
- data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
- data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
- data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
- data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
- data/http_parser.rb.gemspec +14 -7
- data/spec/parser_spec.rb +196 -102
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +202 -36
- data/tasks/compile.rake +2 -2
- data/tasks/fixtures.rake +8 -2
- data/tasks/spec.rake +1 -1
- metadata +141 -134
- data/Gemfile.lock +0 -32
- data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
- data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
@@ -26,16 +26,23 @@
|
|
26
26
|
#include <string.h>
|
27
27
|
#include <stdarg.h>
|
28
28
|
|
29
|
+
#if defined(__APPLE__)
|
30
|
+
# undef strlncpy
|
31
|
+
#endif /* defined(__APPLE__) */
|
32
|
+
|
29
33
|
#undef TRUE
|
30
34
|
#define TRUE 1
|
31
35
|
#undef FALSE
|
32
36
|
#define FALSE 0
|
33
37
|
|
34
38
|
#define MAX_HEADERS 13
|
35
|
-
#define MAX_ELEMENT_SIZE
|
39
|
+
#define MAX_ELEMENT_SIZE 2048
|
40
|
+
#define MAX_CHUNKS 16
|
36
41
|
|
37
42
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
38
43
|
|
44
|
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
45
|
+
|
39
46
|
static http_parser *parser;
|
40
47
|
|
41
48
|
struct message {
|
@@ -44,18 +51,26 @@ struct message {
|
|
44
51
|
enum http_parser_type type;
|
45
52
|
enum http_method method;
|
46
53
|
int status_code;
|
54
|
+
char response_status[MAX_ELEMENT_SIZE];
|
47
55
|
char request_path[MAX_ELEMENT_SIZE];
|
48
56
|
char request_url[MAX_ELEMENT_SIZE];
|
49
57
|
char fragment[MAX_ELEMENT_SIZE];
|
50
58
|
char query_string[MAX_ELEMENT_SIZE];
|
51
59
|
char body[MAX_ELEMENT_SIZE];
|
52
60
|
size_t body_size;
|
61
|
+
const char *host;
|
62
|
+
const char *userinfo;
|
63
|
+
uint16_t port;
|
53
64
|
int num_headers;
|
54
65
|
enum { NONE=0, FIELD, VALUE } last_header_element;
|
55
66
|
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
56
67
|
int should_keep_alive;
|
57
68
|
|
58
|
-
int
|
69
|
+
int num_chunks;
|
70
|
+
int num_chunks_complete;
|
71
|
+
int chunk_lengths[MAX_CHUNKS];
|
72
|
+
|
73
|
+
const char *upgrade; // upgraded body
|
59
74
|
|
60
75
|
unsigned short http_major;
|
61
76
|
unsigned short http_minor;
|
@@ -63,13 +78,16 @@ struct message {
|
|
63
78
|
int message_begin_cb_called;
|
64
79
|
int headers_complete_cb_called;
|
65
80
|
int message_complete_cb_called;
|
81
|
+
int status_cb_called;
|
66
82
|
int message_complete_on_eof;
|
83
|
+
int body_is_final;
|
67
84
|
};
|
68
85
|
|
69
86
|
static int currently_parsing_eof;
|
70
87
|
|
71
88
|
static struct message messages[5];
|
72
89
|
static int num_messages;
|
90
|
+
static http_parser_settings *current_pause_parser;
|
73
91
|
|
74
92
|
/* * R E Q U E S T S * */
|
75
93
|
const struct message requests[] =
|
@@ -289,6 +307,8 @@ const struct message requests[] =
|
|
289
307
|
{ { "Transfer-Encoding" , "chunked" }
|
290
308
|
}
|
291
309
|
,.body= "all your base are belong to us"
|
310
|
+
,.num_chunks_complete= 2
|
311
|
+
,.chunk_lengths= { 0x1e }
|
292
312
|
}
|
293
313
|
|
294
314
|
#define TWO_CHUNKS_MULT_ZERO_END 9
|
@@ -315,6 +335,8 @@ const struct message requests[] =
|
|
315
335
|
{ { "Transfer-Encoding", "chunked" }
|
316
336
|
}
|
317
337
|
,.body= "hello world"
|
338
|
+
,.num_chunks_complete= 3
|
339
|
+
,.chunk_lengths= { 5, 6 }
|
318
340
|
}
|
319
341
|
|
320
342
|
#define CHUNKED_W_TRAILING_HEADERS 10
|
@@ -345,6 +367,8 @@ const struct message requests[] =
|
|
345
367
|
, { "Content-Type", "text/plain" }
|
346
368
|
}
|
347
369
|
,.body= "hello world"
|
370
|
+
,.num_chunks_complete= 3
|
371
|
+
,.chunk_lengths= { 5, 6 }
|
348
372
|
}
|
349
373
|
|
350
374
|
#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
|
@@ -371,6 +395,8 @@ const struct message requests[] =
|
|
371
395
|
{ { "Transfer-Encoding", "chunked" }
|
372
396
|
}
|
373
397
|
,.body= "hello world"
|
398
|
+
,.num_chunks_complete= 3
|
399
|
+
,.chunk_lengths= { 5, 6 }
|
374
400
|
}
|
375
401
|
|
376
402
|
#define WITH_QUOTES 12
|
@@ -473,6 +499,7 @@ const struct message requests[] =
|
|
473
499
|
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
|
474
500
|
"Origin: http://example.com\r\n"
|
475
501
|
"\r\n"
|
502
|
+
"Hot diggity dogg"
|
476
503
|
,.should_keep_alive= TRUE
|
477
504
|
,.message_complete_on_eof= FALSE
|
478
505
|
,.http_major= 1
|
@@ -483,7 +510,7 @@ const struct message requests[] =
|
|
483
510
|
,.request_path= "/demo"
|
484
511
|
,.request_url= "/demo"
|
485
512
|
,.num_headers= 7
|
486
|
-
,.upgrade=
|
513
|
+
,.upgrade="Hot diggity dogg"
|
487
514
|
,.headers= { { "Host", "example.com" }
|
488
515
|
, { "Connection", "Upgrade" }
|
489
516
|
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
|
@@ -498,10 +525,12 @@ const struct message requests[] =
|
|
498
525
|
#define CONNECT_REQUEST 17
|
499
526
|
, {.name = "connect request"
|
500
527
|
,.type= HTTP_REQUEST
|
501
|
-
,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
|
528
|
+
,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
|
502
529
|
"User-agent: Mozilla/1.1N\r\n"
|
503
530
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
504
531
|
"\r\n"
|
532
|
+
"some data\r\n"
|
533
|
+
"and yet even more data"
|
505
534
|
,.should_keep_alive= FALSE
|
506
535
|
,.message_complete_on_eof= FALSE
|
507
536
|
,.http_major= 1
|
@@ -510,9 +539,9 @@ const struct message requests[] =
|
|
510
539
|
,.query_string= ""
|
511
540
|
,.fragment= ""
|
512
541
|
,.request_path= ""
|
513
|
-
,.request_url= "home0.netscape.com:443"
|
542
|
+
,.request_url= "0-home0.netscape.com:443"
|
514
543
|
,.num_headers= 2
|
515
|
-
,.upgrade=
|
544
|
+
,.upgrade="some data\r\nand yet even more data"
|
516
545
|
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
517
546
|
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
518
547
|
}
|
@@ -582,27 +611,44 @@ const struct message requests[] =
|
|
582
611
|
,.body= ""
|
583
612
|
}
|
584
613
|
|
585
|
-
#define
|
586
|
-
, {.name= "
|
614
|
+
#define LINE_FOLDING_IN_HEADER 21
|
615
|
+
, {.name= "line folding in header value"
|
587
616
|
,.type= HTTP_REQUEST
|
588
|
-
,.raw= "GET
|
589
|
-
"
|
617
|
+
,.raw= "GET / HTTP/1.1\r\n"
|
618
|
+
"Line1: abc\r\n"
|
619
|
+
"\tdef\r\n"
|
620
|
+
" ghi\r\n"
|
621
|
+
"\t\tjkl\r\n"
|
622
|
+
" mno \r\n"
|
623
|
+
"\t \tqrs\r\n"
|
624
|
+
"Line2: \t line2\t\r\n"
|
625
|
+
"Line3:\r\n"
|
626
|
+
" line3\r\n"
|
627
|
+
"Line4: \r\n"
|
628
|
+
" \r\n"
|
629
|
+
"Connection:\r\n"
|
630
|
+
" close\r\n"
|
590
631
|
"\r\n"
|
591
|
-
,.should_keep_alive=
|
632
|
+
,.should_keep_alive= FALSE
|
592
633
|
,.message_complete_on_eof= FALSE
|
593
634
|
,.http_major= 1
|
594
635
|
,.http_minor= 1
|
595
636
|
,.method= HTTP_GET
|
596
|
-
,.query_string= "
|
597
|
-
,.fragment= "
|
598
|
-
,.request_path= "
|
599
|
-
,.request_url= "
|
600
|
-
,.num_headers=
|
601
|
-
,.headers= { {"
|
637
|
+
,.query_string= ""
|
638
|
+
,.fragment= ""
|
639
|
+
,.request_path= "/"
|
640
|
+
,.request_url= "/"
|
641
|
+
,.num_headers= 5
|
642
|
+
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
|
643
|
+
, { "Line2", "line2\t" }
|
644
|
+
, { "Line3", "line3" }
|
645
|
+
, { "Line4", "" }
|
646
|
+
, { "Connection", "close" },
|
602
647
|
}
|
603
648
|
,.body= ""
|
604
649
|
}
|
605
650
|
|
651
|
+
|
606
652
|
#define QUERY_TERMINATED_HOST 22
|
607
653
|
, {.name= "host terminated by a query string"
|
608
654
|
,.type= HTTP_REQUEST
|
@@ -617,6 +663,7 @@ const struct message requests[] =
|
|
617
663
|
,.fragment= ""
|
618
664
|
,.request_path= ""
|
619
665
|
,.request_url= "http://hypnotoad.org?hail=all"
|
666
|
+
,.host= "hypnotoad.org"
|
620
667
|
,.num_headers= 0
|
621
668
|
,.headers= { }
|
622
669
|
,.body= ""
|
@@ -636,6 +683,8 @@ const struct message requests[] =
|
|
636
683
|
,.fragment= ""
|
637
684
|
,.request_path= ""
|
638
685
|
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
686
|
+
,.host= "hypnotoad.org"
|
687
|
+
,.port= 1234
|
639
688
|
,.num_headers= 0
|
640
689
|
,.headers= { }
|
641
690
|
,.body= ""
|
@@ -655,405 +704,1317 @@ const struct message requests[] =
|
|
655
704
|
,.fragment= ""
|
656
705
|
,.request_path= ""
|
657
706
|
,.request_url= "http://hypnotoad.org:1234"
|
707
|
+
,.host= "hypnotoad.org"
|
708
|
+
,.port= 1234
|
658
709
|
,.num_headers= 0
|
659
710
|
,.headers= { }
|
660
711
|
,.body= ""
|
661
712
|
}
|
662
713
|
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
|
672
|
-
"Location: http://www.google.com/\r\n"
|
673
|
-
"Content-Type: text/html; charset=UTF-8\r\n"
|
674
|
-
"Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
|
675
|
-
"Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
|
676
|
-
"X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
|
677
|
-
"Cache-Control: public, max-age=2592000\r\n"
|
678
|
-
"Server: gws\r\n"
|
679
|
-
"Content-Length: 219 \r\n"
|
714
|
+
#define PATCH_REQ 25
|
715
|
+
, {.name = "PATCH request"
|
716
|
+
,.type= HTTP_REQUEST
|
717
|
+
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
|
718
|
+
"Host: www.example.com\r\n"
|
719
|
+
"Content-Type: application/example\r\n"
|
720
|
+
"If-Match: \"e0023aa4e\"\r\n"
|
721
|
+
"Content-Length: 10\r\n"
|
680
722
|
"\r\n"
|
681
|
-
"
|
682
|
-
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
683
|
-
"<H1>301 Moved</H1>\n"
|
684
|
-
"The document has moved\n"
|
685
|
-
"<A HREF=\"http://www.google.com/\">here</A>.\r\n"
|
686
|
-
"</BODY></HTML>\r\n"
|
723
|
+
"cccccccccc"
|
687
724
|
,.should_keep_alive= TRUE
|
688
725
|
,.message_complete_on_eof= FALSE
|
689
726
|
,.http_major= 1
|
690
727
|
,.http_minor= 1
|
691
|
-
,.
|
692
|
-
,.
|
693
|
-
,.
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
704
|
-
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
705
|
-
"<H1>301 Moved</H1>\n"
|
706
|
-
"The document has moved\n"
|
707
|
-
"<A HREF=\"http://www.google.com/\">here</A>.\r\n"
|
708
|
-
"</BODY></HTML>\r\n"
|
728
|
+
,.method= HTTP_PATCH
|
729
|
+
,.query_string= ""
|
730
|
+
,.fragment= ""
|
731
|
+
,.request_path= "/file.txt"
|
732
|
+
,.request_url= "/file.txt"
|
733
|
+
,.num_headers= 4
|
734
|
+
,.headers= { { "Host", "www.example.com" }
|
735
|
+
, { "Content-Type", "application/example" }
|
736
|
+
, { "If-Match", "\"e0023aa4e\"" }
|
737
|
+
, { "Content-Length", "10" }
|
738
|
+
}
|
739
|
+
,.body= "cccccccccc"
|
709
740
|
}
|
710
741
|
|
711
|
-
#define
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
, {.name= "no content-length response"
|
718
|
-
,.type= HTTP_RESPONSE
|
719
|
-
,.raw= "HTTP/1.1 200 OK\r\n"
|
720
|
-
"Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
|
721
|
-
"Server: Apache\r\n"
|
722
|
-
"X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
|
723
|
-
"Content-Type: text/xml; charset=utf-8\r\n"
|
724
|
-
"Connection: close\r\n"
|
742
|
+
#define CONNECT_CAPS_REQUEST 26
|
743
|
+
, {.name = "connect caps request"
|
744
|
+
,.type= HTTP_REQUEST
|
745
|
+
,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
|
746
|
+
"User-agent: Mozilla/1.1N\r\n"
|
747
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
725
748
|
"\r\n"
|
726
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
727
|
-
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
|
728
|
-
" <SOAP-ENV:Body>\n"
|
729
|
-
" <SOAP-ENV:Fault>\n"
|
730
|
-
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
731
|
-
" <faultstring>Client Error</faultstring>\n"
|
732
|
-
" </SOAP-ENV:Fault>\n"
|
733
|
-
" </SOAP-ENV:Body>\n"
|
734
|
-
"</SOAP-ENV:Envelope>"
|
735
749
|
,.should_keep_alive= FALSE
|
736
|
-
,.message_complete_on_eof=
|
750
|
+
,.message_complete_on_eof= FALSE
|
737
751
|
,.http_major= 1
|
738
|
-
,.http_minor=
|
739
|
-
,.
|
740
|
-
,.
|
741
|
-
,.
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
" <SOAP-ENV:Body>\n"
|
751
|
-
" <SOAP-ENV:Fault>\n"
|
752
|
-
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
753
|
-
" <faultstring>Client Error</faultstring>\n"
|
754
|
-
" </SOAP-ENV:Fault>\n"
|
755
|
-
" </SOAP-ENV:Body>\n"
|
756
|
-
"</SOAP-ENV:Envelope>"
|
752
|
+
,.http_minor= 0
|
753
|
+
,.method= HTTP_CONNECT
|
754
|
+
,.query_string= ""
|
755
|
+
,.fragment= ""
|
756
|
+
,.request_path= ""
|
757
|
+
,.request_url= "HOME0.NETSCAPE.COM:443"
|
758
|
+
,.num_headers= 2
|
759
|
+
,.upgrade=""
|
760
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
761
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
762
|
+
}
|
763
|
+
,.body= ""
|
757
764
|
}
|
758
765
|
|
759
|
-
#
|
760
|
-
|
761
|
-
|
762
|
-
,.
|
766
|
+
#if !HTTP_PARSER_STRICT
|
767
|
+
#define UTF8_PATH_REQ 27
|
768
|
+
, {.name= "utf-8 path request"
|
769
|
+
,.type= HTTP_REQUEST
|
770
|
+
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
|
771
|
+
"Host: github.com\r\n"
|
772
|
+
"\r\n"
|
763
773
|
,.should_keep_alive= TRUE
|
764
774
|
,.message_complete_on_eof= FALSE
|
765
775
|
,.http_major= 1
|
766
776
|
,.http_minor= 1
|
767
|
-
,.
|
768
|
-
,.
|
769
|
-
,.
|
770
|
-
,.
|
777
|
+
,.method= HTTP_GET
|
778
|
+
,.query_string= "q=1"
|
779
|
+
,.fragment= "narf"
|
780
|
+
,.request_path= "/δ¶/δt/pope"
|
781
|
+
,.request_url= "/δ¶/δt/pope?q=1#narf"
|
782
|
+
,.num_headers= 1
|
783
|
+
,.headers= { {"Host", "github.com" }
|
784
|
+
}
|
771
785
|
,.body= ""
|
772
786
|
}
|
773
787
|
|
774
|
-
#define
|
775
|
-
, {.name= "
|
776
|
-
,.type=
|
777
|
-
,.raw= "HTTP/1.
|
778
|
-
|
788
|
+
#define HOSTNAME_UNDERSCORE 28
|
789
|
+
, {.name = "hostname underscore"
|
790
|
+
,.type= HTTP_REQUEST
|
791
|
+
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
|
792
|
+
"User-agent: Mozilla/1.1N\r\n"
|
793
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
794
|
+
"\r\n"
|
795
|
+
,.should_keep_alive= FALSE
|
779
796
|
,.message_complete_on_eof= FALSE
|
780
797
|
,.http_major= 1
|
781
|
-
,.http_minor=
|
782
|
-
,.
|
783
|
-
,.
|
784
|
-
,.
|
798
|
+
,.http_minor= 0
|
799
|
+
,.method= HTTP_CONNECT
|
800
|
+
,.query_string= ""
|
801
|
+
,.fragment= ""
|
802
|
+
,.request_path= ""
|
803
|
+
,.request_url= "home_0.netscape.com:443"
|
804
|
+
,.num_headers= 2
|
805
|
+
,.upgrade=""
|
806
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
807
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
808
|
+
}
|
785
809
|
,.body= ""
|
786
810
|
}
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
"
|
794
|
-
"\r\n"
|
795
|
-
"
|
796
|
-
"This is the data in the first chunk\r\n"
|
797
|
-
"\r\n"
|
798
|
-
"1C\r\n"
|
799
|
-
"and this is the second one\r\n"
|
800
|
-
"\r\n"
|
801
|
-
"0 \r\n"
|
811
|
+
#endif /* !HTTP_PARSER_STRICT */
|
812
|
+
|
813
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
814
|
+
#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
|
815
|
+
, {.name = "eat CRLF between requests, no \"Connection: close\" header"
|
816
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
817
|
+
"Host: www.example.com\r\n"
|
818
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
819
|
+
"Content-Length: 4\r\n"
|
802
820
|
"\r\n"
|
821
|
+
"q=42\r\n" /* note the trailing CRLF */
|
803
822
|
,.should_keep_alive= TRUE
|
804
823
|
,.message_complete_on_eof= FALSE
|
805
824
|
,.http_major= 1
|
806
825
|
,.http_minor= 1
|
807
|
-
,.
|
808
|
-
,.
|
809
|
-
,.
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
,.
|
814
|
-
,.
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
#define NO_CARRIAGE_RET 5
|
821
|
-
, {.name="no carriage ret"
|
822
|
-
,.type= HTTP_RESPONSE
|
823
|
-
,.raw= "HTTP/1.1 200 OK\n"
|
824
|
-
"Content-Type: text/html; charset=utf-8\n"
|
825
|
-
"Connection: close\n"
|
826
|
-
"\n"
|
827
|
-
"these headers are from http://news.ycombinator.com/"
|
828
|
-
,.should_keep_alive= FALSE
|
829
|
-
,.message_complete_on_eof= TRUE
|
830
|
-
,.http_major= 1
|
831
|
-
,.http_minor= 1
|
832
|
-
,.status_code= 200
|
833
|
-
,.num_headers= 2
|
834
|
-
,.headers=
|
835
|
-
{ {"Content-Type", "text/html; charset=utf-8" }
|
836
|
-
, {"Connection", "close" }
|
837
|
-
}
|
838
|
-
,.body= "these headers are from http://news.ycombinator.com/"
|
826
|
+
,.method= HTTP_POST
|
827
|
+
,.query_string= ""
|
828
|
+
,.fragment= ""
|
829
|
+
,.request_path= "/"
|
830
|
+
,.request_url= "/"
|
831
|
+
,.num_headers= 3
|
832
|
+
,.upgrade= 0
|
833
|
+
,.headers= { { "Host", "www.example.com" }
|
834
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
835
|
+
, { "Content-Length", "4" }
|
836
|
+
}
|
837
|
+
,.body= "q=42"
|
839
838
|
}
|
840
839
|
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
,.raw= "HTTP/1.1
|
845
|
-
"
|
846
|
-
"Content-
|
847
|
-
"
|
848
|
-
"
|
840
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
841
|
+
#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
|
842
|
+
, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
|
843
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
844
|
+
"Host: www.example.com\r\n"
|
845
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
846
|
+
"Content-Length: 4\r\n"
|
847
|
+
"Connection: close\r\n"
|
849
848
|
"\r\n"
|
850
|
-
"
|
849
|
+
"q=42\r\n" /* note the trailing CRLF */
|
851
850
|
,.should_keep_alive= FALSE
|
852
|
-
,.message_complete_on_eof= FALSE
|
851
|
+
,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
|
853
852
|
,.http_major= 1
|
854
853
|
,.http_minor= 1
|
855
|
-
,.
|
854
|
+
,.method= HTTP_POST
|
855
|
+
,.query_string= ""
|
856
|
+
,.fragment= ""
|
857
|
+
,.request_path= "/"
|
858
|
+
,.request_url= "/"
|
856
859
|
,.num_headers= 4
|
857
|
-
,.
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
,.body= "
|
860
|
+
,.upgrade= 0
|
861
|
+
,.headers= { { "Host", "www.example.com" }
|
862
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
863
|
+
, { "Content-Length", "4" }
|
864
|
+
, { "Connection", "close" }
|
865
|
+
}
|
866
|
+
,.body= "q=42"
|
864
867
|
}
|
865
868
|
|
866
|
-
#define
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
"Server: DCLK-AdSvr\r\n"
|
873
|
-
"Content-Type: text/xml\r\n"
|
874
|
-
"Content-Length: 0\r\n"
|
875
|
-
"DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
|
869
|
+
#define PURGE_REQ 31
|
870
|
+
, {.name = "PURGE request"
|
871
|
+
,.type= HTTP_REQUEST
|
872
|
+
,.raw= "PURGE /file.txt HTTP/1.1\r\n"
|
873
|
+
"Host: www.example.com\r\n"
|
874
|
+
"\r\n"
|
876
875
|
,.should_keep_alive= TRUE
|
877
876
|
,.message_complete_on_eof= FALSE
|
878
877
|
,.http_major= 1
|
879
878
|
,.http_minor= 1
|
879
|
+
,.method= HTTP_PURGE
|
880
|
+
,.query_string= ""
|
881
|
+
,.fragment= ""
|
882
|
+
,.request_path= "/file.txt"
|
883
|
+
,.request_url= "/file.txt"
|
884
|
+
,.num_headers= 1
|
885
|
+
,.headers= { { "Host", "www.example.com" } }
|
886
|
+
,.body= ""
|
887
|
+
}
|
888
|
+
|
889
|
+
#define SEARCH_REQ 32
|
890
|
+
, {.name = "SEARCH request"
|
891
|
+
,.type= HTTP_REQUEST
|
892
|
+
,.raw= "SEARCH / HTTP/1.1\r\n"
|
893
|
+
"Host: www.example.com\r\n"
|
894
|
+
"\r\n"
|
895
|
+
,.should_keep_alive= TRUE
|
896
|
+
,.message_complete_on_eof= FALSE
|
897
|
+
,.http_major= 1
|
898
|
+
,.http_minor= 1
|
899
|
+
,.method= HTTP_SEARCH
|
900
|
+
,.query_string= ""
|
901
|
+
,.fragment= ""
|
902
|
+
,.request_path= "/"
|
903
|
+
,.request_url= "/"
|
904
|
+
,.num_headers= 1
|
905
|
+
,.headers= { { "Host", "www.example.com" } }
|
906
|
+
,.body= ""
|
907
|
+
}
|
908
|
+
|
909
|
+
#define PROXY_WITH_BASIC_AUTH 33
|
910
|
+
, {.name= "host:port and basic_auth"
|
911
|
+
,.type= HTTP_REQUEST
|
912
|
+
,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
|
913
|
+
"\r\n"
|
914
|
+
,.should_keep_alive= TRUE
|
915
|
+
,.message_complete_on_eof= FALSE
|
916
|
+
,.http_major= 1
|
917
|
+
,.http_minor= 1
|
918
|
+
,.method= HTTP_GET
|
919
|
+
,.fragment= ""
|
920
|
+
,.request_path= "/toto"
|
921
|
+
,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
|
922
|
+
,.host= "hypnotoad.org"
|
923
|
+
,.userinfo= "a%12:b!&*$"
|
924
|
+
,.port= 1234
|
925
|
+
,.num_headers= 0
|
926
|
+
,.headers= { }
|
927
|
+
,.body= ""
|
928
|
+
}
|
929
|
+
|
930
|
+
#define LINE_FOLDING_IN_HEADER_WITH_LF 34
|
931
|
+
, {.name= "line folding in header value"
|
932
|
+
,.type= HTTP_REQUEST
|
933
|
+
,.raw= "GET / HTTP/1.1\n"
|
934
|
+
"Line1: abc\n"
|
935
|
+
"\tdef\n"
|
936
|
+
" ghi\n"
|
937
|
+
"\t\tjkl\n"
|
938
|
+
" mno \n"
|
939
|
+
"\t \tqrs\n"
|
940
|
+
"Line2: \t line2\t\n"
|
941
|
+
"Line3:\n"
|
942
|
+
" line3\n"
|
943
|
+
"Line4: \n"
|
944
|
+
" \n"
|
945
|
+
"Connection:\n"
|
946
|
+
" close\n"
|
947
|
+
"\n"
|
948
|
+
,.should_keep_alive= FALSE
|
949
|
+
,.message_complete_on_eof= FALSE
|
950
|
+
,.http_major= 1
|
951
|
+
,.http_minor= 1
|
952
|
+
,.method= HTTP_GET
|
953
|
+
,.query_string= ""
|
954
|
+
,.fragment= ""
|
955
|
+
,.request_path= "/"
|
956
|
+
,.request_url= "/"
|
957
|
+
,.num_headers= 5
|
958
|
+
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
|
959
|
+
, { "Line2", "line2\t" }
|
960
|
+
, { "Line3", "line3" }
|
961
|
+
, { "Line4", "" }
|
962
|
+
, { "Connection", "close" },
|
963
|
+
}
|
964
|
+
,.body= ""
|
965
|
+
}
|
966
|
+
|
967
|
+
#define CONNECTION_MULTI 35
|
968
|
+
, {.name = "multiple connection header values with folding"
|
969
|
+
,.type= HTTP_REQUEST
|
970
|
+
,.raw= "GET /demo HTTP/1.1\r\n"
|
971
|
+
"Host: example.com\r\n"
|
972
|
+
"Connection: Something,\r\n"
|
973
|
+
" Upgrade, ,Keep-Alive\r\n"
|
974
|
+
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
|
975
|
+
"Sec-WebSocket-Protocol: sample\r\n"
|
976
|
+
"Upgrade: WebSocket\r\n"
|
977
|
+
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
|
978
|
+
"Origin: http://example.com\r\n"
|
979
|
+
"\r\n"
|
980
|
+
"Hot diggity dogg"
|
981
|
+
,.should_keep_alive= TRUE
|
982
|
+
,.message_complete_on_eof= FALSE
|
983
|
+
,.http_major= 1
|
984
|
+
,.http_minor= 1
|
985
|
+
,.method= HTTP_GET
|
986
|
+
,.query_string= ""
|
987
|
+
,.fragment= ""
|
988
|
+
,.request_path= "/demo"
|
989
|
+
,.request_url= "/demo"
|
990
|
+
,.num_headers= 7
|
991
|
+
,.upgrade="Hot diggity dogg"
|
992
|
+
,.headers= { { "Host", "example.com" }
|
993
|
+
, { "Connection", "Something, Upgrade, ,Keep-Alive" }
|
994
|
+
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
|
995
|
+
, { "Sec-WebSocket-Protocol", "sample" }
|
996
|
+
, { "Upgrade", "WebSocket" }
|
997
|
+
, { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
|
998
|
+
, { "Origin", "http://example.com" }
|
999
|
+
}
|
1000
|
+
,.body= ""
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
#define CONNECTION_MULTI_LWS 36
|
1004
|
+
, {.name = "multiple connection header values with folding and lws"
|
1005
|
+
,.type= HTTP_REQUEST
|
1006
|
+
,.raw= "GET /demo HTTP/1.1\r\n"
|
1007
|
+
"Connection: keep-alive, upgrade\r\n"
|
1008
|
+
"Upgrade: WebSocket\r\n"
|
1009
|
+
"\r\n"
|
1010
|
+
"Hot diggity dogg"
|
1011
|
+
,.should_keep_alive= TRUE
|
1012
|
+
,.message_complete_on_eof= FALSE
|
1013
|
+
,.http_major= 1
|
1014
|
+
,.http_minor= 1
|
1015
|
+
,.method= HTTP_GET
|
1016
|
+
,.query_string= ""
|
1017
|
+
,.fragment= ""
|
1018
|
+
,.request_path= "/demo"
|
1019
|
+
,.request_url= "/demo"
|
1020
|
+
,.num_headers= 2
|
1021
|
+
,.upgrade="Hot diggity dogg"
|
1022
|
+
,.headers= { { "Connection", "keep-alive, upgrade" }
|
1023
|
+
, { "Upgrade", "WebSocket" }
|
1024
|
+
}
|
1025
|
+
,.body= ""
|
1026
|
+
}
|
1027
|
+
|
1028
|
+
#define CONNECTION_MULTI_LWS_CRLF 37
|
1029
|
+
, {.name = "multiple connection header values with folding and lws"
|
1030
|
+
,.type= HTTP_REQUEST
|
1031
|
+
,.raw= "GET /demo HTTP/1.1\r\n"
|
1032
|
+
"Connection: keep-alive, \r\n upgrade\r\n"
|
1033
|
+
"Upgrade: WebSocket\r\n"
|
1034
|
+
"\r\n"
|
1035
|
+
"Hot diggity dogg"
|
1036
|
+
,.should_keep_alive= TRUE
|
1037
|
+
,.message_complete_on_eof= FALSE
|
1038
|
+
,.http_major= 1
|
1039
|
+
,.http_minor= 1
|
1040
|
+
,.method= HTTP_GET
|
1041
|
+
,.query_string= ""
|
1042
|
+
,.fragment= ""
|
1043
|
+
,.request_path= "/demo"
|
1044
|
+
,.request_url= "/demo"
|
1045
|
+
,.num_headers= 2
|
1046
|
+
,.upgrade="Hot diggity dogg"
|
1047
|
+
,.headers= { { "Connection", "keep-alive, upgrade" }
|
1048
|
+
, { "Upgrade", "WebSocket" }
|
1049
|
+
}
|
1050
|
+
,.body= ""
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
#define UPGRADE_POST_REQUEST 38
|
1054
|
+
, {.name = "upgrade post request"
|
1055
|
+
,.type= HTTP_REQUEST
|
1056
|
+
,.raw= "POST /demo HTTP/1.1\r\n"
|
1057
|
+
"Host: example.com\r\n"
|
1058
|
+
"Connection: Upgrade\r\n"
|
1059
|
+
"Upgrade: HTTP/2.0\r\n"
|
1060
|
+
"Content-Length: 15\r\n"
|
1061
|
+
"\r\n"
|
1062
|
+
"sweet post body"
|
1063
|
+
"Hot diggity dogg"
|
1064
|
+
,.should_keep_alive= TRUE
|
1065
|
+
,.message_complete_on_eof= FALSE
|
1066
|
+
,.http_major= 1
|
1067
|
+
,.http_minor= 1
|
1068
|
+
,.method= HTTP_POST
|
1069
|
+
,.request_path= "/demo"
|
1070
|
+
,.request_url= "/demo"
|
1071
|
+
,.num_headers= 4
|
1072
|
+
,.upgrade="Hot diggity dogg"
|
1073
|
+
,.headers= { { "Host", "example.com" }
|
1074
|
+
, { "Connection", "Upgrade" }
|
1075
|
+
, { "Upgrade", "HTTP/2.0" }
|
1076
|
+
, { "Content-Length", "15" }
|
1077
|
+
}
|
1078
|
+
,.body= "sweet post body"
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
#define CONNECT_WITH_BODY_REQUEST 39
|
1082
|
+
, {.name = "connect with body request"
|
1083
|
+
,.type= HTTP_REQUEST
|
1084
|
+
,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
|
1085
|
+
"User-agent: Mozilla/1.1N\r\n"
|
1086
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
1087
|
+
"Content-Length: 10\r\n"
|
1088
|
+
"\r\n"
|
1089
|
+
"blarfcicle"
|
1090
|
+
,.should_keep_alive= FALSE
|
1091
|
+
,.message_complete_on_eof= FALSE
|
1092
|
+
,.http_major= 1
|
1093
|
+
,.http_minor= 0
|
1094
|
+
,.method= HTTP_CONNECT
|
1095
|
+
,.request_url= "foo.bar.com:443"
|
1096
|
+
,.num_headers= 3
|
1097
|
+
,.upgrade="blarfcicle"
|
1098
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
1099
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
1100
|
+
, { "Content-Length", "10" }
|
1101
|
+
}
|
1102
|
+
,.body= ""
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
/* Examples from the Internet draft for LINK/UNLINK methods:
|
1106
|
+
* https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5
|
1107
|
+
*/
|
1108
|
+
|
1109
|
+
#define LINK_REQUEST 40
|
1110
|
+
, {.name = "link request"
|
1111
|
+
,.type= HTTP_REQUEST
|
1112
|
+
,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n"
|
1113
|
+
"Host: example.com\r\n"
|
1114
|
+
"Link: <http://example.com/profiles/joe>; rel=\"tag\"\r\n"
|
1115
|
+
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
|
1116
|
+
"\r\n"
|
1117
|
+
,.should_keep_alive= TRUE
|
1118
|
+
,.message_complete_on_eof= FALSE
|
1119
|
+
,.http_major= 1
|
1120
|
+
,.http_minor= 1
|
1121
|
+
,.method= HTTP_LINK
|
1122
|
+
,.request_path= "/images/my_dog.jpg"
|
1123
|
+
,.request_url= "/images/my_dog.jpg"
|
1124
|
+
,.query_string= ""
|
1125
|
+
,.fragment= ""
|
1126
|
+
,.num_headers= 3
|
1127
|
+
,.headers= { { "Host", "example.com" }
|
1128
|
+
, { "Link", "<http://example.com/profiles/joe>; rel=\"tag\"" }
|
1129
|
+
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
|
1130
|
+
}
|
1131
|
+
,.body= ""
|
1132
|
+
}
|
1133
|
+
|
1134
|
+
#define UNLINK_REQUEST 41
|
1135
|
+
, {.name = "unlink request"
|
1136
|
+
,.type= HTTP_REQUEST
|
1137
|
+
,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
|
1138
|
+
"Host: example.com\r\n"
|
1139
|
+
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
|
1140
|
+
"\r\n"
|
1141
|
+
,.should_keep_alive= TRUE
|
1142
|
+
,.message_complete_on_eof= FALSE
|
1143
|
+
,.http_major= 1
|
1144
|
+
,.http_minor= 1
|
1145
|
+
,.method= HTTP_UNLINK
|
1146
|
+
,.request_path= "/images/my_dog.jpg"
|
1147
|
+
,.request_url= "/images/my_dog.jpg"
|
1148
|
+
,.query_string= ""
|
1149
|
+
,.fragment= ""
|
1150
|
+
,.num_headers= 2
|
1151
|
+
,.headers= { { "Host", "example.com" }
|
1152
|
+
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
|
1153
|
+
}
|
1154
|
+
,.body= ""
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
#define SOURCE_REQUEST 42
|
1158
|
+
, {.name = "source request"
|
1159
|
+
,.type= HTTP_REQUEST
|
1160
|
+
,.raw= "SOURCE /music/sweet/music HTTP/1.1\r\n"
|
1161
|
+
"Host: example.com\r\n"
|
1162
|
+
"\r\n"
|
1163
|
+
,.should_keep_alive= TRUE
|
1164
|
+
,.message_complete_on_eof= FALSE
|
1165
|
+
,.http_major= 1
|
1166
|
+
,.http_minor= 1
|
1167
|
+
,.method= HTTP_SOURCE
|
1168
|
+
,.request_path= "/music/sweet/music"
|
1169
|
+
,.request_url= "/music/sweet/music"
|
1170
|
+
,.query_string= ""
|
1171
|
+
,.fragment= ""
|
1172
|
+
,.num_headers= 1
|
1173
|
+
,.headers= { { "Host", "example.com" } }
|
1174
|
+
,.body= ""
|
1175
|
+
}
|
1176
|
+
};
|
1177
|
+
|
1178
|
+
/* * R E S P O N S E S * */
|
1179
|
+
const struct message responses[] =
|
1180
|
+
#define GOOGLE_301 0
|
1181
|
+
{ {.name= "google 301"
|
1182
|
+
,.type= HTTP_RESPONSE
|
1183
|
+
,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
|
1184
|
+
"Location: http://www.google.com/\r\n"
|
1185
|
+
"Content-Type: text/html; charset=UTF-8\r\n"
|
1186
|
+
"Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
|
1187
|
+
"Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
|
1188
|
+
"X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
|
1189
|
+
"Cache-Control: public, max-age=2592000\r\n"
|
1190
|
+
"Server: gws\r\n"
|
1191
|
+
"Content-Length: 219 \r\n"
|
1192
|
+
"\r\n"
|
1193
|
+
"<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
1194
|
+
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
1195
|
+
"<H1>301 Moved</H1>\n"
|
1196
|
+
"The document has moved\n"
|
1197
|
+
"<A HREF=\"http://www.google.com/\">here</A>.\r\n"
|
1198
|
+
"</BODY></HTML>\r\n"
|
1199
|
+
,.should_keep_alive= TRUE
|
1200
|
+
,.message_complete_on_eof= FALSE
|
1201
|
+
,.http_major= 1
|
1202
|
+
,.http_minor= 1
|
1203
|
+
,.status_code= 301
|
1204
|
+
,.response_status= "Moved Permanently"
|
1205
|
+
,.num_headers= 8
|
1206
|
+
,.headers=
|
1207
|
+
{ { "Location", "http://www.google.com/" }
|
1208
|
+
, { "Content-Type", "text/html; charset=UTF-8" }
|
1209
|
+
, { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
|
1210
|
+
, { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
|
1211
|
+
, { "X-$PrototypeBI-Version", "1.6.0.3" }
|
1212
|
+
, { "Cache-Control", "public, max-age=2592000" }
|
1213
|
+
, { "Server", "gws" }
|
1214
|
+
, { "Content-Length", "219 " }
|
1215
|
+
}
|
1216
|
+
,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
1217
|
+
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
1218
|
+
"<H1>301 Moved</H1>\n"
|
1219
|
+
"The document has moved\n"
|
1220
|
+
"<A HREF=\"http://www.google.com/\">here</A>.\r\n"
|
1221
|
+
"</BODY></HTML>\r\n"
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
#define NO_CONTENT_LENGTH_RESPONSE 1
|
1225
|
+
/* The client should wait for the server's EOF. That is, when content-length
|
1226
|
+
* is not specified, and "Connection: close", the end of body is specified
|
1227
|
+
* by the EOF.
|
1228
|
+
* Compare with APACHEBENCH_GET
|
1229
|
+
*/
|
1230
|
+
, {.name= "no content-length response"
|
1231
|
+
,.type= HTTP_RESPONSE
|
1232
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1233
|
+
"Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
|
1234
|
+
"Server: Apache\r\n"
|
1235
|
+
"X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
|
1236
|
+
"Content-Type: text/xml; charset=utf-8\r\n"
|
1237
|
+
"Connection: close\r\n"
|
1238
|
+
"\r\n"
|
1239
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
1240
|
+
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
|
1241
|
+
" <SOAP-ENV:Body>\n"
|
1242
|
+
" <SOAP-ENV:Fault>\n"
|
1243
|
+
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
1244
|
+
" <faultstring>Client Error</faultstring>\n"
|
1245
|
+
" </SOAP-ENV:Fault>\n"
|
1246
|
+
" </SOAP-ENV:Body>\n"
|
1247
|
+
"</SOAP-ENV:Envelope>"
|
1248
|
+
,.should_keep_alive= FALSE
|
1249
|
+
,.message_complete_on_eof= TRUE
|
1250
|
+
,.http_major= 1
|
1251
|
+
,.http_minor= 1
|
1252
|
+
,.status_code= 200
|
1253
|
+
,.response_status= "OK"
|
1254
|
+
,.num_headers= 5
|
1255
|
+
,.headers=
|
1256
|
+
{ { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
|
1257
|
+
, { "Server", "Apache" }
|
1258
|
+
, { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
|
1259
|
+
, { "Content-Type", "text/xml; charset=utf-8" }
|
1260
|
+
, { "Connection", "close" }
|
1261
|
+
}
|
1262
|
+
,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
1263
|
+
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
|
1264
|
+
" <SOAP-ENV:Body>\n"
|
1265
|
+
" <SOAP-ENV:Fault>\n"
|
1266
|
+
" <faultcode>SOAP-ENV:Client</faultcode>\n"
|
1267
|
+
" <faultstring>Client Error</faultstring>\n"
|
1268
|
+
" </SOAP-ENV:Fault>\n"
|
1269
|
+
" </SOAP-ENV:Body>\n"
|
1270
|
+
"</SOAP-ENV:Envelope>"
|
1271
|
+
}
|
1272
|
+
|
1273
|
+
#define NO_HEADERS_NO_BODY_404 2
|
1274
|
+
, {.name= "404 no headers no body"
|
1275
|
+
,.type= HTTP_RESPONSE
|
1276
|
+
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
1277
|
+
,.should_keep_alive= FALSE
|
1278
|
+
,.message_complete_on_eof= TRUE
|
1279
|
+
,.http_major= 1
|
1280
|
+
,.http_minor= 1
|
1281
|
+
,.status_code= 404
|
1282
|
+
,.response_status= "Not Found"
|
1283
|
+
,.num_headers= 0
|
1284
|
+
,.headers= {}
|
1285
|
+
,.body_size= 0
|
1286
|
+
,.body= ""
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
#define NO_REASON_PHRASE 3
|
1290
|
+
, {.name= "301 no response phrase"
|
1291
|
+
,.type= HTTP_RESPONSE
|
1292
|
+
,.raw= "HTTP/1.1 301\r\n\r\n"
|
1293
|
+
,.should_keep_alive = FALSE
|
1294
|
+
,.message_complete_on_eof= TRUE
|
1295
|
+
,.http_major= 1
|
1296
|
+
,.http_minor= 1
|
1297
|
+
,.status_code= 301
|
1298
|
+
,.response_status= ""
|
1299
|
+
,.num_headers= 0
|
1300
|
+
,.headers= {}
|
1301
|
+
,.body= ""
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
#define TRAILING_SPACE_ON_CHUNKED_BODY 4
|
1305
|
+
, {.name="200 trailing space on chunked body"
|
1306
|
+
,.type= HTTP_RESPONSE
|
1307
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1308
|
+
"Content-Type: text/plain\r\n"
|
1309
|
+
"Transfer-Encoding: chunked\r\n"
|
1310
|
+
"\r\n"
|
1311
|
+
"25 \r\n"
|
1312
|
+
"This is the data in the first chunk\r\n"
|
1313
|
+
"\r\n"
|
1314
|
+
"1C\r\n"
|
1315
|
+
"and this is the second one\r\n"
|
1316
|
+
"\r\n"
|
1317
|
+
"0 \r\n"
|
1318
|
+
"\r\n"
|
1319
|
+
,.should_keep_alive= TRUE
|
1320
|
+
,.message_complete_on_eof= FALSE
|
1321
|
+
,.http_major= 1
|
1322
|
+
,.http_minor= 1
|
1323
|
+
,.status_code= 200
|
1324
|
+
,.response_status= "OK"
|
1325
|
+
,.num_headers= 2
|
1326
|
+
,.headers=
|
1327
|
+
{ {"Content-Type", "text/plain" }
|
1328
|
+
, {"Transfer-Encoding", "chunked" }
|
1329
|
+
}
|
1330
|
+
,.body_size = 37+28
|
1331
|
+
,.body =
|
1332
|
+
"This is the data in the first chunk\r\n"
|
1333
|
+
"and this is the second one\r\n"
|
1334
|
+
,.num_chunks_complete= 3
|
1335
|
+
,.chunk_lengths= { 0x25, 0x1c }
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
#define NO_CARRIAGE_RET 5
|
1339
|
+
, {.name="no carriage ret"
|
1340
|
+
,.type= HTTP_RESPONSE
|
1341
|
+
,.raw= "HTTP/1.1 200 OK\n"
|
1342
|
+
"Content-Type: text/html; charset=utf-8\n"
|
1343
|
+
"Connection: close\n"
|
1344
|
+
"\n"
|
1345
|
+
"these headers are from http://news.ycombinator.com/"
|
1346
|
+
,.should_keep_alive= FALSE
|
1347
|
+
,.message_complete_on_eof= TRUE
|
1348
|
+
,.http_major= 1
|
1349
|
+
,.http_minor= 1
|
1350
|
+
,.status_code= 200
|
1351
|
+
,.response_status= "OK"
|
1352
|
+
,.num_headers= 2
|
1353
|
+
,.headers=
|
1354
|
+
{ {"Content-Type", "text/html; charset=utf-8" }
|
1355
|
+
, {"Connection", "close" }
|
1356
|
+
}
|
1357
|
+
,.body= "these headers are from http://news.ycombinator.com/"
|
1358
|
+
}
|
1359
|
+
|
1360
|
+
#define PROXY_CONNECTION 6
|
1361
|
+
, {.name="proxy connection"
|
1362
|
+
,.type= HTTP_RESPONSE
|
1363
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1364
|
+
"Content-Type: text/html; charset=UTF-8\r\n"
|
1365
|
+
"Content-Length: 11\r\n"
|
1366
|
+
"Proxy-Connection: close\r\n"
|
1367
|
+
"Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
|
1368
|
+
"\r\n"
|
1369
|
+
"hello world"
|
1370
|
+
,.should_keep_alive= FALSE
|
1371
|
+
,.message_complete_on_eof= FALSE
|
1372
|
+
,.http_major= 1
|
1373
|
+
,.http_minor= 1
|
1374
|
+
,.status_code= 200
|
1375
|
+
,.response_status= "OK"
|
1376
|
+
,.num_headers= 4
|
1377
|
+
,.headers=
|
1378
|
+
{ {"Content-Type", "text/html; charset=UTF-8" }
|
1379
|
+
, {"Content-Length", "11" }
|
1380
|
+
, {"Proxy-Connection", "close" }
|
1381
|
+
, {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
|
1382
|
+
}
|
1383
|
+
,.body= "hello world"
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
#define UNDERSTORE_HEADER_KEY 7
|
1387
|
+
// shown by
|
1388
|
+
// curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;"
|
1389
|
+
, {.name="underscore header key"
|
1390
|
+
,.type= HTTP_RESPONSE
|
1391
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1392
|
+
"Server: DCLK-AdSvr\r\n"
|
1393
|
+
"Content-Type: text/xml\r\n"
|
1394
|
+
"Content-Length: 0\r\n"
|
1395
|
+
"DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
|
1396
|
+
,.should_keep_alive= TRUE
|
1397
|
+
,.message_complete_on_eof= FALSE
|
1398
|
+
,.http_major= 1
|
1399
|
+
,.http_minor= 1
|
1400
|
+
,.status_code= 200
|
1401
|
+
,.response_status= "OK"
|
1402
|
+
,.num_headers= 4
|
1403
|
+
,.headers=
|
1404
|
+
{ {"Server", "DCLK-AdSvr" }
|
1405
|
+
, {"Content-Type", "text/xml" }
|
1406
|
+
, {"Content-Length", "0" }
|
1407
|
+
, {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" }
|
1408
|
+
}
|
1409
|
+
,.body= ""
|
1410
|
+
}
|
1411
|
+
|
1412
|
+
#define BONJOUR_MADAME_FR 8
|
1413
|
+
/* The client should not merge two headers fields when the first one doesn't
|
1414
|
+
* have a value.
|
1415
|
+
*/
|
1416
|
+
, {.name= "bonjourmadame.fr"
|
1417
|
+
,.type= HTTP_RESPONSE
|
1418
|
+
,.raw= "HTTP/1.0 301 Moved Permanently\r\n"
|
1419
|
+
"Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n"
|
1420
|
+
"Server: Apache/2.2.3 (Red Hat)\r\n"
|
1421
|
+
"Cache-Control: public\r\n"
|
1422
|
+
"Pragma: \r\n"
|
1423
|
+
"Location: http://www.bonjourmadame.fr/\r\n"
|
1424
|
+
"Vary: Accept-Encoding\r\n"
|
1425
|
+
"Content-Length: 0\r\n"
|
1426
|
+
"Content-Type: text/html; charset=UTF-8\r\n"
|
1427
|
+
"Connection: keep-alive\r\n"
|
1428
|
+
"\r\n"
|
1429
|
+
,.should_keep_alive= TRUE
|
1430
|
+
,.message_complete_on_eof= FALSE
|
1431
|
+
,.http_major= 1
|
1432
|
+
,.http_minor= 0
|
1433
|
+
,.status_code= 301
|
1434
|
+
,.response_status= "Moved Permanently"
|
1435
|
+
,.num_headers= 9
|
1436
|
+
,.headers=
|
1437
|
+
{ { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
|
1438
|
+
, { "Server", "Apache/2.2.3 (Red Hat)" }
|
1439
|
+
, { "Cache-Control", "public" }
|
1440
|
+
, { "Pragma", "" }
|
1441
|
+
, { "Location", "http://www.bonjourmadame.fr/" }
|
1442
|
+
, { "Vary", "Accept-Encoding" }
|
1443
|
+
, { "Content-Length", "0" }
|
1444
|
+
, { "Content-Type", "text/html; charset=UTF-8" }
|
1445
|
+
, { "Connection", "keep-alive" }
|
1446
|
+
}
|
1447
|
+
,.body= ""
|
1448
|
+
}
|
1449
|
+
|
1450
|
+
#define RES_FIELD_UNDERSCORE 9
|
1451
|
+
/* Should handle spaces in header fields */
|
1452
|
+
, {.name= "field underscore"
|
1453
|
+
,.type= HTTP_RESPONSE
|
1454
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1455
|
+
"Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
|
1456
|
+
"Server: Apache\r\n"
|
1457
|
+
"Cache-Control: no-cache, must-revalidate\r\n"
|
1458
|
+
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
|
1459
|
+
".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
|
1460
|
+
"Vary: Accept-Encoding\r\n"
|
1461
|
+
"_eep-Alive: timeout=45\r\n" /* semantic value ignored */
|
1462
|
+
"_onnection: Keep-Alive\r\n" /* semantic value ignored */
|
1463
|
+
"Transfer-Encoding: chunked\r\n"
|
1464
|
+
"Content-Type: text/html\r\n"
|
1465
|
+
"Connection: close\r\n"
|
1466
|
+
"\r\n"
|
1467
|
+
"0\r\n\r\n"
|
1468
|
+
,.should_keep_alive= FALSE
|
1469
|
+
,.message_complete_on_eof= FALSE
|
1470
|
+
,.http_major= 1
|
1471
|
+
,.http_minor= 1
|
880
1472
|
,.status_code= 200
|
881
|
-
,.
|
1473
|
+
,.response_status= "OK"
|
1474
|
+
,.num_headers= 11
|
882
1475
|
,.headers=
|
883
|
-
{ {"
|
884
|
-
, {"
|
885
|
-
, {"
|
886
|
-
, {"
|
1476
|
+
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
|
1477
|
+
, { "Server", "Apache" }
|
1478
|
+
, { "Cache-Control", "no-cache, must-revalidate" }
|
1479
|
+
, { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
|
1480
|
+
, { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
|
1481
|
+
, { "Vary", "Accept-Encoding" }
|
1482
|
+
, { "_eep-Alive", "timeout=45" }
|
1483
|
+
, { "_onnection", "Keep-Alive" }
|
1484
|
+
, { "Transfer-Encoding", "chunked" }
|
1485
|
+
, { "Content-Type", "text/html" }
|
1486
|
+
, { "Connection", "close" }
|
887
1487
|
}
|
888
1488
|
,.body= ""
|
1489
|
+
,.num_chunks_complete= 1
|
1490
|
+
,.chunk_lengths= {}
|
889
1491
|
}
|
890
1492
|
|
891
|
-
#define
|
892
|
-
/*
|
893
|
-
|
894
|
-
*/
|
895
|
-
, {.name= "bonjourmadame.fr"
|
1493
|
+
#define NON_ASCII_IN_STATUS_LINE 10
|
1494
|
+
/* Should handle non-ASCII in status line */
|
1495
|
+
, {.name= "non-ASCII in status line"
|
896
1496
|
,.type= HTTP_RESPONSE
|
897
|
-
,.raw= "HTTP/1.
|
898
|
-
"Date:
|
899
|
-
"Server: Apache/2.2.3 (Red Hat)\r\n"
|
900
|
-
"Cache-Control: public\r\n"
|
901
|
-
"Pragma: \r\n"
|
902
|
-
"Location: http://www.bonjourmadame.fr/\r\n"
|
903
|
-
"Vary: Accept-Encoding\r\n"
|
1497
|
+
,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
|
1498
|
+
"Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
|
904
1499
|
"Content-Length: 0\r\n"
|
905
|
-
"
|
1500
|
+
"Connection: close\r\n"
|
1501
|
+
"\r\n"
|
1502
|
+
,.should_keep_alive= FALSE
|
1503
|
+
,.message_complete_on_eof= FALSE
|
1504
|
+
,.http_major= 1
|
1505
|
+
,.http_minor= 1
|
1506
|
+
,.status_code= 500
|
1507
|
+
,.response_status= "Oriëntatieprobleem"
|
1508
|
+
,.num_headers= 3
|
1509
|
+
,.headers=
|
1510
|
+
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
|
1511
|
+
, { "Content-Length", "0" }
|
1512
|
+
, { "Connection", "close" }
|
1513
|
+
}
|
1514
|
+
,.body= ""
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
#define HTTP_VERSION_0_9 11
|
1518
|
+
/* Should handle HTTP/0.9 */
|
1519
|
+
, {.name= "http version 0.9"
|
1520
|
+
,.type= HTTP_RESPONSE
|
1521
|
+
,.raw= "HTTP/0.9 200 OK\r\n"
|
1522
|
+
"\r\n"
|
1523
|
+
,.should_keep_alive= FALSE
|
1524
|
+
,.message_complete_on_eof= TRUE
|
1525
|
+
,.http_major= 0
|
1526
|
+
,.http_minor= 9
|
1527
|
+
,.status_code= 200
|
1528
|
+
,.response_status= "OK"
|
1529
|
+
,.num_headers= 0
|
1530
|
+
,.headers=
|
1531
|
+
{}
|
1532
|
+
,.body= ""
|
1533
|
+
}
|
1534
|
+
|
1535
|
+
#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
|
1536
|
+
/* The client should wait for the server's EOF. That is, when neither
|
1537
|
+
* content-length nor transfer-encoding is specified, the end of body
|
1538
|
+
* is specified by the EOF.
|
1539
|
+
*/
|
1540
|
+
, {.name= "neither content-length nor transfer-encoding response"
|
1541
|
+
,.type= HTTP_RESPONSE
|
1542
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1543
|
+
"Content-Type: text/plain\r\n"
|
1544
|
+
"\r\n"
|
1545
|
+
"hello world"
|
1546
|
+
,.should_keep_alive= FALSE
|
1547
|
+
,.message_complete_on_eof= TRUE
|
1548
|
+
,.http_major= 1
|
1549
|
+
,.http_minor= 1
|
1550
|
+
,.status_code= 200
|
1551
|
+
,.response_status= "OK"
|
1552
|
+
,.num_headers= 1
|
1553
|
+
,.headers=
|
1554
|
+
{ { "Content-Type", "text/plain" }
|
1555
|
+
}
|
1556
|
+
,.body= "hello world"
|
1557
|
+
}
|
1558
|
+
|
1559
|
+
#define NO_BODY_HTTP10_KA_200 13
|
1560
|
+
, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
|
1561
|
+
,.type= HTTP_RESPONSE
|
1562
|
+
,.raw= "HTTP/1.0 200 OK\r\n"
|
1563
|
+
"Connection: keep-alive\r\n"
|
1564
|
+
"\r\n"
|
1565
|
+
,.should_keep_alive= FALSE
|
1566
|
+
,.message_complete_on_eof= TRUE
|
1567
|
+
,.http_major= 1
|
1568
|
+
,.http_minor= 0
|
1569
|
+
,.status_code= 200
|
1570
|
+
,.response_status= "OK"
|
1571
|
+
,.num_headers= 1
|
1572
|
+
,.headers=
|
1573
|
+
{ { "Connection", "keep-alive" }
|
1574
|
+
}
|
1575
|
+
,.body_size= 0
|
1576
|
+
,.body= ""
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
#define NO_BODY_HTTP10_KA_204 14
|
1580
|
+
, {.name= "HTTP/1.0 with keep-alive and a 204 status"
|
1581
|
+
,.type= HTTP_RESPONSE
|
1582
|
+
,.raw= "HTTP/1.0 204 No content\r\n"
|
1583
|
+
"Connection: keep-alive\r\n"
|
1584
|
+
"\r\n"
|
1585
|
+
,.should_keep_alive= TRUE
|
1586
|
+
,.message_complete_on_eof= FALSE
|
1587
|
+
,.http_major= 1
|
1588
|
+
,.http_minor= 0
|
1589
|
+
,.status_code= 204
|
1590
|
+
,.response_status= "No content"
|
1591
|
+
,.num_headers= 1
|
1592
|
+
,.headers=
|
1593
|
+
{ { "Connection", "keep-alive" }
|
1594
|
+
}
|
1595
|
+
,.body_size= 0
|
1596
|
+
,.body= ""
|
1597
|
+
}
|
1598
|
+
|
1599
|
+
#define NO_BODY_HTTP11_KA_200 15
|
1600
|
+
, {.name= "HTTP/1.1 with an EOF-terminated 200 status"
|
1601
|
+
,.type= HTTP_RESPONSE
|
1602
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1603
|
+
"\r\n"
|
1604
|
+
,.should_keep_alive= FALSE
|
1605
|
+
,.message_complete_on_eof= TRUE
|
1606
|
+
,.http_major= 1
|
1607
|
+
,.http_minor= 1
|
1608
|
+
,.status_code= 200
|
1609
|
+
,.response_status= "OK"
|
1610
|
+
,.num_headers= 0
|
1611
|
+
,.headers={}
|
1612
|
+
,.body_size= 0
|
1613
|
+
,.body= ""
|
1614
|
+
}
|
1615
|
+
|
1616
|
+
#define NO_BODY_HTTP11_KA_204 16
|
1617
|
+
, {.name= "HTTP/1.1 with a 204 status"
|
1618
|
+
,.type= HTTP_RESPONSE
|
1619
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1620
|
+
"\r\n"
|
1621
|
+
,.should_keep_alive= TRUE
|
1622
|
+
,.message_complete_on_eof= FALSE
|
1623
|
+
,.http_major= 1
|
1624
|
+
,.http_minor= 1
|
1625
|
+
,.status_code= 204
|
1626
|
+
,.response_status= "No content"
|
1627
|
+
,.num_headers= 0
|
1628
|
+
,.headers={}
|
1629
|
+
,.body_size= 0
|
1630
|
+
,.body= ""
|
1631
|
+
}
|
1632
|
+
|
1633
|
+
#define NO_BODY_HTTP11_NOKA_204 17
|
1634
|
+
, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
|
1635
|
+
,.type= HTTP_RESPONSE
|
1636
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1637
|
+
"Connection: close\r\n"
|
1638
|
+
"\r\n"
|
1639
|
+
,.should_keep_alive= FALSE
|
1640
|
+
,.message_complete_on_eof= FALSE
|
1641
|
+
,.http_major= 1
|
1642
|
+
,.http_minor= 1
|
1643
|
+
,.status_code= 204
|
1644
|
+
,.response_status= "No content"
|
1645
|
+
,.num_headers= 1
|
1646
|
+
,.headers=
|
1647
|
+
{ { "Connection", "close" }
|
1648
|
+
}
|
1649
|
+
,.body_size= 0
|
1650
|
+
,.body= ""
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
#define NO_BODY_HTTP11_KA_CHUNKED_200 18
|
1654
|
+
, {.name= "HTTP/1.1 with chunked endocing and a 200 response"
|
1655
|
+
,.type= HTTP_RESPONSE
|
1656
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1657
|
+
"Transfer-Encoding: chunked\r\n"
|
1658
|
+
"\r\n"
|
1659
|
+
"0\r\n"
|
1660
|
+
"\r\n"
|
1661
|
+
,.should_keep_alive= TRUE
|
1662
|
+
,.message_complete_on_eof= FALSE
|
1663
|
+
,.http_major= 1
|
1664
|
+
,.http_minor= 1
|
1665
|
+
,.status_code= 200
|
1666
|
+
,.response_status= "OK"
|
1667
|
+
,.num_headers= 1
|
1668
|
+
,.headers=
|
1669
|
+
{ { "Transfer-Encoding", "chunked" }
|
1670
|
+
}
|
1671
|
+
,.body_size= 0
|
1672
|
+
,.body= ""
|
1673
|
+
,.num_chunks_complete= 1
|
1674
|
+
}
|
1675
|
+
|
1676
|
+
#if !HTTP_PARSER_STRICT
|
1677
|
+
#define SPACE_IN_FIELD_RES 19
|
1678
|
+
/* Should handle spaces in header fields */
|
1679
|
+
, {.name= "field space"
|
1680
|
+
,.type= HTTP_RESPONSE
|
1681
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1682
|
+
"Server: Microsoft-IIS/6.0\r\n"
|
1683
|
+
"X-Powered-By: ASP.NET\r\n"
|
1684
|
+
"en-US Content-Type: text/xml\r\n" /* this is the problem */
|
1685
|
+
"Content-Type: text/xml\r\n"
|
1686
|
+
"Content-Length: 16\r\n"
|
1687
|
+
"Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
|
906
1688
|
"Connection: keep-alive\r\n"
|
907
1689
|
"\r\n"
|
1690
|
+
"<xml>hello</xml>" /* fake body */
|
1691
|
+
,.should_keep_alive= TRUE
|
1692
|
+
,.message_complete_on_eof= FALSE
|
1693
|
+
,.http_major= 1
|
1694
|
+
,.http_minor= 1
|
1695
|
+
,.status_code= 200
|
1696
|
+
,.response_status= "OK"
|
1697
|
+
,.num_headers= 7
|
1698
|
+
,.headers=
|
1699
|
+
{ { "Server", "Microsoft-IIS/6.0" }
|
1700
|
+
, { "X-Powered-By", "ASP.NET" }
|
1701
|
+
, { "en-US Content-Type", "text/xml" }
|
1702
|
+
, { "Content-Type", "text/xml" }
|
1703
|
+
, { "Content-Length", "16" }
|
1704
|
+
, { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
|
1705
|
+
, { "Connection", "keep-alive" }
|
1706
|
+
}
|
1707
|
+
,.body= "<xml>hello</xml>"
|
1708
|
+
}
|
1709
|
+
#endif /* !HTTP_PARSER_STRICT */
|
1710
|
+
|
1711
|
+
#define AMAZON_COM 20
|
1712
|
+
, {.name= "amazon.com"
|
1713
|
+
,.type= HTTP_RESPONSE
|
1714
|
+
,.raw= "HTTP/1.1 301 MovedPermanently\r\n"
|
1715
|
+
"Date: Wed, 15 May 2013 17:06:33 GMT\r\n"
|
1716
|
+
"Server: Server\r\n"
|
1717
|
+
"x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n"
|
1718
|
+
"p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n"
|
1719
|
+
"x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n"
|
1720
|
+
"Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n"
|
1721
|
+
"Vary: Accept-Encoding,User-Agent\r\n"
|
1722
|
+
"Content-Type: text/html; charset=ISO-8859-1\r\n"
|
1723
|
+
"Transfer-Encoding: chunked\r\n"
|
1724
|
+
"\r\n"
|
1725
|
+
"1\r\n"
|
1726
|
+
"\n\r\n"
|
1727
|
+
"0\r\n"
|
1728
|
+
"\r\n"
|
1729
|
+
,.should_keep_alive= TRUE
|
1730
|
+
,.message_complete_on_eof= FALSE
|
1731
|
+
,.http_major= 1
|
1732
|
+
,.http_minor= 1
|
1733
|
+
,.status_code= 301
|
1734
|
+
,.response_status= "MovedPermanently"
|
1735
|
+
,.num_headers= 9
|
1736
|
+
,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
|
1737
|
+
, { "Server", "Server" }
|
1738
|
+
, { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" }
|
1739
|
+
, { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" }
|
1740
|
+
, { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" }
|
1741
|
+
, { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" }
|
1742
|
+
, { "Vary", "Accept-Encoding,User-Agent" }
|
1743
|
+
, { "Content-Type", "text/html; charset=ISO-8859-1" }
|
1744
|
+
, { "Transfer-Encoding", "chunked" }
|
1745
|
+
}
|
1746
|
+
,.body= "\n"
|
1747
|
+
,.num_chunks_complete= 2
|
1748
|
+
,.chunk_lengths= { 1 }
|
1749
|
+
}
|
1750
|
+
|
1751
|
+
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20
|
1752
|
+
, {.name= "empty reason phrase after space"
|
1753
|
+
,.type= HTTP_RESPONSE
|
1754
|
+
,.raw= "HTTP/1.1 200 \r\n"
|
1755
|
+
"\r\n"
|
1756
|
+
,.should_keep_alive= FALSE
|
1757
|
+
,.message_complete_on_eof= TRUE
|
1758
|
+
,.http_major= 1
|
1759
|
+
,.http_minor= 1
|
1760
|
+
,.status_code= 200
|
1761
|
+
,.response_status= ""
|
1762
|
+
,.num_headers= 0
|
1763
|
+
,.headers= {}
|
1764
|
+
,.body= ""
|
1765
|
+
}
|
1766
|
+
|
1767
|
+
#define CONTENT_LENGTH_X 21
|
1768
|
+
, {.name= "Content-Length-X"
|
1769
|
+
,.type= HTTP_RESPONSE
|
1770
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1771
|
+
"Content-Length-X: 0\r\n"
|
1772
|
+
"Transfer-Encoding: chunked\r\n"
|
1773
|
+
"\r\n"
|
1774
|
+
"2\r\n"
|
1775
|
+
"OK\r\n"
|
1776
|
+
"0\r\n"
|
1777
|
+
"\r\n"
|
1778
|
+
,.should_keep_alive= TRUE
|
1779
|
+
,.message_complete_on_eof= FALSE
|
1780
|
+
,.http_major= 1
|
1781
|
+
,.http_minor= 1
|
1782
|
+
,.status_code= 200
|
1783
|
+
,.response_status= "OK"
|
1784
|
+
,.num_headers= 2
|
1785
|
+
,.headers= { { "Content-Length-X", "0" }
|
1786
|
+
, { "Transfer-Encoding", "chunked" }
|
1787
|
+
}
|
1788
|
+
,.body= "OK"
|
1789
|
+
,.num_chunks_complete= 2
|
1790
|
+
,.chunk_lengths= { 2 }
|
1791
|
+
}
|
1792
|
+
|
1793
|
+
#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER 22
|
1794
|
+
, {.name= "HTTP 101 response with Upgrade header"
|
1795
|
+
,.type= HTTP_RESPONSE
|
1796
|
+
,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
|
1797
|
+
"Connection: upgrade\r\n"
|
1798
|
+
"Upgrade: h2c\r\n"
|
1799
|
+
"\r\n"
|
1800
|
+
"proto"
|
1801
|
+
,.should_keep_alive= TRUE
|
1802
|
+
,.message_complete_on_eof= FALSE
|
1803
|
+
,.http_major= 1
|
1804
|
+
,.http_minor= 1
|
1805
|
+
,.status_code= 101
|
1806
|
+
,.response_status= "Switching Protocols"
|
1807
|
+
,.upgrade= "proto"
|
1808
|
+
,.num_headers= 2
|
1809
|
+
,.headers=
|
1810
|
+
{ { "Connection", "upgrade" }
|
1811
|
+
, { "Upgrade", "h2c" }
|
1812
|
+
}
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 23
|
1816
|
+
, {.name= "HTTP 101 response with Upgrade and Content-Length header"
|
1817
|
+
,.type= HTTP_RESPONSE
|
1818
|
+
,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
|
1819
|
+
"Connection: upgrade\r\n"
|
1820
|
+
"Upgrade: h2c\r\n"
|
1821
|
+
"Content-Length: 4\r\n"
|
1822
|
+
"\r\n"
|
1823
|
+
"body"
|
1824
|
+
"proto"
|
908
1825
|
,.should_keep_alive= TRUE
|
909
1826
|
,.message_complete_on_eof= FALSE
|
910
1827
|
,.http_major= 1
|
911
|
-
,.http_minor=
|
912
|
-
,.status_code=
|
913
|
-
,.
|
1828
|
+
,.http_minor= 1
|
1829
|
+
,.status_code= 101
|
1830
|
+
,.response_status= "Switching Protocols"
|
1831
|
+
,.body= "body"
|
1832
|
+
,.upgrade= "proto"
|
1833
|
+
,.num_headers= 3
|
914
1834
|
,.headers=
|
915
|
-
{ { "
|
916
|
-
, { "
|
917
|
-
, { "
|
918
|
-
, { "Pragma", "" }
|
919
|
-
, { "Location", "http://www.bonjourmadame.fr/" }
|
920
|
-
, { "Vary", "Accept-Encoding" }
|
921
|
-
, { "Content-Length", "0" }
|
922
|
-
, { "Content-Type", "text/html; charset=UTF-8" }
|
923
|
-
, { "Connection", "keep-alive" }
|
1835
|
+
{ { "Connection", "upgrade" }
|
1836
|
+
, { "Upgrade", "h2c" }
|
1837
|
+
, { "Content-Length", "4" }
|
924
1838
|
}
|
925
|
-
,.body= ""
|
926
1839
|
}
|
927
1840
|
|
928
|
-
#define
|
929
|
-
|
930
|
-
, {.name= "field space"
|
1841
|
+
#define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 24
|
1842
|
+
, {.name= "HTTP 101 response with Upgrade and Transfer-Encoding header"
|
931
1843
|
,.type= HTTP_RESPONSE
|
932
|
-
,.raw= "HTTP/1.1
|
933
|
-
"
|
934
|
-
"
|
935
|
-
"
|
936
|
-
"Content-Type: text/xml\r\n"
|
937
|
-
"Content-Length: 16\r\n"
|
938
|
-
"Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
|
939
|
-
"Connection: keep-alive\r\n"
|
1844
|
+
,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
|
1845
|
+
"Connection: upgrade\r\n"
|
1846
|
+
"Upgrade: h2c\r\n"
|
1847
|
+
"Transfer-Encoding: chunked\r\n"
|
940
1848
|
"\r\n"
|
941
|
-
"
|
1849
|
+
"2\r\n"
|
1850
|
+
"bo\r\n"
|
1851
|
+
"2\r\n"
|
1852
|
+
"dy\r\n"
|
1853
|
+
"0\r\n"
|
1854
|
+
"\r\n"
|
1855
|
+
"proto"
|
942
1856
|
,.should_keep_alive= TRUE
|
943
1857
|
,.message_complete_on_eof= FALSE
|
944
1858
|
,.http_major= 1
|
945
1859
|
,.http_minor= 1
|
946
|
-
,.status_code=
|
947
|
-
,.
|
1860
|
+
,.status_code= 101
|
1861
|
+
,.response_status= "Switching Protocols"
|
1862
|
+
,.body= "body"
|
1863
|
+
,.upgrade= "proto"
|
1864
|
+
,.num_headers= 3
|
948
1865
|
,.headers=
|
949
|
-
{ { "
|
950
|
-
, { "
|
951
|
-
, { "
|
952
|
-
, { "Content-Type", "text/xml" }
|
953
|
-
, { "Content-Length", "16" }
|
954
|
-
, { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
|
955
|
-
, { "Connection", "keep-alive" }
|
1866
|
+
{ { "Connection", "upgrade" }
|
1867
|
+
, { "Upgrade", "h2c" }
|
1868
|
+
, { "Transfer-Encoding", "chunked" }
|
956
1869
|
}
|
957
|
-
,.
|
1870
|
+
,.num_chunks_complete= 3
|
1871
|
+
,.chunk_lengths= { 2, 2 }
|
958
1872
|
}
|
959
1873
|
|
960
|
-
|
961
|
-
|
962
|
-
/* Should handle spaces in header fields */
|
963
|
-
, {.name= "field underscore"
|
1874
|
+
#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER 25
|
1875
|
+
, {.name= "HTTP 200 response with Upgrade header"
|
964
1876
|
,.type= HTTP_RESPONSE
|
965
1877
|
,.raw= "HTTP/1.1 200 OK\r\n"
|
966
|
-
"
|
967
|
-
"
|
968
|
-
"Cache-Control: no-cache, must-revalidate\r\n"
|
969
|
-
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
|
970
|
-
".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
|
971
|
-
"Vary: Accept-Encoding\r\n"
|
972
|
-
"_eep-Alive: timeout=45\r\n" /* semantic value ignored */
|
973
|
-
"_onnection: Keep-Alive\r\n" /* semantic value ignored */
|
974
|
-
"Transfer-Encoding: chunked\r\n"
|
975
|
-
"Content-Type: text/html\r\n"
|
976
|
-
"Connection: close\r\n"
|
1878
|
+
"Connection: upgrade\r\n"
|
1879
|
+
"Upgrade: h2c\r\n"
|
977
1880
|
"\r\n"
|
978
|
-
"
|
1881
|
+
"body"
|
979
1882
|
,.should_keep_alive= FALSE
|
980
|
-
,.message_complete_on_eof=
|
1883
|
+
,.message_complete_on_eof= TRUE
|
981
1884
|
,.http_major= 1
|
982
1885
|
,.http_minor= 1
|
983
1886
|
,.status_code= 200
|
984
|
-
,.
|
1887
|
+
,.response_status= "OK"
|
1888
|
+
,.body= "body"
|
1889
|
+
,.upgrade= NULL
|
1890
|
+
,.num_headers= 2
|
985
1891
|
,.headers=
|
986
|
-
{ { "
|
987
|
-
, { "
|
988
|
-
, { "Cache-Control", "no-cache, must-revalidate" }
|
989
|
-
, { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
|
990
|
-
, { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
|
991
|
-
, { "Vary", "Accept-Encoding" }
|
992
|
-
, { "_eep-Alive", "timeout=45" }
|
993
|
-
, { "_onnection", "Keep-Alive" }
|
994
|
-
, { "Transfer-Encoding", "chunked" }
|
995
|
-
, { "Content-Type", "text/html" }
|
996
|
-
, { "Connection", "close" }
|
1892
|
+
{ { "Connection", "upgrade" }
|
1893
|
+
, { "Upgrade", "h2c" }
|
997
1894
|
}
|
998
|
-
,.body= ""
|
999
1895
|
}
|
1000
1896
|
|
1001
|
-
#define
|
1002
|
-
|
1003
|
-
, {.name= "non-ASCII in status line"
|
1897
|
+
#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 26
|
1898
|
+
, {.name= "HTTP 200 response with Upgrade and Content-Length header"
|
1004
1899
|
,.type= HTTP_RESPONSE
|
1005
|
-
,.raw= "HTTP/1.1
|
1006
|
-
"
|
1007
|
-
"
|
1008
|
-
"
|
1900
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1901
|
+
"Connection: upgrade\r\n"
|
1902
|
+
"Upgrade: h2c\r\n"
|
1903
|
+
"Content-Length: 4\r\n"
|
1009
1904
|
"\r\n"
|
1010
|
-
|
1905
|
+
"body"
|
1906
|
+
,.should_keep_alive= TRUE
|
1011
1907
|
,.message_complete_on_eof= FALSE
|
1012
1908
|
,.http_major= 1
|
1013
1909
|
,.http_minor= 1
|
1014
|
-
,.status_code=
|
1910
|
+
,.status_code= 200
|
1911
|
+
,.response_status= "OK"
|
1015
1912
|
,.num_headers= 3
|
1913
|
+
,.body= "body"
|
1914
|
+
,.upgrade= NULL
|
1016
1915
|
,.headers=
|
1017
|
-
{ { "
|
1018
|
-
, { "
|
1019
|
-
, { "
|
1916
|
+
{ { "Connection", "upgrade" }
|
1917
|
+
, { "Upgrade", "h2c" }
|
1918
|
+
, { "Content-Length", "4" }
|
1020
1919
|
}
|
1021
|
-
,.body= ""
|
1022
1920
|
}
|
1023
1921
|
|
1024
|
-
|
1025
|
-
, {.name=
|
1922
|
+
#define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 27
|
1923
|
+
, {.name= "HTTP 200 response with Upgrade and Transfer-Encoding header"
|
1924
|
+
,.type= HTTP_RESPONSE
|
1925
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1926
|
+
"Connection: upgrade\r\n"
|
1927
|
+
"Upgrade: h2c\r\n"
|
1928
|
+
"Transfer-Encoding: chunked\r\n"
|
1929
|
+
"\r\n"
|
1930
|
+
"2\r\n"
|
1931
|
+
"bo\r\n"
|
1932
|
+
"2\r\n"
|
1933
|
+
"dy\r\n"
|
1934
|
+
"0\r\n"
|
1935
|
+
"\r\n"
|
1936
|
+
,.should_keep_alive= TRUE
|
1937
|
+
,.message_complete_on_eof= FALSE
|
1938
|
+
,.http_major= 1
|
1939
|
+
,.http_minor= 1
|
1940
|
+
,.status_code= 200
|
1941
|
+
,.response_status= "OK"
|
1942
|
+
,.num_headers= 3
|
1943
|
+
,.body= "body"
|
1944
|
+
,.upgrade= NULL
|
1945
|
+
,.headers=
|
1946
|
+
{ { "Connection", "upgrade" }
|
1947
|
+
, { "Upgrade", "h2c" }
|
1948
|
+
, { "Transfer-Encoding", "chunked" }
|
1949
|
+
}
|
1950
|
+
,.num_chunks_complete= 3
|
1951
|
+
,.chunk_lengths= { 2, 2 }
|
1952
|
+
}
|
1026
1953
|
};
|
1027
1954
|
|
1028
|
-
|
1029
|
-
|
1955
|
+
/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
|
1956
|
+
* define it ourselves.
|
1957
|
+
*/
|
1958
|
+
size_t
|
1959
|
+
strnlen(const char *s, size_t maxlen)
|
1030
1960
|
{
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1961
|
+
const char *p;
|
1962
|
+
|
1963
|
+
p = memchr(s, '\0', maxlen);
|
1964
|
+
if (p == NULL)
|
1965
|
+
return maxlen;
|
1966
|
+
|
1967
|
+
return p - s;
|
1034
1968
|
}
|
1035
1969
|
|
1036
|
-
|
1037
|
-
|
1970
|
+
size_t
|
1971
|
+
strlncat(char *dst, size_t len, const char *src, size_t n)
|
1038
1972
|
{
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1973
|
+
size_t slen;
|
1974
|
+
size_t dlen;
|
1975
|
+
size_t rlen;
|
1976
|
+
size_t ncpy;
|
1977
|
+
|
1978
|
+
slen = strnlen(src, n);
|
1979
|
+
dlen = strnlen(dst, len);
|
1980
|
+
|
1981
|
+
if (dlen < len) {
|
1982
|
+
rlen = len - dlen;
|
1983
|
+
ncpy = slen < rlen ? slen : (rlen - 1);
|
1984
|
+
memcpy(dst + dlen, src, ncpy);
|
1985
|
+
dst[dlen + ncpy] = '\0';
|
1986
|
+
}
|
1987
|
+
|
1988
|
+
assert(len > slen + dlen);
|
1989
|
+
return slen + dlen;
|
1042
1990
|
}
|
1043
1991
|
|
1044
|
-
|
1045
|
-
|
1992
|
+
size_t
|
1993
|
+
strlncpy(char *dst, size_t len, const char *src, size_t n)
|
1046
1994
|
{
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1995
|
+
size_t slen;
|
1996
|
+
size_t ncpy;
|
1997
|
+
|
1998
|
+
slen = strnlen(src, n);
|
1999
|
+
|
2000
|
+
if (len > 0) {
|
2001
|
+
ncpy = slen < len ? slen : (len - 1);
|
2002
|
+
memcpy(dst, src, ncpy);
|
2003
|
+
dst[ncpy] = '\0';
|
2004
|
+
}
|
2005
|
+
|
2006
|
+
assert(len > slen);
|
2007
|
+
return slen;
|
1050
2008
|
}
|
1051
2009
|
|
1052
2010
|
int
|
1053
|
-
|
2011
|
+
request_url_cb (http_parser *p, const char *buf, size_t len)
|
1054
2012
|
{
|
1055
2013
|
assert(p == parser);
|
1056
|
-
|
2014
|
+
strlncat(messages[num_messages].request_url,
|
2015
|
+
sizeof(messages[num_messages].request_url),
|
2016
|
+
buf,
|
2017
|
+
len);
|
1057
2018
|
return 0;
|
1058
2019
|
}
|
1059
2020
|
|
@@ -1066,7 +2027,10 @@ header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
1066
2027
|
if (m->last_header_element != FIELD)
|
1067
2028
|
m->num_headers++;
|
1068
2029
|
|
1069
|
-
|
2030
|
+
strlncat(m->headers[m->num_headers-1][0],
|
2031
|
+
sizeof(m->headers[m->num_headers-1][0]),
|
2032
|
+
buf,
|
2033
|
+
len);
|
1070
2034
|
|
1071
2035
|
m->last_header_element = FIELD;
|
1072
2036
|
|
@@ -1079,19 +2043,39 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
1079
2043
|
assert(p == parser);
|
1080
2044
|
struct message *m = &messages[num_messages];
|
1081
2045
|
|
1082
|
-
|
2046
|
+
strlncat(m->headers[m->num_headers-1][1],
|
2047
|
+
sizeof(m->headers[m->num_headers-1][1]),
|
2048
|
+
buf,
|
2049
|
+
len);
|
1083
2050
|
|
1084
2051
|
m->last_header_element = VALUE;
|
1085
2052
|
|
1086
2053
|
return 0;
|
1087
2054
|
}
|
1088
2055
|
|
2056
|
+
void
|
2057
|
+
check_body_is_final (const http_parser *p)
|
2058
|
+
{
|
2059
|
+
if (messages[num_messages].body_is_final) {
|
2060
|
+
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
2061
|
+
"on last on_body callback call "
|
2062
|
+
"but it doesn't! ***\n\n");
|
2063
|
+
assert(0);
|
2064
|
+
abort();
|
2065
|
+
}
|
2066
|
+
messages[num_messages].body_is_final = http_body_is_final(p);
|
2067
|
+
}
|
2068
|
+
|
1089
2069
|
int
|
1090
2070
|
body_cb (http_parser *p, const char *buf, size_t len)
|
1091
2071
|
{
|
1092
2072
|
assert(p == parser);
|
1093
|
-
|
2073
|
+
strlncat(messages[num_messages].body,
|
2074
|
+
sizeof(messages[num_messages].body),
|
2075
|
+
buf,
|
2076
|
+
len);
|
1094
2077
|
messages[num_messages].body_size += len;
|
2078
|
+
check_body_is_final(p);
|
1095
2079
|
// printf("body_cb: '%s'\n", requests[num_messages].body);
|
1096
2080
|
return 0;
|
1097
2081
|
}
|
@@ -1102,6 +2086,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
|
|
1102
2086
|
assert(p == parser);
|
1103
2087
|
assert(buf);
|
1104
2088
|
messages[num_messages].body_size += len;
|
2089
|
+
check_body_is_final(p);
|
1105
2090
|
return 0;
|
1106
2091
|
}
|
1107
2092
|
|
@@ -1136,53 +2121,330 @@ message_complete_cb (http_parser *p)
|
|
1136
2121
|
"value in both on_message_complete and on_headers_complete "
|
1137
2122
|
"but it doesn't! ***\n\n");
|
1138
2123
|
assert(0);
|
1139
|
-
|
2124
|
+
abort();
|
1140
2125
|
}
|
2126
|
+
|
2127
|
+
if (messages[num_messages].body_size &&
|
2128
|
+
http_body_is_final(p) &&
|
2129
|
+
!messages[num_messages].body_is_final)
|
2130
|
+
{
|
2131
|
+
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
2132
|
+
"on last on_body callback call "
|
2133
|
+
"but it doesn't! ***\n\n");
|
2134
|
+
assert(0);
|
2135
|
+
abort();
|
2136
|
+
}
|
2137
|
+
|
1141
2138
|
messages[num_messages].message_complete_cb_called = TRUE;
|
1142
2139
|
|
1143
|
-
messages[num_messages].message_complete_on_eof = currently_parsing_eof;
|
2140
|
+
messages[num_messages].message_complete_on_eof = currently_parsing_eof;
|
2141
|
+
|
2142
|
+
num_messages++;
|
2143
|
+
return 0;
|
2144
|
+
}
|
2145
|
+
|
2146
|
+
int
|
2147
|
+
response_status_cb (http_parser *p, const char *buf, size_t len)
|
2148
|
+
{
|
2149
|
+
assert(p == parser);
|
2150
|
+
|
2151
|
+
messages[num_messages].status_cb_called = TRUE;
|
2152
|
+
|
2153
|
+
strlncat(messages[num_messages].response_status,
|
2154
|
+
sizeof(messages[num_messages].response_status),
|
2155
|
+
buf,
|
2156
|
+
len);
|
2157
|
+
return 0;
|
2158
|
+
}
|
2159
|
+
|
2160
|
+
int
|
2161
|
+
chunk_header_cb (http_parser *p)
|
2162
|
+
{
|
2163
|
+
assert(p == parser);
|
2164
|
+
int chunk_idx = messages[num_messages].num_chunks;
|
2165
|
+
messages[num_messages].num_chunks++;
|
2166
|
+
if (chunk_idx < MAX_CHUNKS) {
|
2167
|
+
messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
|
2168
|
+
}
|
2169
|
+
|
2170
|
+
return 0;
|
2171
|
+
}
|
2172
|
+
|
2173
|
+
int
|
2174
|
+
chunk_complete_cb (http_parser *p)
|
2175
|
+
{
|
2176
|
+
assert(p == parser);
|
2177
|
+
|
2178
|
+
/* Here we want to verify that each chunk_header_cb is matched by a
|
2179
|
+
* chunk_complete_cb, so not only should the total number of calls to
|
2180
|
+
* both callbacks be the same, but they also should be interleaved
|
2181
|
+
* properly */
|
2182
|
+
assert(messages[num_messages].num_chunks ==
|
2183
|
+
messages[num_messages].num_chunks_complete + 1);
|
2184
|
+
|
2185
|
+
messages[num_messages].num_chunks_complete++;
|
2186
|
+
return 0;
|
2187
|
+
}
|
2188
|
+
|
2189
|
+
/* These dontcall_* callbacks exist so that we can verify that when we're
|
2190
|
+
* paused, no additional callbacks are invoked */
|
2191
|
+
int
|
2192
|
+
dontcall_message_begin_cb (http_parser *p)
|
2193
|
+
{
|
2194
|
+
if (p) { } // gcc
|
2195
|
+
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
|
2196
|
+
abort();
|
2197
|
+
}
|
2198
|
+
|
2199
|
+
int
|
2200
|
+
dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
|
2201
|
+
{
|
2202
|
+
if (p || buf || len) { } // gcc
|
2203
|
+
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
|
2204
|
+
abort();
|
2205
|
+
}
|
2206
|
+
|
2207
|
+
int
|
2208
|
+
dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
|
2209
|
+
{
|
2210
|
+
if (p || buf || len) { } // gcc
|
2211
|
+
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
|
2212
|
+
abort();
|
2213
|
+
}
|
2214
|
+
|
2215
|
+
int
|
2216
|
+
dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
|
2217
|
+
{
|
2218
|
+
if (p || buf || len) { } // gcc
|
2219
|
+
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
|
2220
|
+
abort();
|
2221
|
+
}
|
2222
|
+
|
2223
|
+
int
|
2224
|
+
dontcall_body_cb (http_parser *p, const char *buf, size_t len)
|
2225
|
+
{
|
2226
|
+
if (p || buf || len) { } // gcc
|
2227
|
+
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
|
2228
|
+
abort();
|
2229
|
+
}
|
2230
|
+
|
2231
|
+
int
|
2232
|
+
dontcall_headers_complete_cb (http_parser *p)
|
2233
|
+
{
|
2234
|
+
if (p) { } // gcc
|
2235
|
+
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
|
2236
|
+
"parser ***\n\n");
|
2237
|
+
abort();
|
2238
|
+
}
|
2239
|
+
|
2240
|
+
int
|
2241
|
+
dontcall_message_complete_cb (http_parser *p)
|
2242
|
+
{
|
2243
|
+
if (p) { } // gcc
|
2244
|
+
fprintf(stderr, "\n\n*** on_message_complete() called on paused "
|
2245
|
+
"parser ***\n\n");
|
2246
|
+
abort();
|
2247
|
+
}
|
2248
|
+
|
2249
|
+
int
|
2250
|
+
dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
|
2251
|
+
{
|
2252
|
+
if (p || buf || len) { } // gcc
|
2253
|
+
fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
|
2254
|
+
abort();
|
2255
|
+
}
|
2256
|
+
|
2257
|
+
int
|
2258
|
+
dontcall_chunk_header_cb (http_parser *p)
|
2259
|
+
{
|
2260
|
+
if (p) { } // gcc
|
2261
|
+
fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
|
2262
|
+
exit(1);
|
2263
|
+
}
|
2264
|
+
|
2265
|
+
int
|
2266
|
+
dontcall_chunk_complete_cb (http_parser *p)
|
2267
|
+
{
|
2268
|
+
if (p) { } // gcc
|
2269
|
+
fprintf(stderr, "\n\n*** on_chunk_complete() "
|
2270
|
+
"called on paused parser ***\n\n");
|
2271
|
+
exit(1);
|
2272
|
+
}
|
2273
|
+
|
2274
|
+
static http_parser_settings settings_dontcall =
|
2275
|
+
{.on_message_begin = dontcall_message_begin_cb
|
2276
|
+
,.on_header_field = dontcall_header_field_cb
|
2277
|
+
,.on_header_value = dontcall_header_value_cb
|
2278
|
+
,.on_url = dontcall_request_url_cb
|
2279
|
+
,.on_status = dontcall_response_status_cb
|
2280
|
+
,.on_body = dontcall_body_cb
|
2281
|
+
,.on_headers_complete = dontcall_headers_complete_cb
|
2282
|
+
,.on_message_complete = dontcall_message_complete_cb
|
2283
|
+
,.on_chunk_header = dontcall_chunk_header_cb
|
2284
|
+
,.on_chunk_complete = dontcall_chunk_complete_cb
|
2285
|
+
};
|
2286
|
+
|
2287
|
+
/* These pause_* callbacks always pause the parser and just invoke the regular
|
2288
|
+
* callback that tracks content. Before returning, we overwrite the parser
|
2289
|
+
* settings to point to the _dontcall variety so that we can verify that
|
2290
|
+
* the pause actually did, you know, pause. */
|
2291
|
+
int
|
2292
|
+
pause_message_begin_cb (http_parser *p)
|
2293
|
+
{
|
2294
|
+
http_parser_pause(p, 1);
|
2295
|
+
*current_pause_parser = settings_dontcall;
|
2296
|
+
return message_begin_cb(p);
|
2297
|
+
}
|
2298
|
+
|
2299
|
+
int
|
2300
|
+
pause_header_field_cb (http_parser *p, const char *buf, size_t len)
|
2301
|
+
{
|
2302
|
+
http_parser_pause(p, 1);
|
2303
|
+
*current_pause_parser = settings_dontcall;
|
2304
|
+
return header_field_cb(p, buf, len);
|
2305
|
+
}
|
2306
|
+
|
2307
|
+
int
|
2308
|
+
pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
2309
|
+
{
|
2310
|
+
http_parser_pause(p, 1);
|
2311
|
+
*current_pause_parser = settings_dontcall;
|
2312
|
+
return header_value_cb(p, buf, len);
|
2313
|
+
}
|
2314
|
+
|
2315
|
+
int
|
2316
|
+
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
2317
|
+
{
|
2318
|
+
http_parser_pause(p, 1);
|
2319
|
+
*current_pause_parser = settings_dontcall;
|
2320
|
+
return request_url_cb(p, buf, len);
|
2321
|
+
}
|
2322
|
+
|
2323
|
+
int
|
2324
|
+
pause_body_cb (http_parser *p, const char *buf, size_t len)
|
2325
|
+
{
|
2326
|
+
http_parser_pause(p, 1);
|
2327
|
+
*current_pause_parser = settings_dontcall;
|
2328
|
+
return body_cb(p, buf, len);
|
2329
|
+
}
|
2330
|
+
|
2331
|
+
int
|
2332
|
+
pause_headers_complete_cb (http_parser *p)
|
2333
|
+
{
|
2334
|
+
http_parser_pause(p, 1);
|
2335
|
+
*current_pause_parser = settings_dontcall;
|
2336
|
+
return headers_complete_cb(p);
|
2337
|
+
}
|
2338
|
+
|
2339
|
+
int
|
2340
|
+
pause_message_complete_cb (http_parser *p)
|
2341
|
+
{
|
2342
|
+
http_parser_pause(p, 1);
|
2343
|
+
*current_pause_parser = settings_dontcall;
|
2344
|
+
return message_complete_cb(p);
|
2345
|
+
}
|
2346
|
+
|
2347
|
+
int
|
2348
|
+
pause_response_status_cb (http_parser *p, const char *buf, size_t len)
|
2349
|
+
{
|
2350
|
+
http_parser_pause(p, 1);
|
2351
|
+
*current_pause_parser = settings_dontcall;
|
2352
|
+
return response_status_cb(p, buf, len);
|
2353
|
+
}
|
2354
|
+
|
2355
|
+
int
|
2356
|
+
pause_chunk_header_cb (http_parser *p)
|
2357
|
+
{
|
2358
|
+
http_parser_pause(p, 1);
|
2359
|
+
*current_pause_parser = settings_dontcall;
|
2360
|
+
return chunk_header_cb(p);
|
2361
|
+
}
|
2362
|
+
|
2363
|
+
int
|
2364
|
+
pause_chunk_complete_cb (http_parser *p)
|
2365
|
+
{
|
2366
|
+
http_parser_pause(p, 1);
|
2367
|
+
*current_pause_parser = settings_dontcall;
|
2368
|
+
return chunk_complete_cb(p);
|
2369
|
+
}
|
2370
|
+
|
2371
|
+
int
|
2372
|
+
connect_headers_complete_cb (http_parser *p)
|
2373
|
+
{
|
2374
|
+
headers_complete_cb(p);
|
2375
|
+
return 1;
|
2376
|
+
}
|
1144
2377
|
|
1145
|
-
|
1146
|
-
|
2378
|
+
int
|
2379
|
+
connect_message_complete_cb (http_parser *p)
|
2380
|
+
{
|
2381
|
+
messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
|
2382
|
+
return message_complete_cb(p);
|
1147
2383
|
}
|
1148
2384
|
|
2385
|
+
static http_parser_settings settings_pause =
|
2386
|
+
{.on_message_begin = pause_message_begin_cb
|
2387
|
+
,.on_header_field = pause_header_field_cb
|
2388
|
+
,.on_header_value = pause_header_value_cb
|
2389
|
+
,.on_url = pause_request_url_cb
|
2390
|
+
,.on_status = pause_response_status_cb
|
2391
|
+
,.on_body = pause_body_cb
|
2392
|
+
,.on_headers_complete = pause_headers_complete_cb
|
2393
|
+
,.on_message_complete = pause_message_complete_cb
|
2394
|
+
,.on_chunk_header = pause_chunk_header_cb
|
2395
|
+
,.on_chunk_complete = pause_chunk_complete_cb
|
2396
|
+
};
|
2397
|
+
|
1149
2398
|
static http_parser_settings settings =
|
1150
2399
|
{.on_message_begin = message_begin_cb
|
1151
2400
|
,.on_header_field = header_field_cb
|
1152
2401
|
,.on_header_value = header_value_cb
|
1153
|
-
,.on_path = request_path_cb
|
1154
2402
|
,.on_url = request_url_cb
|
1155
|
-
,.
|
1156
|
-
,.on_query_string = query_string_cb
|
2403
|
+
,.on_status = response_status_cb
|
1157
2404
|
,.on_body = body_cb
|
1158
2405
|
,.on_headers_complete = headers_complete_cb
|
1159
2406
|
,.on_message_complete = message_complete_cb
|
2407
|
+
,.on_chunk_header = chunk_header_cb
|
2408
|
+
,.on_chunk_complete = chunk_complete_cb
|
1160
2409
|
};
|
1161
2410
|
|
1162
2411
|
static http_parser_settings settings_count_body =
|
1163
2412
|
{.on_message_begin = message_begin_cb
|
1164
2413
|
,.on_header_field = header_field_cb
|
1165
2414
|
,.on_header_value = header_value_cb
|
1166
|
-
,.on_path = request_path_cb
|
1167
2415
|
,.on_url = request_url_cb
|
1168
|
-
,.
|
1169
|
-
,.on_query_string = query_string_cb
|
2416
|
+
,.on_status = response_status_cb
|
1170
2417
|
,.on_body = count_body_cb
|
1171
2418
|
,.on_headers_complete = headers_complete_cb
|
1172
2419
|
,.on_message_complete = message_complete_cb
|
2420
|
+
,.on_chunk_header = chunk_header_cb
|
2421
|
+
,.on_chunk_complete = chunk_complete_cb
|
2422
|
+
};
|
2423
|
+
|
2424
|
+
static http_parser_settings settings_connect =
|
2425
|
+
{.on_message_begin = message_begin_cb
|
2426
|
+
,.on_header_field = header_field_cb
|
2427
|
+
,.on_header_value = header_value_cb
|
2428
|
+
,.on_url = request_url_cb
|
2429
|
+
,.on_status = response_status_cb
|
2430
|
+
,.on_body = dontcall_body_cb
|
2431
|
+
,.on_headers_complete = connect_headers_complete_cb
|
2432
|
+
,.on_message_complete = connect_message_complete_cb
|
2433
|
+
,.on_chunk_header = chunk_header_cb
|
2434
|
+
,.on_chunk_complete = chunk_complete_cb
|
1173
2435
|
};
|
1174
2436
|
|
1175
2437
|
static http_parser_settings settings_null =
|
1176
2438
|
{.on_message_begin = 0
|
1177
2439
|
,.on_header_field = 0
|
1178
2440
|
,.on_header_value = 0
|
1179
|
-
,.on_path = 0
|
1180
2441
|
,.on_url = 0
|
1181
|
-
,.
|
1182
|
-
,.on_query_string = 0
|
2442
|
+
,.on_status = 0
|
1183
2443
|
,.on_body = 0
|
1184
2444
|
,.on_headers_complete = 0
|
1185
2445
|
,.on_message_complete = 0
|
2446
|
+
,.on_chunk_header = 0
|
2447
|
+
,.on_chunk_complete = 0
|
1186
2448
|
};
|
1187
2449
|
|
1188
2450
|
void
|
@@ -1224,12 +2486,37 @@ size_t parse_count_body (const char *buf, size_t len)
|
|
1224
2486
|
return nparsed;
|
1225
2487
|
}
|
1226
2488
|
|
2489
|
+
size_t parse_pause (const char *buf, size_t len)
|
2490
|
+
{
|
2491
|
+
size_t nparsed;
|
2492
|
+
http_parser_settings s = settings_pause;
|
2493
|
+
|
2494
|
+
currently_parsing_eof = (len == 0);
|
2495
|
+
current_pause_parser = &s;
|
2496
|
+
nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
|
2497
|
+
return nparsed;
|
2498
|
+
}
|
2499
|
+
|
2500
|
+
size_t parse_connect (const char *buf, size_t len)
|
2501
|
+
{
|
2502
|
+
size_t nparsed;
|
2503
|
+
currently_parsing_eof = (len == 0);
|
2504
|
+
nparsed = http_parser_execute(parser, &settings_connect, buf, len);
|
2505
|
+
return nparsed;
|
2506
|
+
}
|
2507
|
+
|
1227
2508
|
static inline int
|
1228
2509
|
check_str_eq (const struct message *m,
|
1229
2510
|
const char *prop,
|
1230
2511
|
const char *expected,
|
1231
2512
|
const char *found) {
|
1232
|
-
if (
|
2513
|
+
if ((expected == NULL) != (found == NULL)) {
|
2514
|
+
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
2515
|
+
printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
|
2516
|
+
printf(" found %s\n", (found == NULL) ? "NULL" : found);
|
2517
|
+
return 0;
|
2518
|
+
}
|
2519
|
+
if (expected != NULL && 0 != strcmp(expected, found)) {
|
1233
2520
|
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
1234
2521
|
printf("expected '%s'\n", expected);
|
1235
2522
|
printf(" found '%s'\n", found);
|
@@ -1258,9 +2545,23 @@ check_num_eq (const struct message *m,
|
|
1258
2545
|
#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
|
1259
2546
|
if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
|
1260
2547
|
|
2548
|
+
#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
|
2549
|
+
do { \
|
2550
|
+
char ubuf[256]; \
|
2551
|
+
\
|
2552
|
+
if ((u)->field_set & (1 << (fn))) { \
|
2553
|
+
memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
|
2554
|
+
(u)->field_data[(fn)].len); \
|
2555
|
+
ubuf[(u)->field_data[(fn)].len] = '\0'; \
|
2556
|
+
} else { \
|
2557
|
+
ubuf[0] = '\0'; \
|
2558
|
+
} \
|
2559
|
+
\
|
2560
|
+
check_str_eq(expected, #prop, expected->prop, ubuf); \
|
2561
|
+
} while(0)
|
1261
2562
|
|
1262
2563
|
int
|
1263
|
-
message_eq (int index, const struct message *expected)
|
2564
|
+
message_eq (int index, int connect, const struct message *expected)
|
1264
2565
|
{
|
1265
2566
|
int i;
|
1266
2567
|
struct message *m = &messages[index];
|
@@ -1272,80 +2573,820 @@ message_eq (int index, const struct message *expected)
|
|
1272
2573
|
MESSAGE_CHECK_NUM_EQ(expected, m, method);
|
1273
2574
|
} else {
|
1274
2575
|
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
|
2576
|
+
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
|
2577
|
+
assert(m->status_cb_called);
|
1275
2578
|
}
|
1276
2579
|
|
1277
|
-
|
1278
|
-
|
2580
|
+
if (!connect) {
|
2581
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
|
2582
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
|
2583
|
+
}
|
1279
2584
|
|
1280
2585
|
assert(m->message_begin_cb_called);
|
1281
2586
|
assert(m->headers_complete_cb_called);
|
1282
2587
|
assert(m->message_complete_cb_called);
|
1283
2588
|
|
1284
2589
|
|
1285
|
-
MESSAGE_CHECK_STR_EQ(expected, m, request_path);
|
1286
|
-
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
|
1287
|
-
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
|
1288
2590
|
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
1289
|
-
|
2591
|
+
|
2592
|
+
/* Check URL components; we can't do this w/ CONNECT since it doesn't
|
2593
|
+
* send us a well-formed URL.
|
2594
|
+
*/
|
2595
|
+
if (*m->request_url && m->method != HTTP_CONNECT) {
|
2596
|
+
struct http_parser_url u;
|
2597
|
+
|
2598
|
+
if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
|
2599
|
+
fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
|
2600
|
+
m->request_url);
|
2601
|
+
abort();
|
2602
|
+
}
|
2603
|
+
|
2604
|
+
if (expected->host) {
|
2605
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
|
2606
|
+
}
|
2607
|
+
|
2608
|
+
if (expected->userinfo) {
|
2609
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
|
2610
|
+
}
|
2611
|
+
|
2612
|
+
m->port = (u.field_set & (1 << UF_PORT)) ?
|
2613
|
+
u.port : 0;
|
2614
|
+
|
2615
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
|
2616
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
|
2617
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
|
2618
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, port);
|
2619
|
+
}
|
2620
|
+
|
2621
|
+
if (connect) {
|
2622
|
+
check_num_eq(m, "body_size", 0, m->body_size);
|
2623
|
+
} else if (expected->body_size) {
|
1290
2624
|
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
|
1291
2625
|
} else {
|
1292
2626
|
MESSAGE_CHECK_STR_EQ(expected, m, body);
|
1293
2627
|
}
|
1294
2628
|
|
1295
|
-
|
2629
|
+
if (connect) {
|
2630
|
+
check_num_eq(m, "num_chunks_complete", 0, m->num_chunks_complete);
|
2631
|
+
} else {
|
2632
|
+
assert(m->num_chunks == m->num_chunks_complete);
|
2633
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
|
2634
|
+
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
|
2635
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
|
2636
|
+
}
|
2637
|
+
}
|
2638
|
+
|
2639
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
|
2640
|
+
|
2641
|
+
int r;
|
2642
|
+
for (i = 0; i < m->num_headers; i++) {
|
2643
|
+
r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]);
|
2644
|
+
if (!r) return 0;
|
2645
|
+
r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
|
2646
|
+
if (!r) return 0;
|
2647
|
+
}
|
2648
|
+
|
2649
|
+
if (!connect) {
|
2650
|
+
MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
|
2651
|
+
}
|
2652
|
+
|
2653
|
+
return 1;
|
2654
|
+
}
|
2655
|
+
|
2656
|
+
/* Given a sequence of varargs messages, return the number of them that the
|
2657
|
+
* parser should successfully parse, taking into account that upgraded
|
2658
|
+
* messages prevent all subsequent messages from being parsed.
|
2659
|
+
*/
|
2660
|
+
size_t
|
2661
|
+
count_parsed_messages(const size_t nmsgs, ...) {
|
2662
|
+
size_t i;
|
2663
|
+
va_list ap;
|
2664
|
+
|
2665
|
+
va_start(ap, nmsgs);
|
2666
|
+
|
2667
|
+
for (i = 0; i < nmsgs; i++) {
|
2668
|
+
struct message *m = va_arg(ap, struct message *);
|
2669
|
+
|
2670
|
+
if (m->upgrade) {
|
2671
|
+
va_end(ap);
|
2672
|
+
return i + 1;
|
2673
|
+
}
|
2674
|
+
}
|
2675
|
+
|
2676
|
+
va_end(ap);
|
2677
|
+
return nmsgs;
|
2678
|
+
}
|
2679
|
+
|
2680
|
+
/* Given a sequence of bytes and the number of these that we were able to
|
2681
|
+
* parse, verify that upgrade bodies are correct.
|
2682
|
+
*/
|
2683
|
+
void
|
2684
|
+
upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
|
2685
|
+
va_list ap;
|
2686
|
+
size_t i;
|
2687
|
+
size_t off = 0;
|
2688
|
+
|
2689
|
+
va_start(ap, nmsgs);
|
2690
|
+
|
2691
|
+
for (i = 0; i < nmsgs; i++) {
|
2692
|
+
struct message *m = va_arg(ap, struct message *);
|
2693
|
+
|
2694
|
+
off += strlen(m->raw);
|
2695
|
+
|
2696
|
+
if (m->upgrade) {
|
2697
|
+
off -= strlen(m->upgrade);
|
2698
|
+
|
2699
|
+
/* Check the portion of the response after its specified upgrade */
|
2700
|
+
if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
2701
|
+
abort();
|
2702
|
+
}
|
2703
|
+
|
2704
|
+
/* Fix up the response so that message_eq() will verify the beginning
|
2705
|
+
* of the upgrade */
|
2706
|
+
*(body + nread + strlen(m->upgrade)) = '\0';
|
2707
|
+
messages[num_messages -1 ].upgrade = body + nread;
|
2708
|
+
|
2709
|
+
va_end(ap);
|
2710
|
+
return;
|
2711
|
+
}
|
2712
|
+
}
|
2713
|
+
|
2714
|
+
va_end(ap);
|
2715
|
+
printf("\n\n*** Error: expected a message with upgrade ***\n");
|
2716
|
+
|
2717
|
+
abort();
|
2718
|
+
}
|
2719
|
+
|
2720
|
+
static void
|
2721
|
+
print_error (const char *raw, size_t error_location)
|
2722
|
+
{
|
2723
|
+
fprintf(stderr, "\n*** %s ***\n\n",
|
2724
|
+
http_errno_description(HTTP_PARSER_ERRNO(parser)));
|
2725
|
+
|
2726
|
+
int this_line = 0, char_len = 0;
|
2727
|
+
size_t i, j, len = strlen(raw), error_location_line = 0;
|
2728
|
+
for (i = 0; i < len; i++) {
|
2729
|
+
if (i == error_location) this_line = 1;
|
2730
|
+
switch (raw[i]) {
|
2731
|
+
case '\r':
|
2732
|
+
char_len = 2;
|
2733
|
+
fprintf(stderr, "\\r");
|
2734
|
+
break;
|
2735
|
+
|
2736
|
+
case '\n':
|
2737
|
+
fprintf(stderr, "\\n\n");
|
2738
|
+
|
2739
|
+
if (this_line) goto print;
|
2740
|
+
|
2741
|
+
error_location_line = 0;
|
2742
|
+
continue;
|
2743
|
+
|
2744
|
+
default:
|
2745
|
+
char_len = 1;
|
2746
|
+
fputc(raw[i], stderr);
|
2747
|
+
break;
|
2748
|
+
}
|
2749
|
+
if (!this_line) error_location_line += char_len;
|
2750
|
+
}
|
2751
|
+
|
2752
|
+
fprintf(stderr, "[eof]\n");
|
2753
|
+
|
2754
|
+
print:
|
2755
|
+
for (j = 0; j < error_location_line; j++) {
|
2756
|
+
fputc(' ', stderr);
|
2757
|
+
}
|
2758
|
+
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
2759
|
+
}
|
2760
|
+
|
2761
|
+
void
|
2762
|
+
test_preserve_data (void)
|
2763
|
+
{
|
2764
|
+
char my_data[] = "application-specific data";
|
2765
|
+
http_parser parser;
|
2766
|
+
parser.data = my_data;
|
2767
|
+
http_parser_init(&parser, HTTP_REQUEST);
|
2768
|
+
if (parser.data != my_data) {
|
2769
|
+
printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
|
2770
|
+
abort();
|
2771
|
+
}
|
2772
|
+
}
|
2773
|
+
|
2774
|
+
struct url_test {
|
2775
|
+
const char *name;
|
2776
|
+
const char *url;
|
2777
|
+
int is_connect;
|
2778
|
+
struct http_parser_url u;
|
2779
|
+
int rv;
|
2780
|
+
};
|
2781
|
+
|
2782
|
+
const struct url_test url_tests[] =
|
2783
|
+
{ {.name="proxy request"
|
2784
|
+
,.url="http://hostname/"
|
2785
|
+
,.is_connect=0
|
2786
|
+
,.u=
|
2787
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2788
|
+
,.port=0
|
2789
|
+
,.field_data=
|
2790
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2791
|
+
,{ 7, 8 } /* UF_HOST */
|
2792
|
+
,{ 0, 0 } /* UF_PORT */
|
2793
|
+
,{ 15, 1 } /* UF_PATH */
|
2794
|
+
,{ 0, 0 } /* UF_QUERY */
|
2795
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2796
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2797
|
+
}
|
2798
|
+
}
|
2799
|
+
,.rv=0
|
2800
|
+
}
|
2801
|
+
|
2802
|
+
, {.name="proxy request with port"
|
2803
|
+
,.url="http://hostname:444/"
|
2804
|
+
,.is_connect=0
|
2805
|
+
,.u=
|
2806
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
2807
|
+
,.port=444
|
2808
|
+
,.field_data=
|
2809
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2810
|
+
,{ 7, 8 } /* UF_HOST */
|
2811
|
+
,{ 16, 3 } /* UF_PORT */
|
2812
|
+
,{ 19, 1 } /* UF_PATH */
|
2813
|
+
,{ 0, 0 } /* UF_QUERY */
|
2814
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2815
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2816
|
+
}
|
2817
|
+
}
|
2818
|
+
,.rv=0
|
2819
|
+
}
|
2820
|
+
|
2821
|
+
, {.name="CONNECT request"
|
2822
|
+
,.url="hostname:443"
|
2823
|
+
,.is_connect=1
|
2824
|
+
,.u=
|
2825
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
2826
|
+
,.port=443
|
2827
|
+
,.field_data=
|
2828
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2829
|
+
,{ 0, 8 } /* UF_HOST */
|
2830
|
+
,{ 9, 3 } /* UF_PORT */
|
2831
|
+
,{ 0, 0 } /* UF_PATH */
|
2832
|
+
,{ 0, 0 } /* UF_QUERY */
|
2833
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2834
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2835
|
+
}
|
2836
|
+
}
|
2837
|
+
,.rv=0
|
2838
|
+
}
|
2839
|
+
|
2840
|
+
, {.name="CONNECT request but not connect"
|
2841
|
+
,.url="hostname:443"
|
2842
|
+
,.is_connect=0
|
2843
|
+
,.rv=1
|
2844
|
+
}
|
2845
|
+
|
2846
|
+
, {.name="proxy ipv6 request"
|
2847
|
+
,.url="http://[1:2::3:4]/"
|
2848
|
+
,.is_connect=0
|
2849
|
+
,.u=
|
2850
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2851
|
+
,.port=0
|
2852
|
+
,.field_data=
|
2853
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2854
|
+
,{ 8, 8 } /* UF_HOST */
|
2855
|
+
,{ 0, 0 } /* UF_PORT */
|
2856
|
+
,{ 17, 1 } /* UF_PATH */
|
2857
|
+
,{ 0, 0 } /* UF_QUERY */
|
2858
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2859
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2860
|
+
}
|
2861
|
+
}
|
2862
|
+
,.rv=0
|
2863
|
+
}
|
2864
|
+
|
2865
|
+
, {.name="proxy ipv6 request with port"
|
2866
|
+
,.url="http://[1:2::3:4]:67/"
|
2867
|
+
,.is_connect=0
|
2868
|
+
,.u=
|
2869
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
2870
|
+
,.port=67
|
2871
|
+
,.field_data=
|
2872
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2873
|
+
,{ 8, 8 } /* UF_HOST */
|
2874
|
+
,{ 18, 2 } /* UF_PORT */
|
2875
|
+
,{ 20, 1 } /* UF_PATH */
|
2876
|
+
,{ 0, 0 } /* UF_QUERY */
|
2877
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2878
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2879
|
+
}
|
2880
|
+
}
|
2881
|
+
,.rv=0
|
2882
|
+
}
|
2883
|
+
|
2884
|
+
, {.name="CONNECT ipv6 address"
|
2885
|
+
,.url="[1:2::3:4]:443"
|
2886
|
+
,.is_connect=1
|
2887
|
+
,.u=
|
2888
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
2889
|
+
,.port=443
|
2890
|
+
,.field_data=
|
2891
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2892
|
+
,{ 1, 8 } /* UF_HOST */
|
2893
|
+
,{ 11, 3 } /* UF_PORT */
|
2894
|
+
,{ 0, 0 } /* UF_PATH */
|
2895
|
+
,{ 0, 0 } /* UF_QUERY */
|
2896
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2897
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2898
|
+
}
|
2899
|
+
}
|
2900
|
+
,.rv=0
|
2901
|
+
}
|
2902
|
+
|
2903
|
+
, {.name="ipv4 in ipv6 address"
|
2904
|
+
,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
|
2905
|
+
,.is_connect=0
|
2906
|
+
,.u=
|
2907
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2908
|
+
,.port=0
|
2909
|
+
,.field_data=
|
2910
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2911
|
+
,{ 8, 37 } /* UF_HOST */
|
2912
|
+
,{ 0, 0 } /* UF_PORT */
|
2913
|
+
,{ 46, 1 } /* UF_PATH */
|
2914
|
+
,{ 0, 0 } /* UF_QUERY */
|
2915
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2916
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2917
|
+
}
|
2918
|
+
}
|
2919
|
+
,.rv=0
|
2920
|
+
}
|
2921
|
+
|
2922
|
+
, {.name="extra ? in query string"
|
2923
|
+
,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
|
2924
|
+
"fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
|
2925
|
+
"fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
|
2926
|
+
,.is_connect=0
|
2927
|
+
,.u=
|
2928
|
+
{.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
|
2929
|
+
,.port=0
|
2930
|
+
,.field_data=
|
2931
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2932
|
+
,{ 7, 10 } /* UF_HOST */
|
2933
|
+
,{ 0, 0 } /* UF_PORT */
|
2934
|
+
,{ 17, 12 } /* UF_PATH */
|
2935
|
+
,{ 30,187 } /* UF_QUERY */
|
2936
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2937
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2938
|
+
}
|
2939
|
+
}
|
2940
|
+
,.rv=0
|
2941
|
+
}
|
2942
|
+
|
2943
|
+
, {.name="space URL encoded"
|
2944
|
+
,.url="/toto.html?toto=a%20b"
|
2945
|
+
,.is_connect=0
|
2946
|
+
,.u=
|
2947
|
+
{.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
|
2948
|
+
,.port=0
|
2949
|
+
,.field_data=
|
2950
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2951
|
+
,{ 0, 0 } /* UF_HOST */
|
2952
|
+
,{ 0, 0 } /* UF_PORT */
|
2953
|
+
,{ 0, 10 } /* UF_PATH */
|
2954
|
+
,{ 11, 10 } /* UF_QUERY */
|
2955
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2956
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2957
|
+
}
|
2958
|
+
}
|
2959
|
+
,.rv=0
|
2960
|
+
}
|
2961
|
+
|
2962
|
+
|
2963
|
+
, {.name="URL fragment"
|
2964
|
+
,.url="/toto.html#titi"
|
2965
|
+
,.is_connect=0
|
2966
|
+
,.u=
|
2967
|
+
{.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
|
2968
|
+
,.port=0
|
2969
|
+
,.field_data=
|
2970
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2971
|
+
,{ 0, 0 } /* UF_HOST */
|
2972
|
+
,{ 0, 0 } /* UF_PORT */
|
2973
|
+
,{ 0, 10 } /* UF_PATH */
|
2974
|
+
,{ 0, 0 } /* UF_QUERY */
|
2975
|
+
,{ 11, 4 } /* UF_FRAGMENT */
|
2976
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2977
|
+
}
|
2978
|
+
}
|
2979
|
+
,.rv=0
|
2980
|
+
}
|
2981
|
+
|
2982
|
+
, {.name="complex URL fragment"
|
2983
|
+
,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
|
2984
|
+
"http://www.example.com/index.html?foo=bar&hello=world#midpage"
|
2985
|
+
,.is_connect=0
|
2986
|
+
,.u=
|
2987
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
|
2988
|
+
(1<<UF_FRAGMENT)
|
2989
|
+
,.port=0
|
2990
|
+
,.field_data=
|
2991
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2992
|
+
,{ 7, 22 } /* UF_HOST */
|
2993
|
+
,{ 0, 0 } /* UF_PORT */
|
2994
|
+
,{ 29, 6 } /* UF_PATH */
|
2995
|
+
,{ 36, 69 } /* UF_QUERY */
|
2996
|
+
,{106, 7 } /* UF_FRAGMENT */
|
2997
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2998
|
+
}
|
2999
|
+
}
|
3000
|
+
,.rv=0
|
3001
|
+
}
|
3002
|
+
|
3003
|
+
, {.name="complex URL from node js url parser doc"
|
3004
|
+
,.url="http://host.com:8080/p/a/t/h?query=string#hash"
|
3005
|
+
,.is_connect=0
|
3006
|
+
,.u=
|
3007
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
3008
|
+
(1<<UF_QUERY) | (1<<UF_FRAGMENT)
|
3009
|
+
,.port=8080
|
3010
|
+
,.field_data=
|
3011
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3012
|
+
,{ 7, 8 } /* UF_HOST */
|
3013
|
+
,{ 16, 4 } /* UF_PORT */
|
3014
|
+
,{ 20, 8 } /* UF_PATH */
|
3015
|
+
,{ 29, 12 } /* UF_QUERY */
|
3016
|
+
,{ 42, 4 } /* UF_FRAGMENT */
|
3017
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3018
|
+
}
|
3019
|
+
}
|
3020
|
+
,.rv=0
|
3021
|
+
}
|
3022
|
+
|
3023
|
+
, {.name="complex URL with basic auth from node js url parser doc"
|
3024
|
+
,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
|
3025
|
+
,.is_connect=0
|
3026
|
+
,.u=
|
3027
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
3028
|
+
(1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
|
3029
|
+
,.port=8080
|
3030
|
+
,.field_data=
|
3031
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3032
|
+
,{ 11, 8 } /* UF_HOST */
|
3033
|
+
,{ 20, 4 } /* UF_PORT */
|
3034
|
+
,{ 24, 8 } /* UF_PATH */
|
3035
|
+
,{ 33, 12 } /* UF_QUERY */
|
3036
|
+
,{ 46, 4 } /* UF_FRAGMENT */
|
3037
|
+
,{ 7, 3 } /* UF_USERINFO */
|
3038
|
+
}
|
3039
|
+
}
|
3040
|
+
,.rv=0
|
3041
|
+
}
|
3042
|
+
|
3043
|
+
, {.name="double @"
|
3044
|
+
,.url="http://a:b@@hostname:443/"
|
3045
|
+
,.is_connect=0
|
3046
|
+
,.rv=1
|
3047
|
+
}
|
3048
|
+
|
3049
|
+
, {.name="proxy empty host"
|
3050
|
+
,.url="http://:443/"
|
3051
|
+
,.is_connect=0
|
3052
|
+
,.rv=1
|
3053
|
+
}
|
3054
|
+
|
3055
|
+
, {.name="proxy empty port"
|
3056
|
+
,.url="http://hostname:/"
|
3057
|
+
,.is_connect=0
|
3058
|
+
,.rv=1
|
3059
|
+
}
|
3060
|
+
|
3061
|
+
, {.name="CONNECT with basic auth"
|
3062
|
+
,.url="a:b@hostname:443"
|
3063
|
+
,.is_connect=1
|
3064
|
+
,.rv=1
|
3065
|
+
}
|
3066
|
+
|
3067
|
+
, {.name="CONNECT empty host"
|
3068
|
+
,.url=":443"
|
3069
|
+
,.is_connect=1
|
3070
|
+
,.rv=1
|
3071
|
+
}
|
3072
|
+
|
3073
|
+
, {.name="CONNECT empty port"
|
3074
|
+
,.url="hostname:"
|
3075
|
+
,.is_connect=1
|
3076
|
+
,.rv=1
|
3077
|
+
}
|
3078
|
+
|
3079
|
+
, {.name="CONNECT with extra bits"
|
3080
|
+
,.url="hostname:443/"
|
3081
|
+
,.is_connect=1
|
3082
|
+
,.rv=1
|
3083
|
+
}
|
3084
|
+
|
3085
|
+
, {.name="space in URL"
|
3086
|
+
,.url="/foo bar/"
|
3087
|
+
,.rv=1 /* s_dead */
|
3088
|
+
}
|
3089
|
+
|
3090
|
+
, {.name="proxy basic auth with space url encoded"
|
3091
|
+
,.url="http://a%20:b@host.com/"
|
3092
|
+
,.is_connect=0
|
3093
|
+
,.u=
|
3094
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
3095
|
+
,.port=0
|
3096
|
+
,.field_data=
|
3097
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3098
|
+
,{ 14, 8 } /* UF_HOST */
|
3099
|
+
,{ 0, 0 } /* UF_PORT */
|
3100
|
+
,{ 22, 1 } /* UF_PATH */
|
3101
|
+
,{ 0, 0 } /* UF_QUERY */
|
3102
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3103
|
+
,{ 7, 6 } /* UF_USERINFO */
|
3104
|
+
}
|
3105
|
+
}
|
3106
|
+
,.rv=0
|
3107
|
+
}
|
3108
|
+
|
3109
|
+
, {.name="carriage return in URL"
|
3110
|
+
,.url="/foo\rbar/"
|
3111
|
+
,.rv=1 /* s_dead */
|
3112
|
+
}
|
3113
|
+
|
3114
|
+
, {.name="proxy double : in URL"
|
3115
|
+
,.url="http://hostname::443/"
|
3116
|
+
,.rv=1 /* s_dead */
|
3117
|
+
}
|
3118
|
+
|
3119
|
+
, {.name="proxy basic auth with double :"
|
3120
|
+
,.url="http://a::b@host.com/"
|
3121
|
+
,.is_connect=0
|
3122
|
+
,.u=
|
3123
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
3124
|
+
,.port=0
|
3125
|
+
,.field_data=
|
3126
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3127
|
+
,{ 12, 8 } /* UF_HOST */
|
3128
|
+
,{ 0, 0 } /* UF_PORT */
|
3129
|
+
,{ 20, 1 } /* UF_PATH */
|
3130
|
+
,{ 0, 0 } /* UF_QUERY */
|
3131
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3132
|
+
,{ 7, 4 } /* UF_USERINFO */
|
3133
|
+
}
|
3134
|
+
}
|
3135
|
+
,.rv=0
|
3136
|
+
}
|
3137
|
+
|
3138
|
+
, {.name="line feed in URL"
|
3139
|
+
,.url="/foo\nbar/"
|
3140
|
+
,.rv=1 /* s_dead */
|
3141
|
+
}
|
3142
|
+
|
3143
|
+
, {.name="proxy empty basic auth"
|
3144
|
+
,.url="http://@hostname/fo"
|
3145
|
+
,.u=
|
3146
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
|
3147
|
+
,.port=0
|
3148
|
+
,.field_data=
|
3149
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3150
|
+
,{ 8, 8 } /* UF_HOST */
|
3151
|
+
,{ 0, 0 } /* UF_PORT */
|
3152
|
+
,{ 16, 3 } /* UF_PATH */
|
3153
|
+
,{ 0, 0 } /* UF_QUERY */
|
3154
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3155
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3156
|
+
}
|
3157
|
+
}
|
3158
|
+
,.rv=0
|
3159
|
+
}
|
3160
|
+
, {.name="proxy line feed in hostname"
|
3161
|
+
,.url="http://host\name/fo"
|
3162
|
+
,.rv=1 /* s_dead */
|
3163
|
+
}
|
3164
|
+
|
3165
|
+
, {.name="proxy % in hostname"
|
3166
|
+
,.url="http://host%name/fo"
|
3167
|
+
,.rv=1 /* s_dead */
|
3168
|
+
}
|
3169
|
+
|
3170
|
+
, {.name="proxy ; in hostname"
|
3171
|
+
,.url="http://host;ame/fo"
|
3172
|
+
,.rv=1 /* s_dead */
|
3173
|
+
}
|
3174
|
+
|
3175
|
+
, {.name="proxy basic auth with unreservedchars"
|
3176
|
+
,.url="http://a!;-_!=+$@host.com/"
|
3177
|
+
,.is_connect=0
|
3178
|
+
,.u=
|
3179
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
3180
|
+
,.port=0
|
3181
|
+
,.field_data=
|
3182
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3183
|
+
,{ 17, 8 } /* UF_HOST */
|
3184
|
+
,{ 0, 0 } /* UF_PORT */
|
3185
|
+
,{ 25, 1 } /* UF_PATH */
|
3186
|
+
,{ 0, 0 } /* UF_QUERY */
|
3187
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3188
|
+
,{ 7, 9 } /* UF_USERINFO */
|
3189
|
+
}
|
3190
|
+
}
|
3191
|
+
,.rv=0
|
3192
|
+
}
|
3193
|
+
|
3194
|
+
, {.name="proxy only empty basic auth"
|
3195
|
+
,.url="http://@/fo"
|
3196
|
+
,.rv=1 /* s_dead */
|
3197
|
+
}
|
3198
|
+
|
3199
|
+
, {.name="proxy only basic auth"
|
3200
|
+
,.url="http://toto@/fo"
|
3201
|
+
,.rv=1 /* s_dead */
|
3202
|
+
}
|
3203
|
+
|
3204
|
+
, {.name="proxy emtpy hostname"
|
3205
|
+
,.url="http:///fo"
|
3206
|
+
,.rv=1 /* s_dead */
|
3207
|
+
}
|
3208
|
+
|
3209
|
+
, {.name="proxy = in URL"
|
3210
|
+
,.url="http://host=ame/fo"
|
3211
|
+
,.rv=1 /* s_dead */
|
3212
|
+
}
|
3213
|
+
|
3214
|
+
, {.name="ipv6 address with Zone ID"
|
3215
|
+
,.url="http://[fe80::a%25eth0]/"
|
3216
|
+
,.is_connect=0
|
3217
|
+
,.u=
|
3218
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
|
3219
|
+
,.port=0
|
3220
|
+
,.field_data=
|
3221
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3222
|
+
,{ 8, 14 } /* UF_HOST */
|
3223
|
+
,{ 0, 0 } /* UF_PORT */
|
3224
|
+
,{ 23, 1 } /* UF_PATH */
|
3225
|
+
,{ 0, 0 } /* UF_QUERY */
|
3226
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3227
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3228
|
+
}
|
3229
|
+
}
|
3230
|
+
,.rv=0
|
3231
|
+
}
|
3232
|
+
|
3233
|
+
, {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
|
3234
|
+
,.url="http://[fe80::a%eth0]/"
|
3235
|
+
,.is_connect=0
|
3236
|
+
,.u=
|
3237
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
|
3238
|
+
,.port=0
|
3239
|
+
,.field_data=
|
3240
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
3241
|
+
,{ 8, 12 } /* UF_HOST */
|
3242
|
+
,{ 0, 0 } /* UF_PORT */
|
3243
|
+
,{ 21, 1 } /* UF_PATH */
|
3244
|
+
,{ 0, 0 } /* UF_QUERY */
|
3245
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3246
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3247
|
+
}
|
3248
|
+
}
|
3249
|
+
,.rv=0
|
3250
|
+
}
|
3251
|
+
|
3252
|
+
, {.name="ipv6 address ending with '%'"
|
3253
|
+
,.url="http://[fe80::a%]/"
|
3254
|
+
,.rv=1 /* s_dead */
|
3255
|
+
}
|
3256
|
+
|
3257
|
+
, {.name="ipv6 address with Zone ID including bad character"
|
3258
|
+
,.url="http://[fe80::a%$HOME]/"
|
3259
|
+
,.rv=1 /* s_dead */
|
3260
|
+
}
|
1296
3261
|
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
if (!r) return 0;
|
1301
|
-
r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
|
1302
|
-
if (!r) return 0;
|
3262
|
+
, {.name="just ipv6 Zone ID"
|
3263
|
+
,.url="http://[%eth0]/"
|
3264
|
+
,.rv=1 /* s_dead */
|
1303
3265
|
}
|
1304
3266
|
|
1305
|
-
|
1306
|
-
}
|
3267
|
+
#if HTTP_PARSER_STRICT
|
1307
3268
|
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
3269
|
+
, {.name="tab in URL"
|
3270
|
+
,.url="/foo\tbar/"
|
3271
|
+
,.rv=1 /* s_dead */
|
3272
|
+
}
|
1312
3273
|
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
switch (raw[i]) {
|
1318
|
-
case '\r':
|
1319
|
-
char_len = 2;
|
1320
|
-
fprintf(stderr, "\\r");
|
1321
|
-
break;
|
3274
|
+
, {.name="form feed in URL"
|
3275
|
+
,.url="/foo\fbar/"
|
3276
|
+
,.rv=1 /* s_dead */
|
3277
|
+
}
|
1322
3278
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
3279
|
+
#else /* !HTTP_PARSER_STRICT */
|
3280
|
+
|
3281
|
+
, {.name="tab in URL"
|
3282
|
+
,.url="/foo\tbar/"
|
3283
|
+
,.u=
|
3284
|
+
{.field_set=(1 << UF_PATH)
|
3285
|
+
,.field_data=
|
3286
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
3287
|
+
,{ 0, 0 } /* UF_HOST */
|
3288
|
+
,{ 0, 0 } /* UF_PORT */
|
3289
|
+
,{ 0, 9 } /* UF_PATH */
|
3290
|
+
,{ 0, 0 } /* UF_QUERY */
|
3291
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3292
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3293
|
+
}
|
3294
|
+
}
|
3295
|
+
,.rv=0
|
3296
|
+
}
|
1326
3297
|
|
1327
|
-
|
3298
|
+
, {.name="form feed in URL"
|
3299
|
+
,.url="/foo\fbar/"
|
3300
|
+
,.u=
|
3301
|
+
{.field_set=(1 << UF_PATH)
|
3302
|
+
,.field_data=
|
3303
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
3304
|
+
,{ 0, 0 } /* UF_HOST */
|
3305
|
+
,{ 0, 0 } /* UF_PORT */
|
3306
|
+
,{ 0, 9 } /* UF_PATH */
|
3307
|
+
,{ 0, 0 } /* UF_QUERY */
|
3308
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
3309
|
+
,{ 0, 0 } /* UF_USERINFO */
|
3310
|
+
}
|
3311
|
+
}
|
3312
|
+
,.rv=0
|
3313
|
+
}
|
3314
|
+
#endif
|
3315
|
+
};
|
1328
3316
|
|
1329
|
-
|
1330
|
-
|
3317
|
+
void
|
3318
|
+
dump_url (const char *url, const struct http_parser_url *u)
|
3319
|
+
{
|
3320
|
+
unsigned int i;
|
1331
3321
|
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
3322
|
+
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
3323
|
+
for (i = 0; i < UF_MAX; i++) {
|
3324
|
+
if ((u->field_set & (1 << i)) == 0) {
|
3325
|
+
printf("\tfield_data[%u]: unset\n", i);
|
3326
|
+
continue;
|
1336
3327
|
}
|
1337
|
-
|
3328
|
+
|
3329
|
+
printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
|
3330
|
+
i,
|
3331
|
+
u->field_data[i].off,
|
3332
|
+
u->field_data[i].len,
|
3333
|
+
u->field_data[i].len,
|
3334
|
+
url + u->field_data[i].off);
|
1338
3335
|
}
|
3336
|
+
}
|
1339
3337
|
|
1340
|
-
|
3338
|
+
void
|
3339
|
+
test_parse_url (void)
|
3340
|
+
{
|
3341
|
+
struct http_parser_url u;
|
3342
|
+
const struct url_test *test;
|
3343
|
+
unsigned int i;
|
3344
|
+
int rv;
|
3345
|
+
|
3346
|
+
for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
|
3347
|
+
test = &url_tests[i];
|
3348
|
+
memset(&u, 0, sizeof(u));
|
3349
|
+
|
3350
|
+
rv = http_parser_parse_url(test->url,
|
3351
|
+
strlen(test->url),
|
3352
|
+
test->is_connect,
|
3353
|
+
&u);
|
3354
|
+
|
3355
|
+
if (test->rv == 0) {
|
3356
|
+
if (rv != 0) {
|
3357
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
3358
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
3359
|
+
abort();
|
3360
|
+
}
|
1341
3361
|
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
3362
|
+
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
|
3363
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
|
3364
|
+
test->url, test->name);
|
3365
|
+
|
3366
|
+
printf("target http_parser_url:\n");
|
3367
|
+
dump_url(test->url, &test->u);
|
3368
|
+
printf("result http_parser_url:\n");
|
3369
|
+
dump_url(test->url, &u);
|
3370
|
+
|
3371
|
+
abort();
|
3372
|
+
}
|
3373
|
+
} else {
|
3374
|
+
/* test->rv != 0 */
|
3375
|
+
if (rv == 0) {
|
3376
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
3377
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
3378
|
+
abort();
|
3379
|
+
}
|
3380
|
+
}
|
1345
3381
|
}
|
1346
|
-
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
1347
3382
|
}
|
1348
3383
|
|
3384
|
+
void
|
3385
|
+
test_method_str (void)
|
3386
|
+
{
|
3387
|
+
assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
|
3388
|
+
assert(0 == strcmp("<unknown>", http_method_str(1337)));
|
3389
|
+
}
|
1349
3390
|
|
1350
3391
|
void
|
1351
3392
|
test_message (const struct message *message)
|
@@ -1363,41 +3404,45 @@ test_message (const struct message *message)
|
|
1363
3404
|
if (msg1len) {
|
1364
3405
|
read = parse(msg1, msg1len);
|
1365
3406
|
|
1366
|
-
if (message->upgrade && parser->upgrade)
|
3407
|
+
if (message->upgrade && parser->upgrade && num_messages > 0) {
|
3408
|
+
messages[num_messages - 1].upgrade = msg1 + read;
|
3409
|
+
goto test;
|
3410
|
+
}
|
1367
3411
|
|
1368
3412
|
if (read != msg1len) {
|
1369
3413
|
print_error(msg1, read);
|
1370
|
-
|
3414
|
+
abort();
|
1371
3415
|
}
|
1372
3416
|
}
|
1373
3417
|
|
1374
3418
|
|
1375
3419
|
read = parse(msg2, msg2len);
|
1376
3420
|
|
1377
|
-
if (message->upgrade && parser->upgrade)
|
3421
|
+
if (message->upgrade && parser->upgrade) {
|
3422
|
+
messages[num_messages - 1].upgrade = msg2 + read;
|
3423
|
+
goto test;
|
3424
|
+
}
|
1378
3425
|
|
1379
3426
|
if (read != msg2len) {
|
1380
3427
|
print_error(msg2, read);
|
1381
|
-
|
3428
|
+
abort();
|
1382
3429
|
}
|
1383
3430
|
|
1384
3431
|
read = parse(NULL, 0);
|
1385
3432
|
|
1386
|
-
if (message->upgrade && parser->upgrade) goto test;
|
1387
|
-
|
1388
3433
|
if (read != 0) {
|
1389
3434
|
print_error(message->raw, read);
|
1390
|
-
|
3435
|
+
abort();
|
1391
3436
|
}
|
1392
3437
|
|
1393
3438
|
test:
|
1394
3439
|
|
1395
3440
|
if (num_messages != 1) {
|
1396
3441
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1397
|
-
|
3442
|
+
abort();
|
1398
3443
|
}
|
1399
3444
|
|
1400
|
-
if(!message_eq(0, message))
|
3445
|
+
if(!message_eq(0, 0, message)) abort();
|
1401
3446
|
|
1402
3447
|
parser_free();
|
1403
3448
|
}
|
@@ -1418,7 +3463,7 @@ test_message_count_body (const struct message *message)
|
|
1418
3463
|
read = parse_count_body(message->raw + i, toread);
|
1419
3464
|
if (read != toread) {
|
1420
3465
|
print_error(message->raw, read);
|
1421
|
-
|
3466
|
+
abort();
|
1422
3467
|
}
|
1423
3468
|
}
|
1424
3469
|
|
@@ -1426,36 +3471,224 @@ test_message_count_body (const struct message *message)
|
|
1426
3471
|
read = parse_count_body(NULL, 0);
|
1427
3472
|
if (read != 0) {
|
1428
3473
|
print_error(message->raw, read);
|
1429
|
-
|
3474
|
+
abort();
|
1430
3475
|
}
|
1431
3476
|
|
1432
3477
|
if (num_messages != 1) {
|
1433
3478
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1434
|
-
|
3479
|
+
abort();
|
1435
3480
|
}
|
1436
3481
|
|
1437
|
-
if(!message_eq(0, message))
|
3482
|
+
if(!message_eq(0, 0, message)) abort();
|
1438
3483
|
|
1439
3484
|
parser_free();
|
1440
3485
|
}
|
1441
3486
|
|
1442
3487
|
void
|
1443
|
-
|
3488
|
+
test_simple_type (const char *buf,
|
3489
|
+
enum http_errno err_expected,
|
3490
|
+
enum http_parser_type type)
|
1444
3491
|
{
|
1445
|
-
parser_init(
|
3492
|
+
parser_init(type);
|
1446
3493
|
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
pass &= (parsed == 0);
|
3494
|
+
enum http_errno err;
|
3495
|
+
|
3496
|
+
parse(buf, strlen(buf));
|
3497
|
+
err = HTTP_PARSER_ERRNO(parser);
|
3498
|
+
parse(NULL, 0);
|
1453
3499
|
|
1454
3500
|
parser_free();
|
1455
3501
|
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
3502
|
+
/* In strict mode, allow us to pass with an unexpected HPE_STRICT as
|
3503
|
+
* long as the caller isn't expecting success.
|
3504
|
+
*/
|
3505
|
+
#if HTTP_PARSER_STRICT
|
3506
|
+
if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
|
3507
|
+
#else
|
3508
|
+
if (err_expected != err) {
|
3509
|
+
#endif
|
3510
|
+
fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
|
3511
|
+
http_errno_name(err_expected), http_errno_name(err), buf);
|
3512
|
+
abort();
|
3513
|
+
}
|
3514
|
+
}
|
3515
|
+
|
3516
|
+
void
|
3517
|
+
test_simple (const char *buf, enum http_errno err_expected)
|
3518
|
+
{
|
3519
|
+
test_simple_type(buf, err_expected, HTTP_REQUEST);
|
3520
|
+
}
|
3521
|
+
|
3522
|
+
void
|
3523
|
+
test_invalid_header_content (int req, const char* str)
|
3524
|
+
{
|
3525
|
+
http_parser parser;
|
3526
|
+
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
3527
|
+
size_t parsed;
|
3528
|
+
const char *buf;
|
3529
|
+
buf = req ?
|
3530
|
+
"GET / HTTP/1.1\r\n" :
|
3531
|
+
"HTTP/1.1 200 OK\r\n";
|
3532
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3533
|
+
assert(parsed == strlen(buf));
|
3534
|
+
|
3535
|
+
buf = str;
|
3536
|
+
size_t buflen = strlen(buf);
|
3537
|
+
|
3538
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3539
|
+
if (parsed != buflen) {
|
3540
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
|
3541
|
+
return;
|
3542
|
+
}
|
3543
|
+
|
3544
|
+
fprintf(stderr,
|
3545
|
+
"\n*** Error expected but none in invalid header content test ***\n");
|
3546
|
+
abort();
|
3547
|
+
}
|
3548
|
+
|
3549
|
+
void
|
3550
|
+
test_invalid_header_field_content_error (int req)
|
3551
|
+
{
|
3552
|
+
test_invalid_header_content(req, "Foo: F\01ailure");
|
3553
|
+
test_invalid_header_content(req, "Foo: B\02ar");
|
3554
|
+
}
|
3555
|
+
|
3556
|
+
void
|
3557
|
+
test_invalid_header_field (int req, const char* str)
|
3558
|
+
{
|
3559
|
+
http_parser parser;
|
3560
|
+
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
3561
|
+
size_t parsed;
|
3562
|
+
const char *buf;
|
3563
|
+
buf = req ?
|
3564
|
+
"GET / HTTP/1.1\r\n" :
|
3565
|
+
"HTTP/1.1 200 OK\r\n";
|
3566
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3567
|
+
assert(parsed == strlen(buf));
|
3568
|
+
|
3569
|
+
buf = str;
|
3570
|
+
size_t buflen = strlen(buf);
|
3571
|
+
|
3572
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3573
|
+
if (parsed != buflen) {
|
3574
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
|
3575
|
+
return;
|
3576
|
+
}
|
3577
|
+
|
3578
|
+
fprintf(stderr,
|
3579
|
+
"\n*** Error expected but none in invalid header token test ***\n");
|
3580
|
+
abort();
|
3581
|
+
}
|
3582
|
+
|
3583
|
+
void
|
3584
|
+
test_invalid_header_field_token_error (int req)
|
3585
|
+
{
|
3586
|
+
test_invalid_header_field(req, "Fo@: Failure");
|
3587
|
+
test_invalid_header_field(req, "Foo\01\test: Bar");
|
3588
|
+
}
|
3589
|
+
|
3590
|
+
void
|
3591
|
+
test_double_content_length_error (int req)
|
3592
|
+
{
|
3593
|
+
http_parser parser;
|
3594
|
+
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
3595
|
+
size_t parsed;
|
3596
|
+
const char *buf;
|
3597
|
+
buf = req ?
|
3598
|
+
"GET / HTTP/1.1\r\n" :
|
3599
|
+
"HTTP/1.1 200 OK\r\n";
|
3600
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3601
|
+
assert(parsed == strlen(buf));
|
3602
|
+
|
3603
|
+
buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
|
3604
|
+
size_t buflen = strlen(buf);
|
3605
|
+
|
3606
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3607
|
+
if (parsed != buflen) {
|
3608
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
|
3609
|
+
return;
|
3610
|
+
}
|
3611
|
+
|
3612
|
+
fprintf(stderr,
|
3613
|
+
"\n*** Error expected but none in double content-length test ***\n");
|
3614
|
+
abort();
|
3615
|
+
}
|
3616
|
+
|
3617
|
+
void
|
3618
|
+
test_chunked_content_length_error (int req)
|
3619
|
+
{
|
3620
|
+
http_parser parser;
|
3621
|
+
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
3622
|
+
size_t parsed;
|
3623
|
+
const char *buf;
|
3624
|
+
buf = req ?
|
3625
|
+
"GET / HTTP/1.1\r\n" :
|
3626
|
+
"HTTP/1.1 200 OK\r\n";
|
3627
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3628
|
+
assert(parsed == strlen(buf));
|
3629
|
+
|
3630
|
+
buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
|
3631
|
+
size_t buflen = strlen(buf);
|
3632
|
+
|
3633
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3634
|
+
if (parsed != buflen) {
|
3635
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
|
3636
|
+
return;
|
3637
|
+
}
|
3638
|
+
|
3639
|
+
fprintf(stderr,
|
3640
|
+
"\n*** Error expected but none in chunked content-length test ***\n");
|
3641
|
+
abort();
|
3642
|
+
}
|
3643
|
+
|
3644
|
+
void
|
3645
|
+
test_header_cr_no_lf_error (int req)
|
3646
|
+
{
|
3647
|
+
http_parser parser;
|
3648
|
+
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
3649
|
+
size_t parsed;
|
3650
|
+
const char *buf;
|
3651
|
+
buf = req ?
|
3652
|
+
"GET / HTTP/1.1\r\n" :
|
3653
|
+
"HTTP/1.1 200 OK\r\n";
|
3654
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3655
|
+
assert(parsed == strlen(buf));
|
3656
|
+
|
3657
|
+
buf = "Foo: 1\rBar: 1\r\n\r\n";
|
3658
|
+
size_t buflen = strlen(buf);
|
3659
|
+
|
3660
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3661
|
+
if (parsed != buflen) {
|
3662
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
|
3663
|
+
return;
|
3664
|
+
}
|
3665
|
+
|
3666
|
+
fprintf(stderr,
|
3667
|
+
"\n*** Error expected but none in header whitespace test ***\n");
|
3668
|
+
abort();
|
3669
|
+
}
|
3670
|
+
|
3671
|
+
void
|
3672
|
+
test_no_overflow_parse_url (void)
|
3673
|
+
{
|
3674
|
+
int rv;
|
3675
|
+
struct http_parser_url u;
|
3676
|
+
|
3677
|
+
http_parser_url_init(&u);
|
3678
|
+
rv = http_parser_parse_url("http://example.com:8001", 22, 0, &u);
|
3679
|
+
|
3680
|
+
if (rv != 0) {
|
3681
|
+
fprintf(stderr,
|
3682
|
+
"\n*** test_no_overflow_parse_url invalid return value=%d\n",
|
3683
|
+
rv);
|
3684
|
+
abort();
|
3685
|
+
}
|
3686
|
+
|
3687
|
+
if (u.port != 800) {
|
3688
|
+
fprintf(stderr,
|
3689
|
+
"\n*** test_no_overflow_parse_url invalid port number=%d\n",
|
3690
|
+
u.port);
|
3691
|
+
abort();
|
1459
3692
|
}
|
1460
3693
|
}
|
1461
3694
|
|
@@ -1471,16 +3704,83 @@ test_header_overflow_error (int req)
|
|
1471
3704
|
assert(parsed == strlen(buf));
|
1472
3705
|
|
1473
3706
|
buf = "header-key: header-value\r\n";
|
3707
|
+
size_t buflen = strlen(buf);
|
3708
|
+
|
1474
3709
|
int i;
|
1475
3710
|
for (i = 0; i < 10000; i++) {
|
1476
|
-
|
3711
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
3712
|
+
if (parsed != buflen) {
|
1477
3713
|
//fprintf(stderr, "error found on iter %d\n", i);
|
3714
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
|
1478
3715
|
return;
|
1479
3716
|
}
|
1480
3717
|
}
|
1481
3718
|
|
1482
3719
|
fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
|
1483
|
-
|
3720
|
+
abort();
|
3721
|
+
}
|
3722
|
+
|
3723
|
+
|
3724
|
+
void
|
3725
|
+
test_header_nread_value ()
|
3726
|
+
{
|
3727
|
+
http_parser parser;
|
3728
|
+
http_parser_init(&parser, HTTP_REQUEST);
|
3729
|
+
size_t parsed;
|
3730
|
+
const char *buf;
|
3731
|
+
buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
|
3732
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
3733
|
+
assert(parsed == strlen(buf));
|
3734
|
+
|
3735
|
+
assert(parser.nread == strlen(buf));
|
3736
|
+
}
|
3737
|
+
|
3738
|
+
|
3739
|
+
static void
|
3740
|
+
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
|
3741
|
+
{
|
3742
|
+
http_parser parser;
|
3743
|
+
http_parser_init(&parser, HTTP_RESPONSE);
|
3744
|
+
http_parser_execute(&parser, &settings_null, buf, buflen);
|
3745
|
+
|
3746
|
+
if (expect_ok)
|
3747
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
|
3748
|
+
else
|
3749
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
|
3750
|
+
}
|
3751
|
+
|
3752
|
+
void
|
3753
|
+
test_header_content_length_overflow_error (void)
|
3754
|
+
{
|
3755
|
+
#define X(size) \
|
3756
|
+
"HTTP/1.1 200 OK\r\n" \
|
3757
|
+
"Content-Length: " #size "\r\n" \
|
3758
|
+
"\r\n"
|
3759
|
+
const char a[] = X(1844674407370955160); /* 2^64 / 10 - 1 */
|
3760
|
+
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
3761
|
+
const char c[] = X(18446744073709551616); /* 2^64 */
|
3762
|
+
#undef X
|
3763
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
3764
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
3765
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
3766
|
+
}
|
3767
|
+
|
3768
|
+
void
|
3769
|
+
test_chunk_content_length_overflow_error (void)
|
3770
|
+
{
|
3771
|
+
#define X(size) \
|
3772
|
+
"HTTP/1.1 200 OK\r\n" \
|
3773
|
+
"Transfer-Encoding: chunked\r\n" \
|
3774
|
+
"\r\n" \
|
3775
|
+
#size "\r\n" \
|
3776
|
+
"..."
|
3777
|
+
const char a[] = X(FFFFFFFFFFFFFFE); /* 2^64 / 16 - 1 */
|
3778
|
+
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
3779
|
+
const char c[] = X(10000000000000000); /* 2^64 */
|
3780
|
+
#undef X
|
3781
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
3782
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
3783
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
1484
3784
|
}
|
1485
3785
|
|
1486
3786
|
void
|
@@ -1491,8 +3791,8 @@ test_no_overflow_long_body (int req, size_t length)
|
|
1491
3791
|
size_t parsed;
|
1492
3792
|
size_t i;
|
1493
3793
|
char buf1[3000];
|
1494
|
-
size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %
|
1495
|
-
req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", length);
|
3794
|
+
size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
|
3795
|
+
req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
|
1496
3796
|
parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
|
1497
3797
|
if (parsed != buf1len)
|
1498
3798
|
goto err;
|
@@ -1510,21 +3810,16 @@ test_no_overflow_long_body (int req, size_t length)
|
|
1510
3810
|
|
1511
3811
|
err:
|
1512
3812
|
fprintf(stderr,
|
1513
|
-
"\n*** error in test_no_overflow_long_body %s of length %
|
3813
|
+
"\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
|
1514
3814
|
req ? "REQUEST" : "RESPONSE",
|
1515
|
-
length);
|
1516
|
-
|
3815
|
+
(unsigned long)length);
|
3816
|
+
abort();
|
1517
3817
|
}
|
1518
3818
|
|
1519
3819
|
void
|
1520
3820
|
test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
|
1521
3821
|
{
|
1522
|
-
int message_count =
|
1523
|
-
if (!r1->upgrade) {
|
1524
|
-
message_count++;
|
1525
|
-
if (!r2->upgrade) message_count++;
|
1526
|
-
}
|
1527
|
-
int has_upgrade = (message_count < 3 || r3->upgrade);
|
3822
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1528
3823
|
|
1529
3824
|
char total[ strlen(r1->raw)
|
1530
3825
|
+ strlen(r2->raw)
|
@@ -1543,36 +3838,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
|
|
1543
3838
|
|
1544
3839
|
read = parse(total, strlen(total));
|
1545
3840
|
|
1546
|
-
if (
|
3841
|
+
if (parser->upgrade) {
|
3842
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
3843
|
+
goto test;
|
3844
|
+
}
|
1547
3845
|
|
1548
3846
|
if (read != strlen(total)) {
|
1549
3847
|
print_error(total, read);
|
1550
|
-
|
3848
|
+
abort();
|
1551
3849
|
}
|
1552
3850
|
|
1553
3851
|
read = parse(NULL, 0);
|
1554
3852
|
|
1555
|
-
if (has_upgrade && parser->upgrade) goto test;
|
1556
|
-
|
1557
3853
|
if (read != 0) {
|
1558
3854
|
print_error(total, read);
|
1559
|
-
|
3855
|
+
abort();
|
1560
3856
|
}
|
1561
3857
|
|
1562
3858
|
test:
|
1563
3859
|
|
1564
3860
|
if (message_count != num_messages) {
|
1565
3861
|
fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
|
1566
|
-
|
3862
|
+
abort();
|
1567
3863
|
}
|
1568
3864
|
|
1569
|
-
if (!message_eq(0, r1))
|
1570
|
-
if (message_count > 1)
|
1571
|
-
|
1572
|
-
if (message_count > 2) {
|
1573
|
-
if (!message_eq(2, r3)) exit(1);
|
1574
|
-
}
|
1575
|
-
}
|
3865
|
+
if (!message_eq(0, 0, r1)) abort();
|
3866
|
+
if (message_count > 1 && !message_eq(1, 0, r2)) abort();
|
3867
|
+
if (message_count > 2 && !message_eq(2, 0, r3)) abort();
|
1576
3868
|
|
1577
3869
|
parser_free();
|
1578
3870
|
}
|
@@ -1601,6 +3893,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1601
3893
|
int ops = 0 ;
|
1602
3894
|
|
1603
3895
|
size_t buf1_len, buf2_len, buf3_len;
|
3896
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1604
3897
|
|
1605
3898
|
int i,j,type_both;
|
1606
3899
|
for (type_both = 0; type_both < 2; type_both ++ ) {
|
@@ -1616,40 +3909,40 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1616
3909
|
parser_init(type_both ? HTTP_BOTH : r1->type);
|
1617
3910
|
|
1618
3911
|
buf1_len = i;
|
1619
|
-
|
3912
|
+
strlncpy(buf1, sizeof(buf1), total, buf1_len);
|
1620
3913
|
buf1[buf1_len] = 0;
|
1621
3914
|
|
1622
3915
|
buf2_len = j - i;
|
1623
|
-
|
3916
|
+
strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
|
1624
3917
|
buf2[buf2_len] = 0;
|
1625
3918
|
|
1626
3919
|
buf3_len = total_len - j;
|
1627
|
-
|
3920
|
+
strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
|
1628
3921
|
buf3[buf3_len] = 0;
|
1629
3922
|
|
1630
3923
|
read = parse(buf1, buf1_len);
|
1631
3924
|
|
1632
|
-
if (
|
3925
|
+
if (parser->upgrade) goto test;
|
1633
3926
|
|
1634
3927
|
if (read != buf1_len) {
|
1635
3928
|
print_error(buf1, read);
|
1636
3929
|
goto error;
|
1637
3930
|
}
|
1638
3931
|
|
1639
|
-
read
|
3932
|
+
read += parse(buf2, buf2_len);
|
1640
3933
|
|
1641
|
-
if (
|
3934
|
+
if (parser->upgrade) goto test;
|
1642
3935
|
|
1643
|
-
if (read != buf2_len) {
|
3936
|
+
if (read != buf1_len + buf2_len) {
|
1644
3937
|
print_error(buf2, read);
|
1645
3938
|
goto error;
|
1646
3939
|
}
|
1647
3940
|
|
1648
|
-
read
|
3941
|
+
read += parse(buf3, buf3_len);
|
1649
3942
|
|
1650
|
-
if (
|
3943
|
+
if (parser->upgrade) goto test;
|
1651
3944
|
|
1652
|
-
if (read != buf3_len) {
|
3945
|
+
if (read != buf1_len + buf2_len + buf3_len) {
|
1653
3946
|
print_error(buf3, read);
|
1654
3947
|
goto error;
|
1655
3948
|
}
|
@@ -1657,23 +3950,27 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1657
3950
|
parse(NULL, 0);
|
1658
3951
|
|
1659
3952
|
test:
|
3953
|
+
if (parser->upgrade) {
|
3954
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
3955
|
+
}
|
1660
3956
|
|
1661
|
-
if (
|
1662
|
-
fprintf(stderr, "\n\nParser didn't see
|
3957
|
+
if (message_count != num_messages) {
|
3958
|
+
fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
|
3959
|
+
message_count, num_messages);
|
1663
3960
|
goto error;
|
1664
3961
|
}
|
1665
3962
|
|
1666
|
-
if (!message_eq(0, r1)) {
|
3963
|
+
if (!message_eq(0, 0, r1)) {
|
1667
3964
|
fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
|
1668
3965
|
goto error;
|
1669
3966
|
}
|
1670
3967
|
|
1671
|
-
if (!message_eq(1, r2)) {
|
3968
|
+
if (message_count > 1 && !message_eq(1, 0, r2)) {
|
1672
3969
|
fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
|
1673
3970
|
goto error;
|
1674
3971
|
}
|
1675
3972
|
|
1676
|
-
if (!message_eq(2, r3)) {
|
3973
|
+
if (message_count > 2 && !message_eq(2, 0, r3)) {
|
1677
3974
|
fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
|
1678
3975
|
goto error;
|
1679
3976
|
}
|
@@ -1690,7 +3987,7 @@ test:
|
|
1690
3987
|
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
|
1691
3988
|
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
|
1692
3989
|
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
|
1693
|
-
|
3990
|
+
abort();
|
1694
3991
|
}
|
1695
3992
|
|
1696
3993
|
// user required to free the result
|
@@ -1724,21 +4021,108 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
1724
4021
|
return buf;
|
1725
4022
|
}
|
1726
4023
|
|
4024
|
+
/* Verify that we can pause parsing at any of the bytes in the
|
4025
|
+
* message and still get the result that we're expecting. */
|
4026
|
+
void
|
4027
|
+
test_message_pause (const struct message *msg)
|
4028
|
+
{
|
4029
|
+
char *buf = (char*) msg->raw;
|
4030
|
+
size_t buflen = strlen(msg->raw);
|
4031
|
+
size_t nread;
|
4032
|
+
|
4033
|
+
parser_init(msg->type);
|
4034
|
+
|
4035
|
+
do {
|
4036
|
+
nread = parse_pause(buf, buflen);
|
4037
|
+
|
4038
|
+
// We can only set the upgrade buffer once we've gotten our message
|
4039
|
+
// completion callback.
|
4040
|
+
if (messages[0].message_complete_cb_called &&
|
4041
|
+
msg->upgrade &&
|
4042
|
+
parser->upgrade) {
|
4043
|
+
messages[0].upgrade = buf + nread;
|
4044
|
+
goto test;
|
4045
|
+
}
|
4046
|
+
|
4047
|
+
if (nread < buflen) {
|
4048
|
+
|
4049
|
+
// Not much do to if we failed a strict-mode check
|
4050
|
+
if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
|
4051
|
+
parser_free();
|
4052
|
+
return;
|
4053
|
+
}
|
4054
|
+
|
4055
|
+
assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
|
4056
|
+
}
|
4057
|
+
|
4058
|
+
buf += nread;
|
4059
|
+
buflen -= nread;
|
4060
|
+
http_parser_pause(parser, 0);
|
4061
|
+
} while (buflen > 0);
|
4062
|
+
|
4063
|
+
nread = parse_pause(NULL, 0);
|
4064
|
+
assert (nread == 0);
|
4065
|
+
|
4066
|
+
test:
|
4067
|
+
if (num_messages != 1) {
|
4068
|
+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
4069
|
+
abort();
|
4070
|
+
}
|
4071
|
+
|
4072
|
+
if(!message_eq(0, 0, msg)) abort();
|
4073
|
+
|
4074
|
+
parser_free();
|
4075
|
+
}
|
4076
|
+
|
4077
|
+
/* Verify that body and next message won't be parsed in responses to CONNECT */
|
4078
|
+
void
|
4079
|
+
test_message_connect (const struct message *msg)
|
4080
|
+
{
|
4081
|
+
char *buf = (char*) msg->raw;
|
4082
|
+
size_t buflen = strlen(msg->raw);
|
4083
|
+
|
4084
|
+
parser_init(msg->type);
|
4085
|
+
|
4086
|
+
parse_connect(buf, buflen);
|
4087
|
+
|
4088
|
+
if (num_messages != 1) {
|
4089
|
+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
4090
|
+
abort();
|
4091
|
+
}
|
4092
|
+
|
4093
|
+
if(!message_eq(0, 1, msg)) abort();
|
4094
|
+
|
4095
|
+
parser_free();
|
4096
|
+
}
|
1727
4097
|
|
1728
4098
|
int
|
1729
4099
|
main (void)
|
1730
4100
|
{
|
1731
4101
|
parser = NULL;
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
4102
|
+
unsigned i, j, k;
|
4103
|
+
unsigned long version;
|
4104
|
+
unsigned major;
|
4105
|
+
unsigned minor;
|
4106
|
+
unsigned patch;
|
4107
|
+
|
4108
|
+
version = http_parser_version();
|
4109
|
+
major = (version >> 16) & 255;
|
4110
|
+
minor = (version >> 8) & 255;
|
4111
|
+
patch = version & 255;
|
4112
|
+
printf("http_parser v%u.%u.%u (0x%06lx)\n", major, minor, patch, version);
|
1735
4113
|
|
1736
4114
|
printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
|
1737
4115
|
|
1738
|
-
|
1739
|
-
|
4116
|
+
//// API
|
4117
|
+
test_preserve_data();
|
4118
|
+
test_parse_url();
|
4119
|
+
test_method_str();
|
4120
|
+
|
4121
|
+
//// NREAD
|
4122
|
+
test_header_nread_value();
|
1740
4123
|
|
1741
4124
|
//// OVERFLOW CONDITIONS
|
4125
|
+
test_no_overflow_parse_url();
|
1742
4126
|
|
1743
4127
|
test_header_overflow_error(HTTP_REQUEST);
|
1744
4128
|
test_no_overflow_long_body(HTTP_REQUEST, 1000);
|
@@ -1748,17 +4132,67 @@ main (void)
|
|
1748
4132
|
test_no_overflow_long_body(HTTP_RESPONSE, 1000);
|
1749
4133
|
test_no_overflow_long_body(HTTP_RESPONSE, 100000);
|
1750
4134
|
|
4135
|
+
test_header_content_length_overflow_error();
|
4136
|
+
test_chunk_content_length_overflow_error();
|
4137
|
+
|
4138
|
+
//// HEADER FIELD CONDITIONS
|
4139
|
+
test_double_content_length_error(HTTP_REQUEST);
|
4140
|
+
test_chunked_content_length_error(HTTP_REQUEST);
|
4141
|
+
test_header_cr_no_lf_error(HTTP_REQUEST);
|
4142
|
+
test_invalid_header_field_token_error(HTTP_REQUEST);
|
4143
|
+
test_invalid_header_field_content_error(HTTP_REQUEST);
|
4144
|
+
test_double_content_length_error(HTTP_RESPONSE);
|
4145
|
+
test_chunked_content_length_error(HTTP_RESPONSE);
|
4146
|
+
test_header_cr_no_lf_error(HTTP_RESPONSE);
|
4147
|
+
test_invalid_header_field_token_error(HTTP_RESPONSE);
|
4148
|
+
test_invalid_header_field_content_error(HTTP_RESPONSE);
|
4149
|
+
|
4150
|
+
test_simple_type(
|
4151
|
+
"POST / HTTP/1.1\r\n"
|
4152
|
+
"Content-Length: 42 \r\n" // Note the surrounding whitespace.
|
4153
|
+
"\r\n",
|
4154
|
+
HPE_OK,
|
4155
|
+
HTTP_REQUEST);
|
4156
|
+
|
4157
|
+
test_simple_type(
|
4158
|
+
"POST / HTTP/1.1\r\n"
|
4159
|
+
"Content-Length: 4 2\r\n"
|
4160
|
+
"\r\n",
|
4161
|
+
HPE_INVALID_CONTENT_LENGTH,
|
4162
|
+
HTTP_REQUEST);
|
4163
|
+
|
4164
|
+
test_simple_type(
|
4165
|
+
"POST / HTTP/1.1\r\n"
|
4166
|
+
"Content-Length: 13 37\r\n"
|
4167
|
+
"\r\n",
|
4168
|
+
HPE_INVALID_CONTENT_LENGTH,
|
4169
|
+
HTTP_REQUEST);
|
4170
|
+
|
1751
4171
|
//// RESPONSES
|
1752
4172
|
|
1753
|
-
|
4173
|
+
test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
|
4174
|
+
test_simple_type("HTTP/01.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
|
4175
|
+
test_simple_type("HTTP/11.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
|
4176
|
+
test_simple_type("HTTP/1.01 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
|
4177
|
+
test_simple_type("HTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
|
4178
|
+
|
4179
|
+
for (i = 0; i < ARRAY_SIZE(responses); i++) {
|
1754
4180
|
test_message(&responses[i]);
|
1755
4181
|
}
|
1756
4182
|
|
1757
|
-
for (i = 0; i <
|
4183
|
+
for (i = 0; i < ARRAY_SIZE(responses); i++) {
|
4184
|
+
test_message_pause(&responses[i]);
|
4185
|
+
}
|
4186
|
+
|
4187
|
+
for (i = 0; i < ARRAY_SIZE(responses); i++) {
|
4188
|
+
test_message_connect(&responses[i]);
|
4189
|
+
}
|
4190
|
+
|
4191
|
+
for (i = 0; i < ARRAY_SIZE(responses); i++) {
|
1758
4192
|
if (!responses[i].should_keep_alive) continue;
|
1759
|
-
for (j = 0; j <
|
4193
|
+
for (j = 0; j < ARRAY_SIZE(responses); j++) {
|
1760
4194
|
if (!responses[j].should_keep_alive) continue;
|
1761
|
-
for (k = 0; k <
|
4195
|
+
for (k = 0; k < ARRAY_SIZE(responses); k++) {
|
1762
4196
|
test_multiple3(&responses[i], &responses[j], &responses[k]);
|
1763
4197
|
}
|
1764
4198
|
}
|
@@ -1783,13 +4217,18 @@ main (void)
|
|
1783
4217
|
,.http_major= 1
|
1784
4218
|
,.http_minor= 0
|
1785
4219
|
,.status_code= 200
|
4220
|
+
,.response_status= "OK"
|
1786
4221
|
,.num_headers= 2
|
1787
4222
|
,.headers=
|
1788
4223
|
{ { "Transfer-Encoding", "chunked" }
|
1789
4224
|
, { "Content-Type", "text/plain" }
|
1790
4225
|
}
|
1791
4226
|
,.body_size= 31337*1024
|
4227
|
+
,.num_chunks_complete= 31338
|
1792
4228
|
};
|
4229
|
+
for (i = 0; i < MAX_CHUNKS; i++) {
|
4230
|
+
large_chunked.chunk_lengths[i] = 1024;
|
4231
|
+
}
|
1793
4232
|
test_message_count_body(&large_chunked);
|
1794
4233
|
free(msg);
|
1795
4234
|
}
|
@@ -1798,7 +4237,7 @@ main (void)
|
|
1798
4237
|
|
1799
4238
|
printf("response scan 1/2 ");
|
1800
4239
|
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
1801
|
-
, &responses[
|
4240
|
+
, &responses[NO_BODY_HTTP10_KA_204]
|
1802
4241
|
, &responses[NO_REASON_PHRASE]
|
1803
4242
|
);
|
1804
4243
|
|
@@ -1813,13 +4252,15 @@ main (void)
|
|
1813
4252
|
|
1814
4253
|
/// REQUESTS
|
1815
4254
|
|
1816
|
-
test_simple("
|
1817
|
-
test_simple("GET /
|
4255
|
+
test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
|
4256
|
+
test_simple("GET / HTTP/01.1\r\n\r\n", HPE_INVALID_VERSION);
|
4257
|
+
test_simple("GET / HTTP/11.1\r\n\r\n", HPE_INVALID_VERSION);
|
4258
|
+
test_simple("GET / HTTP/1.01\r\n\r\n", HPE_INVALID_VERSION);
|
1818
4259
|
|
1819
|
-
|
1820
|
-
test_simple("
|
1821
|
-
|
1822
|
-
|
4260
|
+
// Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js
|
4261
|
+
test_simple("GET / HTTP/1.1\r\n"
|
4262
|
+
"Test: Düsseldorf\r\n",
|
4263
|
+
HPE_OK);
|
1823
4264
|
|
1824
4265
|
// Well-formed but incomplete
|
1825
4266
|
test_simple("GET / HTTP/1.1\r\n"
|
@@ -1827,7 +4268,7 @@ main (void)
|
|
1827
4268
|
"Content-Length: 6\r\n"
|
1828
4269
|
"\r\n"
|
1829
4270
|
"fooba",
|
1830
|
-
|
4271
|
+
HPE_OK);
|
1831
4272
|
|
1832
4273
|
static const char *all_methods[] = {
|
1833
4274
|
"DELETE",
|
@@ -1844,15 +4285,60 @@ main (void)
|
|
1844
4285
|
"MOVE",
|
1845
4286
|
"PROPFIND",
|
1846
4287
|
"PROPPATCH",
|
4288
|
+
"SEARCH",
|
1847
4289
|
"UNLOCK",
|
4290
|
+
"BIND",
|
4291
|
+
"REBIND",
|
4292
|
+
"UNBIND",
|
4293
|
+
"ACL",
|
4294
|
+
"REPORT",
|
4295
|
+
"MKACTIVITY",
|
4296
|
+
"CHECKOUT",
|
4297
|
+
"MERGE",
|
4298
|
+
"M-SEARCH",
|
4299
|
+
"NOTIFY",
|
4300
|
+
"SUBSCRIBE",
|
4301
|
+
"UNSUBSCRIBE",
|
4302
|
+
"PATCH",
|
4303
|
+
"PURGE",
|
4304
|
+
"MKCALENDAR",
|
4305
|
+
"LINK",
|
4306
|
+
"UNLINK",
|
1848
4307
|
0 };
|
1849
4308
|
const char **this_method;
|
1850
4309
|
for (this_method = all_methods; *this_method; this_method++) {
|
1851
4310
|
char buf[200];
|
1852
4311
|
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
1853
|
-
test_simple(buf,
|
4312
|
+
test_simple(buf, HPE_OK);
|
4313
|
+
}
|
4314
|
+
|
4315
|
+
static const char *bad_methods[] = {
|
4316
|
+
"ASDF",
|
4317
|
+
"C******",
|
4318
|
+
"COLA",
|
4319
|
+
"GEM",
|
4320
|
+
"GETA",
|
4321
|
+
"M****",
|
4322
|
+
"MKCOLA",
|
4323
|
+
"PROPPATCHA",
|
4324
|
+
"PUN",
|
4325
|
+
"PX",
|
4326
|
+
"SA",
|
4327
|
+
"hello world",
|
4328
|
+
0 };
|
4329
|
+
for (this_method = bad_methods; *this_method; this_method++) {
|
4330
|
+
char buf[200];
|
4331
|
+
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
4332
|
+
test_simple(buf, HPE_INVALID_METHOD);
|
1854
4333
|
}
|
1855
4334
|
|
4335
|
+
// illegal header field name line folding
|
4336
|
+
test_simple("GET / HTTP/1.1\r\n"
|
4337
|
+
"name\r\n"
|
4338
|
+
" : value\r\n"
|
4339
|
+
"\r\n",
|
4340
|
+
HPE_INVALID_HEADER_TOKEN);
|
4341
|
+
|
1856
4342
|
const char *dumbfuck2 =
|
1857
4343
|
"GET / HTTP/1.1\r\n"
|
1858
4344
|
"X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
|
@@ -1888,7 +4374,23 @@ main (void)
|
|
1888
4374
|
"\tRA==\r\n"
|
1889
4375
|
"\t-----END CERTIFICATE-----\r\n"
|
1890
4376
|
"\r\n";
|
1891
|
-
test_simple(dumbfuck2,
|
4377
|
+
test_simple(dumbfuck2, HPE_OK);
|
4378
|
+
|
4379
|
+
const char *corrupted_connection =
|
4380
|
+
"GET / HTTP/1.1\r\n"
|
4381
|
+
"Host: www.example.com\r\n"
|
4382
|
+
"Connection\r\033\065\325eep-Alive\r\n"
|
4383
|
+
"Accept-Encoding: gzip\r\n"
|
4384
|
+
"\r\n";
|
4385
|
+
test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
|
4386
|
+
|
4387
|
+
const char *corrupted_header_name =
|
4388
|
+
"GET / HTTP/1.1\r\n"
|
4389
|
+
"Host: www.example.com\r\n"
|
4390
|
+
"X-Some-Header\r\033\065\325eep-Alive\r\n"
|
4391
|
+
"Accept-Encoding: gzip\r\n"
|
4392
|
+
"\r\n";
|
4393
|
+
test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
|
1892
4394
|
|
1893
4395
|
#if 0
|
1894
4396
|
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
|
@@ -1906,17 +4408,19 @@ main (void)
|
|
1906
4408
|
|
1907
4409
|
|
1908
4410
|
/* check to make sure our predefined requests are okay */
|
1909
|
-
for (i = 0; requests
|
4411
|
+
for (i = 0; i < ARRAY_SIZE(requests); i++) {
|
1910
4412
|
test_message(&requests[i]);
|
1911
4413
|
}
|
1912
4414
|
|
4415
|
+
for (i = 0; i < ARRAY_SIZE(requests); i++) {
|
4416
|
+
test_message_pause(&requests[i]);
|
4417
|
+
}
|
1913
4418
|
|
1914
|
-
|
1915
|
-
for (i = 0; i < request_count; i++) {
|
4419
|
+
for (i = 0; i < ARRAY_SIZE(requests); i++) {
|
1916
4420
|
if (!requests[i].should_keep_alive) continue;
|
1917
|
-
for (j = 0; j <
|
4421
|
+
for (j = 0; j < ARRAY_SIZE(requests); j++) {
|
1918
4422
|
if (!requests[j].should_keep_alive) continue;
|
1919
|
-
for (k = 0; k <
|
4423
|
+
for (k = 0; k < ARRAY_SIZE(requests); k++) {
|
1920
4424
|
test_multiple3(&requests[i], &requests[j], &requests[k]);
|
1921
4425
|
}
|
1922
4426
|
}
|