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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/LICENSE +353 -22
- data/README.md +1 -1
- data/ext/llhttp/api.c +170 -16
- data/ext/llhttp/http.c +31 -2
- data/ext/llhttp/llhttp.c +9729 -848
- data/ext/llhttp/llhttp.h +229 -26
- data/ext/llhttp/llhttp_ext.c +159 -75
- data/lib/llhttp/delegate.rb +71 -39
- data/lib/llhttp/parser.rb +7 -1
- data/lib/llhttp/version.rb +1 -1
- metadata +5 -5
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
|
28
|
-
#define LLHTTP_VERSION_MINOR
|
29
|
-
#define LLHTTP_VERSION_PATCH
|
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
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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,
|
184
|
-
XX(16,
|
185
|
-
XX(17,
|
186
|
-
XX(18,
|
187
|
-
XX(19,
|
188
|
-
XX(20,
|
189
|
-
XX(21,
|
190
|
-
XX(22,
|
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
|
-
*
|
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
|
-
*
|
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
|
data/ext/llhttp/llhttp_ext.c
CHANGED
@@ -1,25 +1,8 @@
|
|
1
|
-
|
1
|
+
/*
|
2
|
+
This software is licensed under the MPL-2.0 License.
|
2
3
|
|
3
|
-
|
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
|
-
|
48
|
-
rb_funcall(delegate,
|
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,
|
52
|
-
rb_funcall(delegate,
|
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
|
-
|
54
|
+
return NUM2INT(rb_llhttp_callback_call((VALUE)parser->data, rb_llhttp_callback_on_message_begin));
|
55
|
+
}
|
57
56
|
|
58
|
-
|
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
|
-
|
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
|
64
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
96
|
-
|
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
|
104
|
-
|
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
|
112
|
-
|
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
|
120
|
-
|
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
|
128
|
-
|
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
|
-
|
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
|
174
|
+
return ULL2NUM(parser->content_length);
|
169
175
|
}
|
170
176
|
|
171
|
-
VALUE
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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, "
|
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
|
|