http_parser.rb 0.5.3 → 0.6.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitmodules +3 -3
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +9 -2
  4. data/README.md +50 -45
  5. data/bench/standalone.rb +23 -0
  6. data/bench/thin.rb +1 -0
  7. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +66 -58
  8. data/ext/ruby_http_parser/ruby_http_parser.c +10 -41
  9. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  10. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
  11. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
  12. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1029 -615
  14. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +177 -43
  16. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +13 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +4 -1
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +2 -2
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +12 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +715 -637
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -1
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +71 -21
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  39. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1141 -210
  40. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  41. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
  42. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
  43. data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1029 -615
  45. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
  46. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +145 -16
  47. data/ext/ruby_http_parser/vendor/http-parser/test.c +1065 -141
  48. data/http_parser.rb.gemspec +3 -1
  49. data/spec/parser_spec.rb +41 -17
  50. data/spec/support/requests.json +236 -24
  51. data/spec/support/responses.json +182 -36
  52. data/tasks/compile.rake +2 -2
  53. data/tasks/fixtures.rake +7 -1
  54. metadata +57 -19
  55. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  56. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  57. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  58. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
@@ -41,6 +41,11 @@ public class Util {
41
41
  throw new RuntimeException("!");
42
42
  }
43
43
  }
44
+ static void check (int should, int is) {
45
+ if (should != is) {
46
+ throw new RuntimeException("should be: "+should+" is:"+is);
47
+ }
48
+ }
44
49
 
45
50
  static void test_message(Message mes) {
46
51
  int raw_len = mes.raw.length;
@@ -51,11 +56,11 @@ public class Util {
51
56
 
52
57
  HTTPParser parser = new HTTPParser(mes.type);
53
58
  ParserSettings settings = mes.settings();
54
-
59
+
55
60
  int read = 0;
56
61
  if (msg1len !=0) {
57
62
  read = parser.execute(settings, msg1);
58
- if (mes.upgrade && parser.upgrade) {
63
+ if (mes.upgrade() && parser.upgrade) {
59
64
  // Messages have a settings() that checks itself...
60
65
  check(1 == mes.num_called);
61
66
  continue;
@@ -64,17 +69,17 @@ public class Util {
64
69
  }
65
70
 
66
71
  read = parser.execute(settings, msg2);
67
- if (mes.upgrade && parser.upgrade) {
72
+ if (mes.upgrade() && parser.upgrade) {
68
73
  check(1 == mes.num_called);
69
74
  continue;
70
75
  }
71
76
 
72
- check(read == mes.raw.length - msg1len);
77
+ check( mes.raw.length - msg1len, read);
73
78
 
74
79
  ByteBuffer empty = Util.empty();
75
80
  read = parser.execute(settings, empty);
76
81
 
77
- if (mes.upgrade && parser.upgrade) {
82
+ if (mes.upgrade() && parser.upgrade) {
78
83
  check(1 == mes.num_called);
79
84
  continue;
80
85
  }
@@ -87,13 +92,13 @@ public class Util {
87
92
 
88
93
  static void test_multiple3(Message r1, Message r2, Message r3) {
89
94
  int message_count = 1;
90
- if (!r1.upgrade) {
95
+ if (!r1.upgrade()) {
91
96
  message_count++;
92
- if (!r2.upgrade) {
97
+ if (!r2.upgrade()) {
93
98
  message_count++;
94
99
  }
95
100
  }
96
- boolean has_upgrade = (message_count < 3 || r3.upgrade);
101
+ boolean has_upgrade = (message_count < 3 || r3.upgrade());
97
102
 
98
103
  ByteList blist = new ByteList();
99
104
  blist.addAll(r1.raw);
@@ -108,6 +113,7 @@ public class Util {
108
113
 
109
114
  int read = parser.execute(settings, buf);
110
115
  if (has_upgrade && parser.upgrade) {
116
+ raw = upgrade_message_fix(raw, read, r1,r2,r3);
111
117
  check(settings.numCalled == message_count);
112
118
  return;
113
119
  }
@@ -122,8 +128,73 @@ public class Util {
122
128
  }
123
129
 
124
130
  check(0 == read);
125
- check(settings.numCalled == message_count);
131
+ check(settings.numCalled == message_count);
126
132
  }
133
+
134
+ /* Given a sequence of bytes and the number of these that we were able to
135
+ * parse, verify that upgrade bodies are correct.
136
+ */
137
+ static byte [] upgrade_message_fix(byte[] body, int nread, Message... msgs) {
138
+ int off = 0;
139
+ for (Message m : msgs) {
140
+ off += m.raw.length;
141
+ if (m.upgrade()) {
142
+ off -= m.upgrade.length;
143
+ // Original C:
144
+ // Check the portion of the response after its specified upgrade
145
+ // if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
146
+ // abort();
147
+ // }
148
+ // to me, this seems to be equivalent to comparing off and nread ...
149
+ check (off, nread);
150
+
151
+ // Original C:
152
+ // Fix up the response so that message_eq() will verify the beginning
153
+ // of the upgrade */
154
+ //
155
+ // *(body + nread + strlen(m->upgrade)) = '\0';
156
+ // This only shortens body so the strlen check passes.
157
+ return new byte[off];
158
+
159
+ }
160
+ }
161
+ return null;
162
+ }
163
+ //upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
164
+ // va_list ap;
165
+ // size_t i;
166
+ // size_t off = 0;
167
+ //
168
+ // va_start(ap, nmsgs);
169
+ //
170
+ // for (i = 0; i < nmsgs; i++) {
171
+ // struct message *m = va_arg(ap, struct message *);
172
+ //
173
+ // off += strlen(m->raw);
174
+ //
175
+ // if (m->upgrade) {
176
+ // off -= strlen(m->upgrade);
177
+ //
178
+ // /* Check the portion of the response after its specified upgrade */
179
+ // if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
180
+ // abort();
181
+ // }
182
+ //
183
+ // /* Fix up the response so that message_eq() will verify the beginning
184
+ // * of the upgrade */
185
+ // *(body + nread + strlen(m->upgrade)) = '\0';
186
+ // messages[num_messages -1 ].upgrade = body + nread;
187
+ //
188
+ // va_end(ap);
189
+ // return;
190
+ // }
191
+ // }
192
+ //
193
+ // va_end(ap);
194
+ // printf("\n\n*** Error: expected a message with upgrade ***\n");
195
+ //
196
+ // abort();
197
+ //}
127
198
  static void p (Object o) {
128
199
  System.out.println(o);
129
200
  }
@@ -14,6 +14,7 @@ public class WrongContentLength {
14
14
  "hello" +
15
15
  "hello_again";
16
16
  static void test () {
17
+ p(WrongContentLength.class);
17
18
  HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST);
18
19
  ByteBuffer buf = buffer(contentLength);
19
20
 
@@ -43,7 +44,7 @@ public class WrongContentLength {
43
44
  this.on_body = new HTTPDataCallback() {
44
45
  public int cb (HTTPParser p, ByteBuffer b, int pos, int len) {
45
46
  bodyCount += len;
46
- p(str(b, pos, len));
47
+ check ("hello".equals(str(b, pos, len)));
47
48
  return 0;
48
49
  }
49
50
  };
@@ -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
- int upgrade;
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=1
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 home0.netscape.com:443 HTTP/1.0\r\n"
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= "home0.netscape.com:443"
518
+ ,.request_url= "0-home0.netscape.com:443"
514
519
  ,.num_headers= 2
515
- ,.upgrade=1
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
  }
@@ -582,28 +587,36 @@ const struct message requests[] =
582
587
  ,.body= ""
583
588
  }
584
589
 
585
- #define UTF8_PATH_REQ 21
586
- , {.name= "utf-8 path request"
590
+ #define LINE_FOLDING_IN_HEADER 20
591
+ , {.name= "line folding in header value"
587
592
  ,.type= HTTP_REQUEST
588
- ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
589
- "Host: github.com\r\n"
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"
590
601
  "\r\n"
591
602
  ,.should_keep_alive= TRUE
592
603
  ,.message_complete_on_eof= FALSE
593
604
  ,.http_major= 1
594
605
  ,.http_minor= 1
595
606
  ,.method= HTTP_GET
596
- ,.query_string= "q=1"
597
- ,.fragment= "narf"
598
- ,.request_path= "/δ¶/δt/pope"
599
- ,.request_url= "/δ¶/δt/pope?q=1#narf"
600
- ,.num_headers= 1
601
- ,.headers= { {"Host", "github.com" }
607
+ ,.query_string= ""
608
+ ,.fragment= ""
609
+ ,.request_path= "/"
610
+ ,.request_url= "/"
611
+ ,.num_headers= 2
612
+ ,.headers= { { "Line1", "abcdefghijklmno qrs" }
613
+ , { "Line2", "line2\t" }
602
614
  }
603
615
  ,.body= ""
604
616
  }
605
617
 
606
- #define QUERY_TERMINATED_HOST 22
618
+
619
+ #define QUERY_TERMINATED_HOST 21
607
620
  , {.name= "host terminated by a query string"
608
621
  ,.type= HTTP_REQUEST
609
622
  ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
@@ -622,7 +635,7 @@ const struct message requests[] =
622
635
  ,.body= ""
623
636
  }
624
637
 
625
- #define QUERY_TERMINATED_HOSTPORT 23
638
+ #define QUERY_TERMINATED_HOSTPORT 22
626
639
  , {.name= "host:port terminated by a query string"
627
640
  ,.type= HTTP_REQUEST
628
641
  ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
@@ -636,12 +649,13 @@ const struct message requests[] =
636
649
  ,.fragment= ""
637
650
  ,.request_path= ""
638
651
  ,.request_url= "http://hypnotoad.org:1234?hail=all"
652
+ ,.port= 1234
639
653
  ,.num_headers= 0
640
654
  ,.headers= { }
641
655
  ,.body= ""
642
656
  }
643
657
 
644
- #define SPACE_TERMINATED_HOSTPORT 24
658
+ #define SPACE_TERMINATED_HOSTPORT 23
645
659
  , {.name= "host:port terminated by a space"
646
660
  ,.type= HTTP_REQUEST
647
661
  ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
@@ -655,11 +669,187 @@ const struct message requests[] =
655
669
  ,.fragment= ""
656
670
  ,.request_path= ""
657
671
  ,.request_url= "http://hypnotoad.org:1234"
672
+ ,.port= 1234
658
673
  ,.num_headers= 0
659
674
  ,.headers= { }
660
675
  ,.body= ""
661
676
  }
662
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
+
663
853
  , {.name= NULL } /* sentinel */
664
854
  };
665
855
 
@@ -760,8 +950,8 @@ const struct message responses[] =
760
950
  , {.name= "404 no headers no body"
761
951
  ,.type= HTTP_RESPONSE
762
952
  ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
763
- ,.should_keep_alive= TRUE
764
- ,.message_complete_on_eof= FALSE
953
+ ,.should_keep_alive= FALSE
954
+ ,.message_complete_on_eof= TRUE
765
955
  ,.http_major= 1
766
956
  ,.http_minor= 1
767
957
  ,.status_code= 404
@@ -775,8 +965,8 @@ const struct message responses[] =
775
965
  , {.name= "301 no response phrase"
776
966
  ,.type= HTTP_RESPONSE
777
967
  ,.raw= "HTTP/1.1 301\r\n\r\n"
778
- ,.should_keep_alive = TRUE
779
- ,.message_complete_on_eof= FALSE
968
+ ,.should_keep_alive = FALSE
969
+ ,.message_complete_on_eof= TRUE
780
970
  ,.http_major= 1
781
971
  ,.http_minor= 1
782
972
  ,.status_code= 301
@@ -925,40 +1115,7 @@ const struct message responses[] =
925
1115
  ,.body= ""
926
1116
  }
927
1117
 
928
- #define SPACE_IN_FIELD_RES 9
929
- /* Should handle spaces in header fields */
930
- , {.name= "field space"
931
- ,.type= HTTP_RESPONSE
932
- ,.raw= "HTTP/1.1 200 OK\r\n"
933
- "Server: Microsoft-IIS/6.0\r\n"
934
- "X-Powered-By: ASP.NET\r\n"
935
- "en-US Content-Type: text/xml\r\n" /* this is the problem */
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"
940
- "\r\n"
941
- "<xml>hello</xml>" /* fake body */
942
- ,.should_keep_alive= TRUE
943
- ,.message_complete_on_eof= FALSE
944
- ,.http_major= 1
945
- ,.http_minor= 1
946
- ,.status_code= 200
947
- ,.num_headers= 7
948
- ,.headers=
949
- { { "Server", "Microsoft-IIS/6.0" }
950
- , { "X-Powered-By", "ASP.NET" }
951
- , { "en-US Content-Type", "text/xml" }
952
- , { "Content-Type", "text/xml" }
953
- , { "Content-Length", "16" }
954
- , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
955
- , { "Connection", "keep-alive" }
956
- }
957
- ,.body= "<xml>hello</xml>"
958
- }
959
-
960
-
961
- #define RES_FIELD_UNDERSCORE 10
1118
+ #define RES_FIELD_UNDERSCORE 9
962
1119
  /* Should handle spaces in header fields */
963
1120
  , {.name= "field underscore"
964
1121
  ,.type= HTTP_RESPONSE
@@ -998,7 +1155,7 @@ const struct message responses[] =
998
1155
  ,.body= ""
999
1156
  }
1000
1157
 
1001
- #define NON_ASCII_IN_STATUS_LINE 11
1158
+ #define NON_ASCII_IN_STATUS_LINE 10
1002
1159
  /* Should handle non-ASCII in status line */
1003
1160
  , {.name= "non-ASCII in status line"
1004
1161
  ,.type= HTTP_RESPONSE
@@ -1018,21 +1175,196 @@ const struct message responses[] =
1018
1175
  , { "Content-Length", "0" }
1019
1176
  , { "Connection", "close" }
1020
1177
  }
1021
- ,.body= ""
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
1333
+ /* Should handle spaces in header fields */
1334
+ , {.name= "field space"
1335
+ ,.type= HTTP_RESPONSE
1336
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1337
+ "Server: Microsoft-IIS/6.0\r\n"
1338
+ "X-Powered-By: ASP.NET\r\n"
1339
+ "en-US Content-Type: text/xml\r\n" /* this is the problem */
1340
+ "Content-Type: text/xml\r\n"
1341
+ "Content-Length: 16\r\n"
1342
+ "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
1343
+ "Connection: keep-alive\r\n"
1344
+ "\r\n"
1345
+ "<xml>hello</xml>" /* fake body */
1346
+ ,.should_keep_alive= TRUE
1347
+ ,.message_complete_on_eof= FALSE
1348
+ ,.http_major= 1
1349
+ ,.http_minor= 1
1350
+ ,.status_code= 200
1351
+ ,.num_headers= 7
1352
+ ,.headers=
1353
+ { { "Server", "Microsoft-IIS/6.0" }
1354
+ , { "X-Powered-By", "ASP.NET" }
1355
+ , { "en-US Content-Type", "text/xml" }
1356
+ , { "Content-Type", "text/xml" }
1357
+ , { "Content-Length", "16" }
1358
+ , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
1359
+ , { "Connection", "keep-alive" }
1360
+ }
1361
+ ,.body= "<xml>hello</xml>"
1022
1362
  }
1023
-
1363
+ #endif /* !HTTP_PARSER_STRICT */
1024
1364
 
1025
1365
  , {.name= NULL } /* sentinel */
1026
1366
  };
1027
1367
 
1028
- int
1029
- request_path_cb (http_parser *p, const char *buf, size_t len)
1030
- {
1031
- assert(p == parser);
1032
- strncat(messages[num_messages].request_path, buf, len);
1033
- return 0;
1034
- }
1035
-
1036
1368
  int
1037
1369
  request_url_cb (http_parser *p, const char *buf, size_t len)
1038
1370
  {
@@ -1041,22 +1373,6 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
1041
1373
  return 0;
1042
1374
  }
1043
1375
 
1044
- int
1045
- query_string_cb (http_parser *p, const char *buf, size_t len)
1046
- {
1047
- assert(p == parser);
1048
- strncat(messages[num_messages].query_string, buf, len);
1049
- return 0;
1050
- }
1051
-
1052
- int
1053
- fragment_cb (http_parser *p, const char *buf, size_t len)
1054
- {
1055
- assert(p == parser);
1056
- strncat(messages[num_messages].fragment, buf, len);
1057
- return 0;
1058
- }
1059
-
1060
1376
  int
1061
1377
  header_field_cb (http_parser *p, const char *buf, size_t len)
1062
1378
  {
@@ -1136,7 +1452,7 @@ message_complete_cb (http_parser *p)
1136
1452
  "value in both on_message_complete and on_headers_complete "
1137
1453
  "but it doesn't! ***\n\n");
1138
1454
  assert(0);
1139
- exit(1);
1455
+ abort();
1140
1456
  }
1141
1457
  messages[num_messages].message_complete_cb_called = TRUE;
1142
1458
 
@@ -1146,14 +1462,151 @@ message_complete_cb (http_parser *p)
1146
1462
  return 0;
1147
1463
  }
1148
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
+
1149
1605
  static http_parser_settings settings =
1150
1606
  {.on_message_begin = message_begin_cb
1151
1607
  ,.on_header_field = header_field_cb
1152
1608
  ,.on_header_value = header_value_cb
1153
- ,.on_path = request_path_cb
1154
1609
  ,.on_url = request_url_cb
1155
- ,.on_fragment = fragment_cb
1156
- ,.on_query_string = query_string_cb
1157
1610
  ,.on_body = body_cb
1158
1611
  ,.on_headers_complete = headers_complete_cb
1159
1612
  ,.on_message_complete = message_complete_cb
@@ -1163,10 +1616,7 @@ static http_parser_settings settings_count_body =
1163
1616
  {.on_message_begin = message_begin_cb
1164
1617
  ,.on_header_field = header_field_cb
1165
1618
  ,.on_header_value = header_value_cb
1166
- ,.on_path = request_path_cb
1167
1619
  ,.on_url = request_url_cb
1168
- ,.on_fragment = fragment_cb
1169
- ,.on_query_string = query_string_cb
1170
1620
  ,.on_body = count_body_cb
1171
1621
  ,.on_headers_complete = headers_complete_cb
1172
1622
  ,.on_message_complete = message_complete_cb
@@ -1176,10 +1626,7 @@ static http_parser_settings settings_null =
1176
1626
  {.on_message_begin = 0
1177
1627
  ,.on_header_field = 0
1178
1628
  ,.on_header_value = 0
1179
- ,.on_path = 0
1180
1629
  ,.on_url = 0
1181
- ,.on_fragment = 0
1182
- ,.on_query_string = 0
1183
1630
  ,.on_body = 0
1184
1631
  ,.on_headers_complete = 0
1185
1632
  ,.on_message_complete = 0
@@ -1224,12 +1671,29 @@ size_t parse_count_body (const char *buf, size_t len)
1224
1671
  return nparsed;
1225
1672
  }
1226
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
+
1227
1685
  static inline int
1228
1686
  check_str_eq (const struct message *m,
1229
1687
  const char *prop,
1230
1688
  const char *expected,
1231
1689
  const char *found) {
1232
- if (0 != strcmp(expected, found)) {
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)) {
1233
1697
  printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1234
1698
  printf("expected '%s'\n", expected);
1235
1699
  printf(" found '%s'\n", found);
@@ -1258,6 +1722,20 @@ check_num_eq (const struct message *m,
1258
1722
  #define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
1259
1723
  if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
1260
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)
1261
1739
 
1262
1740
  int
1263
1741
  message_eq (int index, const struct message *expected)
@@ -1282,10 +1760,29 @@ message_eq (int index, const struct message *expected)
1282
1760
  assert(m->message_complete_cb_called);
1283
1761
 
1284
1762
 
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
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
+
1289
1786
  if (expected->body_size) {
1290
1787
  MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
1291
1788
  } else {
@@ -1302,13 +1799,81 @@ message_eq (int index, const struct message *expected)
1302
1799
  if (!r) return 0;
1303
1800
  }
1304
1801
 
1802
+ MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
1803
+
1305
1804
  return 1;
1306
1805
  }
1307
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
+
1308
1871
  static void
1309
1872
  print_error (const char *raw, size_t error_location)
1310
1873
  {
1311
- fprintf(stderr, "\n*** parse error ***\n\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)));
1312
1877
 
1313
1878
  int this_line = 0, char_len = 0;
1314
1879
  size_t i, j, len = strlen(raw), error_location_line = 0;
@@ -1346,6 +1911,218 @@ print_error (const char *raw, size_t error_location)
1346
1911
  fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
1347
1912
  }
1348
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
+ }
1349
2126
 
1350
2127
  void
1351
2128
  test_message (const struct message *message)
@@ -1363,41 +2140,45 @@ test_message (const struct message *message)
1363
2140
  if (msg1len) {
1364
2141
  read = parse(msg1, msg1len);
1365
2142
 
1366
- if (message->upgrade && parser->upgrade) goto test;
2143
+ if (message->upgrade && parser->upgrade) {
2144
+ messages[num_messages - 1].upgrade = msg1 + read;
2145
+ goto test;
2146
+ }
1367
2147
 
1368
2148
  if (read != msg1len) {
1369
2149
  print_error(msg1, read);
1370
- exit(1);
2150
+ abort();
1371
2151
  }
1372
2152
  }
1373
2153
 
1374
2154
 
1375
2155
  read = parse(msg2, msg2len);
1376
2156
 
1377
- if (message->upgrade && parser->upgrade) goto test;
2157
+ if (message->upgrade && parser->upgrade) {
2158
+ messages[num_messages - 1].upgrade = msg2 + read;
2159
+ goto test;
2160
+ }
1378
2161
 
1379
2162
  if (read != msg2len) {
1380
2163
  print_error(msg2, read);
1381
- exit(1);
2164
+ abort();
1382
2165
  }
1383
2166
 
1384
2167
  read = parse(NULL, 0);
1385
2168
 
1386
- if (message->upgrade && parser->upgrade) goto test;
1387
-
1388
2169
  if (read != 0) {
1389
2170
  print_error(message->raw, read);
1390
- exit(1);
2171
+ abort();
1391
2172
  }
1392
2173
 
1393
2174
  test:
1394
2175
 
1395
2176
  if (num_messages != 1) {
1396
2177
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
1397
- exit(1);
2178
+ abort();
1398
2179
  }
1399
2180
 
1400
- if(!message_eq(0, message)) exit(1);
2181
+ if(!message_eq(0, message)) abort();
1401
2182
 
1402
2183
  parser_free();
1403
2184
  }
@@ -1418,7 +2199,7 @@ test_message_count_body (const struct message *message)
1418
2199
  read = parse_count_body(message->raw + i, toread);
1419
2200
  if (read != toread) {
1420
2201
  print_error(message->raw, read);
1421
- exit(1);
2202
+ abort();
1422
2203
  }
1423
2204
  }
1424
2205
 
@@ -1426,36 +2207,47 @@ test_message_count_body (const struct message *message)
1426
2207
  read = parse_count_body(NULL, 0);
1427
2208
  if (read != 0) {
1428
2209
  print_error(message->raw, read);
1429
- exit(1);
2210
+ abort();
1430
2211
  }
1431
2212
 
1432
2213
  if (num_messages != 1) {
1433
2214
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
1434
- exit(1);
2215
+ abort();
1435
2216
  }
1436
2217
 
1437
- if(!message_eq(0, message)) exit(1);
2218
+ if(!message_eq(0, message)) abort();
1438
2219
 
1439
2220
  parser_free();
1440
2221
  }
1441
2222
 
1442
2223
  void
1443
- test_simple (const char *buf, int should_pass)
2224
+ test_simple (const char *buf, enum http_errno err_expected)
1444
2225
  {
1445
2226
  parser_init(HTTP_REQUEST);
1446
2227
 
1447
2228
  size_t parsed;
1448
2229
  int pass;
2230
+ enum http_errno err;
2231
+
1449
2232
  parsed = parse(buf, strlen(buf));
1450
2233
  pass = (parsed == strlen(buf));
2234
+ err = HTTP_PARSER_ERRNO(parser);
1451
2235
  parsed = parse(NULL, 0);
1452
2236
  pass &= (parsed == 0);
1453
2237
 
1454
2238
  parser_free();
1455
2239
 
1456
- if (pass != should_pass) {
1457
- fprintf(stderr, "\n*** test_simple expected %s ***\n\n%s", should_pass ? "success" : "error", buf);
1458
- exit(1);
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();
1459
2251
  }
1460
2252
  }
1461
2253
 
@@ -1471,16 +2263,67 @@ test_header_overflow_error (int req)
1471
2263
  assert(parsed == strlen(buf));
1472
2264
 
1473
2265
  buf = "header-key: header-value\r\n";
2266
+ size_t buflen = strlen(buf);
2267
+
1474
2268
  int i;
1475
2269
  for (i = 0; i < 10000; i++) {
1476
- if (http_parser_execute(&parser, &settings_null, buf, strlen(buf)) != strlen(buf)) {
2270
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
2271
+ if (parsed != buflen) {
1477
2272
  //fprintf(stderr, "error found on iter %d\n", i);
2273
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
1478
2274
  return;
1479
2275
  }
1480
2276
  }
1481
2277
 
1482
2278
  fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
1483
- exit(1);
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 */
1484
2327
  }
1485
2328
 
1486
2329
  void
@@ -1513,18 +2356,13 @@ test_no_overflow_long_body (int req, size_t length)
1513
2356
  "\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
1514
2357
  req ? "REQUEST" : "RESPONSE",
1515
2358
  length);
1516
- exit(1);
2359
+ abort();
1517
2360
  }
1518
2361
 
1519
2362
  void
1520
2363
  test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
1521
2364
  {
1522
- int message_count = 1;
1523
- if (!r1->upgrade) {
1524
- message_count++;
1525
- if (!r2->upgrade) message_count++;
1526
- }
1527
- int has_upgrade = (message_count < 3 || r3->upgrade);
2365
+ int message_count = count_parsed_messages(3, r1, r2, r3);
1528
2366
 
1529
2367
  char total[ strlen(r1->raw)
1530
2368
  + strlen(r2->raw)
@@ -1543,36 +2381,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
1543
2381
 
1544
2382
  read = parse(total, strlen(total));
1545
2383
 
1546
- if (has_upgrade && parser->upgrade) goto test;
2384
+ if (parser->upgrade) {
2385
+ upgrade_message_fix(total, read, 3, r1, r2, r3);
2386
+ goto test;
2387
+ }
1547
2388
 
1548
2389
  if (read != strlen(total)) {
1549
2390
  print_error(total, read);
1550
- exit(1);
2391
+ abort();
1551
2392
  }
1552
2393
 
1553
2394
  read = parse(NULL, 0);
1554
2395
 
1555
- if (has_upgrade && parser->upgrade) goto test;
1556
-
1557
2396
  if (read != 0) {
1558
2397
  print_error(total, read);
1559
- exit(1);
2398
+ abort();
1560
2399
  }
1561
2400
 
1562
2401
  test:
1563
2402
 
1564
2403
  if (message_count != num_messages) {
1565
2404
  fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
1566
- exit(1);
2405
+ abort();
1567
2406
  }
1568
2407
 
1569
- if (!message_eq(0, r1)) exit(1);
1570
- if (message_count > 1) {
1571
- if (!message_eq(1, r2)) exit(1);
1572
- if (message_count > 2) {
1573
- if (!message_eq(2, r3)) exit(1);
1574
- }
1575
- }
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();
1576
2411
 
1577
2412
  parser_free();
1578
2413
  }
@@ -1601,6 +2436,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1601
2436
  int ops = 0 ;
1602
2437
 
1603
2438
  size_t buf1_len, buf2_len, buf3_len;
2439
+ int message_count = count_parsed_messages(3, r1, r2, r3);
1604
2440
 
1605
2441
  int i,j,type_both;
1606
2442
  for (type_both = 0; type_both < 2; type_both ++ ) {
@@ -1629,27 +2465,27 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1629
2465
 
1630
2466
  read = parse(buf1, buf1_len);
1631
2467
 
1632
- if (r3->upgrade && parser->upgrade) goto test;
2468
+ if (parser->upgrade) goto test;
1633
2469
 
1634
2470
  if (read != buf1_len) {
1635
2471
  print_error(buf1, read);
1636
2472
  goto error;
1637
2473
  }
1638
2474
 
1639
- read = parse(buf2, buf2_len);
2475
+ read += parse(buf2, buf2_len);
1640
2476
 
1641
- if (r3->upgrade && parser->upgrade) goto test;
2477
+ if (parser->upgrade) goto test;
1642
2478
 
1643
- if (read != buf2_len) {
2479
+ if (read != buf1_len + buf2_len) {
1644
2480
  print_error(buf2, read);
1645
2481
  goto error;
1646
2482
  }
1647
2483
 
1648
- read = parse(buf3, buf3_len);
2484
+ read += parse(buf3, buf3_len);
1649
2485
 
1650
- if (r3->upgrade && parser->upgrade) goto test;
2486
+ if (parser->upgrade) goto test;
1651
2487
 
1652
- if (read != buf3_len) {
2488
+ if (read != buf1_len + buf2_len + buf3_len) {
1653
2489
  print_error(buf3, read);
1654
2490
  goto error;
1655
2491
  }
@@ -1657,9 +2493,13 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1657
2493
  parse(NULL, 0);
1658
2494
 
1659
2495
  test:
2496
+ if (parser->upgrade) {
2497
+ upgrade_message_fix(total, read, 3, r1, r2, r3);
2498
+ }
1660
2499
 
1661
- if (3 != num_messages) {
1662
- fprintf(stderr, "\n\nParser didn't see 3 messages only %d\n", num_messages);
2500
+ if (message_count != num_messages) {
2501
+ fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
2502
+ message_count, num_messages);
1663
2503
  goto error;
1664
2504
  }
1665
2505
 
@@ -1668,12 +2508,12 @@ test:
1668
2508
  goto error;
1669
2509
  }
1670
2510
 
1671
- if (!message_eq(1, r2)) {
2511
+ if (message_count > 1 && !message_eq(1, r2)) {
1672
2512
  fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
1673
2513
  goto error;
1674
2514
  }
1675
2515
 
1676
- if (!message_eq(2, r3)) {
2516
+ if (message_count > 2 && !message_eq(2, r3)) {
1677
2517
  fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
1678
2518
  goto error;
1679
2519
  }
@@ -1690,7 +2530,7 @@ test:
1690
2530
  fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
1691
2531
  fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
1692
2532
  fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
1693
- exit(1);
2533
+ abort();
1694
2534
  }
1695
2535
 
1696
2536
  // user required to free the result
@@ -1724,49 +2564,50 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
1724
2564
  return buf;
1725
2565
  }
1726
2566
 
1727
- char *
2567
+ char *
1728
2568
  quote(const char * orig) {
1729
- size_t j, i, len = strlen(orig);
1730
- char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
1731
- bzero(quoted, len == 0 ? 1 : len*2);
1732
- for (i=0, j=0; i!=len; ++i) {
1733
- switch (orig[i]){
1734
- case '\n':
1735
- quoted[j++] = '\\';
1736
- quoted[j++] = 'n';
1737
- break;
1738
- case '\r':
1739
- quoted[j++] = '\\';
1740
- quoted[j++] = 'r';
1741
- break;
1742
- case '"':
1743
- quoted[j++] = '\\';
1744
- quoted[j++] = '"';
1745
- break;
1746
- default :
1747
- quoted[j++] = orig[i];
1748
- }
1749
- }
1750
- return quoted;
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;
1751
2592
  }
1752
2593
 
1753
- void
2594
+ void
1754
2595
  dump_message(const struct message * m)
1755
2596
  {
1756
- int i;
1757
- printf("name :%s\n", m->name);
1758
- char * bla = quote(m->raw);
1759
- printf("raw :\"%s\"\n", bla);
1760
- free(bla);
1761
- switch (m->type){
1762
- case HTTP_REQUEST:
1763
- printf("type :HTTP_REQUEST\n");break;
1764
- case HTTP_RESPONSE:
1765
- printf("type :HTTP_RESPONSE\n"); break;
1766
- case HTTP_BOTH:
1767
- printf("type :HTTP_BOTH\n");
1768
- }
1769
- switch (m->method) {
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) {
1770
2611
  case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
1771
2612
  case HTTP_GET: printf("method: HTTP_GET\n");break;
1772
2613
  case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
@@ -1792,38 +2633,42 @@ dump_message(const struct message * m)
1792
2633
  case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
1793
2634
  case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
1794
2635
  case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
1795
- default:
2636
+ default:
1796
2637
  printf("method: UNKNOWN\n"); break;
1797
- break;
1798
- }
1799
- printf("status_code :%d\n", m->status_code);
2638
+ break;
2639
+ }
2640
+ printf("status_code :%d\n", m->status_code);
1800
2641
  printf("request_path:%s\n", m->request_path);
1801
2642
  printf("request_url :%s\n", m->request_url);
1802
2643
  printf("fragment :%s\n", m->fragment);
1803
2644
  printf("query_string:%s\n", m->query_string);
1804
2645
 
1805
- bla = quote(m->body);
2646
+ bla = quote(m->body);
1806
2647
  printf("body :\"%s\"\n", bla);
1807
- free(bla);
2648
+ free(bla);
1808
2649
  printf("body_size :%zu\n", m->body_size);
1809
2650
 
1810
- for (i=0; i!=m->num_headers; ++i){
1811
- printf("header_%d :{ \"%s\": \"%s\"}\n", i, m->headers[i][0], m->headers[i][1]);
1812
- }
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
+ }
1813
2654
 
1814
2655
  printf("should_keep_alive :%d\n", m->should_keep_alive);
1815
- printf("upgrade :%d\n", m->upgrade);
2656
+ bla = quote(m->upgrade);
2657
+ if (bla) {
2658
+ printf("upgrade :\"%s\"\n", bla);
2659
+ }
2660
+ free(bla);
1816
2661
  printf("http_major :%d\n", m->http_major);
1817
2662
  printf("http_minor :%d\n", m->http_minor);
1818
2663
  // printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
1819
2664
  // printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
1820
2665
  // printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
1821
2666
  // printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
1822
- printf("\n");
2667
+ printf("\n");
1823
2668
  }
1824
2669
 
1825
- void
1826
- dump_messages(void)
2670
+ void
2671
+ dump_messages(void)
1827
2672
  {
1828
2673
  int request_count;
1829
2674
  for (request_count = 0; requests[request_count].name; request_count++){
@@ -1834,6 +2679,60 @@ dump_messages(void)
1834
2679
  }
1835
2680
  }
1836
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
+
1837
2736
  int
1838
2737
  main (int argc, char * argv[])
1839
2738
  {
@@ -1854,6 +2753,10 @@ main (int argc, char * argv[])
1854
2753
  for (request_count = 0; requests[request_count].name; request_count++);
1855
2754
  for (response_count = 0; responses[response_count].name; response_count++);
1856
2755
 
2756
+ //// API
2757
+ test_preserve_data();
2758
+ test_parse_url();
2759
+
1857
2760
  //// OVERFLOW CONDITIONS
1858
2761
 
1859
2762
  test_header_overflow_error(HTTP_REQUEST);
@@ -1864,12 +2767,19 @@ main (int argc, char * argv[])
1864
2767
  test_no_overflow_long_body(HTTP_RESPONSE, 1000);
1865
2768
  test_no_overflow_long_body(HTTP_RESPONSE, 100000);
1866
2769
 
2770
+ test_header_content_length_overflow_error();
2771
+ test_chunk_content_length_overflow_error();
2772
+
1867
2773
  //// RESPONSES
1868
2774
 
1869
2775
  for (i = 0; i < response_count; i++) {
1870
2776
  test_message(&responses[i]);
1871
2777
  }
1872
2778
 
2779
+ for (i = 0; i < response_count; i++) {
2780
+ test_message_pause(&responses[i]);
2781
+ }
2782
+
1873
2783
  for (i = 0; i < response_count; i++) {
1874
2784
  if (!responses[i].should_keep_alive) continue;
1875
2785
  for (j = 0; j < response_count; j++) {
@@ -1914,7 +2824,7 @@ main (int argc, char * argv[])
1914
2824
 
1915
2825
  printf("response scan 1/2 ");
1916
2826
  test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
1917
- , &responses[NO_HEADERS_NO_BODY_404]
2827
+ , &responses[NO_BODY_HTTP10_KA_204]
1918
2828
  , &responses[NO_REASON_PHRASE]
1919
2829
  );
1920
2830
 
@@ -1929,13 +2839,13 @@ main (int argc, char * argv[])
1929
2839
 
1930
2840
  /// REQUESTS
1931
2841
 
1932
- test_simple("hello world", 0);
1933
- test_simple("GET / HTP/1.1\r\n\r\n", 0);
2842
+ test_simple("hello world", HPE_INVALID_METHOD);
2843
+ test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
1934
2844
 
1935
2845
 
1936
- test_simple("ASDF / HTTP/1.1\r\n\r\n", 0);
1937
- test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", 0);
1938
- test_simple("GETA / HTTP/1.1\r\n\r\n", 0);
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);
1939
2849
 
1940
2850
  // Well-formed but incomplete
1941
2851
  test_simple("GET / HTTP/1.1\r\n"
@@ -1943,7 +2853,7 @@ main (int argc, char * argv[])
1943
2853
  "Content-Length: 6\r\n"
1944
2854
  "\r\n"
1945
2855
  "fooba",
1946
- 0);
2856
+ HPE_OK);
1947
2857
 
1948
2858
  static const char *all_methods[] = {
1949
2859
  "DELETE",
@@ -1961,12 +2871,31 @@ main (int argc, char * argv[])
1961
2871
  "PROPFIND",
1962
2872
  "PROPPATCH",
1963
2873
  "UNLOCK",
2874
+ "REPORT",
2875
+ "MKACTIVITY",
2876
+ "CHECKOUT",
2877
+ "MERGE",
2878
+ "M-SEARCH",
2879
+ "NOTIFY",
2880
+ "SUBSCRIBE",
2881
+ "UNSUBSCRIBE",
2882
+ "PATCH",
1964
2883
  0 };
1965
2884
  const char **this_method;
1966
2885
  for (this_method = all_methods; *this_method; this_method++) {
1967
2886
  char buf[200];
1968
2887
  sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
1969
- test_simple(buf, 1);
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);
1970
2899
  }
1971
2900
 
1972
2901
  const char *dumbfuck2 =
@@ -2004,7 +2933,7 @@ main (int argc, char * argv[])
2004
2933
  "\tRA==\r\n"
2005
2934
  "\t-----END CERTIFICATE-----\r\n"
2006
2935
  "\r\n";
2007
- test_simple(dumbfuck2, 0);
2936
+ test_simple(dumbfuck2, HPE_OK);
2008
2937
 
2009
2938
  #if 0
2010
2939
  // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
@@ -2026,7 +2955,9 @@ main (int argc, char * argv[])
2026
2955
  test_message(&requests[i]);
2027
2956
  }
2028
2957
 
2029
-
2958
+ for (i = 0; i < request_count; i++) {
2959
+ test_message_pause(&requests[i]);
2960
+ }
2030
2961
 
2031
2962
  for (i = 0; i < request_count; i++) {
2032
2963
  if (!requests[i].should_keep_alive) continue;