http-parser 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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