pico_http_parser 0.0.2 → 0.0.3
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 +4 -4
- data/README.md +7 -6
- data/benchmark/benchmark.rb +3 -9
- data/ext/pico_http_parser/pico_http_parser.c +101 -16
- data/ext/pico_http_parser/picohttpparser/Makefile +2 -1
- data/ext/pico_http_parser/picohttpparser/README.md +3 -3
- data/ext/pico_http_parser/picohttpparser/bench.c +3 -2
- data/ext/pico_http_parser/picohttpparser/picohttpparser.c +60 -3
- data/ext/pico_http_parser/picohttpparser/picohttpparser.h +2 -1
- data/ext/pico_http_parser/picohttpparser/test.c +13 -1
- data/lib/pico_http_parser/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 417f57e6c7289be7606e9fdda1b65346751f3c10
|
4
|
+
data.tar.gz: 420957b9c7d8ed9338c29d20030109ea0f6c17c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cd7184656ea42efb5f22aa27a42d30ed381f241c665859fbc9e94937195248db6216a4be25903799841148c51842fd2fa93bf0ddf39b699cb48192eb44d0e1a
|
7
|
+
data.tar.gz: 8656caa1f569d72acc097392e67c9316e26c7aa5546d165d1d600566e80a6e1057660696e8096fb00db9a6b7a88860fa890d8a801dbdbedf9f877c4f06e51f62
|
data/README.md
CHANGED
@@ -54,16 +54,17 @@ given request is incomplete
|
|
54
54
|
On my Macbook Air
|
55
55
|
|
56
56
|
```
|
57
|
+
$ ruby benchmark.rb
|
57
58
|
Calculating -------------------------------------
|
58
|
-
PicoHTTPParser 13.
|
59
|
-
Unicorn's HttpParser
|
59
|
+
PicoHTTPParser 13.655k i/100ms
|
60
|
+
Unicorn's HttpParser 11.554k i/100ms
|
60
61
|
-------------------------------------------------
|
61
|
-
PicoHTTPParser
|
62
|
-
Unicorn's HttpParser
|
62
|
+
PicoHTTPParser 155.331k (�� 3.7%) i/s - 778.335k
|
63
|
+
Unicorn's HttpParser 127.455k (�� 3.5%) i/s - 647.024k
|
63
64
|
|
64
65
|
Comparison:
|
65
|
-
PicoHTTPParser:
|
66
|
-
Unicorn's HttpParser:
|
66
|
+
PicoHTTPParser: 155331.2 i/s
|
67
|
+
Unicorn's HttpParser: 127455.1 i/s - 1.22x slower
|
67
68
|
```
|
68
69
|
|
69
70
|
## SEE ALSO
|
data/benchmark/benchmark.rb
CHANGED
@@ -2,15 +2,9 @@ require File.expand_path(File.dirname(__FILE__) + '/bench_helper')
|
|
2
2
|
|
3
3
|
require 'pico_http_parser'
|
4
4
|
|
5
|
-
request_body =
|
6
|
-
GET /
|
7
|
-
|
8
|
-
Cookie: blah=woop\r
|
9
|
-
\r
|
10
|
-
REQ
|
11
|
-
loop = 300000
|
12
|
-
|
13
|
-
#File.read(File.expand_path(File.dirname(__FILE__) + '/sample_request.http'))
|
5
|
+
# request_body = "GET /foo/bar/baz.html?key=value HTTP/1.0\r\nHost: blooperblorp\r\n\r\n"
|
6
|
+
request_body = "GET /foo/bar/baz.html?key=value HTTP/1.0\r\nHost: blooperblorp\r\nCookie: foobar\r\nX-Forwared-For: 127.0.0.1\r\n\r\n"
|
7
|
+
# request_body = "GET /foo/bar/baz.html?key=value HTTP/1.0\r\n\r\n"
|
14
8
|
|
15
9
|
Benchmark.ips do |x|
|
16
10
|
x.time = 5
|
@@ -8,6 +8,58 @@
|
|
8
8
|
|
9
9
|
VALUE cPicoHTTPParser;
|
10
10
|
|
11
|
+
static VALUE request_method_key;
|
12
|
+
static VALUE request_uri_key;
|
13
|
+
static VALUE script_name_key;
|
14
|
+
static VALUE server_protocol_key;
|
15
|
+
static VALUE query_string_key;
|
16
|
+
|
17
|
+
struct common_header {
|
18
|
+
const char * name;
|
19
|
+
size_t name_len;
|
20
|
+
VALUE key;
|
21
|
+
};
|
22
|
+
static int common_headers_num = 0;
|
23
|
+
static struct common_header common_headers[20];
|
24
|
+
|
25
|
+
static
|
26
|
+
void set_common_header(const char * key, int key_len, const int raw)
|
27
|
+
{
|
28
|
+
char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") - 1];
|
29
|
+
const char* name;
|
30
|
+
size_t name_len;
|
31
|
+
const char * s;
|
32
|
+
char* d;
|
33
|
+
size_t n;
|
34
|
+
VALUE env_key;
|
35
|
+
|
36
|
+
if ( raw == 1) {
|
37
|
+
for (s = key, n = key_len, d = tmp;
|
38
|
+
n != 0;
|
39
|
+
s++, --n, d++) {
|
40
|
+
*d = *s == '-' ? '_' : TOU(*s);
|
41
|
+
name = tmp;
|
42
|
+
name_len = key_len;
|
43
|
+
}
|
44
|
+
} else {
|
45
|
+
strcpy(tmp, "HTTP_");
|
46
|
+
for (s = key, n = key_len, d = tmp + 5;
|
47
|
+
n != 0;
|
48
|
+
s++, --n, d++) {
|
49
|
+
*d = *s == '-' ? '_' : TOU(*s);
|
50
|
+
name = tmp;
|
51
|
+
name_len = key_len + 5;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
env_key = rb_obj_freeze(rb_str_new(name,name_len));
|
55
|
+
common_headers[common_headers_num].name = key;
|
56
|
+
common_headers[common_headers_num].name_len = key_len;
|
57
|
+
common_headers[common_headers_num].key = env_key;
|
58
|
+
rb_gc_register_address(&common_headers[common_headers_num].key);
|
59
|
+
common_headers_num++;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
11
63
|
static
|
12
64
|
size_t find_ch(const char* s, size_t len, char ch)
|
13
65
|
{
|
@@ -31,6 +83,16 @@ int header_is(const struct phr_header* header, const char* name,
|
|
31
83
|
return 1;
|
32
84
|
}
|
33
85
|
|
86
|
+
static
|
87
|
+
VALUE find_common_header(const struct phr_header* header) {
|
88
|
+
int i;
|
89
|
+
for ( i = 0; i < common_headers_num; i++ ) {
|
90
|
+
if ( header_is(header, common_headers[i].name, common_headers[i].name_len) ) {
|
91
|
+
return common_headers[i].key;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
return Qnil;
|
95
|
+
}
|
34
96
|
|
35
97
|
static
|
36
98
|
int store_path_info(VALUE envref, const char* src, size_t src_len) {
|
@@ -93,11 +155,12 @@ VALUE phr_parse_http_request(VALUE self, VALUE buf, VALUE envref)
|
|
93
155
|
if (ret < 0)
|
94
156
|
goto done;
|
95
157
|
|
96
|
-
rb_hash_aset(envref,
|
97
|
-
rb_hash_aset(envref,
|
98
|
-
rb_hash_aset(envref,
|
99
|
-
|
100
|
-
|
158
|
+
rb_hash_aset(envref, request_method_key, rb_str_new(method,method_len));
|
159
|
+
rb_hash_aset(envref, request_uri_key, rb_str_new(path, path_len));
|
160
|
+
rb_hash_aset(envref, script_name_key, rb_str_new2(""));
|
161
|
+
strcpy(tmp, "HTTP/1.");
|
162
|
+
tmp[7] = 48 + ((minor_version > 1 || minor_version < 0 ) ? 0 : minor_version);
|
163
|
+
rb_hash_aset(envref, server_protocol_key, rb_str_new(tmp, sizeof("HTTP/1.0") - 1));
|
101
164
|
|
102
165
|
/* PATH_INFO QUERY_STRING */
|
103
166
|
path_len = find_ch(path, path_len, '#'); /* strip off all text after # after storing request_uri */
|
@@ -108,7 +171,7 @@ VALUE phr_parse_http_request(VALUE self, VALUE buf, VALUE envref)
|
|
108
171
|
goto done;
|
109
172
|
}
|
110
173
|
if (question_at != path_len) ++question_at;
|
111
|
-
rb_hash_aset(envref,
|
174
|
+
rb_hash_aset(envref, query_string_key, rb_str_new(path + question_at, path_len - question_at));
|
112
175
|
|
113
176
|
last_value = Qnil;
|
114
177
|
for (i = 0; i < num_headers; ++i) {
|
@@ -116,13 +179,9 @@ VALUE phr_parse_http_request(VALUE self, VALUE buf, VALUE envref)
|
|
116
179
|
const char* name;
|
117
180
|
size_t name_len;
|
118
181
|
VALUE slot;
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
} else if (header_is(headers + i, "CONTENT-LENGTH", sizeof("CONTENT-LENGTH") - 1)) {
|
123
|
-
name = "CONTENT_LENGTH";
|
124
|
-
name_len = sizeof("CONTENT_LENGTH") - 1;
|
125
|
-
} else {
|
182
|
+
VALUE env_key;
|
183
|
+
env_key = find_common_header(headers + i);
|
184
|
+
if ( env_key == Qnil ) {
|
126
185
|
const char* s;
|
127
186
|
char* d;
|
128
187
|
size_t n;
|
@@ -138,20 +197,22 @@ VALUE phr_parse_http_request(VALUE self, VALUE buf, VALUE envref)
|
|
138
197
|
*d = *s == '-' ? '_' : TOU(*s);
|
139
198
|
name = tmp;
|
140
199
|
name_len = headers[i].name_len + 5;
|
200
|
+
env_key = rb_str_new(name, name_len);
|
141
201
|
}
|
142
202
|
}
|
143
|
-
slot = rb_hash_aref(envref,
|
203
|
+
slot = rb_hash_aref(envref, env_key);
|
144
204
|
if ( slot != Qnil ) {
|
145
205
|
rb_str_cat2(slot, ", ");
|
146
206
|
rb_str_cat(slot, headers[i].value, headers[i].value_len);
|
147
207
|
} else {
|
148
208
|
slot = rb_str_new(headers[i].value, headers[i].value_len);
|
149
|
-
rb_hash_aset(envref,
|
209
|
+
rb_hash_aset(envref, env_key, slot);
|
150
210
|
last_value = slot;
|
151
211
|
}
|
152
212
|
} else {
|
153
213
|
/* continuing lines of a mulitiline header */
|
154
|
-
|
214
|
+
if ( last_value != Qnil )
|
215
|
+
rb_str_cat(last_value, headers[i].value, headers[i].value_len);
|
155
216
|
}
|
156
217
|
}
|
157
218
|
|
@@ -161,6 +222,30 @@ VALUE phr_parse_http_request(VALUE self, VALUE buf, VALUE envref)
|
|
161
222
|
|
162
223
|
void Init_pico_http_parser()
|
163
224
|
{
|
225
|
+
request_method_key = rb_obj_freeze(rb_str_new2("REQUEST_METHOD"));
|
226
|
+
rb_gc_register_address(&request_method_key);
|
227
|
+
request_uri_key = rb_obj_freeze(rb_str_new2("REQUEST_URI"));
|
228
|
+
rb_gc_register_address(&request_uri_key);
|
229
|
+
script_name_key = rb_obj_freeze(rb_str_new2("SCRIPT_NAME"));
|
230
|
+
rb_gc_register_address(&script_name_key);
|
231
|
+
server_protocol_key = rb_obj_freeze(rb_str_new2("SERVER_PROTOCOL"));
|
232
|
+
rb_gc_register_address(&server_protocol_key);
|
233
|
+
query_string_key = rb_obj_freeze(rb_str_new2("QUERY_STRING"));
|
234
|
+
rb_gc_register_address(&query_string_key);
|
235
|
+
|
236
|
+
set_common_header("ACCEPT",sizeof("ACCEPT") - 1, 0);
|
237
|
+
set_common_header("ACCEPT-ENCODING",sizeof("ACCEPT-ENCODING") - 1, 0);
|
238
|
+
set_common_header("ACCEPT-LANGUAGE",sizeof("ACCEPT-LANGUAGE") - 1, 0);
|
239
|
+
set_common_header("CACHE-CONTROL",sizeof("CACHE-CONTROL") - 1, 0);
|
240
|
+
set_common_header("CONNECTION",sizeof("CONNECTION") - 1, 0);
|
241
|
+
set_common_header("CONTENT-LENGTH",sizeof("CONTENT-LENGTH") - 1, 1);
|
242
|
+
set_common_header("CONTENT-TYPE",sizeof("CONTENT-TYPE") - 1, 1);
|
243
|
+
set_common_header("COOKIE",sizeof("COOKIE") - 1, 0);
|
244
|
+
set_common_header("HOST",sizeof("HOST") - 1, 0);
|
245
|
+
set_common_header("IF-MODIFIED-SINCE",sizeof("IF-MODIFIED-SINCE") - 1, 0);
|
246
|
+
set_common_header("REFERER",sizeof("REFERER") - 1, 0);
|
247
|
+
set_common_header("USER-AGENT",sizeof("USER-AGENT") - 1, 0);
|
248
|
+
set_common_header("X-FORWARDED-FOR",sizeof("X-FORWARDED-FOR") - 1, 0);
|
164
249
|
|
165
250
|
cPicoHTTPParser = rb_const_get(rb_cObject, rb_intern("PicoHTTPParser"));
|
166
251
|
rb_define_module_function(cPicoHTTPParser, "parse_http_request", phr_parse_http_request, 2);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
PicoHTTPParser
|
2
2
|
=============
|
3
3
|
|
4
|
-
Copyright (c) 2009-2014 [Kazuho Oku](https://github.com/kazuho), [Tokuhiro Matsuno](https://github.com/tokuhirom), [Daisuke Murase](https://github.com/typester)
|
4
|
+
Copyright (c) 2009-2014 [Kazuho Oku](https://github.com/kazuho), [Tokuhiro Matsuno](https://github.com/tokuhirom), [Daisuke Murase](https://github.com/typester), [Shigeo Mitsunari](https://github.com/herumi)
|
5
5
|
|
6
6
|
PicoHTTPParser is a tiny, primitive, fast HTTP request/response parser.
|
7
7
|
|
@@ -17,8 +17,8 @@ The software is dual-licensed under the Perl License or the MIT License.
|
|
17
17
|
Benchmark
|
18
18
|
---------
|
19
19
|
|
20
|
-

|
21
21
|
|
22
|
-
The benchmark code is from [fukamachi/fast-http](https://github.com/fukamachi/fast-http/).
|
22
|
+
The benchmark code is from [fukamachi/fast-http@6b91103](https://github.com/fukamachi/fast-http/tree/6b9110347c7a3407310c08979aefd65078518478).
|
23
23
|
|
24
24
|
The internals of picohttpparser has been described to some extent in [my blog entry]( http://blog.kazuhooku.com/2014/11/the-internals-h2o-or-how-to-write-fast.html).
|
@@ -1,5 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase
|
2
|
+
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
|
3
|
+
* Shigeo Mitsunari
|
3
4
|
*
|
4
5
|
* The software is licensed under either the MIT License (below) or the Perl
|
5
6
|
* license.
|
@@ -40,7 +41,7 @@ int main(void)
|
|
40
41
|
size_t num_headers;
|
41
42
|
int i, ret;
|
42
43
|
|
43
|
-
for (i = 0; i <
|
44
|
+
for (i = 0; i < 10000000; i++) {
|
44
45
|
num_headers = sizeof(headers) / sizeof(headers[0]);
|
45
46
|
ret = phr_parse_request(REQ, sizeof(REQ) - 1, &method, &method_len, &path,
|
46
47
|
&path_len, &minor_version, headers, &num_headers,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase
|
2
|
+
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
|
3
|
+
* Shigeo Mitsunari
|
3
4
|
*
|
4
5
|
* The software is licensed under either the MIT License (below) or the Perl
|
5
6
|
* license.
|
@@ -24,6 +25,9 @@
|
|
24
25
|
*/
|
25
26
|
|
26
27
|
#include <stddef.h>
|
28
|
+
#ifdef __SSE4_2__
|
29
|
+
# include <x86intrin.h>
|
30
|
+
#endif
|
27
31
|
#include "picohttpparser.h"
|
28
32
|
|
29
33
|
/* $Id$ */
|
@@ -53,8 +57,13 @@
|
|
53
57
|
|
54
58
|
#define ADVANCE_TOKEN(tok, toklen) do { \
|
55
59
|
const char* tok_start = buf; \
|
56
|
-
|
60
|
+
static const char ranges2[] __attribute__((aligned(16))) = "\000\040\177\177"; \
|
61
|
+
int found2; \
|
62
|
+
buf = findchar_fast(buf, buf_end, ranges2, sizeof(ranges2) - 1, &found2); \
|
63
|
+
if (! found2) { \
|
57
64
|
CHECK_EOF(); \
|
65
|
+
} \
|
66
|
+
while (1) { \
|
58
67
|
if (*buf == ' ') { \
|
59
68
|
break; \
|
60
69
|
} else if (unlikely(! IS_PRINTABLE_ASCII(*buf))) { \
|
@@ -63,6 +72,8 @@
|
|
63
72
|
return NULL; \
|
64
73
|
} \
|
65
74
|
} \
|
75
|
+
++buf; \
|
76
|
+
CHECK_EOF(); \
|
66
77
|
} \
|
67
78
|
tok = tok_start; \
|
68
79
|
toklen = buf - tok_start; \
|
@@ -78,12 +89,50 @@ static const char* token_char_map =
|
|
78
89
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
79
90
|
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
80
91
|
|
92
|
+
static const char* findchar_fast(const char* buf, const char* buf_end, const char *ranges, size_t ranges_size, int* found)
|
93
|
+
{
|
94
|
+
*found = 0;
|
95
|
+
#if __SSE4_2__
|
96
|
+
if (likely(buf_end - buf >= 16)) {
|
97
|
+
__m128i ranges16 = _mm_loadu_si128((const __m128i*)ranges);
|
98
|
+
|
99
|
+
size_t left = (buf_end - buf) & ~15;
|
100
|
+
do {
|
101
|
+
__m128i b16 = _mm_loadu_si128((void*)buf);
|
102
|
+
int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
|
103
|
+
if (unlikely(r != 16)) {
|
104
|
+
buf += r;
|
105
|
+
*found = 1;
|
106
|
+
break;
|
107
|
+
}
|
108
|
+
buf += 16;
|
109
|
+
left -= 16;
|
110
|
+
} while (likely(left != 0));
|
111
|
+
}
|
112
|
+
#endif
|
113
|
+
return buf;
|
114
|
+
}
|
115
|
+
|
81
116
|
static const char* get_token_to_eol(const char* buf, const char* buf_end,
|
82
117
|
const char** token, size_t* token_len,
|
83
118
|
int* ret)
|
84
119
|
{
|
85
120
|
const char* token_start = buf;
|
86
121
|
|
122
|
+
#ifdef __SSE4_2__
|
123
|
+
static const char ranges1[] =
|
124
|
+
"\0\010"
|
125
|
+
/* allow HT */
|
126
|
+
"\012\037"
|
127
|
+
/* allow SP and up to but not including DEL */
|
128
|
+
"\177\177"
|
129
|
+
/* allow chars w. MSB set */
|
130
|
+
;
|
131
|
+
int found;
|
132
|
+
buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
|
133
|
+
if (found)
|
134
|
+
goto FOUND_CTL;
|
135
|
+
#else
|
87
136
|
/* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
|
88
137
|
while (likely(buf_end - buf >= 8)) {
|
89
138
|
#define DOIT() if (unlikely(! IS_PRINTABLE_ASCII(*buf))) goto NonPrintable; ++buf
|
@@ -97,6 +146,7 @@ static const char* get_token_to_eol(const char* buf, const char* buf_end,
|
|
97
146
|
}
|
98
147
|
++buf;
|
99
148
|
}
|
149
|
+
#endif
|
100
150
|
for (; ; ++buf) {
|
101
151
|
CHECK_EOF();
|
102
152
|
if (unlikely(! IS_PRINTABLE_ASCII(*buf))) {
|
@@ -211,14 +261,21 @@ static const char* parse_headers(const char* buf, const char* buf_end,
|
|
211
261
|
/* parsing name, but do not discard SP before colon, see
|
212
262
|
* http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
|
213
263
|
headers[*num_headers].name = buf;
|
214
|
-
|
264
|
+
static const char ranges1[] __attribute__((aligned(16))) = "::\x00\037";
|
265
|
+
int found;
|
266
|
+
buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
|
267
|
+
if (! found) {
|
215
268
|
CHECK_EOF();
|
269
|
+
}
|
270
|
+
while (1) {
|
216
271
|
if (*buf == ':') {
|
217
272
|
break;
|
218
273
|
} else if (*buf < ' ') {
|
219
274
|
*ret = -1;
|
220
275
|
return NULL;
|
221
276
|
}
|
277
|
+
++buf;
|
278
|
+
CHECK_EOF();
|
222
279
|
}
|
223
280
|
headers[*num_headers].name_len = buf - headers[*num_headers].name;
|
224
281
|
++buf;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
/* use `make test` to run the test */
|
2
2
|
/*
|
3
|
-
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase
|
3
|
+
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
|
4
|
+
* Shigeo Mitsunari
|
4
5
|
*
|
5
6
|
* The software is licensed under either the MIT License (below) or the Perl
|
6
7
|
* license.
|
@@ -97,6 +98,15 @@ static void test_request(void)
|
|
97
98
|
ok(headers[2].name == NULL);
|
98
99
|
ok(bufis(headers[2].value, headers[2].value_len, " \tc"));
|
99
100
|
|
101
|
+
PARSE("GET / HTTP/1.0\r\nfoo : ab\r\n\r\n", 0, 0,
|
102
|
+
"parse header name with trailing space");
|
103
|
+
ok(num_headers == 1);
|
104
|
+
ok(bufis(method, method_len, "GET"));
|
105
|
+
ok(bufis(path, path_len, "/"));
|
106
|
+
ok(minor_version == 0);
|
107
|
+
ok(bufis(headers[0].name, headers[0].name_len, "foo "));
|
108
|
+
ok(bufis(headers[0].value, headers[0].value_len, "ab"));
|
109
|
+
|
100
110
|
PARSE("GET", 0, -2, "incomplete 1");
|
101
111
|
ok(method == NULL);
|
102
112
|
PARSE("GET ", 0, -2, "incomplete 2");
|
@@ -125,6 +135,8 @@ static void test_request(void)
|
|
125
135
|
PARSE("GET /\x7fhello HTTP/1.0\r\n\r\n", 0, -1, "DEL in uri-path");
|
126
136
|
PARSE("GET / HTTP/1.0\r\na\0b: c\r\n\r\n", 0, -1, "NUL in header name");
|
127
137
|
PARSE("GET / HTTP/1.0\r\nab: c\0d\r\n\r\n", 0, -1, "NUL in header value");
|
138
|
+
PARSE("GET / HTTP/1.0\r\na\033b: c\r\n\r\n", 0, -1, "CTL in header name");
|
139
|
+
PARSE("GET / HTTP/1.0\r\nab: c\033\r\n\r\n", 0, -1, "CTL in header value");
|
128
140
|
PARSE("GET /\xa0 HTTP/1.0\r\nh: c\xa2y\r\n\r\n", 0, 0, "accept MSB chars");
|
129
141
|
ok(num_headers == 1);
|
130
142
|
ok(bufis(method, method_len, "GET"));
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pico_http_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro Nagano
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|