http_parser.rb 0.5.0-x86-mingw32

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.
Files changed (57) hide show
  1. data/.gitignore +11 -0
  2. data/.gitmodules +6 -0
  3. data/README.md +45 -0
  4. data/Rakefile +6 -0
  5. data/bench/thin.rb +57 -0
  6. data/ext/ruby_http_parser/.gitignore +1 -0
  7. data/ext/ruby_http_parser/RubyHttpParserService.java +18 -0
  8. data/ext/ruby_http_parser/ext_help.h +18 -0
  9. data/ext/ruby_http_parser/extconf.rb +16 -0
  10. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +403 -0
  11. data/ext/ruby_http_parser/ruby_http_parser.c +474 -0
  12. data/ext/ruby_http_parser/vendor/.gitkeep +0 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +4 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +19 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +171 -0
  16. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +19 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/compile +1 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1590 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +167 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +7 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +90 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +31 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java +13 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java +5 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java +25 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java +7 -0
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +1894 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +78 -0
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/Util.java +112 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +487 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +115 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1865 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +539 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb +6 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb +13 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb +15 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb +33 -0
  40. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +4 -0
  41. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +19 -0
  42. data/ext/ruby_http_parser/vendor/http-parser/README.md +171 -0
  43. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1590 -0
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +167 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/test.c +1755 -0
  46. data/http_parser.rb.gemspec +15 -0
  47. data/lib/http/parser.rb +1 -0
  48. data/lib/http_parser.rb +4 -0
  49. data/lib/ruby_http_parser.rb +2 -0
  50. data/spec/parser_spec.rb +187 -0
  51. data/spec/spec_helper.rb +2 -0
  52. data/spec/support/requests.json +381 -0
  53. data/spec/support/responses.json +186 -0
  54. data/tasks/compile.rake +39 -0
  55. data/tasks/spec.rake +5 -0
  56. data/tasks/submodules.rake +7 -0
  57. metadata +124 -0
@@ -0,0 +1,474 @@
1
+ #include "ruby.h"
2
+ #include "ext_help.h"
3
+ #include "ryah_http_parser.h"
4
+
5
+ #define GET_WRAPPER(N, from) ParserWrapper *N = (ParserWrapper *)(from)->data;
6
+ #define HASH_CAT(h, k, ptr, len) \
7
+ do { \
8
+ VALUE __v = rb_hash_aref(h, k); \
9
+ if (__v != Qnil) { \
10
+ rb_str_cat(__v, ptr, len); \
11
+ } else { \
12
+ rb_hash_aset(h, k, rb_str_new(ptr, len)); \
13
+ } \
14
+ } while(0)
15
+
16
+ typedef struct ParserWrapper {
17
+ ryah_http_parser parser;
18
+
19
+ VALUE request_url;
20
+ VALUE request_path;
21
+ VALUE query_string;
22
+ VALUE fragment;
23
+
24
+ VALUE headers;
25
+
26
+ VALUE on_message_begin;
27
+ VALUE on_headers_complete;
28
+ VALUE on_body;
29
+ VALUE on_message_complete;
30
+
31
+ VALUE callback_object;
32
+ VALUE stopped;
33
+
34
+ VALUE last_field_name;
35
+ const char *last_field_name_at;
36
+ size_t last_field_name_length;
37
+
38
+ enum ryah_http_parser_type type;
39
+ } ParserWrapper;
40
+
41
+ void ParserWrapper_init(ParserWrapper *wrapper) {
42
+ ryah_http_parser_init(&wrapper->parser, wrapper->type);
43
+ wrapper->parser.status_code = 0;
44
+ wrapper->parser.http_major = 0;
45
+ wrapper->parser.http_minor = 0;
46
+
47
+ wrapper->request_url = Qnil;
48
+ wrapper->request_path = Qnil;
49
+ wrapper->query_string = Qnil;
50
+ wrapper->fragment = Qnil;
51
+
52
+ wrapper->headers = Qnil;
53
+
54
+ wrapper->last_field_name = Qnil;
55
+ wrapper->last_field_name_at = NULL;
56
+ wrapper->last_field_name_length = 0;
57
+ }
58
+
59
+ void ParserWrapper_mark(void *data) {
60
+ if(data) {
61
+ ParserWrapper *wrapper = (ParserWrapper *) data;
62
+ rb_gc_mark_maybe(wrapper->request_url);
63
+ rb_gc_mark_maybe(wrapper->request_path);
64
+ rb_gc_mark_maybe(wrapper->query_string);
65
+ rb_gc_mark_maybe(wrapper->fragment);
66
+ rb_gc_mark_maybe(wrapper->headers);
67
+ rb_gc_mark_maybe(wrapper->on_message_begin);
68
+ rb_gc_mark_maybe(wrapper->on_headers_complete);
69
+ rb_gc_mark_maybe(wrapper->on_body);
70
+ rb_gc_mark_maybe(wrapper->on_message_complete);
71
+ rb_gc_mark_maybe(wrapper->callback_object);
72
+ rb_gc_mark_maybe(wrapper->last_field_name);
73
+ }
74
+ }
75
+
76
+ void ParserWrapper_free(void *data) {
77
+ if(data) {
78
+ free(data);
79
+ }
80
+ }
81
+
82
+ static VALUE cParser;
83
+ static VALUE cRequestParser;
84
+ static VALUE cResponseParser;
85
+
86
+ static VALUE eParserError;
87
+
88
+ static ID Icall;
89
+ static ID Ion_message_begin;
90
+ static ID Ion_headers_complete;
91
+ static ID Ion_body;
92
+ static ID Ion_message_complete;
93
+
94
+ static VALUE Sstop;
95
+
96
+ /** Callbacks **/
97
+
98
+ int on_message_begin(ryah_http_parser *parser) {
99
+ GET_WRAPPER(wrapper, parser);
100
+
101
+ wrapper->request_url = rb_str_new2("");
102
+ wrapper->request_path = rb_str_new2("");
103
+ wrapper->query_string = rb_str_new2("");
104
+ wrapper->fragment = rb_str_new2("");
105
+ wrapper->headers = rb_hash_new();
106
+
107
+ VALUE ret = Qnil;
108
+
109
+ if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_message_begin)) {
110
+ ret = rb_funcall(wrapper->callback_object, Ion_message_begin, 0);
111
+ } else if (wrapper->on_message_begin != Qnil) {
112
+ ret = rb_funcall(wrapper->on_message_begin, Icall, 0);
113
+ }
114
+
115
+ if (ret == Sstop) {
116
+ wrapper->stopped = Qtrue;
117
+ return -1;
118
+ } else {
119
+ return 0;
120
+ }
121
+ }
122
+
123
+ int on_url(ryah_http_parser *parser, const char *at, size_t length) {
124
+ GET_WRAPPER(wrapper, parser);
125
+ rb_str_cat(wrapper->request_url, at, length);
126
+ return 0;
127
+ }
128
+
129
+ int on_path(ryah_http_parser *parser, const char *at, size_t length) {
130
+ GET_WRAPPER(wrapper, parser);
131
+ rb_str_cat(wrapper->request_path, at, length);
132
+ return 0;
133
+ }
134
+
135
+ int on_query_string(ryah_http_parser *parser, const char *at, size_t length) {
136
+ GET_WRAPPER(wrapper, parser);
137
+ rb_str_cat(wrapper->query_string, at, length);
138
+ return 0;
139
+ }
140
+
141
+ int on_fragment(ryah_http_parser *parser, const char *at, size_t length) {
142
+ GET_WRAPPER(wrapper, parser);
143
+ rb_str_cat(wrapper->fragment, at, length);
144
+ return 0;
145
+ }
146
+
147
+ int on_header_field(ryah_http_parser *parser, const char *at, size_t length) {
148
+ GET_WRAPPER(wrapper, parser);
149
+
150
+ wrapper->last_field_name = Qnil;
151
+
152
+ if (wrapper->last_field_name_at == NULL) {
153
+ wrapper->last_field_name_at = at;
154
+ wrapper->last_field_name_length = length;
155
+ } else {
156
+ wrapper->last_field_name_length += length;
157
+ }
158
+
159
+ return 0;
160
+ }
161
+
162
+ int on_header_value(ryah_http_parser *parser, const char *at, size_t length) {
163
+ GET_WRAPPER(wrapper, parser);
164
+
165
+ if (wrapper->last_field_name == Qnil) {
166
+ wrapper->last_field_name = rb_str_new(wrapper->last_field_name_at, wrapper->last_field_name_length);
167
+
168
+ VALUE val = rb_hash_aref(wrapper->headers, wrapper->last_field_name);
169
+ if (val != Qnil) {
170
+ rb_str_cat(val, ", ", 2);
171
+ }
172
+
173
+ wrapper->last_field_name_at = NULL;
174
+ wrapper->last_field_name_length = 0;
175
+ }
176
+
177
+ HASH_CAT(wrapper->headers, wrapper->last_field_name, at, length);
178
+
179
+ return 0;
180
+ }
181
+
182
+ int on_headers_complete(ryah_http_parser *parser) {
183
+ GET_WRAPPER(wrapper, parser);
184
+
185
+ VALUE ret = Qnil;
186
+
187
+ if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_headers_complete)) {
188
+ ret = rb_funcall(wrapper->callback_object, Ion_headers_complete, 1, wrapper->headers);
189
+ } else if (wrapper->on_headers_complete != Qnil) {
190
+ ret = rb_funcall(wrapper->on_headers_complete, Icall, 1, wrapper->headers);
191
+ }
192
+
193
+ if (ret == Sstop) {
194
+ wrapper->stopped = Qtrue;
195
+ return -1;
196
+ } else {
197
+ return 0;
198
+ }
199
+ }
200
+
201
+ int on_body(ryah_http_parser *parser, const char *at, size_t length) {
202
+ GET_WRAPPER(wrapper, parser);
203
+
204
+ VALUE ret = Qnil;
205
+
206
+ if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_body)) {
207
+ ret = rb_funcall(wrapper->callback_object, Ion_body, 1, rb_str_new(at, length));
208
+ } else if (wrapper->on_body != Qnil) {
209
+ ret = rb_funcall(wrapper->on_body, Icall, 1, rb_str_new(at, length));
210
+ }
211
+
212
+ if (ret == Sstop) {
213
+ wrapper->stopped = Qtrue;
214
+ return -1;
215
+ } else {
216
+ return 0;
217
+ }
218
+ }
219
+
220
+ int on_message_complete(ryah_http_parser *parser) {
221
+ GET_WRAPPER(wrapper, parser);
222
+
223
+ VALUE ret = Qnil;
224
+
225
+ if (wrapper->callback_object != Qnil && rb_respond_to(wrapper->callback_object, Ion_message_complete)) {
226
+ ret = rb_funcall(wrapper->callback_object, Ion_message_complete, 0);
227
+ } else if (wrapper->on_message_complete != Qnil) {
228
+ ret = rb_funcall(wrapper->on_message_complete, Icall, 0);
229
+ }
230
+
231
+ if (ret == Sstop) {
232
+ wrapper->stopped = Qtrue;
233
+ return -1;
234
+ } else {
235
+ return 0;
236
+ }
237
+ }
238
+
239
+ static ryah_http_parser_settings settings = {
240
+ .on_message_begin = on_message_begin,
241
+ .on_path = on_path,
242
+ .on_query_string = on_query_string,
243
+ .on_url = on_url,
244
+ .on_fragment = on_fragment,
245
+ .on_header_field = on_header_field,
246
+ .on_header_value = on_header_value,
247
+ .on_headers_complete = on_headers_complete,
248
+ .on_body = on_body,
249
+ .on_message_complete = on_message_complete
250
+ };
251
+
252
+ VALUE Parser_alloc_by_type(VALUE klass, enum ryah_http_parser_type type) {
253
+ ParserWrapper *wrapper = ALLOC_N(ParserWrapper, 1);
254
+ wrapper->type = type;
255
+ wrapper->parser.data = wrapper;
256
+
257
+ wrapper->on_message_begin = Qnil;
258
+ wrapper->on_headers_complete = Qnil;
259
+ wrapper->on_body = Qnil;
260
+ wrapper->on_message_complete = Qnil;
261
+
262
+ wrapper->callback_object = Qnil;
263
+
264
+ ParserWrapper_init(wrapper);
265
+
266
+ return Data_Wrap_Struct(klass, ParserWrapper_mark, ParserWrapper_free, wrapper);
267
+ }
268
+
269
+ VALUE Parser_alloc(VALUE klass) {
270
+ return Parser_alloc_by_type(klass, HTTP_BOTH);
271
+ }
272
+
273
+ VALUE RequestParser_alloc(VALUE klass) {
274
+ return Parser_alloc_by_type(klass, HTTP_REQUEST);
275
+ }
276
+
277
+ VALUE ResponseParser_alloc(VALUE klass) {
278
+ return Parser_alloc_by_type(klass, HTTP_RESPONSE);
279
+ }
280
+
281
+ VALUE Parser_initialize(int argc, VALUE *argv, VALUE self) {
282
+ ParserWrapper *wrapper = NULL;
283
+ DATA_GET(self, ParserWrapper, wrapper);
284
+
285
+ if (argc == 1)
286
+ wrapper->callback_object = argv[0];
287
+
288
+ return self;
289
+ }
290
+
291
+ VALUE Parser_execute(VALUE self, VALUE data) {
292
+ ParserWrapper *wrapper = NULL;
293
+ char *ptr = RSTRING_PTR(data);
294
+ long len = RSTRING_LEN(data);
295
+
296
+ DATA_GET(self, ParserWrapper, wrapper);
297
+
298
+ wrapper->stopped = Qfalse;
299
+ size_t nparsed = ryah_http_parser_execute(&wrapper->parser, &settings, ptr, len);
300
+
301
+ if (wrapper->parser.upgrade) {
302
+ // upgrade request
303
+ } else if (nparsed != len) {
304
+ if (!RTEST(wrapper->stopped))
305
+ rb_raise(eParserError, "Could not parse data entirely");
306
+ else
307
+ nparsed += 1; // error states fail on the current character
308
+ }
309
+
310
+ return INT2FIX(nparsed);
311
+ }
312
+
313
+ VALUE Parser_set_on_message_begin(VALUE self, VALUE callback) {
314
+ ParserWrapper *wrapper = NULL;
315
+ DATA_GET(self, ParserWrapper, wrapper);
316
+
317
+ wrapper->on_message_begin = callback;
318
+ return callback;
319
+ }
320
+
321
+ VALUE Parser_set_on_headers_complete(VALUE self, VALUE callback) {
322
+ ParserWrapper *wrapper = NULL;
323
+ DATA_GET(self, ParserWrapper, wrapper);
324
+
325
+ wrapper->on_headers_complete = callback;
326
+ return callback;
327
+ }
328
+
329
+ VALUE Parser_set_on_body(VALUE self, VALUE callback) {
330
+ ParserWrapper *wrapper = NULL;
331
+ DATA_GET(self, ParserWrapper, wrapper);
332
+
333
+ wrapper->on_body = callback;
334
+ return callback;
335
+ }
336
+
337
+ VALUE Parser_set_on_message_complete(VALUE self, VALUE callback) {
338
+ ParserWrapper *wrapper = NULL;
339
+ DATA_GET(self, ParserWrapper, wrapper);
340
+
341
+ wrapper->on_message_complete = callback;
342
+ return callback;
343
+ }
344
+
345
+ VALUE Parser_keep_alive_p(VALUE self) {
346
+ ParserWrapper *wrapper = NULL;
347
+ DATA_GET(self, ParserWrapper, wrapper);
348
+
349
+ return http_should_keep_alive(&wrapper->parser) == 1 ? Qtrue : Qfalse;
350
+ }
351
+
352
+ VALUE Parser_upgrade_p(VALUE self) {
353
+ ParserWrapper *wrapper = NULL;
354
+ DATA_GET(self, ParserWrapper, wrapper);
355
+
356
+ return wrapper->parser.upgrade == 1 ? Qtrue : Qfalse;
357
+ }
358
+
359
+ VALUE Parser_http_version(VALUE self) {
360
+ ParserWrapper *wrapper = NULL;
361
+ DATA_GET(self, ParserWrapper, wrapper);
362
+
363
+ if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0)
364
+ return Qnil;
365
+ else
366
+ return rb_ary_new3(2, INT2FIX(wrapper->parser.http_major), INT2FIX(wrapper->parser.http_minor));
367
+ }
368
+
369
+ VALUE Parser_http_major(VALUE self) {
370
+ ParserWrapper *wrapper = NULL;
371
+ DATA_GET(self, ParserWrapper, wrapper);
372
+
373
+ if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0)
374
+ return Qnil;
375
+ else
376
+ return INT2FIX(wrapper->parser.http_major);
377
+ }
378
+
379
+ VALUE Parser_http_minor(VALUE self) {
380
+ ParserWrapper *wrapper = NULL;
381
+ DATA_GET(self, ParserWrapper, wrapper);
382
+
383
+ if (wrapper->parser.http_major == 0 && wrapper->parser.http_minor == 0)
384
+ return Qnil;
385
+ else
386
+ return INT2FIX(wrapper->parser.http_minor);
387
+ }
388
+
389
+ VALUE Parser_http_method(VALUE self) {
390
+ ParserWrapper *wrapper = NULL;
391
+ DATA_GET(self, ParserWrapper, wrapper);
392
+
393
+ if (wrapper->parser.type == HTTP_REQUEST)
394
+ return rb_str_new2(http_method_str(wrapper->parser.method));
395
+ else
396
+ return Qnil;
397
+ }
398
+
399
+ VALUE Parser_status_code(VALUE self) {
400
+ ParserWrapper *wrapper = NULL;
401
+ DATA_GET(self, ParserWrapper, wrapper);
402
+
403
+ if (wrapper->parser.status_code)
404
+ return INT2FIX(wrapper->parser.status_code);
405
+ else
406
+ return Qnil;
407
+ }
408
+
409
+ #define DEFINE_GETTER(name) \
410
+ VALUE Parser_##name(VALUE self) { \
411
+ ParserWrapper *wrapper = NULL; \
412
+ DATA_GET(self, ParserWrapper, wrapper); \
413
+ return wrapper->name; \
414
+ }
415
+
416
+ DEFINE_GETTER(request_url);
417
+ DEFINE_GETTER(request_path);
418
+ DEFINE_GETTER(query_string);
419
+ DEFINE_GETTER(fragment);
420
+ DEFINE_GETTER(headers);
421
+
422
+ VALUE Parser_reset(VALUE self) {
423
+ ParserWrapper *wrapper = NULL;
424
+ DATA_GET(self, ParserWrapper, wrapper);
425
+
426
+ ParserWrapper_init(wrapper);
427
+
428
+ return Qtrue;
429
+ }
430
+
431
+ void Init_ruby_http_parser() {
432
+ VALUE mHTTP = rb_define_module("HTTP");
433
+ cParser = rb_define_class_under(mHTTP, "Parser", rb_cObject);
434
+ cRequestParser = rb_define_class_under(mHTTP, "RequestParser", cParser);
435
+ cResponseParser = rb_define_class_under(mHTTP, "ResponseParser", cParser);
436
+
437
+ eParserError = rb_define_class_under(cParser, "Error", rb_eIOError);
438
+ Icall = rb_intern("call");
439
+ Ion_message_begin = rb_intern("on_message_begin");
440
+ Ion_headers_complete = rb_intern("on_headers_complete");
441
+ Ion_body = rb_intern("on_body");
442
+ Ion_message_complete = rb_intern("on_message_complete");
443
+ Sstop = ID2SYM(rb_intern("stop"));
444
+
445
+ rb_define_alloc_func(cParser, Parser_alloc);
446
+ rb_define_alloc_func(cRequestParser, RequestParser_alloc);
447
+ rb_define_alloc_func(cResponseParser, ResponseParser_alloc);
448
+
449
+ rb_define_method(cParser, "initialize", Parser_initialize, -1);
450
+
451
+ rb_define_method(cParser, "on_message_begin=", Parser_set_on_message_begin, 1);
452
+ rb_define_method(cParser, "on_headers_complete=", Parser_set_on_headers_complete, 1);
453
+ rb_define_method(cParser, "on_body=", Parser_set_on_body, 1);
454
+ rb_define_method(cParser, "on_message_complete=", Parser_set_on_message_complete, 1);
455
+ rb_define_method(cParser, "<<", Parser_execute, 1);
456
+
457
+ rb_define_method(cParser, "keep_alive?", Parser_keep_alive_p, 0);
458
+ rb_define_method(cParser, "upgrade?", Parser_upgrade_p, 0);
459
+
460
+ rb_define_method(cParser, "http_version", Parser_http_version, 0);
461
+ rb_define_method(cParser, "http_major", Parser_http_major, 0);
462
+ rb_define_method(cParser, "http_minor", Parser_http_minor, 0);
463
+
464
+ rb_define_method(cParser, "http_method", Parser_http_method, 0);
465
+ rb_define_method(cParser, "status_code", Parser_status_code, 0);
466
+
467
+ rb_define_method(cParser, "request_url", Parser_request_url, 0);
468
+ rb_define_method(cParser, "request_path", Parser_request_path, 0);
469
+ rb_define_method(cParser, "query_string", Parser_query_string, 0);
470
+ rb_define_method(cParser, "fragment", Parser_fragment, 0);
471
+ rb_define_method(cParser, "headers", Parser_headers, 0);
472
+
473
+ rb_define_method(cParser, "reset!", Parser_reset, 0);
474
+ }