llhttp 0.0.3 → 0.4.0

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/llhttp/llhttp.h CHANGED
@@ -24,9 +24,13 @@
24
24
  #ifndef INCLUDE_LLHTTP_H_
25
25
  #define INCLUDE_LLHTTP_H_
26
26
 
27
- #define LLHTTP_VERSION_MAJOR 1
28
- #define LLHTTP_VERSION_MINOR 1
29
- #define LLHTTP_VERSION_PATCH 1
27
+ #define LLHTTP_VERSION_MAJOR 6
28
+ #define LLHTTP_VERSION_MINOR 0
29
+ #define LLHTTP_VERSION_PATCH 5
30
+
31
+ #ifndef LLHTTP_STRICT_MODE
32
+ # define LLHTTP_STRICT_MODE 0
33
+ #endif
30
34
 
31
35
  #ifndef INCLUDE_LLHTTP_ITSELF_H_
32
36
  #define INCLUDE_LLHTTP_ITSELF_H_
@@ -52,10 +56,11 @@ struct llhttp__internal_s {
52
56
  uint8_t http_major;
53
57
  uint8_t http_minor;
54
58
  uint8_t header_state;
55
- uint8_t flags;
59
+ uint8_t lenient_flags;
56
60
  uint8_t upgrade;
57
- uint16_t status_code;
58
61
  uint8_t finish;
62
+ uint16_t flags;
63
+ uint16_t status_code;
59
64
  void* settings;
60
65
  };
61
66
 
@@ -89,14 +94,16 @@ enum llhttp_errno {
89
94
  HPE_INVALID_CHUNK_SIZE = 12,
90
95
  HPE_INVALID_STATUS = 13,
91
96
  HPE_INVALID_EOF_STATE = 14,
92
- HPE_CB_MESSAGE_BEGIN = 15,
93
- HPE_CB_HEADERS_COMPLETE = 16,
94
- HPE_CB_MESSAGE_COMPLETE = 17,
95
- HPE_CB_CHUNK_HEADER = 18,
96
- HPE_CB_CHUNK_COMPLETE = 19,
97
- HPE_PAUSED = 20,
98
- HPE_PAUSED_UPGRADE = 21,
99
- HPE_USER = 22
97
+ HPE_INVALID_TRANSFER_ENCODING = 15,
98
+ HPE_CB_MESSAGE_BEGIN = 16,
99
+ HPE_CB_HEADERS_COMPLETE = 17,
100
+ HPE_CB_MESSAGE_COMPLETE = 18,
101
+ HPE_CB_CHUNK_HEADER = 19,
102
+ HPE_CB_CHUNK_COMPLETE = 20,
103
+ HPE_PAUSED = 21,
104
+ HPE_PAUSED_UPGRADE = 22,
105
+ HPE_PAUSED_H2_UPGRADE = 23,
106
+ HPE_USER = 24
100
107
  };
101
108
  typedef enum llhttp_errno llhttp_errno_t;
102
109
 
@@ -108,10 +115,18 @@ enum llhttp_flags {
108
115
  F_UPGRADE = 0x10,
109
116
  F_CONTENT_LENGTH = 0x20,
110
117
  F_SKIPBODY = 0x40,
111
- F_TRAILING = 0x80
118
+ F_TRAILING = 0x80,
119
+ F_TRANSFER_ENCODING = 0x200
112
120
  };
113
121
  typedef enum llhttp_flags llhttp_flags_t;
114
122
 
123
+ enum llhttp_lenient_flags {
124
+ LENIENT_HEADERS = 0x1,
125
+ LENIENT_CHUNKED_LENGTH = 0x2,
126
+ LENIENT_KEEP_ALIVE = 0x4
127
+ };
128
+ typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;
129
+
115
130
  enum llhttp_type {
116
131
  HTTP_BOTH = 0,
117
132
  HTTP_REQUEST = 1,
@@ -160,7 +175,19 @@ enum llhttp_method {
160
175
  HTTP_MKCALENDAR = 30,
161
176
  HTTP_LINK = 31,
162
177
  HTTP_UNLINK = 32,
163
- HTTP_SOURCE = 33
178
+ HTTP_SOURCE = 33,
179
+ HTTP_PRI = 34,
180
+ HTTP_DESCRIBE = 35,
181
+ HTTP_ANNOUNCE = 36,
182
+ HTTP_SETUP = 37,
183
+ HTTP_PLAY = 38,
184
+ HTTP_PAUSE = 39,
185
+ HTTP_TEARDOWN = 40,
186
+ HTTP_GET_PARAMETER = 41,
187
+ HTTP_SET_PARAMETER = 42,
188
+ HTTP_REDIRECT = 43,
189
+ HTTP_RECORD = 44,
190
+ HTTP_FLUSH = 45
164
191
  };
165
192
  typedef enum llhttp_method llhttp_method_t;
166
193
 
@@ -180,14 +207,16 @@ typedef enum llhttp_method llhttp_method_t;
180
207
  XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
181
208
  XX(13, INVALID_STATUS, INVALID_STATUS) \
182
209
  XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \
183
- XX(15, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
184
- XX(16, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
185
- XX(17, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
186
- XX(18, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
187
- XX(19, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
188
- XX(20, PAUSED, PAUSED) \
189
- XX(21, PAUSED_UPGRADE, PAUSED_UPGRADE) \
190
- XX(22, USER, USER) \
210
+ XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \
211
+ XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
212
+ XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
213
+ XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
214
+ XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
215
+ XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
216
+ XX(21, PAUSED, PAUSED) \
217
+ XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
218
+ XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \
219
+ XX(24, USER, USER) \
191
220
 
192
221
 
193
222
  #define HTTP_METHOD_MAP(XX) \
@@ -227,6 +256,71 @@ typedef enum llhttp_method llhttp_method_t;
227
256
  XX(33, SOURCE, SOURCE) \
228
257
 
229
258
 
259
+ #define RTSP_METHOD_MAP(XX) \
260
+ XX(1, GET, GET) \
261
+ XX(3, POST, POST) \
262
+ XX(6, OPTIONS, OPTIONS) \
263
+ XX(35, DESCRIBE, DESCRIBE) \
264
+ XX(36, ANNOUNCE, ANNOUNCE) \
265
+ XX(37, SETUP, SETUP) \
266
+ XX(38, PLAY, PLAY) \
267
+ XX(39, PAUSE, PAUSE) \
268
+ XX(40, TEARDOWN, TEARDOWN) \
269
+ XX(41, GET_PARAMETER, GET_PARAMETER) \
270
+ XX(42, SET_PARAMETER, SET_PARAMETER) \
271
+ XX(43, REDIRECT, REDIRECT) \
272
+ XX(44, RECORD, RECORD) \
273
+ XX(45, FLUSH, FLUSH) \
274
+
275
+
276
+ #define HTTP_ALL_METHOD_MAP(XX) \
277
+ XX(0, DELETE, DELETE) \
278
+ XX(1, GET, GET) \
279
+ XX(2, HEAD, HEAD) \
280
+ XX(3, POST, POST) \
281
+ XX(4, PUT, PUT) \
282
+ XX(5, CONNECT, CONNECT) \
283
+ XX(6, OPTIONS, OPTIONS) \
284
+ XX(7, TRACE, TRACE) \
285
+ XX(8, COPY, COPY) \
286
+ XX(9, LOCK, LOCK) \
287
+ XX(10, MKCOL, MKCOL) \
288
+ XX(11, MOVE, MOVE) \
289
+ XX(12, PROPFIND, PROPFIND) \
290
+ XX(13, PROPPATCH, PROPPATCH) \
291
+ XX(14, SEARCH, SEARCH) \
292
+ XX(15, UNLOCK, UNLOCK) \
293
+ XX(16, BIND, BIND) \
294
+ XX(17, REBIND, REBIND) \
295
+ XX(18, UNBIND, UNBIND) \
296
+ XX(19, ACL, ACL) \
297
+ XX(20, REPORT, REPORT) \
298
+ XX(21, MKACTIVITY, MKACTIVITY) \
299
+ XX(22, CHECKOUT, CHECKOUT) \
300
+ XX(23, MERGE, MERGE) \
301
+ XX(24, MSEARCH, M-SEARCH) \
302
+ XX(25, NOTIFY, NOTIFY) \
303
+ XX(26, SUBSCRIBE, SUBSCRIBE) \
304
+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
305
+ XX(28, PATCH, PATCH) \
306
+ XX(29, PURGE, PURGE) \
307
+ XX(30, MKCALENDAR, MKCALENDAR) \
308
+ XX(31, LINK, LINK) \
309
+ XX(32, UNLINK, UNLINK) \
310
+ XX(33, SOURCE, SOURCE) \
311
+ XX(34, PRI, PRI) \
312
+ XX(35, DESCRIBE, DESCRIBE) \
313
+ XX(36, ANNOUNCE, ANNOUNCE) \
314
+ XX(37, SETUP, SETUP) \
315
+ XX(38, PLAY, PLAY) \
316
+ XX(39, PAUSE, PAUSE) \
317
+ XX(40, TEARDOWN, TEARDOWN) \
318
+ XX(41, GET_PARAMETER, GET_PARAMETER) \
319
+ XX(42, SET_PARAMETER, SET_PARAMETER) \
320
+ XX(43, REDIRECT, REDIRECT) \
321
+ XX(44, RECORD, RECORD) \
322
+ XX(45, FLUSH, FLUSH) \
323
+
230
324
 
231
325
  #ifdef __cplusplus
232
326
  } /* extern "C" */
@@ -240,6 +334,12 @@ extern "C" {
240
334
  #endif
241
335
  #include <stddef.h>
242
336
 
337
+ #if defined(__wasm__)
338
+ #define LLHTTP_EXPORT __attribute__((visibility("default")))
339
+ #else
340
+ #define LLHTTP_EXPORT
341
+ #endif
342
+
243
343
  typedef llhttp__internal_t llhttp_t;
244
344
  typedef struct llhttp_settings_s llhttp_settings_t;
245
345
 
@@ -250,6 +350,7 @@ struct llhttp_settings_s {
250
350
  /* Possible return values 0, -1, `HPE_PAUSED` */
251
351
  llhttp_cb on_message_begin;
252
352
 
353
+ /* Possible return values 0, -1, HPE_USER */
253
354
  llhttp_data_cb on_url;
254
355
  llhttp_data_cb on_status;
255
356
  llhttp_data_cb on_header_field;
@@ -266,6 +367,7 @@ struct llhttp_settings_s {
266
367
  */
267
368
  llhttp_cb on_headers_complete;
268
369
 
370
+ /* Possible return values 0, -1, HPE_USER */
269
371
  llhttp_data_cb on_body;
270
372
 
271
373
  /* Possible return values 0, -1, `HPE_PAUSED` */
@@ -277,13 +379,60 @@ struct llhttp_settings_s {
277
379
  */
278
380
  llhttp_cb on_chunk_header;
279
381
  llhttp_cb on_chunk_complete;
382
+
383
+ /* Information-only callbacks, return value is ignored */
384
+ llhttp_cb on_url_complete;
385
+ llhttp_cb on_status_complete;
386
+ llhttp_cb on_header_field_complete;
387
+ llhttp_cb on_header_value_complete;
280
388
  };
281
389
 
282
- /* Initialize the parser with specific type and user settings */
390
+ /* Initialize the parser with specific type and user settings.
391
+ *
392
+ * NOTE: lifetime of `settings` has to be at least the same as the lifetime of
393
+ * the `parser` here. In practice, `settings` has to be either a static
394
+ * variable or be allocated with `malloc`, `new`, etc.
395
+ */
396
+ LLHTTP_EXPORT
283
397
  void llhttp_init(llhttp_t* parser, llhttp_type_t type,
284
398
  const llhttp_settings_t* settings);
285
399
 
400
+ #if defined(__wasm__)
401
+
402
+ LLHTTP_EXPORT
403
+ llhttp_t* llhttp_alloc(llhttp_type_t type);
404
+
405
+ LLHTTP_EXPORT
406
+ void llhttp_free(llhttp_t* parser);
407
+
408
+ LLHTTP_EXPORT
409
+ uint8_t llhttp_get_type(llhttp_t* parser);
410
+
411
+ LLHTTP_EXPORT
412
+ uint8_t llhttp_get_http_major(llhttp_t* parser);
413
+
414
+ LLHTTP_EXPORT
415
+ uint8_t llhttp_get_http_minor(llhttp_t* parser);
416
+
417
+ LLHTTP_EXPORT
418
+ uint8_t llhttp_get_method(llhttp_t* parser);
419
+
420
+ LLHTTP_EXPORT
421
+ int llhttp_get_status_code(llhttp_t* parser);
422
+
423
+ LLHTTP_EXPORT
424
+ uint8_t llhttp_get_upgrade(llhttp_t* parser);
425
+
426
+ #endif // defined(__wasm__)
427
+
428
+ /* Reset an already initialized parser back to the start state, preserving the
429
+ * existing parser type, callback settings, user data, and lenient flags.
430
+ */
431
+ LLHTTP_EXPORT
432
+ void llhttp_reset(llhttp_t* parser);
433
+
286
434
  /* Initialize the settings object */
435
+ LLHTTP_EXPORT
287
436
  void llhttp_settings_init(llhttp_settings_t* settings);
288
437
 
289
438
  /* Parse full or partial request/response, invoking user callbacks along the
@@ -300,8 +449,9 @@ void llhttp_settings_init(llhttp_settings_t* settings);
300
449
  *
301
450
  * NOTE: if this function ever returns a non-pause type error, it will continue
302
451
  * to return the same error upon each successive call up until `llhttp_init()`
303
- * call.
452
+ * is called.
304
453
  */
454
+ LLHTTP_EXPORT
305
455
  llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
306
456
 
307
457
  /* This method should be called when the other side has no further bytes to
@@ -312,16 +462,19 @@ llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
312
462
  * connection. This method will invoke `on_message_complete()` callback if the
313
463
  * request was terminated safely. Otherwise a error code would be returned.
314
464
  */
465
+ LLHTTP_EXPORT
315
466
  llhttp_errno_t llhttp_finish(llhttp_t* parser);
316
467
 
317
468
  /* Returns `1` if the incoming message is parsed until the last byte, and has
318
469
  * to be completed by calling `llhttp_finish()` on EOF
319
470
  */
471
+ LLHTTP_EXPORT
320
472
  int llhttp_message_needs_eof(const llhttp_t* parser);
321
473
 
322
474
  /* Returns `1` if there might be any other messages following the last that was
323
- * successfuly parsed.
475
+ * successfully parsed.
324
476
  */
477
+ LLHTTP_EXPORT
325
478
  int llhttp_should_keep_alive(const llhttp_t* parser);
326
479
 
327
480
  /* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
@@ -330,6 +483,7 @@ int llhttp_should_keep_alive(const llhttp_t* parser);
330
483
  * Important: do not call this from user callbacks! User callbacks must return
331
484
  * `HPE_PAUSED` if pausing is required.
332
485
  */
486
+ LLHTTP_EXPORT
333
487
  void llhttp_pause(llhttp_t* parser);
334
488
 
335
489
  /* Might be called to resume the execution after the pause in user's callback.
@@ -337,6 +491,7 @@ void llhttp_pause(llhttp_t* parser);
337
491
  *
338
492
  * Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
339
493
  */
494
+ LLHTTP_EXPORT
340
495
  void llhttp_resume(llhttp_t* parser);
341
496
 
342
497
  /* Might be called to resume the execution after the pause in user's callback.
@@ -344,9 +499,11 @@ void llhttp_resume(llhttp_t* parser);
344
499
  *
345
500
  * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
346
501
  */
502
+ LLHTTP_EXPORT
347
503
  void llhttp_resume_after_upgrade(llhttp_t* parser);
348
504
 
349
505
  /* Returns the latest return error */
506
+ LLHTTP_EXPORT
350
507
  llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
351
508
 
352
509
  /* Returns the verbal explanation of the latest returned error.
@@ -354,6 +511,7 @@ llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
354
511
  * Note: User callback should set error reason when returning the error. See
355
512
  * `llhttp_set_error_reason()` for details.
356
513
  */
514
+ LLHTTP_EXPORT
357
515
  const char* llhttp_get_error_reason(const llhttp_t* parser);
358
516
 
359
517
  /* Assign verbal description to the returned error. Must be called in user
@@ -361,6 +519,7 @@ const char* llhttp_get_error_reason(const llhttp_t* parser);
361
519
  *
362
520
  * Note: `HPE_USER` error code might be useful in user callbacks.
363
521
  */
522
+ LLHTTP_EXPORT
364
523
  void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
365
524
 
366
525
  /* Returns the pointer to the last parsed byte before the returned error. The
@@ -368,14 +527,58 @@ void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
368
527
  *
369
528
  * Note: this method might be useful for counting the number of parsed bytes.
370
529
  */
530
+ LLHTTP_EXPORT
371
531
  const char* llhttp_get_error_pos(const llhttp_t* parser);
372
532
 
373
533
  /* Returns textual name of error code */
534
+ LLHTTP_EXPORT
374
535
  const char* llhttp_errno_name(llhttp_errno_t err);
375
536
 
376
537
  /* Returns textual name of HTTP method */
538
+ LLHTTP_EXPORT
377
539
  const char* llhttp_method_name(llhttp_method_t method);
378
540
 
541
+
542
+ /* Enables/disables lenient header value parsing (disabled by default).
543
+ *
544
+ * Lenient parsing disables header value token checks, extending llhttp's
545
+ * protocol support to highly non-compliant clients/server. No
546
+ * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
547
+ * lenient parsing is "on".
548
+ *
549
+ * **(USE AT YOUR OWN RISK)**
550
+ */
551
+ LLHTTP_EXPORT
552
+ void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
553
+
554
+
555
+ /* Enables/disables lenient handling of conflicting `Transfer-Encoding` and
556
+ * `Content-Length` headers (disabled by default).
557
+ *
558
+ * Normally `llhttp` would error when `Transfer-Encoding` is present in
559
+ * conjunction with `Content-Length`. This error is important to prevent HTTP
560
+ * request smuggling, but may be less desirable for small number of cases
561
+ * involving legacy servers.
562
+ *
563
+ * **(USE AT YOUR OWN RISK)**
564
+ */
565
+ LLHTTP_EXPORT
566
+ void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
567
+
568
+
569
+ /* Enables/disables lenient handling of `Connection: close` and HTTP/1.0
570
+ * requests responses.
571
+ *
572
+ * Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
573
+ * the HTTP request/response after the request/response with `Connection: close`
574
+ * and `Content-Length`. This is important to prevent cache poisoning attacks,
575
+ * but might interact badly with outdated and insecure clients. With this flag
576
+ * the extra request/response will be parsed normally.
577
+ *
578
+ * **(USE AT YOUR OWN RISK)**
579
+ */
580
+ void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
581
+
379
582
  #ifdef __cplusplus
380
583
  } /* extern "C" */
381
584
  #endif
@@ -1,25 +1,8 @@
1
- // This software is licensed under the MIT License.
1
+ /*
2
+ This software is licensed under the MPL-2.0 License.
2
3
 
3
- // Copyright Bryan Powell, 2020.
4
-
5
- // Permission is hereby granted, free of charge, to any person obtaining a
6
- // copy of this software and associated documentation files (the
7
- // "Software"), to deal in the Software without restriction, including
8
- // without limitation the rights to use, copy, modify, merge, publish,
9
- // distribute, sublicense, and/or sell copies of the Software, and to permit
10
- // persons to whom the Software is furnished to do so, subject to the
11
- // following conditions:
12
-
13
- // The above copyright notice and this permission notice shall be included
14
- // in all copies or substantial portions of the Software.
15
-
16
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
19
- // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22
- // USE OR OTHER DEALINGS IN THE SOFTWARE.
4
+ Copyright Bryan Powell, 2020.
5
+ */
23
6
 
24
7
  #include <ruby/ruby.h>
25
8
 
@@ -27,6 +10,21 @@
27
10
 
28
11
  static VALUE mLLHttp, cParser, eError;
29
12
 
13
+ static ID rb_llhttp_callback_on_message_begin;
14
+ static ID rb_llhttp_callback_on_url;
15
+ static ID rb_llhttp_callback_on_status;
16
+ static ID rb_llhttp_callback_on_header_field;
17
+ static ID rb_llhttp_callback_on_header_value;
18
+ static ID rb_llhttp_callback_on_headers_complete;
19
+ static ID rb_llhttp_callback_on_body;
20
+ static ID rb_llhttp_callback_on_message_complete;
21
+ static ID rb_llhttp_callback_on_chunk_header;
22
+ static ID rb_llhttp_callback_on_chunk_complete;
23
+ static ID rb_llhttp_callback_on_url_complete;
24
+ static ID rb_llhttp_callback_on_status_complete;
25
+ static ID rb_llhttp_callback_on_header_field_complete;
26
+ static ID rb_llhttp_callback_on_header_value_complete;
27
+
30
28
  static void rb_llhttp_free(llhttp_t *parser) {
31
29
  if (parser) {
32
30
  free(parser->settings);
@@ -44,90 +42,86 @@ VALUE rb_llhttp_allocate(VALUE klass) {
44
42
  return Data_Wrap_Struct(klass, 0, rb_llhttp_free, parser);
45
43
  }
46
44
 
47
- void rb_llhttp_callback_call(VALUE delegate, const char *name) {
48
- rb_funcall(delegate, rb_intern(name), 0);
45
+ VALUE rb_llhttp_callback_call(VALUE delegate, ID method) {
46
+ return rb_funcall(delegate, method, 0);
49
47
  }
50
48
 
51
- void rb_llhttp_data_callback_call(VALUE delegate, const char *name, char *data, size_t length) {
52
- rb_funcall(delegate, rb_intern(name), 1, rb_str_new(data, length));
49
+ void rb_llhttp_data_callback_call(VALUE delegate, ID method, char *data, size_t length) {
50
+ rb_funcall(delegate, method, 1, rb_str_new(data, length));
53
51
  }
54
52
 
55
53
  int rb_llhttp_on_message_begin(llhttp_t *parser) {
56
- VALUE delegate = (VALUE)parser->data;
54
+ return NUM2INT(rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_message_begin));
55
+ }
57
56
 
58
- rb_llhttp_callback_call(delegate, "on_message_begin");
57
+ int rb_llhttp_on_headers_complete(llhttp_t *parser) {
58
+ return NUM2INT(rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_headers_complete));
59
+ }
59
60
 
60
- return 0;
61
+ int rb_llhttp_on_message_complete(llhttp_t *parser) {
62
+ return NUM2INT(rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_message_complete));
61
63
  }
62
64
 
63
- int rb_llhttp_on_url(llhttp_t *parser, char *data, size_t length) {
64
- VALUE delegate = (VALUE)parser->data;
65
+ int rb_llhttp_on_chunk_header(llhttp_t *parser) {
66
+ return NUM2INT(rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_chunk_header));
67
+ }
65
68
 
66
- rb_llhttp_data_callback_call(delegate, "on_url", data, length);
69
+ int rb_llhttp_on_url(llhttp_t *parser, char *data, size_t length) {
70
+ rb_llhttp_data_callback_call((VALUE)parser->data, rb_llhttp_callback_on_url, data, length);
67
71
 
68
72
  return 0;
69
73
  }
70
74
 
71
75
  int rb_llhttp_on_status(llhttp_t *parser, char *data, size_t length) {
72
- VALUE delegate = (VALUE)parser->data;
73
-
74
- rb_llhttp_data_callback_call(delegate, "on_status", data, length);
76
+ rb_llhttp_data_callback_call((VALUE)parser->data, rb_llhttp_callback_on_status, data, length);
75
77
 
76
78
  return 0;
77
79
  }
78
80
 
79
81
  int rb_llhttp_on_header_field(llhttp_t *parser, char *data, size_t length) {
80
- VALUE delegate = (VALUE)parser->data;
81
-
82
- rb_llhttp_data_callback_call(delegate, "on_header_field", data, length);
82
+ rb_llhttp_data_callback_call((VALUE)parser->data, rb_llhttp_callback_on_header_field, data, length);
83
83
 
84
84
  return 0;
85
85
  }
86
86
 
87
87
  int rb_llhttp_on_header_value(llhttp_t *parser, char *data, size_t length) {
88
- VALUE delegate = (VALUE)parser->data;
89
-
90
- rb_llhttp_data_callback_call(delegate, "on_header_value", data, length);
88
+ rb_llhttp_data_callback_call((VALUE)parser->data, rb_llhttp_callback_on_header_value, data, length);
91
89
 
92
90
  return 0;
93
91
  }
94
92
 
95
- int rb_llhttp_on_headers_complete(llhttp_t *parser) {
96
- VALUE delegate = (VALUE)parser->data;
97
-
98
- rb_llhttp_callback_call(delegate, "on_headers_complete");
93
+ int rb_llhttp_on_body(llhttp_t *parser, char *data, size_t length) {
94
+ rb_llhttp_data_callback_call((VALUE)parser->data, rb_llhttp_callback_on_body, data, length);
99
95
 
100
96
  return 0;
101
97
  }
102
98
 
103
- int rb_llhttp_on_body(llhttp_t *parser, char *data, size_t length) {
104
- VALUE delegate = (VALUE)parser->data;
105
-
106
- rb_llhttp_data_callback_call(delegate, "on_body", data, length);
99
+ int rb_llhttp_on_chunk_complete(llhttp_t *parser) {
100
+ rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_chunk_complete);
107
101
 
108
102
  return 0;
109
103
  }
110
104
 
111
- int rb_llhttp_on_message_complete(llhttp_t *parser) {
112
- VALUE delegate = (VALUE)parser->data;
113
-
114
- rb_llhttp_callback_call(delegate, "on_message_complete");
105
+ int rb_llhttp_on_url_complete(llhttp_t *parser) {
106
+ rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_url_complete);
115
107
 
116
108
  return 0;
117
109
  }
118
110
 
119
- int rb_llhttp_on_chunk_header(llhttp_t *parser) {
120
- VALUE delegate = (VALUE)parser->data;
121
-
122
- rb_llhttp_callback_call(delegate, "on_chunk_header");
111
+ int rb_llhttp_on_status_complete(llhttp_t *parser) {
112
+ rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_status_complete);
123
113
 
124
114
  return 0;
125
115
  }
126
116
 
127
- int rb_llhttp_on_chunk_complete(llhttp_t *parser) {
128
- VALUE delegate = (VALUE)parser->data;
117
+ int rb_llhttp_on_header_field_complete(llhttp_t *parser) {
118
+ rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_header_field_complete);
129
119
 
130
- rb_llhttp_callback_call(delegate, "on_chunk_complete");
120
+ return 0;
121
+ }
122
+
123
+ int rb_llhttp_on_header_value_complete(llhttp_t *parser) {
124
+ rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_header_value_complete);
131
125
 
132
126
  return 0;
133
127
  }
@@ -160,15 +154,27 @@ VALUE rb_llhttp_finish(VALUE self) {
160
154
  return Qtrue;
161
155
  }
162
156
 
157
+ VALUE rb_llhttp_reset(VALUE self) {
158
+ llhttp_t *parser;
159
+
160
+ Data_Get_Struct(self, llhttp_t, parser);
161
+
162
+ llhttp_settings_t *settings = parser->settings;
163
+
164
+ llhttp_reset(parser);
165
+
166
+ return Qtrue;
167
+ }
168
+
163
169
  VALUE rb_llhttp_content_length(VALUE self) {
164
170
  llhttp_t *parser;
165
171
 
166
172
  Data_Get_Struct(self, llhttp_t, parser);
167
173
 
168
- return UINT2NUM(parser->content_length);
174
+ return ULL2NUM(parser->content_length);
169
175
  }
170
176
 
171
- VALUE rb_llhttp_method(VALUE self) {
177
+ VALUE rb_llhttp_method_name(VALUE self) {
172
178
  llhttp_t *parser;
173
179
 
174
180
  Data_Get_Struct(self, llhttp_t, parser);
@@ -184,6 +190,22 @@ VALUE rb_llhttp_status_code(VALUE self) {
184
190
  return UINT2NUM(parser->status_code);
185
191
  }
186
192
 
193
+ VALUE rb_llhttp_http_major(VALUE self) {
194
+ llhttp_t *parser;
195
+
196
+ Data_Get_Struct(self, llhttp_t, parser);
197
+
198
+ return UINT2NUM(parser->http_major);
199
+ }
200
+
201
+ VALUE rb_llhttp_http_minor(VALUE self) {
202
+ llhttp_t *parser;
203
+
204
+ Data_Get_Struct(self, llhttp_t, parser);
205
+
206
+ return UINT2NUM(parser->http_minor);
207
+ }
208
+
187
209
  VALUE rb_llhttp_keep_alive(VALUE self) {
188
210
  llhttp_t *parser;
189
211
 
@@ -201,22 +223,81 @@ static VALUE rb_llhttp_init(VALUE self, VALUE type) {
201
223
 
202
224
  llhttp_settings_t *settings = parser->settings;
203
225
 
204
- settings->on_message_begin = (llhttp_cb)rb_llhttp_on_message_begin;
205
- settings->on_url = (llhttp_data_cb)rb_llhttp_on_url;
206
- settings->on_status = (llhttp_data_cb)rb_llhttp_on_status;
207
- settings->on_header_field = (llhttp_data_cb)rb_llhttp_on_header_field;
208
- settings->on_header_value = (llhttp_data_cb)rb_llhttp_on_header_value;
209
- settings->on_headers_complete = (llhttp_cb)rb_llhttp_on_headers_complete;
210
- settings->on_body = (llhttp_data_cb)rb_llhttp_on_body;
211
- settings->on_message_complete = (llhttp_cb)rb_llhttp_on_message_complete;
212
- settings->on_chunk_header = (llhttp_cb)rb_llhttp_on_chunk_header;
213
- settings->on_chunk_complete = (llhttp_cb)rb_llhttp_on_chunk_complete;
226
+ VALUE delegate = rb_iv_get(self, "@delegate");
227
+
228
+ rb_llhttp_callback_on_message_begin = rb_intern("internal_on_message_begin");
229
+ rb_llhttp_callback_on_headers_complete = rb_intern("internal_on_headers_complete");
230
+ rb_llhttp_callback_on_message_complete = rb_intern("internal_on_message_complete");
231
+ rb_llhttp_callback_on_chunk_header = rb_intern("internal_on_chunk_header");
232
+ rb_llhttp_callback_on_url = rb_intern("on_url");
233
+ rb_llhttp_callback_on_status = rb_intern("on_status");
234
+ rb_llhttp_callback_on_header_field = rb_intern("on_header_field");
235
+ rb_llhttp_callback_on_header_value = rb_intern("on_header_value");
236
+ rb_llhttp_callback_on_body = rb_intern("on_body");
237
+ rb_llhttp_callback_on_chunk_complete = rb_intern("on_chunk_complete");
238
+ rb_llhttp_callback_on_url_complete = rb_intern("on_url_complete");
239
+ rb_llhttp_callback_on_status_complete = rb_intern("on_status_complete");
240
+ rb_llhttp_callback_on_header_field_complete = rb_intern("on_header_field_complete");
241
+ rb_llhttp_callback_on_header_value_complete = rb_intern("on_header_value_complete");
242
+
243
+ if (rb_respond_to(delegate, rb_intern("on_message_begin"))) {
244
+ settings->on_message_begin = (llhttp_cb)rb_llhttp_on_message_begin;
245
+ }
246
+
247
+ if (rb_respond_to(delegate, rb_intern("on_headers_complete"))) {
248
+ settings->on_headers_complete = (llhttp_cb)rb_llhttp_on_headers_complete;
249
+ }
250
+
251
+ if (rb_respond_to(delegate, rb_intern("on_message_complete"))) {
252
+ settings->on_message_complete = (llhttp_cb)rb_llhttp_on_message_complete;
253
+ }
254
+
255
+ if (rb_respond_to(delegate, rb_intern("on_chunk_header"))) {
256
+ settings->on_chunk_header = (llhttp_cb)rb_llhttp_on_chunk_header;
257
+ }
258
+
259
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_url)) {
260
+ settings->on_url = (llhttp_data_cb)rb_llhttp_on_url;
261
+ }
262
+
263
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_status)) {
264
+ settings->on_status = (llhttp_data_cb)rb_llhttp_on_status;
265
+ }
266
+
267
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_header_field)) {
268
+ settings->on_header_field = (llhttp_data_cb)rb_llhttp_on_header_field;
269
+ }
270
+
271
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_header_value)) {
272
+ settings->on_header_value = (llhttp_data_cb)rb_llhttp_on_header_value;
273
+ }
274
+
275
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_body)) {
276
+ settings->on_body = (llhttp_data_cb)rb_llhttp_on_body;
277
+ }
278
+
279
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_chunk_complete)) {
280
+ settings->on_chunk_complete = (llhttp_cb)rb_llhttp_on_chunk_complete;
281
+ }
282
+
283
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_url_complete)) {
284
+ settings->on_url_complete = (llhttp_cb)rb_llhttp_on_url_complete;
285
+ }
286
+
287
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_status_complete)) {
288
+ settings->on_status_complete = (llhttp_cb)rb_llhttp_on_status_complete;
289
+ }
290
+
291
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_header_field_complete)) {
292
+ settings->on_header_field_complete = (llhttp_cb)rb_llhttp_on_header_field_complete;
293
+ }
294
+
295
+ if (rb_respond_to(delegate, rb_llhttp_callback_on_header_value_complete)) {
296
+ settings->on_header_value_complete = (llhttp_cb)rb_llhttp_on_header_value_complete;
297
+ }
214
298
 
215
299
  llhttp_init(parser, FIX2INT(type), settings);
216
300
 
217
- // Store a pointer to the delegate for lookup in callbacks.
218
- //
219
- VALUE delegate = rb_iv_get(self, "@delegate");
220
301
  parser->data = (void*)delegate;
221
302
 
222
303
  return Qtrue;
@@ -232,10 +313,13 @@ void Init_llhttp_ext(void) {
232
313
  rb_define_method(cParser, "<<", rb_llhttp_parse, 1);
233
314
  rb_define_method(cParser, "parse", rb_llhttp_parse, 1);
234
315
  rb_define_method(cParser, "finish", rb_llhttp_finish, 0);
316
+ rb_define_method(cParser, "reset", rb_llhttp_reset, 0);
235
317
 
236
318
  rb_define_method(cParser, "content_length", rb_llhttp_content_length, 0);
237
- rb_define_method(cParser, "method", rb_llhttp_method, 0);
319
+ rb_define_method(cParser, "method_name", rb_llhttp_method_name, 0);
238
320
  rb_define_method(cParser, "status_code", rb_llhttp_status_code, 0);
321
+ rb_define_method(cParser, "http_major", rb_llhttp_http_major, 0);
322
+ rb_define_method(cParser, "http_minor", rb_llhttp_http_minor, 0);
239
323
 
240
324
  rb_define_method(cParser, "keep_alive?", rb_llhttp_keep_alive, 0);
241
325