em-http-request 0.2.10 → 0.2.11

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of em-http-request might be problematic. Click here for more details.

@@ -1,14 +1,14 @@
1
- #ifndef ext_help_h
2
- #define ext_help_h
3
-
4
- #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
5
- #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
6
- #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
7
-
8
- #ifdef DEBUG
9
- #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
10
- #else
11
- #define TRACE()
12
- #endif
13
-
14
- #endif
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
5
+ #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
6
+ #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
7
+
8
+ #ifdef DEBUG
9
+ #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
10
+ #else
11
+ #define TRACE()
12
+ #endif
13
+
14
+ #endif
@@ -1,6 +1,6 @@
1
- require 'mkmf'
2
-
3
- dir_config("http11_client")
4
- have_library("c", "main")
5
-
6
- create_makefile("http11_client")
1
+ require 'mkmf'
2
+
3
+ dir_config("http11_client")
4
+ have_library("c", "main")
5
+
6
+ create_makefile("http11_client")
@@ -1,328 +1,328 @@
1
- /**
2
- * Copyright (c) 2005 Zed A. Shaw
3
- * You can redistribute it and/or modify it under the same terms as Ruby.
4
- */
5
-
6
- #include "ruby.h"
7
- #include "ext_help.h"
8
- #include <assert.h>
9
- #include <string.h>
10
- #include "http11_parser.h"
11
- #include <ctype.h>
12
-
13
- static VALUE mEm;
14
- static VALUE cHttpClientParser;
15
- static VALUE eHttpClientParserError;
16
-
17
- #define id_reason rb_intern("@http_reason")
18
- #define id_status rb_intern("@http_status")
19
- #define id_version rb_intern("@http_version")
20
- #define id_body rb_intern("@http_body")
21
- #define id_chunk_size rb_intern("@http_chunk_size")
22
- #define id_last_chunk rb_intern("@last_chunk")
23
-
24
- #ifndef RHASH_TBL
25
- /* rb_hash_lookup() is only in Ruby 1.8.7 */
26
- static VALUE rb_hash_lookup(VALUE hash, VALUE key)
27
- {
28
- VALUE val;
29
-
30
- if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
31
- return Qnil; /* without Hash#default */
32
- }
33
-
34
- return val;
35
- }
36
- #endif
37
-
38
- void client_http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
39
- {
40
- char *ch, *end;
41
- VALUE req = (VALUE)data;
42
- VALUE v = Qnil;
43
- VALUE f = Qnil;
44
- VALUE el = Qnil;
45
-
46
- v = rb_str_new(value, vlen);
47
- f = rb_str_new(field, flen);
48
-
49
- /* Yes Children, rb_str_upcase_bang isn't even available as an intern.h function.
50
- * how incredibly handy to not have that. Nope, I have to do it by hand.*/
51
- for(ch = RSTRING_PTR(f), end = ch + RSTRING_LEN(f); ch < end; ch++) {
52
- if(*ch == '-') {
53
- *ch = '_';
54
- } else {
55
- *ch = toupper(*ch);
56
- }
57
- }
58
-
59
- el = rb_hash_lookup(req, f);
60
- switch(TYPE(el)) {
61
- case T_ARRAY:
62
- rb_ary_push(el, v);
63
- break;
64
- case T_STRING:
65
- rb_hash_aset(req, f, rb_ary_new3(2, el, v));
66
- break;
67
- default:
68
- rb_hash_aset(req, f, v);
69
- break;
70
- }
71
- }
72
-
73
- void client_reason_phrase(void *data, const char *at, size_t length)
74
- {
75
- VALUE req = (VALUE)data;
76
- VALUE v = Qnil;
77
-
78
- v = rb_str_new(at, length);
79
-
80
- rb_ivar_set(req, id_reason, v);
81
- }
82
-
83
- void client_status_code(void *data, const char *at, size_t length)
84
- {
85
- VALUE req = (VALUE)data;
86
- VALUE v = Qnil;
87
-
88
- v = rb_str_new(at, length);
89
-
90
- rb_ivar_set(req, id_status, v);
91
- }
92
-
93
- void client_http_version(void *data, const char *at, size_t length)
94
- {
95
- VALUE req = (VALUE)data;
96
- VALUE v = Qnil;
97
-
98
- v = rb_str_new(at, length);
99
-
100
- rb_ivar_set(req, id_version, v);
101
- }
102
-
103
- /** Finalizes the request header to have a bunch of stuff that's
104
- needed. */
105
- void client_header_done(void *data, const char *at, size_t length)
106
- {
107
- VALUE req = (VALUE)data;
108
- VALUE v = Qnil;
109
-
110
- v = rb_str_new(at, length);
111
- rb_ivar_set(req, id_body, v);
112
- }
113
-
114
- void client_chunk_size(void *data, const char *at, size_t length)
115
- {
116
- VALUE req = (VALUE)data;
117
- VALUE v = Qnil;
118
-
119
- if(length <= 0) {
120
- rb_raise(eHttpClientParserError, "Chunked Encoding gave <= 0 chunk size.");
121
- }
122
-
123
- v = rb_str_new(at, length);
124
-
125
- rb_ivar_set(req, id_chunk_size, v);
126
- }
127
-
128
- void client_last_chunk(void *data, const char *at, size_t length) {
129
- VALUE req = (VALUE)data;
130
- rb_ivar_set(req, id_last_chunk,Qtrue);
131
- }
132
-
133
-
134
- void HttpClientParser_free(void *data) {
135
- TRACE();
136
-
137
- if(data) {
138
- free(data);
139
- }
140
- }
141
-
142
-
143
- VALUE HttpClientParser_alloc(VALUE klass)
144
- {
145
- VALUE obj;
146
- httpclient_parser *hp = ALLOC_N(httpclient_parser, 1);
147
- TRACE();
148
- hp->http_field = client_http_field;
149
- hp->status_code = client_status_code;
150
- hp->reason_phrase = client_reason_phrase;
151
- hp->http_version = client_http_version;
152
- hp->header_done = client_header_done;
153
- hp->chunk_size = client_chunk_size;
154
- hp->last_chunk = client_last_chunk;
155
- httpclient_parser_init(hp);
156
-
157
- obj = Data_Wrap_Struct(klass, NULL, HttpClientParser_free, hp);
158
-
159
- return obj;
160
- }
161
-
162
-
163
- /**
164
- * call-seq:
165
- * parser.new -> parser
166
- *
167
- * Creates a new parser.
168
- */
169
- VALUE HttpClientParser_init(VALUE self)
170
- {
171
- httpclient_parser *http = NULL;
172
- DATA_GET(self, httpclient_parser, http);
173
- httpclient_parser_init(http);
174
-
175
- return self;
176
- }
177
-
178
-
179
- /**
180
- * call-seq:
181
- * parser.reset -> nil
182
- *
183
- * Resets the parser to it's initial state so that you can reuse it
184
- * rather than making new ones.
185
- */
186
- VALUE HttpClientParser_reset(VALUE self)
187
- {
188
- httpclient_parser *http = NULL;
189
- DATA_GET(self, httpclient_parser, http);
190
- httpclient_parser_init(http);
191
-
192
- return Qnil;
193
- }
194
-
195
-
196
- /**
197
- * call-seq:
198
- * parser.finish -> true/false
199
- *
200
- * Finishes a parser early which could put in a "good" or bad state.
201
- * You should call reset after finish it or bad things will happen.
202
- */
203
- VALUE HttpClientParser_finish(VALUE self)
204
- {
205
- httpclient_parser *http = NULL;
206
- DATA_GET(self, httpclient_parser, http);
207
- httpclient_parser_finish(http);
208
-
209
- return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
210
- }
211
-
212
-
213
- /**
214
- * call-seq:
215
- * parser.execute(req_hash, data, start) -> Integer
216
- *
217
- * Takes a Hash and a String of data, parses the String of data filling in the Hash
218
- * returning an Integer to indicate how much of the data has been read. No matter
219
- * what the return value, you should call HttpClientParser#finished? and HttpClientParser#error?
220
- * to figure out if it's done parsing or there was an error.
221
- *
222
- * This function now throws an exception when there is a parsing error. This makes
223
- * the logic for working with the parser much easier. You can still test for an
224
- * error, but now you need to wrap the parser with an exception handling block.
225
- *
226
- * The third argument allows for parsing a partial request and then continuing
227
- * the parsing from that position. It needs all of the original data as well
228
- * so you have to append to the data buffer as you read.
229
- */
230
- VALUE HttpClientParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
231
- {
232
- httpclient_parser *http = NULL;
233
- int from = 0;
234
- char *dptr = NULL;
235
- long dlen = 0;
236
-
237
- REQUIRE_TYPE(req_hash, T_HASH);
238
- REQUIRE_TYPE(data, T_STRING);
239
- REQUIRE_TYPE(start, T_FIXNUM);
240
-
241
- DATA_GET(self, httpclient_parser, http);
242
-
243
- from = FIX2INT(start);
244
- dptr = RSTRING_PTR(data);
245
- dlen = RSTRING_LEN(data);
246
-
247
- if(from >= dlen) {
248
- rb_raise(eHttpClientParserError, "Requested start is after data buffer end.");
249
- } else {
250
- http->data = (void *)req_hash;
251
- httpclient_parser_execute(http, dptr, dlen, from);
252
-
253
- if(httpclient_parser_has_error(http)) {
254
- rb_raise(eHttpClientParserError, "Invalid HTTP format, parsing fails.");
255
- } else {
256
- return INT2FIX(httpclient_parser_nread(http));
257
- }
258
- }
259
- }
260
-
261
-
262
-
263
- /**
264
- * call-seq:
265
- * parser.error? -> true/false
266
- *
267
- * Tells you whether the parser is in an error state.
268
- */
269
- VALUE HttpClientParser_has_error(VALUE self)
270
- {
271
- httpclient_parser *http = NULL;
272
- DATA_GET(self, httpclient_parser, http);
273
-
274
- return httpclient_parser_has_error(http) ? Qtrue : Qfalse;
275
- }
276
-
277
-
278
- /**
279
- * call-seq:
280
- * parser.finished? -> true/false
281
- *
282
- * Tells you whether the parser is finished or not and in a good state.
283
- */
284
- VALUE HttpClientParser_is_finished(VALUE self)
285
- {
286
- httpclient_parser *http = NULL;
287
- DATA_GET(self, httpclient_parser, http);
288
-
289
- return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
290
- }
291
-
292
-
293
- /**
294
- * call-seq:
295
- * parser.nread -> Integer
296
- *
297
- * Returns the amount of data processed so far during this processing cycle. It is
298
- * set to 0 on initialize or reset calls and is incremented each time execute is called.
299
- */
300
- VALUE HttpClientParser_nread(VALUE self)
301
- {
302
- httpclient_parser *http = NULL;
303
- DATA_GET(self, httpclient_parser, http);
304
-
305
- return INT2FIX(http->nread);
306
- }
307
-
308
-
309
-
310
- void Init_http11_client()
311
- {
312
-
313
- mEm = rb_define_module("EventMachine");
314
-
315
- eHttpClientParserError = rb_define_class_under(mEm, "HttpClientParserError", rb_eIOError);
316
-
317
- cHttpClientParser = rb_define_class_under(mEm, "HttpClientParser", rb_cObject);
318
- rb_define_alloc_func(cHttpClientParser, HttpClientParser_alloc);
319
- rb_define_method(cHttpClientParser, "initialize", HttpClientParser_init,0);
320
- rb_define_method(cHttpClientParser, "reset", HttpClientParser_reset,0);
321
- rb_define_method(cHttpClientParser, "finish", HttpClientParser_finish,0);
322
- rb_define_method(cHttpClientParser, "execute", HttpClientParser_execute,3);
323
- rb_define_method(cHttpClientParser, "error?", HttpClientParser_has_error,0);
324
- rb_define_method(cHttpClientParser, "finished?", HttpClientParser_is_finished,0);
325
- rb_define_method(cHttpClientParser, "nread", HttpClientParser_nread,0);
326
- }
327
-
328
-
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ */
5
+
6
+ #include "ruby.h"
7
+ #include "ext_help.h"
8
+ #include <assert.h>
9
+ #include <string.h>
10
+ #include "http11_parser.h"
11
+ #include <ctype.h>
12
+
13
+ static VALUE mEm;
14
+ static VALUE cHttpClientParser;
15
+ static VALUE eHttpClientParserError;
16
+
17
+ #define id_reason rb_intern("@http_reason")
18
+ #define id_status rb_intern("@http_status")
19
+ #define id_version rb_intern("@http_version")
20
+ #define id_body rb_intern("@http_body")
21
+ #define id_chunk_size rb_intern("@http_chunk_size")
22
+ #define id_last_chunk rb_intern("@last_chunk")
23
+
24
+ #ifndef RHASH_TBL
25
+ /* rb_hash_lookup() is only in Ruby 1.8.7 */
26
+ static VALUE rb_hash_lookup(VALUE hash, VALUE key)
27
+ {
28
+ VALUE val;
29
+
30
+ if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
31
+ return Qnil; /* without Hash#default */
32
+ }
33
+
34
+ return val;
35
+ }
36
+ #endif
37
+
38
+ void client_http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
39
+ {
40
+ char *ch, *end;
41
+ VALUE req = (VALUE)data;
42
+ VALUE v = Qnil;
43
+ VALUE f = Qnil;
44
+ VALUE el = Qnil;
45
+
46
+ v = rb_str_new(value, vlen);
47
+ f = rb_str_new(field, flen);
48
+
49
+ /* Yes Children, rb_str_upcase_bang isn't even available as an intern.h function.
50
+ * how incredibly handy to not have that. Nope, I have to do it by hand.*/
51
+ for(ch = RSTRING_PTR(f), end = ch + RSTRING_LEN(f); ch < end; ch++) {
52
+ if(*ch == '-') {
53
+ *ch = '_';
54
+ } else {
55
+ *ch = toupper(*ch);
56
+ }
57
+ }
58
+
59
+ el = rb_hash_lookup(req, f);
60
+ switch(TYPE(el)) {
61
+ case T_ARRAY:
62
+ rb_ary_push(el, v);
63
+ break;
64
+ case T_STRING:
65
+ rb_hash_aset(req, f, rb_ary_new3(2, el, v));
66
+ break;
67
+ default:
68
+ rb_hash_aset(req, f, v);
69
+ break;
70
+ }
71
+ }
72
+
73
+ void client_reason_phrase(void *data, const char *at, size_t length)
74
+ {
75
+ VALUE req = (VALUE)data;
76
+ VALUE v = Qnil;
77
+
78
+ v = rb_str_new(at, length);
79
+
80
+ rb_ivar_set(req, id_reason, v);
81
+ }
82
+
83
+ void client_status_code(void *data, const char *at, size_t length)
84
+ {
85
+ VALUE req = (VALUE)data;
86
+ VALUE v = Qnil;
87
+
88
+ v = rb_str_new(at, length);
89
+
90
+ rb_ivar_set(req, id_status, v);
91
+ }
92
+
93
+ void client_http_version(void *data, const char *at, size_t length)
94
+ {
95
+ VALUE req = (VALUE)data;
96
+ VALUE v = Qnil;
97
+
98
+ v = rb_str_new(at, length);
99
+
100
+ rb_ivar_set(req, id_version, v);
101
+ }
102
+
103
+ /** Finalizes the request header to have a bunch of stuff that's
104
+ needed. */
105
+ void client_header_done(void *data, const char *at, size_t length)
106
+ {
107
+ VALUE req = (VALUE)data;
108
+ VALUE v = Qnil;
109
+
110
+ v = rb_str_new(at, length);
111
+ rb_ivar_set(req, id_body, v);
112
+ }
113
+
114
+ void client_chunk_size(void *data, const char *at, size_t length)
115
+ {
116
+ VALUE req = (VALUE)data;
117
+ VALUE v = Qnil;
118
+
119
+ if(length <= 0) {
120
+ rb_raise(eHttpClientParserError, "Chunked Encoding gave <= 0 chunk size.");
121
+ }
122
+
123
+ v = rb_str_new(at, length);
124
+
125
+ rb_ivar_set(req, id_chunk_size, v);
126
+ }
127
+
128
+ void client_last_chunk(void *data, const char *at, size_t length) {
129
+ VALUE req = (VALUE)data;
130
+ rb_ivar_set(req, id_last_chunk,Qtrue);
131
+ }
132
+
133
+
134
+ void HttpClientParser_free(void *data) {
135
+ TRACE();
136
+
137
+ if(data) {
138
+ free(data);
139
+ }
140
+ }
141
+
142
+
143
+ VALUE HttpClientParser_alloc(VALUE klass)
144
+ {
145
+ VALUE obj;
146
+ httpclient_parser *hp = ALLOC_N(httpclient_parser, 1);
147
+ TRACE();
148
+ hp->http_field = client_http_field;
149
+ hp->status_code = client_status_code;
150
+ hp->reason_phrase = client_reason_phrase;
151
+ hp->http_version = client_http_version;
152
+ hp->header_done = client_header_done;
153
+ hp->chunk_size = client_chunk_size;
154
+ hp->last_chunk = client_last_chunk;
155
+ httpclient_parser_init(hp);
156
+
157
+ obj = Data_Wrap_Struct(klass, NULL, HttpClientParser_free, hp);
158
+
159
+ return obj;
160
+ }
161
+
162
+
163
+ /**
164
+ * call-seq:
165
+ * parser.new -> parser
166
+ *
167
+ * Creates a new parser.
168
+ */
169
+ VALUE HttpClientParser_init(VALUE self)
170
+ {
171
+ httpclient_parser *http = NULL;
172
+ DATA_GET(self, httpclient_parser, http);
173
+ httpclient_parser_init(http);
174
+
175
+ return self;
176
+ }
177
+
178
+
179
+ /**
180
+ * call-seq:
181
+ * parser.reset -> nil
182
+ *
183
+ * Resets the parser to it's initial state so that you can reuse it
184
+ * rather than making new ones.
185
+ */
186
+ VALUE HttpClientParser_reset(VALUE self)
187
+ {
188
+ httpclient_parser *http = NULL;
189
+ DATA_GET(self, httpclient_parser, http);
190
+ httpclient_parser_init(http);
191
+
192
+ return Qnil;
193
+ }
194
+
195
+
196
+ /**
197
+ * call-seq:
198
+ * parser.finish -> true/false
199
+ *
200
+ * Finishes a parser early which could put in a "good" or bad state.
201
+ * You should call reset after finish it or bad things will happen.
202
+ */
203
+ VALUE HttpClientParser_finish(VALUE self)
204
+ {
205
+ httpclient_parser *http = NULL;
206
+ DATA_GET(self, httpclient_parser, http);
207
+ httpclient_parser_finish(http);
208
+
209
+ return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
210
+ }
211
+
212
+
213
+ /**
214
+ * call-seq:
215
+ * parser.execute(req_hash, data, start) -> Integer
216
+ *
217
+ * Takes a Hash and a String of data, parses the String of data filling in the Hash
218
+ * returning an Integer to indicate how much of the data has been read. No matter
219
+ * what the return value, you should call HttpClientParser#finished? and HttpClientParser#error?
220
+ * to figure out if it's done parsing or there was an error.
221
+ *
222
+ * This function now throws an exception when there is a parsing error. This makes
223
+ * the logic for working with the parser much easier. You can still test for an
224
+ * error, but now you need to wrap the parser with an exception handling block.
225
+ *
226
+ * The third argument allows for parsing a partial request and then continuing
227
+ * the parsing from that position. It needs all of the original data as well
228
+ * so you have to append to the data buffer as you read.
229
+ */
230
+ VALUE HttpClientParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
231
+ {
232
+ httpclient_parser *http = NULL;
233
+ int from = 0;
234
+ char *dptr = NULL;
235
+ long dlen = 0;
236
+
237
+ REQUIRE_TYPE(req_hash, T_HASH);
238
+ REQUIRE_TYPE(data, T_STRING);
239
+ REQUIRE_TYPE(start, T_FIXNUM);
240
+
241
+ DATA_GET(self, httpclient_parser, http);
242
+
243
+ from = FIX2INT(start);
244
+ dptr = RSTRING_PTR(data);
245
+ dlen = RSTRING_LEN(data);
246
+
247
+ if(from >= dlen) {
248
+ rb_raise(eHttpClientParserError, "Requested start is after data buffer end.");
249
+ } else {
250
+ http->data = (void *)req_hash;
251
+ httpclient_parser_execute(http, dptr, dlen, from);
252
+
253
+ if(httpclient_parser_has_error(http)) {
254
+ rb_raise(eHttpClientParserError, "Invalid HTTP format, parsing fails.");
255
+ } else {
256
+ return INT2FIX(httpclient_parser_nread(http));
257
+ }
258
+ }
259
+ }
260
+
261
+
262
+
263
+ /**
264
+ * call-seq:
265
+ * parser.error? -> true/false
266
+ *
267
+ * Tells you whether the parser is in an error state.
268
+ */
269
+ VALUE HttpClientParser_has_error(VALUE self)
270
+ {
271
+ httpclient_parser *http = NULL;
272
+ DATA_GET(self, httpclient_parser, http);
273
+
274
+ return httpclient_parser_has_error(http) ? Qtrue : Qfalse;
275
+ }
276
+
277
+
278
+ /**
279
+ * call-seq:
280
+ * parser.finished? -> true/false
281
+ *
282
+ * Tells you whether the parser is finished or not and in a good state.
283
+ */
284
+ VALUE HttpClientParser_is_finished(VALUE self)
285
+ {
286
+ httpclient_parser *http = NULL;
287
+ DATA_GET(self, httpclient_parser, http);
288
+
289
+ return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
290
+ }
291
+
292
+
293
+ /**
294
+ * call-seq:
295
+ * parser.nread -> Integer
296
+ *
297
+ * Returns the amount of data processed so far during this processing cycle. It is
298
+ * set to 0 on initialize or reset calls and is incremented each time execute is called.
299
+ */
300
+ VALUE HttpClientParser_nread(VALUE self)
301
+ {
302
+ httpclient_parser *http = NULL;
303
+ DATA_GET(self, httpclient_parser, http);
304
+
305
+ return INT2FIX(http->nread);
306
+ }
307
+
308
+
309
+
310
+ void Init_http11_client()
311
+ {
312
+
313
+ mEm = rb_define_module("EventMachine");
314
+
315
+ eHttpClientParserError = rb_define_class_under(mEm, "HttpClientParserError", rb_eIOError);
316
+
317
+ cHttpClientParser = rb_define_class_under(mEm, "HttpClientParser", rb_cObject);
318
+ rb_define_alloc_func(cHttpClientParser, HttpClientParser_alloc);
319
+ rb_define_method(cHttpClientParser, "initialize", HttpClientParser_init,0);
320
+ rb_define_method(cHttpClientParser, "reset", HttpClientParser_reset,0);
321
+ rb_define_method(cHttpClientParser, "finish", HttpClientParser_finish,0);
322
+ rb_define_method(cHttpClientParser, "execute", HttpClientParser_execute,3);
323
+ rb_define_method(cHttpClientParser, "error?", HttpClientParser_has_error,0);
324
+ rb_define_method(cHttpClientParser, "finished?", HttpClientParser_is_finished,0);
325
+ rb_define_method(cHttpClientParser, "nread", HttpClientParser_nread,0);
326
+ }
327
+
328
+