igrigorik-em-http-request 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ require 'mkmf'
2
+
3
+ libs = []
4
+
5
+ $defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
6
+
7
+ if have_func('rb_thread_blocking_region')
8
+ $defs << '-DHAVE_RB_THREAD_BLOCKING_REGION'
9
+ end
10
+
11
+ if have_func('rb_str_set_len')
12
+ $defs << '-DHAVE_RB_STR_SET_LEN'
13
+ end
14
+
15
+ if have_header('sys/select.h')
16
+ $defs << '-DEV_USE_SELECT'
17
+ end
18
+
19
+ if have_header('poll.h')
20
+ $defs << '-DEV_USE_POLL'
21
+ end
22
+
23
+ if have_header('sys/epoll.h')
24
+ $defs << '-DEV_USE_EPOLL'
25
+ end
26
+
27
+ if have_header('sys/event.h') and have_header('sys/queue.h')
28
+ $defs << '-DEV_USE_KQUEUE'
29
+ end
30
+
31
+ if have_header('port.h')
32
+ $defs << '-DEV_USE_PORT'
33
+ end
34
+
35
+ if have_header('openssl/ssl.h')
36
+ $defs << '-DHAVE_OPENSSL_SSL_H'
37
+ libs << '-lssl -lcrypto'
38
+ end
39
+
40
+ # ncpu detection specifics
41
+ case RUBY_PLATFORM
42
+ when /linux/
43
+ $defs << '-DHAVE_LINUX_PROCFS'
44
+ else
45
+ if have_func('sysctlbyname', ['sys/param.h', 'sys/sysctl.h'])
46
+ $defs << '-DHAVE_SYSCTLBYNAME'
47
+ end
48
+ end
49
+
50
+ $LIBS << ' ' << libs.join(' ')
51
+
52
+ dir_config('em_buffer')
53
+ create_makefile('em_buffer')
@@ -0,0 +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
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("http11_client")
4
+ have_library("c", "main")
5
+
6
+ create_makefile("http11_client")
@@ -0,0 +1,302 @@
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
+ void client_http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
25
+ {
26
+ char *ch, *end;
27
+ VALUE req = (VALUE)data;
28
+ VALUE v = Qnil;
29
+ VALUE f = Qnil;
30
+
31
+ v = rb_str_new(value, vlen);
32
+ f = rb_str_new(field, flen);
33
+
34
+ /* Yes Children, rb_str_upcase_bang isn't even available as an intern.h function.
35
+ * how incredibly handy to not have that. Nope, I have to do it by hand.*/
36
+ for(ch = RSTRING_PTR(f), end = ch + RSTRING_LEN(f); ch < end; ch++) {
37
+ if(*ch == '-') {
38
+ *ch = '_';
39
+ } else {
40
+ *ch = toupper(*ch);
41
+ }
42
+ }
43
+
44
+ rb_hash_aset(req, f, v);
45
+ }
46
+
47
+ void client_reason_phrase(void *data, const char *at, size_t length)
48
+ {
49
+ VALUE req = (VALUE)data;
50
+ VALUE v = Qnil;
51
+
52
+ v = rb_str_new(at, length);
53
+
54
+ rb_ivar_set(req, id_reason, v);
55
+ }
56
+
57
+ void client_status_code(void *data, const char *at, size_t length)
58
+ {
59
+ VALUE req = (VALUE)data;
60
+ VALUE v = Qnil;
61
+
62
+ v = rb_str_new(at, length);
63
+
64
+ rb_ivar_set(req, id_status, v);
65
+ }
66
+
67
+ void client_http_version(void *data, const char *at, size_t length)
68
+ {
69
+ VALUE req = (VALUE)data;
70
+ VALUE v = Qnil;
71
+
72
+ v = rb_str_new(at, length);
73
+
74
+ rb_ivar_set(req, id_version, v);
75
+ }
76
+
77
+ /** Finalizes the request header to have a bunch of stuff that's
78
+ needed. */
79
+ void client_header_done(void *data, const char *at, size_t length)
80
+ {
81
+ VALUE req = (VALUE)data;
82
+ VALUE v = Qnil;
83
+
84
+ v = rb_str_new(at, length);
85
+ rb_ivar_set(req, id_body, v);
86
+ }
87
+
88
+ void client_chunk_size(void *data, const char *at, size_t length)
89
+ {
90
+ VALUE req = (VALUE)data;
91
+ VALUE v = Qnil;
92
+
93
+ if(length <= 0) {
94
+ rb_raise(eHttpClientParserError, "Chunked Encoding gave <= 0 chunk size.");
95
+ }
96
+
97
+ v = rb_str_new(at, length);
98
+
99
+ rb_ivar_set(req, id_chunk_size, v);
100
+ }
101
+
102
+ void client_last_chunk(void *data, const char *at, size_t length) {
103
+ VALUE req = (VALUE)data;
104
+ rb_ivar_set(req, id_last_chunk,Qtrue);
105
+ }
106
+
107
+
108
+ void HttpClientParser_free(void *data) {
109
+ TRACE();
110
+
111
+ if(data) {
112
+ free(data);
113
+ }
114
+ }
115
+
116
+
117
+ VALUE HttpClientParser_alloc(VALUE klass)
118
+ {
119
+ VALUE obj;
120
+ httpclient_parser *hp = ALLOC_N(httpclient_parser, 1);
121
+ TRACE();
122
+ hp->http_field = client_http_field;
123
+ hp->status_code = client_status_code;
124
+ hp->reason_phrase = client_reason_phrase;
125
+ hp->http_version = client_http_version;
126
+ hp->header_done = client_header_done;
127
+ hp->chunk_size = client_chunk_size;
128
+ hp->last_chunk = client_last_chunk;
129
+ httpclient_parser_init(hp);
130
+
131
+ obj = Data_Wrap_Struct(klass, NULL, HttpClientParser_free, hp);
132
+
133
+ return obj;
134
+ }
135
+
136
+
137
+ /**
138
+ * call-seq:
139
+ * parser.new -> parser
140
+ *
141
+ * Creates a new parser.
142
+ */
143
+ VALUE HttpClientParser_init(VALUE self)
144
+ {
145
+ httpclient_parser *http = NULL;
146
+ DATA_GET(self, httpclient_parser, http);
147
+ httpclient_parser_init(http);
148
+
149
+ return self;
150
+ }
151
+
152
+
153
+ /**
154
+ * call-seq:
155
+ * parser.reset -> nil
156
+ *
157
+ * Resets the parser to it's initial state so that you can reuse it
158
+ * rather than making new ones.
159
+ */
160
+ VALUE HttpClientParser_reset(VALUE self)
161
+ {
162
+ httpclient_parser *http = NULL;
163
+ DATA_GET(self, httpclient_parser, http);
164
+ httpclient_parser_init(http);
165
+
166
+ return Qnil;
167
+ }
168
+
169
+
170
+ /**
171
+ * call-seq:
172
+ * parser.finish -> true/false
173
+ *
174
+ * Finishes a parser early which could put in a "good" or bad state.
175
+ * You should call reset after finish it or bad things will happen.
176
+ */
177
+ VALUE HttpClientParser_finish(VALUE self)
178
+ {
179
+ httpclient_parser *http = NULL;
180
+ DATA_GET(self, httpclient_parser, http);
181
+ httpclient_parser_finish(http);
182
+
183
+ return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
184
+ }
185
+
186
+
187
+ /**
188
+ * call-seq:
189
+ * parser.execute(req_hash, data, start) -> Integer
190
+ *
191
+ * Takes a Hash and a String of data, parses the String of data filling in the Hash
192
+ * returning an Integer to indicate how much of the data has been read. No matter
193
+ * what the return value, you should call HttpClientParser#finished? and HttpClientParser#error?
194
+ * to figure out if it's done parsing or there was an error.
195
+ *
196
+ * This function now throws an exception when there is a parsing error. This makes
197
+ * the logic for working with the parser much easier. You can still test for an
198
+ * error, but now you need to wrap the parser with an exception handling block.
199
+ *
200
+ * The third argument allows for parsing a partial request and then continuing
201
+ * the parsing from that position. It needs all of the original data as well
202
+ * so you have to append to the data buffer as you read.
203
+ */
204
+ VALUE HttpClientParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
205
+ {
206
+ httpclient_parser *http = NULL;
207
+ int from = 0;
208
+ char *dptr = NULL;
209
+ long dlen = 0;
210
+
211
+ REQUIRE_TYPE(req_hash, T_HASH);
212
+ REQUIRE_TYPE(data, T_STRING);
213
+ REQUIRE_TYPE(start, T_FIXNUM);
214
+
215
+ DATA_GET(self, httpclient_parser, http);
216
+
217
+ from = FIX2INT(start);
218
+ dptr = RSTRING_PTR(data);
219
+ dlen = RSTRING_LEN(data);
220
+
221
+ if(from >= dlen) {
222
+ rb_raise(eHttpClientParserError, "Requested start is after data buffer end.");
223
+ } else {
224
+ http->data = (void *)req_hash;
225
+ httpclient_parser_execute(http, dptr, dlen, from);
226
+
227
+ if(httpclient_parser_has_error(http)) {
228
+ rb_raise(eHttpClientParserError, "Invalid HTTP format, parsing fails.");
229
+ } else {
230
+ return INT2FIX(httpclient_parser_nread(http));
231
+ }
232
+ }
233
+ }
234
+
235
+
236
+
237
+ /**
238
+ * call-seq:
239
+ * parser.error? -> true/false
240
+ *
241
+ * Tells you whether the parser is in an error state.
242
+ */
243
+ VALUE HttpClientParser_has_error(VALUE self)
244
+ {
245
+ httpclient_parser *http = NULL;
246
+ DATA_GET(self, httpclient_parser, http);
247
+
248
+ return httpclient_parser_has_error(http) ? Qtrue : Qfalse;
249
+ }
250
+
251
+
252
+ /**
253
+ * call-seq:
254
+ * parser.finished? -> true/false
255
+ *
256
+ * Tells you whether the parser is finished or not and in a good state.
257
+ */
258
+ VALUE HttpClientParser_is_finished(VALUE self)
259
+ {
260
+ httpclient_parser *http = NULL;
261
+ DATA_GET(self, httpclient_parser, http);
262
+
263
+ return httpclient_parser_is_finished(http) ? Qtrue : Qfalse;
264
+ }
265
+
266
+
267
+ /**
268
+ * call-seq:
269
+ * parser.nread -> Integer
270
+ *
271
+ * Returns the amount of data processed so far during this processing cycle. It is
272
+ * set to 0 on initialize or reset calls and is incremented each time execute is called.
273
+ */
274
+ VALUE HttpClientParser_nread(VALUE self)
275
+ {
276
+ httpclient_parser *http = NULL;
277
+ DATA_GET(self, httpclient_parser, http);
278
+
279
+ return INT2FIX(http->nread);
280
+ }
281
+
282
+
283
+
284
+ void Init_http11_client()
285
+ {
286
+
287
+ mEm = rb_define_module("EventMachine");
288
+
289
+ eHttpClientParserError = rb_define_class_under(mEm, "HttpClientParserError", rb_eIOError);
290
+
291
+ cHttpClientParser = rb_define_class_under(mEm, "HttpClientParser", rb_cObject);
292
+ rb_define_alloc_func(cHttpClientParser, HttpClientParser_alloc);
293
+ rb_define_method(cHttpClientParser, "initialize", HttpClientParser_init,0);
294
+ rb_define_method(cHttpClientParser, "reset", HttpClientParser_reset,0);
295
+ rb_define_method(cHttpClientParser, "finish", HttpClientParser_finish,0);
296
+ rb_define_method(cHttpClientParser, "execute", HttpClientParser_execute,3);
297
+ rb_define_method(cHttpClientParser, "error?", HttpClientParser_has_error,0);
298
+ rb_define_method(cHttpClientParser, "finished?", HttpClientParser_is_finished,0);
299
+ rb_define_method(cHttpClientParser, "nread", HttpClientParser_nread,0);
300
+ }
301
+
302
+
@@ -0,0 +1,403 @@
1
+ #line 1 "http11_parser.rl"
2
+ /**
3
+ * Copyright (c) 2005 Zed A. Shaw
4
+ * You can redistribute it and/or modify it under the same terms as Ruby.
5
+ */
6
+
7
+ #include "http11_parser.h"
8
+ #include <stdio.h>
9
+ #include <assert.h>
10
+ #include <stdlib.h>
11
+ #include <ctype.h>
12
+ #include <string.h>
13
+
14
+ #define LEN(AT, FPC) (FPC - buffer - parser->AT)
15
+ #define MARK(M,FPC) (parser->M = (FPC) - buffer)
16
+ #define PTR_TO(F) (buffer + parser->F)
17
+ #define L(M) fprintf(stderr, "" # M "\n");
18
+
19
+
20
+ /** machine **/
21
+ #line 95 "http11_parser.rl"
22
+
23
+
24
+ /** Data **/
25
+
26
+ #line 27 "http11_parser.c"
27
+ static const char _httpclient_parser_actions[] = {
28
+ 0, 1, 0, 1, 1, 1, 2, 1,
29
+ 3, 1, 4, 1, 5, 1, 7, 1,
30
+ 8, 1, 10, 2, 2, 3, 2, 6,
31
+ 0, 2, 6, 5, 2, 9, 10, 2,
32
+ 10, 9, 3, 2, 3, 4
33
+ };
34
+
35
+ static const short _httpclient_parser_key_offsets[] = {
36
+ 0, 10, 10, 11, 22, 26, 27, 28,
37
+ 39, 54, 75, 90, 110, 125, 146, 161,
38
+ 181, 196, 214, 229, 246, 247, 248, 249,
39
+ 250, 252, 255, 257, 260, 262, 264, 266,
40
+ 268, 269, 270, 286, 302, 304, 305, 306
41
+ };
42
+
43
+ static const char _httpclient_parser_trans_keys[] = {
44
+ 13, 48, 59, 72, 49, 57, 65, 70,
45
+ 97, 102, 10, 13, 32, 59, 9, 12,
46
+ 48, 57, 65, 70, 97, 102, 13, 32,
47
+ 9, 12, 10, 10, 13, 32, 59, 9,
48
+ 12, 48, 57, 65, 70, 97, 102, 33,
49
+ 124, 126, 35, 39, 42, 43, 45, 46,
50
+ 48, 57, 65, 90, 94, 122, 13, 32,
51
+ 33, 59, 61, 124, 126, 9, 12, 35,
52
+ 39, 42, 43, 45, 46, 48, 57, 65,
53
+ 90, 94, 122, 33, 124, 126, 35, 39,
54
+ 42, 43, 45, 46, 48, 57, 65, 90,
55
+ 94, 122, 13, 32, 33, 59, 124, 126,
56
+ 9, 12, 35, 39, 42, 43, 45, 46,
57
+ 48, 57, 65, 90, 94, 122, 33, 124,
58
+ 126, 35, 39, 42, 43, 45, 46, 48,
59
+ 57, 65, 90, 94, 122, 13, 32, 33,
60
+ 59, 61, 124, 126, 9, 12, 35, 39,
61
+ 42, 43, 45, 46, 48, 57, 65, 90,
62
+ 94, 122, 33, 124, 126, 35, 39, 42,
63
+ 43, 45, 46, 48, 57, 65, 90, 94,
64
+ 122, 13, 32, 33, 59, 124, 126, 9,
65
+ 12, 35, 39, 42, 43, 45, 46, 48,
66
+ 57, 65, 90, 94, 122, 33, 124, 126,
67
+ 35, 39, 42, 43, 45, 46, 48, 57,
68
+ 65, 90, 94, 122, 13, 33, 59, 61,
69
+ 124, 126, 35, 39, 42, 43, 45, 46,
70
+ 48, 57, 65, 90, 94, 122, 33, 124,
71
+ 126, 35, 39, 42, 43, 45, 46, 48,
72
+ 57, 65, 90, 94, 122, 13, 33, 59,
73
+ 124, 126, 35, 39, 42, 43, 45, 46,
74
+ 48, 57, 65, 90, 94, 122, 84, 84,
75
+ 80, 47, 48, 57, 46, 48, 57, 48,
76
+ 57, 32, 48, 57, 48, 57, 48, 57,
77
+ 48, 57, 13, 32, 13, 10, 13, 33,
78
+ 124, 126, 35, 39, 42, 43, 45, 46,
79
+ 48, 57, 65, 90, 94, 122, 33, 58,
80
+ 124, 126, 35, 39, 42, 43, 45, 46,
81
+ 48, 57, 65, 90, 94, 122, 13, 32,
82
+ 13, 13, 0
83
+ };
84
+
85
+ static const char _httpclient_parser_single_lengths[] = {
86
+ 4, 0, 1, 3, 2, 1, 1, 3,
87
+ 3, 7, 3, 6, 3, 7, 3, 6,
88
+ 3, 6, 3, 5, 1, 1, 1, 1,
89
+ 0, 1, 0, 1, 0, 0, 0, 2,
90
+ 1, 1, 4, 4, 2, 1, 1, 0
91
+ };
92
+
93
+ static const char _httpclient_parser_range_lengths[] = {
94
+ 3, 0, 0, 4, 1, 0, 0, 4,
95
+ 6, 7, 6, 7, 6, 7, 6, 7,
96
+ 6, 6, 6, 6, 0, 0, 0, 0,
97
+ 1, 1, 1, 1, 1, 1, 1, 0,
98
+ 0, 0, 6, 6, 0, 0, 0, 0
99
+ };
100
+
101
+ static const unsigned char _httpclient_parser_index_offsets[] = {
102
+ 0, 8, 8, 10, 18, 22, 24, 26,
103
+ 34, 44, 59, 69, 83, 93, 108, 118,
104
+ 132, 142, 155, 165, 177, 179, 181, 183,
105
+ 185, 187, 190, 192, 195, 197, 199, 201,
106
+ 204, 206, 208, 219, 230, 233, 235, 237
107
+ };
108
+
109
+ static const char _httpclient_parser_indicies[] = {
110
+ 14, 15, 17, 18, 16, 16, 16, 0,
111
+ 30, 0, 63, 37, 64, 37, 39, 39,
112
+ 39, 0, 19, 32, 32, 0, 29, 0,
113
+ 31, 0, 38, 37, 40, 37, 39, 39,
114
+ 39, 0, 58, 58, 58, 58, 58, 58,
115
+ 58, 58, 58, 0, 42, 41, 43, 44,
116
+ 45, 43, 43, 41, 43, 43, 43, 43,
117
+ 43, 43, 0, 59, 59, 59, 59, 59,
118
+ 59, 59, 59, 59, 0, 34, 33, 35,
119
+ 36, 35, 35, 33, 35, 35, 35, 35,
120
+ 35, 35, 0, 70, 70, 70, 70, 70,
121
+ 70, 70, 70, 70, 0, 65, 41, 66,
122
+ 67, 68, 66, 66, 41, 66, 66, 66,
123
+ 66, 66, 66, 0, 69, 69, 69, 69,
124
+ 69, 69, 69, 69, 69, 0, 60, 33,
125
+ 61, 62, 61, 61, 33, 61, 61, 61,
126
+ 61, 61, 61, 0, 10, 10, 10, 10,
127
+ 10, 10, 10, 10, 10, 0, 24, 25,
128
+ 26, 27, 25, 25, 25, 25, 25, 25,
129
+ 25, 25, 0, 11, 11, 11, 11, 11,
130
+ 11, 11, 11, 11, 0, 21, 22, 23,
131
+ 22, 22, 22, 22, 22, 22, 22, 22,
132
+ 0, 1, 0, 56, 0, 2, 0, 5,
133
+ 0, 7, 0, 6, 7, 0, 13, 0,
134
+ 12, 13, 0, 4, 0, 3, 0, 57,
135
+ 0, 54, 55, 53, 49, 48, 28, 0,
136
+ 19, 20, 20, 20, 20, 20, 20, 20,
137
+ 20, 20, 0, 8, 9, 8, 8, 8,
138
+ 8, 8, 8, 8, 8, 0, 47, 52,
139
+ 51, 47, 46, 49, 50, 0, 0
140
+ };
141
+
142
+ static const char _httpclient_parser_trans_targs_wi[] = {
143
+ 1, 21, 23, 30, 29, 24, 26, 25,
144
+ 35, 36, 17, 19, 28, 27, 2, 3,
145
+ 7, 16, 20, 5, 35, 2, 19, 16,
146
+ 2, 17, 16, 18, 34, 39, 39, 39,
147
+ 4, 4, 5, 11, 8, 4, 5, 7,
148
+ 8, 4, 5, 9, 8, 10, 37, 33,
149
+ 32, 33, 32, 37, 36, 32, 33, 38,
150
+ 22, 31, 9, 11, 6, 15, 12, 6,
151
+ 12, 6, 13, 12, 14, 15, 13
152
+ };
153
+
154
+ static const char _httpclient_parser_trans_actions_wi[] = {
155
+ 0, 0, 0, 0, 1, 0, 0, 0,
156
+ 0, 5, 3, 7, 13, 0, 0, 1,
157
+ 1, 0, 1, 0, 3, 9, 0, 9,
158
+ 34, 0, 34, 19, 0, 17, 28, 31,
159
+ 0, 9, 9, 0, 9, 15, 15, 0,
160
+ 15, 34, 34, 0, 34, 19, 0, 9,
161
+ 0, 11, 1, 7, 7, 22, 25, 22,
162
+ 0, 0, 3, 7, 9, 0, 9, 15,
163
+ 15, 34, 0, 34, 19, 7, 3
164
+ };
165
+
166
+ static const int httpclient_parser_start = 0;
167
+
168
+ static const int httpclient_parser_first_final = 39;
169
+
170
+ static const int httpclient_parser_error = 1;
171
+
172
+ #line 99 "http11_parser.rl"
173
+
174
+ int httpclient_parser_init(httpclient_parser *parser) {
175
+ int cs = 0;
176
+
177
+ #line 178 "http11_parser.c"
178
+ {
179
+ cs = httpclient_parser_start;
180
+ }
181
+ #line 103 "http11_parser.rl"
182
+ parser->cs = cs;
183
+ parser->body_start = 0;
184
+ parser->content_len = 0;
185
+ parser->mark = 0;
186
+ parser->nread = 0;
187
+ parser->field_len = 0;
188
+ parser->field_start = 0;
189
+
190
+ return(1);
191
+ }
192
+
193
+
194
+ /** exec **/
195
+ size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer, size_t len, size_t off) {
196
+ const char *p, *pe;
197
+ int cs = parser->cs;
198
+
199
+ assert(off <= len && "offset past end of buffer");
200
+
201
+ p = buffer+off;
202
+ pe = buffer+len;
203
+
204
+ assert(*pe == '\0' && "pointer does not end on NUL");
205
+ assert(pe - p == len - off && "pointers aren't same distance");
206
+
207
+
208
+
209
+ #line 210 "http11_parser.c"
210
+ {
211
+ int _klen;
212
+ unsigned int _trans;
213
+ const char *_acts;
214
+ unsigned int _nacts;
215
+ const char *_keys;
216
+
217
+ if ( p == pe )
218
+ goto _out;
219
+ _resume:
220
+ if ( cs == 1 )
221
+ goto _out;
222
+ _keys = _httpclient_parser_trans_keys + _httpclient_parser_key_offsets[cs];
223
+ _trans = _httpclient_parser_index_offsets[cs];
224
+
225
+ _klen = _httpclient_parser_single_lengths[cs];
226
+ if ( _klen > 0 ) {
227
+ const char *_lower = _keys;
228
+ const char *_mid;
229
+ const char *_upper = _keys + _klen - 1;
230
+ while (1) {
231
+ if ( _upper < _lower )
232
+ break;
233
+
234
+ _mid = _lower + ((_upper-_lower) >> 1);
235
+ if ( (*p) < *_mid )
236
+ _upper = _mid - 1;
237
+ else if ( (*p) > *_mid )
238
+ _lower = _mid + 1;
239
+ else {
240
+ _trans += (_mid - _keys);
241
+ goto _match;
242
+ }
243
+ }
244
+ _keys += _klen;
245
+ _trans += _klen;
246
+ }
247
+
248
+ _klen = _httpclient_parser_range_lengths[cs];
249
+ if ( _klen > 0 ) {
250
+ const char *_lower = _keys;
251
+ const char *_mid;
252
+ const char *_upper = _keys + (_klen<<1) - 2;
253
+ while (1) {
254
+ if ( _upper < _lower )
255
+ break;
256
+
257
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
258
+ if ( (*p) < _mid[0] )
259
+ _upper = _mid - 2;
260
+ else if ( (*p) > _mid[1] )
261
+ _lower = _mid + 2;
262
+ else {
263
+ _trans += ((_mid - _keys)>>1);
264
+ goto _match;
265
+ }
266
+ }
267
+ _trans += _klen;
268
+ }
269
+
270
+ _match:
271
+ _trans = _httpclient_parser_indicies[_trans];
272
+ cs = _httpclient_parser_trans_targs_wi[_trans];
273
+
274
+ if ( _httpclient_parser_trans_actions_wi[_trans] == 0 )
275
+ goto _again;
276
+
277
+ _acts = _httpclient_parser_actions + _httpclient_parser_trans_actions_wi[_trans];
278
+ _nacts = (unsigned int) *_acts++;
279
+ while ( _nacts-- > 0 )
280
+ {
281
+ switch ( *_acts++ )
282
+ {
283
+ case 0:
284
+ #line 23 "http11_parser.rl"
285
+ {MARK(mark, p); }
286
+ break;
287
+ case 1:
288
+ #line 25 "http11_parser.rl"
289
+ { MARK(field_start, p); }
290
+ break;
291
+ case 2:
292
+ #line 27 "http11_parser.rl"
293
+ {
294
+ parser->field_len = LEN(field_start, p);
295
+ }
296
+ break;
297
+ case 3:
298
+ #line 31 "http11_parser.rl"
299
+ { MARK(mark, p); }
300
+ break;
301
+ case 4:
302
+ #line 33 "http11_parser.rl"
303
+ {
304
+ parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
305
+ }
306
+ break;
307
+ case 5:
308
+ #line 37 "http11_parser.rl"
309
+ {
310
+ parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark, p));
311
+ }
312
+ break;
313
+ case 6:
314
+ #line 41 "http11_parser.rl"
315
+ {
316
+ parser->status_code(parser->data, PTR_TO(mark), LEN(mark, p));
317
+ }
318
+ break;
319
+ case 7:
320
+ #line 45 "http11_parser.rl"
321
+ {
322
+ parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
323
+ }
324
+ break;
325
+ case 8:
326
+ #line 49 "http11_parser.rl"
327
+ {
328
+ parser->chunk_size(parser->data, PTR_TO(mark), LEN(mark, p));
329
+ }
330
+ break;
331
+ case 9:
332
+ #line 53 "http11_parser.rl"
333
+ {
334
+ parser->last_chunk(parser->data, NULL, 0);
335
+ }
336
+ break;
337
+ case 10:
338
+ #line 57 "http11_parser.rl"
339
+ {
340
+ parser->body_start = p - buffer + 1;
341
+ if(parser->header_done != NULL)
342
+ parser->header_done(parser->data, p + 1, pe - p - 1);
343
+ goto _out;
344
+ }
345
+ break;
346
+ #line 347 "http11_parser.c"
347
+ }
348
+ }
349
+
350
+ _again:
351
+ if ( ++p != pe )
352
+ goto _resume;
353
+ _out: {}
354
+ }
355
+ #line 130 "http11_parser.rl"
356
+
357
+ parser->cs = cs;
358
+ parser->nread += p - (buffer + off);
359
+
360
+ assert(p <= pe && "buffer overflow after parsing execute");
361
+ assert(parser->nread <= len && "nread longer than length");
362
+ assert(parser->body_start <= len && "body starts after buffer end");
363
+ assert(parser->mark < len && "mark is after buffer end");
364
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
365
+ assert(parser->field_start < len && "field starts after buffer end");
366
+
367
+ if(parser->body_start) {
368
+ /* final \r\n combo encountered so stop right here */
369
+
370
+ #line 371 "http11_parser.c"
371
+ #line 144 "http11_parser.rl"
372
+ parser->nread++;
373
+ }
374
+
375
+ return(parser->nread);
376
+ }
377
+
378
+ int httpclient_parser_finish(httpclient_parser *parser)
379
+ {
380
+ int cs = parser->cs;
381
+
382
+
383
+ #line 384 "http11_parser.c"
384
+ #line 155 "http11_parser.rl"
385
+
386
+ parser->cs = cs;
387
+
388
+ if (httpclient_parser_has_error(parser) ) {
389
+ return -1;
390
+ } else if (httpclient_parser_is_finished(parser) ) {
391
+ return 1;
392
+ } else {
393
+ return 0;
394
+ }
395
+ }
396
+
397
+ int httpclient_parser_has_error(httpclient_parser *parser) {
398
+ return parser->cs == httpclient_parser_error;
399
+ }
400
+
401
+ int httpclient_parser_is_finished(httpclient_parser *parser) {
402
+ return parser->cs == httpclient_parser_first_final;
403
+ }