http_parser.rb 0.5.1 → 0.6.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitmodules +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -4
- data/LICENSE-MIT +20 -0
- data/README.md +51 -46
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +121 -56
- data/ext/ruby_http_parser/ruby_http_parser.c +89 -48
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser/Makefile +34 -17
- data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1045 -589
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +148 -17
- data/ext/ruby_http_parser/vendor/http-parser/test.c +1138 -128
- data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +30 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/Makefile +34 -17
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +30 -18
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +9 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +74 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/ext/primitives.jar +0 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1075 -607
- 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 +190 -40
- 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/HTTPCallback.java +8 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +34 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +12 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +4 -2
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +13 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +67 -52
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +5 -0
- 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 +323 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/{lolevel/Util.java → Util.java} +34 -35
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +12 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +839 -587
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +374 -0
- 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 +69 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +52 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +16 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +48 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +171 -446
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +62 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +3 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +27 -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 +236 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +59 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1318 -184
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +355 -49
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +17 -0
- data/http_parser.rb.gemspec +10 -2
- data/lib/http_parser.rb +17 -0
- data/spec/parser_spec.rb +157 -23
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +182 -36
- data/tasks/compile.rake +5 -3
- data/tasks/fixtures.rake +8 -2
- metadata +209 -127
- data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +0 -4
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Copyright
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
2
2
|
*
|
|
3
3
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
4
|
* of this software and associated documentation files (the "Software"), to
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
#undef FALSE
|
|
32
32
|
#define FALSE 0
|
|
33
33
|
|
|
34
|
-
#define MAX_HEADERS
|
|
34
|
+
#define MAX_HEADERS 13
|
|
35
35
|
#define MAX_ELEMENT_SIZE 500
|
|
36
36
|
|
|
37
37
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
@@ -50,12 +50,13 @@ struct message {
|
|
|
50
50
|
char query_string[MAX_ELEMENT_SIZE];
|
|
51
51
|
char body[MAX_ELEMENT_SIZE];
|
|
52
52
|
size_t body_size;
|
|
53
|
+
uint16_t port;
|
|
53
54
|
int num_headers;
|
|
54
55
|
enum { NONE=0, FIELD, VALUE } last_header_element;
|
|
55
56
|
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
|
56
57
|
int should_keep_alive;
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
const char *upgrade; // upgraded body
|
|
59
60
|
|
|
60
61
|
unsigned short http_major;
|
|
61
62
|
unsigned short http_minor;
|
|
@@ -70,6 +71,7 @@ static int currently_parsing_eof;
|
|
|
70
71
|
|
|
71
72
|
static struct message messages[5];
|
|
72
73
|
static int num_messages;
|
|
74
|
+
static http_parser_settings *current_pause_parser;
|
|
73
75
|
|
|
74
76
|
/* * R E Q U E S T S * */
|
|
75
77
|
const struct message requests[] =
|
|
@@ -473,6 +475,7 @@ const struct message requests[] =
|
|
|
473
475
|
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
|
|
474
476
|
"Origin: http://example.com\r\n"
|
|
475
477
|
"\r\n"
|
|
478
|
+
"Hot diggity dogg"
|
|
476
479
|
,.should_keep_alive= TRUE
|
|
477
480
|
,.message_complete_on_eof= FALSE
|
|
478
481
|
,.http_major= 1
|
|
@@ -483,7 +486,7 @@ const struct message requests[] =
|
|
|
483
486
|
,.request_path= "/demo"
|
|
484
487
|
,.request_url= "/demo"
|
|
485
488
|
,.num_headers= 7
|
|
486
|
-
,.upgrade=
|
|
489
|
+
,.upgrade="Hot diggity dogg"
|
|
487
490
|
,.headers= { { "Host", "example.com" }
|
|
488
491
|
, { "Connection", "Upgrade" }
|
|
489
492
|
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
|
|
@@ -498,10 +501,12 @@ const struct message requests[] =
|
|
|
498
501
|
#define CONNECT_REQUEST 17
|
|
499
502
|
, {.name = "connect request"
|
|
500
503
|
,.type= HTTP_REQUEST
|
|
501
|
-
,.raw= "CONNECT
|
|
504
|
+
,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
|
|
502
505
|
"User-agent: Mozilla/1.1N\r\n"
|
|
503
506
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
|
504
507
|
"\r\n"
|
|
508
|
+
"some data\r\n"
|
|
509
|
+
"and yet even more data"
|
|
505
510
|
,.should_keep_alive= FALSE
|
|
506
511
|
,.message_complete_on_eof= FALSE
|
|
507
512
|
,.http_major= 1
|
|
@@ -510,9 +515,9 @@ const struct message requests[] =
|
|
|
510
515
|
,.query_string= ""
|
|
511
516
|
,.fragment= ""
|
|
512
517
|
,.request_path= ""
|
|
513
|
-
,.request_url= "
|
|
518
|
+
,.request_url= "0-home0.netscape.com:443"
|
|
514
519
|
,.num_headers= 2
|
|
515
|
-
,.upgrade=
|
|
520
|
+
,.upgrade="some data\r\nand yet even more data"
|
|
516
521
|
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
|
517
522
|
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
|
518
523
|
}
|
|
@@ -538,6 +543,313 @@ const struct message requests[] =
|
|
|
538
543
|
,.body= ""
|
|
539
544
|
}
|
|
540
545
|
|
|
546
|
+
#define NO_HTTP_VERSION 19
|
|
547
|
+
, {.name= "request with no http version"
|
|
548
|
+
,.type= HTTP_REQUEST
|
|
549
|
+
,.raw= "GET /\r\n"
|
|
550
|
+
"\r\n"
|
|
551
|
+
,.should_keep_alive= FALSE
|
|
552
|
+
,.message_complete_on_eof= FALSE
|
|
553
|
+
,.http_major= 0
|
|
554
|
+
,.http_minor= 9
|
|
555
|
+
,.method= HTTP_GET
|
|
556
|
+
,.query_string= ""
|
|
557
|
+
,.fragment= ""
|
|
558
|
+
,.request_path= "/"
|
|
559
|
+
,.request_url= "/"
|
|
560
|
+
,.num_headers= 0
|
|
561
|
+
,.headers= {}
|
|
562
|
+
,.body= ""
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
#define MSEARCH_REQ 20
|
|
566
|
+
, {.name= "m-search request"
|
|
567
|
+
,.type= HTTP_REQUEST
|
|
568
|
+
,.raw= "M-SEARCH * HTTP/1.1\r\n"
|
|
569
|
+
"HOST: 239.255.255.250:1900\r\n"
|
|
570
|
+
"MAN: \"ssdp:discover\"\r\n"
|
|
571
|
+
"ST: \"ssdp:all\"\r\n"
|
|
572
|
+
"\r\n"
|
|
573
|
+
,.should_keep_alive= TRUE
|
|
574
|
+
,.message_complete_on_eof= FALSE
|
|
575
|
+
,.http_major= 1
|
|
576
|
+
,.http_minor= 1
|
|
577
|
+
,.method= HTTP_MSEARCH
|
|
578
|
+
,.query_string= ""
|
|
579
|
+
,.fragment= ""
|
|
580
|
+
,.request_path= "*"
|
|
581
|
+
,.request_url= "*"
|
|
582
|
+
,.num_headers= 3
|
|
583
|
+
,.headers= { { "HOST", "239.255.255.250:1900" }
|
|
584
|
+
, { "MAN", "\"ssdp:discover\"" }
|
|
585
|
+
, { "ST", "\"ssdp:all\"" }
|
|
586
|
+
}
|
|
587
|
+
,.body= ""
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
#define LINE_FOLDING_IN_HEADER 20
|
|
591
|
+
, {.name= "line folding in header value"
|
|
592
|
+
,.type= HTTP_REQUEST
|
|
593
|
+
,.raw= "GET / HTTP/1.1\r\n"
|
|
594
|
+
"Line1: abc\r\n"
|
|
595
|
+
"\tdef\r\n"
|
|
596
|
+
" ghi\r\n"
|
|
597
|
+
"\t\tjkl\r\n"
|
|
598
|
+
" mno \r\n"
|
|
599
|
+
"\t \tqrs\r\n"
|
|
600
|
+
"Line2: \t line2\t\r\n"
|
|
601
|
+
"\r\n"
|
|
602
|
+
,.should_keep_alive= TRUE
|
|
603
|
+
,.message_complete_on_eof= FALSE
|
|
604
|
+
,.http_major= 1
|
|
605
|
+
,.http_minor= 1
|
|
606
|
+
,.method= HTTP_GET
|
|
607
|
+
,.query_string= ""
|
|
608
|
+
,.fragment= ""
|
|
609
|
+
,.request_path= "/"
|
|
610
|
+
,.request_url= "/"
|
|
611
|
+
,.num_headers= 2
|
|
612
|
+
,.headers= { { "Line1", "abcdefghijklmno qrs" }
|
|
613
|
+
, { "Line2", "line2\t" }
|
|
614
|
+
}
|
|
615
|
+
,.body= ""
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
#define QUERY_TERMINATED_HOST 21
|
|
620
|
+
, {.name= "host terminated by a query string"
|
|
621
|
+
,.type= HTTP_REQUEST
|
|
622
|
+
,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
|
|
623
|
+
"\r\n"
|
|
624
|
+
,.should_keep_alive= TRUE
|
|
625
|
+
,.message_complete_on_eof= FALSE
|
|
626
|
+
,.http_major= 1
|
|
627
|
+
,.http_minor= 1
|
|
628
|
+
,.method= HTTP_GET
|
|
629
|
+
,.query_string= "hail=all"
|
|
630
|
+
,.fragment= ""
|
|
631
|
+
,.request_path= ""
|
|
632
|
+
,.request_url= "http://hypnotoad.org?hail=all"
|
|
633
|
+
,.num_headers= 0
|
|
634
|
+
,.headers= { }
|
|
635
|
+
,.body= ""
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
#define QUERY_TERMINATED_HOSTPORT 22
|
|
639
|
+
, {.name= "host:port terminated by a query string"
|
|
640
|
+
,.type= HTTP_REQUEST
|
|
641
|
+
,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
|
|
642
|
+
"\r\n"
|
|
643
|
+
,.should_keep_alive= TRUE
|
|
644
|
+
,.message_complete_on_eof= FALSE
|
|
645
|
+
,.http_major= 1
|
|
646
|
+
,.http_minor= 1
|
|
647
|
+
,.method= HTTP_GET
|
|
648
|
+
,.query_string= "hail=all"
|
|
649
|
+
,.fragment= ""
|
|
650
|
+
,.request_path= ""
|
|
651
|
+
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
|
652
|
+
,.port= 1234
|
|
653
|
+
,.num_headers= 0
|
|
654
|
+
,.headers= { }
|
|
655
|
+
,.body= ""
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
#define SPACE_TERMINATED_HOSTPORT 23
|
|
659
|
+
, {.name= "host:port terminated by a space"
|
|
660
|
+
,.type= HTTP_REQUEST
|
|
661
|
+
,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
|
|
662
|
+
"\r\n"
|
|
663
|
+
,.should_keep_alive= TRUE
|
|
664
|
+
,.message_complete_on_eof= FALSE
|
|
665
|
+
,.http_major= 1
|
|
666
|
+
,.http_minor= 1
|
|
667
|
+
,.method= HTTP_GET
|
|
668
|
+
,.query_string= ""
|
|
669
|
+
,.fragment= ""
|
|
670
|
+
,.request_path= ""
|
|
671
|
+
,.request_url= "http://hypnotoad.org:1234"
|
|
672
|
+
,.port= 1234
|
|
673
|
+
,.num_headers= 0
|
|
674
|
+
,.headers= { }
|
|
675
|
+
,.body= ""
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
#define PATCH_REQ 24
|
|
679
|
+
, {.name = "PATCH request"
|
|
680
|
+
,.type= HTTP_REQUEST
|
|
681
|
+
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
|
|
682
|
+
"Host: www.example.com\r\n"
|
|
683
|
+
"Content-Type: application/example\r\n"
|
|
684
|
+
"If-Match: \"e0023aa4e\"\r\n"
|
|
685
|
+
"Content-Length: 10\r\n"
|
|
686
|
+
"\r\n"
|
|
687
|
+
"cccccccccc"
|
|
688
|
+
,.should_keep_alive= TRUE
|
|
689
|
+
,.message_complete_on_eof= FALSE
|
|
690
|
+
,.http_major= 1
|
|
691
|
+
,.http_minor= 1
|
|
692
|
+
,.method= HTTP_PATCH
|
|
693
|
+
,.query_string= ""
|
|
694
|
+
,.fragment= ""
|
|
695
|
+
,.request_path= "/file.txt"
|
|
696
|
+
,.request_url= "/file.txt"
|
|
697
|
+
,.num_headers= 4
|
|
698
|
+
,.headers= { { "Host", "www.example.com" }
|
|
699
|
+
, { "Content-Type", "application/example" }
|
|
700
|
+
, { "If-Match", "\"e0023aa4e\"" }
|
|
701
|
+
, { "Content-Length", "10" }
|
|
702
|
+
}
|
|
703
|
+
,.body= "cccccccccc"
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
#define CONNECT_CAPS_REQUEST 25
|
|
707
|
+
, {.name = "connect caps request"
|
|
708
|
+
,.type= HTTP_REQUEST
|
|
709
|
+
,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
|
|
710
|
+
"User-agent: Mozilla/1.1N\r\n"
|
|
711
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
|
712
|
+
"\r\n"
|
|
713
|
+
,.should_keep_alive= FALSE
|
|
714
|
+
,.message_complete_on_eof= FALSE
|
|
715
|
+
,.http_major= 1
|
|
716
|
+
,.http_minor= 0
|
|
717
|
+
,.method= HTTP_CONNECT
|
|
718
|
+
,.query_string= ""
|
|
719
|
+
,.fragment= ""
|
|
720
|
+
,.request_path= ""
|
|
721
|
+
,.request_url= "HOME0.NETSCAPE.COM:443"
|
|
722
|
+
,.num_headers= 2
|
|
723
|
+
,.upgrade=""
|
|
724
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
|
725
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
|
726
|
+
}
|
|
727
|
+
,.body= ""
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
#if !HTTP_PARSER_STRICT
|
|
731
|
+
#define UTF8_PATH_REQ 26
|
|
732
|
+
, {.name= "utf-8 path request"
|
|
733
|
+
,.type= HTTP_REQUEST
|
|
734
|
+
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
|
|
735
|
+
"Host: github.com\r\n"
|
|
736
|
+
"\r\n"
|
|
737
|
+
,.should_keep_alive= TRUE
|
|
738
|
+
,.message_complete_on_eof= FALSE
|
|
739
|
+
,.http_major= 1
|
|
740
|
+
,.http_minor= 1
|
|
741
|
+
,.method= HTTP_GET
|
|
742
|
+
,.query_string= "q=1"
|
|
743
|
+
,.fragment= "narf"
|
|
744
|
+
,.request_path= "/δ¶/δt/pope"
|
|
745
|
+
,.request_url= "/δ¶/δt/pope?q=1#narf"
|
|
746
|
+
,.num_headers= 1
|
|
747
|
+
,.headers= { {"Host", "github.com" }
|
|
748
|
+
}
|
|
749
|
+
,.body= ""
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
#define HOSTNAME_UNDERSCORE 27
|
|
753
|
+
, {.name = "hostname underscore"
|
|
754
|
+
,.type= HTTP_REQUEST
|
|
755
|
+
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
|
|
756
|
+
"User-agent: Mozilla/1.1N\r\n"
|
|
757
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
|
758
|
+
"\r\n"
|
|
759
|
+
,.should_keep_alive= FALSE
|
|
760
|
+
,.message_complete_on_eof= FALSE
|
|
761
|
+
,.http_major= 1
|
|
762
|
+
,.http_minor= 0
|
|
763
|
+
,.method= HTTP_CONNECT
|
|
764
|
+
,.query_string= ""
|
|
765
|
+
,.fragment= ""
|
|
766
|
+
,.request_path= ""
|
|
767
|
+
,.request_url= "home_0.netscape.com:443"
|
|
768
|
+
,.num_headers= 2
|
|
769
|
+
,.upgrade=""
|
|
770
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
|
771
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
|
772
|
+
}
|
|
773
|
+
,.body= ""
|
|
774
|
+
}
|
|
775
|
+
#endif /* !HTTP_PARSER_STRICT */
|
|
776
|
+
|
|
777
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
|
778
|
+
#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28
|
|
779
|
+
, {.name = "eat CRLF between requests, no \"Connection: close\" header"
|
|
780
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
|
781
|
+
"Host: www.example.com\r\n"
|
|
782
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
|
783
|
+
"Content-Length: 4\r\n"
|
|
784
|
+
"\r\n"
|
|
785
|
+
"q=42\r\n" /* note the trailing CRLF */
|
|
786
|
+
,.should_keep_alive= TRUE
|
|
787
|
+
,.message_complete_on_eof= FALSE
|
|
788
|
+
,.http_major= 1
|
|
789
|
+
,.http_minor= 1
|
|
790
|
+
,.method= HTTP_POST
|
|
791
|
+
,.query_string= ""
|
|
792
|
+
,.fragment= ""
|
|
793
|
+
,.request_path= "/"
|
|
794
|
+
,.request_url= "/"
|
|
795
|
+
,.num_headers= 3
|
|
796
|
+
,.upgrade= 0
|
|
797
|
+
,.headers= { { "Host", "www.example.com" }
|
|
798
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
|
799
|
+
, { "Content-Length", "4" }
|
|
800
|
+
}
|
|
801
|
+
,.body= "q=42"
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
|
805
|
+
#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29
|
|
806
|
+
, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
|
|
807
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
|
808
|
+
"Host: www.example.com\r\n"
|
|
809
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
|
810
|
+
"Content-Length: 4\r\n"
|
|
811
|
+
"Connection: close\r\n"
|
|
812
|
+
"\r\n"
|
|
813
|
+
"q=42\r\n" /* note the trailing CRLF */
|
|
814
|
+
,.should_keep_alive= FALSE
|
|
815
|
+
,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
|
|
816
|
+
,.http_major= 1
|
|
817
|
+
,.http_minor= 1
|
|
818
|
+
,.method= HTTP_POST
|
|
819
|
+
,.query_string= ""
|
|
820
|
+
,.fragment= ""
|
|
821
|
+
,.request_path= "/"
|
|
822
|
+
,.request_url= "/"
|
|
823
|
+
,.num_headers= 4
|
|
824
|
+
,.upgrade= 0
|
|
825
|
+
,.headers= { { "Host", "www.example.com" }
|
|
826
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
|
827
|
+
, { "Content-Length", "4" }
|
|
828
|
+
, { "Connection", "close" }
|
|
829
|
+
}
|
|
830
|
+
,.body= "q=42"
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
#define PURGE_REQ 30
|
|
834
|
+
, {.name = "PURGE request"
|
|
835
|
+
,.type= HTTP_REQUEST
|
|
836
|
+
,.raw= "PURGE /file.txt HTTP/1.1\r\n"
|
|
837
|
+
"Host: www.example.com\r\n"
|
|
838
|
+
"\r\n"
|
|
839
|
+
,.should_keep_alive= TRUE
|
|
840
|
+
,.message_complete_on_eof= FALSE
|
|
841
|
+
,.http_major= 1
|
|
842
|
+
,.http_minor= 1
|
|
843
|
+
,.method= HTTP_PURGE
|
|
844
|
+
,.query_string= ""
|
|
845
|
+
,.fragment= ""
|
|
846
|
+
,.request_path= "/file.txt"
|
|
847
|
+
,.request_url= "/file.txt"
|
|
848
|
+
,.num_headers= 1
|
|
849
|
+
,.headers= { { "Host", "www.example.com" } }
|
|
850
|
+
,.body= ""
|
|
851
|
+
}
|
|
852
|
+
|
|
541
853
|
, {.name= NULL } /* sentinel */
|
|
542
854
|
};
|
|
543
855
|
|
|
@@ -551,9 +863,10 @@ const struct message responses[] =
|
|
|
551
863
|
"Content-Type: text/html; charset=UTF-8\r\n"
|
|
552
864
|
"Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
|
|
553
865
|
"Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
|
|
866
|
+
"X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
|
|
554
867
|
"Cache-Control: public, max-age=2592000\r\n"
|
|
555
868
|
"Server: gws\r\n"
|
|
556
|
-
"Content-Length:
|
|
869
|
+
"Content-Length: 219 \r\n"
|
|
557
870
|
"\r\n"
|
|
558
871
|
"<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
|
559
872
|
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
|
@@ -566,15 +879,16 @@ const struct message responses[] =
|
|
|
566
879
|
,.http_major= 1
|
|
567
880
|
,.http_minor= 1
|
|
568
881
|
,.status_code= 301
|
|
569
|
-
,.num_headers=
|
|
882
|
+
,.num_headers= 8
|
|
570
883
|
,.headers=
|
|
571
884
|
{ { "Location", "http://www.google.com/" }
|
|
572
885
|
, { "Content-Type", "text/html; charset=UTF-8" }
|
|
573
886
|
, { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
|
|
574
887
|
, { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
|
|
888
|
+
, { "X-$PrototypeBI-Version", "1.6.0.3" }
|
|
575
889
|
, { "Cache-Control", "public, max-age=2592000" }
|
|
576
890
|
, { "Server", "gws" }
|
|
577
|
-
, { "Content-Length", "219" }
|
|
891
|
+
, { "Content-Length", "219 " }
|
|
578
892
|
}
|
|
579
893
|
,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
|
|
580
894
|
"<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
|
|
@@ -636,8 +950,8 @@ const struct message responses[] =
|
|
|
636
950
|
, {.name= "404 no headers no body"
|
|
637
951
|
,.type= HTTP_RESPONSE
|
|
638
952
|
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
|
639
|
-
,.should_keep_alive=
|
|
640
|
-
,.message_complete_on_eof=
|
|
953
|
+
,.should_keep_alive= FALSE
|
|
954
|
+
,.message_complete_on_eof= TRUE
|
|
641
955
|
,.http_major= 1
|
|
642
956
|
,.http_minor= 1
|
|
643
957
|
,.status_code= 404
|
|
@@ -651,8 +965,8 @@ const struct message responses[] =
|
|
|
651
965
|
, {.name= "301 no response phrase"
|
|
652
966
|
,.type= HTTP_RESPONSE
|
|
653
967
|
,.raw= "HTTP/1.1 301\r\n\r\n"
|
|
654
|
-
,.should_keep_alive =
|
|
655
|
-
,.message_complete_on_eof=
|
|
968
|
+
,.should_keep_alive = FALSE
|
|
969
|
+
,.message_complete_on_eof= TRUE
|
|
656
970
|
,.http_major= 1
|
|
657
971
|
,.http_minor= 1
|
|
658
972
|
,.status_code= 301
|
|
@@ -801,7 +1115,221 @@ const struct message responses[] =
|
|
|
801
1115
|
,.body= ""
|
|
802
1116
|
}
|
|
803
1117
|
|
|
804
|
-
#define
|
|
1118
|
+
#define RES_FIELD_UNDERSCORE 9
|
|
1119
|
+
/* Should handle spaces in header fields */
|
|
1120
|
+
, {.name= "field underscore"
|
|
1121
|
+
,.type= HTTP_RESPONSE
|
|
1122
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
|
1123
|
+
"Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
|
|
1124
|
+
"Server: Apache\r\n"
|
|
1125
|
+
"Cache-Control: no-cache, must-revalidate\r\n"
|
|
1126
|
+
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
|
|
1127
|
+
".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
|
|
1128
|
+
"Vary: Accept-Encoding\r\n"
|
|
1129
|
+
"_eep-Alive: timeout=45\r\n" /* semantic value ignored */
|
|
1130
|
+
"_onnection: Keep-Alive\r\n" /* semantic value ignored */
|
|
1131
|
+
"Transfer-Encoding: chunked\r\n"
|
|
1132
|
+
"Content-Type: text/html\r\n"
|
|
1133
|
+
"Connection: close\r\n"
|
|
1134
|
+
"\r\n"
|
|
1135
|
+
"0\r\n\r\n"
|
|
1136
|
+
,.should_keep_alive= FALSE
|
|
1137
|
+
,.message_complete_on_eof= FALSE
|
|
1138
|
+
,.http_major= 1
|
|
1139
|
+
,.http_minor= 1
|
|
1140
|
+
,.status_code= 200
|
|
1141
|
+
,.num_headers= 11
|
|
1142
|
+
,.headers=
|
|
1143
|
+
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
|
|
1144
|
+
, { "Server", "Apache" }
|
|
1145
|
+
, { "Cache-Control", "no-cache, must-revalidate" }
|
|
1146
|
+
, { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
|
|
1147
|
+
, { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
|
|
1148
|
+
, { "Vary", "Accept-Encoding" }
|
|
1149
|
+
, { "_eep-Alive", "timeout=45" }
|
|
1150
|
+
, { "_onnection", "Keep-Alive" }
|
|
1151
|
+
, { "Transfer-Encoding", "chunked" }
|
|
1152
|
+
, { "Content-Type", "text/html" }
|
|
1153
|
+
, { "Connection", "close" }
|
|
1154
|
+
}
|
|
1155
|
+
,.body= ""
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
#define NON_ASCII_IN_STATUS_LINE 10
|
|
1159
|
+
/* Should handle non-ASCII in status line */
|
|
1160
|
+
, {.name= "non-ASCII in status line"
|
|
1161
|
+
,.type= HTTP_RESPONSE
|
|
1162
|
+
,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
|
|
1163
|
+
"Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
|
|
1164
|
+
"Content-Length: 0\r\n"
|
|
1165
|
+
"Connection: close\r\n"
|
|
1166
|
+
"\r\n"
|
|
1167
|
+
,.should_keep_alive= FALSE
|
|
1168
|
+
,.message_complete_on_eof= FALSE
|
|
1169
|
+
,.http_major= 1
|
|
1170
|
+
,.http_minor= 1
|
|
1171
|
+
,.status_code= 500
|
|
1172
|
+
,.num_headers= 3
|
|
1173
|
+
,.headers=
|
|
1174
|
+
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
|
|
1175
|
+
, { "Content-Length", "0" }
|
|
1176
|
+
, { "Connection", "close" }
|
|
1177
|
+
}
|
|
1178
|
+
,.body= ""
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
#define HTTP_VERSION_0_9 11
|
|
1182
|
+
/* Should handle HTTP/0.9 */
|
|
1183
|
+
, {.name= "http version 0.9"
|
|
1184
|
+
,.type= HTTP_RESPONSE
|
|
1185
|
+
,.raw= "HTTP/0.9 200 OK\r\n"
|
|
1186
|
+
"\r\n"
|
|
1187
|
+
,.should_keep_alive= FALSE
|
|
1188
|
+
,.message_complete_on_eof= TRUE
|
|
1189
|
+
,.http_major= 0
|
|
1190
|
+
,.http_minor= 9
|
|
1191
|
+
,.status_code= 200
|
|
1192
|
+
,.num_headers= 0
|
|
1193
|
+
,.headers=
|
|
1194
|
+
{}
|
|
1195
|
+
,.body= ""
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
|
|
1199
|
+
/* The client should wait for the server's EOF. That is, when neither
|
|
1200
|
+
* content-length nor transfer-encoding is specified, the end of body
|
|
1201
|
+
* is specified by the EOF.
|
|
1202
|
+
*/
|
|
1203
|
+
, {.name= "neither content-length nor transfer-encoding response"
|
|
1204
|
+
,.type= HTTP_RESPONSE
|
|
1205
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
|
1206
|
+
"Content-Type: text/plain\r\n"
|
|
1207
|
+
"\r\n"
|
|
1208
|
+
"hello world"
|
|
1209
|
+
,.should_keep_alive= FALSE
|
|
1210
|
+
,.message_complete_on_eof= TRUE
|
|
1211
|
+
,.http_major= 1
|
|
1212
|
+
,.http_minor= 1
|
|
1213
|
+
,.status_code= 200
|
|
1214
|
+
,.num_headers= 1
|
|
1215
|
+
,.headers=
|
|
1216
|
+
{ { "Content-Type", "text/plain" }
|
|
1217
|
+
}
|
|
1218
|
+
,.body= "hello world"
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
#define NO_BODY_HTTP10_KA_200 13
|
|
1222
|
+
, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
|
|
1223
|
+
,.type= HTTP_RESPONSE
|
|
1224
|
+
,.raw= "HTTP/1.0 200 OK\r\n"
|
|
1225
|
+
"Connection: keep-alive\r\n"
|
|
1226
|
+
"\r\n"
|
|
1227
|
+
,.should_keep_alive= FALSE
|
|
1228
|
+
,.message_complete_on_eof= TRUE
|
|
1229
|
+
,.http_major= 1
|
|
1230
|
+
,.http_minor= 0
|
|
1231
|
+
,.status_code= 200
|
|
1232
|
+
,.num_headers= 1
|
|
1233
|
+
,.headers=
|
|
1234
|
+
{ { "Connection", "keep-alive" }
|
|
1235
|
+
}
|
|
1236
|
+
,.body_size= 0
|
|
1237
|
+
,.body= ""
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
#define NO_BODY_HTTP10_KA_204 14
|
|
1241
|
+
, {.name= "HTTP/1.0 with keep-alive and a 204 status"
|
|
1242
|
+
,.type= HTTP_RESPONSE
|
|
1243
|
+
,.raw= "HTTP/1.0 204 No content\r\n"
|
|
1244
|
+
"Connection: keep-alive\r\n"
|
|
1245
|
+
"\r\n"
|
|
1246
|
+
,.should_keep_alive= TRUE
|
|
1247
|
+
,.message_complete_on_eof= FALSE
|
|
1248
|
+
,.http_major= 1
|
|
1249
|
+
,.http_minor= 0
|
|
1250
|
+
,.status_code= 204
|
|
1251
|
+
,.num_headers= 1
|
|
1252
|
+
,.headers=
|
|
1253
|
+
{ { "Connection", "keep-alive" }
|
|
1254
|
+
}
|
|
1255
|
+
,.body_size= 0
|
|
1256
|
+
,.body= ""
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
#define NO_BODY_HTTP11_KA_200 15
|
|
1260
|
+
, {.name= "HTTP/1.1 with an EOF-terminated 200 status"
|
|
1261
|
+
,.type= HTTP_RESPONSE
|
|
1262
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
|
1263
|
+
"\r\n"
|
|
1264
|
+
,.should_keep_alive= FALSE
|
|
1265
|
+
,.message_complete_on_eof= TRUE
|
|
1266
|
+
,.http_major= 1
|
|
1267
|
+
,.http_minor= 1
|
|
1268
|
+
,.status_code= 200
|
|
1269
|
+
,.num_headers= 0
|
|
1270
|
+
,.headers={}
|
|
1271
|
+
,.body_size= 0
|
|
1272
|
+
,.body= ""
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
#define NO_BODY_HTTP11_KA_204 16
|
|
1276
|
+
, {.name= "HTTP/1.1 with a 204 status"
|
|
1277
|
+
,.type= HTTP_RESPONSE
|
|
1278
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
|
1279
|
+
"\r\n"
|
|
1280
|
+
,.should_keep_alive= TRUE
|
|
1281
|
+
,.message_complete_on_eof= FALSE
|
|
1282
|
+
,.http_major= 1
|
|
1283
|
+
,.http_minor= 1
|
|
1284
|
+
,.status_code= 204
|
|
1285
|
+
,.num_headers= 0
|
|
1286
|
+
,.headers={}
|
|
1287
|
+
,.body_size= 0
|
|
1288
|
+
,.body= ""
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
#define NO_BODY_HTTP11_NOKA_204 17
|
|
1292
|
+
, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
|
|
1293
|
+
,.type= HTTP_RESPONSE
|
|
1294
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
|
1295
|
+
"Connection: close\r\n"
|
|
1296
|
+
"\r\n"
|
|
1297
|
+
,.should_keep_alive= FALSE
|
|
1298
|
+
,.message_complete_on_eof= FALSE
|
|
1299
|
+
,.http_major= 1
|
|
1300
|
+
,.http_minor= 1
|
|
1301
|
+
,.status_code= 204
|
|
1302
|
+
,.num_headers= 1
|
|
1303
|
+
,.headers=
|
|
1304
|
+
{ { "Connection", "close" }
|
|
1305
|
+
}
|
|
1306
|
+
,.body_size= 0
|
|
1307
|
+
,.body= ""
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
#define NO_BODY_HTTP11_KA_CHUNKED_200 18
|
|
1311
|
+
, {.name= "HTTP/1.1 with chunked endocing and a 200 response"
|
|
1312
|
+
,.type= HTTP_RESPONSE
|
|
1313
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
|
1314
|
+
"Transfer-Encoding: chunked\r\n"
|
|
1315
|
+
"\r\n"
|
|
1316
|
+
"0\r\n"
|
|
1317
|
+
"\r\n"
|
|
1318
|
+
,.should_keep_alive= TRUE
|
|
1319
|
+
,.message_complete_on_eof= FALSE
|
|
1320
|
+
,.http_major= 1
|
|
1321
|
+
,.http_minor= 1
|
|
1322
|
+
,.status_code= 200
|
|
1323
|
+
,.num_headers= 1
|
|
1324
|
+
,.headers=
|
|
1325
|
+
{ { "Transfer-Encoding", "chunked" }
|
|
1326
|
+
}
|
|
1327
|
+
,.body_size= 0
|
|
1328
|
+
,.body= ""
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
#if !HTTP_PARSER_STRICT
|
|
1332
|
+
#define SPACE_IN_FIELD_RES 19
|
|
805
1333
|
/* Should handle spaces in header fields */
|
|
806
1334
|
, {.name= "field space"
|
|
807
1335
|
,.type= HTTP_RESPONSE
|
|
@@ -832,18 +1360,11 @@ const struct message responses[] =
|
|
|
832
1360
|
}
|
|
833
1361
|
,.body= "<xml>hello</xml>"
|
|
834
1362
|
}
|
|
1363
|
+
#endif /* !HTTP_PARSER_STRICT */
|
|
835
1364
|
|
|
836
1365
|
, {.name= NULL } /* sentinel */
|
|
837
1366
|
};
|
|
838
1367
|
|
|
839
|
-
int
|
|
840
|
-
request_path_cb (http_parser *p, const char *buf, size_t len)
|
|
841
|
-
{
|
|
842
|
-
assert(p == parser);
|
|
843
|
-
strncat(messages[num_messages].request_path, buf, len);
|
|
844
|
-
return 0;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
1368
|
int
|
|
848
1369
|
request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
849
1370
|
{
|
|
@@ -852,22 +1373,6 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
|
852
1373
|
return 0;
|
|
853
1374
|
}
|
|
854
1375
|
|
|
855
|
-
int
|
|
856
|
-
query_string_cb (http_parser *p, const char *buf, size_t len)
|
|
857
|
-
{
|
|
858
|
-
assert(p == parser);
|
|
859
|
-
strncat(messages[num_messages].query_string, buf, len);
|
|
860
|
-
return 0;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
int
|
|
864
|
-
fragment_cb (http_parser *p, const char *buf, size_t len)
|
|
865
|
-
{
|
|
866
|
-
assert(p == parser);
|
|
867
|
-
strncat(messages[num_messages].fragment, buf, len);
|
|
868
|
-
return 0;
|
|
869
|
-
}
|
|
870
|
-
|
|
871
1376
|
int
|
|
872
1377
|
header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
873
1378
|
{
|
|
@@ -947,7 +1452,7 @@ message_complete_cb (http_parser *p)
|
|
|
947
1452
|
"value in both on_message_complete and on_headers_complete "
|
|
948
1453
|
"but it doesn't! ***\n\n");
|
|
949
1454
|
assert(0);
|
|
950
|
-
|
|
1455
|
+
abort();
|
|
951
1456
|
}
|
|
952
1457
|
messages[num_messages].message_complete_cb_called = TRUE;
|
|
953
1458
|
|
|
@@ -957,14 +1462,151 @@ message_complete_cb (http_parser *p)
|
|
|
957
1462
|
return 0;
|
|
958
1463
|
}
|
|
959
1464
|
|
|
1465
|
+
/* These dontcall_* callbacks exist so that we can verify that when we're
|
|
1466
|
+
* paused, no additional callbacks are invoked */
|
|
1467
|
+
int
|
|
1468
|
+
dontcall_message_begin_cb (http_parser *p)
|
|
1469
|
+
{
|
|
1470
|
+
if (p) { } // gcc
|
|
1471
|
+
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
|
|
1472
|
+
abort();
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
int
|
|
1476
|
+
dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
1477
|
+
{
|
|
1478
|
+
if (p || buf || len) { } // gcc
|
|
1479
|
+
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
|
|
1480
|
+
abort();
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
int
|
|
1484
|
+
dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
1485
|
+
{
|
|
1486
|
+
if (p || buf || len) { } // gcc
|
|
1487
|
+
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
|
|
1488
|
+
abort();
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
int
|
|
1492
|
+
dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
1493
|
+
{
|
|
1494
|
+
if (p || buf || len) { } // gcc
|
|
1495
|
+
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
|
|
1496
|
+
abort();
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
int
|
|
1500
|
+
dontcall_body_cb (http_parser *p, const char *buf, size_t len)
|
|
1501
|
+
{
|
|
1502
|
+
if (p || buf || len) { } // gcc
|
|
1503
|
+
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
|
|
1504
|
+
abort();
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
int
|
|
1508
|
+
dontcall_headers_complete_cb (http_parser *p)
|
|
1509
|
+
{
|
|
1510
|
+
if (p) { } // gcc
|
|
1511
|
+
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
|
|
1512
|
+
"parser ***\n\n");
|
|
1513
|
+
abort();
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
int
|
|
1517
|
+
dontcall_message_complete_cb (http_parser *p)
|
|
1518
|
+
{
|
|
1519
|
+
if (p) { } // gcc
|
|
1520
|
+
fprintf(stderr, "\n\n*** on_message_complete() called on paused "
|
|
1521
|
+
"parser ***\n\n");
|
|
1522
|
+
abort();
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
static http_parser_settings settings_dontcall =
|
|
1526
|
+
{.on_message_begin = dontcall_message_begin_cb
|
|
1527
|
+
,.on_header_field = dontcall_header_field_cb
|
|
1528
|
+
,.on_header_value = dontcall_header_value_cb
|
|
1529
|
+
,.on_url = dontcall_request_url_cb
|
|
1530
|
+
,.on_body = dontcall_body_cb
|
|
1531
|
+
,.on_headers_complete = dontcall_headers_complete_cb
|
|
1532
|
+
,.on_message_complete = dontcall_message_complete_cb
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
/* These pause_* callbacks always pause the parser and just invoke the regular
|
|
1536
|
+
* callback that tracks content. Before returning, we overwrite the parser
|
|
1537
|
+
* settings to point to the _dontcall variety so that we can verify that
|
|
1538
|
+
* the pause actually did, you know, pause. */
|
|
1539
|
+
int
|
|
1540
|
+
pause_message_begin_cb (http_parser *p)
|
|
1541
|
+
{
|
|
1542
|
+
http_parser_pause(p, 1);
|
|
1543
|
+
*current_pause_parser = settings_dontcall;
|
|
1544
|
+
return message_begin_cb(p);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
int
|
|
1548
|
+
pause_header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
1549
|
+
{
|
|
1550
|
+
http_parser_pause(p, 1);
|
|
1551
|
+
*current_pause_parser = settings_dontcall;
|
|
1552
|
+
return header_field_cb(p, buf, len);
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
int
|
|
1556
|
+
pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
1557
|
+
{
|
|
1558
|
+
http_parser_pause(p, 1);
|
|
1559
|
+
*current_pause_parser = settings_dontcall;
|
|
1560
|
+
return header_value_cb(p, buf, len);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
int
|
|
1564
|
+
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
1565
|
+
{
|
|
1566
|
+
http_parser_pause(p, 1);
|
|
1567
|
+
*current_pause_parser = settings_dontcall;
|
|
1568
|
+
return request_url_cb(p, buf, len);
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
int
|
|
1572
|
+
pause_body_cb (http_parser *p, const char *buf, size_t len)
|
|
1573
|
+
{
|
|
1574
|
+
http_parser_pause(p, 1);
|
|
1575
|
+
*current_pause_parser = settings_dontcall;
|
|
1576
|
+
return body_cb(p, buf, len);
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
int
|
|
1580
|
+
pause_headers_complete_cb (http_parser *p)
|
|
1581
|
+
{
|
|
1582
|
+
http_parser_pause(p, 1);
|
|
1583
|
+
*current_pause_parser = settings_dontcall;
|
|
1584
|
+
return headers_complete_cb(p);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
int
|
|
1588
|
+
pause_message_complete_cb (http_parser *p)
|
|
1589
|
+
{
|
|
1590
|
+
http_parser_pause(p, 1);
|
|
1591
|
+
*current_pause_parser = settings_dontcall;
|
|
1592
|
+
return message_complete_cb(p);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
static http_parser_settings settings_pause =
|
|
1596
|
+
{.on_message_begin = pause_message_begin_cb
|
|
1597
|
+
,.on_header_field = pause_header_field_cb
|
|
1598
|
+
,.on_header_value = pause_header_value_cb
|
|
1599
|
+
,.on_url = pause_request_url_cb
|
|
1600
|
+
,.on_body = pause_body_cb
|
|
1601
|
+
,.on_headers_complete = pause_headers_complete_cb
|
|
1602
|
+
,.on_message_complete = pause_message_complete_cb
|
|
1603
|
+
};
|
|
1604
|
+
|
|
960
1605
|
static http_parser_settings settings =
|
|
961
1606
|
{.on_message_begin = message_begin_cb
|
|
962
1607
|
,.on_header_field = header_field_cb
|
|
963
1608
|
,.on_header_value = header_value_cb
|
|
964
|
-
,.on_path = request_path_cb
|
|
965
1609
|
,.on_url = request_url_cb
|
|
966
|
-
,.on_fragment = fragment_cb
|
|
967
|
-
,.on_query_string = query_string_cb
|
|
968
1610
|
,.on_body = body_cb
|
|
969
1611
|
,.on_headers_complete = headers_complete_cb
|
|
970
1612
|
,.on_message_complete = message_complete_cb
|
|
@@ -974,10 +1616,7 @@ static http_parser_settings settings_count_body =
|
|
|
974
1616
|
{.on_message_begin = message_begin_cb
|
|
975
1617
|
,.on_header_field = header_field_cb
|
|
976
1618
|
,.on_header_value = header_value_cb
|
|
977
|
-
,.on_path = request_path_cb
|
|
978
1619
|
,.on_url = request_url_cb
|
|
979
|
-
,.on_fragment = fragment_cb
|
|
980
|
-
,.on_query_string = query_string_cb
|
|
981
1620
|
,.on_body = count_body_cb
|
|
982
1621
|
,.on_headers_complete = headers_complete_cb
|
|
983
1622
|
,.on_message_complete = message_complete_cb
|
|
@@ -987,10 +1626,7 @@ static http_parser_settings settings_null =
|
|
|
987
1626
|
{.on_message_begin = 0
|
|
988
1627
|
,.on_header_field = 0
|
|
989
1628
|
,.on_header_value = 0
|
|
990
|
-
,.on_path = 0
|
|
991
1629
|
,.on_url = 0
|
|
992
|
-
,.on_fragment = 0
|
|
993
|
-
,.on_query_string = 0
|
|
994
1630
|
,.on_body = 0
|
|
995
1631
|
,.on_headers_complete = 0
|
|
996
1632
|
,.on_message_complete = 0
|
|
@@ -1035,12 +1671,29 @@ size_t parse_count_body (const char *buf, size_t len)
|
|
|
1035
1671
|
return nparsed;
|
|
1036
1672
|
}
|
|
1037
1673
|
|
|
1674
|
+
size_t parse_pause (const char *buf, size_t len)
|
|
1675
|
+
{
|
|
1676
|
+
size_t nparsed;
|
|
1677
|
+
http_parser_settings s = settings_pause;
|
|
1678
|
+
|
|
1679
|
+
currently_parsing_eof = (len == 0);
|
|
1680
|
+
current_pause_parser = &s;
|
|
1681
|
+
nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
|
|
1682
|
+
return nparsed;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1038
1685
|
static inline int
|
|
1039
1686
|
check_str_eq (const struct message *m,
|
|
1040
1687
|
const char *prop,
|
|
1041
1688
|
const char *expected,
|
|
1042
1689
|
const char *found) {
|
|
1043
|
-
if (
|
|
1690
|
+
if ((expected == NULL) != (found == NULL)) {
|
|
1691
|
+
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
|
1692
|
+
printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
|
|
1693
|
+
printf(" found %s\n", (found == NULL) ? "NULL" : found);
|
|
1694
|
+
return 0;
|
|
1695
|
+
}
|
|
1696
|
+
if (expected != NULL && 0 != strcmp(expected, found)) {
|
|
1044
1697
|
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
|
1045
1698
|
printf("expected '%s'\n", expected);
|
|
1046
1699
|
printf(" found '%s'\n", found);
|
|
@@ -1069,6 +1722,20 @@ check_num_eq (const struct message *m,
|
|
|
1069
1722
|
#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
|
|
1070
1723
|
if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
|
|
1071
1724
|
|
|
1725
|
+
#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
|
|
1726
|
+
do { \
|
|
1727
|
+
char ubuf[256]; \
|
|
1728
|
+
\
|
|
1729
|
+
if ((u)->field_set & (1 << (fn))) { \
|
|
1730
|
+
memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
|
|
1731
|
+
(u)->field_data[(fn)].len); \
|
|
1732
|
+
ubuf[(u)->field_data[(fn)].len] = '\0'; \
|
|
1733
|
+
} else { \
|
|
1734
|
+
ubuf[0] = '\0'; \
|
|
1735
|
+
} \
|
|
1736
|
+
\
|
|
1737
|
+
check_str_eq(expected, #prop, expected->prop, ubuf); \
|
|
1738
|
+
} while(0)
|
|
1072
1739
|
|
|
1073
1740
|
int
|
|
1074
1741
|
message_eq (int index, const struct message *expected)
|
|
@@ -1093,10 +1760,29 @@ message_eq (int index, const struct message *expected)
|
|
|
1093
1760
|
assert(m->message_complete_cb_called);
|
|
1094
1761
|
|
|
1095
1762
|
|
|
1096
|
-
MESSAGE_CHECK_STR_EQ(expected, m, request_path);
|
|
1097
|
-
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
|
|
1098
|
-
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
|
|
1099
1763
|
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
|
1764
|
+
|
|
1765
|
+
/* Check URL components; we can't do this w/ CONNECT since it doesn't
|
|
1766
|
+
* send us a well-formed URL.
|
|
1767
|
+
*/
|
|
1768
|
+
if (*m->request_url && m->method != HTTP_CONNECT) {
|
|
1769
|
+
struct http_parser_url u;
|
|
1770
|
+
|
|
1771
|
+
if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
|
|
1772
|
+
fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
|
|
1773
|
+
m->request_url);
|
|
1774
|
+
abort();
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
m->port = (u.field_set & (1 << UF_PORT)) ?
|
|
1778
|
+
u.port : 0;
|
|
1779
|
+
|
|
1780
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
|
|
1781
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
|
|
1782
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
|
|
1783
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, port);
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1100
1786
|
if (expected->body_size) {
|
|
1101
1787
|
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
|
|
1102
1788
|
} else {
|
|
@@ -1113,13 +1799,81 @@ message_eq (int index, const struct message *expected)
|
|
|
1113
1799
|
if (!r) return 0;
|
|
1114
1800
|
}
|
|
1115
1801
|
|
|
1802
|
+
MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
|
|
1803
|
+
|
|
1116
1804
|
return 1;
|
|
1117
1805
|
}
|
|
1118
1806
|
|
|
1807
|
+
/* Given a sequence of varargs messages, return the number of them that the
|
|
1808
|
+
* parser should successfully parse, taking into account that upgraded
|
|
1809
|
+
* messages prevent all subsequent messages from being parsed.
|
|
1810
|
+
*/
|
|
1811
|
+
size_t
|
|
1812
|
+
count_parsed_messages(const size_t nmsgs, ...) {
|
|
1813
|
+
size_t i;
|
|
1814
|
+
va_list ap;
|
|
1815
|
+
|
|
1816
|
+
va_start(ap, nmsgs);
|
|
1817
|
+
|
|
1818
|
+
for (i = 0; i < nmsgs; i++) {
|
|
1819
|
+
struct message *m = va_arg(ap, struct message *);
|
|
1820
|
+
|
|
1821
|
+
if (m->upgrade) {
|
|
1822
|
+
va_end(ap);
|
|
1823
|
+
return i + 1;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
va_end(ap);
|
|
1828
|
+
return nmsgs;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
/* Given a sequence of bytes and the number of these that we were able to
|
|
1832
|
+
* parse, verify that upgrade bodies are correct.
|
|
1833
|
+
*/
|
|
1834
|
+
void
|
|
1835
|
+
upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
|
|
1836
|
+
va_list ap;
|
|
1837
|
+
size_t i;
|
|
1838
|
+
size_t off = 0;
|
|
1839
|
+
|
|
1840
|
+
va_start(ap, nmsgs);
|
|
1841
|
+
|
|
1842
|
+
for (i = 0; i < nmsgs; i++) {
|
|
1843
|
+
struct message *m = va_arg(ap, struct message *);
|
|
1844
|
+
|
|
1845
|
+
off += strlen(m->raw);
|
|
1846
|
+
|
|
1847
|
+
if (m->upgrade) {
|
|
1848
|
+
off -= strlen(m->upgrade);
|
|
1849
|
+
|
|
1850
|
+
/* Check the portion of the response after its specified upgrade */
|
|
1851
|
+
if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
|
1852
|
+
abort();
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/* Fix up the response so that message_eq() will verify the beginning
|
|
1856
|
+
* of the upgrade */
|
|
1857
|
+
*(body + nread + strlen(m->upgrade)) = '\0';
|
|
1858
|
+
messages[num_messages -1 ].upgrade = body + nread;
|
|
1859
|
+
|
|
1860
|
+
va_end(ap);
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
va_end(ap);
|
|
1866
|
+
printf("\n\n*** Error: expected a message with upgrade ***\n");
|
|
1867
|
+
|
|
1868
|
+
abort();
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1119
1871
|
static void
|
|
1120
1872
|
print_error (const char *raw, size_t error_location)
|
|
1121
1873
|
{
|
|
1122
|
-
fprintf(stderr, "\n***
|
|
1874
|
+
fprintf(stderr, "\n*** %s:%d -- %s ***\n\n",
|
|
1875
|
+
"http_parser.c", HTTP_PARSER_ERRNO_LINE(parser),
|
|
1876
|
+
http_errno_description(HTTP_PARSER_ERRNO(parser)));
|
|
1123
1877
|
|
|
1124
1878
|
int this_line = 0, char_len = 0;
|
|
1125
1879
|
size_t i, j, len = strlen(raw), error_location_line = 0;
|
|
@@ -1157,6 +1911,218 @@ print_error (const char *raw, size_t error_location)
|
|
|
1157
1911
|
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
|
1158
1912
|
}
|
|
1159
1913
|
|
|
1914
|
+
void
|
|
1915
|
+
test_preserve_data (void)
|
|
1916
|
+
{
|
|
1917
|
+
char my_data[] = "application-specific data";
|
|
1918
|
+
http_parser parser;
|
|
1919
|
+
parser.data = my_data;
|
|
1920
|
+
http_parser_init(&parser, HTTP_REQUEST);
|
|
1921
|
+
if (parser.data != my_data) {
|
|
1922
|
+
printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
|
|
1923
|
+
abort();
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
struct url_test {
|
|
1928
|
+
const char *name;
|
|
1929
|
+
const char *url;
|
|
1930
|
+
int is_connect;
|
|
1931
|
+
struct http_parser_url u;
|
|
1932
|
+
int rv;
|
|
1933
|
+
};
|
|
1934
|
+
|
|
1935
|
+
const struct url_test url_tests[] =
|
|
1936
|
+
{ {.name="proxy request"
|
|
1937
|
+
,.url="http://hostname/"
|
|
1938
|
+
,.is_connect=0
|
|
1939
|
+
,.u=
|
|
1940
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
|
1941
|
+
,.port=0
|
|
1942
|
+
,.field_data=
|
|
1943
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
|
1944
|
+
,{ 7, 8 } /* UF_HOST */
|
|
1945
|
+
,{ 0, 0 } /* UF_PORT */
|
|
1946
|
+
,{ 15, 1 } /* UF_PATH */
|
|
1947
|
+
,{ 0, 0 } /* UF_QUERY */
|
|
1948
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
,.rv=0
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
, {.name="CONNECT request"
|
|
1955
|
+
,.url="hostname:443"
|
|
1956
|
+
,.is_connect=1
|
|
1957
|
+
,.u=
|
|
1958
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
|
1959
|
+
,.port=443
|
|
1960
|
+
,.field_data=
|
|
1961
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
|
1962
|
+
,{ 0, 8 } /* UF_HOST */
|
|
1963
|
+
,{ 9, 3 } /* UF_PORT */
|
|
1964
|
+
,{ 0, 0 } /* UF_PATH */
|
|
1965
|
+
,{ 0, 0 } /* UF_QUERY */
|
|
1966
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
,.rv=0
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
, {.name="proxy ipv6 request"
|
|
1973
|
+
,.url="http://[1:2::3:4]/"
|
|
1974
|
+
,.is_connect=0
|
|
1975
|
+
,.u=
|
|
1976
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
|
1977
|
+
,.port=0
|
|
1978
|
+
,.field_data=
|
|
1979
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
|
1980
|
+
,{ 8, 8 } /* UF_HOST */
|
|
1981
|
+
,{ 0, 0 } /* UF_PORT */
|
|
1982
|
+
,{ 17, 1 } /* UF_PATH */
|
|
1983
|
+
,{ 0, 0 } /* UF_QUERY */
|
|
1984
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
,.rv=0
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
, {.name="CONNECT ipv6 address"
|
|
1991
|
+
,.url="[1:2::3:4]:443"
|
|
1992
|
+
,.is_connect=1
|
|
1993
|
+
,.u=
|
|
1994
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
|
1995
|
+
,.port=443
|
|
1996
|
+
,.field_data=
|
|
1997
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
|
1998
|
+
,{ 1, 8 } /* UF_HOST */
|
|
1999
|
+
,{ 11, 3 } /* UF_PORT */
|
|
2000
|
+
,{ 0, 0 } /* UF_PATH */
|
|
2001
|
+
,{ 0, 0 } /* UF_QUERY */
|
|
2002
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
,.rv=0
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
, {.name="extra ? in query string"
|
|
2009
|
+
,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
|
|
2010
|
+
,.is_connect=0
|
|
2011
|
+
,.u=
|
|
2012
|
+
{.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
|
|
2013
|
+
,.port=0
|
|
2014
|
+
,.field_data=
|
|
2015
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
|
2016
|
+
,{ 7, 10 } /* UF_HOST */
|
|
2017
|
+
,{ 0, 0 } /* UF_PORT */
|
|
2018
|
+
,{ 17, 12 } /* UF_PATH */
|
|
2019
|
+
,{ 30,187 } /* UF_QUERY */
|
|
2020
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
,.rv=0
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
, {.name="proxy empty host"
|
|
2027
|
+
,.url="http://:443/"
|
|
2028
|
+
,.is_connect=0
|
|
2029
|
+
,.rv=1
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
, {.name="proxy empty port"
|
|
2033
|
+
,.url="http://hostname:/"
|
|
2034
|
+
,.is_connect=0
|
|
2035
|
+
,.rv=1
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
, {.name="CONNECT empty host"
|
|
2039
|
+
,.url=":443"
|
|
2040
|
+
,.is_connect=1
|
|
2041
|
+
,.rv=1
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
, {.name="CONNECT empty port"
|
|
2045
|
+
,.url="hostname:"
|
|
2046
|
+
,.is_connect=1
|
|
2047
|
+
,.rv=1
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
, {.name="CONNECT with extra bits"
|
|
2051
|
+
,.url="hostname:443/"
|
|
2052
|
+
,.is_connect=1
|
|
2053
|
+
,.rv=1
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
void
|
|
2058
|
+
dump_url (const char *url, const struct http_parser_url *u)
|
|
2059
|
+
{
|
|
2060
|
+
char part[512];
|
|
2061
|
+
unsigned int i;
|
|
2062
|
+
|
|
2063
|
+
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
|
2064
|
+
for (i = 0; i < UF_MAX; i++) {
|
|
2065
|
+
if ((u->field_set & (1 << i)) == 0) {
|
|
2066
|
+
printf("\tfield_data[%u]: unset\n", i);
|
|
2067
|
+
continue;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
memcpy(part, url + u->field_data[i].off, u->field_data[i].len);
|
|
2071
|
+
part[u->field_data[i].len] = '\0';
|
|
2072
|
+
|
|
2073
|
+
printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n",
|
|
2074
|
+
i,
|
|
2075
|
+
u->field_data[i].off,
|
|
2076
|
+
u->field_data[i].len,
|
|
2077
|
+
part);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
void
|
|
2082
|
+
test_parse_url (void)
|
|
2083
|
+
{
|
|
2084
|
+
struct http_parser_url u;
|
|
2085
|
+
const struct url_test *test;
|
|
2086
|
+
unsigned int i;
|
|
2087
|
+
int rv;
|
|
2088
|
+
|
|
2089
|
+
for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
|
|
2090
|
+
test = &url_tests[i];
|
|
2091
|
+
memset(&u, 0, sizeof(u));
|
|
2092
|
+
|
|
2093
|
+
rv = http_parser_parse_url(test->url,
|
|
2094
|
+
strlen(test->url),
|
|
2095
|
+
test->is_connect,
|
|
2096
|
+
&u);
|
|
2097
|
+
|
|
2098
|
+
if (test->rv == 0) {
|
|
2099
|
+
if (rv != 0) {
|
|
2100
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
|
2101
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
|
2102
|
+
abort();
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
|
|
2106
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
|
|
2107
|
+
test->url, test->name);
|
|
2108
|
+
|
|
2109
|
+
printf("target http_parser_url:\n");
|
|
2110
|
+
dump_url(test->url, &test->u);
|
|
2111
|
+
printf("result http_parser_url:\n");
|
|
2112
|
+
dump_url(test->url, &u);
|
|
2113
|
+
|
|
2114
|
+
abort();
|
|
2115
|
+
}
|
|
2116
|
+
} else {
|
|
2117
|
+
/* test->rv != 0 */
|
|
2118
|
+
if (rv == 0) {
|
|
2119
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
|
2120
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
|
2121
|
+
abort();
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
1160
2126
|
|
|
1161
2127
|
void
|
|
1162
2128
|
test_message (const struct message *message)
|
|
@@ -1174,41 +2140,45 @@ test_message (const struct message *message)
|
|
|
1174
2140
|
if (msg1len) {
|
|
1175
2141
|
read = parse(msg1, msg1len);
|
|
1176
2142
|
|
|
1177
|
-
if (message->upgrade && parser->upgrade)
|
|
2143
|
+
if (message->upgrade && parser->upgrade) {
|
|
2144
|
+
messages[num_messages - 1].upgrade = msg1 + read;
|
|
2145
|
+
goto test;
|
|
2146
|
+
}
|
|
1178
2147
|
|
|
1179
2148
|
if (read != msg1len) {
|
|
1180
2149
|
print_error(msg1, read);
|
|
1181
|
-
|
|
2150
|
+
abort();
|
|
1182
2151
|
}
|
|
1183
2152
|
}
|
|
1184
2153
|
|
|
1185
2154
|
|
|
1186
2155
|
read = parse(msg2, msg2len);
|
|
1187
2156
|
|
|
1188
|
-
if (message->upgrade && parser->upgrade)
|
|
2157
|
+
if (message->upgrade && parser->upgrade) {
|
|
2158
|
+
messages[num_messages - 1].upgrade = msg2 + read;
|
|
2159
|
+
goto test;
|
|
2160
|
+
}
|
|
1189
2161
|
|
|
1190
2162
|
if (read != msg2len) {
|
|
1191
2163
|
print_error(msg2, read);
|
|
1192
|
-
|
|
2164
|
+
abort();
|
|
1193
2165
|
}
|
|
1194
2166
|
|
|
1195
2167
|
read = parse(NULL, 0);
|
|
1196
2168
|
|
|
1197
|
-
if (message->upgrade && parser->upgrade) goto test;
|
|
1198
|
-
|
|
1199
2169
|
if (read != 0) {
|
|
1200
2170
|
print_error(message->raw, read);
|
|
1201
|
-
|
|
2171
|
+
abort();
|
|
1202
2172
|
}
|
|
1203
2173
|
|
|
1204
2174
|
test:
|
|
1205
2175
|
|
|
1206
2176
|
if (num_messages != 1) {
|
|
1207
2177
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
|
1208
|
-
|
|
2178
|
+
abort();
|
|
1209
2179
|
}
|
|
1210
2180
|
|
|
1211
|
-
if(!message_eq(0, message))
|
|
2181
|
+
if(!message_eq(0, message)) abort();
|
|
1212
2182
|
|
|
1213
2183
|
parser_free();
|
|
1214
2184
|
}
|
|
@@ -1229,7 +2199,7 @@ test_message_count_body (const struct message *message)
|
|
|
1229
2199
|
read = parse_count_body(message->raw + i, toread);
|
|
1230
2200
|
if (read != toread) {
|
|
1231
2201
|
print_error(message->raw, read);
|
|
1232
|
-
|
|
2202
|
+
abort();
|
|
1233
2203
|
}
|
|
1234
2204
|
}
|
|
1235
2205
|
|
|
@@ -1237,36 +2207,47 @@ test_message_count_body (const struct message *message)
|
|
|
1237
2207
|
read = parse_count_body(NULL, 0);
|
|
1238
2208
|
if (read != 0) {
|
|
1239
2209
|
print_error(message->raw, read);
|
|
1240
|
-
|
|
2210
|
+
abort();
|
|
1241
2211
|
}
|
|
1242
2212
|
|
|
1243
2213
|
if (num_messages != 1) {
|
|
1244
2214
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
|
1245
|
-
|
|
2215
|
+
abort();
|
|
1246
2216
|
}
|
|
1247
2217
|
|
|
1248
|
-
if(!message_eq(0, message))
|
|
2218
|
+
if(!message_eq(0, message)) abort();
|
|
1249
2219
|
|
|
1250
2220
|
parser_free();
|
|
1251
2221
|
}
|
|
1252
2222
|
|
|
1253
2223
|
void
|
|
1254
|
-
test_simple (const char *buf,
|
|
2224
|
+
test_simple (const char *buf, enum http_errno err_expected)
|
|
1255
2225
|
{
|
|
1256
2226
|
parser_init(HTTP_REQUEST);
|
|
1257
2227
|
|
|
1258
2228
|
size_t parsed;
|
|
1259
2229
|
int pass;
|
|
2230
|
+
enum http_errno err;
|
|
2231
|
+
|
|
1260
2232
|
parsed = parse(buf, strlen(buf));
|
|
1261
2233
|
pass = (parsed == strlen(buf));
|
|
2234
|
+
err = HTTP_PARSER_ERRNO(parser);
|
|
1262
2235
|
parsed = parse(NULL, 0);
|
|
1263
2236
|
pass &= (parsed == 0);
|
|
1264
2237
|
|
|
1265
2238
|
parser_free();
|
|
1266
2239
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
2240
|
+
/* In strict mode, allow us to pass with an unexpected HPE_STRICT as
|
|
2241
|
+
* long as the caller isn't expecting success.
|
|
2242
|
+
*/
|
|
2243
|
+
#if HTTP_PARSER_STRICT
|
|
2244
|
+
if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
|
|
2245
|
+
#else
|
|
2246
|
+
if (err_expected != err) {
|
|
2247
|
+
#endif
|
|
2248
|
+
fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
|
|
2249
|
+
http_errno_name(err_expected), http_errno_name(err), buf);
|
|
2250
|
+
abort();
|
|
1270
2251
|
}
|
|
1271
2252
|
}
|
|
1272
2253
|
|
|
@@ -1282,16 +2263,67 @@ test_header_overflow_error (int req)
|
|
|
1282
2263
|
assert(parsed == strlen(buf));
|
|
1283
2264
|
|
|
1284
2265
|
buf = "header-key: header-value\r\n";
|
|
2266
|
+
size_t buflen = strlen(buf);
|
|
2267
|
+
|
|
1285
2268
|
int i;
|
|
1286
2269
|
for (i = 0; i < 10000; i++) {
|
|
1287
|
-
|
|
2270
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
|
2271
|
+
if (parsed != buflen) {
|
|
1288
2272
|
//fprintf(stderr, "error found on iter %d\n", i);
|
|
2273
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
|
|
1289
2274
|
return;
|
|
1290
2275
|
}
|
|
1291
2276
|
}
|
|
1292
2277
|
|
|
1293
2278
|
fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
|
|
1294
|
-
|
|
2279
|
+
abort();
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
static void
|
|
2283
|
+
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
|
|
2284
|
+
{
|
|
2285
|
+
http_parser parser;
|
|
2286
|
+
http_parser_init(&parser, HTTP_RESPONSE);
|
|
2287
|
+
http_parser_execute(&parser, &settings_null, buf, buflen);
|
|
2288
|
+
|
|
2289
|
+
if (expect_ok)
|
|
2290
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
|
|
2291
|
+
else
|
|
2292
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
void
|
|
2296
|
+
test_header_content_length_overflow_error (void)
|
|
2297
|
+
{
|
|
2298
|
+
#define X(size) \
|
|
2299
|
+
"HTTP/1.1 200 OK\r\n" \
|
|
2300
|
+
"Content-Length: " #size "\r\n" \
|
|
2301
|
+
"\r\n"
|
|
2302
|
+
const char a[] = X(18446744073709551614); /* 2^64-2 */
|
|
2303
|
+
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
|
2304
|
+
const char c[] = X(18446744073709551616); /* 2^64 */
|
|
2305
|
+
#undef X
|
|
2306
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
|
2307
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
|
2308
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
void
|
|
2312
|
+
test_chunk_content_length_overflow_error (void)
|
|
2313
|
+
{
|
|
2314
|
+
#define X(size) \
|
|
2315
|
+
"HTTP/1.1 200 OK\r\n" \
|
|
2316
|
+
"Transfer-Encoding: chunked\r\n" \
|
|
2317
|
+
"\r\n" \
|
|
2318
|
+
#size "\r\n" \
|
|
2319
|
+
"..."
|
|
2320
|
+
const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
|
|
2321
|
+
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
|
2322
|
+
const char c[] = X(10000000000000000); /* 2^64 */
|
|
2323
|
+
#undef X
|
|
2324
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
|
2325
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
|
2326
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
|
1295
2327
|
}
|
|
1296
2328
|
|
|
1297
2329
|
void
|
|
@@ -1324,18 +2356,13 @@ test_no_overflow_long_body (int req, size_t length)
|
|
|
1324
2356
|
"\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
|
|
1325
2357
|
req ? "REQUEST" : "RESPONSE",
|
|
1326
2358
|
length);
|
|
1327
|
-
|
|
2359
|
+
abort();
|
|
1328
2360
|
}
|
|
1329
2361
|
|
|
1330
2362
|
void
|
|
1331
2363
|
test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
|
|
1332
2364
|
{
|
|
1333
|
-
int message_count =
|
|
1334
|
-
if (!r1->upgrade) {
|
|
1335
|
-
message_count++;
|
|
1336
|
-
if (!r2->upgrade) message_count++;
|
|
1337
|
-
}
|
|
1338
|
-
int has_upgrade = (message_count < 3 || r3->upgrade);
|
|
2365
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
|
1339
2366
|
|
|
1340
2367
|
char total[ strlen(r1->raw)
|
|
1341
2368
|
+ strlen(r2->raw)
|
|
@@ -1354,36 +2381,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
|
|
|
1354
2381
|
|
|
1355
2382
|
read = parse(total, strlen(total));
|
|
1356
2383
|
|
|
1357
|
-
if (
|
|
2384
|
+
if (parser->upgrade) {
|
|
2385
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
|
2386
|
+
goto test;
|
|
2387
|
+
}
|
|
1358
2388
|
|
|
1359
2389
|
if (read != strlen(total)) {
|
|
1360
2390
|
print_error(total, read);
|
|
1361
|
-
|
|
2391
|
+
abort();
|
|
1362
2392
|
}
|
|
1363
2393
|
|
|
1364
2394
|
read = parse(NULL, 0);
|
|
1365
2395
|
|
|
1366
|
-
if (has_upgrade && parser->upgrade) goto test;
|
|
1367
|
-
|
|
1368
2396
|
if (read != 0) {
|
|
1369
2397
|
print_error(total, read);
|
|
1370
|
-
|
|
2398
|
+
abort();
|
|
1371
2399
|
}
|
|
1372
2400
|
|
|
1373
2401
|
test:
|
|
1374
2402
|
|
|
1375
2403
|
if (message_count != num_messages) {
|
|
1376
2404
|
fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
|
|
1377
|
-
|
|
2405
|
+
abort();
|
|
1378
2406
|
}
|
|
1379
2407
|
|
|
1380
|
-
if (!message_eq(0, r1))
|
|
1381
|
-
if (message_count > 1)
|
|
1382
|
-
|
|
1383
|
-
if (message_count > 2) {
|
|
1384
|
-
if (!message_eq(2, r3)) exit(1);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
2408
|
+
if (!message_eq(0, r1)) abort();
|
|
2409
|
+
if (message_count > 1 && !message_eq(1, r2)) abort();
|
|
2410
|
+
if (message_count > 2 && !message_eq(2, r3)) abort();
|
|
1387
2411
|
|
|
1388
2412
|
parser_free();
|
|
1389
2413
|
}
|
|
@@ -1412,6 +2436,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
|
1412
2436
|
int ops = 0 ;
|
|
1413
2437
|
|
|
1414
2438
|
size_t buf1_len, buf2_len, buf3_len;
|
|
2439
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
|
1415
2440
|
|
|
1416
2441
|
int i,j,type_both;
|
|
1417
2442
|
for (type_both = 0; type_both < 2; type_both ++ ) {
|
|
@@ -1440,27 +2465,27 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
|
1440
2465
|
|
|
1441
2466
|
read = parse(buf1, buf1_len);
|
|
1442
2467
|
|
|
1443
|
-
if (
|
|
2468
|
+
if (parser->upgrade) goto test;
|
|
1444
2469
|
|
|
1445
2470
|
if (read != buf1_len) {
|
|
1446
2471
|
print_error(buf1, read);
|
|
1447
2472
|
goto error;
|
|
1448
2473
|
}
|
|
1449
2474
|
|
|
1450
|
-
read
|
|
2475
|
+
read += parse(buf2, buf2_len);
|
|
1451
2476
|
|
|
1452
|
-
if (
|
|
2477
|
+
if (parser->upgrade) goto test;
|
|
1453
2478
|
|
|
1454
|
-
if (read != buf2_len) {
|
|
2479
|
+
if (read != buf1_len + buf2_len) {
|
|
1455
2480
|
print_error(buf2, read);
|
|
1456
2481
|
goto error;
|
|
1457
2482
|
}
|
|
1458
2483
|
|
|
1459
|
-
read
|
|
2484
|
+
read += parse(buf3, buf3_len);
|
|
1460
2485
|
|
|
1461
|
-
if (
|
|
2486
|
+
if (parser->upgrade) goto test;
|
|
1462
2487
|
|
|
1463
|
-
if (read != buf3_len) {
|
|
2488
|
+
if (read != buf1_len + buf2_len + buf3_len) {
|
|
1464
2489
|
print_error(buf3, read);
|
|
1465
2490
|
goto error;
|
|
1466
2491
|
}
|
|
@@ -1468,9 +2493,13 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
|
1468
2493
|
parse(NULL, 0);
|
|
1469
2494
|
|
|
1470
2495
|
test:
|
|
2496
|
+
if (parser->upgrade) {
|
|
2497
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
|
2498
|
+
}
|
|
1471
2499
|
|
|
1472
|
-
if (
|
|
1473
|
-
fprintf(stderr, "\n\nParser didn't see
|
|
2500
|
+
if (message_count != num_messages) {
|
|
2501
|
+
fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
|
|
2502
|
+
message_count, num_messages);
|
|
1474
2503
|
goto error;
|
|
1475
2504
|
}
|
|
1476
2505
|
|
|
@@ -1479,12 +2508,12 @@ test:
|
|
|
1479
2508
|
goto error;
|
|
1480
2509
|
}
|
|
1481
2510
|
|
|
1482
|
-
if (!message_eq(1, r2)) {
|
|
2511
|
+
if (message_count > 1 && !message_eq(1, r2)) {
|
|
1483
2512
|
fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
|
|
1484
2513
|
goto error;
|
|
1485
2514
|
}
|
|
1486
2515
|
|
|
1487
|
-
if (!message_eq(2, r3)) {
|
|
2516
|
+
if (message_count > 2 && !message_eq(2, r3)) {
|
|
1488
2517
|
fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
|
|
1489
2518
|
goto error;
|
|
1490
2519
|
}
|
|
@@ -1501,7 +2530,7 @@ test:
|
|
|
1501
2530
|
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
|
|
1502
2531
|
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
|
|
1503
2532
|
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
|
|
1504
|
-
|
|
2533
|
+
abort();
|
|
1505
2534
|
}
|
|
1506
2535
|
|
|
1507
2536
|
// user required to free the result
|
|
@@ -1535,100 +2564,111 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
|
1535
2564
|
return buf;
|
|
1536
2565
|
}
|
|
1537
2566
|
|
|
1538
|
-
char *
|
|
2567
|
+
char *
|
|
1539
2568
|
quote(const char * orig) {
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
2569
|
+
if (!orig) return NULL;
|
|
2570
|
+
size_t j, i, len = strlen(orig);
|
|
2571
|
+
char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
|
|
2572
|
+
bzero(quoted, len == 0 ? 1 : len*2);
|
|
2573
|
+
for (i=0, j=0; i!=len; ++i) {
|
|
2574
|
+
switch (orig[i]){
|
|
2575
|
+
case '\n':
|
|
2576
|
+
quoted[j++] = '\\';
|
|
2577
|
+
quoted[j++] = 'n';
|
|
2578
|
+
break;
|
|
2579
|
+
case '\r':
|
|
2580
|
+
quoted[j++] = '\\';
|
|
2581
|
+
quoted[j++] = 'r';
|
|
2582
|
+
break;
|
|
2583
|
+
case '"':
|
|
2584
|
+
quoted[j++] = '\\';
|
|
2585
|
+
quoted[j++] = '"';
|
|
2586
|
+
break;
|
|
2587
|
+
default :
|
|
2588
|
+
quoted[j++] = orig[i];
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
return quoted;
|
|
1562
2592
|
}
|
|
1563
2593
|
|
|
1564
|
-
void
|
|
2594
|
+
void
|
|
1565
2595
|
dump_message(const struct message * m)
|
|
1566
2596
|
{
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
case HTTP_DELETE:
|
|
1582
|
-
case HTTP_GET:
|
|
1583
|
-
case HTTP_HEAD:
|
|
1584
|
-
case HTTP_POST:
|
|
1585
|
-
case HTTP_PUT:
|
|
1586
|
-
case HTTP_CONNECT:
|
|
1587
|
-
case HTTP_OPTIONS:
|
|
1588
|
-
case HTTP_TRACE:
|
|
1589
|
-
case HTTP_COPY:
|
|
1590
|
-
case HTTP_LOCK:
|
|
1591
|
-
case HTTP_MKCOL:
|
|
1592
|
-
case HTTP_MOVE:
|
|
1593
|
-
case HTTP_PROPFIND:
|
|
1594
|
-
case HTTP_PROPPATCH:
|
|
1595
|
-
case HTTP_UNLOCK:
|
|
2597
|
+
int i;
|
|
2598
|
+
printf("name :%s\n", m->name);
|
|
2599
|
+
char * bla = quote(m->raw);
|
|
2600
|
+
printf("raw :\"%s\"\n", bla);
|
|
2601
|
+
free(bla);
|
|
2602
|
+
switch (m->type){
|
|
2603
|
+
case HTTP_REQUEST:
|
|
2604
|
+
printf("type :HTTP_REQUEST\n");break;
|
|
2605
|
+
case HTTP_RESPONSE:
|
|
2606
|
+
printf("type :HTTP_RESPONSE\n"); break;
|
|
2607
|
+
case HTTP_BOTH:
|
|
2608
|
+
printf("type :HTTP_BOTH\n");
|
|
2609
|
+
}
|
|
2610
|
+
switch (m->method) {
|
|
2611
|
+
case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
|
|
2612
|
+
case HTTP_GET: printf("method: HTTP_GET\n");break;
|
|
2613
|
+
case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
|
|
2614
|
+
case HTTP_POST: printf("method: HTTP_POST\n");break;
|
|
2615
|
+
case HTTP_PUT: printf("method: HTTP_PUT\n");break;
|
|
2616
|
+
case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
|
|
2617
|
+
case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
|
|
2618
|
+
case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
|
|
2619
|
+
case HTTP_COPY: printf("method: HTTP_COPY\n");break;
|
|
2620
|
+
case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
|
|
2621
|
+
case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
|
|
2622
|
+
case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
|
|
2623
|
+
case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
|
|
2624
|
+
case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
|
|
2625
|
+
case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
|
|
1596
2626
|
/* subversion */
|
|
1597
|
-
case HTTP_REPORT:
|
|
1598
|
-
case HTTP_MKACTIVITY:
|
|
1599
|
-
case HTTP_CHECKOUT:
|
|
1600
|
-
case HTTP_MERGE:
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
2627
|
+
case HTTP_REPORT: printf("method: HTTP_REPORT\n"); break;
|
|
2628
|
+
case HTTP_MKACTIVITY: printf("method: HTTP_MKACTIVITY\n"); break;
|
|
2629
|
+
case HTTP_CHECKOUT: printf("method: HTTP_CHECKOUT\n"); break;
|
|
2630
|
+
case HTTP_MERGE: printf("method: HTTP_MERGE\n"); break;
|
|
2631
|
+
|
|
2632
|
+
case HTTP_MSEARCH: printf("method: HTTP_MSEARCH\n"); break;
|
|
2633
|
+
case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
|
|
2634
|
+
case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
|
|
2635
|
+
case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
|
|
2636
|
+
default:
|
|
2637
|
+
printf("method: UNKNOWN\n"); break;
|
|
2638
|
+
break;
|
|
2639
|
+
}
|
|
2640
|
+
printf("status_code :%d\n", m->status_code);
|
|
1605
2641
|
printf("request_path:%s\n", m->request_path);
|
|
1606
2642
|
printf("request_url :%s\n", m->request_url);
|
|
1607
2643
|
printf("fragment :%s\n", m->fragment);
|
|
1608
2644
|
printf("query_string:%s\n", m->query_string);
|
|
1609
2645
|
|
|
1610
|
-
|
|
2646
|
+
bla = quote(m->body);
|
|
1611
2647
|
printf("body :\"%s\"\n", bla);
|
|
1612
|
-
|
|
2648
|
+
free(bla);
|
|
1613
2649
|
printf("body_size :%zu\n", m->body_size);
|
|
1614
2650
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
2651
|
+
for (i=0; i!=m->num_headers; ++i){
|
|
2652
|
+
printf("header_%d :{ \"%s\": \"%s\"}\n", i, m->headers[i][0], m->headers[i][1]);
|
|
2653
|
+
}
|
|
1618
2654
|
|
|
1619
2655
|
printf("should_keep_alive :%d\n", m->should_keep_alive);
|
|
1620
|
-
|
|
2656
|
+
bla = quote(m->upgrade);
|
|
2657
|
+
if (bla) {
|
|
2658
|
+
printf("upgrade :\"%s\"\n", bla);
|
|
2659
|
+
}
|
|
2660
|
+
free(bla);
|
|
1621
2661
|
printf("http_major :%d\n", m->http_major);
|
|
1622
2662
|
printf("http_minor :%d\n", m->http_minor);
|
|
1623
2663
|
// printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
|
|
1624
2664
|
// printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
|
|
1625
2665
|
// printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
|
|
1626
2666
|
// printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
|
|
1627
|
-
|
|
2667
|
+
printf("\n");
|
|
1628
2668
|
}
|
|
1629
2669
|
|
|
1630
|
-
void
|
|
1631
|
-
dump_messages(void)
|
|
2670
|
+
void
|
|
2671
|
+
dump_messages(void)
|
|
1632
2672
|
{
|
|
1633
2673
|
int request_count;
|
|
1634
2674
|
for (request_count = 0; requests[request_count].name; request_count++){
|
|
@@ -1639,6 +2679,60 @@ dump_messages(void)
|
|
|
1639
2679
|
}
|
|
1640
2680
|
}
|
|
1641
2681
|
|
|
2682
|
+
/* Verify that we can pause parsing at any of the bytes in the
|
|
2683
|
+
* message and still get the result that we're expecting. */
|
|
2684
|
+
void
|
|
2685
|
+
test_message_pause (const struct message *msg)
|
|
2686
|
+
{
|
|
2687
|
+
char *buf = (char*) msg->raw;
|
|
2688
|
+
size_t buflen = strlen(msg->raw);
|
|
2689
|
+
size_t nread;
|
|
2690
|
+
|
|
2691
|
+
parser_init(msg->type);
|
|
2692
|
+
|
|
2693
|
+
do {
|
|
2694
|
+
nread = parse_pause(buf, buflen);
|
|
2695
|
+
|
|
2696
|
+
// We can only set the upgrade buffer once we've gotten our message
|
|
2697
|
+
// completion callback.
|
|
2698
|
+
if (messages[0].message_complete_cb_called &&
|
|
2699
|
+
msg->upgrade &&
|
|
2700
|
+
parser->upgrade) {
|
|
2701
|
+
messages[0].upgrade = buf + nread;
|
|
2702
|
+
goto test;
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
if (nread < buflen) {
|
|
2706
|
+
|
|
2707
|
+
// Not much do to if we failed a strict-mode check
|
|
2708
|
+
if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
|
|
2709
|
+
parser_free();
|
|
2710
|
+
return;
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
buf += nread;
|
|
2717
|
+
buflen -= nread;
|
|
2718
|
+
http_parser_pause(parser, 0);
|
|
2719
|
+
} while (buflen > 0);
|
|
2720
|
+
|
|
2721
|
+
nread = parse_pause(NULL, 0);
|
|
2722
|
+
assert (nread == 0);
|
|
2723
|
+
|
|
2724
|
+
test:
|
|
2725
|
+
if (num_messages != 1) {
|
|
2726
|
+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
|
2727
|
+
abort();
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
if(!message_eq(0, msg)) abort();
|
|
2731
|
+
|
|
2732
|
+
parser_free();
|
|
2733
|
+
|
|
2734
|
+
}
|
|
2735
|
+
|
|
1642
2736
|
int
|
|
1643
2737
|
main (int argc, char * argv[])
|
|
1644
2738
|
{
|
|
@@ -1659,6 +2753,10 @@ main (int argc, char * argv[])
|
|
|
1659
2753
|
for (request_count = 0; requests[request_count].name; request_count++);
|
|
1660
2754
|
for (response_count = 0; responses[response_count].name; response_count++);
|
|
1661
2755
|
|
|
2756
|
+
//// API
|
|
2757
|
+
test_preserve_data();
|
|
2758
|
+
test_parse_url();
|
|
2759
|
+
|
|
1662
2760
|
//// OVERFLOW CONDITIONS
|
|
1663
2761
|
|
|
1664
2762
|
test_header_overflow_error(HTTP_REQUEST);
|
|
@@ -1669,12 +2767,19 @@ main (int argc, char * argv[])
|
|
|
1669
2767
|
test_no_overflow_long_body(HTTP_RESPONSE, 1000);
|
|
1670
2768
|
test_no_overflow_long_body(HTTP_RESPONSE, 100000);
|
|
1671
2769
|
|
|
2770
|
+
test_header_content_length_overflow_error();
|
|
2771
|
+
test_chunk_content_length_overflow_error();
|
|
2772
|
+
|
|
1672
2773
|
//// RESPONSES
|
|
1673
2774
|
|
|
1674
2775
|
for (i = 0; i < response_count; i++) {
|
|
1675
2776
|
test_message(&responses[i]);
|
|
1676
2777
|
}
|
|
1677
2778
|
|
|
2779
|
+
for (i = 0; i < response_count; i++) {
|
|
2780
|
+
test_message_pause(&responses[i]);
|
|
2781
|
+
}
|
|
2782
|
+
|
|
1678
2783
|
for (i = 0; i < response_count; i++) {
|
|
1679
2784
|
if (!responses[i].should_keep_alive) continue;
|
|
1680
2785
|
for (j = 0; j < response_count; j++) {
|
|
@@ -1719,7 +2824,7 @@ main (int argc, char * argv[])
|
|
|
1719
2824
|
|
|
1720
2825
|
printf("response scan 1/2 ");
|
|
1721
2826
|
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
|
1722
|
-
, &responses[
|
|
2827
|
+
, &responses[NO_BODY_HTTP10_KA_204]
|
|
1723
2828
|
, &responses[NO_REASON_PHRASE]
|
|
1724
2829
|
);
|
|
1725
2830
|
|
|
@@ -1734,13 +2839,21 @@ main (int argc, char * argv[])
|
|
|
1734
2839
|
|
|
1735
2840
|
/// REQUESTS
|
|
1736
2841
|
|
|
2842
|
+
test_simple("hello world", HPE_INVALID_METHOD);
|
|
2843
|
+
test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
|
|
1737
2844
|
|
|
1738
|
-
test_simple("hello world", 0);
|
|
1739
|
-
test_simple("GET / HTP/1.1\r\n\r\n", 0);
|
|
1740
2845
|
|
|
1741
|
-
test_simple("ASDF / HTTP/1.1\r\n\r\n",
|
|
1742
|
-
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n",
|
|
1743
|
-
test_simple("GETA / HTTP/1.1\r\n\r\n",
|
|
2846
|
+
test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
|
2847
|
+
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
|
2848
|
+
test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
|
2849
|
+
|
|
2850
|
+
// Well-formed but incomplete
|
|
2851
|
+
test_simple("GET / HTTP/1.1\r\n"
|
|
2852
|
+
"Content-Type: text/plain\r\n"
|
|
2853
|
+
"Content-Length: 6\r\n"
|
|
2854
|
+
"\r\n"
|
|
2855
|
+
"fooba",
|
|
2856
|
+
HPE_OK);
|
|
1744
2857
|
|
|
1745
2858
|
static const char *all_methods[] = {
|
|
1746
2859
|
"DELETE",
|
|
@@ -1758,12 +2871,31 @@ main (int argc, char * argv[])
|
|
|
1758
2871
|
"PROPFIND",
|
|
1759
2872
|
"PROPPATCH",
|
|
1760
2873
|
"UNLOCK",
|
|
2874
|
+
"REPORT",
|
|
2875
|
+
"MKACTIVITY",
|
|
2876
|
+
"CHECKOUT",
|
|
2877
|
+
"MERGE",
|
|
2878
|
+
"M-SEARCH",
|
|
2879
|
+
"NOTIFY",
|
|
2880
|
+
"SUBSCRIBE",
|
|
2881
|
+
"UNSUBSCRIBE",
|
|
2882
|
+
"PATCH",
|
|
1761
2883
|
0 };
|
|
1762
2884
|
const char **this_method;
|
|
1763
2885
|
for (this_method = all_methods; *this_method; this_method++) {
|
|
1764
2886
|
char buf[200];
|
|
1765
2887
|
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
|
1766
|
-
test_simple(buf,
|
|
2888
|
+
test_simple(buf, HPE_OK);
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
static const char *bad_methods[] = {
|
|
2892
|
+
"C******",
|
|
2893
|
+
"M****",
|
|
2894
|
+
0 };
|
|
2895
|
+
for (this_method = bad_methods; *this_method; this_method++) {
|
|
2896
|
+
char buf[200];
|
|
2897
|
+
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
|
2898
|
+
test_simple(buf, HPE_UNKNOWN);
|
|
1767
2899
|
}
|
|
1768
2900
|
|
|
1769
2901
|
const char *dumbfuck2 =
|
|
@@ -1801,7 +2933,7 @@ main (int argc, char * argv[])
|
|
|
1801
2933
|
"\tRA==\r\n"
|
|
1802
2934
|
"\t-----END CERTIFICATE-----\r\n"
|
|
1803
2935
|
"\r\n";
|
|
1804
|
-
test_simple(dumbfuck2,
|
|
2936
|
+
test_simple(dumbfuck2, HPE_OK);
|
|
1805
2937
|
|
|
1806
2938
|
#if 0
|
|
1807
2939
|
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
|
|
@@ -1823,7 +2955,9 @@ main (int argc, char * argv[])
|
|
|
1823
2955
|
test_message(&requests[i]);
|
|
1824
2956
|
}
|
|
1825
2957
|
|
|
1826
|
-
|
|
2958
|
+
for (i = 0; i < request_count; i++) {
|
|
2959
|
+
test_message_pause(&requests[i]);
|
|
2960
|
+
}
|
|
1827
2961
|
|
|
1828
2962
|
for (i = 0; i < request_count; i++) {
|
|
1829
2963
|
if (!requests[i].should_keep_alive) continue;
|