http_parser.rb 0.5.3-java → 0.6.0.beta.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitmodules +3 -3
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +14 -5
  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 +120 -85
  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 +1202 -671
  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 +172 -51
  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/HTTPMethod.java +8 -3
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  37. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
  38. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  39. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
  40. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
  41. data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
  42. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1029 -615
  43. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +145 -16
  45. data/ext/ruby_http_parser/vendor/http-parser/test.c +1065 -141
  46. data/http_parser.rb.gemspec +3 -1
  47. data/spec/parser_spec.rb +41 -17
  48. data/spec/support/requests.json +236 -24
  49. data/spec/support/responses.json +182 -36
  50. data/tasks/compile.rake +2 -2
  51. data/tasks/fixtures.rake +7 -1
  52. metadata +213 -162
  53. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  54. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  55. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  56. 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
  };
@@ -32,7 +32,7 @@
32
32
  #define FALSE 0
33
33
 
34
34
  #define MAX_HEADERS 13
35
- #define MAX_ELEMENT_SIZE 500
35
+ #define MAX_ELEMENT_SIZE 2048
36
36
 
37
37
  #define MIN(a,b) ((a) < (b) ? (a) : (b))
38
38
 
@@ -50,12 +50,15 @@ struct message {
50
50
  char query_string[MAX_ELEMENT_SIZE];
51
51
  char body[MAX_ELEMENT_SIZE];
52
52
  size_t body_size;
53
+ const char *host;
54
+ const char *userinfo;
55
+ uint16_t port;
53
56
  int num_headers;
54
57
  enum { NONE=0, FIELD, VALUE } last_header_element;
55
58
  char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
56
59
  int should_keep_alive;
57
60
 
58
- int upgrade;
61
+ const char *upgrade; // upgraded body
59
62
 
60
63
  unsigned short http_major;
61
64
  unsigned short http_minor;
@@ -64,12 +67,14 @@ struct message {
64
67
  int headers_complete_cb_called;
65
68
  int message_complete_cb_called;
66
69
  int message_complete_on_eof;
70
+ int body_is_final;
67
71
  };
68
72
 
69
73
  static int currently_parsing_eof;
70
74
 
71
75
  static struct message messages[5];
72
76
  static int num_messages;
77
+ static http_parser_settings *current_pause_parser;
73
78
 
74
79
  /* * R E Q U E S T S * */
75
80
  const struct message requests[] =
@@ -473,6 +478,7 @@ const struct message requests[] =
473
478
  "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
474
479
  "Origin: http://example.com\r\n"
475
480
  "\r\n"
481
+ "Hot diggity dogg"
476
482
  ,.should_keep_alive= TRUE
477
483
  ,.message_complete_on_eof= FALSE
478
484
  ,.http_major= 1
@@ -483,7 +489,7 @@ const struct message requests[] =
483
489
  ,.request_path= "/demo"
484
490
  ,.request_url= "/demo"
485
491
  ,.num_headers= 7
486
- ,.upgrade=1
492
+ ,.upgrade="Hot diggity dogg"
487
493
  ,.headers= { { "Host", "example.com" }
488
494
  , { "Connection", "Upgrade" }
489
495
  , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
@@ -498,10 +504,12 @@ const struct message requests[] =
498
504
  #define CONNECT_REQUEST 17
499
505
  , {.name = "connect request"
500
506
  ,.type= HTTP_REQUEST
501
- ,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
507
+ ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
502
508
  "User-agent: Mozilla/1.1N\r\n"
503
509
  "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
504
510
  "\r\n"
511
+ "some data\r\n"
512
+ "and yet even more data"
505
513
  ,.should_keep_alive= FALSE
506
514
  ,.message_complete_on_eof= FALSE
507
515
  ,.http_major= 1
@@ -510,9 +518,9 @@ const struct message requests[] =
510
518
  ,.query_string= ""
511
519
  ,.fragment= ""
512
520
  ,.request_path= ""
513
- ,.request_url= "home0.netscape.com:443"
521
+ ,.request_url= "0-home0.netscape.com:443"
514
522
  ,.num_headers= 2
515
- ,.upgrade=1
523
+ ,.upgrade="some data\r\nand yet even more data"
516
524
  ,.headers= { { "User-agent", "Mozilla/1.1N" }
517
525
  , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
518
526
  }
@@ -582,27 +590,35 @@ const struct message requests[] =
582
590
  ,.body= ""
583
591
  }
584
592
 
585
- #define UTF8_PATH_REQ 21
586
- , {.name= "utf-8 path request"
593
+ #define LINE_FOLDING_IN_HEADER 21
594
+ , {.name= "line folding in header value"
587
595
  ,.type= HTTP_REQUEST
588
- ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
589
- "Host: github.com\r\n"
596
+ ,.raw= "GET / HTTP/1.1\r\n"
597
+ "Line1: abc\r\n"
598
+ "\tdef\r\n"
599
+ " ghi\r\n"
600
+ "\t\tjkl\r\n"
601
+ " mno \r\n"
602
+ "\t \tqrs\r\n"
603
+ "Line2: \t line2\t\r\n"
590
604
  "\r\n"
591
605
  ,.should_keep_alive= TRUE
592
606
  ,.message_complete_on_eof= FALSE
593
607
  ,.http_major= 1
594
608
  ,.http_minor= 1
595
609
  ,.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" }
610
+ ,.query_string= ""
611
+ ,.fragment= ""
612
+ ,.request_path= "/"
613
+ ,.request_url= "/"
614
+ ,.num_headers= 2
615
+ ,.headers= { { "Line1", "abcdefghijklmno qrs" }
616
+ , { "Line2", "line2\t" }
602
617
  }
603
618
  ,.body= ""
604
619
  }
605
620
 
621
+
606
622
  #define QUERY_TERMINATED_HOST 22
607
623
  , {.name= "host terminated by a query string"
608
624
  ,.type= HTTP_REQUEST
@@ -617,6 +633,7 @@ const struct message requests[] =
617
633
  ,.fragment= ""
618
634
  ,.request_path= ""
619
635
  ,.request_url= "http://hypnotoad.org?hail=all"
636
+ ,.host= "hypnotoad.org"
620
637
  ,.num_headers= 0
621
638
  ,.headers= { }
622
639
  ,.body= ""
@@ -636,6 +653,8 @@ const struct message requests[] =
636
653
  ,.fragment= ""
637
654
  ,.request_path= ""
638
655
  ,.request_url= "http://hypnotoad.org:1234?hail=all"
656
+ ,.host= "hypnotoad.org"
657
+ ,.port= 1234
639
658
  ,.num_headers= 0
640
659
  ,.headers= { }
641
660
  ,.body= ""
@@ -655,11 +674,230 @@ const struct message requests[] =
655
674
  ,.fragment= ""
656
675
  ,.request_path= ""
657
676
  ,.request_url= "http://hypnotoad.org:1234"
677
+ ,.host= "hypnotoad.org"
678
+ ,.port= 1234
679
+ ,.num_headers= 0
680
+ ,.headers= { }
681
+ ,.body= ""
682
+ }
683
+
684
+ #define PATCH_REQ 25
685
+ , {.name = "PATCH request"
686
+ ,.type= HTTP_REQUEST
687
+ ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
688
+ "Host: www.example.com\r\n"
689
+ "Content-Type: application/example\r\n"
690
+ "If-Match: \"e0023aa4e\"\r\n"
691
+ "Content-Length: 10\r\n"
692
+ "\r\n"
693
+ "cccccccccc"
694
+ ,.should_keep_alive= TRUE
695
+ ,.message_complete_on_eof= FALSE
696
+ ,.http_major= 1
697
+ ,.http_minor= 1
698
+ ,.method= HTTP_PATCH
699
+ ,.query_string= ""
700
+ ,.fragment= ""
701
+ ,.request_path= "/file.txt"
702
+ ,.request_url= "/file.txt"
703
+ ,.num_headers= 4
704
+ ,.headers= { { "Host", "www.example.com" }
705
+ , { "Content-Type", "application/example" }
706
+ , { "If-Match", "\"e0023aa4e\"" }
707
+ , { "Content-Length", "10" }
708
+ }
709
+ ,.body= "cccccccccc"
710
+ }
711
+
712
+ #define CONNECT_CAPS_REQUEST 26
713
+ , {.name = "connect caps request"
714
+ ,.type= HTTP_REQUEST
715
+ ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
716
+ "User-agent: Mozilla/1.1N\r\n"
717
+ "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
718
+ "\r\n"
719
+ ,.should_keep_alive= FALSE
720
+ ,.message_complete_on_eof= FALSE
721
+ ,.http_major= 1
722
+ ,.http_minor= 0
723
+ ,.method= HTTP_CONNECT
724
+ ,.query_string= ""
725
+ ,.fragment= ""
726
+ ,.request_path= ""
727
+ ,.request_url= "HOME0.NETSCAPE.COM:443"
728
+ ,.num_headers= 2
729
+ ,.upgrade=""
730
+ ,.headers= { { "User-agent", "Mozilla/1.1N" }
731
+ , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
732
+ }
733
+ ,.body= ""
734
+ }
735
+
736
+ #if !HTTP_PARSER_STRICT
737
+ #define UTF8_PATH_REQ 27
738
+ , {.name= "utf-8 path request"
739
+ ,.type= HTTP_REQUEST
740
+ ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
741
+ "Host: github.com\r\n"
742
+ "\r\n"
743
+ ,.should_keep_alive= TRUE
744
+ ,.message_complete_on_eof= FALSE
745
+ ,.http_major= 1
746
+ ,.http_minor= 1
747
+ ,.method= HTTP_GET
748
+ ,.query_string= "q=1"
749
+ ,.fragment= "narf"
750
+ ,.request_path= "/δ¶/δt/pope"
751
+ ,.request_url= "/δ¶/δt/pope?q=1#narf"
752
+ ,.num_headers= 1
753
+ ,.headers= { {"Host", "github.com" }
754
+ }
755
+ ,.body= ""
756
+ }
757
+
758
+ #define HOSTNAME_UNDERSCORE 28
759
+ , {.name = "hostname underscore"
760
+ ,.type= HTTP_REQUEST
761
+ ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
762
+ "User-agent: Mozilla/1.1N\r\n"
763
+ "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
764
+ "\r\n"
765
+ ,.should_keep_alive= FALSE
766
+ ,.message_complete_on_eof= FALSE
767
+ ,.http_major= 1
768
+ ,.http_minor= 0
769
+ ,.method= HTTP_CONNECT
770
+ ,.query_string= ""
771
+ ,.fragment= ""
772
+ ,.request_path= ""
773
+ ,.request_url= "home_0.netscape.com:443"
774
+ ,.num_headers= 2
775
+ ,.upgrade=""
776
+ ,.headers= { { "User-agent", "Mozilla/1.1N" }
777
+ , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
778
+ }
779
+ ,.body= ""
780
+ }
781
+ #endif /* !HTTP_PARSER_STRICT */
782
+
783
+ /* see https://github.com/ry/http-parser/issues/47 */
784
+ #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
785
+ , {.name = "eat CRLF between requests, no \"Connection: close\" header"
786
+ ,.raw= "POST / HTTP/1.1\r\n"
787
+ "Host: www.example.com\r\n"
788
+ "Content-Type: application/x-www-form-urlencoded\r\n"
789
+ "Content-Length: 4\r\n"
790
+ "\r\n"
791
+ "q=42\r\n" /* note the trailing CRLF */
792
+ ,.should_keep_alive= TRUE
793
+ ,.message_complete_on_eof= FALSE
794
+ ,.http_major= 1
795
+ ,.http_minor= 1
796
+ ,.method= HTTP_POST
797
+ ,.query_string= ""
798
+ ,.fragment= ""
799
+ ,.request_path= "/"
800
+ ,.request_url= "/"
801
+ ,.num_headers= 3
802
+ ,.upgrade= 0
803
+ ,.headers= { { "Host", "www.example.com" }
804
+ , { "Content-Type", "application/x-www-form-urlencoded" }
805
+ , { "Content-Length", "4" }
806
+ }
807
+ ,.body= "q=42"
808
+ }
809
+
810
+ /* see https://github.com/ry/http-parser/issues/47 */
811
+ #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
812
+ , {.name = "eat CRLF between requests even if \"Connection: close\" is set"
813
+ ,.raw= "POST / HTTP/1.1\r\n"
814
+ "Host: www.example.com\r\n"
815
+ "Content-Type: application/x-www-form-urlencoded\r\n"
816
+ "Content-Length: 4\r\n"
817
+ "Connection: close\r\n"
818
+ "\r\n"
819
+ "q=42\r\n" /* note the trailing CRLF */
820
+ ,.should_keep_alive= FALSE
821
+ ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
822
+ ,.http_major= 1
823
+ ,.http_minor= 1
824
+ ,.method= HTTP_POST
825
+ ,.query_string= ""
826
+ ,.fragment= ""
827
+ ,.request_path= "/"
828
+ ,.request_url= "/"
829
+ ,.num_headers= 4
830
+ ,.upgrade= 0
831
+ ,.headers= { { "Host", "www.example.com" }
832
+ , { "Content-Type", "application/x-www-form-urlencoded" }
833
+ , { "Content-Length", "4" }
834
+ , { "Connection", "close" }
835
+ }
836
+ ,.body= "q=42"
837
+ }
838
+
839
+ #define PURGE_REQ 31
840
+ , {.name = "PURGE request"
841
+ ,.type= HTTP_REQUEST
842
+ ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
843
+ "Host: www.example.com\r\n"
844
+ "\r\n"
845
+ ,.should_keep_alive= TRUE
846
+ ,.message_complete_on_eof= FALSE
847
+ ,.http_major= 1
848
+ ,.http_minor= 1
849
+ ,.method= HTTP_PURGE
850
+ ,.query_string= ""
851
+ ,.fragment= ""
852
+ ,.request_path= "/file.txt"
853
+ ,.request_url= "/file.txt"
854
+ ,.num_headers= 1
855
+ ,.headers= { { "Host", "www.example.com" } }
856
+ ,.body= ""
857
+ }
858
+
859
+ #define SEARCH_REQ 32
860
+ , {.name = "SEARCH request"
861
+ ,.type= HTTP_REQUEST
862
+ ,.raw= "SEARCH / HTTP/1.1\r\n"
863
+ "Host: www.example.com\r\n"
864
+ "\r\n"
865
+ ,.should_keep_alive= TRUE
866
+ ,.message_complete_on_eof= FALSE
867
+ ,.http_major= 1
868
+ ,.http_minor= 1
869
+ ,.method= HTTP_SEARCH
870
+ ,.query_string= ""
871
+ ,.fragment= ""
872
+ ,.request_path= "/"
873
+ ,.request_url= "/"
874
+ ,.num_headers= 1
875
+ ,.headers= { { "Host", "www.example.com" } }
876
+ ,.body= ""
877
+ }
878
+
879
+ #define PROXY_WITH_BASIC_AUTH 33
880
+ , {.name= "host:port and basic_auth"
881
+ ,.type= HTTP_REQUEST
882
+ ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
883
+ "\r\n"
884
+ ,.should_keep_alive= TRUE
885
+ ,.message_complete_on_eof= FALSE
886
+ ,.http_major= 1
887
+ ,.http_minor= 1
888
+ ,.method= HTTP_GET
889
+ ,.fragment= ""
890
+ ,.request_path= "/toto"
891
+ ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
892
+ ,.host= "hypnotoad.org"
893
+ ,.userinfo= "a%12:b!&*$"
894
+ ,.port= 1234
658
895
  ,.num_headers= 0
659
896
  ,.headers= { }
660
897
  ,.body= ""
661
898
  }
662
899
 
900
+
663
901
  , {.name= NULL } /* sentinel */
664
902
  };
665
903
 
@@ -760,8 +998,8 @@ const struct message responses[] =
760
998
  , {.name= "404 no headers no body"
761
999
  ,.type= HTTP_RESPONSE
762
1000
  ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
763
- ,.should_keep_alive= TRUE
764
- ,.message_complete_on_eof= FALSE
1001
+ ,.should_keep_alive= FALSE
1002
+ ,.message_complete_on_eof= TRUE
765
1003
  ,.http_major= 1
766
1004
  ,.http_minor= 1
767
1005
  ,.status_code= 404
@@ -775,8 +1013,8 @@ const struct message responses[] =
775
1013
  , {.name= "301 no response phrase"
776
1014
  ,.type= HTTP_RESPONSE
777
1015
  ,.raw= "HTTP/1.1 301\r\n\r\n"
778
- ,.should_keep_alive = TRUE
779
- ,.message_complete_on_eof= FALSE
1016
+ ,.should_keep_alive = FALSE
1017
+ ,.message_complete_on_eof= TRUE
780
1018
  ,.http_major= 1
781
1019
  ,.http_minor= 1
782
1020
  ,.status_code= 301
@@ -925,40 +1163,7 @@ const struct message responses[] =
925
1163
  ,.body= ""
926
1164
  }
927
1165
 
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
1166
+ #define RES_FIELD_UNDERSCORE 9
962
1167
  /* Should handle spaces in header fields */
963
1168
  , {.name= "field underscore"
964
1169
  ,.type= HTTP_RESPONSE
@@ -998,7 +1203,7 @@ const struct message responses[] =
998
1203
  ,.body= ""
999
1204
  }
1000
1205
 
1001
- #define NON_ASCII_IN_STATUS_LINE 11
1206
+ #define NON_ASCII_IN_STATUS_LINE 10
1002
1207
  /* Should handle non-ASCII in status line */
1003
1208
  , {.name= "non-ASCII in status line"
1004
1209
  ,.type= HTTP_RESPONSE
@@ -1021,39 +1226,275 @@ const struct message responses[] =
1021
1226
  ,.body= ""
1022
1227
  }
1023
1228
 
1229
+ #define HTTP_VERSION_0_9 11
1230
+ /* Should handle HTTP/0.9 */
1231
+ , {.name= "http version 0.9"
1232
+ ,.type= HTTP_RESPONSE
1233
+ ,.raw= "HTTP/0.9 200 OK\r\n"
1234
+ "\r\n"
1235
+ ,.should_keep_alive= FALSE
1236
+ ,.message_complete_on_eof= TRUE
1237
+ ,.http_major= 0
1238
+ ,.http_minor= 9
1239
+ ,.status_code= 200
1240
+ ,.num_headers= 0
1241
+ ,.headers=
1242
+ {}
1243
+ ,.body= ""
1244
+ }
1245
+
1246
+ #define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
1247
+ /* The client should wait for the server's EOF. That is, when neither
1248
+ * content-length nor transfer-encoding is specified, the end of body
1249
+ * is specified by the EOF.
1250
+ */
1251
+ , {.name= "neither content-length nor transfer-encoding response"
1252
+ ,.type= HTTP_RESPONSE
1253
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1254
+ "Content-Type: text/plain\r\n"
1255
+ "\r\n"
1256
+ "hello world"
1257
+ ,.should_keep_alive= FALSE
1258
+ ,.message_complete_on_eof= TRUE
1259
+ ,.http_major= 1
1260
+ ,.http_minor= 1
1261
+ ,.status_code= 200
1262
+ ,.num_headers= 1
1263
+ ,.headers=
1264
+ { { "Content-Type", "text/plain" }
1265
+ }
1266
+ ,.body= "hello world"
1267
+ }
1268
+
1269
+ #define NO_BODY_HTTP10_KA_200 13
1270
+ , {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
1271
+ ,.type= HTTP_RESPONSE
1272
+ ,.raw= "HTTP/1.0 200 OK\r\n"
1273
+ "Connection: keep-alive\r\n"
1274
+ "\r\n"
1275
+ ,.should_keep_alive= FALSE
1276
+ ,.message_complete_on_eof= TRUE
1277
+ ,.http_major= 1
1278
+ ,.http_minor= 0
1279
+ ,.status_code= 200
1280
+ ,.num_headers= 1
1281
+ ,.headers=
1282
+ { { "Connection", "keep-alive" }
1283
+ }
1284
+ ,.body_size= 0
1285
+ ,.body= ""
1286
+ }
1287
+
1288
+ #define NO_BODY_HTTP10_KA_204 14
1289
+ , {.name= "HTTP/1.0 with keep-alive and a 204 status"
1290
+ ,.type= HTTP_RESPONSE
1291
+ ,.raw= "HTTP/1.0 204 No content\r\n"
1292
+ "Connection: keep-alive\r\n"
1293
+ "\r\n"
1294
+ ,.should_keep_alive= TRUE
1295
+ ,.message_complete_on_eof= FALSE
1296
+ ,.http_major= 1
1297
+ ,.http_minor= 0
1298
+ ,.status_code= 204
1299
+ ,.num_headers= 1
1300
+ ,.headers=
1301
+ { { "Connection", "keep-alive" }
1302
+ }
1303
+ ,.body_size= 0
1304
+ ,.body= ""
1305
+ }
1306
+
1307
+ #define NO_BODY_HTTP11_KA_200 15
1308
+ , {.name= "HTTP/1.1 with an EOF-terminated 200 status"
1309
+ ,.type= HTTP_RESPONSE
1310
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1311
+ "\r\n"
1312
+ ,.should_keep_alive= FALSE
1313
+ ,.message_complete_on_eof= TRUE
1314
+ ,.http_major= 1
1315
+ ,.http_minor= 1
1316
+ ,.status_code= 200
1317
+ ,.num_headers= 0
1318
+ ,.headers={}
1319
+ ,.body_size= 0
1320
+ ,.body= ""
1321
+ }
1322
+
1323
+ #define NO_BODY_HTTP11_KA_204 16
1324
+ , {.name= "HTTP/1.1 with a 204 status"
1325
+ ,.type= HTTP_RESPONSE
1326
+ ,.raw= "HTTP/1.1 204 No content\r\n"
1327
+ "\r\n"
1328
+ ,.should_keep_alive= TRUE
1329
+ ,.message_complete_on_eof= FALSE
1330
+ ,.http_major= 1
1331
+ ,.http_minor= 1
1332
+ ,.status_code= 204
1333
+ ,.num_headers= 0
1334
+ ,.headers={}
1335
+ ,.body_size= 0
1336
+ ,.body= ""
1337
+ }
1338
+
1339
+ #define NO_BODY_HTTP11_NOKA_204 17
1340
+ , {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
1341
+ ,.type= HTTP_RESPONSE
1342
+ ,.raw= "HTTP/1.1 204 No content\r\n"
1343
+ "Connection: close\r\n"
1344
+ "\r\n"
1345
+ ,.should_keep_alive= FALSE
1346
+ ,.message_complete_on_eof= FALSE
1347
+ ,.http_major= 1
1348
+ ,.http_minor= 1
1349
+ ,.status_code= 204
1350
+ ,.num_headers= 1
1351
+ ,.headers=
1352
+ { { "Connection", "close" }
1353
+ }
1354
+ ,.body_size= 0
1355
+ ,.body= ""
1356
+ }
1357
+
1358
+ #define NO_BODY_HTTP11_KA_CHUNKED_200 18
1359
+ , {.name= "HTTP/1.1 with chunked endocing and a 200 response"
1360
+ ,.type= HTTP_RESPONSE
1361
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1362
+ "Transfer-Encoding: chunked\r\n"
1363
+ "\r\n"
1364
+ "0\r\n"
1365
+ "\r\n"
1366
+ ,.should_keep_alive= TRUE
1367
+ ,.message_complete_on_eof= FALSE
1368
+ ,.http_major= 1
1369
+ ,.http_minor= 1
1370
+ ,.status_code= 200
1371
+ ,.num_headers= 1
1372
+ ,.headers=
1373
+ { { "Transfer-Encoding", "chunked" }
1374
+ }
1375
+ ,.body_size= 0
1376
+ ,.body= ""
1377
+ }
1378
+
1379
+ #if !HTTP_PARSER_STRICT
1380
+ #define SPACE_IN_FIELD_RES 19
1381
+ /* Should handle spaces in header fields */
1382
+ , {.name= "field space"
1383
+ ,.type= HTTP_RESPONSE
1384
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1385
+ "Server: Microsoft-IIS/6.0\r\n"
1386
+ "X-Powered-By: ASP.NET\r\n"
1387
+ "en-US Content-Type: text/xml\r\n" /* this is the problem */
1388
+ "Content-Type: text/xml\r\n"
1389
+ "Content-Length: 16\r\n"
1390
+ "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
1391
+ "Connection: keep-alive\r\n"
1392
+ "\r\n"
1393
+ "<xml>hello</xml>" /* fake body */
1394
+ ,.should_keep_alive= TRUE
1395
+ ,.message_complete_on_eof= FALSE
1396
+ ,.http_major= 1
1397
+ ,.http_minor= 1
1398
+ ,.status_code= 200
1399
+ ,.num_headers= 7
1400
+ ,.headers=
1401
+ { { "Server", "Microsoft-IIS/6.0" }
1402
+ , { "X-Powered-By", "ASP.NET" }
1403
+ , { "en-US Content-Type", "text/xml" }
1404
+ , { "Content-Type", "text/xml" }
1405
+ , { "Content-Length", "16" }
1406
+ , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
1407
+ , { "Connection", "keep-alive" }
1408
+ }
1409
+ ,.body= "<xml>hello</xml>"
1410
+ }
1411
+ #endif /* !HTTP_PARSER_STRICT */
1024
1412
 
1025
1413
  , {.name= NULL } /* sentinel */
1026
1414
  };
1027
1415
 
1028
- int
1029
- request_path_cb (http_parser *p, const char *buf, size_t len)
1416
+ /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
1417
+ * define it ourselves.
1418
+ */
1419
+ size_t
1420
+ strnlen(const char *s, size_t maxlen)
1030
1421
  {
1031
- assert(p == parser);
1032
- strncat(messages[num_messages].request_path, buf, len);
1033
- return 0;
1422
+ const char *p;
1423
+
1424
+ p = memchr(s, '\0', maxlen);
1425
+ if (p == NULL)
1426
+ return maxlen;
1427
+
1428
+ return p - s;
1034
1429
  }
1035
1430
 
1036
- int
1037
- request_url_cb (http_parser *p, const char *buf, size_t len)
1431
+ size_t
1432
+ strlncat(char *dst, size_t len, const char *src, size_t n)
1038
1433
  {
1039
- assert(p == parser);
1040
- strncat(messages[num_messages].request_url, buf, len);
1041
- return 0;
1434
+ size_t slen;
1435
+ size_t dlen;
1436
+ size_t rlen;
1437
+ size_t ncpy;
1438
+
1439
+ slen = strnlen(src, n);
1440
+ dlen = strnlen(dst, len);
1441
+
1442
+ if (dlen < len) {
1443
+ rlen = len - dlen;
1444
+ ncpy = slen < rlen ? slen : (rlen - 1);
1445
+ memcpy(dst + dlen, src, ncpy);
1446
+ dst[dlen + ncpy] = '\0';
1447
+ }
1448
+
1449
+ assert(len > slen + dlen);
1450
+ return slen + dlen;
1451
+ }
1452
+
1453
+ size_t
1454
+ strlcat(char *dst, const char *src, size_t len)
1455
+ {
1456
+ return strlncat(dst, len, src, (size_t) -1);
1457
+ }
1458
+
1459
+ size_t
1460
+ strlncpy(char *dst, size_t len, const char *src, size_t n)
1461
+ {
1462
+ size_t slen;
1463
+ size_t ncpy;
1464
+
1465
+ slen = strnlen(src, n);
1466
+
1467
+ if (len > 0) {
1468
+ ncpy = slen < len ? slen : (len - 1);
1469
+ memcpy(dst, src, ncpy);
1470
+ dst[ncpy] = '\0';
1471
+ }
1472
+
1473
+ assert(len > slen);
1474
+ return slen;
1475
+ }
1476
+
1477
+ size_t
1478
+ strlcpy(char *dst, const char *src, size_t len)
1479
+ {
1480
+ return strlncpy(dst, len, src, (size_t) -1);
1042
1481
  }
1043
1482
 
1044
1483
  int
1045
- query_string_cb (http_parser *p, const char *buf, size_t len)
1484
+ request_url_cb (http_parser *p, const char *buf, size_t len)
1046
1485
  {
1047
1486
  assert(p == parser);
1048
- strncat(messages[num_messages].query_string, buf, len);
1487
+ strlncat(messages[num_messages].request_url,
1488
+ sizeof(messages[num_messages].request_url),
1489
+ buf,
1490
+ len);
1049
1491
  return 0;
1050
1492
  }
1051
1493
 
1052
1494
  int
1053
- fragment_cb (http_parser *p, const char *buf, size_t len)
1054
- {
1495
+ status_complete_cb (http_parser *p) {
1055
1496
  assert(p == parser);
1056
- strncat(messages[num_messages].fragment, buf, len);
1497
+ p->data++;
1057
1498
  return 0;
1058
1499
  }
1059
1500
 
@@ -1066,7 +1507,10 @@ header_field_cb (http_parser *p, const char *buf, size_t len)
1066
1507
  if (m->last_header_element != FIELD)
1067
1508
  m->num_headers++;
1068
1509
 
1069
- strncat(m->headers[m->num_headers-1][0], buf, len);
1510
+ strlncat(m->headers[m->num_headers-1][0],
1511
+ sizeof(m->headers[m->num_headers-1][0]),
1512
+ buf,
1513
+ len);
1070
1514
 
1071
1515
  m->last_header_element = FIELD;
1072
1516
 
@@ -1079,19 +1523,39 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
1079
1523
  assert(p == parser);
1080
1524
  struct message *m = &messages[num_messages];
1081
1525
 
1082
- strncat(m->headers[m->num_headers-1][1], buf, len);
1526
+ strlncat(m->headers[m->num_headers-1][1],
1527
+ sizeof(m->headers[m->num_headers-1][1]),
1528
+ buf,
1529
+ len);
1083
1530
 
1084
1531
  m->last_header_element = VALUE;
1085
1532
 
1086
1533
  return 0;
1087
1534
  }
1088
1535
 
1536
+ void
1537
+ check_body_is_final (const http_parser *p)
1538
+ {
1539
+ if (messages[num_messages].body_is_final) {
1540
+ fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1541
+ "on last on_body callback call "
1542
+ "but it doesn't! ***\n\n");
1543
+ assert(0);
1544
+ abort();
1545
+ }
1546
+ messages[num_messages].body_is_final = http_body_is_final(p);
1547
+ }
1548
+
1089
1549
  int
1090
1550
  body_cb (http_parser *p, const char *buf, size_t len)
1091
1551
  {
1092
1552
  assert(p == parser);
1093
- strncat(messages[num_messages].body, buf, len);
1553
+ strlncat(messages[num_messages].body,
1554
+ sizeof(messages[num_messages].body),
1555
+ buf,
1556
+ len);
1094
1557
  messages[num_messages].body_size += len;
1558
+ check_body_is_final(p);
1095
1559
  // printf("body_cb: '%s'\n", requests[num_messages].body);
1096
1560
  return 0;
1097
1561
  }
@@ -1102,6 +1566,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
1102
1566
  assert(p == parser);
1103
1567
  assert(buf);
1104
1568
  messages[num_messages].body_size += len;
1569
+ check_body_is_final(p);
1105
1570
  return 0;
1106
1571
  }
1107
1572
 
@@ -1127,33 +1592,182 @@ headers_complete_cb (http_parser *p)
1127
1592
  }
1128
1593
 
1129
1594
  int
1130
- message_complete_cb (http_parser *p)
1595
+ message_complete_cb (http_parser *p)
1596
+ {
1597
+ assert(p == parser);
1598
+ if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
1599
+ {
1600
+ fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
1601
+ "value in both on_message_complete and on_headers_complete "
1602
+ "but it doesn't! ***\n\n");
1603
+ assert(0);
1604
+ abort();
1605
+ }
1606
+
1607
+ if (messages[num_messages].body_size &&
1608
+ http_body_is_final(p) &&
1609
+ !messages[num_messages].body_is_final)
1610
+ {
1611
+ fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
1612
+ "on last on_body callback call "
1613
+ "but it doesn't! ***\n\n");
1614
+ assert(0);
1615
+ abort();
1616
+ }
1617
+
1618
+ messages[num_messages].message_complete_cb_called = TRUE;
1619
+
1620
+ messages[num_messages].message_complete_on_eof = currently_parsing_eof;
1621
+
1622
+ num_messages++;
1623
+ return 0;
1624
+ }
1625
+
1626
+ /* These dontcall_* callbacks exist so that we can verify that when we're
1627
+ * paused, no additional callbacks are invoked */
1628
+ int
1629
+ dontcall_message_begin_cb (http_parser *p)
1630
+ {
1631
+ if (p) { } // gcc
1632
+ fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
1633
+ abort();
1634
+ }
1635
+
1636
+ int
1637
+ dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
1638
+ {
1639
+ if (p || buf || len) { } // gcc
1640
+ fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
1641
+ abort();
1642
+ }
1643
+
1644
+ int
1645
+ dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
1646
+ {
1647
+ if (p || buf || len) { } // gcc
1648
+ fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
1649
+ abort();
1650
+ }
1651
+
1652
+ int
1653
+ dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
1654
+ {
1655
+ if (p || buf || len) { } // gcc
1656
+ fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
1657
+ abort();
1658
+ }
1659
+
1660
+ int
1661
+ dontcall_body_cb (http_parser *p, const char *buf, size_t len)
1662
+ {
1663
+ if (p || buf || len) { } // gcc
1664
+ fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
1665
+ abort();
1666
+ }
1667
+
1668
+ int
1669
+ dontcall_headers_complete_cb (http_parser *p)
1670
+ {
1671
+ if (p) { } // gcc
1672
+ fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
1673
+ "parser ***\n\n");
1674
+ abort();
1675
+ }
1676
+
1677
+ int
1678
+ dontcall_message_complete_cb (http_parser *p)
1679
+ {
1680
+ if (p) { } // gcc
1681
+ fprintf(stderr, "\n\n*** on_message_complete() called on paused "
1682
+ "parser ***\n\n");
1683
+ abort();
1684
+ }
1685
+
1686
+ static http_parser_settings settings_dontcall =
1687
+ {.on_message_begin = dontcall_message_begin_cb
1688
+ ,.on_header_field = dontcall_header_field_cb
1689
+ ,.on_header_value = dontcall_header_value_cb
1690
+ ,.on_url = dontcall_request_url_cb
1691
+ ,.on_body = dontcall_body_cb
1692
+ ,.on_headers_complete = dontcall_headers_complete_cb
1693
+ ,.on_message_complete = dontcall_message_complete_cb
1694
+ };
1695
+
1696
+ /* These pause_* callbacks always pause the parser and just invoke the regular
1697
+ * callback that tracks content. Before returning, we overwrite the parser
1698
+ * settings to point to the _dontcall variety so that we can verify that
1699
+ * the pause actually did, you know, pause. */
1700
+ int
1701
+ pause_message_begin_cb (http_parser *p)
1702
+ {
1703
+ http_parser_pause(p, 1);
1704
+ *current_pause_parser = settings_dontcall;
1705
+ return message_begin_cb(p);
1706
+ }
1707
+
1708
+ int
1709
+ pause_header_field_cb (http_parser *p, const char *buf, size_t len)
1710
+ {
1711
+ http_parser_pause(p, 1);
1712
+ *current_pause_parser = settings_dontcall;
1713
+ return header_field_cb(p, buf, len);
1714
+ }
1715
+
1716
+ int
1717
+ pause_header_value_cb (http_parser *p, const char *buf, size_t len)
1718
+ {
1719
+ http_parser_pause(p, 1);
1720
+ *current_pause_parser = settings_dontcall;
1721
+ return header_value_cb(p, buf, len);
1722
+ }
1723
+
1724
+ int
1725
+ pause_request_url_cb (http_parser *p, const char *buf, size_t len)
1726
+ {
1727
+ http_parser_pause(p, 1);
1728
+ *current_pause_parser = settings_dontcall;
1729
+ return request_url_cb(p, buf, len);
1730
+ }
1731
+
1732
+ int
1733
+ pause_body_cb (http_parser *p, const char *buf, size_t len)
1131
1734
  {
1132
- assert(p == parser);
1133
- if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
1134
- {
1135
- fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
1136
- "value in both on_message_complete and on_headers_complete "
1137
- "but it doesn't! ***\n\n");
1138
- assert(0);
1139
- exit(1);
1140
- }
1141
- messages[num_messages].message_complete_cb_called = TRUE;
1735
+ http_parser_pause(p, 1);
1736
+ *current_pause_parser = settings_dontcall;
1737
+ return body_cb(p, buf, len);
1738
+ }
1142
1739
 
1143
- messages[num_messages].message_complete_on_eof = currently_parsing_eof;
1740
+ int
1741
+ pause_headers_complete_cb (http_parser *p)
1742
+ {
1743
+ http_parser_pause(p, 1);
1744
+ *current_pause_parser = settings_dontcall;
1745
+ return headers_complete_cb(p);
1746
+ }
1144
1747
 
1145
- num_messages++;
1146
- return 0;
1748
+ int
1749
+ pause_message_complete_cb (http_parser *p)
1750
+ {
1751
+ http_parser_pause(p, 1);
1752
+ *current_pause_parser = settings_dontcall;
1753
+ return message_complete_cb(p);
1147
1754
  }
1148
1755
 
1756
+ static http_parser_settings settings_pause =
1757
+ {.on_message_begin = pause_message_begin_cb
1758
+ ,.on_header_field = pause_header_field_cb
1759
+ ,.on_header_value = pause_header_value_cb
1760
+ ,.on_url = pause_request_url_cb
1761
+ ,.on_body = pause_body_cb
1762
+ ,.on_headers_complete = pause_headers_complete_cb
1763
+ ,.on_message_complete = pause_message_complete_cb
1764
+ };
1765
+
1149
1766
  static http_parser_settings settings =
1150
1767
  {.on_message_begin = message_begin_cb
1151
1768
  ,.on_header_field = header_field_cb
1152
1769
  ,.on_header_value = header_value_cb
1153
- ,.on_path = request_path_cb
1154
1770
  ,.on_url = request_url_cb
1155
- ,.on_fragment = fragment_cb
1156
- ,.on_query_string = query_string_cb
1157
1771
  ,.on_body = body_cb
1158
1772
  ,.on_headers_complete = headers_complete_cb
1159
1773
  ,.on_message_complete = message_complete_cb
@@ -1163,10 +1777,7 @@ static http_parser_settings settings_count_body =
1163
1777
  {.on_message_begin = message_begin_cb
1164
1778
  ,.on_header_field = header_field_cb
1165
1779
  ,.on_header_value = header_value_cb
1166
- ,.on_path = request_path_cb
1167
1780
  ,.on_url = request_url_cb
1168
- ,.on_fragment = fragment_cb
1169
- ,.on_query_string = query_string_cb
1170
1781
  ,.on_body = count_body_cb
1171
1782
  ,.on_headers_complete = headers_complete_cb
1172
1783
  ,.on_message_complete = message_complete_cb
@@ -1176,10 +1787,7 @@ static http_parser_settings settings_null =
1176
1787
  {.on_message_begin = 0
1177
1788
  ,.on_header_field = 0
1178
1789
  ,.on_header_value = 0
1179
- ,.on_path = 0
1180
1790
  ,.on_url = 0
1181
- ,.on_fragment = 0
1182
- ,.on_query_string = 0
1183
1791
  ,.on_body = 0
1184
1792
  ,.on_headers_complete = 0
1185
1793
  ,.on_message_complete = 0
@@ -1224,12 +1832,29 @@ size_t parse_count_body (const char *buf, size_t len)
1224
1832
  return nparsed;
1225
1833
  }
1226
1834
 
1835
+ size_t parse_pause (const char *buf, size_t len)
1836
+ {
1837
+ size_t nparsed;
1838
+ http_parser_settings s = settings_pause;
1839
+
1840
+ currently_parsing_eof = (len == 0);
1841
+ current_pause_parser = &s;
1842
+ nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
1843
+ return nparsed;
1844
+ }
1845
+
1227
1846
  static inline int
1228
1847
  check_str_eq (const struct message *m,
1229
1848
  const char *prop,
1230
1849
  const char *expected,
1231
1850
  const char *found) {
1232
- if (0 != strcmp(expected, found)) {
1851
+ if ((expected == NULL) != (found == NULL)) {
1852
+ printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1853
+ printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
1854
+ printf(" found %s\n", (found == NULL) ? "NULL" : found);
1855
+ return 0;
1856
+ }
1857
+ if (expected != NULL && 0 != strcmp(expected, found)) {
1233
1858
  printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1234
1859
  printf("expected '%s'\n", expected);
1235
1860
  printf(" found '%s'\n", found);
@@ -1258,6 +1883,20 @@ check_num_eq (const struct message *m,
1258
1883
  #define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
1259
1884
  if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
1260
1885
 
1886
+ #define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
1887
+ do { \
1888
+ char ubuf[256]; \
1889
+ \
1890
+ if ((u)->field_set & (1 << (fn))) { \
1891
+ memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
1892
+ (u)->field_data[(fn)].len); \
1893
+ ubuf[(u)->field_data[(fn)].len] = '\0'; \
1894
+ } else { \
1895
+ ubuf[0] = '\0'; \
1896
+ } \
1897
+ \
1898
+ check_str_eq(expected, #prop, expected->prop, ubuf); \
1899
+ } while(0)
1261
1900
 
1262
1901
  int
1263
1902
  message_eq (int index, const struct message *expected)
@@ -1282,10 +1921,37 @@ message_eq (int index, const struct message *expected)
1282
1921
  assert(m->message_complete_cb_called);
1283
1922
 
1284
1923
 
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
1924
  MESSAGE_CHECK_STR_EQ(expected, m, request_url);
1925
+
1926
+ /* Check URL components; we can't do this w/ CONNECT since it doesn't
1927
+ * send us a well-formed URL.
1928
+ */
1929
+ if (*m->request_url && m->method != HTTP_CONNECT) {
1930
+ struct http_parser_url u;
1931
+
1932
+ if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
1933
+ fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
1934
+ m->request_url);
1935
+ abort();
1936
+ }
1937
+
1938
+ if (expected->host) {
1939
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
1940
+ }
1941
+
1942
+ if (expected->userinfo) {
1943
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
1944
+ }
1945
+
1946
+ m->port = (u.field_set & (1 << UF_PORT)) ?
1947
+ u.port : 0;
1948
+
1949
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
1950
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
1951
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
1952
+ MESSAGE_CHECK_NUM_EQ(expected, m, port);
1953
+ }
1954
+
1289
1955
  if (expected->body_size) {
1290
1956
  MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
1291
1957
  } else {
@@ -1302,13 +1968,80 @@ message_eq (int index, const struct message *expected)
1302
1968
  if (!r) return 0;
1303
1969
  }
1304
1970
 
1971
+ MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
1972
+
1305
1973
  return 1;
1306
1974
  }
1307
1975
 
1976
+ /* Given a sequence of varargs messages, return the number of them that the
1977
+ * parser should successfully parse, taking into account that upgraded
1978
+ * messages prevent all subsequent messages from being parsed.
1979
+ */
1980
+ size_t
1981
+ count_parsed_messages(const size_t nmsgs, ...) {
1982
+ size_t i;
1983
+ va_list ap;
1984
+
1985
+ va_start(ap, nmsgs);
1986
+
1987
+ for (i = 0; i < nmsgs; i++) {
1988
+ struct message *m = va_arg(ap, struct message *);
1989
+
1990
+ if (m->upgrade) {
1991
+ va_end(ap);
1992
+ return i + 1;
1993
+ }
1994
+ }
1995
+
1996
+ va_end(ap);
1997
+ return nmsgs;
1998
+ }
1999
+
2000
+ /* Given a sequence of bytes and the number of these that we were able to
2001
+ * parse, verify that upgrade bodies are correct.
2002
+ */
2003
+ void
2004
+ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
2005
+ va_list ap;
2006
+ size_t i;
2007
+ size_t off = 0;
2008
+
2009
+ va_start(ap, nmsgs);
2010
+
2011
+ for (i = 0; i < nmsgs; i++) {
2012
+ struct message *m = va_arg(ap, struct message *);
2013
+
2014
+ off += strlen(m->raw);
2015
+
2016
+ if (m->upgrade) {
2017
+ off -= strlen(m->upgrade);
2018
+
2019
+ /* Check the portion of the response after its specified upgrade */
2020
+ if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
2021
+ abort();
2022
+ }
2023
+
2024
+ /* Fix up the response so that message_eq() will verify the beginning
2025
+ * of the upgrade */
2026
+ *(body + nread + strlen(m->upgrade)) = '\0';
2027
+ messages[num_messages -1 ].upgrade = body + nread;
2028
+
2029
+ va_end(ap);
2030
+ return;
2031
+ }
2032
+ }
2033
+
2034
+ va_end(ap);
2035
+ printf("\n\n*** Error: expected a message with upgrade ***\n");
2036
+
2037
+ abort();
2038
+ }
2039
+
1308
2040
  static void
1309
2041
  print_error (const char *raw, size_t error_location)
1310
2042
  {
1311
- fprintf(stderr, "\n*** parse error ***\n\n");
2043
+ fprintf(stderr, "\n*** %s ***\n\n",
2044
+ http_errno_description(HTTP_PARSER_ERRNO(parser)));
1312
2045
 
1313
2046
  int this_line = 0, char_len = 0;
1314
2047
  size_t i, j, len = strlen(raw), error_location_line = 0;
@@ -1346,6 +2079,582 @@ print_error (const char *raw, size_t error_location)
1346
2079
  fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
1347
2080
  }
1348
2081
 
2082
+ void
2083
+ test_preserve_data (void)
2084
+ {
2085
+ char my_data[] = "application-specific data";
2086
+ http_parser parser;
2087
+ parser.data = my_data;
2088
+ http_parser_init(&parser, HTTP_REQUEST);
2089
+ if (parser.data != my_data) {
2090
+ printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
2091
+ abort();
2092
+ }
2093
+ }
2094
+
2095
+ struct url_test {
2096
+ const char *name;
2097
+ const char *url;
2098
+ int is_connect;
2099
+ struct http_parser_url u;
2100
+ int rv;
2101
+ };
2102
+
2103
+ const struct url_test url_tests[] =
2104
+ { {.name="proxy request"
2105
+ ,.url="http://hostname/"
2106
+ ,.is_connect=0
2107
+ ,.u=
2108
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2109
+ ,.port=0
2110
+ ,.field_data=
2111
+ {{ 0, 4 } /* UF_SCHEMA */
2112
+ ,{ 7, 8 } /* UF_HOST */
2113
+ ,{ 0, 0 } /* UF_PORT */
2114
+ ,{ 15, 1 } /* UF_PATH */
2115
+ ,{ 0, 0 } /* UF_QUERY */
2116
+ ,{ 0, 0 } /* UF_FRAGMENT */
2117
+ ,{ 0, 0 } /* UF_USERINFO */
2118
+ }
2119
+ }
2120
+ ,.rv=0
2121
+ }
2122
+
2123
+ , {.name="proxy request with port"
2124
+ ,.url="http://hostname:444/"
2125
+ ,.is_connect=0
2126
+ ,.u=
2127
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2128
+ ,.port=444
2129
+ ,.field_data=
2130
+ {{ 0, 4 } /* UF_SCHEMA */
2131
+ ,{ 7, 8 } /* UF_HOST */
2132
+ ,{ 16, 3 } /* UF_PORT */
2133
+ ,{ 19, 1 } /* UF_PATH */
2134
+ ,{ 0, 0 } /* UF_QUERY */
2135
+ ,{ 0, 0 } /* UF_FRAGMENT */
2136
+ ,{ 0, 0 } /* UF_USERINFO */
2137
+ }
2138
+ }
2139
+ ,.rv=0
2140
+ }
2141
+
2142
+ , {.name="CONNECT request"
2143
+ ,.url="hostname:443"
2144
+ ,.is_connect=1
2145
+ ,.u=
2146
+ {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2147
+ ,.port=443
2148
+ ,.field_data=
2149
+ {{ 0, 0 } /* UF_SCHEMA */
2150
+ ,{ 0, 8 } /* UF_HOST */
2151
+ ,{ 9, 3 } /* UF_PORT */
2152
+ ,{ 0, 0 } /* UF_PATH */
2153
+ ,{ 0, 0 } /* UF_QUERY */
2154
+ ,{ 0, 0 } /* UF_FRAGMENT */
2155
+ ,{ 0, 0 } /* UF_USERINFO */
2156
+ }
2157
+ }
2158
+ ,.rv=0
2159
+ }
2160
+
2161
+ , {.name="CONNECT request but not connect"
2162
+ ,.url="hostname:443"
2163
+ ,.is_connect=0
2164
+ ,.rv=1
2165
+ }
2166
+
2167
+ , {.name="proxy ipv6 request"
2168
+ ,.url="http://[1:2::3:4]/"
2169
+ ,.is_connect=0
2170
+ ,.u=
2171
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2172
+ ,.port=0
2173
+ ,.field_data=
2174
+ {{ 0, 4 } /* UF_SCHEMA */
2175
+ ,{ 8, 8 } /* UF_HOST */
2176
+ ,{ 0, 0 } /* UF_PORT */
2177
+ ,{ 17, 1 } /* UF_PATH */
2178
+ ,{ 0, 0 } /* UF_QUERY */
2179
+ ,{ 0, 0 } /* UF_FRAGMENT */
2180
+ ,{ 0, 0 } /* UF_USERINFO */
2181
+ }
2182
+ }
2183
+ ,.rv=0
2184
+ }
2185
+
2186
+ , {.name="proxy ipv6 request with port"
2187
+ ,.url="http://[1:2::3:4]:67/"
2188
+ ,.is_connect=0
2189
+ ,.u=
2190
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2191
+ ,.port=67
2192
+ ,.field_data=
2193
+ {{ 0, 4 } /* UF_SCHEMA */
2194
+ ,{ 8, 8 } /* UF_HOST */
2195
+ ,{ 18, 2 } /* UF_PORT */
2196
+ ,{ 20, 1 } /* UF_PATH */
2197
+ ,{ 0, 0 } /* UF_QUERY */
2198
+ ,{ 0, 0 } /* UF_FRAGMENT */
2199
+ ,{ 0, 0 } /* UF_USERINFO */
2200
+ }
2201
+ }
2202
+ ,.rv=0
2203
+ }
2204
+
2205
+ , {.name="CONNECT ipv6 address"
2206
+ ,.url="[1:2::3:4]:443"
2207
+ ,.is_connect=1
2208
+ ,.u=
2209
+ {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2210
+ ,.port=443
2211
+ ,.field_data=
2212
+ {{ 0, 0 } /* UF_SCHEMA */
2213
+ ,{ 1, 8 } /* UF_HOST */
2214
+ ,{ 11, 3 } /* UF_PORT */
2215
+ ,{ 0, 0 } /* UF_PATH */
2216
+ ,{ 0, 0 } /* UF_QUERY */
2217
+ ,{ 0, 0 } /* UF_FRAGMENT */
2218
+ ,{ 0, 0 } /* UF_USERINFO */
2219
+ }
2220
+ }
2221
+ ,.rv=0
2222
+ }
2223
+
2224
+ , {.name="ipv4 in ipv6 address"
2225
+ ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
2226
+ ,.is_connect=0
2227
+ ,.u=
2228
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2229
+ ,.port=0
2230
+ ,.field_data=
2231
+ {{ 0, 4 } /* UF_SCHEMA */
2232
+ ,{ 8, 37 } /* UF_HOST */
2233
+ ,{ 0, 0 } /* UF_PORT */
2234
+ ,{ 46, 1 } /* UF_PATH */
2235
+ ,{ 0, 0 } /* UF_QUERY */
2236
+ ,{ 0, 0 } /* UF_FRAGMENT */
2237
+ ,{ 0, 0 } /* UF_USERINFO */
2238
+ }
2239
+ }
2240
+ ,.rv=0
2241
+ }
2242
+
2243
+ , {.name="extra ? in query string"
2244
+ ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
2245
+ "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
2246
+ "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
2247
+ ,.is_connect=0
2248
+ ,.u=
2249
+ {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
2250
+ ,.port=0
2251
+ ,.field_data=
2252
+ {{ 0, 4 } /* UF_SCHEMA */
2253
+ ,{ 7, 10 } /* UF_HOST */
2254
+ ,{ 0, 0 } /* UF_PORT */
2255
+ ,{ 17, 12 } /* UF_PATH */
2256
+ ,{ 30,187 } /* UF_QUERY */
2257
+ ,{ 0, 0 } /* UF_FRAGMENT */
2258
+ ,{ 0, 0 } /* UF_USERINFO */
2259
+ }
2260
+ }
2261
+ ,.rv=0
2262
+ }
2263
+
2264
+ , {.name="space URL encoded"
2265
+ ,.url="/toto.html?toto=a%20b"
2266
+ ,.is_connect=0
2267
+ ,.u=
2268
+ {.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
2269
+ ,.port=0
2270
+ ,.field_data=
2271
+ {{ 0, 0 } /* UF_SCHEMA */
2272
+ ,{ 0, 0 } /* UF_HOST */
2273
+ ,{ 0, 0 } /* UF_PORT */
2274
+ ,{ 0, 10 } /* UF_PATH */
2275
+ ,{ 11, 10 } /* UF_QUERY */
2276
+ ,{ 0, 0 } /* UF_FRAGMENT */
2277
+ ,{ 0, 0 } /* UF_USERINFO */
2278
+ }
2279
+ }
2280
+ ,.rv=0
2281
+ }
2282
+
2283
+
2284
+ , {.name="URL fragment"
2285
+ ,.url="/toto.html#titi"
2286
+ ,.is_connect=0
2287
+ ,.u=
2288
+ {.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
2289
+ ,.port=0
2290
+ ,.field_data=
2291
+ {{ 0, 0 } /* UF_SCHEMA */
2292
+ ,{ 0, 0 } /* UF_HOST */
2293
+ ,{ 0, 0 } /* UF_PORT */
2294
+ ,{ 0, 10 } /* UF_PATH */
2295
+ ,{ 0, 0 } /* UF_QUERY */
2296
+ ,{ 11, 4 } /* UF_FRAGMENT */
2297
+ ,{ 0, 0 } /* UF_USERINFO */
2298
+ }
2299
+ }
2300
+ ,.rv=0
2301
+ }
2302
+
2303
+ , {.name="complex URL fragment"
2304
+ ,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
2305
+ "http://www.example.com/index.html?foo=bar&hello=world#midpage"
2306
+ ,.is_connect=0
2307
+ ,.u=
2308
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
2309
+ (1<<UF_FRAGMENT)
2310
+ ,.port=0
2311
+ ,.field_data=
2312
+ {{ 0, 4 } /* UF_SCHEMA */
2313
+ ,{ 7, 22 } /* UF_HOST */
2314
+ ,{ 0, 0 } /* UF_PORT */
2315
+ ,{ 29, 6 } /* UF_PATH */
2316
+ ,{ 36, 69 } /* UF_QUERY */
2317
+ ,{106, 7 } /* UF_FRAGMENT */
2318
+ ,{ 0, 0 } /* UF_USERINFO */
2319
+ }
2320
+ }
2321
+ ,.rv=0
2322
+ }
2323
+
2324
+ , {.name="complex URL from node js url parser doc"
2325
+ ,.url="http://host.com:8080/p/a/t/h?query=string#hash"
2326
+ ,.is_connect=0
2327
+ ,.u=
2328
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2329
+ (1<<UF_QUERY) | (1<<UF_FRAGMENT)
2330
+ ,.port=8080
2331
+ ,.field_data=
2332
+ {{ 0, 4 } /* UF_SCHEMA */
2333
+ ,{ 7, 8 } /* UF_HOST */
2334
+ ,{ 16, 4 } /* UF_PORT */
2335
+ ,{ 20, 8 } /* UF_PATH */
2336
+ ,{ 29, 12 } /* UF_QUERY */
2337
+ ,{ 42, 4 } /* UF_FRAGMENT */
2338
+ ,{ 0, 0 } /* UF_USERINFO */
2339
+ }
2340
+ }
2341
+ ,.rv=0
2342
+ }
2343
+
2344
+ , {.name="complex URL with basic auth from node js url parser doc"
2345
+ ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
2346
+ ,.is_connect=0
2347
+ ,.u=
2348
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
2349
+ (1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
2350
+ ,.port=8080
2351
+ ,.field_data=
2352
+ {{ 0, 4 } /* UF_SCHEMA */
2353
+ ,{ 11, 8 } /* UF_HOST */
2354
+ ,{ 20, 4 } /* UF_PORT */
2355
+ ,{ 24, 8 } /* UF_PATH */
2356
+ ,{ 33, 12 } /* UF_QUERY */
2357
+ ,{ 46, 4 } /* UF_FRAGMENT */
2358
+ ,{ 7, 3 } /* UF_USERINFO */
2359
+ }
2360
+ }
2361
+ ,.rv=0
2362
+ }
2363
+
2364
+ , {.name="double @"
2365
+ ,.url="http://a:b@@hostname:443/"
2366
+ ,.is_connect=0
2367
+ ,.rv=1
2368
+ }
2369
+
2370
+ , {.name="proxy empty host"
2371
+ ,.url="http://:443/"
2372
+ ,.is_connect=0
2373
+ ,.rv=1
2374
+ }
2375
+
2376
+ , {.name="proxy empty port"
2377
+ ,.url="http://hostname:/"
2378
+ ,.is_connect=0
2379
+ ,.rv=1
2380
+ }
2381
+
2382
+ , {.name="CONNECT with basic auth"
2383
+ ,.url="a:b@hostname:443"
2384
+ ,.is_connect=1
2385
+ ,.rv=1
2386
+ }
2387
+
2388
+ , {.name="CONNECT empty host"
2389
+ ,.url=":443"
2390
+ ,.is_connect=1
2391
+ ,.rv=1
2392
+ }
2393
+
2394
+ , {.name="CONNECT empty port"
2395
+ ,.url="hostname:"
2396
+ ,.is_connect=1
2397
+ ,.rv=1
2398
+ }
2399
+
2400
+ , {.name="CONNECT with extra bits"
2401
+ ,.url="hostname:443/"
2402
+ ,.is_connect=1
2403
+ ,.rv=1
2404
+ }
2405
+
2406
+ , {.name="space in URL"
2407
+ ,.url="/foo bar/"
2408
+ ,.rv=1 /* s_dead */
2409
+ }
2410
+
2411
+ , {.name="proxy basic auth with space url encoded"
2412
+ ,.url="http://a%20:b@host.com/"
2413
+ ,.is_connect=0
2414
+ ,.u=
2415
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2416
+ ,.port=0
2417
+ ,.field_data=
2418
+ {{ 0, 4 } /* UF_SCHEMA */
2419
+ ,{ 14, 8 } /* UF_HOST */
2420
+ ,{ 0, 0 } /* UF_PORT */
2421
+ ,{ 22, 1 } /* UF_PATH */
2422
+ ,{ 0, 0 } /* UF_QUERY */
2423
+ ,{ 0, 0 } /* UF_FRAGMENT */
2424
+ ,{ 7, 6 } /* UF_USERINFO */
2425
+ }
2426
+ }
2427
+ ,.rv=0
2428
+ }
2429
+
2430
+ , {.name="carriage return in URL"
2431
+ ,.url="/foo\rbar/"
2432
+ ,.rv=1 /* s_dead */
2433
+ }
2434
+
2435
+ , {.name="proxy double : in URL"
2436
+ ,.url="http://hostname::443/"
2437
+ ,.rv=1 /* s_dead */
2438
+ }
2439
+
2440
+ , {.name="proxy basic auth with double :"
2441
+ ,.url="http://a::b@host.com/"
2442
+ ,.is_connect=0
2443
+ ,.u=
2444
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2445
+ ,.port=0
2446
+ ,.field_data=
2447
+ {{ 0, 4 } /* UF_SCHEMA */
2448
+ ,{ 12, 8 } /* UF_HOST */
2449
+ ,{ 0, 0 } /* UF_PORT */
2450
+ ,{ 20, 1 } /* UF_PATH */
2451
+ ,{ 0, 0 } /* UF_QUERY */
2452
+ ,{ 0, 0 } /* UF_FRAGMENT */
2453
+ ,{ 7, 4 } /* UF_USERINFO */
2454
+ }
2455
+ }
2456
+ ,.rv=0
2457
+ }
2458
+
2459
+ , {.name="line feed in URL"
2460
+ ,.url="/foo\nbar/"
2461
+ ,.rv=1 /* s_dead */
2462
+ }
2463
+
2464
+ , {.name="proxy empty basic auth"
2465
+ ,.url="http://@hostname/fo"
2466
+ ,.u=
2467
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
2468
+ ,.port=0
2469
+ ,.field_data=
2470
+ {{ 0, 4 } /* UF_SCHEMA */
2471
+ ,{ 8, 8 } /* UF_HOST */
2472
+ ,{ 0, 0 } /* UF_PORT */
2473
+ ,{ 16, 3 } /* UF_PATH */
2474
+ ,{ 0, 0 } /* UF_QUERY */
2475
+ ,{ 0, 0 } /* UF_FRAGMENT */
2476
+ ,{ 0, 0 } /* UF_USERINFO */
2477
+ }
2478
+ }
2479
+ ,.rv=0
2480
+ }
2481
+ , {.name="proxy line feed in hostname"
2482
+ ,.url="http://host\name/fo"
2483
+ ,.rv=1 /* s_dead */
2484
+ }
2485
+
2486
+ , {.name="proxy % in hostname"
2487
+ ,.url="http://host%name/fo"
2488
+ ,.rv=1 /* s_dead */
2489
+ }
2490
+
2491
+ , {.name="proxy ; in hostname"
2492
+ ,.url="http://host;ame/fo"
2493
+ ,.rv=1 /* s_dead */
2494
+ }
2495
+
2496
+ , {.name="proxy basic auth with unreservedchars"
2497
+ ,.url="http://a!;-_!=+$@host.com/"
2498
+ ,.is_connect=0
2499
+ ,.u=
2500
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
2501
+ ,.port=0
2502
+ ,.field_data=
2503
+ {{ 0, 4 } /* UF_SCHEMA */
2504
+ ,{ 17, 8 } /* UF_HOST */
2505
+ ,{ 0, 0 } /* UF_PORT */
2506
+ ,{ 25, 1 } /* UF_PATH */
2507
+ ,{ 0, 0 } /* UF_QUERY */
2508
+ ,{ 0, 0 } /* UF_FRAGMENT */
2509
+ ,{ 7, 9 } /* UF_USERINFO */
2510
+ }
2511
+ }
2512
+ ,.rv=0
2513
+ }
2514
+
2515
+ , {.name="proxy only empty basic auth"
2516
+ ,.url="http://@/fo"
2517
+ ,.rv=1 /* s_dead */
2518
+ }
2519
+
2520
+ , {.name="proxy only basic auth"
2521
+ ,.url="http://toto@/fo"
2522
+ ,.rv=1 /* s_dead */
2523
+ }
2524
+
2525
+ , {.name="proxy emtpy hostname"
2526
+ ,.url="http:///fo"
2527
+ ,.rv=1 /* s_dead */
2528
+ }
2529
+
2530
+ , {.name="proxy = in URL"
2531
+ ,.url="http://host=ame/fo"
2532
+ ,.rv=1 /* s_dead */
2533
+ }
2534
+
2535
+ #if HTTP_PARSER_STRICT
2536
+
2537
+ , {.name="tab in URL"
2538
+ ,.url="/foo\tbar/"
2539
+ ,.rv=1 /* s_dead */
2540
+ }
2541
+
2542
+ , {.name="form feed in URL"
2543
+ ,.url="/foo\fbar/"
2544
+ ,.rv=1 /* s_dead */
2545
+ }
2546
+
2547
+ #else /* !HTTP_PARSER_STRICT */
2548
+
2549
+ , {.name="tab in URL"
2550
+ ,.url="/foo\tbar/"
2551
+ ,.u=
2552
+ {.field_set=(1 << UF_PATH)
2553
+ ,.field_data=
2554
+ {{ 0, 0 } /* UF_SCHEMA */
2555
+ ,{ 0, 0 } /* UF_HOST */
2556
+ ,{ 0, 0 } /* UF_PORT */
2557
+ ,{ 0, 9 } /* UF_PATH */
2558
+ ,{ 0, 0 } /* UF_QUERY */
2559
+ ,{ 0, 0 } /* UF_FRAGMENT */
2560
+ ,{ 0, 0 } /* UF_USERINFO */
2561
+ }
2562
+ }
2563
+ ,.rv=0
2564
+ }
2565
+
2566
+ , {.name="form feed in URL"
2567
+ ,.url="/foo\fbar/"
2568
+ ,.u=
2569
+ {.field_set=(1 << UF_PATH)
2570
+ ,.field_data=
2571
+ {{ 0, 0 } /* UF_SCHEMA */
2572
+ ,{ 0, 0 } /* UF_HOST */
2573
+ ,{ 0, 0 } /* UF_PORT */
2574
+ ,{ 0, 9 } /* UF_PATH */
2575
+ ,{ 0, 0 } /* UF_QUERY */
2576
+ ,{ 0, 0 } /* UF_FRAGMENT */
2577
+ ,{ 0, 0 } /* UF_USERINFO */
2578
+ }
2579
+ }
2580
+ ,.rv=0
2581
+ }
2582
+ #endif
2583
+ };
2584
+
2585
+ void
2586
+ dump_url (const char *url, const struct http_parser_url *u)
2587
+ {
2588
+ unsigned int i;
2589
+
2590
+ printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
2591
+ for (i = 0; i < UF_MAX; i++) {
2592
+ if ((u->field_set & (1 << i)) == 0) {
2593
+ printf("\tfield_data[%u]: unset\n", i);
2594
+ continue;
2595
+ }
2596
+
2597
+ printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
2598
+ i,
2599
+ u->field_data[i].off,
2600
+ u->field_data[i].len,
2601
+ u->field_data[i].len,
2602
+ url + u->field_data[i].off);
2603
+ }
2604
+ }
2605
+
2606
+ void
2607
+ test_parse_url (void)
2608
+ {
2609
+ struct http_parser_url u;
2610
+ const struct url_test *test;
2611
+ unsigned int i;
2612
+ int rv;
2613
+
2614
+ for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
2615
+ test = &url_tests[i];
2616
+ memset(&u, 0, sizeof(u));
2617
+
2618
+ rv = http_parser_parse_url(test->url,
2619
+ strlen(test->url),
2620
+ test->is_connect,
2621
+ &u);
2622
+
2623
+ if (test->rv == 0) {
2624
+ if (rv != 0) {
2625
+ printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2626
+ "unexpected rv %d ***\n\n", test->url, test->name, rv);
2627
+ abort();
2628
+ }
2629
+
2630
+ if (memcmp(&u, &test->u, sizeof(u)) != 0) {
2631
+ printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
2632
+ test->url, test->name);
2633
+
2634
+ printf("target http_parser_url:\n");
2635
+ dump_url(test->url, &test->u);
2636
+ printf("result http_parser_url:\n");
2637
+ dump_url(test->url, &u);
2638
+
2639
+ abort();
2640
+ }
2641
+ } else {
2642
+ /* test->rv != 0 */
2643
+ if (rv == 0) {
2644
+ printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2645
+ "unexpected rv %d ***\n\n", test->url, test->name, rv);
2646
+ abort();
2647
+ }
2648
+ }
2649
+ }
2650
+ }
2651
+
2652
+ void
2653
+ test_method_str (void)
2654
+ {
2655
+ assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
2656
+ assert(0 == strcmp("<unknown>", http_method_str(1337)));
2657
+ }
1349
2658
 
1350
2659
  void
1351
2660
  test_message (const struct message *message)
@@ -1363,41 +2672,45 @@ test_message (const struct message *message)
1363
2672
  if (msg1len) {
1364
2673
  read = parse(msg1, msg1len);
1365
2674
 
1366
- if (message->upgrade && parser->upgrade) goto test;
2675
+ if (message->upgrade && parser->upgrade) {
2676
+ messages[num_messages - 1].upgrade = msg1 + read;
2677
+ goto test;
2678
+ }
1367
2679
 
1368
2680
  if (read != msg1len) {
1369
2681
  print_error(msg1, read);
1370
- exit(1);
2682
+ abort();
1371
2683
  }
1372
2684
  }
1373
2685
 
1374
2686
 
1375
2687
  read = parse(msg2, msg2len);
1376
2688
 
1377
- if (message->upgrade && parser->upgrade) goto test;
2689
+ if (message->upgrade && parser->upgrade) {
2690
+ messages[num_messages - 1].upgrade = msg2 + read;
2691
+ goto test;
2692
+ }
1378
2693
 
1379
2694
  if (read != msg2len) {
1380
2695
  print_error(msg2, read);
1381
- exit(1);
2696
+ abort();
1382
2697
  }
1383
2698
 
1384
2699
  read = parse(NULL, 0);
1385
2700
 
1386
- if (message->upgrade && parser->upgrade) goto test;
1387
-
1388
2701
  if (read != 0) {
1389
2702
  print_error(message->raw, read);
1390
- exit(1);
2703
+ abort();
1391
2704
  }
1392
2705
 
1393
2706
  test:
1394
2707
 
1395
2708
  if (num_messages != 1) {
1396
2709
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
1397
- exit(1);
2710
+ abort();
1398
2711
  }
1399
2712
 
1400
- if(!message_eq(0, message)) exit(1);
2713
+ if(!message_eq(0, message)) abort();
1401
2714
 
1402
2715
  parser_free();
1403
2716
  }
@@ -1418,7 +2731,7 @@ test_message_count_body (const struct message *message)
1418
2731
  read = parse_count_body(message->raw + i, toread);
1419
2732
  if (read != toread) {
1420
2733
  print_error(message->raw, read);
1421
- exit(1);
2734
+ abort();
1422
2735
  }
1423
2736
  }
1424
2737
 
@@ -1426,36 +2739,47 @@ test_message_count_body (const struct message *message)
1426
2739
  read = parse_count_body(NULL, 0);
1427
2740
  if (read != 0) {
1428
2741
  print_error(message->raw, read);
1429
- exit(1);
2742
+ abort();
1430
2743
  }
1431
2744
 
1432
2745
  if (num_messages != 1) {
1433
2746
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
1434
- exit(1);
2747
+ abort();
1435
2748
  }
1436
2749
 
1437
- if(!message_eq(0, message)) exit(1);
2750
+ if(!message_eq(0, message)) abort();
1438
2751
 
1439
2752
  parser_free();
1440
2753
  }
1441
2754
 
1442
2755
  void
1443
- test_simple (const char *buf, int should_pass)
2756
+ test_simple (const char *buf, enum http_errno err_expected)
1444
2757
  {
1445
2758
  parser_init(HTTP_REQUEST);
1446
2759
 
1447
2760
  size_t parsed;
1448
2761
  int pass;
2762
+ enum http_errno err;
2763
+
1449
2764
  parsed = parse(buf, strlen(buf));
1450
2765
  pass = (parsed == strlen(buf));
2766
+ err = HTTP_PARSER_ERRNO(parser);
1451
2767
  parsed = parse(NULL, 0);
1452
2768
  pass &= (parsed == 0);
1453
2769
 
1454
2770
  parser_free();
1455
2771
 
1456
- if (pass != should_pass) {
1457
- fprintf(stderr, "\n*** test_simple expected %s ***\n\n%s", should_pass ? "success" : "error", buf);
1458
- exit(1);
2772
+ /* In strict mode, allow us to pass with an unexpected HPE_STRICT as
2773
+ * long as the caller isn't expecting success.
2774
+ */
2775
+ #if HTTP_PARSER_STRICT
2776
+ if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
2777
+ #else
2778
+ if (err_expected != err) {
2779
+ #endif
2780
+ fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
2781
+ http_errno_name(err_expected), http_errno_name(err), buf);
2782
+ abort();
1459
2783
  }
1460
2784
  }
1461
2785
 
@@ -1471,16 +2795,67 @@ test_header_overflow_error (int req)
1471
2795
  assert(parsed == strlen(buf));
1472
2796
 
1473
2797
  buf = "header-key: header-value\r\n";
2798
+ size_t buflen = strlen(buf);
2799
+
1474
2800
  int i;
1475
2801
  for (i = 0; i < 10000; i++) {
1476
- if (http_parser_execute(&parser, &settings_null, buf, strlen(buf)) != strlen(buf)) {
2802
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
2803
+ if (parsed != buflen) {
1477
2804
  //fprintf(stderr, "error found on iter %d\n", i);
2805
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
1478
2806
  return;
1479
2807
  }
1480
2808
  }
1481
2809
 
1482
2810
  fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
1483
- exit(1);
2811
+ abort();
2812
+ }
2813
+
2814
+ static void
2815
+ test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
2816
+ {
2817
+ http_parser parser;
2818
+ http_parser_init(&parser, HTTP_RESPONSE);
2819
+ http_parser_execute(&parser, &settings_null, buf, buflen);
2820
+
2821
+ if (expect_ok)
2822
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
2823
+ else
2824
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
2825
+ }
2826
+
2827
+ void
2828
+ test_header_content_length_overflow_error (void)
2829
+ {
2830
+ #define X(size) \
2831
+ "HTTP/1.1 200 OK\r\n" \
2832
+ "Content-Length: " #size "\r\n" \
2833
+ "\r\n"
2834
+ const char a[] = X(18446744073709551614); /* 2^64-2 */
2835
+ const char b[] = X(18446744073709551615); /* 2^64-1 */
2836
+ const char c[] = X(18446744073709551616); /* 2^64 */
2837
+ #undef X
2838
+ test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
2839
+ test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
2840
+ test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
2841
+ }
2842
+
2843
+ void
2844
+ test_chunk_content_length_overflow_error (void)
2845
+ {
2846
+ #define X(size) \
2847
+ "HTTP/1.1 200 OK\r\n" \
2848
+ "Transfer-Encoding: chunked\r\n" \
2849
+ "\r\n" \
2850
+ #size "\r\n" \
2851
+ "..."
2852
+ const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
2853
+ const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
2854
+ const char c[] = X(10000000000000000); /* 2^64 */
2855
+ #undef X
2856
+ test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
2857
+ test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
2858
+ test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
1484
2859
  }
1485
2860
 
1486
2861
  void
@@ -1491,8 +2866,8 @@ test_no_overflow_long_body (int req, size_t length)
1491
2866
  size_t parsed;
1492
2867
  size_t i;
1493
2868
  char buf1[3000];
1494
- size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %zu\r\n\r\n",
1495
- req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", length);
2869
+ size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
2870
+ req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
1496
2871
  parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
1497
2872
  if (parsed != buf1len)
1498
2873
  goto err;
@@ -1510,21 +2885,16 @@ test_no_overflow_long_body (int req, size_t length)
1510
2885
 
1511
2886
  err:
1512
2887
  fprintf(stderr,
1513
- "\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
2888
+ "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
1514
2889
  req ? "REQUEST" : "RESPONSE",
1515
- length);
1516
- exit(1);
2890
+ (unsigned long)length);
2891
+ abort();
1517
2892
  }
1518
2893
 
1519
2894
  void
1520
2895
  test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
1521
2896
  {
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);
2897
+ int message_count = count_parsed_messages(3, r1, r2, r3);
1528
2898
 
1529
2899
  char total[ strlen(r1->raw)
1530
2900
  + strlen(r2->raw)
@@ -1543,36 +2913,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
1543
2913
 
1544
2914
  read = parse(total, strlen(total));
1545
2915
 
1546
- if (has_upgrade && parser->upgrade) goto test;
2916
+ if (parser->upgrade) {
2917
+ upgrade_message_fix(total, read, 3, r1, r2, r3);
2918
+ goto test;
2919
+ }
1547
2920
 
1548
2921
  if (read != strlen(total)) {
1549
2922
  print_error(total, read);
1550
- exit(1);
2923
+ abort();
1551
2924
  }
1552
2925
 
1553
2926
  read = parse(NULL, 0);
1554
2927
 
1555
- if (has_upgrade && parser->upgrade) goto test;
1556
-
1557
2928
  if (read != 0) {
1558
2929
  print_error(total, read);
1559
- exit(1);
2930
+ abort();
1560
2931
  }
1561
2932
 
1562
2933
  test:
1563
2934
 
1564
2935
  if (message_count != num_messages) {
1565
2936
  fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
1566
- exit(1);
2937
+ abort();
1567
2938
  }
1568
2939
 
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
- }
2940
+ if (!message_eq(0, r1)) abort();
2941
+ if (message_count > 1 && !message_eq(1, r2)) abort();
2942
+ if (message_count > 2 && !message_eq(2, r3)) abort();
1576
2943
 
1577
2944
  parser_free();
1578
2945
  }
@@ -1601,6 +2968,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1601
2968
  int ops = 0 ;
1602
2969
 
1603
2970
  size_t buf1_len, buf2_len, buf3_len;
2971
+ int message_count = count_parsed_messages(3, r1, r2, r3);
1604
2972
 
1605
2973
  int i,j,type_both;
1606
2974
  for (type_both = 0; type_both < 2; type_both ++ ) {
@@ -1616,40 +2984,40 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1616
2984
  parser_init(type_both ? HTTP_BOTH : r1->type);
1617
2985
 
1618
2986
  buf1_len = i;
1619
- strncpy(buf1, total, buf1_len);
2987
+ strlncpy(buf1, sizeof(buf1), total, buf1_len);
1620
2988
  buf1[buf1_len] = 0;
1621
2989
 
1622
2990
  buf2_len = j - i;
1623
- strncpy(buf2, total+i, buf2_len);
2991
+ strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
1624
2992
  buf2[buf2_len] = 0;
1625
2993
 
1626
2994
  buf3_len = total_len - j;
1627
- strncpy(buf3, total+j, buf3_len);
2995
+ strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
1628
2996
  buf3[buf3_len] = 0;
1629
2997
 
1630
2998
  read = parse(buf1, buf1_len);
1631
2999
 
1632
- if (r3->upgrade && parser->upgrade) goto test;
3000
+ if (parser->upgrade) goto test;
1633
3001
 
1634
3002
  if (read != buf1_len) {
1635
3003
  print_error(buf1, read);
1636
3004
  goto error;
1637
3005
  }
1638
3006
 
1639
- read = parse(buf2, buf2_len);
3007
+ read += parse(buf2, buf2_len);
1640
3008
 
1641
- if (r3->upgrade && parser->upgrade) goto test;
3009
+ if (parser->upgrade) goto test;
1642
3010
 
1643
- if (read != buf2_len) {
3011
+ if (read != buf1_len + buf2_len) {
1644
3012
  print_error(buf2, read);
1645
3013
  goto error;
1646
3014
  }
1647
3015
 
1648
- read = parse(buf3, buf3_len);
3016
+ read += parse(buf3, buf3_len);
1649
3017
 
1650
- if (r3->upgrade && parser->upgrade) goto test;
3018
+ if (parser->upgrade) goto test;
1651
3019
 
1652
- if (read != buf3_len) {
3020
+ if (read != buf1_len + buf2_len + buf3_len) {
1653
3021
  print_error(buf3, read);
1654
3022
  goto error;
1655
3023
  }
@@ -1657,9 +3025,13 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
1657
3025
  parse(NULL, 0);
1658
3026
 
1659
3027
  test:
3028
+ if (parser->upgrade) {
3029
+ upgrade_message_fix(total, read, 3, r1, r2, r3);
3030
+ }
1660
3031
 
1661
- if (3 != num_messages) {
1662
- fprintf(stderr, "\n\nParser didn't see 3 messages only %d\n", num_messages);
3032
+ if (message_count != num_messages) {
3033
+ fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
3034
+ message_count, num_messages);
1663
3035
  goto error;
1664
3036
  }
1665
3037
 
@@ -1668,12 +3040,12 @@ test:
1668
3040
  goto error;
1669
3041
  }
1670
3042
 
1671
- if (!message_eq(1, r2)) {
3043
+ if (message_count > 1 && !message_eq(1, r2)) {
1672
3044
  fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
1673
3045
  goto error;
1674
3046
  }
1675
3047
 
1676
- if (!message_eq(2, r3)) {
3048
+ if (message_count > 2 && !message_eq(2, r3)) {
1677
3049
  fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
1678
3050
  goto error;
1679
3051
  }
@@ -1690,7 +3062,7 @@ test:
1690
3062
  fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
1691
3063
  fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
1692
3064
  fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
1693
- exit(1);
3065
+ abort();
1694
3066
  }
1695
3067
 
1696
3068
  // user required to free the result
@@ -1724,136 +3096,91 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
1724
3096
  return buf;
1725
3097
  }
1726
3098
 
1727
- char *
1728
- 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;
1751
- }
1752
-
1753
- void
1754
- dump_message(const struct message * m)
3099
+ void
3100
+ test_status_complete (void)
1755
3101
  {
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) {
1770
- case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
1771
- case HTTP_GET: printf("method: HTTP_GET\n");break;
1772
- case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
1773
- case HTTP_POST: printf("method: HTTP_POST\n");break;
1774
- case HTTP_PUT: printf("method: HTTP_PUT\n");break;
1775
- case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
1776
- case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
1777
- case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
1778
- case HTTP_COPY: printf("method: HTTP_COPY\n");break;
1779
- case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
1780
- case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
1781
- case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
1782
- case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
1783
- case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
1784
- case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
1785
- /* subversion */
1786
- case HTTP_REPORT: printf("method: HTTP_REPORT\n"); break;
1787
- case HTTP_MKACTIVITY: printf("method: HTTP_MKACTIVITY\n"); break;
1788
- case HTTP_CHECKOUT: printf("method: HTTP_CHECKOUT\n"); break;
1789
- case HTTP_MERGE: printf("method: HTTP_MERGE\n"); break;
1790
-
1791
- case HTTP_MSEARCH: printf("method: HTTP_MSEARCH\n"); break;
1792
- case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
1793
- case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
1794
- case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
1795
- default:
1796
- printf("method: UNKNOWN\n"); break;
1797
- break;
1798
- }
1799
- printf("status_code :%d\n", m->status_code);
1800
- printf("request_path:%s\n", m->request_path);
1801
- printf("request_url :%s\n", m->request_url);
1802
- printf("fragment :%s\n", m->fragment);
1803
- printf("query_string:%s\n", m->query_string);
1804
-
1805
- bla = quote(m->body);
1806
- printf("body :\"%s\"\n", bla);
1807
- free(bla);
1808
- printf("body_size :%zu\n", m->body_size);
1809
-
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
- }
1813
-
1814
- printf("should_keep_alive :%d\n", m->should_keep_alive);
1815
- printf("upgrade :%d\n", m->upgrade);
1816
- printf("http_major :%d\n", m->http_major);
1817
- printf("http_minor :%d\n", m->http_minor);
1818
- // printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
1819
- // printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
1820
- // printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
1821
- // printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
1822
- printf("\n");
3102
+ parser_init(HTTP_RESPONSE);
3103
+ parser->data = 0;
3104
+ http_parser_settings settings = settings_null;
3105
+ settings.on_status_complete = status_complete_cb;
3106
+
3107
+ char *response = "don't mind me, just a simple response";
3108
+ http_parser_execute(parser, &settings, response, strlen(response));
3109
+ assert(parser->data == (void*)0); // the status_complete callback was never called
3110
+ assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line
1823
3111
  }
1824
3112
 
1825
- void
1826
- dump_messages(void)
3113
+ /* Verify that we can pause parsing at any of the bytes in the
3114
+ * message and still get the result that we're expecting. */
3115
+ void
3116
+ test_message_pause (const struct message *msg)
1827
3117
  {
1828
- int request_count;
1829
- for (request_count = 0; requests[request_count].name; request_count++){
1830
- dump_message(&requests[request_count]);
1831
- }
1832
- for (request_count = 0; responses[request_count].name; request_count++){
1833
- dump_message(&responses[request_count]);
3118
+ char *buf = (char*) msg->raw;
3119
+ size_t buflen = strlen(msg->raw);
3120
+ size_t nread;
3121
+
3122
+ parser_init(msg->type);
3123
+
3124
+ do {
3125
+ nread = parse_pause(buf, buflen);
3126
+
3127
+ // We can only set the upgrade buffer once we've gotten our message
3128
+ // completion callback.
3129
+ if (messages[0].message_complete_cb_called &&
3130
+ msg->upgrade &&
3131
+ parser->upgrade) {
3132
+ messages[0].upgrade = buf + nread;
3133
+ goto test;
3134
+ }
3135
+
3136
+ if (nread < buflen) {
3137
+
3138
+ // Not much do to if we failed a strict-mode check
3139
+ if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
3140
+ parser_free();
3141
+ return;
3142
+ }
3143
+
3144
+ assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
3145
+ }
3146
+
3147
+ buf += nread;
3148
+ buflen -= nread;
3149
+ http_parser_pause(parser, 0);
3150
+ } while (buflen > 0);
3151
+
3152
+ nread = parse_pause(NULL, 0);
3153
+ assert (nread == 0);
3154
+
3155
+ test:
3156
+ if (num_messages != 1) {
3157
+ printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
3158
+ abort();
1834
3159
  }
3160
+
3161
+ if(!message_eq(0, msg)) abort();
3162
+
3163
+ parser_free();
1835
3164
  }
1836
3165
 
1837
3166
  int
1838
- main (int argc, char * argv[])
3167
+ main (void)
1839
3168
  {
1840
3169
  parser = NULL;
1841
3170
  int i, j, k;
1842
3171
  int request_count;
1843
3172
  int response_count;
1844
-
1845
- if (1 != argc) {
1846
- if (0 == (strncmp("-dump", argv[1], sizeof("-dump")))) {
1847
- dump_messages();
1848
- exit(0);
1849
- }
1850
- }
1851
3173
 
1852
3174
  printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
1853
3175
 
1854
3176
  for (request_count = 0; requests[request_count].name; request_count++);
1855
3177
  for (response_count = 0; responses[response_count].name; response_count++);
1856
3178
 
3179
+ //// API
3180
+ test_preserve_data();
3181
+ test_parse_url();
3182
+ test_method_str();
3183
+
1857
3184
  //// OVERFLOW CONDITIONS
1858
3185
 
1859
3186
  test_header_overflow_error(HTTP_REQUEST);
@@ -1864,12 +3191,19 @@ main (int argc, char * argv[])
1864
3191
  test_no_overflow_long_body(HTTP_RESPONSE, 1000);
1865
3192
  test_no_overflow_long_body(HTTP_RESPONSE, 100000);
1866
3193
 
3194
+ test_header_content_length_overflow_error();
3195
+ test_chunk_content_length_overflow_error();
3196
+
1867
3197
  //// RESPONSES
1868
3198
 
1869
3199
  for (i = 0; i < response_count; i++) {
1870
3200
  test_message(&responses[i]);
1871
3201
  }
1872
3202
 
3203
+ for (i = 0; i < response_count; i++) {
3204
+ test_message_pause(&responses[i]);
3205
+ }
3206
+
1873
3207
  for (i = 0; i < response_count; i++) {
1874
3208
  if (!responses[i].should_keep_alive) continue;
1875
3209
  for (j = 0; j < response_count; j++) {
@@ -1914,7 +3248,7 @@ main (int argc, char * argv[])
1914
3248
 
1915
3249
  printf("response scan 1/2 ");
1916
3250
  test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
1917
- , &responses[NO_HEADERS_NO_BODY_404]
3251
+ , &responses[NO_BODY_HTTP10_KA_204]
1918
3252
  , &responses[NO_REASON_PHRASE]
1919
3253
  );
1920
3254
 
@@ -1929,13 +3263,13 @@ main (int argc, char * argv[])
1929
3263
 
1930
3264
  /// REQUESTS
1931
3265
 
1932
- test_simple("hello world", 0);
1933
- test_simple("GET / HTP/1.1\r\n\r\n", 0);
3266
+ test_simple("hello world", HPE_INVALID_METHOD);
3267
+ test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
1934
3268
 
1935
3269
 
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);
3270
+ test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
3271
+ test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
3272
+ test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
1939
3273
 
1940
3274
  // Well-formed but incomplete
1941
3275
  test_simple("GET / HTTP/1.1\r\n"
@@ -1943,7 +3277,7 @@ main (int argc, char * argv[])
1943
3277
  "Content-Length: 6\r\n"
1944
3278
  "\r\n"
1945
3279
  "fooba",
1946
- 0);
3280
+ HPE_OK);
1947
3281
 
1948
3282
  static const char *all_methods[] = {
1949
3283
  "DELETE",
@@ -1961,12 +3295,31 @@ main (int argc, char * argv[])
1961
3295
  "PROPFIND",
1962
3296
  "PROPPATCH",
1963
3297
  "UNLOCK",
3298
+ "REPORT",
3299
+ "MKACTIVITY",
3300
+ "CHECKOUT",
3301
+ "MERGE",
3302
+ "M-SEARCH",
3303
+ "NOTIFY",
3304
+ "SUBSCRIBE",
3305
+ "UNSUBSCRIBE",
3306
+ "PATCH",
1964
3307
  0 };
1965
3308
  const char **this_method;
1966
3309
  for (this_method = all_methods; *this_method; this_method++) {
1967
3310
  char buf[200];
1968
3311
  sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
1969
- test_simple(buf, 1);
3312
+ test_simple(buf, HPE_OK);
3313
+ }
3314
+
3315
+ static const char *bad_methods[] = {
3316
+ "C******",
3317
+ "M****",
3318
+ 0 };
3319
+ for (this_method = bad_methods; *this_method; this_method++) {
3320
+ char buf[200];
3321
+ sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
3322
+ test_simple(buf, HPE_UNKNOWN);
1970
3323
  }
1971
3324
 
1972
3325
  const char *dumbfuck2 =
@@ -2004,7 +3357,7 @@ main (int argc, char * argv[])
2004
3357
  "\tRA==\r\n"
2005
3358
  "\t-----END CERTIFICATE-----\r\n"
2006
3359
  "\r\n";
2007
- test_simple(dumbfuck2, 0);
3360
+ test_simple(dumbfuck2, HPE_OK);
2008
3361
 
2009
3362
  #if 0
2010
3363
  // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
@@ -2026,7 +3379,9 @@ main (int argc, char * argv[])
2026
3379
  test_message(&requests[i]);
2027
3380
  }
2028
3381
 
2029
-
3382
+ for (i = 0; i < request_count; i++) {
3383
+ test_message_pause(&requests[i]);
3384
+ }
2030
3385
 
2031
3386
  for (i = 0; i < request_count; i++) {
2032
3387
  if (!requests[i].should_keep_alive) continue;
@@ -2062,6 +3417,8 @@ main (int argc, char * argv[])
2062
3417
  , &requests[CONNECT_REQUEST]
2063
3418
  );
2064
3419
 
3420
+ test_status_complete();
3421
+
2065
3422
  puts("requests okay");
2066
3423
 
2067
3424
  return 0;