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