http_parser.rb 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,16 +26,23 @@
26
26
  #include <string.h>
27
27
  #include <stdarg.h>
28
28
 
29
+ #if defined(__APPLE__)
30
+ # undef strlncpy
31
+ #endif /* defined(__APPLE__) */
32
+
29
33
  #undef TRUE
30
34
  #define TRUE 1
31
35
  #undef FALSE
32
36
  #define FALSE 0
33
37
 
34
38
  #define MAX_HEADERS 13
35
- #define MAX_ELEMENT_SIZE 500
39
+ #define MAX_ELEMENT_SIZE 2048
40
+ #define MAX_CHUNKS 16
36
41
 
37
42
  #define MIN(a,b) ((a) < (b) ? (a) : (b))
38
43
 
44
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
45
+
39
46
  static http_parser *parser;
40
47
 
41
48
  struct message {
@@ -44,18 +51,25 @@ struct message {
44
51
  enum http_parser_type type;
45
52
  enum http_method method;
46
53
  int status_code;
54
+ char response_status[MAX_ELEMENT_SIZE];
47
55
  char request_path[MAX_ELEMENT_SIZE];
48
56
  char request_url[MAX_ELEMENT_SIZE];
49
57
  char fragment[MAX_ELEMENT_SIZE];
50
58
  char query_string[MAX_ELEMENT_SIZE];
51
59
  char body[MAX_ELEMENT_SIZE];
52
60
  size_t body_size;
61
+ const char *host;
62
+ const char *userinfo;
53
63
  uint16_t port;
54
64
  int num_headers;
55
65
  enum { NONE=0, FIELD, VALUE } last_header_element;
56
66
  char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
57
67
  int should_keep_alive;
58
68
 
69
+ int num_chunks;
70
+ int num_chunks_complete;
71
+ int chunk_lengths[MAX_CHUNKS];
72
+
59
73
  const char *upgrade; // upgraded body
60
74
 
61
75
  unsigned short http_major;
@@ -64,7 +78,9 @@ struct message {
64
78
  int message_begin_cb_called;
65
79
  int headers_complete_cb_called;
66
80
  int message_complete_cb_called;
81
+ int status_cb_called;
67
82
  int message_complete_on_eof;
83
+ int body_is_final;
68
84
  };
69
85
 
70
86
  static int currently_parsing_eof;
@@ -291,6 +307,8 @@ const struct message requests[] =
291
307
  { { "Transfer-Encoding" , "chunked" }
292
308
  }
293
309
  ,.body= "all your base are belong to us"
310
+ ,.num_chunks_complete= 2
311
+ ,.chunk_lengths= { 0x1e }
294
312
  }
295
313
 
296
314
  #define TWO_CHUNKS_MULT_ZERO_END 9
@@ -317,6 +335,8 @@ const struct message requests[] =
317
335
  { { "Transfer-Encoding", "chunked" }
318
336
  }
319
337
  ,.body= "hello world"
338
+ ,.num_chunks_complete= 3
339
+ ,.chunk_lengths= { 5, 6 }
320
340
  }
321
341
 
322
342
  #define CHUNKED_W_TRAILING_HEADERS 10
@@ -347,6 +367,8 @@ const struct message requests[] =
347
367
  , { "Content-Type", "text/plain" }
348
368
  }
349
369
  ,.body= "hello world"
370
+ ,.num_chunks_complete= 3
371
+ ,.chunk_lengths= { 5, 6 }
350
372
  }
351
373
 
352
374
  #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
@@ -373,6 +395,8 @@ const struct message requests[] =
373
395
  { { "Transfer-Encoding", "chunked" }
374
396
  }
375
397
  ,.body= "hello world"
398
+ ,.num_chunks_complete= 3
399
+ ,.chunk_lengths= { 5, 6 }
376
400
  }
377
401
 
378
402
  #define WITH_QUOTES 12
@@ -587,7 +611,7 @@ const struct message requests[] =
587
611
  ,.body= ""
588
612
  }
589
613
 
590
- #define LINE_FOLDING_IN_HEADER 20
614
+ #define LINE_FOLDING_IN_HEADER 21
591
615
  , {.name= "line folding in header value"
592
616
  ,.type= HTTP_REQUEST
593
617
  ,.raw= "GET / HTTP/1.1\r\n"
@@ -598,8 +622,14 @@ const struct message requests[] =
598
622
  " mno \r\n"
599
623
  "\t \tqrs\r\n"
600
624
  "Line2: \t line2\t\r\n"
625
+ "Line3:\r\n"
626
+ " line3\r\n"
627
+ "Line4: \r\n"
628
+ " \r\n"
629
+ "Connection:\r\n"
630
+ " close\r\n"
601
631
  "\r\n"
602
- ,.should_keep_alive= TRUE
632
+ ,.should_keep_alive= FALSE
603
633
  ,.message_complete_on_eof= FALSE
604
634
  ,.http_major= 1
605
635
  ,.http_minor= 1
@@ -608,15 +638,18 @@ const struct message requests[] =
608
638
  ,.fragment= ""
609
639
  ,.request_path= "/"
610
640
  ,.request_url= "/"
611
- ,.num_headers= 2
612
- ,.headers= { { "Line1", "abcdefghijklmno qrs" }
641
+ ,.num_headers= 5
642
+ ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
613
643
  , { "Line2", "line2\t" }
644
+ , { "Line3", "line3" }
645
+ , { "Line4", "" }
646
+ , { "Connection", "close" },
614
647
  }
615
648
  ,.body= ""
616
649
  }
617
650
 
618
651
 
619
- #define QUERY_TERMINATED_HOST 21
652
+ #define QUERY_TERMINATED_HOST 22
620
653
  , {.name= "host terminated by a query string"
621
654
  ,.type= HTTP_REQUEST
622
655
  ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
@@ -630,12 +663,13 @@ const struct message requests[] =
630
663
  ,.fragment= ""
631
664
  ,.request_path= ""
632
665
  ,.request_url= "http://hypnotoad.org?hail=all"
666
+ ,.host= "hypnotoad.org"
633
667
  ,.num_headers= 0
634
668
  ,.headers= { }
635
669
  ,.body= ""
636
670
  }
637
671
 
638
- #define QUERY_TERMINATED_HOSTPORT 22
672
+ #define QUERY_TERMINATED_HOSTPORT 23
639
673
  , {.name= "host:port terminated by a query string"
640
674
  ,.type= HTTP_REQUEST
641
675
  ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
@@ -649,13 +683,14 @@ const struct message requests[] =
649
683
  ,.fragment= ""
650
684
  ,.request_path= ""
651
685
  ,.request_url= "http://hypnotoad.org:1234?hail=all"
686
+ ,.host= "hypnotoad.org"
652
687
  ,.port= 1234
653
688
  ,.num_headers= 0
654
689
  ,.headers= { }
655
690
  ,.body= ""
656
691
  }
657
692
 
658
- #define SPACE_TERMINATED_HOSTPORT 23
693
+ #define SPACE_TERMINATED_HOSTPORT 24
659
694
  , {.name= "host:port terminated by a space"
660
695
  ,.type= HTTP_REQUEST
661
696
  ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
@@ -669,13 +704,14 @@ const struct message requests[] =
669
704
  ,.fragment= ""
670
705
  ,.request_path= ""
671
706
  ,.request_url= "http://hypnotoad.org:1234"
707
+ ,.host= "hypnotoad.org"
672
708
  ,.port= 1234
673
709
  ,.num_headers= 0
674
710
  ,.headers= { }
675
711
  ,.body= ""
676
712
  }
677
713
 
678
- #define PATCH_REQ 24
714
+ #define PATCH_REQ 25
679
715
  , {.name = "PATCH request"
680
716
  ,.type= HTTP_REQUEST
681
717
  ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
@@ -703,7 +739,7 @@ const struct message requests[] =
703
739
  ,.body= "cccccccccc"
704
740
  }
705
741
 
706
- #define CONNECT_CAPS_REQUEST 25
742
+ #define CONNECT_CAPS_REQUEST 26
707
743
  , {.name = "connect caps request"
708
744
  ,.type= HTTP_REQUEST
709
745
  ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
@@ -728,7 +764,7 @@ const struct message requests[] =
728
764
  }
729
765
 
730
766
  #if !HTTP_PARSER_STRICT
731
- #define UTF8_PATH_REQ 26
767
+ #define UTF8_PATH_REQ 27
732
768
  , {.name= "utf-8 path request"
733
769
  ,.type= HTTP_REQUEST
734
770
  ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
@@ -749,7 +785,7 @@ const struct message requests[] =
749
785
  ,.body= ""
750
786
  }
751
787
 
752
- #define HOSTNAME_UNDERSCORE 27
788
+ #define HOSTNAME_UNDERSCORE 28
753
789
  , {.name = "hostname underscore"
754
790
  ,.type= HTTP_REQUEST
755
791
  ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
@@ -775,7 +811,7 @@ const struct message requests[] =
775
811
  #endif /* !HTTP_PARSER_STRICT */
776
812
 
777
813
  /* see https://github.com/ry/http-parser/issues/47 */
778
- #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28
814
+ #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
779
815
  , {.name = "eat CRLF between requests, no \"Connection: close\" header"
780
816
  ,.raw= "POST / HTTP/1.1\r\n"
781
817
  "Host: www.example.com\r\n"
@@ -802,7 +838,7 @@ const struct message requests[] =
802
838
  }
803
839
 
804
840
  /* see https://github.com/ry/http-parser/issues/47 */
805
- #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29
841
+ #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
806
842
  , {.name = "eat CRLF between requests even if \"Connection: close\" is set"
807
843
  ,.raw= "POST / HTTP/1.1\r\n"
808
844
  "Host: www.example.com\r\n"
@@ -830,7 +866,7 @@ const struct message requests[] =
830
866
  ,.body= "q=42"
831
867
  }
832
868
 
833
- #define PURGE_REQ 30
869
+ #define PURGE_REQ 31
834
870
  , {.name = "PURGE request"
835
871
  ,.type= HTTP_REQUEST
836
872
  ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
@@ -850,7 +886,293 @@ const struct message requests[] =
850
886
  ,.body= ""
851
887
  }
852
888
 
853
- , {.name= NULL } /* sentinel */
889
+ #define SEARCH_REQ 32
890
+ , {.name = "SEARCH request"
891
+ ,.type= HTTP_REQUEST
892
+ ,.raw= "SEARCH / HTTP/1.1\r\n"
893
+ "Host: www.example.com\r\n"
894
+ "\r\n"
895
+ ,.should_keep_alive= TRUE
896
+ ,.message_complete_on_eof= FALSE
897
+ ,.http_major= 1
898
+ ,.http_minor= 1
899
+ ,.method= HTTP_SEARCH
900
+ ,.query_string= ""
901
+ ,.fragment= ""
902
+ ,.request_path= "/"
903
+ ,.request_url= "/"
904
+ ,.num_headers= 1
905
+ ,.headers= { { "Host", "www.example.com" } }
906
+ ,.body= ""
907
+ }
908
+
909
+ #define PROXY_WITH_BASIC_AUTH 33
910
+ , {.name= "host:port and basic_auth"
911
+ ,.type= HTTP_REQUEST
912
+ ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
913
+ "\r\n"
914
+ ,.should_keep_alive= TRUE
915
+ ,.message_complete_on_eof= FALSE
916
+ ,.http_major= 1
917
+ ,.http_minor= 1
918
+ ,.method= HTTP_GET
919
+ ,.fragment= ""
920
+ ,.request_path= "/toto"
921
+ ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
922
+ ,.host= "hypnotoad.org"
923
+ ,.userinfo= "a%12:b!&*$"
924
+ ,.port= 1234
925
+ ,.num_headers= 0
926
+ ,.headers= { }
927
+ ,.body= ""
928
+ }
929
+
930
+ #define LINE_FOLDING_IN_HEADER_WITH_LF 34
931
+ , {.name= "line folding in header value"
932
+ ,.type= HTTP_REQUEST
933
+ ,.raw= "GET / HTTP/1.1\n"
934
+ "Line1: abc\n"
935
+ "\tdef\n"
936
+ " ghi\n"
937
+ "\t\tjkl\n"
938
+ " mno \n"
939
+ "\t \tqrs\n"
940
+ "Line2: \t line2\t\n"
941
+ "Line3:\n"
942
+ " line3\n"
943
+ "Line4: \n"
944
+ " \n"
945
+ "Connection:\n"
946
+ " close\n"
947
+ "\n"
948
+ ,.should_keep_alive= FALSE
949
+ ,.message_complete_on_eof= FALSE
950
+ ,.http_major= 1
951
+ ,.http_minor= 1
952
+ ,.method= HTTP_GET
953
+ ,.query_string= ""
954
+ ,.fragment= ""
955
+ ,.request_path= "/"
956
+ ,.request_url= "/"
957
+ ,.num_headers= 5
958
+ ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
959
+ , { "Line2", "line2\t" }
960
+ , { "Line3", "line3" }
961
+ , { "Line4", "" }
962
+ , { "Connection", "close" },
963
+ }
964
+ ,.body= ""
965
+ }
966
+
967
+ #define CONNECTION_MULTI 35
968
+ , {.name = "multiple connection header values with folding"
969
+ ,.type= HTTP_REQUEST
970
+ ,.raw= "GET /demo HTTP/1.1\r\n"
971
+ "Host: example.com\r\n"
972
+ "Connection: Something,\r\n"
973
+ " Upgrade, ,Keep-Alive\r\n"
974
+ "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
975
+ "Sec-WebSocket-Protocol: sample\r\n"
976
+ "Upgrade: WebSocket\r\n"
977
+ "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
978
+ "Origin: http://example.com\r\n"
979
+ "\r\n"
980
+ "Hot diggity dogg"
981
+ ,.should_keep_alive= TRUE
982
+ ,.message_complete_on_eof= FALSE
983
+ ,.http_major= 1
984
+ ,.http_minor= 1
985
+ ,.method= HTTP_GET
986
+ ,.query_string= ""
987
+ ,.fragment= ""
988
+ ,.request_path= "/demo"
989
+ ,.request_url= "/demo"
990
+ ,.num_headers= 7
991
+ ,.upgrade="Hot diggity dogg"
992
+ ,.headers= { { "Host", "example.com" }
993
+ , { "Connection", "Something, Upgrade, ,Keep-Alive" }
994
+ , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
995
+ , { "Sec-WebSocket-Protocol", "sample" }
996
+ , { "Upgrade", "WebSocket" }
997
+ , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
998
+ , { "Origin", "http://example.com" }
999
+ }
1000
+ ,.body= ""
1001
+ }
1002
+
1003
+ #define CONNECTION_MULTI_LWS 36
1004
+ , {.name = "multiple connection header values with folding and lws"
1005
+ ,.type= HTTP_REQUEST
1006
+ ,.raw= "GET /demo HTTP/1.1\r\n"
1007
+ "Connection: keep-alive, upgrade\r\n"
1008
+ "Upgrade: WebSocket\r\n"
1009
+ "\r\n"
1010
+ "Hot diggity dogg"
1011
+ ,.should_keep_alive= TRUE
1012
+ ,.message_complete_on_eof= FALSE
1013
+ ,.http_major= 1
1014
+ ,.http_minor= 1
1015
+ ,.method= HTTP_GET
1016
+ ,.query_string= ""
1017
+ ,.fragment= ""
1018
+ ,.request_path= "/demo"
1019
+ ,.request_url= "/demo"
1020
+ ,.num_headers= 2
1021
+ ,.upgrade="Hot diggity dogg"
1022
+ ,.headers= { { "Connection", "keep-alive, upgrade" }
1023
+ , { "Upgrade", "WebSocket" }
1024
+ }
1025
+ ,.body= ""
1026
+ }
1027
+
1028
+ #define CONNECTION_MULTI_LWS_CRLF 37
1029
+ , {.name = "multiple connection header values with folding and lws"
1030
+ ,.type= HTTP_REQUEST
1031
+ ,.raw= "GET /demo HTTP/1.1\r\n"
1032
+ "Connection: keep-alive, \r\n upgrade\r\n"
1033
+ "Upgrade: WebSocket\r\n"
1034
+ "\r\n"
1035
+ "Hot diggity dogg"
1036
+ ,.should_keep_alive= TRUE
1037
+ ,.message_complete_on_eof= FALSE
1038
+ ,.http_major= 1
1039
+ ,.http_minor= 1
1040
+ ,.method= HTTP_GET
1041
+ ,.query_string= ""
1042
+ ,.fragment= ""
1043
+ ,.request_path= "/demo"
1044
+ ,.request_url= "/demo"
1045
+ ,.num_headers= 2
1046
+ ,.upgrade="Hot diggity dogg"
1047
+ ,.headers= { { "Connection", "keep-alive, upgrade" }
1048
+ , { "Upgrade", "WebSocket" }
1049
+ }
1050
+ ,.body= ""
1051
+ }
1052
+
1053
+ #define UPGRADE_POST_REQUEST 38
1054
+ , {.name = "upgrade post request"
1055
+ ,.type= HTTP_REQUEST
1056
+ ,.raw= "POST /demo HTTP/1.1\r\n"
1057
+ "Host: example.com\r\n"
1058
+ "Connection: Upgrade\r\n"
1059
+ "Upgrade: HTTP/2.0\r\n"
1060
+ "Content-Length: 15\r\n"
1061
+ "\r\n"
1062
+ "sweet post body"
1063
+ "Hot diggity dogg"
1064
+ ,.should_keep_alive= TRUE
1065
+ ,.message_complete_on_eof= FALSE
1066
+ ,.http_major= 1
1067
+ ,.http_minor= 1
1068
+ ,.method= HTTP_POST
1069
+ ,.request_path= "/demo"
1070
+ ,.request_url= "/demo"
1071
+ ,.num_headers= 4
1072
+ ,.upgrade="Hot diggity dogg"
1073
+ ,.headers= { { "Host", "example.com" }
1074
+ , { "Connection", "Upgrade" }
1075
+ , { "Upgrade", "HTTP/2.0" }
1076
+ , { "Content-Length", "15" }
1077
+ }
1078
+ ,.body= "sweet post body"
1079
+ }
1080
+
1081
+ #define CONNECT_WITH_BODY_REQUEST 39
1082
+ , {.name = "connect with body request"
1083
+ ,.type= HTTP_REQUEST
1084
+ ,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
1085
+ "User-agent: Mozilla/1.1N\r\n"
1086
+ "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
1087
+ "Content-Length: 10\r\n"
1088
+ "\r\n"
1089
+ "blarfcicle"
1090
+ ,.should_keep_alive= FALSE
1091
+ ,.message_complete_on_eof= FALSE
1092
+ ,.http_major= 1
1093
+ ,.http_minor= 0
1094
+ ,.method= HTTP_CONNECT
1095
+ ,.request_url= "foo.bar.com:443"
1096
+ ,.num_headers= 3
1097
+ ,.upgrade="blarfcicle"
1098
+ ,.headers= { { "User-agent", "Mozilla/1.1N" }
1099
+ , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
1100
+ , { "Content-Length", "10" }
1101
+ }
1102
+ ,.body= ""
1103
+ }
1104
+
1105
+ /* Examples from the Internet draft for LINK/UNLINK methods:
1106
+ * https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5
1107
+ */
1108
+
1109
+ #define LINK_REQUEST 40
1110
+ , {.name = "link request"
1111
+ ,.type= HTTP_REQUEST
1112
+ ,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n"
1113
+ "Host: example.com\r\n"
1114
+ "Link: <http://example.com/profiles/joe>; rel=\"tag\"\r\n"
1115
+ "Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
1116
+ "\r\n"
1117
+ ,.should_keep_alive= TRUE
1118
+ ,.message_complete_on_eof= FALSE
1119
+ ,.http_major= 1
1120
+ ,.http_minor= 1
1121
+ ,.method= HTTP_LINK
1122
+ ,.request_path= "/images/my_dog.jpg"
1123
+ ,.request_url= "/images/my_dog.jpg"
1124
+ ,.query_string= ""
1125
+ ,.fragment= ""
1126
+ ,.num_headers= 3
1127
+ ,.headers= { { "Host", "example.com" }
1128
+ , { "Link", "<http://example.com/profiles/joe>; rel=\"tag\"" }
1129
+ , { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
1130
+ }
1131
+ ,.body= ""
1132
+ }
1133
+
1134
+ #define UNLINK_REQUEST 41
1135
+ , {.name = "unlink request"
1136
+ ,.type= HTTP_REQUEST
1137
+ ,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
1138
+ "Host: example.com\r\n"
1139
+ "Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
1140
+ "\r\n"
1141
+ ,.should_keep_alive= TRUE
1142
+ ,.message_complete_on_eof= FALSE
1143
+ ,.http_major= 1
1144
+ ,.http_minor= 1
1145
+ ,.method= HTTP_UNLINK
1146
+ ,.request_path= "/images/my_dog.jpg"
1147
+ ,.request_url= "/images/my_dog.jpg"
1148
+ ,.query_string= ""
1149
+ ,.fragment= ""
1150
+ ,.num_headers= 2
1151
+ ,.headers= { { "Host", "example.com" }
1152
+ , { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
1153
+ }
1154
+ ,.body= ""
1155
+ }
1156
+
1157
+ #define SOURCE_REQUEST 42
1158
+ , {.name = "source request"
1159
+ ,.type= HTTP_REQUEST
1160
+ ,.raw= "SOURCE /music/sweet/music HTTP/1.1\r\n"
1161
+ "Host: example.com\r\n"
1162
+ "\r\n"
1163
+ ,.should_keep_alive= TRUE
1164
+ ,.message_complete_on_eof= FALSE
1165
+ ,.http_major= 1
1166
+ ,.http_minor= 1
1167
+ ,.method= HTTP_SOURCE
1168
+ ,.request_path= "/music/sweet/music"
1169
+ ,.request_url= "/music/sweet/music"
1170
+ ,.query_string= ""
1171
+ ,.fragment= ""
1172
+ ,.num_headers= 1
1173
+ ,.headers= { { "Host", "example.com" } }
1174
+ ,.body= ""
1175
+ }
854
1176
  };
855
1177
 
856
1178
  /* * R E S P O N S E S * */
@@ -879,6 +1201,7 @@ const struct message responses[] =
879
1201
  ,.http_major= 1
880
1202
  ,.http_minor= 1
881
1203
  ,.status_code= 301
1204
+ ,.response_status= "Moved Permanently"
882
1205
  ,.num_headers= 8
883
1206
  ,.headers=
884
1207
  { { "Location", "http://www.google.com/" }
@@ -927,6 +1250,7 @@ const struct message responses[] =
927
1250
  ,.http_major= 1
928
1251
  ,.http_minor= 1
929
1252
  ,.status_code= 200
1253
+ ,.response_status= "OK"
930
1254
  ,.num_headers= 5
931
1255
  ,.headers=
932
1256
  { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
@@ -955,6 +1279,7 @@ const struct message responses[] =
955
1279
  ,.http_major= 1
956
1280
  ,.http_minor= 1
957
1281
  ,.status_code= 404
1282
+ ,.response_status= "Not Found"
958
1283
  ,.num_headers= 0
959
1284
  ,.headers= {}
960
1285
  ,.body_size= 0
@@ -970,6 +1295,7 @@ const struct message responses[] =
970
1295
  ,.http_major= 1
971
1296
  ,.http_minor= 1
972
1297
  ,.status_code= 301
1298
+ ,.response_status= ""
973
1299
  ,.num_headers= 0
974
1300
  ,.headers= {}
975
1301
  ,.body= ""
@@ -995,6 +1321,7 @@ const struct message responses[] =
995
1321
  ,.http_major= 1
996
1322
  ,.http_minor= 1
997
1323
  ,.status_code= 200
1324
+ ,.response_status= "OK"
998
1325
  ,.num_headers= 2
999
1326
  ,.headers=
1000
1327
  { {"Content-Type", "text/plain" }
@@ -1004,7 +1331,8 @@ const struct message responses[] =
1004
1331
  ,.body =
1005
1332
  "This is the data in the first chunk\r\n"
1006
1333
  "and this is the second one\r\n"
1007
-
1334
+ ,.num_chunks_complete= 3
1335
+ ,.chunk_lengths= { 0x25, 0x1c }
1008
1336
  }
1009
1337
 
1010
1338
  #define NO_CARRIAGE_RET 5
@@ -1020,6 +1348,7 @@ const struct message responses[] =
1020
1348
  ,.http_major= 1
1021
1349
  ,.http_minor= 1
1022
1350
  ,.status_code= 200
1351
+ ,.response_status= "OK"
1023
1352
  ,.num_headers= 2
1024
1353
  ,.headers=
1025
1354
  { {"Content-Type", "text/html; charset=utf-8" }
@@ -1043,6 +1372,7 @@ const struct message responses[] =
1043
1372
  ,.http_major= 1
1044
1373
  ,.http_minor= 1
1045
1374
  ,.status_code= 200
1375
+ ,.response_status= "OK"
1046
1376
  ,.num_headers= 4
1047
1377
  ,.headers=
1048
1378
  { {"Content-Type", "text/html; charset=UTF-8" }
@@ -1068,6 +1398,7 @@ const struct message responses[] =
1068
1398
  ,.http_major= 1
1069
1399
  ,.http_minor= 1
1070
1400
  ,.status_code= 200
1401
+ ,.response_status= "OK"
1071
1402
  ,.num_headers= 4
1072
1403
  ,.headers=
1073
1404
  { {"Server", "DCLK-AdSvr" }
@@ -1100,6 +1431,7 @@ const struct message responses[] =
1100
1431
  ,.http_major= 1
1101
1432
  ,.http_minor= 0
1102
1433
  ,.status_code= 301
1434
+ ,.response_status= "Moved Permanently"
1103
1435
  ,.num_headers= 9
1104
1436
  ,.headers=
1105
1437
  { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
@@ -1138,6 +1470,7 @@ const struct message responses[] =
1138
1470
  ,.http_major= 1
1139
1471
  ,.http_minor= 1
1140
1472
  ,.status_code= 200
1473
+ ,.response_status= "OK"
1141
1474
  ,.num_headers= 11
1142
1475
  ,.headers=
1143
1476
  { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
@@ -1153,6 +1486,8 @@ const struct message responses[] =
1153
1486
  , { "Connection", "close" }
1154
1487
  }
1155
1488
  ,.body= ""
1489
+ ,.num_chunks_complete= 1
1490
+ ,.chunk_lengths= {}
1156
1491
  }
1157
1492
 
1158
1493
  #define NON_ASCII_IN_STATUS_LINE 10
@@ -1169,6 +1504,7 @@ const struct message responses[] =
1169
1504
  ,.http_major= 1
1170
1505
  ,.http_minor= 1
1171
1506
  ,.status_code= 500
1507
+ ,.response_status= "Oriëntatieprobleem"
1172
1508
  ,.num_headers= 3
1173
1509
  ,.headers=
1174
1510
  { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
@@ -1189,6 +1525,7 @@ const struct message responses[] =
1189
1525
  ,.http_major= 0
1190
1526
  ,.http_minor= 9
1191
1527
  ,.status_code= 200
1528
+ ,.response_status= "OK"
1192
1529
  ,.num_headers= 0
1193
1530
  ,.headers=
1194
1531
  {}
@@ -1211,6 +1548,7 @@ const struct message responses[] =
1211
1548
  ,.http_major= 1
1212
1549
  ,.http_minor= 1
1213
1550
  ,.status_code= 200
1551
+ ,.response_status= "OK"
1214
1552
  ,.num_headers= 1
1215
1553
  ,.headers=
1216
1554
  { { "Content-Type", "text/plain" }
@@ -1229,6 +1567,7 @@ const struct message responses[] =
1229
1567
  ,.http_major= 1
1230
1568
  ,.http_minor= 0
1231
1569
  ,.status_code= 200
1570
+ ,.response_status= "OK"
1232
1571
  ,.num_headers= 1
1233
1572
  ,.headers=
1234
1573
  { { "Connection", "keep-alive" }
@@ -1248,6 +1587,7 @@ const struct message responses[] =
1248
1587
  ,.http_major= 1
1249
1588
  ,.http_minor= 0
1250
1589
  ,.status_code= 204
1590
+ ,.response_status= "No content"
1251
1591
  ,.num_headers= 1
1252
1592
  ,.headers=
1253
1593
  { { "Connection", "keep-alive" }
@@ -1266,6 +1606,7 @@ const struct message responses[] =
1266
1606
  ,.http_major= 1
1267
1607
  ,.http_minor= 1
1268
1608
  ,.status_code= 200
1609
+ ,.response_status= "OK"
1269
1610
  ,.num_headers= 0
1270
1611
  ,.headers={}
1271
1612
  ,.body_size= 0
@@ -1282,6 +1623,7 @@ const struct message responses[] =
1282
1623
  ,.http_major= 1
1283
1624
  ,.http_minor= 1
1284
1625
  ,.status_code= 204
1626
+ ,.response_status= "No content"
1285
1627
  ,.num_headers= 0
1286
1628
  ,.headers={}
1287
1629
  ,.body_size= 0
@@ -1299,6 +1641,7 @@ const struct message responses[] =
1299
1641
  ,.http_major= 1
1300
1642
  ,.http_minor= 1
1301
1643
  ,.status_code= 204
1644
+ ,.response_status= "No content"
1302
1645
  ,.num_headers= 1
1303
1646
  ,.headers=
1304
1647
  { { "Connection", "close" }
@@ -1320,12 +1663,14 @@ const struct message responses[] =
1320
1663
  ,.http_major= 1
1321
1664
  ,.http_minor= 1
1322
1665
  ,.status_code= 200
1666
+ ,.response_status= "OK"
1323
1667
  ,.num_headers= 1
1324
1668
  ,.headers=
1325
1669
  { { "Transfer-Encoding", "chunked" }
1326
1670
  }
1327
1671
  ,.body_size= 0
1328
1672
  ,.body= ""
1673
+ ,.num_chunks_complete= 1
1329
1674
  }
1330
1675
 
1331
1676
  #if !HTTP_PARSER_STRICT
@@ -1348,6 +1693,7 @@ const struct message responses[] =
1348
1693
  ,.http_major= 1
1349
1694
  ,.http_minor= 1
1350
1695
  ,.status_code= 200
1696
+ ,.response_status= "OK"
1351
1697
  ,.num_headers= 7
1352
1698
  ,.headers=
1353
1699
  { { "Server", "Microsoft-IIS/6.0" }
@@ -1362,32 +1708,334 @@ const struct message responses[] =
1362
1708
  }
1363
1709
  #endif /* !HTTP_PARSER_STRICT */
1364
1710
 
1365
- , {.name= NULL } /* sentinel */
1366
- };
1367
-
1368
- int
1369
- request_url_cb (http_parser *p, const char *buf, size_t len)
1370
- {
1371
- assert(p == parser);
1372
- strncat(messages[num_messages].request_url, buf, len);
1373
- return 0;
1374
- }
1375
-
1376
- int
1377
- header_field_cb (http_parser *p, const char *buf, size_t len)
1378
- {
1379
- assert(p == parser);
1380
- struct message *m = &messages[num_messages];
1381
-
1382
- if (m->last_header_element != FIELD)
1383
- m->num_headers++;
1384
-
1385
- strncat(m->headers[m->num_headers-1][0], buf, len);
1386
-
1387
- m->last_header_element = FIELD;
1711
+ #define AMAZON_COM 20
1712
+ , {.name= "amazon.com"
1713
+ ,.type= HTTP_RESPONSE
1714
+ ,.raw= "HTTP/1.1 301 MovedPermanently\r\n"
1715
+ "Date: Wed, 15 May 2013 17:06:33 GMT\r\n"
1716
+ "Server: Server\r\n"
1717
+ "x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n"
1718
+ "p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n"
1719
+ "x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n"
1720
+ "Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n"
1721
+ "Vary: Accept-Encoding,User-Agent\r\n"
1722
+ "Content-Type: text/html; charset=ISO-8859-1\r\n"
1723
+ "Transfer-Encoding: chunked\r\n"
1724
+ "\r\n"
1725
+ "1\r\n"
1726
+ "\n\r\n"
1727
+ "0\r\n"
1728
+ "\r\n"
1729
+ ,.should_keep_alive= TRUE
1730
+ ,.message_complete_on_eof= FALSE
1731
+ ,.http_major= 1
1732
+ ,.http_minor= 1
1733
+ ,.status_code= 301
1734
+ ,.response_status= "MovedPermanently"
1735
+ ,.num_headers= 9
1736
+ ,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
1737
+ , { "Server", "Server" }
1738
+ , { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" }
1739
+ , { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" }
1740
+ , { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" }
1741
+ , { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" }
1742
+ , { "Vary", "Accept-Encoding,User-Agent" }
1743
+ , { "Content-Type", "text/html; charset=ISO-8859-1" }
1744
+ , { "Transfer-Encoding", "chunked" }
1745
+ }
1746
+ ,.body= "\n"
1747
+ ,.num_chunks_complete= 2
1748
+ ,.chunk_lengths= { 1 }
1749
+ }
1388
1750
 
1389
- return 0;
1390
- }
1751
+ #define EMPTY_REASON_PHRASE_AFTER_SPACE 20
1752
+ , {.name= "empty reason phrase after space"
1753
+ ,.type= HTTP_RESPONSE
1754
+ ,.raw= "HTTP/1.1 200 \r\n"
1755
+ "\r\n"
1756
+ ,.should_keep_alive= FALSE
1757
+ ,.message_complete_on_eof= TRUE
1758
+ ,.http_major= 1
1759
+ ,.http_minor= 1
1760
+ ,.status_code= 200
1761
+ ,.response_status= ""
1762
+ ,.num_headers= 0
1763
+ ,.headers= {}
1764
+ ,.body= ""
1765
+ }
1766
+
1767
+ #define CONTENT_LENGTH_X 21
1768
+ , {.name= "Content-Length-X"
1769
+ ,.type= HTTP_RESPONSE
1770
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1771
+ "Content-Length-X: 0\r\n"
1772
+ "Transfer-Encoding: chunked\r\n"
1773
+ "\r\n"
1774
+ "2\r\n"
1775
+ "OK\r\n"
1776
+ "0\r\n"
1777
+ "\r\n"
1778
+ ,.should_keep_alive= TRUE
1779
+ ,.message_complete_on_eof= FALSE
1780
+ ,.http_major= 1
1781
+ ,.http_minor= 1
1782
+ ,.status_code= 200
1783
+ ,.response_status= "OK"
1784
+ ,.num_headers= 2
1785
+ ,.headers= { { "Content-Length-X", "0" }
1786
+ , { "Transfer-Encoding", "chunked" }
1787
+ }
1788
+ ,.body= "OK"
1789
+ ,.num_chunks_complete= 2
1790
+ ,.chunk_lengths= { 2 }
1791
+ }
1792
+
1793
+ #define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER 22
1794
+ , {.name= "HTTP 101 response with Upgrade header"
1795
+ ,.type= HTTP_RESPONSE
1796
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
1797
+ "Connection: upgrade\r\n"
1798
+ "Upgrade: h2c\r\n"
1799
+ "\r\n"
1800
+ "proto"
1801
+ ,.should_keep_alive= TRUE
1802
+ ,.message_complete_on_eof= FALSE
1803
+ ,.http_major= 1
1804
+ ,.http_minor= 1
1805
+ ,.status_code= 101
1806
+ ,.response_status= "Switching Protocols"
1807
+ ,.upgrade= "proto"
1808
+ ,.num_headers= 2
1809
+ ,.headers=
1810
+ { { "Connection", "upgrade" }
1811
+ , { "Upgrade", "h2c" }
1812
+ }
1813
+ }
1814
+
1815
+ #define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 23
1816
+ , {.name= "HTTP 101 response with Upgrade and Content-Length header"
1817
+ ,.type= HTTP_RESPONSE
1818
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
1819
+ "Connection: upgrade\r\n"
1820
+ "Upgrade: h2c\r\n"
1821
+ "Content-Length: 4\r\n"
1822
+ "\r\n"
1823
+ "body"
1824
+ "proto"
1825
+ ,.should_keep_alive= TRUE
1826
+ ,.message_complete_on_eof= FALSE
1827
+ ,.http_major= 1
1828
+ ,.http_minor= 1
1829
+ ,.status_code= 101
1830
+ ,.response_status= "Switching Protocols"
1831
+ ,.body= "body"
1832
+ ,.upgrade= "proto"
1833
+ ,.num_headers= 3
1834
+ ,.headers=
1835
+ { { "Connection", "upgrade" }
1836
+ , { "Upgrade", "h2c" }
1837
+ , { "Content-Length", "4" }
1838
+ }
1839
+ }
1840
+
1841
+ #define HTTP_101_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 24
1842
+ , {.name= "HTTP 101 response with Upgrade and Transfer-Encoding header"
1843
+ ,.type= HTTP_RESPONSE
1844
+ ,.raw= "HTTP/1.1 101 Switching Protocols\r\n"
1845
+ "Connection: upgrade\r\n"
1846
+ "Upgrade: h2c\r\n"
1847
+ "Transfer-Encoding: chunked\r\n"
1848
+ "\r\n"
1849
+ "2\r\n"
1850
+ "bo\r\n"
1851
+ "2\r\n"
1852
+ "dy\r\n"
1853
+ "0\r\n"
1854
+ "\r\n"
1855
+ "proto"
1856
+ ,.should_keep_alive= TRUE
1857
+ ,.message_complete_on_eof= FALSE
1858
+ ,.http_major= 1
1859
+ ,.http_minor= 1
1860
+ ,.status_code= 101
1861
+ ,.response_status= "Switching Protocols"
1862
+ ,.body= "body"
1863
+ ,.upgrade= "proto"
1864
+ ,.num_headers= 3
1865
+ ,.headers=
1866
+ { { "Connection", "upgrade" }
1867
+ , { "Upgrade", "h2c" }
1868
+ , { "Transfer-Encoding", "chunked" }
1869
+ }
1870
+ ,.num_chunks_complete= 3
1871
+ ,.chunk_lengths= { 2, 2 }
1872
+ }
1873
+
1874
+ #define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER 25
1875
+ , {.name= "HTTP 200 response with Upgrade header"
1876
+ ,.type= HTTP_RESPONSE
1877
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1878
+ "Connection: upgrade\r\n"
1879
+ "Upgrade: h2c\r\n"
1880
+ "\r\n"
1881
+ "body"
1882
+ ,.should_keep_alive= FALSE
1883
+ ,.message_complete_on_eof= TRUE
1884
+ ,.http_major= 1
1885
+ ,.http_minor= 1
1886
+ ,.status_code= 200
1887
+ ,.response_status= "OK"
1888
+ ,.body= "body"
1889
+ ,.upgrade= NULL
1890
+ ,.num_headers= 2
1891
+ ,.headers=
1892
+ { { "Connection", "upgrade" }
1893
+ , { "Upgrade", "h2c" }
1894
+ }
1895
+ }
1896
+
1897
+ #define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_CONTENT_LENGTH 26
1898
+ , {.name= "HTTP 200 response with Upgrade and Content-Length header"
1899
+ ,.type= HTTP_RESPONSE
1900
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1901
+ "Connection: upgrade\r\n"
1902
+ "Upgrade: h2c\r\n"
1903
+ "Content-Length: 4\r\n"
1904
+ "\r\n"
1905
+ "body"
1906
+ ,.should_keep_alive= TRUE
1907
+ ,.message_complete_on_eof= FALSE
1908
+ ,.http_major= 1
1909
+ ,.http_minor= 1
1910
+ ,.status_code= 200
1911
+ ,.response_status= "OK"
1912
+ ,.num_headers= 3
1913
+ ,.body= "body"
1914
+ ,.upgrade= NULL
1915
+ ,.headers=
1916
+ { { "Connection", "upgrade" }
1917
+ , { "Upgrade", "h2c" }
1918
+ , { "Content-Length", "4" }
1919
+ }
1920
+ }
1921
+
1922
+ #define HTTP_200_RESPONSE_WITH_UPGRADE_HEADER_AND_TRANSFER_ENCODING 27
1923
+ , {.name= "HTTP 200 response with Upgrade and Transfer-Encoding header"
1924
+ ,.type= HTTP_RESPONSE
1925
+ ,.raw= "HTTP/1.1 200 OK\r\n"
1926
+ "Connection: upgrade\r\n"
1927
+ "Upgrade: h2c\r\n"
1928
+ "Transfer-Encoding: chunked\r\n"
1929
+ "\r\n"
1930
+ "2\r\n"
1931
+ "bo\r\n"
1932
+ "2\r\n"
1933
+ "dy\r\n"
1934
+ "0\r\n"
1935
+ "\r\n"
1936
+ ,.should_keep_alive= TRUE
1937
+ ,.message_complete_on_eof= FALSE
1938
+ ,.http_major= 1
1939
+ ,.http_minor= 1
1940
+ ,.status_code= 200
1941
+ ,.response_status= "OK"
1942
+ ,.num_headers= 3
1943
+ ,.body= "body"
1944
+ ,.upgrade= NULL
1945
+ ,.headers=
1946
+ { { "Connection", "upgrade" }
1947
+ , { "Upgrade", "h2c" }
1948
+ , { "Transfer-Encoding", "chunked" }
1949
+ }
1950
+ ,.num_chunks_complete= 3
1951
+ ,.chunk_lengths= { 2, 2 }
1952
+ }
1953
+ };
1954
+
1955
+ /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
1956
+ * define it ourselves.
1957
+ */
1958
+ size_t
1959
+ strnlen(const char *s, size_t maxlen)
1960
+ {
1961
+ const char *p;
1962
+
1963
+ p = memchr(s, '\0', maxlen);
1964
+ if (p == NULL)
1965
+ return maxlen;
1966
+
1967
+ return p - s;
1968
+ }
1969
+
1970
+ size_t
1971
+ strlncat(char *dst, size_t len, const char *src, size_t n)
1972
+ {
1973
+ size_t slen;
1974
+ size_t dlen;
1975
+ size_t rlen;
1976
+ size_t ncpy;
1977
+
1978
+ slen = strnlen(src, n);
1979
+ dlen = strnlen(dst, len);
1980
+
1981
+ if (dlen < len) {
1982
+ rlen = len - dlen;
1983
+ ncpy = slen < rlen ? slen : (rlen - 1);
1984
+ memcpy(dst + dlen, src, ncpy);
1985
+ dst[dlen + ncpy] = '\0';
1986
+ }
1987
+
1988
+ assert(len > slen + dlen);
1989
+ return slen + dlen;
1990
+ }
1991
+
1992
+ size_t
1993
+ strlncpy(char *dst, size_t len, const char *src, size_t n)
1994
+ {
1995
+ size_t slen;
1996
+ size_t ncpy;
1997
+
1998
+ slen = strnlen(src, n);
1999
+
2000
+ if (len > 0) {
2001
+ ncpy = slen < len ? slen : (len - 1);
2002
+ memcpy(dst, src, ncpy);
2003
+ dst[ncpy] = '\0';
2004
+ }
2005
+
2006
+ assert(len > slen);
2007
+ return slen;
2008
+ }
2009
+
2010
+ int
2011
+ request_url_cb (http_parser *p, const char *buf, size_t len)
2012
+ {
2013
+ assert(p == parser);
2014
+ strlncat(messages[num_messages].request_url,
2015
+ sizeof(messages[num_messages].request_url),
2016
+ buf,
2017
+ len);
2018
+ return 0;
2019
+ }
2020
+
2021
+ int
2022
+ header_field_cb (http_parser *p, const char *buf, size_t len)
2023
+ {
2024
+ assert(p == parser);
2025
+ struct message *m = &messages[num_messages];
2026
+
2027
+ if (m->last_header_element != FIELD)
2028
+ m->num_headers++;
2029
+
2030
+ strlncat(m->headers[m->num_headers-1][0],
2031
+ sizeof(m->headers[m->num_headers-1][0]),
2032
+ buf,
2033
+ len);
2034
+
2035
+ m->last_header_element = FIELD;
2036
+
2037
+ return 0;
2038
+ }
1391
2039
 
1392
2040
  int
1393
2041
  header_value_cb (http_parser *p, const char *buf, size_t len)
@@ -1395,19 +2043,39 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
1395
2043
  assert(p == parser);
1396
2044
  struct message *m = &messages[num_messages];
1397
2045
 
1398
- strncat(m->headers[m->num_headers-1][1], buf, len);
2046
+ strlncat(m->headers[m->num_headers-1][1],
2047
+ sizeof(m->headers[m->num_headers-1][1]),
2048
+ buf,
2049
+ len);
1399
2050
 
1400
2051
  m->last_header_element = VALUE;
1401
2052
 
1402
2053
  return 0;
1403
2054
  }
1404
2055
 
2056
+ void
2057
+ check_body_is_final (const http_parser *p)
2058
+ {
2059
+ if (messages[num_messages].body_is_final) {
2060
+ fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
2061
+ "on last on_body callback call "
2062
+ "but it doesn't! ***\n\n");
2063
+ assert(0);
2064
+ abort();
2065
+ }
2066
+ messages[num_messages].body_is_final = http_body_is_final(p);
2067
+ }
2068
+
1405
2069
  int
1406
2070
  body_cb (http_parser *p, const char *buf, size_t len)
1407
2071
  {
1408
2072
  assert(p == parser);
1409
- strncat(messages[num_messages].body, buf, len);
2073
+ strlncat(messages[num_messages].body,
2074
+ sizeof(messages[num_messages].body),
2075
+ buf,
2076
+ len);
1410
2077
  messages[num_messages].body_size += len;
2078
+ check_body_is_final(p);
1411
2079
  // printf("body_cb: '%s'\n", requests[num_messages].body);
1412
2080
  return 0;
1413
2081
  }
@@ -1418,6 +2086,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
1418
2086
  assert(p == parser);
1419
2087
  assert(buf);
1420
2088
  messages[num_messages].body_size += len;
2089
+ check_body_is_final(p);
1421
2090
  return 0;
1422
2091
  }
1423
2092
 
@@ -1452,8 +2121,20 @@ message_complete_cb (http_parser *p)
1452
2121
  "value in both on_message_complete and on_headers_complete "
1453
2122
  "but it doesn't! ***\n\n");
1454
2123
  assert(0);
1455
- exit(1);
2124
+ abort();
2125
+ }
2126
+
2127
+ if (messages[num_messages].body_size &&
2128
+ http_body_is_final(p) &&
2129
+ !messages[num_messages].body_is_final)
2130
+ {
2131
+ fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
2132
+ "on last on_body callback call "
2133
+ "but it doesn't! ***\n\n");
2134
+ assert(0);
2135
+ abort();
1456
2136
  }
2137
+
1457
2138
  messages[num_messages].message_complete_cb_called = TRUE;
1458
2139
 
1459
2140
  messages[num_messages].message_complete_on_eof = currently_parsing_eof;
@@ -1462,6 +2143,49 @@ message_complete_cb (http_parser *p)
1462
2143
  return 0;
1463
2144
  }
1464
2145
 
2146
+ int
2147
+ response_status_cb (http_parser *p, const char *buf, size_t len)
2148
+ {
2149
+ assert(p == parser);
2150
+
2151
+ messages[num_messages].status_cb_called = TRUE;
2152
+
2153
+ strlncat(messages[num_messages].response_status,
2154
+ sizeof(messages[num_messages].response_status),
2155
+ buf,
2156
+ len);
2157
+ return 0;
2158
+ }
2159
+
2160
+ int
2161
+ chunk_header_cb (http_parser *p)
2162
+ {
2163
+ assert(p == parser);
2164
+ int chunk_idx = messages[num_messages].num_chunks;
2165
+ messages[num_messages].num_chunks++;
2166
+ if (chunk_idx < MAX_CHUNKS) {
2167
+ messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
2168
+ }
2169
+
2170
+ return 0;
2171
+ }
2172
+
2173
+ int
2174
+ chunk_complete_cb (http_parser *p)
2175
+ {
2176
+ assert(p == parser);
2177
+
2178
+ /* Here we want to verify that each chunk_header_cb is matched by a
2179
+ * chunk_complete_cb, so not only should the total number of calls to
2180
+ * both callbacks be the same, but they also should be interleaved
2181
+ * properly */
2182
+ assert(messages[num_messages].num_chunks ==
2183
+ messages[num_messages].num_chunks_complete + 1);
2184
+
2185
+ messages[num_messages].num_chunks_complete++;
2186
+ return 0;
2187
+ }
2188
+
1465
2189
  /* These dontcall_* callbacks exist so that we can verify that when we're
1466
2190
  * paused, no additional callbacks are invoked */
1467
2191
  int
@@ -1469,7 +2193,7 @@ dontcall_message_begin_cb (http_parser *p)
1469
2193
  {
1470
2194
  if (p) { } // gcc
1471
2195
  fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
1472
- exit(1);
2196
+ abort();
1473
2197
  }
1474
2198
 
1475
2199
  int
@@ -1477,7 +2201,7 @@ dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
1477
2201
  {
1478
2202
  if (p || buf || len) { } // gcc
1479
2203
  fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
1480
- exit(1);
2204
+ abort();
1481
2205
  }
1482
2206
 
1483
2207
  int
@@ -1485,7 +2209,7 @@ dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
1485
2209
  {
1486
2210
  if (p || buf || len) { } // gcc
1487
2211
  fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
1488
- exit(1);
2212
+ abort();
1489
2213
  }
1490
2214
 
1491
2215
  int
@@ -1493,7 +2217,7 @@ dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
1493
2217
  {
1494
2218
  if (p || buf || len) { } // gcc
1495
2219
  fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
1496
- exit(1);
2220
+ abort();
1497
2221
  }
1498
2222
 
1499
2223
  int
@@ -1501,7 +2225,7 @@ dontcall_body_cb (http_parser *p, const char *buf, size_t len)
1501
2225
  {
1502
2226
  if (p || buf || len) { } // gcc
1503
2227
  fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
1504
- exit(1);
2228
+ abort();
1505
2229
  }
1506
2230
 
1507
2231
  int
@@ -1510,7 +2234,7 @@ dontcall_headers_complete_cb (http_parser *p)
1510
2234
  if (p) { } // gcc
1511
2235
  fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
1512
2236
  "parser ***\n\n");
1513
- exit(1);
2237
+ abort();
1514
2238
  }
1515
2239
 
1516
2240
  int
@@ -1519,6 +2243,31 @@ dontcall_message_complete_cb (http_parser *p)
1519
2243
  if (p) { } // gcc
1520
2244
  fprintf(stderr, "\n\n*** on_message_complete() called on paused "
1521
2245
  "parser ***\n\n");
2246
+ abort();
2247
+ }
2248
+
2249
+ int
2250
+ dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
2251
+ {
2252
+ if (p || buf || len) { } // gcc
2253
+ fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
2254
+ abort();
2255
+ }
2256
+
2257
+ int
2258
+ dontcall_chunk_header_cb (http_parser *p)
2259
+ {
2260
+ if (p) { } // gcc
2261
+ fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
2262
+ exit(1);
2263
+ }
2264
+
2265
+ int
2266
+ dontcall_chunk_complete_cb (http_parser *p)
2267
+ {
2268
+ if (p) { } // gcc
2269
+ fprintf(stderr, "\n\n*** on_chunk_complete() "
2270
+ "called on paused parser ***\n\n");
1522
2271
  exit(1);
1523
2272
  }
1524
2273
 
@@ -1527,9 +2276,12 @@ static http_parser_settings settings_dontcall =
1527
2276
  ,.on_header_field = dontcall_header_field_cb
1528
2277
  ,.on_header_value = dontcall_header_value_cb
1529
2278
  ,.on_url = dontcall_request_url_cb
2279
+ ,.on_status = dontcall_response_status_cb
1530
2280
  ,.on_body = dontcall_body_cb
1531
2281
  ,.on_headers_complete = dontcall_headers_complete_cb
1532
2282
  ,.on_message_complete = dontcall_message_complete_cb
2283
+ ,.on_chunk_header = dontcall_chunk_header_cb
2284
+ ,.on_chunk_complete = dontcall_chunk_complete_cb
1533
2285
  };
1534
2286
 
1535
2287
  /* These pause_* callbacks always pause the parser and just invoke the regular
@@ -1592,14 +2344,55 @@ pause_message_complete_cb (http_parser *p)
1592
2344
  return message_complete_cb(p);
1593
2345
  }
1594
2346
 
2347
+ int
2348
+ pause_response_status_cb (http_parser *p, const char *buf, size_t len)
2349
+ {
2350
+ http_parser_pause(p, 1);
2351
+ *current_pause_parser = settings_dontcall;
2352
+ return response_status_cb(p, buf, len);
2353
+ }
2354
+
2355
+ int
2356
+ pause_chunk_header_cb (http_parser *p)
2357
+ {
2358
+ http_parser_pause(p, 1);
2359
+ *current_pause_parser = settings_dontcall;
2360
+ return chunk_header_cb(p);
2361
+ }
2362
+
2363
+ int
2364
+ pause_chunk_complete_cb (http_parser *p)
2365
+ {
2366
+ http_parser_pause(p, 1);
2367
+ *current_pause_parser = settings_dontcall;
2368
+ return chunk_complete_cb(p);
2369
+ }
2370
+
2371
+ int
2372
+ connect_headers_complete_cb (http_parser *p)
2373
+ {
2374
+ headers_complete_cb(p);
2375
+ return 1;
2376
+ }
2377
+
2378
+ int
2379
+ connect_message_complete_cb (http_parser *p)
2380
+ {
2381
+ messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
2382
+ return message_complete_cb(p);
2383
+ }
2384
+
1595
2385
  static http_parser_settings settings_pause =
1596
2386
  {.on_message_begin = pause_message_begin_cb
1597
2387
  ,.on_header_field = pause_header_field_cb
1598
2388
  ,.on_header_value = pause_header_value_cb
1599
2389
  ,.on_url = pause_request_url_cb
2390
+ ,.on_status = pause_response_status_cb
1600
2391
  ,.on_body = pause_body_cb
1601
2392
  ,.on_headers_complete = pause_headers_complete_cb
1602
2393
  ,.on_message_complete = pause_message_complete_cb
2394
+ ,.on_chunk_header = pause_chunk_header_cb
2395
+ ,.on_chunk_complete = pause_chunk_complete_cb
1603
2396
  };
1604
2397
 
1605
2398
  static http_parser_settings settings =
@@ -1607,9 +2400,12 @@ static http_parser_settings settings =
1607
2400
  ,.on_header_field = header_field_cb
1608
2401
  ,.on_header_value = header_value_cb
1609
2402
  ,.on_url = request_url_cb
2403
+ ,.on_status = response_status_cb
1610
2404
  ,.on_body = body_cb
1611
2405
  ,.on_headers_complete = headers_complete_cb
1612
2406
  ,.on_message_complete = message_complete_cb
2407
+ ,.on_chunk_header = chunk_header_cb
2408
+ ,.on_chunk_complete = chunk_complete_cb
1613
2409
  };
1614
2410
 
1615
2411
  static http_parser_settings settings_count_body =
@@ -1617,9 +2413,25 @@ static http_parser_settings settings_count_body =
1617
2413
  ,.on_header_field = header_field_cb
1618
2414
  ,.on_header_value = header_value_cb
1619
2415
  ,.on_url = request_url_cb
2416
+ ,.on_status = response_status_cb
1620
2417
  ,.on_body = count_body_cb
1621
2418
  ,.on_headers_complete = headers_complete_cb
1622
2419
  ,.on_message_complete = message_complete_cb
2420
+ ,.on_chunk_header = chunk_header_cb
2421
+ ,.on_chunk_complete = chunk_complete_cb
2422
+ };
2423
+
2424
+ static http_parser_settings settings_connect =
2425
+ {.on_message_begin = message_begin_cb
2426
+ ,.on_header_field = header_field_cb
2427
+ ,.on_header_value = header_value_cb
2428
+ ,.on_url = request_url_cb
2429
+ ,.on_status = response_status_cb
2430
+ ,.on_body = dontcall_body_cb
2431
+ ,.on_headers_complete = connect_headers_complete_cb
2432
+ ,.on_message_complete = connect_message_complete_cb
2433
+ ,.on_chunk_header = chunk_header_cb
2434
+ ,.on_chunk_complete = chunk_complete_cb
1623
2435
  };
1624
2436
 
1625
2437
  static http_parser_settings settings_null =
@@ -1627,9 +2439,12 @@ static http_parser_settings settings_null =
1627
2439
  ,.on_header_field = 0
1628
2440
  ,.on_header_value = 0
1629
2441
  ,.on_url = 0
2442
+ ,.on_status = 0
1630
2443
  ,.on_body = 0
1631
2444
  ,.on_headers_complete = 0
1632
2445
  ,.on_message_complete = 0
2446
+ ,.on_chunk_header = 0
2447
+ ,.on_chunk_complete = 0
1633
2448
  };
1634
2449
 
1635
2450
  void
@@ -1682,6 +2497,14 @@ size_t parse_pause (const char *buf, size_t len)
1682
2497
  return nparsed;
1683
2498
  }
1684
2499
 
2500
+ size_t parse_connect (const char *buf, size_t len)
2501
+ {
2502
+ size_t nparsed;
2503
+ currently_parsing_eof = (len == 0);
2504
+ nparsed = http_parser_execute(parser, &settings_connect, buf, len);
2505
+ return nparsed;
2506
+ }
2507
+
1685
2508
  static inline int
1686
2509
  check_str_eq (const struct message *m,
1687
2510
  const char *prop,
@@ -1738,7 +2561,7 @@ do { \
1738
2561
  } while(0)
1739
2562
 
1740
2563
  int
1741
- message_eq (int index, const struct message *expected)
2564
+ message_eq (int index, int connect, const struct message *expected)
1742
2565
  {
1743
2566
  int i;
1744
2567
  struct message *m = &messages[index];
@@ -1750,10 +2573,14 @@ message_eq (int index, const struct message *expected)
1750
2573
  MESSAGE_CHECK_NUM_EQ(expected, m, method);
1751
2574
  } else {
1752
2575
  MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
2576
+ MESSAGE_CHECK_STR_EQ(expected, m, response_status);
2577
+ assert(m->status_cb_called);
1753
2578
  }
1754
2579
 
1755
- MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
1756
- MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
2580
+ if (!connect) {
2581
+ MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
2582
+ MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
2583
+ }
1757
2584
 
1758
2585
  assert(m->message_begin_cb_called);
1759
2586
  assert(m->headers_complete_cb_called);
@@ -1771,7 +2598,15 @@ message_eq (int index, const struct message *expected)
1771
2598
  if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
1772
2599
  fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
1773
2600
  m->request_url);
1774
- exit(1);
2601
+ abort();
2602
+ }
2603
+
2604
+ if (expected->host) {
2605
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
2606
+ }
2607
+
2608
+ if (expected->userinfo) {
2609
+ MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
1775
2610
  }
1776
2611
 
1777
2612
  m->port = (u.field_set & (1 << UF_PORT)) ?
@@ -1783,12 +2618,24 @@ message_eq (int index, const struct message *expected)
1783
2618
  MESSAGE_CHECK_NUM_EQ(expected, m, port);
1784
2619
  }
1785
2620
 
1786
- if (expected->body_size) {
2621
+ if (connect) {
2622
+ check_num_eq(m, "body_size", 0, m->body_size);
2623
+ } else if (expected->body_size) {
1787
2624
  MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
1788
2625
  } else {
1789
2626
  MESSAGE_CHECK_STR_EQ(expected, m, body);
1790
2627
  }
1791
2628
 
2629
+ if (connect) {
2630
+ check_num_eq(m, "num_chunks_complete", 0, m->num_chunks_complete);
2631
+ } else {
2632
+ assert(m->num_chunks == m->num_chunks_complete);
2633
+ MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
2634
+ for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
2635
+ MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
2636
+ }
2637
+ }
2638
+
1792
2639
  MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
1793
2640
 
1794
2641
  int r;
@@ -1799,7 +2646,9 @@ message_eq (int index, const struct message *expected)
1799
2646
  if (!r) return 0;
1800
2647
  }
1801
2648
 
1802
- MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
2649
+ if (!connect) {
2650
+ MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
2651
+ }
1803
2652
 
1804
2653
  return 1;
1805
2654
  }
@@ -1836,7 +2685,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
1836
2685
  va_list ap;
1837
2686
  size_t i;
1838
2687
  size_t off = 0;
1839
-
2688
+
1840
2689
  va_start(ap, nmsgs);
1841
2690
 
1842
2691
  for (i = 0; i < nmsgs; i++) {
@@ -1849,7 +2698,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
1849
2698
 
1850
2699
  /* Check the portion of the response after its specified upgrade */
1851
2700
  if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
1852
- exit(1);
2701
+ abort();
1853
2702
  }
1854
2703
 
1855
2704
  /* Fix up the response so that message_eq() will verify the beginning
@@ -1865,14 +2714,13 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
1865
2714
  va_end(ap);
1866
2715
  printf("\n\n*** Error: expected a message with upgrade ***\n");
1867
2716
 
1868
- exit(1);
2717
+ abort();
1869
2718
  }
1870
2719
 
1871
2720
  static void
1872
2721
  print_error (const char *raw, size_t error_location)
1873
2722
  {
1874
- fprintf(stderr, "\n*** %s:%d -- %s ***\n\n",
1875
- "http_parser.c", HTTP_PARSER_ERRNO_LINE(parser),
2723
+ fprintf(stderr, "\n*** %s ***\n\n",
1876
2724
  http_errno_description(HTTP_PARSER_ERRNO(parser)));
1877
2725
 
1878
2726
  int this_line = 0, char_len = 0;
@@ -1886,7 +2734,6 @@ print_error (const char *raw, size_t error_location)
1886
2734
  break;
1887
2735
 
1888
2736
  case '\n':
1889
- char_len = 2;
1890
2737
  fprintf(stderr, "\\n\n");
1891
2738
 
1892
2739
  if (this_line) goto print;
@@ -1920,7 +2767,7 @@ test_preserve_data (void)
1920
2767
  http_parser_init(&parser, HTTP_REQUEST);
1921
2768
  if (parser.data != my_data) {
1922
2769
  printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
1923
- exit(1);
2770
+ abort();
1924
2771
  }
1925
2772
  }
1926
2773
 
@@ -1937,127 +2784,539 @@ const struct url_test url_tests[] =
1937
2784
  ,.url="http://hostname/"
1938
2785
  ,.is_connect=0
1939
2786
  ,.u=
1940
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2787
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2788
+ ,.port=0
2789
+ ,.field_data=
2790
+ {{ 0, 4 } /* UF_SCHEMA */
2791
+ ,{ 7, 8 } /* UF_HOST */
2792
+ ,{ 0, 0 } /* UF_PORT */
2793
+ ,{ 15, 1 } /* UF_PATH */
2794
+ ,{ 0, 0 } /* UF_QUERY */
2795
+ ,{ 0, 0 } /* UF_FRAGMENT */
2796
+ ,{ 0, 0 } /* UF_USERINFO */
2797
+ }
2798
+ }
2799
+ ,.rv=0
2800
+ }
2801
+
2802
+ , {.name="proxy request with port"
2803
+ ,.url="http://hostname:444/"
2804
+ ,.is_connect=0
2805
+ ,.u=
2806
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2807
+ ,.port=444
2808
+ ,.field_data=
2809
+ {{ 0, 4 } /* UF_SCHEMA */
2810
+ ,{ 7, 8 } /* UF_HOST */
2811
+ ,{ 16, 3 } /* UF_PORT */
2812
+ ,{ 19, 1 } /* UF_PATH */
2813
+ ,{ 0, 0 } /* UF_QUERY */
2814
+ ,{ 0, 0 } /* UF_FRAGMENT */
2815
+ ,{ 0, 0 } /* UF_USERINFO */
2816
+ }
2817
+ }
2818
+ ,.rv=0
2819
+ }
2820
+
2821
+ , {.name="CONNECT request"
2822
+ ,.url="hostname:443"
2823
+ ,.is_connect=1
2824
+ ,.u=
2825
+ {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2826
+ ,.port=443
2827
+ ,.field_data=
2828
+ {{ 0, 0 } /* UF_SCHEMA */
2829
+ ,{ 0, 8 } /* UF_HOST */
2830
+ ,{ 9, 3 } /* UF_PORT */
2831
+ ,{ 0, 0 } /* UF_PATH */
2832
+ ,{ 0, 0 } /* UF_QUERY */
2833
+ ,{ 0, 0 } /* UF_FRAGMENT */
2834
+ ,{ 0, 0 } /* UF_USERINFO */
2835
+ }
2836
+ }
2837
+ ,.rv=0
2838
+ }
2839
+
2840
+ , {.name="CONNECT request but not connect"
2841
+ ,.url="hostname:443"
2842
+ ,.is_connect=0
2843
+ ,.rv=1
2844
+ }
2845
+
2846
+ , {.name="proxy ipv6 request"
2847
+ ,.url="http://[1:2::3:4]/"
2848
+ ,.is_connect=0
2849
+ ,.u=
2850
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2851
+ ,.port=0
2852
+ ,.field_data=
2853
+ {{ 0, 4 } /* UF_SCHEMA */
2854
+ ,{ 8, 8 } /* UF_HOST */
2855
+ ,{ 0, 0 } /* UF_PORT */
2856
+ ,{ 17, 1 } /* UF_PATH */
2857
+ ,{ 0, 0 } /* UF_QUERY */
2858
+ ,{ 0, 0 } /* UF_FRAGMENT */
2859
+ ,{ 0, 0 } /* UF_USERINFO */
2860
+ }
2861
+ }
2862
+ ,.rv=0
2863
+ }
2864
+
2865
+ , {.name="proxy ipv6 request with port"
2866
+ ,.url="http://[1:2::3:4]:67/"
2867
+ ,.is_connect=0
2868
+ ,.u=
2869
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
2870
+ ,.port=67
2871
+ ,.field_data=
2872
+ {{ 0, 4 } /* UF_SCHEMA */
2873
+ ,{ 8, 8 } /* UF_HOST */
2874
+ ,{ 18, 2 } /* UF_PORT */
2875
+ ,{ 20, 1 } /* UF_PATH */
2876
+ ,{ 0, 0 } /* UF_QUERY */
2877
+ ,{ 0, 0 } /* UF_FRAGMENT */
2878
+ ,{ 0, 0 } /* UF_USERINFO */
2879
+ }
2880
+ }
2881
+ ,.rv=0
2882
+ }
2883
+
2884
+ , {.name="CONNECT ipv6 address"
2885
+ ,.url="[1:2::3:4]:443"
2886
+ ,.is_connect=1
2887
+ ,.u=
2888
+ {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
2889
+ ,.port=443
2890
+ ,.field_data=
2891
+ {{ 0, 0 } /* UF_SCHEMA */
2892
+ ,{ 1, 8 } /* UF_HOST */
2893
+ ,{ 11, 3 } /* UF_PORT */
2894
+ ,{ 0, 0 } /* UF_PATH */
2895
+ ,{ 0, 0 } /* UF_QUERY */
2896
+ ,{ 0, 0 } /* UF_FRAGMENT */
2897
+ ,{ 0, 0 } /* UF_USERINFO */
2898
+ }
2899
+ }
2900
+ ,.rv=0
2901
+ }
2902
+
2903
+ , {.name="ipv4 in ipv6 address"
2904
+ ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
2905
+ ,.is_connect=0
2906
+ ,.u=
2907
+ {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
2908
+ ,.port=0
2909
+ ,.field_data=
2910
+ {{ 0, 4 } /* UF_SCHEMA */
2911
+ ,{ 8, 37 } /* UF_HOST */
2912
+ ,{ 0, 0 } /* UF_PORT */
2913
+ ,{ 46, 1 } /* UF_PATH */
2914
+ ,{ 0, 0 } /* UF_QUERY */
2915
+ ,{ 0, 0 } /* UF_FRAGMENT */
2916
+ ,{ 0, 0 } /* UF_USERINFO */
2917
+ }
2918
+ }
2919
+ ,.rv=0
2920
+ }
2921
+
2922
+ , {.name="extra ? in query string"
2923
+ ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
2924
+ "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
2925
+ "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
2926
+ ,.is_connect=0
2927
+ ,.u=
2928
+ {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
2929
+ ,.port=0
2930
+ ,.field_data=
2931
+ {{ 0, 4 } /* UF_SCHEMA */
2932
+ ,{ 7, 10 } /* UF_HOST */
2933
+ ,{ 0, 0 } /* UF_PORT */
2934
+ ,{ 17, 12 } /* UF_PATH */
2935
+ ,{ 30,187 } /* UF_QUERY */
2936
+ ,{ 0, 0 } /* UF_FRAGMENT */
2937
+ ,{ 0, 0 } /* UF_USERINFO */
2938
+ }
2939
+ }
2940
+ ,.rv=0
2941
+ }
2942
+
2943
+ , {.name="space URL encoded"
2944
+ ,.url="/toto.html?toto=a%20b"
2945
+ ,.is_connect=0
2946
+ ,.u=
2947
+ {.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
2948
+ ,.port=0
2949
+ ,.field_data=
2950
+ {{ 0, 0 } /* UF_SCHEMA */
2951
+ ,{ 0, 0 } /* UF_HOST */
2952
+ ,{ 0, 0 } /* UF_PORT */
2953
+ ,{ 0, 10 } /* UF_PATH */
2954
+ ,{ 11, 10 } /* UF_QUERY */
2955
+ ,{ 0, 0 } /* UF_FRAGMENT */
2956
+ ,{ 0, 0 } /* UF_USERINFO */
2957
+ }
2958
+ }
2959
+ ,.rv=0
2960
+ }
2961
+
2962
+
2963
+ , {.name="URL fragment"
2964
+ ,.url="/toto.html#titi"
2965
+ ,.is_connect=0
2966
+ ,.u=
2967
+ {.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
2968
+ ,.port=0
2969
+ ,.field_data=
2970
+ {{ 0, 0 } /* UF_SCHEMA */
2971
+ ,{ 0, 0 } /* UF_HOST */
2972
+ ,{ 0, 0 } /* UF_PORT */
2973
+ ,{ 0, 10 } /* UF_PATH */
2974
+ ,{ 0, 0 } /* UF_QUERY */
2975
+ ,{ 11, 4 } /* UF_FRAGMENT */
2976
+ ,{ 0, 0 } /* UF_USERINFO */
2977
+ }
2978
+ }
2979
+ ,.rv=0
2980
+ }
2981
+
2982
+ , {.name="complex URL fragment"
2983
+ ,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
2984
+ "http://www.example.com/index.html?foo=bar&hello=world#midpage"
2985
+ ,.is_connect=0
2986
+ ,.u=
2987
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
2988
+ (1<<UF_FRAGMENT)
2989
+ ,.port=0
2990
+ ,.field_data=
2991
+ {{ 0, 4 } /* UF_SCHEMA */
2992
+ ,{ 7, 22 } /* UF_HOST */
2993
+ ,{ 0, 0 } /* UF_PORT */
2994
+ ,{ 29, 6 } /* UF_PATH */
2995
+ ,{ 36, 69 } /* UF_QUERY */
2996
+ ,{106, 7 } /* UF_FRAGMENT */
2997
+ ,{ 0, 0 } /* UF_USERINFO */
2998
+ }
2999
+ }
3000
+ ,.rv=0
3001
+ }
3002
+
3003
+ , {.name="complex URL from node js url parser doc"
3004
+ ,.url="http://host.com:8080/p/a/t/h?query=string#hash"
3005
+ ,.is_connect=0
3006
+ ,.u=
3007
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
3008
+ (1<<UF_QUERY) | (1<<UF_FRAGMENT)
3009
+ ,.port=8080
3010
+ ,.field_data=
3011
+ {{ 0, 4 } /* UF_SCHEMA */
3012
+ ,{ 7, 8 } /* UF_HOST */
3013
+ ,{ 16, 4 } /* UF_PORT */
3014
+ ,{ 20, 8 } /* UF_PATH */
3015
+ ,{ 29, 12 } /* UF_QUERY */
3016
+ ,{ 42, 4 } /* UF_FRAGMENT */
3017
+ ,{ 0, 0 } /* UF_USERINFO */
3018
+ }
3019
+ }
3020
+ ,.rv=0
3021
+ }
3022
+
3023
+ , {.name="complex URL with basic auth from node js url parser doc"
3024
+ ,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
3025
+ ,.is_connect=0
3026
+ ,.u=
3027
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
3028
+ (1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
3029
+ ,.port=8080
3030
+ ,.field_data=
3031
+ {{ 0, 4 } /* UF_SCHEMA */
3032
+ ,{ 11, 8 } /* UF_HOST */
3033
+ ,{ 20, 4 } /* UF_PORT */
3034
+ ,{ 24, 8 } /* UF_PATH */
3035
+ ,{ 33, 12 } /* UF_QUERY */
3036
+ ,{ 46, 4 } /* UF_FRAGMENT */
3037
+ ,{ 7, 3 } /* UF_USERINFO */
3038
+ }
3039
+ }
3040
+ ,.rv=0
3041
+ }
3042
+
3043
+ , {.name="double @"
3044
+ ,.url="http://a:b@@hostname:443/"
3045
+ ,.is_connect=0
3046
+ ,.rv=1
3047
+ }
3048
+
3049
+ , {.name="proxy empty host"
3050
+ ,.url="http://:443/"
3051
+ ,.is_connect=0
3052
+ ,.rv=1
3053
+ }
3054
+
3055
+ , {.name="proxy empty port"
3056
+ ,.url="http://hostname:/"
3057
+ ,.is_connect=0
3058
+ ,.rv=1
3059
+ }
3060
+
3061
+ , {.name="CONNECT with basic auth"
3062
+ ,.url="a:b@hostname:443"
3063
+ ,.is_connect=1
3064
+ ,.rv=1
3065
+ }
3066
+
3067
+ , {.name="CONNECT empty host"
3068
+ ,.url=":443"
3069
+ ,.is_connect=1
3070
+ ,.rv=1
3071
+ }
3072
+
3073
+ , {.name="CONNECT empty port"
3074
+ ,.url="hostname:"
3075
+ ,.is_connect=1
3076
+ ,.rv=1
3077
+ }
3078
+
3079
+ , {.name="CONNECT with extra bits"
3080
+ ,.url="hostname:443/"
3081
+ ,.is_connect=1
3082
+ ,.rv=1
3083
+ }
3084
+
3085
+ , {.name="space in URL"
3086
+ ,.url="/foo bar/"
3087
+ ,.rv=1 /* s_dead */
3088
+ }
3089
+
3090
+ , {.name="proxy basic auth with space url encoded"
3091
+ ,.url="http://a%20:b@host.com/"
3092
+ ,.is_connect=0
3093
+ ,.u=
3094
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
3095
+ ,.port=0
3096
+ ,.field_data=
3097
+ {{ 0, 4 } /* UF_SCHEMA */
3098
+ ,{ 14, 8 } /* UF_HOST */
3099
+ ,{ 0, 0 } /* UF_PORT */
3100
+ ,{ 22, 1 } /* UF_PATH */
3101
+ ,{ 0, 0 } /* UF_QUERY */
3102
+ ,{ 0, 0 } /* UF_FRAGMENT */
3103
+ ,{ 7, 6 } /* UF_USERINFO */
3104
+ }
3105
+ }
3106
+ ,.rv=0
3107
+ }
3108
+
3109
+ , {.name="carriage return in URL"
3110
+ ,.url="/foo\rbar/"
3111
+ ,.rv=1 /* s_dead */
3112
+ }
3113
+
3114
+ , {.name="proxy double : in URL"
3115
+ ,.url="http://hostname::443/"
3116
+ ,.rv=1 /* s_dead */
3117
+ }
3118
+
3119
+ , {.name="proxy basic auth with double :"
3120
+ ,.url="http://a::b@host.com/"
3121
+ ,.is_connect=0
3122
+ ,.u=
3123
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
3124
+ ,.port=0
3125
+ ,.field_data=
3126
+ {{ 0, 4 } /* UF_SCHEMA */
3127
+ ,{ 12, 8 } /* UF_HOST */
3128
+ ,{ 0, 0 } /* UF_PORT */
3129
+ ,{ 20, 1 } /* UF_PATH */
3130
+ ,{ 0, 0 } /* UF_QUERY */
3131
+ ,{ 0, 0 } /* UF_FRAGMENT */
3132
+ ,{ 7, 4 } /* UF_USERINFO */
3133
+ }
3134
+ }
3135
+ ,.rv=0
3136
+ }
3137
+
3138
+ , {.name="line feed in URL"
3139
+ ,.url="/foo\nbar/"
3140
+ ,.rv=1 /* s_dead */
3141
+ }
3142
+
3143
+ , {.name="proxy empty basic auth"
3144
+ ,.url="http://@hostname/fo"
3145
+ ,.u=
3146
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
3147
+ ,.port=0
3148
+ ,.field_data=
3149
+ {{ 0, 4 } /* UF_SCHEMA */
3150
+ ,{ 8, 8 } /* UF_HOST */
3151
+ ,{ 0, 0 } /* UF_PORT */
3152
+ ,{ 16, 3 } /* UF_PATH */
3153
+ ,{ 0, 0 } /* UF_QUERY */
3154
+ ,{ 0, 0 } /* UF_FRAGMENT */
3155
+ ,{ 0, 0 } /* UF_USERINFO */
3156
+ }
3157
+ }
3158
+ ,.rv=0
3159
+ }
3160
+ , {.name="proxy line feed in hostname"
3161
+ ,.url="http://host\name/fo"
3162
+ ,.rv=1 /* s_dead */
3163
+ }
3164
+
3165
+ , {.name="proxy % in hostname"
3166
+ ,.url="http://host%name/fo"
3167
+ ,.rv=1 /* s_dead */
3168
+ }
3169
+
3170
+ , {.name="proxy ; in hostname"
3171
+ ,.url="http://host;ame/fo"
3172
+ ,.rv=1 /* s_dead */
3173
+ }
3174
+
3175
+ , {.name="proxy basic auth with unreservedchars"
3176
+ ,.url="http://a!;-_!=+$@host.com/"
3177
+ ,.is_connect=0
3178
+ ,.u=
3179
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
1941
3180
  ,.port=0
1942
3181
  ,.field_data=
1943
3182
  {{ 0, 4 } /* UF_SCHEMA */
1944
- ,{ 7, 8 } /* UF_HOST */
3183
+ ,{ 17, 8 } /* UF_HOST */
1945
3184
  ,{ 0, 0 } /* UF_PORT */
1946
- ,{ 15, 1 } /* UF_PATH */
3185
+ ,{ 25, 1 } /* UF_PATH */
1947
3186
  ,{ 0, 0 } /* UF_QUERY */
1948
3187
  ,{ 0, 0 } /* UF_FRAGMENT */
3188
+ ,{ 7, 9 } /* UF_USERINFO */
1949
3189
  }
1950
3190
  }
1951
3191
  ,.rv=0
1952
3192
  }
1953
3193
 
1954
- , {.name="CONNECT request"
1955
- ,.url="hostname:443"
1956
- ,.is_connect=1
3194
+ , {.name="proxy only empty basic auth"
3195
+ ,.url="http://@/fo"
3196
+ ,.rv=1 /* s_dead */
3197
+ }
3198
+
3199
+ , {.name="proxy only basic auth"
3200
+ ,.url="http://toto@/fo"
3201
+ ,.rv=1 /* s_dead */
3202
+ }
3203
+
3204
+ , {.name="proxy emtpy hostname"
3205
+ ,.url="http:///fo"
3206
+ ,.rv=1 /* s_dead */
3207
+ }
3208
+
3209
+ , {.name="proxy = in URL"
3210
+ ,.url="http://host=ame/fo"
3211
+ ,.rv=1 /* s_dead */
3212
+ }
3213
+
3214
+ , {.name="ipv6 address with Zone ID"
3215
+ ,.url="http://[fe80::a%25eth0]/"
3216
+ ,.is_connect=0
1957
3217
  ,.u=
1958
- {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
1959
- ,.port=443
3218
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
3219
+ ,.port=0
1960
3220
  ,.field_data=
1961
- {{ 0, 0 } /* UF_SCHEMA */
1962
- ,{ 0, 8 } /* UF_HOST */
1963
- ,{ 9, 3 } /* UF_PORT */
1964
- ,{ 0, 0 } /* UF_PATH */
3221
+ {{ 0, 4 } /* UF_SCHEMA */
3222
+ ,{ 8, 14 } /* UF_HOST */
3223
+ ,{ 0, 0 } /* UF_PORT */
3224
+ ,{ 23, 1 } /* UF_PATH */
1965
3225
  ,{ 0, 0 } /* UF_QUERY */
1966
3226
  ,{ 0, 0 } /* UF_FRAGMENT */
3227
+ ,{ 0, 0 } /* UF_USERINFO */
1967
3228
  }
1968
3229
  }
1969
3230
  ,.rv=0
1970
3231
  }
1971
3232
 
1972
- , {.name="proxy ipv6 request"
1973
- ,.url="http://[1:2::3:4]/"
3233
+ , {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
3234
+ ,.url="http://[fe80::a%eth0]/"
1974
3235
  ,.is_connect=0
1975
3236
  ,.u=
1976
- {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
3237
+ {.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
1977
3238
  ,.port=0
1978
3239
  ,.field_data=
1979
3240
  {{ 0, 4 } /* UF_SCHEMA */
1980
- ,{ 8, 8 } /* UF_HOST */
3241
+ ,{ 8, 12 } /* UF_HOST */
1981
3242
  ,{ 0, 0 } /* UF_PORT */
1982
- ,{ 17, 1 } /* UF_PATH */
3243
+ ,{ 21, 1 } /* UF_PATH */
1983
3244
  ,{ 0, 0 } /* UF_QUERY */
1984
3245
  ,{ 0, 0 } /* UF_FRAGMENT */
3246
+ ,{ 0, 0 } /* UF_USERINFO */
1985
3247
  }
1986
3248
  }
1987
3249
  ,.rv=0
1988
3250
  }
1989
3251
 
1990
- , {.name="CONNECT ipv6 address"
1991
- ,.url="[1:2::3:4]:443"
1992
- ,.is_connect=1
3252
+ , {.name="ipv6 address ending with '%'"
3253
+ ,.url="http://[fe80::a%]/"
3254
+ ,.rv=1 /* s_dead */
3255
+ }
3256
+
3257
+ , {.name="ipv6 address with Zone ID including bad character"
3258
+ ,.url="http://[fe80::a%$HOME]/"
3259
+ ,.rv=1 /* s_dead */
3260
+ }
3261
+
3262
+ , {.name="just ipv6 Zone ID"
3263
+ ,.url="http://[%eth0]/"
3264
+ ,.rv=1 /* s_dead */
3265
+ }
3266
+
3267
+ #if HTTP_PARSER_STRICT
3268
+
3269
+ , {.name="tab in URL"
3270
+ ,.url="/foo\tbar/"
3271
+ ,.rv=1 /* s_dead */
3272
+ }
3273
+
3274
+ , {.name="form feed in URL"
3275
+ ,.url="/foo\fbar/"
3276
+ ,.rv=1 /* s_dead */
3277
+ }
3278
+
3279
+ #else /* !HTTP_PARSER_STRICT */
3280
+
3281
+ , {.name="tab in URL"
3282
+ ,.url="/foo\tbar/"
1993
3283
  ,.u=
1994
- {.field_set=(1 << UF_HOST) | (1 << UF_PORT)
1995
- ,.port=443
3284
+ {.field_set=(1 << UF_PATH)
1996
3285
  ,.field_data=
1997
3286
  {{ 0, 0 } /* UF_SCHEMA */
1998
- ,{ 1, 8 } /* UF_HOST */
1999
- ,{ 11, 3 } /* UF_PORT */
2000
- ,{ 0, 0 } /* UF_PATH */
3287
+ ,{ 0, 0 } /* UF_HOST */
3288
+ ,{ 0, 0 } /* UF_PORT */
3289
+ ,{ 0, 9 } /* UF_PATH */
2001
3290
  ,{ 0, 0 } /* UF_QUERY */
2002
3291
  ,{ 0, 0 } /* UF_FRAGMENT */
3292
+ ,{ 0, 0 } /* UF_USERINFO */
2003
3293
  }
2004
3294
  }
2005
3295
  ,.rv=0
2006
3296
  }
2007
3297
 
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
3298
+ , {.name="form feed in URL"
3299
+ ,.url="/foo\fbar/"
2011
3300
  ,.u=
2012
- {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
2013
- ,.port=0
3301
+ {.field_set=(1 << UF_PATH)
2014
3302
  ,.field_data=
2015
- {{ 0, 4 } /* UF_SCHEMA */
2016
- ,{ 7, 10 } /* UF_HOST */
3303
+ {{ 0, 0 } /* UF_SCHEMA */
3304
+ ,{ 0, 0 } /* UF_HOST */
2017
3305
  ,{ 0, 0 } /* UF_PORT */
2018
- ,{ 17, 12 } /* UF_PATH */
2019
- ,{ 30,187 } /* UF_QUERY */
3306
+ ,{ 0, 9 } /* UF_PATH */
3307
+ ,{ 0, 0 } /* UF_QUERY */
2020
3308
  ,{ 0, 0 } /* UF_FRAGMENT */
3309
+ ,{ 0, 0 } /* UF_USERINFO */
2021
3310
  }
2022
3311
  }
2023
3312
  ,.rv=0
2024
3313
  }
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
- }
3314
+ #endif
2055
3315
  };
2056
3316
 
2057
3317
  void
2058
3318
  dump_url (const char *url, const struct http_parser_url *u)
2059
3319
  {
2060
- char part[512];
2061
3320
  unsigned int i;
2062
3321
 
2063
3322
  printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
@@ -2067,14 +3326,12 @@ dump_url (const char *url, const struct http_parser_url *u)
2067
3326
  continue;
2068
3327
  }
2069
3328
 
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",
3329
+ printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
2074
3330
  i,
2075
3331
  u->field_data[i].off,
2076
3332
  u->field_data[i].len,
2077
- part);
3333
+ u->field_data[i].len,
3334
+ url + u->field_data[i].off);
2078
3335
  }
2079
3336
  }
2080
3337
 
@@ -2099,7 +3356,7 @@ test_parse_url (void)
2099
3356
  if (rv != 0) {
2100
3357
  printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2101
3358
  "unexpected rv %d ***\n\n", test->url, test->name, rv);
2102
- exit(1);
3359
+ abort();
2103
3360
  }
2104
3361
 
2105
3362
  if (memcmp(&u, &test->u, sizeof(u)) != 0) {
@@ -2111,19 +3368,26 @@ test_parse_url (void)
2111
3368
  printf("result http_parser_url:\n");
2112
3369
  dump_url(test->url, &u);
2113
3370
 
2114
- exit(1);
3371
+ abort();
2115
3372
  }
2116
3373
  } else {
2117
3374
  /* test->rv != 0 */
2118
3375
  if (rv == 0) {
2119
3376
  printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
2120
3377
  "unexpected rv %d ***\n\n", test->url, test->name, rv);
2121
- exit(1);
3378
+ abort();
2122
3379
  }
2123
3380
  }
2124
3381
  }
2125
3382
  }
2126
3383
 
3384
+ void
3385
+ test_method_str (void)
3386
+ {
3387
+ assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
3388
+ assert(0 == strcmp("<unknown>", http_method_str(1337)));
3389
+ }
3390
+
2127
3391
  void
2128
3392
  test_message (const struct message *message)
2129
3393
  {
@@ -2140,14 +3404,14 @@ test_message (const struct message *message)
2140
3404
  if (msg1len) {
2141
3405
  read = parse(msg1, msg1len);
2142
3406
 
2143
- if (message->upgrade && parser->upgrade) {
3407
+ if (message->upgrade && parser->upgrade && num_messages > 0) {
2144
3408
  messages[num_messages - 1].upgrade = msg1 + read;
2145
3409
  goto test;
2146
3410
  }
2147
3411
 
2148
3412
  if (read != msg1len) {
2149
3413
  print_error(msg1, read);
2150
- exit(1);
3414
+ abort();
2151
3415
  }
2152
3416
  }
2153
3417
 
@@ -2161,24 +3425,24 @@ test_message (const struct message *message)
2161
3425
 
2162
3426
  if (read != msg2len) {
2163
3427
  print_error(msg2, read);
2164
- exit(1);
3428
+ abort();
2165
3429
  }
2166
3430
 
2167
3431
  read = parse(NULL, 0);
2168
3432
 
2169
3433
  if (read != 0) {
2170
3434
  print_error(message->raw, read);
2171
- exit(1);
3435
+ abort();
2172
3436
  }
2173
3437
 
2174
3438
  test:
2175
3439
 
2176
3440
  if (num_messages != 1) {
2177
3441
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2178
- exit(1);
3442
+ abort();
2179
3443
  }
2180
3444
 
2181
- if(!message_eq(0, message)) exit(1);
3445
+ if(!message_eq(0, 0, message)) abort();
2182
3446
 
2183
3447
  parser_free();
2184
3448
  }
@@ -2199,7 +3463,7 @@ test_message_count_body (const struct message *message)
2199
3463
  read = parse_count_body(message->raw + i, toread);
2200
3464
  if (read != toread) {
2201
3465
  print_error(message->raw, read);
2202
- exit(1);
3466
+ abort();
2203
3467
  }
2204
3468
  }
2205
3469
 
@@ -2207,33 +3471,31 @@ test_message_count_body (const struct message *message)
2207
3471
  read = parse_count_body(NULL, 0);
2208
3472
  if (read != 0) {
2209
3473
  print_error(message->raw, read);
2210
- exit(1);
3474
+ abort();
2211
3475
  }
2212
3476
 
2213
3477
  if (num_messages != 1) {
2214
3478
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2215
- exit(1);
3479
+ abort();
2216
3480
  }
2217
3481
 
2218
- if(!message_eq(0, message)) exit(1);
3482
+ if(!message_eq(0, 0, message)) abort();
2219
3483
 
2220
3484
  parser_free();
2221
3485
  }
2222
3486
 
2223
3487
  void
2224
- test_simple (const char *buf, enum http_errno err_expected)
3488
+ test_simple_type (const char *buf,
3489
+ enum http_errno err_expected,
3490
+ enum http_parser_type type)
2225
3491
  {
2226
- parser_init(HTTP_REQUEST);
3492
+ parser_init(type);
2227
3493
 
2228
- size_t parsed;
2229
- int pass;
2230
3494
  enum http_errno err;
2231
3495
 
2232
- parsed = parse(buf, strlen(buf));
2233
- pass = (parsed == strlen(buf));
3496
+ parse(buf, strlen(buf));
2234
3497
  err = HTTP_PARSER_ERRNO(parser);
2235
- parsed = parse(NULL, 0);
2236
- pass &= (parsed == 0);
3498
+ parse(NULL, 0);
2237
3499
 
2238
3500
  parser_free();
2239
3501
 
@@ -2247,7 +3509,186 @@ test_simple (const char *buf, enum http_errno err_expected)
2247
3509
  #endif
2248
3510
  fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
2249
3511
  http_errno_name(err_expected), http_errno_name(err), buf);
2250
- exit(1);
3512
+ abort();
3513
+ }
3514
+ }
3515
+
3516
+ void
3517
+ test_simple (const char *buf, enum http_errno err_expected)
3518
+ {
3519
+ test_simple_type(buf, err_expected, HTTP_REQUEST);
3520
+ }
3521
+
3522
+ void
3523
+ test_invalid_header_content (int req, const char* str)
3524
+ {
3525
+ http_parser parser;
3526
+ http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3527
+ size_t parsed;
3528
+ const char *buf;
3529
+ buf = req ?
3530
+ "GET / HTTP/1.1\r\n" :
3531
+ "HTTP/1.1 200 OK\r\n";
3532
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3533
+ assert(parsed == strlen(buf));
3534
+
3535
+ buf = str;
3536
+ size_t buflen = strlen(buf);
3537
+
3538
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3539
+ if (parsed != buflen) {
3540
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
3541
+ return;
3542
+ }
3543
+
3544
+ fprintf(stderr,
3545
+ "\n*** Error expected but none in invalid header content test ***\n");
3546
+ abort();
3547
+ }
3548
+
3549
+ void
3550
+ test_invalid_header_field_content_error (int req)
3551
+ {
3552
+ test_invalid_header_content(req, "Foo: F\01ailure");
3553
+ test_invalid_header_content(req, "Foo: B\02ar");
3554
+ }
3555
+
3556
+ void
3557
+ test_invalid_header_field (int req, const char* str)
3558
+ {
3559
+ http_parser parser;
3560
+ http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3561
+ size_t parsed;
3562
+ const char *buf;
3563
+ buf = req ?
3564
+ "GET / HTTP/1.1\r\n" :
3565
+ "HTTP/1.1 200 OK\r\n";
3566
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3567
+ assert(parsed == strlen(buf));
3568
+
3569
+ buf = str;
3570
+ size_t buflen = strlen(buf);
3571
+
3572
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3573
+ if (parsed != buflen) {
3574
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
3575
+ return;
3576
+ }
3577
+
3578
+ fprintf(stderr,
3579
+ "\n*** Error expected but none in invalid header token test ***\n");
3580
+ abort();
3581
+ }
3582
+
3583
+ void
3584
+ test_invalid_header_field_token_error (int req)
3585
+ {
3586
+ test_invalid_header_field(req, "Fo@: Failure");
3587
+ test_invalid_header_field(req, "Foo\01\test: Bar");
3588
+ }
3589
+
3590
+ void
3591
+ test_double_content_length_error (int req)
3592
+ {
3593
+ http_parser parser;
3594
+ http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3595
+ size_t parsed;
3596
+ const char *buf;
3597
+ buf = req ?
3598
+ "GET / HTTP/1.1\r\n" :
3599
+ "HTTP/1.1 200 OK\r\n";
3600
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3601
+ assert(parsed == strlen(buf));
3602
+
3603
+ buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
3604
+ size_t buflen = strlen(buf);
3605
+
3606
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3607
+ if (parsed != buflen) {
3608
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
3609
+ return;
3610
+ }
3611
+
3612
+ fprintf(stderr,
3613
+ "\n*** Error expected but none in double content-length test ***\n");
3614
+ abort();
3615
+ }
3616
+
3617
+ void
3618
+ test_chunked_content_length_error (int req)
3619
+ {
3620
+ http_parser parser;
3621
+ http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3622
+ size_t parsed;
3623
+ const char *buf;
3624
+ buf = req ?
3625
+ "GET / HTTP/1.1\r\n" :
3626
+ "HTTP/1.1 200 OK\r\n";
3627
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3628
+ assert(parsed == strlen(buf));
3629
+
3630
+ buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
3631
+ size_t buflen = strlen(buf);
3632
+
3633
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3634
+ if (parsed != buflen) {
3635
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
3636
+ return;
3637
+ }
3638
+
3639
+ fprintf(stderr,
3640
+ "\n*** Error expected but none in chunked content-length test ***\n");
3641
+ abort();
3642
+ }
3643
+
3644
+ void
3645
+ test_header_cr_no_lf_error (int req)
3646
+ {
3647
+ http_parser parser;
3648
+ http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
3649
+ size_t parsed;
3650
+ const char *buf;
3651
+ buf = req ?
3652
+ "GET / HTTP/1.1\r\n" :
3653
+ "HTTP/1.1 200 OK\r\n";
3654
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3655
+ assert(parsed == strlen(buf));
3656
+
3657
+ buf = "Foo: 1\rBar: 1\r\n\r\n";
3658
+ size_t buflen = strlen(buf);
3659
+
3660
+ parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
3661
+ if (parsed != buflen) {
3662
+ assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
3663
+ return;
3664
+ }
3665
+
3666
+ fprintf(stderr,
3667
+ "\n*** Error expected but none in header whitespace test ***\n");
3668
+ abort();
3669
+ }
3670
+
3671
+ void
3672
+ test_no_overflow_parse_url (void)
3673
+ {
3674
+ int rv;
3675
+ struct http_parser_url u;
3676
+
3677
+ http_parser_url_init(&u);
3678
+ rv = http_parser_parse_url("http://example.com:8001", 22, 0, &u);
3679
+
3680
+ if (rv != 0) {
3681
+ fprintf(stderr,
3682
+ "\n*** test_no_overflow_parse_url invalid return value=%d\n",
3683
+ rv);
3684
+ abort();
3685
+ }
3686
+
3687
+ if (u.port != 800) {
3688
+ fprintf(stderr,
3689
+ "\n*** test_no_overflow_parse_url invalid port number=%d\n",
3690
+ u.port);
3691
+ abort();
2251
3692
  }
2252
3693
  }
2253
3694
 
@@ -2276,9 +3717,25 @@ test_header_overflow_error (int req)
2276
3717
  }
2277
3718
 
2278
3719
  fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
2279
- exit(1);
3720
+ abort();
3721
+ }
3722
+
3723
+
3724
+ void
3725
+ test_header_nread_value ()
3726
+ {
3727
+ http_parser parser;
3728
+ http_parser_init(&parser, HTTP_REQUEST);
3729
+ size_t parsed;
3730
+ const char *buf;
3731
+ buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
3732
+ parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
3733
+ assert(parsed == strlen(buf));
3734
+
3735
+ assert(parser.nread == strlen(buf));
2280
3736
  }
2281
3737
 
3738
+
2282
3739
  static void
2283
3740
  test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
2284
3741
  {
@@ -2299,7 +3756,7 @@ test_header_content_length_overflow_error (void)
2299
3756
  "HTTP/1.1 200 OK\r\n" \
2300
3757
  "Content-Length: " #size "\r\n" \
2301
3758
  "\r\n"
2302
- const char a[] = X(18446744073709551614); /* 2^64-2 */
3759
+ const char a[] = X(1844674407370955160); /* 2^64 / 10 - 1 */
2303
3760
  const char b[] = X(18446744073709551615); /* 2^64-1 */
2304
3761
  const char c[] = X(18446744073709551616); /* 2^64 */
2305
3762
  #undef X
@@ -2317,7 +3774,7 @@ test_chunk_content_length_overflow_error (void)
2317
3774
  "\r\n" \
2318
3775
  #size "\r\n" \
2319
3776
  "..."
2320
- const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
3777
+ const char a[] = X(FFFFFFFFFFFFFFE); /* 2^64 / 16 - 1 */
2321
3778
  const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
2322
3779
  const char c[] = X(10000000000000000); /* 2^64 */
2323
3780
  #undef X
@@ -2334,8 +3791,8 @@ test_no_overflow_long_body (int req, size_t length)
2334
3791
  size_t parsed;
2335
3792
  size_t i;
2336
3793
  char buf1[3000];
2337
- size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %zu\r\n\r\n",
2338
- req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", length);
3794
+ size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
3795
+ req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
2339
3796
  parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2340
3797
  if (parsed != buf1len)
2341
3798
  goto err;
@@ -2353,10 +3810,10 @@ test_no_overflow_long_body (int req, size_t length)
2353
3810
 
2354
3811
  err:
2355
3812
  fprintf(stderr,
2356
- "\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
3813
+ "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
2357
3814
  req ? "REQUEST" : "RESPONSE",
2358
- length);
2359
- exit(1);
3815
+ (unsigned long)length);
3816
+ abort();
2360
3817
  }
2361
3818
 
2362
3819
  void
@@ -2388,26 +3845,26 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
2388
3845
 
2389
3846
  if (read != strlen(total)) {
2390
3847
  print_error(total, read);
2391
- exit(1);
3848
+ abort();
2392
3849
  }
2393
3850
 
2394
3851
  read = parse(NULL, 0);
2395
3852
 
2396
3853
  if (read != 0) {
2397
3854
  print_error(total, read);
2398
- exit(1);
3855
+ abort();
2399
3856
  }
2400
3857
 
2401
3858
  test:
2402
3859
 
2403
3860
  if (message_count != num_messages) {
2404
3861
  fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
2405
- exit(1);
3862
+ abort();
2406
3863
  }
2407
3864
 
2408
- if (!message_eq(0, r1)) exit(1);
2409
- if (message_count > 1 && !message_eq(1, r2)) exit(1);
2410
- if (message_count > 2 && !message_eq(2, r3)) exit(1);
3865
+ if (!message_eq(0, 0, r1)) abort();
3866
+ if (message_count > 1 && !message_eq(1, 0, r2)) abort();
3867
+ if (message_count > 2 && !message_eq(2, 0, r3)) abort();
2411
3868
 
2412
3869
  parser_free();
2413
3870
  }
@@ -2452,15 +3909,15 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
2452
3909
  parser_init(type_both ? HTTP_BOTH : r1->type);
2453
3910
 
2454
3911
  buf1_len = i;
2455
- strncpy(buf1, total, buf1_len);
3912
+ strlncpy(buf1, sizeof(buf1), total, buf1_len);
2456
3913
  buf1[buf1_len] = 0;
2457
3914
 
2458
3915
  buf2_len = j - i;
2459
- strncpy(buf2, total+i, buf2_len);
3916
+ strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
2460
3917
  buf2[buf2_len] = 0;
2461
3918
 
2462
3919
  buf3_len = total_len - j;
2463
- strncpy(buf3, total+j, buf3_len);
3920
+ strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
2464
3921
  buf3[buf3_len] = 0;
2465
3922
 
2466
3923
  read = parse(buf1, buf1_len);
@@ -2503,17 +3960,17 @@ test:
2503
3960
  goto error;
2504
3961
  }
2505
3962
 
2506
- if (!message_eq(0, r1)) {
3963
+ if (!message_eq(0, 0, r1)) {
2507
3964
  fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
2508
3965
  goto error;
2509
3966
  }
2510
3967
 
2511
- if (message_count > 1 && !message_eq(1, r2)) {
3968
+ if (message_count > 1 && !message_eq(1, 0, r2)) {
2512
3969
  fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
2513
3970
  goto error;
2514
3971
  }
2515
3972
 
2516
- if (message_count > 2 && !message_eq(2, r3)) {
3973
+ if (message_count > 2 && !message_eq(2, 0, r3)) {
2517
3974
  fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
2518
3975
  goto error;
2519
3976
  }
@@ -2530,7 +3987,7 @@ test:
2530
3987
  fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
2531
3988
  fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
2532
3989
  fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
2533
- exit(1);
3990
+ abort();
2534
3991
  }
2535
3992
 
2536
3993
  // user required to free the result
@@ -2609,10 +4066,31 @@ test_message_pause (const struct message *msg)
2609
4066
  test:
2610
4067
  if (num_messages != 1) {
2611
4068
  printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
2612
- exit(1);
4069
+ abort();
4070
+ }
4071
+
4072
+ if(!message_eq(0, 0, msg)) abort();
4073
+
4074
+ parser_free();
4075
+ }
4076
+
4077
+ /* Verify that body and next message won't be parsed in responses to CONNECT */
4078
+ void
4079
+ test_message_connect (const struct message *msg)
4080
+ {
4081
+ char *buf = (char*) msg->raw;
4082
+ size_t buflen = strlen(msg->raw);
4083
+
4084
+ parser_init(msg->type);
4085
+
4086
+ parse_connect(buf, buflen);
4087
+
4088
+ if (num_messages != 1) {
4089
+ printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
4090
+ abort();
2613
4091
  }
2614
4092
 
2615
- if(!message_eq(0, msg)) exit(1);
4093
+ if(!message_eq(0, 1, msg)) abort();
2616
4094
 
2617
4095
  parser_free();
2618
4096
  }
@@ -2621,20 +4099,30 @@ int
2621
4099
  main (void)
2622
4100
  {
2623
4101
  parser = NULL;
2624
- int i, j, k;
2625
- int request_count;
2626
- int response_count;
4102
+ unsigned i, j, k;
4103
+ unsigned long version;
4104
+ unsigned major;
4105
+ unsigned minor;
4106
+ unsigned patch;
4107
+
4108
+ version = http_parser_version();
4109
+ major = (version >> 16) & 255;
4110
+ minor = (version >> 8) & 255;
4111
+ patch = version & 255;
4112
+ printf("http_parser v%u.%u.%u (0x%06lx)\n", major, minor, patch, version);
2627
4113
 
2628
4114
  printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
2629
4115
 
2630
- for (request_count = 0; requests[request_count].name; request_count++);
2631
- for (response_count = 0; responses[response_count].name; response_count++);
2632
-
2633
4116
  //// API
2634
4117
  test_preserve_data();
2635
4118
  test_parse_url();
4119
+ test_method_str();
4120
+
4121
+ //// NREAD
4122
+ test_header_nread_value();
2636
4123
 
2637
4124
  //// OVERFLOW CONDITIONS
4125
+ test_no_overflow_parse_url();
2638
4126
 
2639
4127
  test_header_overflow_error(HTTP_REQUEST);
2640
4128
  test_no_overflow_long_body(HTTP_REQUEST, 1000);
@@ -2647,21 +4135,64 @@ main (void)
2647
4135
  test_header_content_length_overflow_error();
2648
4136
  test_chunk_content_length_overflow_error();
2649
4137
 
4138
+ //// HEADER FIELD CONDITIONS
4139
+ test_double_content_length_error(HTTP_REQUEST);
4140
+ test_chunked_content_length_error(HTTP_REQUEST);
4141
+ test_header_cr_no_lf_error(HTTP_REQUEST);
4142
+ test_invalid_header_field_token_error(HTTP_REQUEST);
4143
+ test_invalid_header_field_content_error(HTTP_REQUEST);
4144
+ test_double_content_length_error(HTTP_RESPONSE);
4145
+ test_chunked_content_length_error(HTTP_RESPONSE);
4146
+ test_header_cr_no_lf_error(HTTP_RESPONSE);
4147
+ test_invalid_header_field_token_error(HTTP_RESPONSE);
4148
+ test_invalid_header_field_content_error(HTTP_RESPONSE);
4149
+
4150
+ test_simple_type(
4151
+ "POST / HTTP/1.1\r\n"
4152
+ "Content-Length: 42 \r\n" // Note the surrounding whitespace.
4153
+ "\r\n",
4154
+ HPE_OK,
4155
+ HTTP_REQUEST);
4156
+
4157
+ test_simple_type(
4158
+ "POST / HTTP/1.1\r\n"
4159
+ "Content-Length: 4 2\r\n"
4160
+ "\r\n",
4161
+ HPE_INVALID_CONTENT_LENGTH,
4162
+ HTTP_REQUEST);
4163
+
4164
+ test_simple_type(
4165
+ "POST / HTTP/1.1\r\n"
4166
+ "Content-Length: 13 37\r\n"
4167
+ "\r\n",
4168
+ HPE_INVALID_CONTENT_LENGTH,
4169
+ HTTP_REQUEST);
4170
+
2650
4171
  //// RESPONSES
2651
4172
 
2652
- for (i = 0; i < response_count; i++) {
4173
+ test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
4174
+ test_simple_type("HTTP/01.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
4175
+ test_simple_type("HTTP/11.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
4176
+ test_simple_type("HTTP/1.01 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
4177
+ test_simple_type("HTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
4178
+
4179
+ for (i = 0; i < ARRAY_SIZE(responses); i++) {
2653
4180
  test_message(&responses[i]);
2654
4181
  }
2655
4182
 
2656
- for (i = 0; i < response_count; i++) {
4183
+ for (i = 0; i < ARRAY_SIZE(responses); i++) {
2657
4184
  test_message_pause(&responses[i]);
2658
4185
  }
2659
4186
 
2660
- for (i = 0; i < response_count; i++) {
4187
+ for (i = 0; i < ARRAY_SIZE(responses); i++) {
4188
+ test_message_connect(&responses[i]);
4189
+ }
4190
+
4191
+ for (i = 0; i < ARRAY_SIZE(responses); i++) {
2661
4192
  if (!responses[i].should_keep_alive) continue;
2662
- for (j = 0; j < response_count; j++) {
4193
+ for (j = 0; j < ARRAY_SIZE(responses); j++) {
2663
4194
  if (!responses[j].should_keep_alive) continue;
2664
- for (k = 0; k < response_count; k++) {
4195
+ for (k = 0; k < ARRAY_SIZE(responses); k++) {
2665
4196
  test_multiple3(&responses[i], &responses[j], &responses[k]);
2666
4197
  }
2667
4198
  }
@@ -2686,13 +4217,18 @@ main (void)
2686
4217
  ,.http_major= 1
2687
4218
  ,.http_minor= 0
2688
4219
  ,.status_code= 200
4220
+ ,.response_status= "OK"
2689
4221
  ,.num_headers= 2
2690
4222
  ,.headers=
2691
4223
  { { "Transfer-Encoding", "chunked" }
2692
4224
  , { "Content-Type", "text/plain" }
2693
4225
  }
2694
4226
  ,.body_size= 31337*1024
4227
+ ,.num_chunks_complete= 31338
2695
4228
  };
4229
+ for (i = 0; i < MAX_CHUNKS; i++) {
4230
+ large_chunked.chunk_lengths[i] = 1024;
4231
+ }
2696
4232
  test_message_count_body(&large_chunked);
2697
4233
  free(msg);
2698
4234
  }
@@ -2716,13 +4252,15 @@ main (void)
2716
4252
 
2717
4253
  /// REQUESTS
2718
4254
 
2719
- test_simple("hello world", HPE_INVALID_METHOD);
2720
4255
  test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
4256
+ test_simple("GET / HTTP/01.1\r\n\r\n", HPE_INVALID_VERSION);
4257
+ test_simple("GET / HTTP/11.1\r\n\r\n", HPE_INVALID_VERSION);
4258
+ test_simple("GET / HTTP/1.01\r\n\r\n", HPE_INVALID_VERSION);
2721
4259
 
2722
-
2723
- test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
2724
- test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
2725
- test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
4260
+ // Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js
4261
+ test_simple("GET / HTTP/1.1\r\n"
4262
+ "Test: Düsseldorf\r\n",
4263
+ HPE_OK);
2726
4264
 
2727
4265
  // Well-formed but incomplete
2728
4266
  test_simple("GET / HTTP/1.1\r\n"
@@ -2747,7 +4285,12 @@ main (void)
2747
4285
  "MOVE",
2748
4286
  "PROPFIND",
2749
4287
  "PROPPATCH",
4288
+ "SEARCH",
2750
4289
  "UNLOCK",
4290
+ "BIND",
4291
+ "REBIND",
4292
+ "UNBIND",
4293
+ "ACL",
2751
4294
  "REPORT",
2752
4295
  "MKACTIVITY",
2753
4296
  "CHECKOUT",
@@ -2757,6 +4300,10 @@ main (void)
2757
4300
  "SUBSCRIBE",
2758
4301
  "UNSUBSCRIBE",
2759
4302
  "PATCH",
4303
+ "PURGE",
4304
+ "MKCALENDAR",
4305
+ "LINK",
4306
+ "UNLINK",
2760
4307
  0 };
2761
4308
  const char **this_method;
2762
4309
  for (this_method = all_methods; *this_method; this_method++) {
@@ -2766,15 +4313,32 @@ main (void)
2766
4313
  }
2767
4314
 
2768
4315
  static const char *bad_methods[] = {
4316
+ "ASDF",
2769
4317
  "C******",
4318
+ "COLA",
4319
+ "GEM",
4320
+ "GETA",
2770
4321
  "M****",
4322
+ "MKCOLA",
4323
+ "PROPPATCHA",
4324
+ "PUN",
4325
+ "PX",
4326
+ "SA",
4327
+ "hello world",
2771
4328
  0 };
2772
4329
  for (this_method = bad_methods; *this_method; this_method++) {
2773
4330
  char buf[200];
2774
4331
  sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
2775
- test_simple(buf, HPE_UNKNOWN);
4332
+ test_simple(buf, HPE_INVALID_METHOD);
2776
4333
  }
2777
4334
 
4335
+ // illegal header field name line folding
4336
+ test_simple("GET / HTTP/1.1\r\n"
4337
+ "name\r\n"
4338
+ " : value\r\n"
4339
+ "\r\n",
4340
+ HPE_INVALID_HEADER_TOKEN);
4341
+
2778
4342
  const char *dumbfuck2 =
2779
4343
  "GET / HTTP/1.1\r\n"
2780
4344
  "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
@@ -2812,6 +4376,22 @@ main (void)
2812
4376
  "\r\n";
2813
4377
  test_simple(dumbfuck2, HPE_OK);
2814
4378
 
4379
+ const char *corrupted_connection =
4380
+ "GET / HTTP/1.1\r\n"
4381
+ "Host: www.example.com\r\n"
4382
+ "Connection\r\033\065\325eep-Alive\r\n"
4383
+ "Accept-Encoding: gzip\r\n"
4384
+ "\r\n";
4385
+ test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
4386
+
4387
+ const char *corrupted_header_name =
4388
+ "GET / HTTP/1.1\r\n"
4389
+ "Host: www.example.com\r\n"
4390
+ "X-Some-Header\r\033\065\325eep-Alive\r\n"
4391
+ "Accept-Encoding: gzip\r\n"
4392
+ "\r\n";
4393
+ test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
4394
+
2815
4395
  #if 0
2816
4396
  // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
2817
4397
  // until EOF.
@@ -2828,19 +4408,19 @@ main (void)
2828
4408
 
2829
4409
 
2830
4410
  /* check to make sure our predefined requests are okay */
2831
- for (i = 0; requests[i].name; i++) {
4411
+ for (i = 0; i < ARRAY_SIZE(requests); i++) {
2832
4412
  test_message(&requests[i]);
2833
4413
  }
2834
4414
 
2835
- for (i = 0; i < request_count; i++) {
4415
+ for (i = 0; i < ARRAY_SIZE(requests); i++) {
2836
4416
  test_message_pause(&requests[i]);
2837
4417
  }
2838
4418
 
2839
- for (i = 0; i < request_count; i++) {
4419
+ for (i = 0; i < ARRAY_SIZE(requests); i++) {
2840
4420
  if (!requests[i].should_keep_alive) continue;
2841
- for (j = 0; j < request_count; j++) {
4421
+ for (j = 0; j < ARRAY_SIZE(requests); j++) {
2842
4422
  if (!requests[j].should_keep_alive) continue;
2843
- for (k = 0; k < request_count; k++) {
4423
+ for (k = 0; k < ARRAY_SIZE(requests); k++) {
2844
4424
  test_multiple3(&requests[i], &requests[j], &requests[k]);
2845
4425
  }
2846
4426
  }