h1p 0.2 → 0.3

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
@@ -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
  }