tipi 0.42 → 0.43

Sign up to get free protection for your applications and to get access to all the features.
data/ext/tipi/extconf.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rubygems'
4
- require 'mkmf'
5
-
6
- require_relative '../../security/http1'
7
-
8
- $CFLAGS << " -Wno-format-security"
9
- CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
10
- Tipi::HTTP1_LIMITS.each { |k, v| $defs << "-D#{k.upcase}=#{v}" }
11
-
12
- dir_config 'tipi_ext'
13
- create_makefile 'tipi_ext'
@@ -1,823 +0,0 @@
1
- #include "ruby.h"
2
- #include "http1_parser.h"
3
-
4
- // Security-related limits are defined in security/http1.rb and injected as
5
- // defines in extconf.rb
6
-
7
- #define INITIAL_BUFFER_SIZE 4096
8
- #define BUFFER_TRIM_MIN_LEN 4096
9
- #define BUFFER_TRIM_MIN_POS 2048
10
- #define MAX_HEADERS_READ_LENGTH 4096
11
- #define MAX_BODY_READ_LENGTH (1 << 20) // 1MB
12
-
13
- #define BODY_READ_MODE_UNKNOWN -2
14
- #define BODY_READ_MODE_CHUNKED -1
15
-
16
- ID ID_arity;
17
- ID ID_backend_read;
18
- ID ID_backend_recv;
19
- ID ID_call;
20
- ID ID_downcase;
21
- ID ID_eq;
22
- ID ID_parser_read_method;
23
- ID ID_read;
24
- ID ID_readpartial;
25
- ID ID_to_i;
26
-
27
- static VALUE mPolyphony = Qnil;
28
- static VALUE cError;
29
-
30
- VALUE NUM_max_headers_read_length;
31
- VALUE NUM_buffer_start;
32
- VALUE NUM_buffer_end;
33
-
34
- VALUE STR_pseudo_method;
35
- VALUE STR_pseudo_path;
36
- VALUE STR_pseudo_protocol;
37
- VALUE STR_pseudo_rx;
38
-
39
- VALUE STR_chunked;
40
- VALUE STR_content_length;
41
- VALUE STR_transfer_encoding;
42
-
43
- VALUE SYM_backend_read;
44
- VALUE SYM_backend_recv;
45
-
46
- enum read_method {
47
- method_readpartial, // receiver.readpartial (Polyphony-specific)
48
- method_backend_read, // Polyphony.backend_read (Polyphony-specific)
49
- method_backend_recv, // Polyphony.backend_recv (Polyphony-specific)
50
- method_call // receiver.call(len) (Universal)
51
- };
52
-
53
- typedef struct parser {
54
- VALUE io;
55
- VALUE buffer;
56
- VALUE headers;
57
- int pos;
58
- int current_request_rx;
59
-
60
- enum read_method read_method;
61
- int body_read_mode;
62
- int body_left;
63
- int request_completed;
64
- } Parser_t;
65
-
66
- VALUE cParser = Qnil;
67
-
68
- static void Parser_mark(void *ptr) {
69
- Parser_t *parser = ptr;
70
- rb_gc_mark(parser->io);
71
- rb_gc_mark(parser->buffer);
72
- rb_gc_mark(parser->headers);
73
- }
74
-
75
- static void Parser_free(void *ptr) {
76
- xfree(ptr);
77
- }
78
-
79
- static size_t Parser_size(const void *ptr) {
80
- return sizeof(Parser_t);
81
- }
82
-
83
- static const rb_data_type_t Parser_type = {
84
- "Parser",
85
- {Parser_mark, Parser_free, Parser_size,},
86
- 0, 0, 0
87
- };
88
-
89
- static VALUE Parser_allocate(VALUE klass) {
90
- Parser_t *parser;
91
-
92
- parser = ALLOC(Parser_t);
93
- return TypedData_Wrap_Struct(klass, &Parser_type, parser);
94
- }
95
-
96
- #define GetParser(obj, parser) \
97
- TypedData_Get_Struct((obj), Parser_t, &Parser_type, (parser))
98
-
99
- enum read_method detect_read_method(VALUE io) {
100
- if (rb_respond_to(io, ID_parser_read_method)) {
101
- if (mPolyphony == Qnil)
102
- mPolyphony = rb_const_get(rb_cObject, rb_intern("Polyphony"));
103
- VALUE method = rb_funcall(io, ID_parser_read_method, 0);
104
- if (method == SYM_backend_read) return method_backend_read;
105
- if (method == SYM_backend_recv) return method_backend_recv;
106
- return method_readpartial;
107
- }
108
- else if (rb_respond_to(io, ID_call)) {
109
- return method_call;
110
- }
111
- else
112
- rb_raise(rb_eRuntimeError, "Provided reader should be a callable or respond to #__parser_read_method__");
113
- }
114
-
115
- VALUE Parser_initialize(VALUE self, VALUE io) {
116
- Parser_t *parser;
117
- GetParser(self, parser);
118
-
119
- parser->io = io;
120
- parser->buffer = rb_str_new_literal("");
121
- parser->headers = Qnil;
122
- parser->pos = 0;
123
-
124
- // pre-allocate the buffer
125
- rb_str_modify_expand(parser->buffer, INITIAL_BUFFER_SIZE);
126
-
127
- parser->read_method = detect_read_method(io);
128
- parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
129
- parser->body_left = 0;
130
- return self;
131
- }
132
-
133
- ////////////////////////////////////////////////////////////////////////////////
134
-
135
- #define str_downcase(str) (rb_funcall((str), ID_downcase, 0))
136
-
137
- #define FILL_BUFFER_OR_GOTO_EOF(state) { if (!fill_buffer(state)) goto eof; }
138
-
139
- #define BUFFER_POS(state) ((state)->parser->pos)
140
- #define BUFFER_LEN(state) ((state)->len)
141
- #define BUFFER_CUR(state) ((state)->ptr[(state)->parser->pos])
142
- #define BUFFER_AT(state, pos) ((state)->ptr[pos])
143
- #define BUFFER_PTR(state, pos) ((state)->ptr + pos)
144
- #define BUFFER_STR(state, pos, len) (rb_utf8_str_new((state)->ptr + pos, len))
145
-
146
- #define INC_BUFFER_POS(state) { \
147
- BUFFER_POS(state)++; \
148
- if (BUFFER_POS(state) == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state); \
149
- }
150
-
151
- #define INC_BUFFER_POS_NO_FILL(state) BUFFER_POS(state)++;
152
-
153
- #define INC_BUFFER_POS_UTF8(state, len) { \
154
- unsigned char c = BUFFER_CUR(state); \
155
- if ((c & 0xf0) == 0xf0) { \
156
- while (BUFFER_LEN(state) - BUFFER_POS(state) < 4) FILL_BUFFER_OR_GOTO_EOF(state); \
157
- BUFFER_POS(state) += 4; \
158
- len += 4; \
159
- } \
160
- else if ((c & 0xe0) == 0xe0) { \
161
- while (BUFFER_LEN(state) - BUFFER_POS(state) < 3) FILL_BUFFER_OR_GOTO_EOF(state); \
162
- BUFFER_POS(state) += 3; \
163
- len += 3; \
164
- } \
165
- else if ((c & 0xc0) == 0xc0) { \
166
- while (BUFFER_LEN(state) - BUFFER_POS(state) < 2) FILL_BUFFER_OR_GOTO_EOF(state); \
167
- BUFFER_POS(state) += 2; \
168
- len += 2; \
169
- } \
170
- else { \
171
- BUFFER_POS(state)++; \
172
- len ++; \
173
- if (BUFFER_POS(state) == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state); \
174
- } \
175
- }
176
-
177
- #define INIT_PARSER_STATE(state) { \
178
- (state)->len = RSTRING_LEN((state)->parser->buffer); \
179
- if (BUFFER_POS(state) == BUFFER_LEN(state)) \
180
- FILL_BUFFER_OR_GOTO_EOF(state) \
181
- else \
182
- (state)->ptr = RSTRING_PTR((state)->parser->buffer); \
183
- }
184
-
185
- #define RAISE_BAD_REQUEST(msg) rb_raise(cError, msg)
186
-
187
- #define SET_HEADER_VALUE_FROM_BUFFER(state, headers, key, pos, len) { \
188
- VALUE value = BUFFER_STR(state, pos, len); \
189
- rb_hash_aset(headers, key, value); \
190
- RB_GC_GUARD(value); \
191
- }
192
-
193
- #define SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(state, headers, key, pos, len) { \
194
- VALUE value = str_downcase(BUFFER_STR(state, pos, len)); \
195
- rb_hash_aset(headers, key, value); \
196
- RB_GC_GUARD(value); \
197
- }
198
-
199
- #define CONSUME_CRLF(state) { \
200
- INC_BUFFER_POS(state); \
201
- if (BUFFER_CUR(state) != '\n') goto bad_request; \
202
- INC_BUFFER_POS(state); \
203
- }
204
-
205
- #define CONSUME_CRLF_NO_FILL(state) { \
206
- INC_BUFFER_POS(state); \
207
- if (BUFFER_CUR(state) != '\n') goto bad_request; \
208
- INC_BUFFER_POS_NO_FILL(state); \
209
- }
210
-
211
- #define GLOBAL_STR(v, s) v = rb_str_new_literal(s); rb_global_variable(&v)
212
-
213
- struct parser_state {
214
- struct parser *parser;
215
- char *ptr;
216
- int len;
217
- };
218
-
219
- ////////////////////////////////////////////////////////////////////////////////
220
-
221
- static inline VALUE io_read_call(VALUE io, VALUE maxlen, VALUE buf, VALUE buf_pos) {
222
- VALUE result = rb_funcall(io, ID_call, 1, maxlen);
223
- if (result == Qnil) return Qnil;
224
-
225
- if (buf_pos == NUM_buffer_start) rb_str_set_len(buf, 0);
226
- rb_str_append(buf, result);
227
- RB_GC_GUARD(result);
228
- return buf;
229
- }
230
-
231
- static inline VALUE parser_io_read(Parser_t *parser, VALUE maxlen, VALUE buf, VALUE buf_pos) {
232
- switch (parser->read_method) {
233
- case method_backend_read:
234
- return rb_funcall(mPolyphony, ID_backend_read, 5, parser->io, buf, maxlen, Qfalse, buf_pos);
235
- case method_backend_recv:
236
- return rb_funcall(mPolyphony, ID_backend_recv, 4, parser->io, buf, maxlen, buf_pos);
237
- case method_readpartial:
238
- return rb_funcall(parser->io, ID_readpartial, 4, maxlen, buf, buf_pos, Qfalse);
239
- case method_call:
240
- return io_read_call(parser->io, maxlen, buf, buf_pos);
241
- default:
242
- return Qnil;
243
- }
244
- }
245
-
246
- static inline int fill_buffer(struct parser_state *state) {
247
- VALUE ret = parser_io_read(state->parser, NUM_max_headers_read_length, state->parser->buffer, NUM_buffer_end);
248
- if (ret == Qnil) return 0;
249
-
250
- state->parser->buffer = ret;
251
- int len = RSTRING_LEN(state->parser->buffer);
252
- int read_bytes = len - state->len;
253
- if (!read_bytes) return 0;
254
-
255
- state->ptr = RSTRING_PTR(state->parser->buffer);
256
- state->len = len;
257
- return read_bytes;
258
- }
259
-
260
- static inline void buffer_trim(struct parser_state *state) {
261
- int len = RSTRING_LEN(state->parser->buffer);
262
- int pos = state->parser->pos;
263
- int left = len - pos;
264
-
265
- // The buffer is trimmed only if length and position thresholds are passed,
266
- // *and* position is past the halfway point.
267
- if (len < BUFFER_TRIM_MIN_LEN ||
268
- pos < BUFFER_TRIM_MIN_POS ||
269
- left >= pos) return;
270
-
271
- if (left > 0) {
272
- char *ptr = RSTRING_PTR(state->parser->buffer);
273
- memcpy(ptr, ptr + pos, left);
274
- }
275
- rb_str_set_len(state->parser->buffer, left);
276
- state->parser->pos = 0;
277
- }
278
-
279
- static inline void str_append_from_buffer(VALUE str, char *ptr, int len) {
280
- int str_len = RSTRING_LEN(str);
281
- rb_str_modify_expand(str, len);
282
- memcpy(RSTRING_PTR(str) + str_len, ptr, len);
283
- rb_str_set_len(str, str_len + len);
284
- }
285
-
286
- ////////////////////////////////////////////////////////////////////////////////
287
-
288
- static inline int parse_method(struct parser_state *state, VALUE headers) {
289
- int pos = BUFFER_POS(state);
290
- int len = 0;
291
-
292
- while (1) {
293
- switch (BUFFER_CUR(state)) {
294
- case ' ':
295
- if (len < 1 || len > MAX_METHOD_LENGTH) goto bad_request;
296
- INC_BUFFER_POS(state);
297
- goto done;
298
- case '\r':
299
- case '\n':
300
- goto bad_request;
301
- default:
302
- INC_BUFFER_POS(state);
303
- len++;
304
- // INC_BUFFER_POS_UTF8(state, len);
305
- if (len > MAX_METHOD_LENGTH) goto bad_request;
306
- }
307
- }
308
- done:
309
- SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(state, headers, STR_pseudo_method, pos, len);
310
- return 1;
311
- bad_request:
312
- RAISE_BAD_REQUEST("Invalid method");
313
- eof:
314
- return 0;
315
- }
316
-
317
- static int parse_request_target(struct parser_state *state, VALUE headers) {
318
- while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
319
- int pos = BUFFER_POS(state);
320
- int len = 0;
321
- while (1) {
322
- switch (BUFFER_CUR(state)) {
323
- case ' ':
324
- if (len < 1 || len > MAX_PATH_LENGTH) goto bad_request;
325
- INC_BUFFER_POS(state);
326
- goto done;
327
- case '\r':
328
- case '\n':
329
- goto bad_request;
330
- default:
331
- INC_BUFFER_POS(state);
332
- len++;
333
- // INC_BUFFER_POS_UTF8(state, len);
334
- if (len > MAX_PATH_LENGTH) goto bad_request;
335
- }
336
- }
337
- done:
338
- SET_HEADER_VALUE_FROM_BUFFER(state, headers, STR_pseudo_path, pos, len);
339
- return 1;
340
- bad_request:
341
- RAISE_BAD_REQUEST("Invalid request target");
342
- eof:
343
- return 0;
344
- }
345
-
346
- // case-insensitive compare
347
- #define CMP_CI(state, down, up) ((BUFFER_CUR(state) == down) || (BUFFER_CUR(state) == up))
348
-
349
- static int parse_protocol(struct parser_state *state, VALUE headers) {
350
- while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
351
- int pos = BUFFER_POS(state);
352
- int len = 0;
353
-
354
- if (CMP_CI(state, 'H', 'h')) INC_BUFFER_POS(state) else goto bad_request;
355
- if (CMP_CI(state, 'T', 't')) INC_BUFFER_POS(state) else goto bad_request;
356
- if (CMP_CI(state, 'T', 't')) INC_BUFFER_POS(state) else goto bad_request;
357
- if (CMP_CI(state, 'P', 'p')) INC_BUFFER_POS(state) else goto bad_request;
358
- if (BUFFER_CUR(state) == '/') INC_BUFFER_POS(state) else goto bad_request;
359
- if (BUFFER_CUR(state) == '1') INC_BUFFER_POS(state) else goto bad_request;
360
- len = 6;
361
- while (1) {
362
- switch (BUFFER_CUR(state)) {
363
- case '\r':
364
- CONSUME_CRLF(state);
365
- goto done;
366
- case '\n':
367
- INC_BUFFER_POS(state);
368
- goto done;
369
- case '.':
370
- INC_BUFFER_POS(state);
371
- char c = BUFFER_CUR(state);
372
- if (c == '0' || c == '1') {
373
- INC_BUFFER_POS(state);
374
- len += 2;
375
- continue;
376
- }
377
- goto bad_request;
378
- default:
379
- goto bad_request;
380
- }
381
- }
382
- done:
383
- if (len < 6 || len > 8) goto bad_request;
384
- SET_HEADER_DOWNCASE_VALUE_FROM_BUFFER(state, headers, STR_pseudo_protocol, pos, len);
385
- return 1;
386
- bad_request:
387
- RAISE_BAD_REQUEST("Invalid protocol");
388
- eof:
389
- return 0;
390
- }
391
-
392
- int parse_request_line(struct parser_state *state, VALUE headers) {
393
- if (!parse_method(state, headers)) goto eof;
394
- if (!parse_request_target(state, headers)) goto eof;
395
- if (!parse_protocol(state, headers)) goto eof;
396
-
397
- return 1;
398
- eof:
399
- return 0;
400
- }
401
-
402
- static inline int parse_header_key(struct parser_state *state, VALUE *key) {
403
- int pos = BUFFER_POS(state);
404
- int len = 0;
405
-
406
- while (1) {
407
- switch (BUFFER_CUR(state)) {
408
- case ' ':
409
- goto bad_request;
410
- case ':':
411
- if (len < 1 || len > MAX_HEADER_KEY_LENGTH)
412
- goto bad_request;
413
- INC_BUFFER_POS(state);
414
- goto done;
415
- case '\r':
416
- if (BUFFER_POS(state) > pos) goto bad_request;
417
- CONSUME_CRLF_NO_FILL(state);
418
- goto done;
419
- case '\n':
420
- if (BUFFER_POS(state) > pos) goto bad_request;
421
-
422
- INC_BUFFER_POS_NO_FILL(state);
423
- goto done;
424
- default:
425
- INC_BUFFER_POS(state);
426
- len++;
427
- // INC_BUFFER_POS_UTF8(state, len);
428
- if (len > MAX_HEADER_KEY_LENGTH) goto bad_request;
429
- }
430
- }
431
- done:
432
- if (len == 0) return -1;
433
- (*key) = str_downcase(BUFFER_STR(state, pos, len));
434
- return 1;
435
- bad_request:
436
- RAISE_BAD_REQUEST("Invalid header key");
437
- eof:
438
- return 0;
439
- }
440
-
441
- static inline int parse_header_value(struct parser_state *state, VALUE *value) {
442
- while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
443
-
444
- int pos = BUFFER_POS(state);
445
- int len = 0;
446
-
447
- while (1) {
448
- switch (BUFFER_CUR(state)) {
449
- case '\r':
450
- CONSUME_CRLF(state);
451
- goto done;
452
- case '\n':
453
- INC_BUFFER_POS(state);
454
- goto done;
455
- default:
456
- INC_BUFFER_POS_UTF8(state, len);
457
- if (len > MAX_HEADER_VALUE_LENGTH) goto bad_request;
458
- }
459
- }
460
- done:
461
- if (len < 1 || len > MAX_HEADER_VALUE_LENGTH) goto bad_request;
462
- (*value) = BUFFER_STR(state, pos, len);
463
- return 1;
464
- bad_request:
465
- RAISE_BAD_REQUEST("Invalid header value");
466
- eof:
467
- return 0;
468
- }
469
-
470
- static inline int parse_header(struct parser_state *state, VALUE headers) {
471
- VALUE key, value;
472
-
473
- switch (parse_header_key(state, &key)) {
474
- case -1: return -1;
475
- case 0: goto eof;
476
- }
477
-
478
- if (!parse_header_value(state, &value)) goto eof;
479
-
480
- VALUE existing = rb_hash_aref(headers, key);
481
- if (existing != Qnil) {
482
- if (TYPE(existing) != T_ARRAY) {
483
- existing = rb_ary_new3(2, existing, value);
484
- rb_hash_aset(headers, key, existing);
485
- }
486
- else
487
- rb_ary_push(existing, value);
488
- }
489
- else
490
- rb_hash_aset(headers, key, value);
491
-
492
- RB_GC_GUARD(existing);
493
- RB_GC_GUARD(key);
494
- RB_GC_GUARD(value);
495
- return 1;
496
- eof:
497
- return 0;
498
- }
499
-
500
- VALUE Parser_parse_headers(VALUE self) {
501
- struct parser_state state;
502
- GetParser(self, state.parser);
503
- state.parser->headers = rb_hash_new();
504
-
505
- buffer_trim(&state);
506
- int initial_pos = state.parser->pos;
507
- INIT_PARSER_STATE(&state);
508
- state.parser->current_request_rx = 0;
509
-
510
- if (!parse_request_line(&state, state.parser->headers)) goto eof;
511
-
512
- int header_count = 0;
513
- while (1) {
514
- if (header_count > MAX_HEADER_COUNT) RAISE_BAD_REQUEST("Too many headers");
515
- switch (parse_header(&state, state.parser->headers)) {
516
- case -1: goto done; // empty header => end of headers
517
- case 0: goto eof;
518
- }
519
- header_count++;
520
- }
521
- eof:
522
- state.parser->headers = Qnil;
523
- done:
524
- state.parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
525
- int read_bytes = BUFFER_POS(&state) - initial_pos;
526
-
527
- state.parser->current_request_rx += read_bytes;
528
- if (state.parser->headers != Qnil)
529
- rb_hash_aset(state.parser->headers, STR_pseudo_rx, INT2NUM(read_bytes));
530
- return state.parser->headers;
531
- }
532
-
533
- ////////////////////////////////////////////////////////////////////////////////
534
-
535
- static inline int str_to_int(VALUE value, const char *error_msg) {
536
- char *ptr = RSTRING_PTR(value);
537
- int len = RSTRING_LEN(value);
538
- int int_value = 0;
539
-
540
- while (len) {
541
- char c = *ptr;
542
- if ((c >= '0') && (c <= '9'))
543
- int_value = int_value * 10 + (c - '0');
544
- else
545
- RAISE_BAD_REQUEST(error_msg);
546
- len--;
547
- ptr++;
548
- }
549
-
550
- return int_value;
551
- }
552
-
553
- VALUE read_body_with_content_length(Parser_t *parser, int read_entire_body, int buffered_only) {
554
- if (parser->body_left <= 0) return Qnil;
555
-
556
- VALUE body = Qnil;
557
-
558
- int len = RSTRING_LEN(parser->buffer);
559
- int pos = parser->pos;
560
-
561
- if (pos < len) {
562
- int available = len - pos;
563
- if (available > parser->body_left) available = parser->body_left;
564
- body = rb_str_new(RSTRING_PTR(parser->buffer) + pos, available);
565
- parser->pos += available;
566
- parser->current_request_rx += available;
567
- parser->body_left -= available;
568
- if (!parser->body_left) parser->request_completed = 1;
569
- }
570
- else {
571
- body = Qnil;
572
- len = 0;
573
- }
574
- if (buffered_only) return body;
575
-
576
- while (parser->body_left) {
577
- int maxlen = parser->body_left <= MAX_BODY_READ_LENGTH ? parser->body_left : MAX_BODY_READ_LENGTH;
578
- VALUE tmp_buf = parser_io_read(parser, INT2NUM(maxlen), Qnil, NUM_buffer_start);
579
- if (tmp_buf == Qnil) goto eof;
580
- if (body != Qnil)
581
- rb_str_append(body, tmp_buf);
582
- else
583
- body = tmp_buf;
584
- int read_bytes = RSTRING_LEN(tmp_buf);
585
- parser->current_request_rx += read_bytes;
586
- parser->body_left -= read_bytes;
587
- if (!parser->body_left) parser->request_completed = 1;
588
- RB_GC_GUARD(tmp_buf);
589
- if (!read_entire_body) goto done;
590
- }
591
- done:
592
- rb_hash_aset(parser->headers, STR_pseudo_rx, INT2NUM(parser->current_request_rx));
593
- RB_GC_GUARD(body);
594
- return body;
595
- eof:
596
- RAISE_BAD_REQUEST("Incomplete body");
597
- }
598
-
599
- int chunked_encoding_p(VALUE transfer_encoding) {
600
- if (transfer_encoding == Qnil) return 0;
601
- return rb_funcall(str_downcase(transfer_encoding), ID_eq, 1, STR_chunked) == Qtrue;
602
- }
603
-
604
- int parse_chunk_size(struct parser_state *state, int *chunk_size) {
605
- int len = 0;
606
- int value = 0;
607
- int initial_pos = BUFFER_POS(state);
608
-
609
- while (1) {
610
- char c = BUFFER_CUR(state);
611
- if ((c >= '0') && (c <= '9')) value = (value << 4) + (c - '0');
612
- else if ((c >= 'a') && (c <= 'f')) value = (value << 4) + (c - 'a' + 10);
613
- else if ((c >= 'A') && (c <= 'F')) value = (value << 4) + (c - 'A' + 10);
614
- else switch (c) {
615
- case '\r':
616
- CONSUME_CRLF_NO_FILL(state);
617
- goto done;
618
- case '\n':
619
- INC_BUFFER_POS_NO_FILL(state);
620
- goto done;
621
- default:
622
- goto bad_request;
623
- }
624
- INC_BUFFER_POS(state);
625
- len++;
626
- if (len >= MAX_CHUNKED_ENCODING_CHUNK_SIZE_LENGTH) goto bad_request;
627
- }
628
- done:
629
- if (len == 0) goto bad_request;
630
- (*chunk_size) = value;
631
- state->parser->current_request_rx += BUFFER_POS(state) - initial_pos;
632
- return 1;
633
- bad_request:
634
- RAISE_BAD_REQUEST("Invalid chunk size");
635
- eof:
636
- return 0;
637
- }
638
-
639
- int read_body_chunk_with_chunked_encoding(struct parser_state *state, VALUE *body, int chunk_size, int buffered_only) {
640
- int len = RSTRING_LEN(state->parser->buffer);
641
- int pos = state->parser->pos;
642
- int left = chunk_size;
643
-
644
- if (pos < len) {
645
- int available = len - pos;
646
- if (available > left) available = left;
647
- if (*body != Qnil)
648
- str_append_from_buffer(*body, RSTRING_PTR(state->parser->buffer) + pos, available);
649
- else
650
- *body = rb_str_new(RSTRING_PTR(state->parser->buffer) + pos, available);
651
- state->parser->pos += available;
652
- state->parser->current_request_rx += available;
653
- left -= available;
654
- }
655
- if (buffered_only) return 1;
656
-
657
- while (left) {
658
- int maxlen = left <= MAX_BODY_READ_LENGTH ? left : MAX_BODY_READ_LENGTH;
659
-
660
- VALUE tmp_buf = parser_io_read(state->parser, INT2NUM(maxlen), Qnil, NUM_buffer_start);
661
- if (tmp_buf == Qnil) goto eof;
662
- if (*body != Qnil)
663
- rb_str_append(*body, tmp_buf);
664
- else
665
- *body = tmp_buf;
666
- int read_bytes = RSTRING_LEN(tmp_buf);
667
- state->parser->current_request_rx += read_bytes;
668
- left -= read_bytes;
669
- RB_GC_GUARD(tmp_buf);
670
- }
671
- return 1;
672
- eof:
673
- return 0;
674
- }
675
-
676
- static inline int parse_chunk_postfix(struct parser_state *state) {
677
- int initial_pos = BUFFER_POS(state);
678
- if (initial_pos == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state);
679
- switch (BUFFER_CUR(state)) {
680
- case '\r':
681
- CONSUME_CRLF_NO_FILL(state);
682
- goto done;
683
- case '\n':
684
- INC_BUFFER_POS_NO_FILL(state);
685
- goto done;
686
- default:
687
- goto bad_request;
688
- }
689
- done:
690
- state->parser->current_request_rx += BUFFER_POS(state) - initial_pos;
691
- return 1;
692
- bad_request:
693
- RAISE_BAD_REQUEST("Invalid protocol");
694
- eof:
695
- return 0;
696
- }
697
-
698
- VALUE read_body_with_chunked_encoding(Parser_t *parser, int read_entire_body, int buffered_only) {
699
- struct parser_state state;
700
- state.parser = parser;
701
- buffer_trim(&state);
702
- INIT_PARSER_STATE(&state);
703
- VALUE body = Qnil;
704
-
705
- while (1) {
706
- int chunk_size = 0;
707
- if (BUFFER_POS(&state) == BUFFER_LEN(&state)) FILL_BUFFER_OR_GOTO_EOF(&state);
708
- if (!parse_chunk_size(&state, &chunk_size)) goto bad_request;
709
-
710
- if (chunk_size) {
711
- if (!read_body_chunk_with_chunked_encoding(&state, &body, chunk_size, buffered_only)) goto bad_request;
712
- }
713
- else parser->request_completed = 1;
714
-
715
- if (!parse_chunk_postfix(&state)) goto bad_request;
716
- if (!chunk_size || !read_entire_body) goto done;
717
- }
718
- bad_request:
719
- RAISE_BAD_REQUEST("Malformed request body");
720
- eof:
721
- RAISE_BAD_REQUEST("Incomplete request body");
722
- done:
723
- rb_hash_aset(parser->headers, STR_pseudo_rx, INT2NUM(state.parser->current_request_rx));
724
- RB_GC_GUARD(body);
725
- return body;
726
- }
727
-
728
- static inline void detect_body_read_mode(Parser_t *parser) {
729
- VALUE content_length = rb_hash_aref(parser->headers, STR_content_length);
730
- if (content_length != Qnil) {
731
- int int_content_length = str_to_int(content_length, "Invalid content length");
732
- if (int_content_length < 0) RAISE_BAD_REQUEST("Invalid body content length");
733
- parser->body_read_mode = parser->body_left = int_content_length;
734
- parser->request_completed = 0;
735
- return;
736
- }
737
-
738
- VALUE transfer_encoding = rb_hash_aref(parser->headers, STR_transfer_encoding);
739
- if (chunked_encoding_p(transfer_encoding)) {
740
- parser->body_read_mode = BODY_READ_MODE_CHUNKED;
741
- parser->request_completed = 0;
742
- return;
743
- }
744
- parser->request_completed = 1;
745
-
746
- }
747
-
748
- static inline VALUE read_body(VALUE self, int read_entire_body, int buffered_only) {
749
- Parser_t *parser;
750
- GetParser(self, parser);
751
-
752
- if (parser->body_read_mode == BODY_READ_MODE_UNKNOWN)
753
- detect_body_read_mode(parser);
754
-
755
- if (parser->body_read_mode == BODY_READ_MODE_CHUNKED)
756
- return read_body_with_chunked_encoding(parser, read_entire_body, buffered_only);
757
- return read_body_with_content_length(parser, read_entire_body, buffered_only);
758
- }
759
-
760
- VALUE Parser_read_body(VALUE self) {
761
- return read_body(self, 1, 0);
762
- }
763
-
764
- VALUE Parser_read_body_chunk(VALUE self, VALUE buffered_only) {
765
- return read_body(self, 0, buffered_only == Qtrue);
766
- }
767
-
768
- VALUE Parser_complete_p(VALUE self) {
769
- Parser_t *parser;
770
- GetParser(self, parser);
771
-
772
- if (parser->body_read_mode == BODY_READ_MODE_UNKNOWN)
773
- detect_body_read_mode(parser);
774
-
775
- return parser->request_completed ? Qtrue : Qfalse;
776
- }
777
-
778
- void Init_HTTP1_Parser() {
779
- VALUE mTipi;
780
- VALUE cHTTP1Parser;
781
-
782
- mTipi = rb_define_module("Tipi");
783
- cHTTP1Parser = rb_define_class_under(mTipi, "HTTP1Parser", rb_cObject);
784
- rb_define_alloc_func(cHTTP1Parser, Parser_allocate);
785
-
786
- cError = rb_define_class_under(cHTTP1Parser, "Error", rb_eRuntimeError);
787
-
788
- // backend methods
789
- rb_define_method(cHTTP1Parser, "initialize", Parser_initialize, 1);
790
- rb_define_method(cHTTP1Parser, "parse_headers", Parser_parse_headers, 0);
791
- rb_define_method(cHTTP1Parser, "read_body", Parser_read_body, 0);
792
- rb_define_method(cHTTP1Parser, "read_body_chunk", Parser_read_body_chunk, 1);
793
- rb_define_method(cHTTP1Parser, "complete?", Parser_complete_p, 0);
794
-
795
- ID_arity = rb_intern("arity");
796
- ID_backend_read = rb_intern("backend_read");
797
- ID_backend_recv = rb_intern("backend_recv");
798
- ID_call = rb_intern("call");
799
- ID_downcase = rb_intern("downcase");
800
- ID_eq = rb_intern("==");
801
- ID_parser_read_method = rb_intern("__parser_read_method__");
802
- ID_read = rb_intern("read");
803
- ID_readpartial = rb_intern("readpartial");
804
- ID_to_i = rb_intern("to_i");
805
-
806
- NUM_max_headers_read_length = INT2NUM(MAX_HEADERS_READ_LENGTH);
807
- NUM_buffer_start = INT2NUM(0);
808
- NUM_buffer_end = INT2NUM(-1);
809
-
810
- GLOBAL_STR(STR_pseudo_method, ":method");
811
- GLOBAL_STR(STR_pseudo_path, ":path");
812
- GLOBAL_STR(STR_pseudo_protocol, ":protocol");
813
- GLOBAL_STR(STR_pseudo_rx, ":rx");
814
-
815
- GLOBAL_STR(STR_chunked, "chunked");
816
- GLOBAL_STR(STR_content_length, "content-length");
817
- GLOBAL_STR(STR_transfer_encoding, "transfer-encoding");
818
-
819
- SYM_backend_read = ID2SYM(ID_backend_read);
820
- SYM_backend_recv = ID2SYM(ID_backend_recv);
821
-
822
- rb_global_variable(&mTipi);
823
- }