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.
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 ID_parser_read_method;
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
- method_readpartial, // receiver.readpartial(len, buf, pos, raise_on_eof: false) (Polyphony-specific)
51
- method_backend_read, // Polyphony.backend_read (Polyphony-specific)
52
- method_backend_recv, // Polyphony.backend_recv (Polyphony-specific)
53
- method_call, // receiver.call(len) (Universal)
54
- method_stock_readpartial // receiver.readpartial(len)
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 void get_polyphony() {
104
- if (mPolyphony != Qnil) return;
105
-
106
- mPolyphony = rb_const_get(rb_cObject, rb_intern("Polyphony"));
107
- rb_gc_register_mark_object(mPolyphony);
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, ID_parser_read_method)) {
112
- VALUE method = rb_funcall(io, ID_parser_read_method, 0);
113
- if (method == SYM_stock_readpartial) return method_stock_readpartial;
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
- get_polyphony();
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 method_call;
147
+ return RM_CALL;
123
148
  }
124
149
  else
125
- rb_raise(rb_eRuntimeError, "Provided reader should be a callable or respond to #__parser_read_method__");
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(state) { if (!fill_buffer(state)) goto eof; }
197
+ #define FILL_BUFFER_OR_GOTO_EOF(parser) { if (!fill_buffer(parser)) goto eof; }
152
198
 
153
- #define BUFFER_POS(state) ((state)->parser->pos)
154
- #define BUFFER_LEN(state) ((state)->len)
155
- #define BUFFER_CUR(state) ((state)->ptr[(state)->parser->pos])
156
- #define BUFFER_AT(state, pos) ((state)->ptr[pos])
157
- #define BUFFER_PTR(state, pos) ((state)->ptr + pos)
158
- #define BUFFER_STR(state, pos, len) (rb_obj_freeze(rb_utf8_str_new((state)->ptr + pos, len)))
159
- #define BUFFER_STR_DOWNCASE(state, pos, len) (rb_obj_freeze(str_downcase(rb_utf8_str_new((state)->ptr + pos, len))))
160
- #define BUFFER_STR_UPCASE(state, pos, len) (rb_obj_freeze(str_upcase(rb_utf8_str_new((state)->ptr + pos, len))))
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(state) { \
163
- BUFFER_POS(state)++; \
164
- if (BUFFER_POS(state) == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state); \
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(state) BUFFER_POS(state)++;
213
+ #define INC_BUFFER_POS_NO_FILL(parser) BUFFER_POS(parser)++;
168
214
 
169
- #define INC_BUFFER_POS_UTF8(state, len) { \
170
- unsigned char c = BUFFER_CUR(state); \
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(state) - BUFFER_POS(state) < 4) FILL_BUFFER_OR_GOTO_EOF(state); \
173
- BUFFER_POS(state) += 4; \
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(state) - BUFFER_POS(state) < 3) FILL_BUFFER_OR_GOTO_EOF(state); \
178
- BUFFER_POS(state) += 3; \
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(state) - BUFFER_POS(state) < 2) FILL_BUFFER_OR_GOTO_EOF(state); \
183
- BUFFER_POS(state) += 2; \
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(state)++; \
233
+ BUFFER_POS(parser)++; \
188
234
  len ++; \
189
- if (BUFFER_POS(state) == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state); \
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(state) { \
194
- (state)->len = RSTRING_LEN((state)->parser->buffer); \
195
- if (BUFFER_POS(state) == BUFFER_LEN(state)) \
196
- FILL_BUFFER_OR_GOTO_EOF(state) \
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
- (state)->ptr = RSTRING_PTR((state)->parser->buffer); \
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(state, headers, key, pos, len) { \
204
- VALUE value = BUFFER_STR(state, pos, len); \
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(state, headers, key, pos, len) { \
210
- VALUE value = BUFFER_STR_DOWNCASE(state, pos, len); \
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(state, headers, key, pos, len) { \
216
- VALUE value = BUFFER_STR_UPCASE(state, pos, len); \
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 CONSUME_CRLF(state) { \
222
- INC_BUFFER_POS(state); \
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 CONSUME_CRLF_NO_FILL(state) { \
228
- INC_BUFFER_POS(state); \
229
- if (BUFFER_CUR(state) != '\n') goto bad_request; \
230
- INC_BUFFER_POS_NO_FILL(state); \
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
- struct parser_state {
236
- struct parser *parser;
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 method_backend_read:
270
- return rb_funcall(mPolyphony, ID_backend_read, 5, parser->io, buf, maxlen, Qfalse, buf_pos);
271
- case method_backend_recv:
272
- return rb_funcall(mPolyphony, ID_backend_recv, 4, parser->io, buf, maxlen, buf_pos);
273
- case method_readpartial:
274
- return rb_funcall(parser-> io, ID_readpartial, 4, maxlen, buf, buf_pos, Qfalse);
275
- case method_call:
276
- return io_call(parser ->io, maxlen, buf, buf_pos);
277
- case method_stock_readpartial:
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 int fill_buffer(struct parser_state *state) {
285
- VALUE ret = parser_io_read(state->parser, NUM_max_headers_read_length, state->parser->buffer, NUM_buffer_end);
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
- state->parser->buffer = ret;
289
- int len = RSTRING_LEN(state->parser->buffer);
290
- int read_bytes = len - state->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
- state->ptr = RSTRING_PTR(state->parser->buffer);
294
- state->len = len;
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(struct parser_state *state) {
299
- int len = RSTRING_LEN(state->parser->buffer);
300
- int pos = state->parser->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(state->parser->buffer);
373
+ char *ptr = RSTRING_PTR(parser->buffer);
311
374
  memcpy(ptr, ptr + pos, left);
312
375
  }
313
- rb_str_set_len(state->parser->buffer, left);
314
- state->parser->pos = 0;
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 parse_method(struct parser_state *state, VALUE headers) {
327
- int pos = BUFFER_POS(state);
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(state)) {
394
+ switch (BUFFER_CUR(parser)) {
332
395
  case ' ':
333
396
  if (len < 1 || len > MAX_METHOD_LENGTH) goto bad_request;
334
- INC_BUFFER_POS(state);
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(state);
403
+ INC_BUFFER_POS(parser);
341
404
  len++;
342
- // INC_BUFFER_POS_UTF8(state, len);
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(state, headers, STR_pseudo_method, pos, len);
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 parse_request_target(struct parser_state *state, VALUE headers) {
356
- while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
357
- int pos = BUFFER_POS(state);
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(state)) {
423
+ switch (BUFFER_CUR(parser)) {
361
424
  case ' ':
362
425
  if (len < 1 || len > MAX_PATH_LENGTH) goto bad_request;
363
- INC_BUFFER_POS(state);
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(state);
432
+ INC_BUFFER_POS(parser);
370
433
  len++;
371
- // INC_BUFFER_POS_UTF8(state, len);
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(state, headers, STR_pseudo_path, pos, len);
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
- // case-insensitive compare
385
- #define CMP_CI(state, down, up) ((BUFFER_CUR(state) == down) || (BUFFER_CUR(state) == up))
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(state, 'H', 'h')) INC_BUFFER_POS(state) else goto bad_request;
393
- if (CMP_CI(state, 'T', 't')) INC_BUFFER_POS(state) else goto bad_request;
394
- if (CMP_CI(state, 'T', 't')) INC_BUFFER_POS(state) else goto bad_request;
395
- if (CMP_CI(state, 'P', 'p')) INC_BUFFER_POS(state) else goto bad_request;
396
- if (BUFFER_CUR(state) == '/') INC_BUFFER_POS(state) else goto bad_request;
397
- if (BUFFER_CUR(state) == '1') INC_BUFFER_POS(state) else goto bad_request;
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(state)) {
460
+ switch (BUFFER_CUR(parser)) {
401
461
  case '\r':
402
- CONSUME_CRLF(state);
462
+ CONSUME_CRLF(parser);
403
463
  goto done;
404
464
  case '\n':
405
- INC_BUFFER_POS(state);
465
+ INC_BUFFER_POS(parser);
406
466
  goto done;
407
467
  case '.':
408
- INC_BUFFER_POS(state);
409
- char c = BUFFER_CUR(state);
468
+ INC_BUFFER_POS(parser);
469
+ char c = BUFFER_CUR(parser);
410
470
  if (c == '0' || c == '1') {
411
- INC_BUFFER_POS(state);
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(state, headers, STR_pseudo_protocol, pos, len);
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(struct parser_state *state, VALUE headers) {
431
- if (!parse_method(state, headers)) goto eof;
432
- if (!parse_request_target(state, headers)) goto eof;
433
- if (!parse_protocol(state, headers)) goto eof;
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 parse_header_key(struct parser_state *state, VALUE *key) {
441
- int pos = BUFFER_POS(state);
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(state)) {
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(state);
622
+ INC_BUFFER_POS(parser);
452
623
  goto done;
453
624
  case '\r':
454
- if (BUFFER_POS(state) > pos) goto bad_request;
455
- CONSUME_CRLF_NO_FILL(state);
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(state) > pos) goto bad_request;
629
+ if (BUFFER_POS(parser) > pos) goto bad_request;
459
630
 
460
- INC_BUFFER_POS_NO_FILL(state);
631
+ INC_BUFFER_POS_NO_FILL(parser);
461
632
  goto done;
462
633
  default:
463
- INC_BUFFER_POS(state);
634
+ INC_BUFFER_POS(parser);
464
635
  len++;
465
- // INC_BUFFER_POS_UTF8(state, len);
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(state, pos, len);
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(struct parser_state *state, VALUE *value) {
480
- while (BUFFER_CUR(state) == ' ') INC_BUFFER_POS(state);
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(state);
653
+ int pos = BUFFER_POS(parser);
483
654
  int len = 0;
484
655
 
485
656
  while (1) {
486
- switch (BUFFER_CUR(state)) {
657
+ switch (BUFFER_CUR(parser)) {
487
658
  case '\r':
488
- CONSUME_CRLF(state);
659
+ CONSUME_CRLF(parser);
489
660
  goto done;
490
661
  case '\n':
491
- INC_BUFFER_POS(state);
662
+ INC_BUFFER_POS(parser);
492
663
  goto done;
493
664
  default:
494
- INC_BUFFER_POS_UTF8(state, len);
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(state, pos, len);
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(struct parser_state *state, VALUE headers) {
679
+ static inline int parse_header(Parser_t *parser) {
509
680
  VALUE key, value;
510
681
 
511
- switch (parse_header_key(state, &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(state, &value)) goto eof;
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
- struct parser_state state;
540
- GetParser(self, state.parser);
541
- state.parser->headers = rb_hash_new();
710
+ Parser_t *parser;
711
+ GetParser(self, parser);
712
+ parser->headers = rb_hash_new();
542
713
 
543
- buffer_trim(&state);
544
- int initial_pos = state.parser->pos;
545
- INIT_PARSER_STATE(&state);
546
- state.parser->current_request_rx = 0;
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 (!parse_request_line(&state, state.parser->headers)) goto eof;
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(&state, state.parser->headers)) {
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
- state.parser->headers = Qnil;
736
+ parser->headers = Qnil;
561
737
  done:
562
- state.parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
563
- int read_bytes = BUFFER_POS(&state) - initial_pos;
738
+ parser->body_read_mode = BODY_READ_MODE_UNKNOWN;
739
+ int read_bytes = BUFFER_POS(parser) - initial_pos;
564
740
 
565
- state.parser->current_request_rx += read_bytes;
566
- if (state.parser->headers != Qnil)
567
- rb_hash_aset(state.parser->headers, STR_pseudo_rx, INT2NUM(read_bytes));
568
- return state.parser->headers;
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->pos;
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->pos += available;
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, INT2NUM(maxlen), Qnil, NUM_buffer_start);
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, INT2NUM(parser->current_request_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(struct parser_state *state, int *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(state);
821
+ int initial_pos = BUFFER_POS(parser);
646
822
 
647
823
  while (1) {
648
- char c = BUFFER_CUR(state);
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(state);
830
+ CONSUME_CRLF_NO_FILL(parser);
655
831
  goto done;
656
832
  case '\n':
657
- INC_BUFFER_POS_NO_FILL(state);
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(state);
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
- state->parser->current_request_rx += BUFFER_POS(state) - initial_pos;
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(struct parser_state *state, VALUE *body, int chunk_size, int buffered_only) {
678
- int len = RSTRING_LEN(state->parser->buffer);
679
- int pos = state->parser->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(state->parser->buffer) + pos, available);
862
+ str_append_from_buffer(*body, RSTRING_PTR(parser->buffer) + pos, available);
687
863
  else
688
- *body = rb_str_new(RSTRING_PTR(state->parser->buffer) + pos, available);
689
- state->parser->pos += available;
690
- state->parser->current_request_rx += available;
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(state->parser, INT2NUM(maxlen), Qnil, NUM_buffer_start);
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
- state->parser->current_request_rx += read_bytes;
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
- static inline int parse_chunk_postfix(struct parser_state *state) {
715
- int initial_pos = BUFFER_POS(state);
716
- if (initial_pos == BUFFER_LEN(state)) FILL_BUFFER_OR_GOTO_EOF(state);
717
- switch (BUFFER_CUR(state)) {
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(state);
922
+ CONSUME_CRLF_NO_FILL(parser);
720
923
  goto done;
721
924
  case '\n':
722
- INC_BUFFER_POS_NO_FILL(state);
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
- state->parser->current_request_rx += BUFFER_POS(state) - initial_pos;
931
+ parser->current_request_rx += BUFFER_POS(parser) - initial_pos;
729
932
  return 1;
730
933
  bad_request:
731
- RAISE_BAD_REQUEST("Invalid protocol");
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
- struct parser_state state;
738
- state.parser = parser;
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(&state) == BUFFER_LEN(&state)) FILL_BUFFER_OR_GOTO_EOF(&state);
746
- if (!parse_chunk_size(&state, &chunk_size)) goto bad_request;
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(&state, &body, chunk_size, buffered_only)) goto bad_request;
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(&state)) goto bad_request;
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, INT2NUM(state.parser->current_request_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
- return read_body_with_content_length(parser, read_entire_body, buffered_only);
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, 1);
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
- ID_parser_read_method = rb_intern("__parser_read_method__");
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 = INT2NUM(MAX_HEADERS_READ_LENGTH);
849
- NUM_buffer_start = INT2NUM(0);
850
- NUM_buffer_end = INT2NUM(-1);
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, ":method");
853
- GLOBAL_STR(STR_pseudo_path, ":path");
854
- GLOBAL_STR(STR_pseudo_protocol, ":protocol");
855
- GLOBAL_STR(STR_pseudo_rx, ":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, "chunked");
858
- GLOBAL_STR(STR_content_length, "content-length");
859
- GLOBAL_STR(STR_transfer_encoding, "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
  }