h1p 0.2 → 0.3

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