http-parser 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 521dd5304a0b3ff3e6c1a1ffbec3f383b5ad3665
4
- data.tar.gz: a79ef2fcbc2020577e2060f65b929c7d2cdaeaf0
2
+ SHA256:
3
+ metadata.gz: b10418834197ee747e8e8b0f731efef8f1f80285f05426292b627edadc7da52a
4
+ data.tar.gz: 5e159cadc303a5a811754eeac131d56bb5e6f8eff66be4650c049c8fc10a4a2d
5
5
  SHA512:
6
- metadata.gz: a6fb5d0850ee732007b4ce10edb55fd3dc2bc60f2872cf06d19705db5f7a196daa478aeaf5867362d1ef7ae98c5b22e179d86a7d6d0ed03d1a6fcfa2e476e648
7
- data.tar.gz: d7648c23965f6e6d19b2a3f12a1776726dc028ad6c6a3c5d7543253f14d346c961a965455e293d15ea71e6e9edae19c08be383a3b580d41921908cc0be88d4c7
6
+ metadata.gz: 3fb875b674223383319ab6b02b019acf27964cddec2bb732773d4315f1aac472529b27b1a4edbf8bdbfd5441117c8a274009ad0ace5457082918e42043aa75ef
7
+ data.tar.gz: 3ada5a0f5e72ff81495e6b97c3ea20d16aa7b536fe6a7425477e73360228e3983c92788663ed3fe76e3c1b194230092f1bbed1274e68cf853bdc583c1d053cda
@@ -3,6 +3,6 @@ require 'ffi-compiler/compile_task'
3
3
  FFI::Compiler::CompileTask.new('http-parser-ext') do |t|
4
4
  t.cflags << "-Wall -Wextra -O3"
5
5
  t.cflags << "-D_GNU_SOURCE=1" if RbConfig::CONFIG["host_os"].downcase =~ /mingw/
6
- t.cflags << "-arch x86_64 -arch i386" if t.platform.mac?
7
- t.ldflags << "-arch x86_64 -arch i386" if t.platform.mac?
6
+ t.cflags << "-arch x86_64" if t.platform.mac?
7
+ t.ldflags << "-arch x86_64" if t.platform.mac?
8
8
  end
@@ -1,7 +1,4 @@
1
- /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2
- *
3
- * Additional changes are licensed under the same terms as NGINX and
4
- * copyright Joyent, Inc. and other Node contributors. All rights reserved.
1
+ /* Copyright Joyent, Inc. and other Node contributors.
5
2
  *
6
3
  * Permission is hereby granted, free of charge, to any person obtaining a copy
7
4
  * of this software and associated documentation files (the "Software"), to
@@ -25,7 +22,6 @@
25
22
  #include <assert.h>
26
23
  #include <stddef.h>
27
24
  #include <ctype.h>
28
- #include <stdlib.h>
29
25
  #include <string.h>
30
26
  #include <limits.h>
31
27
 
@@ -53,6 +49,7 @@
53
49
 
54
50
  #define SET_ERRNO(e) \
55
51
  do { \
52
+ parser->nread = nread; \
56
53
  parser->http_errno = (e); \
57
54
  } while(0)
58
55
 
@@ -60,6 +57,7 @@ do { \
60
57
  #define UPDATE_STATE(V) p_state = (enum state) (V);
61
58
  #define RETURN(V) \
62
59
  do { \
60
+ parser->nread = nread; \
63
61
  parser->state = CURRENT_STATE(); \
64
62
  return (V); \
65
63
  } while (0);
@@ -153,8 +151,8 @@ do { \
153
151
  */
154
152
  #define COUNT_HEADER_SIZE(V) \
155
153
  do { \
156
- parser->nread += (V); \
157
- if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \
154
+ nread += (V); \
155
+ if (UNLIKELY(nread > (HTTP_MAX_HEADER_SIZE))) { \
158
156
  SET_ERRNO(HPE_HEADER_OVERFLOW); \
159
157
  goto error; \
160
158
  } \
@@ -196,7 +194,7 @@ static const char tokens[256] = {
196
194
  /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
197
195
  0, 0, 0, 0, 0, 0, 0, 0,
198
196
  /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
199
- 0, '!', 0, '#', '$', '%', '&', '\'',
197
+ ' ', '!', 0, '#', '$', '%', '&', '\'',
200
198
  /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
201
199
  0, 0, '*', '+', 0, '-', '.', 0,
202
200
  /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
@@ -286,10 +284,10 @@ enum state
286
284
  , s_res_HT
287
285
  , s_res_HTT
288
286
  , s_res_HTTP
289
- , s_res_first_http_major
290
287
  , s_res_http_major
291
- , s_res_first_http_minor
288
+ , s_res_http_dot
292
289
  , s_res_http_minor
290
+ , s_res_http_end
293
291
  , s_res_first_status_code
294
292
  , s_res_status_code
295
293
  , s_res_status_start
@@ -316,10 +314,10 @@ enum state
316
314
  , s_req_http_HT
317
315
  , s_req_http_HTT
318
316
  , s_req_http_HTTP
319
- , s_req_first_http_major
320
317
  , s_req_http_major
321
- , s_req_first_http_minor
318
+ , s_req_http_dot
322
319
  , s_req_http_minor
320
+ , s_req_http_end
323
321
  , s_req_line_almost_done
324
322
 
325
323
  , s_header_field_start
@@ -374,6 +372,8 @@ enum header_states
374
372
 
375
373
  , h_connection
376
374
  , h_content_length
375
+ , h_content_length_num
376
+ , h_content_length_ws
377
377
  , h_transfer_encoding
378
378
  , h_upgrade
379
379
 
@@ -421,14 +421,14 @@ enum http_host_state
421
421
  (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
422
422
  (c) == '$' || (c) == ',')
423
423
 
424
- #define STRICT_TOKEN(c) (tokens[(unsigned char)c])
424
+ #define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char)c])
425
425
 
426
426
  #if HTTP_PARSER_STRICT
427
- #define TOKEN(c) (tokens[(unsigned char)c])
427
+ #define TOKEN(c) STRICT_TOKEN(c)
428
428
  #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
429
429
  #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
430
430
  #else
431
- #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
431
+ #define TOKEN(c) tokens[(unsigned char)c]
432
432
  #define IS_URL_CHAR(c) \
433
433
  (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
434
434
  #define IS_HOST_CHAR(c) \
@@ -542,7 +542,7 @@ parse_url_char(enum state s, const char ch)
542
542
  return s_dead;
543
543
  }
544
544
 
545
- /* FALLTHROUGH */
545
+ /* fall through */
546
546
  case s_req_server_start:
547
547
  case s_req_server:
548
548
  if (ch == '/') {
@@ -646,6 +646,7 @@ size_t http_parser_execute (http_parser *parser,
646
646
  const char *status_mark = 0;
647
647
  enum state p_state = (enum state) parser->state;
648
648
  const unsigned int lenient = parser->lenient_http_headers;
649
+ uint32_t nread = parser->nread;
649
650
 
650
651
  /* We're in an error state. Don't bother doing anything. */
651
652
  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
@@ -757,21 +758,16 @@ reexecute:
757
758
 
758
759
  case s_start_res:
759
760
  {
761
+ if (ch == CR || ch == LF)
762
+ break;
760
763
  parser->flags = 0;
761
764
  parser->content_length = ULLONG_MAX;
762
765
 
763
- switch (ch) {
764
- case 'H':
765
- UPDATE_STATE(s_res_H);
766
- break;
767
-
768
- case CR:
769
- case LF:
770
- break;
771
-
772
- default:
773
- SET_ERRNO(HPE_INVALID_CONSTANT);
774
- goto error;
766
+ if (ch == 'H') {
767
+ UPDATE_STATE(s_res_H);
768
+ } else {
769
+ SET_ERRNO(HPE_INVALID_CONSTANT);
770
+ goto error;
775
771
  }
776
772
 
777
773
  CALLBACK_NOTIFY(message_begin);
@@ -795,75 +791,48 @@ reexecute:
795
791
 
796
792
  case s_res_HTTP:
797
793
  STRICT_CHECK(ch != '/');
798
- UPDATE_STATE(s_res_first_http_major);
794
+ UPDATE_STATE(s_res_http_major);
799
795
  break;
800
796
 
801
- case s_res_first_http_major:
802
- if (UNLIKELY(ch < '0' || ch > '9')) {
797
+ case s_res_http_major:
798
+ if (UNLIKELY(!IS_NUM(ch))) {
803
799
  SET_ERRNO(HPE_INVALID_VERSION);
804
800
  goto error;
805
801
  }
806
802
 
807
803
  parser->http_major = ch - '0';
808
- UPDATE_STATE(s_res_http_major);
804
+ UPDATE_STATE(s_res_http_dot);
809
805
  break;
810
806
 
811
- /* major HTTP version or dot */
812
- case s_res_http_major:
807
+ case s_res_http_dot:
813
808
  {
814
- if (ch == '.') {
815
- UPDATE_STATE(s_res_first_http_minor);
816
- break;
817
- }
818
-
819
- if (!IS_NUM(ch)) {
820
- SET_ERRNO(HPE_INVALID_VERSION);
821
- goto error;
822
- }
823
-
824
- parser->http_major *= 10;
825
- parser->http_major += ch - '0';
826
-
827
- if (UNLIKELY(parser->http_major > 999)) {
809
+ if (UNLIKELY(ch != '.')) {
828
810
  SET_ERRNO(HPE_INVALID_VERSION);
829
811
  goto error;
830
812
  }
831
813
 
814
+ UPDATE_STATE(s_res_http_minor);
832
815
  break;
833
816
  }
834
817
 
835
- /* first digit of minor HTTP version */
836
- case s_res_first_http_minor:
818
+ case s_res_http_minor:
837
819
  if (UNLIKELY(!IS_NUM(ch))) {
838
820
  SET_ERRNO(HPE_INVALID_VERSION);
839
821
  goto error;
840
822
  }
841
823
 
842
824
  parser->http_minor = ch - '0';
843
- UPDATE_STATE(s_res_http_minor);
825
+ UPDATE_STATE(s_res_http_end);
844
826
  break;
845
827
 
846
- /* minor HTTP version or end of request line */
847
- case s_res_http_minor:
828
+ case s_res_http_end:
848
829
  {
849
- if (ch == ' ') {
850
- UPDATE_STATE(s_res_first_status_code);
851
- break;
852
- }
853
-
854
- if (UNLIKELY(!IS_NUM(ch))) {
855
- SET_ERRNO(HPE_INVALID_VERSION);
856
- goto error;
857
- }
858
-
859
- parser->http_minor *= 10;
860
- parser->http_minor += ch - '0';
861
-
862
- if (UNLIKELY(parser->http_minor > 999)) {
830
+ if (UNLIKELY(ch != ' ')) {
863
831
  SET_ERRNO(HPE_INVALID_VERSION);
864
832
  goto error;
865
833
  }
866
834
 
835
+ UPDATE_STATE(s_res_first_status_code);
867
836
  break;
868
837
  }
869
838
 
@@ -890,10 +859,9 @@ reexecute:
890
859
  UPDATE_STATE(s_res_status_start);
891
860
  break;
892
861
  case CR:
893
- UPDATE_STATE(s_res_line_almost_done);
894
- break;
895
862
  case LF:
896
- UPDATE_STATE(s_header_field_start);
863
+ UPDATE_STATE(s_res_status_start);
864
+ REEXECUTE();
897
865
  break;
898
866
  default:
899
867
  SET_ERRNO(HPE_INVALID_STATUS);
@@ -915,19 +883,13 @@ reexecute:
915
883
 
916
884
  case s_res_status_start:
917
885
  {
918
- if (ch == CR) {
919
- UPDATE_STATE(s_res_line_almost_done);
920
- break;
921
- }
922
-
923
- if (ch == LF) {
924
- UPDATE_STATE(s_header_field_start);
925
- break;
926
- }
927
-
928
886
  MARK(status);
929
887
  UPDATE_STATE(s_res_status);
930
888
  parser->index = 0;
889
+
890
+ if (ch == CR || ch == LF)
891
+ REEXECUTE();
892
+
931
893
  break;
932
894
  }
933
895
 
@@ -980,7 +942,7 @@ reexecute:
980
942
  /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
981
943
  break;
982
944
  case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
983
- case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
945
+ case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break;
984
946
  case 'T': parser->method = HTTP_TRACE; break;
985
947
  case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
986
948
  default:
@@ -1007,7 +969,7 @@ reexecute:
1007
969
  UPDATE_STATE(s_req_spaces_before_url);
1008
970
  } else if (ch == matcher[parser->index]) {
1009
971
  ; /* nada */
1010
- } else if (IS_ALPHA(ch)) {
972
+ } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') {
1011
973
 
1012
974
  switch (parser->method << 16 | parser->index << 8 | ch) {
1013
975
  #define XX(meth, pos, ch, new_meth) \
@@ -1016,31 +978,28 @@ reexecute:
1016
978
 
1017
979
  XX(POST, 1, 'U', PUT)
1018
980
  XX(POST, 1, 'A', PATCH)
981
+ XX(POST, 1, 'R', PROPFIND)
982
+ XX(PUT, 2, 'R', PURGE)
1019
983
  XX(CONNECT, 1, 'H', CHECKOUT)
1020
984
  XX(CONNECT, 2, 'P', COPY)
1021
985
  XX(MKCOL, 1, 'O', MOVE)
1022
986
  XX(MKCOL, 1, 'E', MERGE)
987
+ XX(MKCOL, 1, '-', MSEARCH)
1023
988
  XX(MKCOL, 2, 'A', MKACTIVITY)
1024
989
  XX(MKCOL, 3, 'A', MKCALENDAR)
1025
990
  XX(SUBSCRIBE, 1, 'E', SEARCH)
991
+ XX(SUBSCRIBE, 1, 'O', SOURCE)
1026
992
  XX(REPORT, 2, 'B', REBIND)
1027
- XX(POST, 1, 'R', PROPFIND)
1028
993
  XX(PROPFIND, 4, 'P', PROPPATCH)
1029
- XX(PUT, 2, 'R', PURGE)
1030
994
  XX(LOCK, 1, 'I', LINK)
1031
995
  XX(UNLOCK, 2, 'S', UNSUBSCRIBE)
1032
996
  XX(UNLOCK, 2, 'B', UNBIND)
1033
997
  XX(UNLOCK, 3, 'I', UNLINK)
1034
998
  #undef XX
1035
-
1036
999
  default:
1037
1000
  SET_ERRNO(HPE_INVALID_METHOD);
1038
1001
  goto error;
1039
1002
  }
1040
- } else if (ch == '-' &&
1041
- parser->index == 1 &&
1042
- parser->method == HTTP_MKCOL) {
1043
- parser->method = HTTP_MSEARCH;
1044
1003
  } else {
1045
1004
  SET_ERRNO(HPE_INVALID_METHOD);
1046
1005
  goto error;
@@ -1153,57 +1112,41 @@ reexecute:
1153
1112
 
1154
1113
  case s_req_http_HTTP:
1155
1114
  STRICT_CHECK(ch != '/');
1156
- UPDATE_STATE(s_req_first_http_major);
1157
- break;
1158
-
1159
- /* first digit of major HTTP version */
1160
- case s_req_first_http_major:
1161
- if (UNLIKELY(ch < '1' || ch > '9')) {
1162
- SET_ERRNO(HPE_INVALID_VERSION);
1163
- goto error;
1164
- }
1165
-
1166
- parser->http_major = ch - '0';
1167
1115
  UPDATE_STATE(s_req_http_major);
1168
1116
  break;
1169
1117
 
1170
- /* major HTTP version or dot */
1171
1118
  case s_req_http_major:
1172
- {
1173
- if (ch == '.') {
1174
- UPDATE_STATE(s_req_first_http_minor);
1175
- break;
1176
- }
1177
-
1178
1119
  if (UNLIKELY(!IS_NUM(ch))) {
1179
1120
  SET_ERRNO(HPE_INVALID_VERSION);
1180
1121
  goto error;
1181
1122
  }
1182
1123
 
1183
- parser->http_major *= 10;
1184
- parser->http_major += ch - '0';
1124
+ parser->http_major = ch - '0';
1125
+ UPDATE_STATE(s_req_http_dot);
1126
+ break;
1185
1127
 
1186
- if (UNLIKELY(parser->http_major > 999)) {
1128
+ case s_req_http_dot:
1129
+ {
1130
+ if (UNLIKELY(ch != '.')) {
1187
1131
  SET_ERRNO(HPE_INVALID_VERSION);
1188
1132
  goto error;
1189
1133
  }
1190
1134
 
1135
+ UPDATE_STATE(s_req_http_minor);
1191
1136
  break;
1192
1137
  }
1193
1138
 
1194
- /* first digit of minor HTTP version */
1195
- case s_req_first_http_minor:
1139
+ case s_req_http_minor:
1196
1140
  if (UNLIKELY(!IS_NUM(ch))) {
1197
1141
  SET_ERRNO(HPE_INVALID_VERSION);
1198
1142
  goto error;
1199
1143
  }
1200
1144
 
1201
1145
  parser->http_minor = ch - '0';
1202
- UPDATE_STATE(s_req_http_minor);
1146
+ UPDATE_STATE(s_req_http_end);
1203
1147
  break;
1204
1148
 
1205
- /* minor HTTP version or end of request line */
1206
- case s_req_http_minor:
1149
+ case s_req_http_end:
1207
1150
  {
1208
1151
  if (ch == CR) {
1209
1152
  UPDATE_STATE(s_req_line_almost_done);
@@ -1215,21 +1158,8 @@ reexecute:
1215
1158
  break;
1216
1159
  }
1217
1160
 
1218
- /* XXX allow spaces after digit? */
1219
-
1220
- if (UNLIKELY(!IS_NUM(ch))) {
1221
- SET_ERRNO(HPE_INVALID_VERSION);
1222
- goto error;
1223
- }
1224
-
1225
- parser->http_minor *= 10;
1226
- parser->http_minor += ch - '0';
1227
-
1228
- if (UNLIKELY(parser->http_minor > 999)) {
1229
- SET_ERRNO(HPE_INVALID_VERSION);
1230
- goto error;
1231
- }
1232
-
1161
+ SET_ERRNO(HPE_INVALID_VERSION);
1162
+ goto error;
1233
1163
  break;
1234
1164
  }
1235
1165
 
@@ -1306,8 +1236,14 @@ reexecute:
1306
1236
  break;
1307
1237
 
1308
1238
  switch (parser->header_state) {
1309
- case h_general:
1239
+ case h_general: {
1240
+ size_t limit = data + len - p;
1241
+ limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
1242
+ while (p+1 < data + limit && TOKEN(p[1])) {
1243
+ p++;
1244
+ }
1310
1245
  break;
1246
+ }
1311
1247
 
1312
1248
  case h_C:
1313
1249
  parser->index++;
@@ -1407,13 +1343,14 @@ reexecute:
1407
1343
  }
1408
1344
  }
1409
1345
 
1410
- COUNT_HEADER_SIZE(p - start);
1411
-
1412
1346
  if (p == data + len) {
1413
1347
  --p;
1348
+ COUNT_HEADER_SIZE(p - start);
1414
1349
  break;
1415
1350
  }
1416
1351
 
1352
+ COUNT_HEADER_SIZE(p - start);
1353
+
1417
1354
  if (ch == ':') {
1418
1355
  UPDATE_STATE(s_header_value_discard_ws);
1419
1356
  CALLBACK_DATA(header_field);
@@ -1437,7 +1374,7 @@ reexecute:
1437
1374
  break;
1438
1375
  }
1439
1376
 
1440
- /* FALLTHROUGH */
1377
+ /* fall through */
1441
1378
 
1442
1379
  case s_header_value_start:
1443
1380
  {
@@ -1476,6 +1413,7 @@ reexecute:
1476
1413
 
1477
1414
  parser->flags |= F_CONTENTLENGTH;
1478
1415
  parser->content_length = ch - '0';
1416
+ parser->header_state = h_content_length_num;
1479
1417
  break;
1480
1418
 
1481
1419
  case h_connection:
@@ -1553,7 +1491,6 @@ reexecute:
1553
1491
  p = data + len;
1554
1492
  }
1555
1493
  --p;
1556
-
1557
1494
  break;
1558
1495
  }
1559
1496
 
@@ -1563,10 +1500,18 @@ reexecute:
1563
1500
  break;
1564
1501
 
1565
1502
  case h_content_length:
1503
+ if (ch == ' ') break;
1504
+ h_state = h_content_length_num;
1505
+ /* fall through */
1506
+
1507
+ case h_content_length_num:
1566
1508
  {
1567
1509
  uint64_t t;
1568
1510
 
1569
- if (ch == ' ') break;
1511
+ if (ch == ' ') {
1512
+ h_state = h_content_length_ws;
1513
+ break;
1514
+ }
1570
1515
 
1571
1516
  if (UNLIKELY(!IS_NUM(ch))) {
1572
1517
  SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
@@ -1589,6 +1534,12 @@ reexecute:
1589
1534
  break;
1590
1535
  }
1591
1536
 
1537
+ case h_content_length_ws:
1538
+ if (ch == ' ') break;
1539
+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1540
+ parser->header_state = h_state;
1541
+ goto error;
1542
+
1592
1543
  /* Transfer-Encoding: chunked */
1593
1544
  case h_matching_transfer_encoding_chunked:
1594
1545
  parser->index++;
@@ -1687,10 +1638,10 @@ reexecute:
1687
1638
  }
1688
1639
  parser->header_state = h_state;
1689
1640
 
1690
- COUNT_HEADER_SIZE(p - start);
1691
-
1692
1641
  if (p == data + len)
1693
1642
  --p;
1643
+
1644
+ COUNT_HEADER_SIZE(p - start);
1694
1645
  break;
1695
1646
  }
1696
1647
 
@@ -1794,10 +1745,17 @@ reexecute:
1794
1745
  UPDATE_STATE(s_headers_done);
1795
1746
 
1796
1747
  /* Set this here so that on_headers_complete() callbacks can see it */
1797
- parser->upgrade =
1798
- ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==
1799
- (F_UPGRADE | F_CONNECTION_UPGRADE) ||
1800
- parser->method == HTTP_CONNECT);
1748
+ if ((parser->flags & F_UPGRADE) &&
1749
+ (parser->flags & F_CONNECTION_UPGRADE)) {
1750
+ /* For responses, "Upgrade: foo" and "Connection: upgrade" are
1751
+ * mandatory only when it is a 101 Switching Protocols response,
1752
+ * otherwise it is purely informational, to announce support.
1753
+ */
1754
+ parser->upgrade =
1755
+ (parser->type == HTTP_REQUEST || parser->status_code == 101);
1756
+ } else {
1757
+ parser->upgrade = (parser->method == HTTP_CONNECT);
1758
+ }
1801
1759
 
1802
1760
  /* Here we call the headers_complete callback. This is somewhat
1803
1761
  * different than other callbacks because if the user returns 1, we
@@ -1816,6 +1774,7 @@ reexecute:
1816
1774
  case 2:
1817
1775
  parser->upgrade = 1;
1818
1776
 
1777
+ /* fall through */
1819
1778
  case 1:
1820
1779
  parser->flags |= F_SKIPBODY;
1821
1780
  break;
@@ -1839,6 +1798,7 @@ reexecute:
1839
1798
  STRICT_CHECK(ch != LF);
1840
1799
 
1841
1800
  parser->nread = 0;
1801
+ nread = 0;
1842
1802
 
1843
1803
  hasBody = parser->flags & F_CHUNKED ||
1844
1804
  (parser->content_length > 0 && parser->content_length != ULLONG_MAX);
@@ -1933,7 +1893,7 @@ reexecute:
1933
1893
 
1934
1894
  case s_chunk_size_start:
1935
1895
  {
1936
- assert(parser->nread == 1);
1896
+ assert(nread == 1);
1937
1897
  assert(parser->flags & F_CHUNKED);
1938
1898
 
1939
1899
  unhex_val = unhex[(unsigned char)ch];
@@ -2001,6 +1961,7 @@ reexecute:
2001
1961
  STRICT_CHECK(ch != LF);
2002
1962
 
2003
1963
  parser->nread = 0;
1964
+ nread = 0;
2004
1965
 
2005
1966
  if (parser->content_length == 0) {
2006
1967
  parser->flags |= F_TRAILING;
@@ -2047,6 +2008,7 @@ reexecute:
2047
2008
  assert(parser->flags & F_CHUNKED);
2048
2009
  STRICT_CHECK(ch != LF);
2049
2010
  parser->nread = 0;
2011
+ nread = 0;
2050
2012
  UPDATE_STATE(s_chunk_size_start);
2051
2013
  CALLBACK_NOTIFY(chunk_complete);
2052
2014
  break;
@@ -2058,7 +2020,7 @@ reexecute:
2058
2020
  }
2059
2021
  }
2060
2022
 
2061
- /* Run callbacks for any marks that we have leftover after we ran our of
2023
+ /* Run callbacks for any marks that we have leftover after we ran out of
2062
2024
  * bytes. There should be at most one of these set, so it's OK to invoke
2063
2025
  * them in series (unset marks will not result in callbacks).
2064
2026
  *
@@ -2140,6 +2102,16 @@ http_method_str (enum http_method m)
2140
2102
  return ELEM_AT(method_strings, m, "<unknown>");
2141
2103
  }
2142
2104
 
2105
+ const char *
2106
+ http_status_str (enum http_status s)
2107
+ {
2108
+ switch (s) {
2109
+ #define XX(num, name, string) case HTTP_STATUS_##name: return #string;
2110
+ HTTP_STATUS_MAP(XX)
2111
+ #undef XX
2112
+ default: return "<unknown>";
2113
+ }
2114
+ }
2143
2115
 
2144
2116
  void
2145
2117
  http_parser_init (http_parser *parser, enum http_parser_type t)
@@ -2200,7 +2172,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
2200
2172
  return s_http_host;
2201
2173
  }
2202
2174
 
2203
- /* FALLTHROUGH */
2175
+ /* fall through */
2204
2176
  case s_http_host_v6_end:
2205
2177
  if (ch == ':') {
2206
2178
  return s_http_host_port_start;
@@ -2213,7 +2185,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
2213
2185
  return s_http_host_v6_end;
2214
2186
  }
2215
2187
 
2216
- /* FALLTHROUGH */
2188
+ /* fall through */
2217
2189
  case s_http_host_v6_start:
2218
2190
  if (IS_HEX(ch) || ch == ':' || ch == '.') {
2219
2191
  return s_http_host_v6;
@@ -2229,7 +2201,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
2229
2201
  return s_http_host_v6_end;
2230
2202
  }
2231
2203
 
2232
- /* FALLTHROUGH */
2204
+ /* fall through */
2233
2205
  case s_http_host_v6_zone_start:
2234
2206
  /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
2235
2207
  if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
@@ -2348,6 +2320,10 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2348
2320
  enum http_parser_url_fields uf, old_uf;
2349
2321
  int found_at = 0;
2350
2322
 
2323
+ if (buflen == 0) {
2324
+ return 1;
2325
+ }
2326
+
2351
2327
  u->port = u->field_set = 0;
2352
2328
  s = is_connect ? s_req_server_start : s_req_spaces_before_url;
2353
2329
  old_uf = UF_MAX;
@@ -2375,7 +2351,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2375
2351
  case s_req_server_with_at:
2376
2352
  found_at = 1;
2377
2353
 
2378
- /* FALLTROUGH */
2354
+ /* fall through */
2379
2355
  case s_req_server:
2380
2356
  uf = UF_HOST;
2381
2357
  break;
@@ -2429,12 +2405,27 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2429
2405
  }
2430
2406
 
2431
2407
  if (u->field_set & (1 << UF_PORT)) {
2432
- /* Don't bother with endp; we've already validated the string */
2433
- unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
2434
-
2435
- /* Ports have a max value of 2^16 */
2436
- if (v > 0xffff) {
2437
- return 1;
2408
+ uint16_t off;
2409
+ uint16_t len;
2410
+ const char* p;
2411
+ const char* end;
2412
+ unsigned long v;
2413
+
2414
+ off = u->field_data[UF_PORT].off;
2415
+ len = u->field_data[UF_PORT].len;
2416
+ end = buf + off + len;
2417
+
2418
+ /* NOTE: The characters are already validated and are in the [0-9] range */
2419
+ assert(off + len <= buflen && "Port number overflow");
2420
+ v = 0;
2421
+ for (p = buf + off; p < end; p++) {
2422
+ v *= 10;
2423
+ v += *p - '0';
2424
+
2425
+ /* Ports have a max value of 2^16 */
2426
+ if (v > 0xffff) {
2427
+ return 1;
2428
+ }
2438
2429
  }
2439
2430
 
2440
2431
  u->port = (uint16_t) v;
@@ -2451,6 +2442,7 @@ http_parser_pause(http_parser *parser, int paused) {
2451
2442
  */
2452
2443
  if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2453
2444
  HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2445
+ uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */
2454
2446
  SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2455
2447
  } else {
2456
2448
  assert(0 && "Attempting to pause parser in error state");
@@ -26,14 +26,13 @@ extern "C" {
26
26
 
27
27
  /* Also update SONAME in the Makefile whenever you change these. */
28
28
  #define HTTP_PARSER_VERSION_MAJOR 2
29
- #define HTTP_PARSER_VERSION_MINOR 7
29
+ #define HTTP_PARSER_VERSION_MINOR 8
30
30
  #define HTTP_PARSER_VERSION_PATCH 1
31
31
 
32
- #include <sys/types.h>
32
+ #include <stddef.h>
33
33
  #if defined(_WIN32) && !defined(__MINGW32__) && \
34
34
  (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
35
35
  #include <BaseTsd.h>
36
- #include <stddef.h>
37
36
  typedef __int8 int8_t;
38
37
  typedef unsigned __int8 uint8_t;
39
38
  typedef __int16 int16_t;
@@ -90,6 +89,76 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
90
89
  typedef int (*http_cb) (http_parser*);
91
90
 
92
91
 
92
+ /* Status Codes */
93
+ #define HTTP_STATUS_MAP(XX) \
94
+ XX(100, CONTINUE, Continue) \
95
+ XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
96
+ XX(102, PROCESSING, Processing) \
97
+ XX(200, OK, OK) \
98
+ XX(201, CREATED, Created) \
99
+ XX(202, ACCEPTED, Accepted) \
100
+ XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
101
+ XX(204, NO_CONTENT, No Content) \
102
+ XX(205, RESET_CONTENT, Reset Content) \
103
+ XX(206, PARTIAL_CONTENT, Partial Content) \
104
+ XX(207, MULTI_STATUS, Multi-Status) \
105
+ XX(208, ALREADY_REPORTED, Already Reported) \
106
+ XX(226, IM_USED, IM Used) \
107
+ XX(300, MULTIPLE_CHOICES, Multiple Choices) \
108
+ XX(301, MOVED_PERMANENTLY, Moved Permanently) \
109
+ XX(302, FOUND, Found) \
110
+ XX(303, SEE_OTHER, See Other) \
111
+ XX(304, NOT_MODIFIED, Not Modified) \
112
+ XX(305, USE_PROXY, Use Proxy) \
113
+ XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
114
+ XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
115
+ XX(400, BAD_REQUEST, Bad Request) \
116
+ XX(401, UNAUTHORIZED, Unauthorized) \
117
+ XX(402, PAYMENT_REQUIRED, Payment Required) \
118
+ XX(403, FORBIDDEN, Forbidden) \
119
+ XX(404, NOT_FOUND, Not Found) \
120
+ XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
121
+ XX(406, NOT_ACCEPTABLE, Not Acceptable) \
122
+ XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
123
+ XX(408, REQUEST_TIMEOUT, Request Timeout) \
124
+ XX(409, CONFLICT, Conflict) \
125
+ XX(410, GONE, Gone) \
126
+ XX(411, LENGTH_REQUIRED, Length Required) \
127
+ XX(412, PRECONDITION_FAILED, Precondition Failed) \
128
+ XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
129
+ XX(414, URI_TOO_LONG, URI Too Long) \
130
+ XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
131
+ XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
132
+ XX(417, EXPECTATION_FAILED, Expectation Failed) \
133
+ XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
134
+ XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
135
+ XX(423, LOCKED, Locked) \
136
+ XX(424, FAILED_DEPENDENCY, Failed Dependency) \
137
+ XX(426, UPGRADE_REQUIRED, Upgrade Required) \
138
+ XX(428, PRECONDITION_REQUIRED, Precondition Required) \
139
+ XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
140
+ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
141
+ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
142
+ XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
143
+ XX(501, NOT_IMPLEMENTED, Not Implemented) \
144
+ XX(502, BAD_GATEWAY, Bad Gateway) \
145
+ XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
146
+ XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
147
+ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
148
+ XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
149
+ XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
150
+ XX(508, LOOP_DETECTED, Loop Detected) \
151
+ XX(510, NOT_EXTENDED, Not Extended) \
152
+ XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
153
+
154
+ enum http_status
155
+ {
156
+ #define XX(num, name, string) HTTP_STATUS_##name = num,
157
+ HTTP_STATUS_MAP(XX)
158
+ #undef XX
159
+ };
160
+
161
+
93
162
  /* Request Methods */
94
163
  #define HTTP_METHOD_MAP(XX) \
95
164
  XX(0, DELETE, DELETE) \
@@ -132,6 +201,8 @@ typedef int (*http_cb) (http_parser*);
132
201
  /* RFC-2068, section 19.6.1.2 */ \
133
202
  XX(31, LINK, LINK) \
134
203
  XX(32, UNLINK, UNLINK) \
204
+ /* icecast */ \
205
+ XX(33, SOURCE, SOURCE) \
135
206
 
136
207
  enum http_method
137
208
  {
@@ -336,6 +407,9 @@ int http_should_keep_alive(const http_parser *parser);
336
407
  /* Returns a string version of the HTTP method. */
337
408
  const char *http_method_str(enum http_method m);
338
409
 
410
+ /* Returns a string version of the HTTP status code. */
411
+ const char *http_status_str(enum http_status s);
412
+
339
413
  /* Return a string name of the given error */
340
414
  const char *http_errno_name(enum http_errno err);
341
415
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HttpParser
4
- VERSION = "1.2.0"
4
+ VERSION = "1.2.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen von Takach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-04 00:00:00.000000000 Z
11
+ date: 2018-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi-compiler
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  version: '0'
120
120
  requirements: []
121
121
  rubyforge_project:
122
- rubygems_version: 2.5.1
122
+ rubygems_version: 2.7.7
123
123
  signing_key:
124
124
  specification_version: 4
125
125
  summary: Ruby bindings to joyent/http-parser