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 +5 -5
- data/ext/Rakefile +2 -2
- data/ext/http-parser/http_parser.c +146 -154
- data/ext/http-parser/http_parser.h +77 -3
- data/lib/http-parser/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b10418834197ee747e8e8b0f731efef8f1f80285f05426292b627edadc7da52a
|
|
4
|
+
data.tar.gz: 5e159cadc303a5a811754eeac131d56bb5e6f8eff66be4650c049c8fc10a4a2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3fb875b674223383319ab6b02b019acf27964cddec2bb732773d4315f1aac472529b27b1a4edbf8bdbfd5441117c8a274009ad0ace5457082918e42043aa75ef
|
|
7
|
+
data.tar.gz: 3ada5a0f5e72ff81495e6b97c3ea20d16aa7b536fe6a7425477e73360228e3983c92788663ed3fe76e3c1b194230092f1bbed1274e68cf853bdc583c1d053cda
|
data/ext/Rakefile
CHANGED
|
@@ -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
|
|
7
|
-
t.ldflags << "-arch x86_64
|
|
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
|
-
/*
|
|
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
|
-
|
|
157
|
-
if (UNLIKELY(
|
|
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
|
-
|
|
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
|
-
,
|
|
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
|
-
,
|
|
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) (
|
|
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)
|
|
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
|
-
/*
|
|
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
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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(
|
|
794
|
+
UPDATE_STATE(s_res_http_major);
|
|
799
795
|
break;
|
|
800
796
|
|
|
801
|
-
case
|
|
802
|
-
if (UNLIKELY(ch
|
|
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(
|
|
804
|
+
UPDATE_STATE(s_res_http_dot);
|
|
809
805
|
break;
|
|
810
806
|
|
|
811
|
-
|
|
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
|
-
|
|
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(
|
|
825
|
+
UPDATE_STATE(s_res_http_end);
|
|
844
826
|
break;
|
|
845
827
|
|
|
846
|
-
|
|
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(
|
|
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 (
|
|
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
|
|
1184
|
-
|
|
1124
|
+
parser->http_major = ch - '0';
|
|
1125
|
+
UPDATE_STATE(s_req_http_dot);
|
|
1126
|
+
break;
|
|
1185
1127
|
|
|
1186
|
-
|
|
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
|
-
|
|
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(
|
|
1146
|
+
UPDATE_STATE(s_req_http_end);
|
|
1203
1147
|
break;
|
|
1204
1148
|
|
|
1205
|
-
|
|
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
|
-
|
|
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
|
-
/*
|
|
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 == ' ')
|
|
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->
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
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(
|
|
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
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
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
|
|
29
|
+
#define HTTP_PARSER_VERSION_MINOR 8
|
|
30
30
|
#define HTTP_PARSER_VERSION_PATCH 1
|
|
31
31
|
|
|
32
|
-
#include <
|
|
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
|
|
data/lib/http-parser/version.rb
CHANGED
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.
|
|
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:
|
|
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.
|
|
122
|
+
rubygems_version: 2.7.7
|
|
123
123
|
signing_key:
|
|
124
124
|
specification_version: 4
|
|
125
125
|
summary: Ruby bindings to joyent/http-parser
|