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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77d9ce494785aca207b88dd3bdc5340d94cac9ad
4
- data.tar.gz: 9ee980d7dd5d1c5f5c2467603dffc0444513fb71
3
+ metadata.gz: 417f57e6c7289be7606e9fdda1b65346751f3c10
4
+ data.tar.gz: 420957b9c7d8ed9338c29d20030109ea0f6c17c0
5
5
  SHA512:
6
- metadata.gz: 7fb958f767c35d5d71234f729ad74e346685329072122b612766787ff000e4ff21c2d12b42b5e73f6096ed63682f570b56fb7ae9f1defed42b8c1fb87d9935d5
7
- data.tar.gz: 7dfa7423fda76a94ea59df99a0e6d15b59ba61620d3e4575269508a1a3411de1e064bb0b0d99bd7d03f2e95f02e65eb0c45783cbf8c24ac570f8f3ae3d118cf7
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.988k i/100ms
59
- Unicorn's HttpParser 12.250k i/100ms
59
+ PicoHTTPParser 13.655k i/100ms
60
+ Unicorn's HttpParser 11.554k i/100ms
60
61
  -------------------------------------------------
61
- PicoHTTPParser 160.563k (± 4.3%) i/s - 811.304k
62
- Unicorn's HttpParser 135.976k (± 4.1%) i/s - 686.000k
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: 160562.7 i/s
66
- Unicorn's HttpParser: 135975.8 i/s - 1.18x slower
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
@@ -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 = <<REQ
6
- GET /blakjsdfkas HTTP/1.1\r
7
- Host: blooperblorp\r
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, rb_str_new2("REQUEST_METHOD"), rb_str_new(method,method_len));
97
- rb_hash_aset(envref, rb_str_new2("REQUEST_URI"), rb_str_new(path, path_len));
98
- rb_hash_aset(envref, rb_str_new2("SCRIPT_NAME"), rb_str_new2(""));
99
- i = sprintf(tmp,"HTTP/1.%d",minor_version);
100
- rb_hash_aset(envref, rb_str_new2("SERVER_PROTOCOL"), rb_str_new(tmp, i));
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, rb_str_new2("QUERY_STRING"), rb_str_new(path + question_at, path_len - question_at));
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
- if (header_is(headers + i, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1)) {
120
- name = "CONTENT_TYPE";
121
- name_len = sizeof("CONTENT_TYPE") - 1;
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, rb_str_new(name, name_len));
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, rb_str_new(name, name_len), slot);
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
- rb_str_cat(last_value, headers[i].value, headers[i].value_len);
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,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.
@@ -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
- ![benchmark results](http://i.gyazo.com/7e098703c29128d69d02c9a216bfb6fb.png)
20
+ ![benchmark results](http://i.gyazo.com/a85c18d3162dfb46b485bb41e0ad443a.png)
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 < 1000000; 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
- for (; ; ++buf) { \
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
- for (; ; ++buf) {
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,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.
@@ -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"));
@@ -1,3 +1,3 @@
1
1
  class PicoHTTPParser
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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.2
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-21 00:00:00.000000000 Z
11
+ date: 2014-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler