h1p 0.2 → 0.5
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/CHANGELOG.md +12 -1
- data/Gemfile.lock +1 -1
- data/README.md +61 -15
- data/Rakefile +1 -1
- data/benchmarks/bm_http1_parser.rb +1 -1
- data/benchmarks/pipelined.rb +101 -0
- data/examples/callable.rb +1 -1
- data/examples/http_server.rb +2 -2
- data/ext/h1p/h1p.c +525 -235
- data/ext/h1p/h1p.h +5 -0
- data/ext/h1p/limits.rb +7 -6
- data/lib/h1p/version.rb +1 -1
- data/lib/h1p.rb +16 -10
- data/test/run.rb +5 -0
- data/test/test_h1p_client.rb +532 -0
- data/test/{test_h1p.rb → test_h1p_server.rb} +91 -36
- metadata +7 -4
data/ext/h1p/h1p.c
CHANGED
@@ -16,17 +16,20 @@
|
|
16
16
|
ID ID_arity;
|
17
17
|
ID ID_backend_read;
|
18
18
|
ID ID_backend_recv;
|
19
|
+
ID ID_backend_send;
|
20
|
+
ID ID_backend_splice;
|
21
|
+
ID ID_backend_write;
|
19
22
|
ID ID_call;
|
20
23
|
ID ID_downcase;
|
21
24
|
ID ID_eof_p;
|
22
25
|
ID ID_eq;
|
23
|
-
ID
|
26
|
+
ID ID_read_method;
|
24
27
|
ID ID_read;
|
25
28
|
ID ID_readpartial;
|
26
29
|
ID ID_to_i;
|
27
30
|
ID ID_upcase;
|
31
|
+
ID ID_write_method;
|
28
32
|
|
29
|
-
static VALUE mPolyphony = Qnil;
|
30
33
|
static VALUE cError;
|
31
34
|
|
32
35
|
VALUE NUM_max_headers_read_length;
|
@@ -37,6 +40,8 @@ VALUE STR_pseudo_method;
|
|
37
40
|
VALUE STR_pseudo_path;
|
38
41
|
VALUE STR_pseudo_protocol;
|
39
42
|
VALUE STR_pseudo_rx;
|
43
|
+
VALUE STR_pseudo_status;
|
44
|
+
VALUE STR_pseudo_status_message;
|
40
45
|
|
41
46
|
VALUE STR_chunked;
|
42
47
|
VALUE STR_content_length;
|
@@ -44,27 +49,47 @@ VALUE STR_transfer_encoding;
|
|
44
49
|
|
45
50
|
VALUE SYM_backend_read;
|
46
51
|
VALUE SYM_backend_recv;
|
52
|
+
VALUE SYM_backend_send;
|
53
|
+
VALUE SYM_backend_write;
|
47
54
|
VALUE SYM_stock_readpartial;
|
48
55
|
|
56
|
+
VALUE SYM_client;
|
57
|
+
VALUE SYM_server;
|
58
|
+
|
49
59
|
enum read_method {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
RM_READPARTIAL, // receiver.readpartial(len, buf, pos, raise_on_eof: false) (Polyphony-specific)
|
61
|
+
RM_BACKEND_READ, // Polyphony.backend_read (Polyphony-specific)
|
62
|
+
RM_BACKEND_RECV, // Polyphony.backend_recv (Polyphony-specific)
|
63
|
+
RM_CALL, // receiver.call(len) (Universal)
|
64
|
+
RM_STOCK_READPARTIAL // receiver.readpartial(len)
|
65
|
+
};
|
66
|
+
|
67
|
+
enum write_method {
|
68
|
+
WM_BACKEND_WRITE,
|
69
|
+
WM_BACKEND_SEND
|
70
|
+
};
|
71
|
+
|
72
|
+
enum parser_mode {
|
73
|
+
mode_server,
|
74
|
+
mode_client
|
55
75
|
};
|
56
76
|
|
57
77
|
typedef struct parser {
|
78
|
+
enum parser_mode mode;
|
58
79
|
VALUE io;
|
59
80
|
VALUE buffer;
|
60
81
|
VALUE headers;
|
61
|
-
int pos;
|
62
82
|
int current_request_rx;
|
63
83
|
|
64
84
|
enum read_method read_method;
|
65
85
|
int body_read_mode;
|
66
86
|
int body_left;
|
67
87
|
int request_completed;
|
88
|
+
|
89
|
+
char *buf_ptr;
|
90
|
+
int buf_len;
|
91
|
+
int buf_pos;
|
92
|
+
|
68
93
|
} Parser_t;
|
69
94
|
|
70
95
|
VALUE cParser = Qnil;
|
@@ -100,39 +125,55 @@ static VALUE Parser_allocate(VALUE klass) {
|
|
100
125
|
#define GetParser(obj, parser) \
|
101
126
|
TypedData_Get_Struct((obj), Parser_t, &Parser_type, (parser))
|
102
127
|
|
103
|
-
static inline
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
128
|
+
static inline VALUE Polyphony() {
|
129
|
+
static VALUE mPolyphony = Qnil;
|
130
|
+
if (mPolyphony == Qnil) {
|
131
|
+
mPolyphony = rb_const_get(rb_cObject, rb_intern("Polyphony"));
|
132
|
+
rb_gc_register_mark_object(mPolyphony);
|
133
|
+
}
|
134
|
+
return mPolyphony;
|
108
135
|
}
|
109
136
|
|
110
|
-
enum read_method detect_read_method(VALUE io) {
|
111
|
-
if (rb_respond_to(io,
|
112
|
-
VALUE method = rb_funcall(io,
|
113
|
-
if (method == SYM_stock_readpartial) return
|
137
|
+
static enum read_method detect_read_method(VALUE io) {
|
138
|
+
if (rb_respond_to(io, ID_read_method)) {
|
139
|
+
VALUE method = rb_funcall(io, ID_read_method, 0);
|
140
|
+
if (method == SYM_stock_readpartial) return RM_STOCK_READPARTIAL;
|
141
|
+
if (method == SYM_backend_read) return RM_BACKEND_READ;
|
142
|
+
if (method == SYM_backend_recv) return RM_BACKEND_RECV;
|
114
143
|
|
115
|
-
|
116
|
-
if (method == SYM_backend_read) return method_backend_read;
|
117
|
-
if (method == SYM_backend_recv) return method_backend_recv;
|
118
|
-
|
119
|
-
return method_readpartial;
|
144
|
+
return RM_READPARTIAL;
|
120
145
|
}
|
121
146
|
else if (rb_respond_to(io, ID_call)) {
|
122
|
-
return
|
147
|
+
return RM_CALL;
|
123
148
|
}
|
124
149
|
else
|
125
|
-
rb_raise(rb_eRuntimeError, "Provided reader should be a callable or respond to #
|
150
|
+
rb_raise(rb_eRuntimeError, "Provided reader should be a callable or respond to #__read_method__");
|
151
|
+
}
|
152
|
+
|
153
|
+
static enum write_method detect_write_method(VALUE io) {
|
154
|
+
if (rb_respond_to(io, ID_write_method)) {
|
155
|
+
VALUE method = rb_funcall(io, ID_write_method, 0);
|
156
|
+
if (method == SYM_backend_write) return WM_BACKEND_WRITE;
|
157
|
+
if (method == SYM_backend_send) return WM_BACKEND_SEND;
|
158
|
+
}
|
159
|
+
rb_raise(rb_eRuntimeError, "Provided io should respond to #__write_method__");
|
160
|
+
}
|
161
|
+
|
162
|
+
enum parser_mode parse_parser_mode(VALUE mode) {
|
163
|
+
if (mode == SYM_server) return mode_server;
|
164
|
+
if (mode == SYM_client) return mode_client;
|
165
|
+
|
166
|
+
rb_raise(rb_eRuntimeError, "Invalid parser mode specified");
|
126
167
|
}
|
127
168
|
|
128
|
-
VALUE Parser_initialize(VALUE self, VALUE io) {
|
169
|
+
VALUE Parser_initialize(VALUE self, VALUE io, VALUE mode) {
|
129
170
|
Parser_t *parser;
|
130
171
|
GetParser(self, parser);
|
131
172
|
|
173
|
+
parser->mode = parse_parser_mode(mode);
|
132
174
|
parser->io = io;
|
133
175
|
parser->buffer = rb_str_new_literal("");
|
134
176
|
parser->headers = Qnil;
|
135
|
-
parser->pos = 0;
|
136
177
|
|
137
178
|
// pre-allocate the buffer
|
138
179
|
rb_str_modify_expand(parser->buffer, INITIAL_BUFFER_SIZE);
|
@@ -140,6 +181,11 @@ VALUE Parser_initialize(VALUE self, VALUE io) {
|
|
140
181
|
parser->read_method = detect_read_method(io);
|
141
182
|
parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
|
142
183
|
parser->body_left = 0;
|
184
|
+
|
185
|
+
parser->buf_ptr = 0;
|
186
|
+
parser->buf_len = 0;
|
187
|
+
parser->buf_pos = 0;
|
188
|
+
|
143
189
|
return self;
|
144
190
|
}
|
145
191
|
|
@@ -148,95 +194,96 @@ VALUE Parser_initialize(VALUE self, VALUE io) {
|
|
148
194
|
#define str_downcase(str) (rb_funcall((str), ID_downcase, 0))
|
149
195
|
#define str_upcase(str) (rb_funcall((str), ID_upcase, 0))
|
150
196
|
|
151
|
-
#define FILL_BUFFER_OR_GOTO_EOF(
|
197
|
+
#define FILL_BUFFER_OR_GOTO_EOF(parser) { if (!fill_buffer(parser)) goto eof; }
|
152
198
|
|
153
|
-
#define BUFFER_POS(
|
154
|
-
#define BUFFER_LEN(
|
155
|
-
#define BUFFER_CUR(
|
156
|
-
#define BUFFER_AT(
|
157
|
-
#define BUFFER_PTR(
|
158
|
-
#define BUFFER_STR(
|
159
|
-
#define BUFFER_STR_DOWNCASE(
|
160
|
-
#define BUFFER_STR_UPCASE(
|
199
|
+
#define BUFFER_POS(parser) ((parser)->buf_pos)
|
200
|
+
#define BUFFER_LEN(parser) ((parser)->buf_len)
|
201
|
+
#define BUFFER_CUR(parser) ((parser)->buf_ptr[(parser)->buf_pos])
|
202
|
+
#define BUFFER_AT(parser, pos) ((parser)->buf_ptr[pos])
|
203
|
+
#define BUFFER_PTR(parser, pos) ((parser)->buf_ptr + pos)
|
204
|
+
#define BUFFER_STR(parser, pos, len) (rb_obj_freeze(rb_utf8_str_new((parser)->buf_ptr + pos, len)))
|
205
|
+
#define BUFFER_STR_DOWNCASE(parser, pos, len) (rb_obj_freeze(str_downcase(rb_utf8_str_new((parser)->buf_ptr + pos, len))))
|
206
|
+
#define BUFFER_STR_UPCASE(parser, pos, len) (rb_obj_freeze(str_upcase(rb_utf8_str_new((parser)->buf_ptr + pos, len))))
|
161
207
|
|
162
|
-
#define INC_BUFFER_POS(
|
163
|
-
BUFFER_POS(
|
164
|
-
if (BUFFER_POS(
|
208
|
+
#define INC_BUFFER_POS(parser) { \
|
209
|
+
BUFFER_POS(parser)++; \
|
210
|
+
if (BUFFER_POS(parser) == BUFFER_LEN(parser)) FILL_BUFFER_OR_GOTO_EOF(parser); \
|
165
211
|
}
|
166
212
|
|
167
|
-
#define INC_BUFFER_POS_NO_FILL(
|
213
|
+
#define INC_BUFFER_POS_NO_FILL(parser) BUFFER_POS(parser)++;
|
168
214
|
|
169
|
-
#define INC_BUFFER_POS_UTF8(
|
170
|
-
unsigned char c = BUFFER_CUR(
|
215
|
+
#define INC_BUFFER_POS_UTF8(parser, len) { \
|
216
|
+
unsigned char c = BUFFER_CUR(parser); \
|
171
217
|
if ((c & 0xf0) == 0xf0) { \
|
172
|
-
while (BUFFER_LEN(
|
173
|
-
BUFFER_POS(
|
218
|
+
while (BUFFER_LEN(parser) - BUFFER_POS(parser) < 4) FILL_BUFFER_OR_GOTO_EOF(parser); \
|
219
|
+
BUFFER_POS(parser) += 4; \
|
174
220
|
len += 4; \
|
175
221
|
} \
|
176
222
|
else if ((c & 0xe0) == 0xe0) { \
|
177
|
-
while (BUFFER_LEN(
|
178
|
-
BUFFER_POS(
|
223
|
+
while (BUFFER_LEN(parser) - BUFFER_POS(parser) < 3) FILL_BUFFER_OR_GOTO_EOF(parser); \
|
224
|
+
BUFFER_POS(parser) += 3; \
|
179
225
|
len += 3; \
|
180
226
|
} \
|
181
227
|
else if ((c & 0xc0) == 0xc0) { \
|
182
|
-
while (BUFFER_LEN(
|
183
|
-
BUFFER_POS(
|
228
|
+
while (BUFFER_LEN(parser) - BUFFER_POS(parser) < 2) FILL_BUFFER_OR_GOTO_EOF(parser); \
|
229
|
+
BUFFER_POS(parser) += 2; \
|
184
230
|
len += 2; \
|
185
231
|
} \
|
186
232
|
else { \
|
187
|
-
BUFFER_POS(
|
233
|
+
BUFFER_POS(parser)++; \
|
188
234
|
len ++; \
|
189
|
-
if (BUFFER_POS(
|
235
|
+
if (BUFFER_POS(parser) == BUFFER_LEN(parser)) FILL_BUFFER_OR_GOTO_EOF(parser); \
|
190
236
|
} \
|
191
237
|
}
|
192
238
|
|
193
|
-
#define INIT_PARSER_STATE(
|
194
|
-
(
|
195
|
-
if (BUFFER_POS(
|
196
|
-
FILL_BUFFER_OR_GOTO_EOF(
|
239
|
+
#define INIT_PARSER_STATE(parser) { \
|
240
|
+
(parser)->buf_len = RSTRING_LEN((parser)->buffer); \
|
241
|
+
if (BUFFER_POS(parser) == BUFFER_LEN(parser)) \
|
242
|
+
FILL_BUFFER_OR_GOTO_EOF(parser) \
|
197
243
|
else \
|
198
|
-
(
|
244
|
+
(parser)->buf_ptr = RSTRING_PTR((parser)->buffer); \
|
199
245
|
}
|
200
246
|
|
201
247
|
#define RAISE_BAD_REQUEST(msg) rb_raise(cError, msg)
|
202
248
|
|
203
|
-
#define SET_HEADER_VALUE_FROM_BUFFER(
|
204
|
-
VALUE value = BUFFER_STR(
|
205
|
-
rb_hash_aset(headers, key, value); \
|
249
|
+
#define SET_HEADER_VALUE_FROM_BUFFER(parser, key, pos, len) { \
|
250
|
+
VALUE value = BUFFER_STR(parser, pos, len); \
|
251
|
+
rb_hash_aset(parser->headers, key, value); \
|
206
252
|
RB_GC_GUARD(value); \
|
207
253
|
}
|
208
254
|
|
209
|
-
#define SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(
|
210
|
-
VALUE value = BUFFER_STR_DOWNCASE(
|
211
|
-
rb_hash_aset(headers, key, value); \
|
255
|
+
#define SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(parser, key, pos, len) { \
|
256
|
+
VALUE value = BUFFER_STR_DOWNCASE(parser, pos, len); \
|
257
|
+
rb_hash_aset(parser->headers, key, value); \
|
212
258
|
RB_GC_GUARD(value); \
|
213
259
|
}
|
214
260
|
|
215
|
-
#define SET_HEADER_UPCASE_VALUE_FROM_BUFFER(
|
216
|
-
VALUE value = BUFFER_STR_UPCASE(
|
217
|
-
rb_hash_aset(headers, key, value); \
|
261
|
+
#define SET_HEADER_UPCASE_VALUE_FROM_BUFFER(parser, key, pos, len) { \
|
262
|
+
VALUE value = BUFFER_STR_UPCASE(parser, pos, len); \
|
263
|
+
rb_hash_aset(parser->headers, key, value); \
|
218
264
|
RB_GC_GUARD(value); \
|
219
265
|
}
|
220
266
|
|
221
|
-
#define
|
222
|
-
|
223
|
-
if (BUFFER_CUR(state) != '\n') goto bad_request; \
|
224
|
-
INC_BUFFER_POS(state); \
|
267
|
+
#define SET_HEADER_VALUE_INT(parser, key, value) { \
|
268
|
+
rb_hash_aset(parser->headers, key, INT2FIX(value)); \
|
225
269
|
}
|
226
270
|
|
227
|
-
#define
|
228
|
-
INC_BUFFER_POS(
|
229
|
-
if (BUFFER_CUR(
|
230
|
-
|
271
|
+
#define CONSUME_CRLF(parser) { \
|
272
|
+
INC_BUFFER_POS(parser); \
|
273
|
+
if (BUFFER_CUR(parser) != '\n') goto bad_request; \
|
274
|
+
INC_BUFFER_POS(parser); \
|
275
|
+
}
|
276
|
+
|
277
|
+
#define CONSUME_CRLF_NO_FILL(parser) { \
|
278
|
+
INC_BUFFER_POS(parser); \
|
279
|
+
if (BUFFER_CUR(parser) != '\n') goto bad_request; \
|
280
|
+
INC_BUFFER_POS_NO_FILL(parser); \
|
231
281
|
}
|
232
282
|
|
233
283
|
#define GLOBAL_STR(v, s) v = rb_str_new_literal(s); rb_global_variable(&v); rb_obj_freeze(v)
|
234
284
|
|
235
|
-
|
236
|
-
|
237
|
-
char *ptr;
|
238
|
-
int len;
|
239
|
-
};
|
285
|
+
// case-insensitive compare
|
286
|
+
#define CMP_CI(parser, down, up) ((BUFFER_CUR(parser) == down) || (BUFFER_CUR(parser) == up))
|
240
287
|
|
241
288
|
////////////////////////////////////////////////////////////////////////////////
|
242
289
|
|
@@ -266,52 +313,68 @@ static inline VALUE io_stock_readpartial(VALUE io, VALUE maxlen, VALUE buf, VALU
|
|
266
313
|
|
267
314
|
static inline VALUE parser_io_read(Parser_t *parser, VALUE maxlen, VALUE buf, VALUE buf_pos) {
|
268
315
|
switch (parser->read_method) {
|
269
|
-
case
|
270
|
-
return rb_funcall(
|
271
|
-
case
|
272
|
-
return rb_funcall(
|
273
|
-
case
|
274
|
-
return rb_funcall(parser->
|
275
|
-
case
|
276
|
-
return io_call(parser
|
277
|
-
case
|
316
|
+
case RM_BACKEND_READ:
|
317
|
+
return rb_funcall(Polyphony(), ID_backend_read, 5, parser->io, buf, maxlen, Qfalse, buf_pos);
|
318
|
+
case RM_BACKEND_RECV:
|
319
|
+
return rb_funcall(Polyphony(), ID_backend_recv, 4, parser->io, buf, maxlen, buf_pos);
|
320
|
+
case RM_READPARTIAL:
|
321
|
+
return rb_funcall(parser->io, ID_readpartial, 4, maxlen, buf, buf_pos, Qfalse);
|
322
|
+
case RM_CALL:
|
323
|
+
return io_call(parser->io, maxlen, buf, buf_pos);
|
324
|
+
case RM_STOCK_READPARTIAL:
|
278
325
|
return io_stock_readpartial(parser->io, maxlen, buf, buf_pos);
|
279
326
|
default:
|
280
327
|
return Qnil;
|
281
328
|
}
|
282
329
|
}
|
283
330
|
|
284
|
-
static inline
|
285
|
-
|
331
|
+
static inline VALUE parser_io_write(VALUE io, VALUE buf, enum write_method method) {
|
332
|
+
switch (method) {
|
333
|
+
case WM_BACKEND_WRITE:
|
334
|
+
return rb_funcall(Polyphony(), ID_backend_write, 2, io, buf);
|
335
|
+
case WM_BACKEND_SEND:
|
336
|
+
return rb_funcall(Polyphony(), ID_backend_send, 3, io, buf, INT2FIX(0));
|
337
|
+
default:
|
338
|
+
return Qnil;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
static inline int parser_io_splice(VALUE src, VALUE dest, int len) {
|
343
|
+
VALUE ret = rb_funcall(Polyphony(), ID_backend_splice, 3, src, dest, INT2FIX(len));
|
344
|
+
return FIX2INT(ret);
|
345
|
+
}
|
346
|
+
|
347
|
+
static inline int fill_buffer(Parser_t *parser) {
|
348
|
+
VALUE ret = parser_io_read(parser, NUM_max_headers_read_length, parser->buffer, NUM_buffer_end);
|
286
349
|
if (ret == Qnil) return 0;
|
287
350
|
|
288
|
-
|
289
|
-
int len = RSTRING_LEN(
|
290
|
-
int read_bytes = len -
|
351
|
+
parser->buffer = ret;
|
352
|
+
int len = RSTRING_LEN(parser->buffer);
|
353
|
+
int read_bytes = len - parser->buf_len;
|
291
354
|
if (!read_bytes) return 0;
|
292
|
-
|
293
|
-
|
294
|
-
|
355
|
+
|
356
|
+
parser->buf_ptr = RSTRING_PTR(parser->buffer);
|
357
|
+
parser->buf_len = len;
|
295
358
|
return read_bytes;
|
296
359
|
}
|
297
360
|
|
298
|
-
static inline void buffer_trim(
|
299
|
-
int len = RSTRING_LEN(
|
300
|
-
int pos =
|
361
|
+
static inline void buffer_trim(Parser_t *parser) {
|
362
|
+
int len = RSTRING_LEN(parser->buffer);
|
363
|
+
int pos = parser->buf_pos;
|
301
364
|
int left = len - pos;
|
302
365
|
|
303
366
|
// The buffer is trimmed only if length and position thresholds are passed,
|
304
|
-
// *and* position is past the halfway point.
|
305
|
-
if (len < BUFFER_TRIM_MIN_LEN ||
|
367
|
+
// *and* position is past the halfway point.
|
368
|
+
if (len < BUFFER_TRIM_MIN_LEN ||
|
306
369
|
pos < BUFFER_TRIM_MIN_POS ||
|
307
370
|
left >= pos) return;
|
308
371
|
|
309
372
|
if (left > 0) {
|
310
|
-
char *ptr = RSTRING_PTR(
|
373
|
+
char *ptr = RSTRING_PTR(parser->buffer);
|
311
374
|
memcpy(ptr, ptr + pos, left);
|
312
375
|
}
|
313
|
-
rb_str_set_len(
|
314
|
-
|
376
|
+
rb_str_set_len(parser->buffer, left);
|
377
|
+
parser->buf_pos = 0;
|
315
378
|
}
|
316
379
|
|
317
380
|
static inline void str_append_from_buffer(VALUE str, char *ptr, int len) {
|
@@ -323,28 +386,28 @@ static inline void str_append_from_buffer(VALUE str, char *ptr, int len) {
|
|
323
386
|
|
324
387
|
////////////////////////////////////////////////////////////////////////////////
|
325
388
|
|
326
|
-
static inline int
|
327
|
-
int pos = BUFFER_POS(
|
389
|
+
static inline int parse_request_line_method(Parser_t *parser) {
|
390
|
+
int pos = BUFFER_POS(parser);
|
328
391
|
int len = 0;
|
329
392
|
|
330
393
|
while (1) {
|
331
|
-
switch (BUFFER_CUR(
|
394
|
+
switch (BUFFER_CUR(parser)) {
|
332
395
|
case ' ':
|
333
396
|
if (len < 1 || len > MAX_METHOD_LENGTH) goto bad_request;
|
334
|
-
INC_BUFFER_POS(
|
397
|
+
INC_BUFFER_POS(parser);
|
335
398
|
goto done;
|
336
399
|
case '\r':
|
337
400
|
case '\n':
|
338
401
|
goto bad_request;
|
339
402
|
default:
|
340
|
-
INC_BUFFER_POS(
|
403
|
+
INC_BUFFER_POS(parser);
|
341
404
|
len++;
|
342
|
-
// INC_BUFFER_POS_UTF8(
|
405
|
+
// INC_BUFFER_POS_UTF8(parser, len);
|
343
406
|
if (len > MAX_METHOD_LENGTH) goto bad_request;
|
344
407
|
}
|
345
408
|
}
|
346
409
|
done:
|
347
|
-
SET_HEADER_UPCASE_VALUE_FROM_BUFFER(
|
410
|
+
SET_HEADER_UPCASE_VALUE_FROM_BUFFER(parser, STR_pseudo_method, pos, len);
|
348
411
|
return 1;
|
349
412
|
bad_request:
|
350
413
|
RAISE_BAD_REQUEST("Invalid method");
|
@@ -352,28 +415,28 @@ eof:
|
|
352
415
|
return 0;
|
353
416
|
}
|
354
417
|
|
355
|
-
static int
|
356
|
-
while (BUFFER_CUR(
|
357
|
-
int pos = BUFFER_POS(
|
418
|
+
static int parse_request_line_target(Parser_t *parser) {
|
419
|
+
while (BUFFER_CUR(parser) == ' ') INC_BUFFER_POS(parser);
|
420
|
+
int pos = BUFFER_POS(parser);
|
358
421
|
int len = 0;
|
359
422
|
while (1) {
|
360
|
-
switch (BUFFER_CUR(
|
423
|
+
switch (BUFFER_CUR(parser)) {
|
361
424
|
case ' ':
|
362
425
|
if (len < 1 || len > MAX_PATH_LENGTH) goto bad_request;
|
363
|
-
INC_BUFFER_POS(
|
426
|
+
INC_BUFFER_POS(parser);
|
364
427
|
goto done;
|
365
428
|
case '\r':
|
366
429
|
case '\n':
|
367
430
|
goto bad_request;
|
368
431
|
default:
|
369
|
-
INC_BUFFER_POS(
|
432
|
+
INC_BUFFER_POS(parser);
|
370
433
|
len++;
|
371
|
-
// INC_BUFFER_POS_UTF8(
|
434
|
+
// INC_BUFFER_POS_UTF8(parser, len);
|
372
435
|
if (len > MAX_PATH_LENGTH) goto bad_request;
|
373
436
|
}
|
374
437
|
}
|
375
438
|
done:
|
376
|
-
SET_HEADER_VALUE_FROM_BUFFER(
|
439
|
+
SET_HEADER_VALUE_FROM_BUFFER(parser, STR_pseudo_path, pos, len);
|
377
440
|
return 1;
|
378
441
|
bad_request:
|
379
442
|
RAISE_BAD_REQUEST("Invalid request target");
|
@@ -381,34 +444,31 @@ eof:
|
|
381
444
|
return 0;
|
382
445
|
}
|
383
446
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
static int parse_protocol(struct parser_state *state, VALUE headers) {
|
388
|
-
while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
|
389
|
-
int pos = BUFFER_POS(state);
|
447
|
+
static int parse_request_line_protocol(Parser_t *parser) {
|
448
|
+
while (BUFFER_CUR(parser) == ' ') INC_BUFFER_POS(parser);
|
449
|
+
int pos = BUFFER_POS(parser);
|
390
450
|
int len = 0;
|
391
451
|
|
392
|
-
if (CMP_CI(
|
393
|
-
if (CMP_CI(
|
394
|
-
if (CMP_CI(
|
395
|
-
if (CMP_CI(
|
396
|
-
if (BUFFER_CUR(
|
397
|
-
if (BUFFER_CUR(
|
452
|
+
if (CMP_CI(parser, 'H', 'h')) INC_BUFFER_POS(parser) else goto bad_request;
|
453
|
+
if (CMP_CI(parser, 'T', 't')) INC_BUFFER_POS(parser) else goto bad_request;
|
454
|
+
if (CMP_CI(parser, 'T', 't')) INC_BUFFER_POS(parser) else goto bad_request;
|
455
|
+
if (CMP_CI(parser, 'P', 'p')) INC_BUFFER_POS(parser) else goto bad_request;
|
456
|
+
if (BUFFER_CUR(parser) == '/') INC_BUFFER_POS(parser) else goto bad_request;
|
457
|
+
if (BUFFER_CUR(parser) == '1') INC_BUFFER_POS(parser) else goto bad_request;
|
398
458
|
len = 6;
|
399
459
|
while (1) {
|
400
|
-
switch (BUFFER_CUR(
|
460
|
+
switch (BUFFER_CUR(parser)) {
|
401
461
|
case '\r':
|
402
|
-
CONSUME_CRLF(
|
462
|
+
CONSUME_CRLF(parser);
|
403
463
|
goto done;
|
404
464
|
case '\n':
|
405
|
-
INC_BUFFER_POS(
|
465
|
+
INC_BUFFER_POS(parser);
|
406
466
|
goto done;
|
407
467
|
case '.':
|
408
|
-
INC_BUFFER_POS(
|
409
|
-
char c = BUFFER_CUR(
|
468
|
+
INC_BUFFER_POS(parser);
|
469
|
+
char c = BUFFER_CUR(parser);
|
410
470
|
if (c == '0' || c == '1') {
|
411
|
-
INC_BUFFER_POS(
|
471
|
+
INC_BUFFER_POS(parser);
|
412
472
|
len += 2;
|
413
473
|
continue;
|
414
474
|
}
|
@@ -419,7 +479,7 @@ static int parse_protocol(struct parser_state *state, VALUE headers) {
|
|
419
479
|
}
|
420
480
|
done:
|
421
481
|
if (len < 6 || len > 8) goto bad_request;
|
422
|
-
SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(
|
482
|
+
SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(parser, STR_pseudo_protocol, pos, len);
|
423
483
|
return 1;
|
424
484
|
bad_request:
|
425
485
|
RAISE_BAD_REQUEST("Invalid protocol");
|
@@ -427,48 +487,159 @@ eof:
|
|
427
487
|
return 0;
|
428
488
|
}
|
429
489
|
|
430
|
-
int parse_request_line(
|
431
|
-
if (!
|
432
|
-
if (!
|
433
|
-
if (!
|
490
|
+
static inline int parse_request_line(Parser_t *parser) {
|
491
|
+
if (!parse_request_line_method(parser)) goto eof;
|
492
|
+
if (!parse_request_line_target(parser)) goto eof;
|
493
|
+
if (!parse_request_line_protocol(parser)) goto eof;
|
434
494
|
|
435
495
|
return 1;
|
436
496
|
eof:
|
437
497
|
return 0;
|
438
498
|
}
|
439
499
|
|
440
|
-
static inline int
|
441
|
-
int pos = BUFFER_POS(
|
500
|
+
static inline int parse_status_line_protocol(Parser_t *parser) {
|
501
|
+
int pos = BUFFER_POS(parser);
|
442
502
|
int len = 0;
|
443
503
|
|
504
|
+
if (CMP_CI(parser, 'H', 'h')) INC_BUFFER_POS(parser) else goto bad_request;
|
505
|
+
if (CMP_CI(parser, 'T', 't')) INC_BUFFER_POS(parser) else goto bad_request;
|
506
|
+
if (CMP_CI(parser, 'T', 't')) INC_BUFFER_POS(parser) else goto bad_request;
|
507
|
+
if (CMP_CI(parser, 'P', 'p')) INC_BUFFER_POS(parser) else goto bad_request;
|
508
|
+
if (BUFFER_CUR(parser) == '/') INC_BUFFER_POS(parser) else goto bad_request;
|
509
|
+
if (BUFFER_CUR(parser) == '1') INC_BUFFER_POS(parser) else goto bad_request;
|
510
|
+
len = 6;
|
444
511
|
while (1) {
|
445
|
-
switch (BUFFER_CUR(
|
512
|
+
switch (BUFFER_CUR(parser)) {
|
513
|
+
case '.':
|
514
|
+
INC_BUFFER_POS(parser);
|
515
|
+
char c = BUFFER_CUR(parser);
|
516
|
+
if (c == '0' || c == '1') {
|
517
|
+
INC_BUFFER_POS(parser);
|
518
|
+
len += 2;
|
519
|
+
continue;
|
520
|
+
}
|
521
|
+
goto bad_request;
|
522
|
+
case ' ':
|
523
|
+
INC_BUFFER_POS(parser);
|
524
|
+
goto done;
|
525
|
+
default:
|
526
|
+
goto bad_request;
|
527
|
+
}
|
528
|
+
}
|
529
|
+
done:
|
530
|
+
if (len < 6 || len > 8) goto bad_request;
|
531
|
+
SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(parser, STR_pseudo_protocol, pos, len);
|
532
|
+
return 1;
|
533
|
+
bad_request:
|
534
|
+
RAISE_BAD_REQUEST("Invalid protocol");
|
535
|
+
eof:
|
536
|
+
return 0;
|
537
|
+
}
|
538
|
+
|
539
|
+
static inline int parse_status_line_status(Parser_t *parser) {
|
540
|
+
while (BUFFER_CUR(parser) == ' ') INC_BUFFER_POS(parser);
|
541
|
+
int len = 0;
|
542
|
+
int status = 0;
|
543
|
+
while (1) {
|
544
|
+
if (len > 4) goto bad_request;
|
545
|
+
|
546
|
+
char c = BUFFER_CUR(parser);
|
547
|
+
if (c >= '0' && c <= '9') {
|
548
|
+
status = status * 10 + (c - '0');
|
549
|
+
len += 1;
|
550
|
+
INC_BUFFER_POS(parser);
|
551
|
+
continue;
|
552
|
+
}
|
553
|
+
switch (c) {
|
554
|
+
case ' ':
|
555
|
+
INC_BUFFER_POS(parser);
|
556
|
+
goto done;
|
557
|
+
case '\r':
|
558
|
+
case '\n':
|
559
|
+
goto done;
|
560
|
+
default:
|
561
|
+
goto bad_request;
|
562
|
+
}
|
563
|
+
}
|
564
|
+
done:
|
565
|
+
SET_HEADER_VALUE_INT(parser, STR_pseudo_status, status);
|
566
|
+
return 1;
|
567
|
+
bad_request:
|
568
|
+
RAISE_BAD_REQUEST("Invalid response status");
|
569
|
+
eof:
|
570
|
+
return 0;
|
571
|
+
}
|
572
|
+
|
573
|
+
static inline int parse_status_line_status_message(Parser_t *parser) {
|
574
|
+
while (BUFFER_CUR(parser) == ' ') INC_BUFFER_POS(parser);
|
575
|
+
int pos = BUFFER_POS(parser);
|
576
|
+
int len = 0;
|
577
|
+
while (1) {
|
578
|
+
switch (BUFFER_CUR(parser)) {
|
579
|
+
case '\r':
|
580
|
+
CONSUME_CRLF(parser);
|
581
|
+
goto done;
|
582
|
+
case '\n':
|
583
|
+
INC_BUFFER_POS(parser);
|
584
|
+
goto done;
|
585
|
+
default:
|
586
|
+
INC_BUFFER_POS(parser);
|
587
|
+
len++;
|
588
|
+
if (len > MAX_STATUS_MESSAGE_LENGTH) goto bad_request;
|
589
|
+
}
|
590
|
+
}
|
591
|
+
done:
|
592
|
+
SET_HEADER_VALUE_FROM_BUFFER(parser, STR_pseudo_status_message, pos, len);
|
593
|
+
return 1;
|
594
|
+
bad_request:
|
595
|
+
RAISE_BAD_REQUEST("Invalid request target");
|
596
|
+
eof:
|
597
|
+
return 0;
|
598
|
+
}
|
599
|
+
|
600
|
+
|
601
|
+
static inline int parse_status_line(Parser_t *parser) {
|
602
|
+
if (!parse_status_line_protocol(parser)) goto eof;
|
603
|
+
if (!parse_status_line_status(parser)) goto eof;
|
604
|
+
if (!parse_status_line_status_message(parser)) goto eof;
|
605
|
+
|
606
|
+
return 1;
|
607
|
+
eof:
|
608
|
+
return 0;
|
609
|
+
}
|
610
|
+
|
611
|
+
static inline int parse_header_key(Parser_t *parser, VALUE *key) {
|
612
|
+
int pos = BUFFER_POS(parser);
|
613
|
+
int len = 0;
|
614
|
+
|
615
|
+
while (1) {
|
616
|
+
switch (BUFFER_CUR(parser)) {
|
446
617
|
case ' ':
|
447
618
|
goto bad_request;
|
448
619
|
case ':':
|
449
620
|
if (len < 1 || len > MAX_HEADER_KEY_LENGTH)
|
450
621
|
goto bad_request;
|
451
|
-
INC_BUFFER_POS(
|
622
|
+
INC_BUFFER_POS(parser);
|
452
623
|
goto done;
|
453
624
|
case '\r':
|
454
|
-
if (BUFFER_POS(
|
455
|
-
CONSUME_CRLF_NO_FILL(
|
625
|
+
if (BUFFER_POS(parser) > pos) goto bad_request;
|
626
|
+
CONSUME_CRLF_NO_FILL(parser);
|
456
627
|
goto done;
|
457
628
|
case '\n':
|
458
|
-
if (BUFFER_POS(
|
629
|
+
if (BUFFER_POS(parser) > pos) goto bad_request;
|
459
630
|
|
460
|
-
INC_BUFFER_POS_NO_FILL(
|
631
|
+
INC_BUFFER_POS_NO_FILL(parser);
|
461
632
|
goto done;
|
462
633
|
default:
|
463
|
-
INC_BUFFER_POS(
|
634
|
+
INC_BUFFER_POS(parser);
|
464
635
|
len++;
|
465
|
-
// INC_BUFFER_POS_UTF8(
|
636
|
+
// INC_BUFFER_POS_UTF8(parser, len);
|
466
637
|
if (len > MAX_HEADER_KEY_LENGTH) goto bad_request;
|
467
638
|
}
|
468
639
|
}
|
469
640
|
done:
|
470
641
|
if (len == 0) return -1;
|
471
|
-
(*key) = BUFFER_STR_DOWNCASE(
|
642
|
+
(*key) = BUFFER_STR_DOWNCASE(parser, pos, len);
|
472
643
|
return 1;
|
473
644
|
bad_request:
|
474
645
|
RAISE_BAD_REQUEST("Invalid header key");
|
@@ -476,28 +647,28 @@ eof:
|
|
476
647
|
return 0;
|
477
648
|
}
|
478
649
|
|
479
|
-
static inline int parse_header_value(
|
480
|
-
while (BUFFER_CUR(
|
650
|
+
static inline int parse_header_value(Parser_t *parser, VALUE *value) {
|
651
|
+
while (BUFFER_CUR(parser) == ' ') INC_BUFFER_POS(parser);
|
481
652
|
|
482
|
-
int pos = BUFFER_POS(
|
653
|
+
int pos = BUFFER_POS(parser);
|
483
654
|
int len = 0;
|
484
655
|
|
485
656
|
while (1) {
|
486
|
-
switch (BUFFER_CUR(
|
657
|
+
switch (BUFFER_CUR(parser)) {
|
487
658
|
case '\r':
|
488
|
-
CONSUME_CRLF(
|
659
|
+
CONSUME_CRLF(parser);
|
489
660
|
goto done;
|
490
661
|
case '\n':
|
491
|
-
INC_BUFFER_POS(
|
662
|
+
INC_BUFFER_POS(parser);
|
492
663
|
goto done;
|
493
664
|
default:
|
494
|
-
INC_BUFFER_POS_UTF8(
|
665
|
+
INC_BUFFER_POS_UTF8(parser, len);
|
495
666
|
if (len > MAX_HEADER_VALUE_LENGTH) goto bad_request;
|
496
667
|
}
|
497
668
|
}
|
498
669
|
done:
|
499
670
|
if (len < 1 || len > MAX_HEADER_VALUE_LENGTH) goto bad_request;
|
500
|
-
(*value) = BUFFER_STR(
|
671
|
+
(*value) = BUFFER_STR(parser, pos, len);
|
501
672
|
return 1;
|
502
673
|
bad_request:
|
503
674
|
RAISE_BAD_REQUEST("Invalid header value");
|
@@ -505,27 +676,27 @@ eof:
|
|
505
676
|
return 0;
|
506
677
|
}
|
507
678
|
|
508
|
-
static inline int parse_header(
|
679
|
+
static inline int parse_header(Parser_t *parser) {
|
509
680
|
VALUE key, value;
|
510
681
|
|
511
|
-
switch (parse_header_key(
|
682
|
+
switch (parse_header_key(parser, &key)) {
|
512
683
|
case -1: return -1;
|
513
684
|
case 0: goto eof;
|
514
685
|
}
|
515
686
|
|
516
|
-
if (!parse_header_value(
|
687
|
+
if (!parse_header_value(parser, &value)) goto eof;
|
517
688
|
|
518
|
-
VALUE existing = rb_hash_aref(headers, key);
|
689
|
+
VALUE existing = rb_hash_aref(parser->headers, key);
|
519
690
|
if (existing != Qnil) {
|
520
691
|
if (TYPE(existing) != T_ARRAY) {
|
521
692
|
existing = rb_ary_new3(2, existing, value);
|
522
|
-
rb_hash_aset(headers, key, existing);
|
693
|
+
rb_hash_aset(parser->headers, key, existing);
|
523
694
|
}
|
524
695
|
else
|
525
696
|
rb_ary_push(existing, value);
|
526
697
|
}
|
527
698
|
else
|
528
|
-
rb_hash_aset(headers, key, value);
|
699
|
+
rb_hash_aset(parser->headers, key, value);
|
529
700
|
|
530
701
|
RB_GC_GUARD(existing);
|
531
702
|
RB_GC_GUARD(key);
|
@@ -536,36 +707,41 @@ eof:
|
|
536
707
|
}
|
537
708
|
|
538
709
|
VALUE Parser_parse_headers(VALUE self) {
|
539
|
-
|
540
|
-
GetParser(self,
|
541
|
-
|
710
|
+
Parser_t *parser;
|
711
|
+
GetParser(self, parser);
|
712
|
+
parser->headers = rb_hash_new();
|
542
713
|
|
543
|
-
buffer_trim(
|
544
|
-
int initial_pos =
|
545
|
-
INIT_PARSER_STATE(
|
546
|
-
|
714
|
+
buffer_trim(parser);
|
715
|
+
int initial_pos = parser->buf_pos;
|
716
|
+
INIT_PARSER_STATE(parser);
|
717
|
+
parser->current_request_rx = 0;
|
547
718
|
|
548
|
-
if (
|
719
|
+
if (parser->mode == mode_server) {
|
720
|
+
if (!parse_request_line(parser)) goto eof;
|
721
|
+
}
|
722
|
+
else {
|
723
|
+
if (!parse_status_line(parser)) goto eof;
|
724
|
+
}
|
549
725
|
|
550
726
|
int header_count = 0;
|
551
727
|
while (1) {
|
552
728
|
if (header_count > MAX_HEADER_COUNT) RAISE_BAD_REQUEST("Too many headers");
|
553
|
-
switch (parse_header(
|
729
|
+
switch (parse_header(parser)) {
|
554
730
|
case -1: goto done; // empty header => end of headers
|
555
731
|
case 0: goto eof;
|
556
732
|
}
|
557
733
|
header_count++;
|
558
734
|
}
|
559
735
|
eof:
|
560
|
-
|
736
|
+
parser->headers = Qnil;
|
561
737
|
done:
|
562
|
-
|
563
|
-
int read_bytes = BUFFER_POS(
|
738
|
+
parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
|
739
|
+
int read_bytes = BUFFER_POS(parser) - initial_pos;
|
564
740
|
|
565
|
-
|
566
|
-
if (
|
567
|
-
rb_hash_aset(
|
568
|
-
return
|
741
|
+
parser->current_request_rx += read_bytes;
|
742
|
+
if (parser->headers != Qnil)
|
743
|
+
rb_hash_aset(parser->headers, STR_pseudo_rx, INT2FIX(read_bytes));
|
744
|
+
return parser->headers;
|
569
745
|
}
|
570
746
|
|
571
747
|
////////////////////////////////////////////////////////////////////////////////
|
@@ -594,13 +770,13 @@ VALUE read_body_with_content_length(Parser_t *parser, int read_entire_body, int
|
|
594
770
|
VALUE body = Qnil;
|
595
771
|
|
596
772
|
int len = RSTRING_LEN(parser->buffer);
|
597
|
-
int pos = parser
|
773
|
+
int pos = BUFFER_POS(parser);
|
598
774
|
|
599
775
|
if (pos < len) {
|
600
776
|
int available = len - pos;
|
601
777
|
if (available > parser->body_left) available = parser->body_left;
|
602
778
|
body = rb_str_new(RSTRING_PTR(parser->buffer) + pos, available);
|
603
|
-
parser
|
779
|
+
BUFFER_POS(parser) += available;
|
604
780
|
parser->current_request_rx += available;
|
605
781
|
parser->body_left -= available;
|
606
782
|
if (!parser->body_left) parser->request_completed = 1;
|
@@ -610,10 +786,10 @@ VALUE read_body_with_content_length(Parser_t *parser, int read_entire_body, int
|
|
610
786
|
len = 0;
|
611
787
|
}
|
612
788
|
if (buffered_only) return body;
|
613
|
-
|
789
|
+
|
614
790
|
while (parser->body_left) {
|
615
791
|
int maxlen = parser->body_left <= MAX_BODY_READ_LENGTH ? parser->body_left : MAX_BODY_READ_LENGTH;
|
616
|
-
VALUE tmp_buf = parser_io_read(parser,
|
792
|
+
VALUE tmp_buf = parser_io_read(parser, INT2FIX(maxlen), Qnil, NUM_buffer_start);
|
617
793
|
if (tmp_buf == Qnil) goto eof;
|
618
794
|
if (body != Qnil)
|
619
795
|
rb_str_append(body, tmp_buf);
|
@@ -627,7 +803,7 @@ VALUE read_body_with_content_length(Parser_t *parser, int read_entire_body, int
|
|
627
803
|
if (!read_entire_body) goto done;
|
628
804
|
}
|
629
805
|
done:
|
630
|
-
rb_hash_aset(parser->headers, STR_pseudo_rx,
|
806
|
+
rb_hash_aset(parser->headers, STR_pseudo_rx, INT2FIX(parser->current_request_rx));
|
631
807
|
RB_GC_GUARD(body);
|
632
808
|
return body;
|
633
809
|
eof:
|
@@ -639,34 +815,34 @@ int chunked_encoding_p(VALUE transfer_encoding) {
|
|
639
815
|
return rb_funcall(str_downcase(transfer_encoding), ID_eq, 1, STR_chunked) == Qtrue;
|
640
816
|
}
|
641
817
|
|
642
|
-
int parse_chunk_size(
|
818
|
+
int parse_chunk_size(Parser_t *parser, int *chunk_size) {
|
643
819
|
int len = 0;
|
644
820
|
int value = 0;
|
645
|
-
int initial_pos = BUFFER_POS(
|
821
|
+
int initial_pos = BUFFER_POS(parser);
|
646
822
|
|
647
823
|
while (1) {
|
648
|
-
char c = BUFFER_CUR(
|
824
|
+
char c = BUFFER_CUR(parser);
|
649
825
|
if ((c >= '0') && (c <= '9')) value = (value << 4) + (c - '0');
|
650
826
|
else if ((c >= 'a') && (c <= 'f')) value = (value << 4) + (c - 'a' + 10);
|
651
827
|
else if ((c >= 'A') && (c <= 'F')) value = (value << 4) + (c - 'A' + 10);
|
652
828
|
else switch (c) {
|
653
829
|
case '\r':
|
654
|
-
CONSUME_CRLF_NO_FILL(
|
830
|
+
CONSUME_CRLF_NO_FILL(parser);
|
655
831
|
goto done;
|
656
832
|
case '\n':
|
657
|
-
INC_BUFFER_POS_NO_FILL(
|
833
|
+
INC_BUFFER_POS_NO_FILL(parser);
|
658
834
|
goto done;
|
659
835
|
default:
|
660
836
|
goto bad_request;
|
661
837
|
}
|
662
|
-
INC_BUFFER_POS(
|
838
|
+
INC_BUFFER_POS(parser);
|
663
839
|
len++;
|
664
840
|
if (len >= MAX_CHUNKED_ENCODING_CHUNK_SIZE_LENGTH) goto bad_request;
|
665
841
|
}
|
666
842
|
done:
|
667
843
|
if (len == 0) goto bad_request;
|
668
844
|
(*chunk_size) = value;
|
669
|
-
|
845
|
+
parser->current_request_rx += BUFFER_POS(parser) - initial_pos;
|
670
846
|
return 1;
|
671
847
|
bad_request:
|
672
848
|
RAISE_BAD_REQUEST("Invalid chunk size");
|
@@ -674,20 +850,20 @@ eof:
|
|
674
850
|
return 0;
|
675
851
|
}
|
676
852
|
|
677
|
-
int read_body_chunk_with_chunked_encoding(
|
678
|
-
int len = RSTRING_LEN(
|
679
|
-
int pos =
|
853
|
+
int read_body_chunk_with_chunked_encoding(Parser_t *parser, VALUE *body, int chunk_size, int buffered_only) {
|
854
|
+
int len = RSTRING_LEN(parser->buffer);
|
855
|
+
int pos = BUFFER_POS(parser);
|
680
856
|
int left = chunk_size;
|
681
857
|
|
682
858
|
if (pos < len) {
|
683
859
|
int available = len - pos;
|
684
860
|
if (available > left) available = left;
|
685
861
|
if (*body != Qnil)
|
686
|
-
str_append_from_buffer(*body, RSTRING_PTR(
|
862
|
+
str_append_from_buffer(*body, RSTRING_PTR(parser->buffer) + pos, available);
|
687
863
|
else
|
688
|
-
*body = rb_str_new(RSTRING_PTR(
|
689
|
-
|
690
|
-
|
864
|
+
*body = rb_str_new(RSTRING_PTR(parser->buffer) + pos, available);
|
865
|
+
BUFFER_POS(parser) += available;
|
866
|
+
parser->current_request_rx += available;
|
691
867
|
left -= available;
|
692
868
|
}
|
693
869
|
if (buffered_only) return 1;
|
@@ -695,14 +871,14 @@ int read_body_chunk_with_chunked_encoding(struct parser_state *state, VALUE *bod
|
|
695
871
|
while (left) {
|
696
872
|
int maxlen = left <= MAX_BODY_READ_LENGTH ? left : MAX_BODY_READ_LENGTH;
|
697
873
|
|
698
|
-
VALUE tmp_buf = parser_io_read(
|
874
|
+
VALUE tmp_buf = parser_io_read(parser, INT2FIX(maxlen), Qnil, NUM_buffer_start);
|
699
875
|
if (tmp_buf == Qnil) goto eof;
|
700
876
|
if (*body != Qnil)
|
701
877
|
rb_str_append(*body, tmp_buf);
|
702
878
|
else
|
703
879
|
*body = tmp_buf;
|
704
880
|
int read_bytes = RSTRING_LEN(tmp_buf);
|
705
|
-
|
881
|
+
parser->current_request_rx += read_bytes;
|
706
882
|
left -= read_bytes;
|
707
883
|
RB_GC_GUARD(tmp_buf);
|
708
884
|
}
|
@@ -711,46 +887,71 @@ eof:
|
|
711
887
|
return 0;
|
712
888
|
}
|
713
889
|
|
714
|
-
|
715
|
-
int
|
716
|
-
|
717
|
-
|
890
|
+
int splice_body_chunk_with_chunked_encoding(Parser_t *parser, VALUE dest, int chunk_size, enum write_method method) {
|
891
|
+
int len = RSTRING_LEN(parser->buffer);
|
892
|
+
int pos = BUFFER_POS(parser);
|
893
|
+
int left = chunk_size;
|
894
|
+
|
895
|
+
if (pos < len) {
|
896
|
+
int available = len - pos;
|
897
|
+
if (available > left) available = left;
|
898
|
+
VALUE buf = rb_str_new(RSTRING_PTR(parser->buffer) + pos, available);
|
899
|
+
BUFFER_POS(parser) += available;
|
900
|
+
parser->current_request_rx += available;
|
901
|
+
parser_io_write(dest, buf, method);
|
902
|
+
RB_GC_GUARD(buf);
|
903
|
+
left -= available;
|
904
|
+
}
|
905
|
+
|
906
|
+
while (left) {
|
907
|
+
int spliced = parser_io_splice(parser->io, dest, left);
|
908
|
+
if (!spliced) goto eof;
|
909
|
+
parser->current_request_rx += spliced;
|
910
|
+
left -= spliced;
|
911
|
+
}
|
912
|
+
return 1;
|
913
|
+
eof:
|
914
|
+
return 0;
|
915
|
+
}
|
916
|
+
|
917
|
+
static inline int parse_chunk_postfix(Parser_t *parser) {
|
918
|
+
int initial_pos = BUFFER_POS(parser);
|
919
|
+
if (initial_pos == BUFFER_LEN(parser)) FILL_BUFFER_OR_GOTO_EOF(parser);
|
920
|
+
switch (BUFFER_CUR(parser)) {
|
718
921
|
case '\r':
|
719
|
-
CONSUME_CRLF_NO_FILL(
|
922
|
+
CONSUME_CRLF_NO_FILL(parser);
|
720
923
|
goto done;
|
721
924
|
case '\n':
|
722
|
-
INC_BUFFER_POS_NO_FILL(
|
925
|
+
INC_BUFFER_POS_NO_FILL(parser);
|
723
926
|
goto done;
|
724
927
|
default:
|
725
928
|
goto bad_request;
|
726
929
|
}
|
727
930
|
done:
|
728
|
-
|
931
|
+
parser->current_request_rx += BUFFER_POS(parser) - initial_pos;
|
729
932
|
return 1;
|
730
933
|
bad_request:
|
731
|
-
RAISE_BAD_REQUEST("Invalid
|
934
|
+
RAISE_BAD_REQUEST("Invalid chunk");
|
732
935
|
eof:
|
733
936
|
return 0;
|
734
937
|
}
|
735
938
|
|
736
939
|
VALUE read_body_with_chunked_encoding(Parser_t *parser, int read_entire_body, int buffered_only) {
|
737
|
-
|
738
|
-
|
739
|
-
buffer_trim(&state);
|
740
|
-
INIT_PARSER_STATE(&state);
|
940
|
+
buffer_trim(parser);
|
941
|
+
INIT_PARSER_STATE(parser);
|
741
942
|
VALUE body = Qnil;
|
742
943
|
|
743
944
|
while (1) {
|
744
945
|
int chunk_size = 0;
|
745
|
-
if (BUFFER_POS(
|
746
|
-
if (!parse_chunk_size(
|
747
|
-
|
946
|
+
if (BUFFER_POS(parser) == BUFFER_LEN(parser)) FILL_BUFFER_OR_GOTO_EOF(parser);
|
947
|
+
if (!parse_chunk_size(parser, &chunk_size)) goto bad_request;
|
948
|
+
|
748
949
|
if (chunk_size) {
|
749
|
-
if (!read_body_chunk_with_chunked_encoding(
|
950
|
+
if (!read_body_chunk_with_chunked_encoding(parser, &body, chunk_size, buffered_only)) goto bad_request;
|
750
951
|
}
|
751
952
|
else parser->request_completed = 1;
|
752
953
|
|
753
|
-
if (!parse_chunk_postfix(
|
954
|
+
if (!parse_chunk_postfix(parser)) goto bad_request;
|
754
955
|
if (!chunk_size || !read_entire_body) goto done;
|
755
956
|
}
|
756
957
|
bad_request:
|
@@ -758,11 +959,70 @@ bad_request:
|
|
758
959
|
eof:
|
759
960
|
RAISE_BAD_REQUEST("Incomplete request body");
|
760
961
|
done:
|
761
|
-
rb_hash_aset(parser->headers, STR_pseudo_rx,
|
962
|
+
rb_hash_aset(parser->headers, STR_pseudo_rx, INT2FIX(parser->current_request_rx));
|
762
963
|
RB_GC_GUARD(body);
|
763
964
|
return body;
|
764
965
|
}
|
765
966
|
|
967
|
+
void splice_body_with_chunked_encoding(Parser_t *parser, VALUE dest, enum write_method method) {
|
968
|
+
buffer_trim(parser);
|
969
|
+
INIT_PARSER_STATE(parser);
|
970
|
+
|
971
|
+
while (1) {
|
972
|
+
int chunk_size = 0;
|
973
|
+
if (BUFFER_POS(parser) == BUFFER_LEN(parser)) FILL_BUFFER_OR_GOTO_EOF(parser);
|
974
|
+
if (!parse_chunk_size(parser, &chunk_size)) goto bad_request;
|
975
|
+
|
976
|
+
if (chunk_size) {
|
977
|
+
if (!splice_body_chunk_with_chunked_encoding(parser, dest, chunk_size, method))
|
978
|
+
goto bad_request;
|
979
|
+
}
|
980
|
+
else
|
981
|
+
parser->request_completed = 1;
|
982
|
+
|
983
|
+
// read post-chunk delimiter ("\r\n")
|
984
|
+
if (!parse_chunk_postfix(parser)) goto bad_request;
|
985
|
+
if (!chunk_size) goto done;
|
986
|
+
}
|
987
|
+
bad_request:
|
988
|
+
RAISE_BAD_REQUEST("Malformed request body");
|
989
|
+
eof:
|
990
|
+
RAISE_BAD_REQUEST("Incomplete request body");
|
991
|
+
done:
|
992
|
+
rb_hash_aset(parser->headers, STR_pseudo_rx, INT2FIX(parser->current_request_rx));
|
993
|
+
}
|
994
|
+
|
995
|
+
void splice_body_with_content_length(Parser_t *parser, VALUE dest, enum write_method method) {
|
996
|
+
if (parser->body_left <= 0) return;
|
997
|
+
|
998
|
+
int len = RSTRING_LEN(parser->buffer);
|
999
|
+
int pos = BUFFER_POS(parser);
|
1000
|
+
|
1001
|
+
if (pos < len) {
|
1002
|
+
int available = len - pos;
|
1003
|
+
if (available > parser->body_left) available = parser->body_left;
|
1004
|
+
VALUE buf = rb_str_new(RSTRING_PTR(parser->buffer) + pos, available);
|
1005
|
+
BUFFER_POS(parser) += available;
|
1006
|
+
parser_io_write(dest, buf, method);
|
1007
|
+
RB_GC_GUARD(buf);
|
1008
|
+
parser->current_request_rx += available;
|
1009
|
+
parser->body_left -= available;
|
1010
|
+
if (!parser->body_left) parser->request_completed = 1;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
while (parser->body_left) {
|
1014
|
+
int spliced = parser_io_splice(parser->io, dest, parser->body_left);
|
1015
|
+
if (!spliced) goto eof;
|
1016
|
+
parser->current_request_rx += spliced;
|
1017
|
+
parser->body_left -= spliced;
|
1018
|
+
}
|
1019
|
+
done:
|
1020
|
+
rb_hash_aset(parser->headers, STR_pseudo_rx, INT2FIX(parser->current_request_rx));
|
1021
|
+
return;
|
1022
|
+
eof:
|
1023
|
+
RAISE_BAD_REQUEST("Incomplete body");
|
1024
|
+
}
|
1025
|
+
|
766
1026
|
static inline void detect_body_read_mode(Parser_t *parser) {
|
767
1027
|
VALUE content_length = rb_hash_aref(parser->headers, STR_content_length);
|
768
1028
|
if (content_length != Qnil) {
|
@@ -772,7 +1032,7 @@ static inline void detect_body_read_mode(Parser_t *parser) {
|
|
772
1032
|
parser->request_completed = 0;
|
773
1033
|
return;
|
774
1034
|
}
|
775
|
-
|
1035
|
+
|
776
1036
|
VALUE transfer_encoding = rb_hash_aref(parser->headers, STR_transfer_encoding);
|
777
1037
|
if (chunked_encoding_p(transfer_encoding)) {
|
778
1038
|
parser->body_read_mode = BODY_READ_MODE_CHUNKED;
|
@@ -792,7 +1052,8 @@ static inline VALUE read_body(VALUE self, int read_entire_body, int buffered_onl
|
|
792
1052
|
|
793
1053
|
if (parser->body_read_mode == BODY_READ_MODE_CHUNKED)
|
794
1054
|
return read_body_with_chunked_encoding(parser, read_entire_body, buffered_only);
|
795
|
-
|
1055
|
+
else
|
1056
|
+
return read_body_with_content_length(parser, read_entire_body, buffered_only);
|
796
1057
|
}
|
797
1058
|
|
798
1059
|
VALUE Parser_read_body(VALUE self) {
|
@@ -803,6 +1064,22 @@ VALUE Parser_read_body_chunk(VALUE self, VALUE buffered_only) {
|
|
803
1064
|
return read_body(self, 0, buffered_only == Qtrue);
|
804
1065
|
}
|
805
1066
|
|
1067
|
+
VALUE Parser_splice_body_to(VALUE self, VALUE dest) {
|
1068
|
+
Parser_t *parser;
|
1069
|
+
GetParser(self, parser);
|
1070
|
+
enum write_method method = detect_write_method(dest);
|
1071
|
+
|
1072
|
+
if (parser->body_read_mode == BODY_READ_MODE_UNKNOWN)
|
1073
|
+
detect_body_read_mode(parser);
|
1074
|
+
|
1075
|
+
if (parser->body_read_mode == BODY_READ_MODE_CHUNKED)
|
1076
|
+
splice_body_with_chunked_encoding(parser, dest, method);
|
1077
|
+
else
|
1078
|
+
splice_body_with_content_length(parser, dest, method);
|
1079
|
+
|
1080
|
+
return self;
|
1081
|
+
}
|
1082
|
+
|
806
1083
|
VALUE Parser_complete_p(VALUE self) {
|
807
1084
|
Parser_t *parser;
|
808
1085
|
GetParser(self, parser);
|
@@ -826,41 +1103,54 @@ void Init_H1P() {
|
|
826
1103
|
rb_gc_register_mark_object(cError);
|
827
1104
|
|
828
1105
|
// backend methods
|
829
|
-
rb_define_method(cParser, "initialize", Parser_initialize,
|
1106
|
+
rb_define_method(cParser, "initialize", Parser_initialize, 2);
|
830
1107
|
rb_define_method(cParser, "parse_headers", Parser_parse_headers, 0);
|
831
1108
|
rb_define_method(cParser, "read_body", Parser_read_body, 0);
|
832
1109
|
rb_define_method(cParser, "read_body_chunk", Parser_read_body_chunk, 1);
|
1110
|
+
rb_define_method(cParser, "splice_body_to", Parser_splice_body_to, 1);
|
833
1111
|
rb_define_method(cParser, "complete?", Parser_complete_p, 0);
|
834
1112
|
|
835
1113
|
ID_arity = rb_intern("arity");
|
836
1114
|
ID_backend_read = rb_intern("backend_read");
|
837
1115
|
ID_backend_recv = rb_intern("backend_recv");
|
1116
|
+
ID_backend_send = rb_intern("backend_send");
|
1117
|
+
ID_backend_splice = rb_intern("backend_splice");
|
1118
|
+
ID_backend_write = rb_intern("backend_write");
|
838
1119
|
ID_call = rb_intern("call");
|
839
1120
|
ID_downcase = rb_intern("downcase");
|
840
1121
|
ID_eof_p = rb_intern("eof?");
|
841
1122
|
ID_eq = rb_intern("==");
|
842
|
-
|
1123
|
+
ID_read_method = rb_intern("__read_method__");
|
843
1124
|
ID_read = rb_intern("read");
|
844
1125
|
ID_readpartial = rb_intern("readpartial");
|
845
1126
|
ID_to_i = rb_intern("to_i");
|
846
1127
|
ID_upcase = rb_intern("upcase");
|
1128
|
+
ID_write_method = rb_intern("__write_method__");
|
847
1129
|
|
848
|
-
NUM_max_headers_read_length =
|
849
|
-
NUM_buffer_start =
|
850
|
-
NUM_buffer_end =
|
1130
|
+
NUM_max_headers_read_length = INT2FIX(MAX_HEADERS_READ_LENGTH);
|
1131
|
+
NUM_buffer_start = INT2FIX(0);
|
1132
|
+
NUM_buffer_end = INT2FIX(-1);
|
851
1133
|
|
852
|
-
GLOBAL_STR(STR_pseudo_method,
|
853
|
-
GLOBAL_STR(STR_pseudo_path,
|
854
|
-
GLOBAL_STR(STR_pseudo_protocol,
|
855
|
-
GLOBAL_STR(STR_pseudo_rx,
|
1134
|
+
GLOBAL_STR(STR_pseudo_method, ":method");
|
1135
|
+
GLOBAL_STR(STR_pseudo_path, ":path");
|
1136
|
+
GLOBAL_STR(STR_pseudo_protocol, ":protocol");
|
1137
|
+
GLOBAL_STR(STR_pseudo_rx, ":rx");
|
1138
|
+
GLOBAL_STR(STR_pseudo_status, ":status");
|
1139
|
+
GLOBAL_STR(STR_pseudo_status_message, ":status_message");
|
856
1140
|
|
857
|
-
GLOBAL_STR(STR_chunked,
|
858
|
-
GLOBAL_STR(STR_content_length,
|
859
|
-
GLOBAL_STR(STR_transfer_encoding,
|
1141
|
+
GLOBAL_STR(STR_chunked, "chunked");
|
1142
|
+
GLOBAL_STR(STR_content_length, "content-length");
|
1143
|
+
GLOBAL_STR(STR_transfer_encoding, "transfer-encoding");
|
1144
|
+
|
1145
|
+
SYM_backend_read = ID2SYM(ID_backend_read);
|
1146
|
+
SYM_backend_recv = ID2SYM(ID_backend_recv);
|
1147
|
+
SYM_backend_send = ID2SYM(ID_backend_send);
|
1148
|
+
SYM_backend_write = ID2SYM(ID_backend_write);
|
860
1149
|
|
861
|
-
SYM_backend_read = ID2SYM(ID_backend_read);
|
862
|
-
SYM_backend_recv = ID2SYM(ID_backend_recv);
|
863
1150
|
SYM_stock_readpartial = ID2SYM(rb_intern("stock_readpartial"));
|
1151
|
+
|
1152
|
+
SYM_client = ID2SYM(rb_intern("client"));
|
1153
|
+
SYM_server = ID2SYM(rb_intern("server"));
|
864
1154
|
|
865
1155
|
rb_global_variable(&mH1P);
|
866
1156
|
}
|