http_parser.rb 0.5.3 → 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.
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;