llhttp 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,384 @@
1
+ // This software is licensed under the MIT License.
2
+
3
+ // Copyright Fedor Indutny, 2018.
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.
23
+
24
+ #ifndef INCLUDE_LLHTTP_H_
25
+ #define INCLUDE_LLHTTP_H_
26
+
27
+ #define LLHTTP_VERSION_MAJOR 1
28
+ #define LLHTTP_VERSION_MINOR 1
29
+ #define LLHTTP_VERSION_PATCH 1
30
+
31
+ #ifndef INCLUDE_LLHTTP_ITSELF_H_
32
+ #define INCLUDE_LLHTTP_ITSELF_H_
33
+ #ifdef __cplusplus
34
+ extern "C" {
35
+ #endif
36
+
37
+ #include <stdint.h>
38
+
39
+ typedef struct llhttp__internal_s llhttp__internal_t;
40
+ struct llhttp__internal_s {
41
+ int32_t _index;
42
+ void* _span_pos0;
43
+ void* _span_cb0;
44
+ int32_t error;
45
+ const char* reason;
46
+ const char* error_pos;
47
+ void* data;
48
+ void* _current;
49
+ uint64_t content_length;
50
+ uint8_t type;
51
+ uint8_t method;
52
+ uint8_t http_major;
53
+ uint8_t http_minor;
54
+ uint8_t header_state;
55
+ uint8_t flags;
56
+ uint8_t upgrade;
57
+ uint16_t status_code;
58
+ uint8_t finish;
59
+ void* settings;
60
+ };
61
+
62
+ int llhttp__internal_init(llhttp__internal_t* s);
63
+ int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);
64
+
65
+ #ifdef __cplusplus
66
+ } /* extern "C" */
67
+ #endif
68
+ #endif /* INCLUDE_LLHTTP_ITSELF_H_ */
69
+
70
+ #ifndef LLLLHTTP_C_HEADERS_
71
+ #define LLLLHTTP_C_HEADERS_
72
+ #ifdef __cplusplus
73
+ extern "C" {
74
+ #endif
75
+
76
+ enum llhttp_errno {
77
+ HPE_OK = 0,
78
+ HPE_INTERNAL = 1,
79
+ HPE_STRICT = 2,
80
+ HPE_LF_EXPECTED = 3,
81
+ HPE_UNEXPECTED_CONTENT_LENGTH = 4,
82
+ HPE_CLOSED_CONNECTION = 5,
83
+ HPE_INVALID_METHOD = 6,
84
+ HPE_INVALID_URL = 7,
85
+ HPE_INVALID_CONSTANT = 8,
86
+ HPE_INVALID_VERSION = 9,
87
+ HPE_INVALID_HEADER_TOKEN = 10,
88
+ HPE_INVALID_CONTENT_LENGTH = 11,
89
+ HPE_INVALID_CHUNK_SIZE = 12,
90
+ HPE_INVALID_STATUS = 13,
91
+ 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
100
+ };
101
+ typedef enum llhttp_errno llhttp_errno_t;
102
+
103
+ enum llhttp_flags {
104
+ F_CONNECTION_KEEP_ALIVE = 0x1,
105
+ F_CONNECTION_CLOSE = 0x2,
106
+ F_CONNECTION_UPGRADE = 0x4,
107
+ F_CHUNKED = 0x8,
108
+ F_UPGRADE = 0x10,
109
+ F_CONTENT_LENGTH = 0x20,
110
+ F_SKIPBODY = 0x40,
111
+ F_TRAILING = 0x80
112
+ };
113
+ typedef enum llhttp_flags llhttp_flags_t;
114
+
115
+ enum llhttp_type {
116
+ HTTP_BOTH = 0,
117
+ HTTP_REQUEST = 1,
118
+ HTTP_RESPONSE = 2
119
+ };
120
+ typedef enum llhttp_type llhttp_type_t;
121
+
122
+ enum llhttp_finish {
123
+ HTTP_FINISH_SAFE = 0,
124
+ HTTP_FINISH_SAFE_WITH_CB = 1,
125
+ HTTP_FINISH_UNSAFE = 2
126
+ };
127
+ typedef enum llhttp_finish llhttp_finish_t;
128
+
129
+ enum llhttp_method {
130
+ HTTP_DELETE = 0,
131
+ HTTP_GET = 1,
132
+ HTTP_HEAD = 2,
133
+ HTTP_POST = 3,
134
+ HTTP_PUT = 4,
135
+ HTTP_CONNECT = 5,
136
+ HTTP_OPTIONS = 6,
137
+ HTTP_TRACE = 7,
138
+ HTTP_COPY = 8,
139
+ HTTP_LOCK = 9,
140
+ HTTP_MKCOL = 10,
141
+ HTTP_MOVE = 11,
142
+ HTTP_PROPFIND = 12,
143
+ HTTP_PROPPATCH = 13,
144
+ HTTP_SEARCH = 14,
145
+ HTTP_UNLOCK = 15,
146
+ HTTP_BIND = 16,
147
+ HTTP_REBIND = 17,
148
+ HTTP_UNBIND = 18,
149
+ HTTP_ACL = 19,
150
+ HTTP_REPORT = 20,
151
+ HTTP_MKACTIVITY = 21,
152
+ HTTP_CHECKOUT = 22,
153
+ HTTP_MERGE = 23,
154
+ HTTP_MSEARCH = 24,
155
+ HTTP_NOTIFY = 25,
156
+ HTTP_SUBSCRIBE = 26,
157
+ HTTP_UNSUBSCRIBE = 27,
158
+ HTTP_PATCH = 28,
159
+ HTTP_PURGE = 29,
160
+ HTTP_MKCALENDAR = 30,
161
+ HTTP_LINK = 31,
162
+ HTTP_UNLINK = 32,
163
+ HTTP_SOURCE = 33
164
+ };
165
+ typedef enum llhttp_method llhttp_method_t;
166
+
167
+ #define HTTP_ERRNO_MAP(XX) \
168
+ XX(0, OK, OK) \
169
+ XX(1, INTERNAL, INTERNAL) \
170
+ XX(2, STRICT, STRICT) \
171
+ XX(3, LF_EXPECTED, LF_EXPECTED) \
172
+ XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \
173
+ XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \
174
+ XX(6, INVALID_METHOD, INVALID_METHOD) \
175
+ XX(7, INVALID_URL, INVALID_URL) \
176
+ XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \
177
+ XX(9, INVALID_VERSION, INVALID_VERSION) \
178
+ XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \
179
+ XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \
180
+ XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
181
+ XX(13, INVALID_STATUS, INVALID_STATUS) \
182
+ 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) \
191
+
192
+
193
+ #define HTTP_METHOD_MAP(XX) \
194
+ XX(0, DELETE, DELETE) \
195
+ XX(1, GET, GET) \
196
+ XX(2, HEAD, HEAD) \
197
+ XX(3, POST, POST) \
198
+ XX(4, PUT, PUT) \
199
+ XX(5, CONNECT, CONNECT) \
200
+ XX(6, OPTIONS, OPTIONS) \
201
+ XX(7, TRACE, TRACE) \
202
+ XX(8, COPY, COPY) \
203
+ XX(9, LOCK, LOCK) \
204
+ XX(10, MKCOL, MKCOL) \
205
+ XX(11, MOVE, MOVE) \
206
+ XX(12, PROPFIND, PROPFIND) \
207
+ XX(13, PROPPATCH, PROPPATCH) \
208
+ XX(14, SEARCH, SEARCH) \
209
+ XX(15, UNLOCK, UNLOCK) \
210
+ XX(16, BIND, BIND) \
211
+ XX(17, REBIND, REBIND) \
212
+ XX(18, UNBIND, UNBIND) \
213
+ XX(19, ACL, ACL) \
214
+ XX(20, REPORT, REPORT) \
215
+ XX(21, MKACTIVITY, MKACTIVITY) \
216
+ XX(22, CHECKOUT, CHECKOUT) \
217
+ XX(23, MERGE, MERGE) \
218
+ XX(24, MSEARCH, M-SEARCH) \
219
+ XX(25, NOTIFY, NOTIFY) \
220
+ XX(26, SUBSCRIBE, SUBSCRIBE) \
221
+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
222
+ XX(28, PATCH, PATCH) \
223
+ XX(29, PURGE, PURGE) \
224
+ XX(30, MKCALENDAR, MKCALENDAR) \
225
+ XX(31, LINK, LINK) \
226
+ XX(32, UNLINK, UNLINK) \
227
+ XX(33, SOURCE, SOURCE) \
228
+
229
+
230
+
231
+ #ifdef __cplusplus
232
+ } /* extern "C" */
233
+ #endif
234
+ #endif /* LLLLHTTP_C_HEADERS_ */
235
+
236
+ #ifndef INCLUDE_LLHTTP_API_H_
237
+ #define INCLUDE_LLHTTP_API_H_
238
+ #ifdef __cplusplus
239
+ extern "C" {
240
+ #endif
241
+ #include <stddef.h>
242
+
243
+ typedef llhttp__internal_t llhttp_t;
244
+ typedef struct llhttp_settings_s llhttp_settings_t;
245
+
246
+ typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);
247
+ typedef int (*llhttp_cb)(llhttp_t*);
248
+
249
+ struct llhttp_settings_s {
250
+ /* Possible return values 0, -1, `HPE_PAUSED` */
251
+ llhttp_cb on_message_begin;
252
+
253
+ llhttp_data_cb on_url;
254
+ llhttp_data_cb on_status;
255
+ llhttp_data_cb on_header_field;
256
+ llhttp_data_cb on_header_value;
257
+
258
+ /* Possible return values:
259
+ * 0 - Proceed normally
260
+ * 1 - Assume that request/response has no body, and proceed to parsing the
261
+ * next message
262
+ * 2 - Assume absence of body (as above) and make `llhttp_execute()` return
263
+ * `HPE_PAUSED_UPGRADE`
264
+ * -1 - Error
265
+ * `HPE_PAUSED`
266
+ */
267
+ llhttp_cb on_headers_complete;
268
+
269
+ llhttp_data_cb on_body;
270
+
271
+ /* Possible return values 0, -1, `HPE_PAUSED` */
272
+ llhttp_cb on_message_complete;
273
+
274
+ /* When on_chunk_header is called, the current chunk length is stored
275
+ * in parser->content_length.
276
+ * Possible return values 0, -1, `HPE_PAUSED`
277
+ */
278
+ llhttp_cb on_chunk_header;
279
+ llhttp_cb on_chunk_complete;
280
+ };
281
+
282
+ /* Initialize the parser with specific type and user settings */
283
+ void llhttp_init(llhttp_t* parser, llhttp_type_t type,
284
+ const llhttp_settings_t* settings);
285
+
286
+ /* Initialize the settings object */
287
+ void llhttp_settings_init(llhttp_settings_t* settings);
288
+
289
+ /* Parse full or partial request/response, invoking user callbacks along the
290
+ * way.
291
+ *
292
+ * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing
293
+ * interrupts, and such errno is returned from `llhttp_execute()`. If
294
+ * `HPE_PAUSED` was used as a errno, the execution can be resumed with
295
+ * `llhttp_resume()` call.
296
+ *
297
+ * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`
298
+ * is returned after fully parsing the request/response. If the user wishes to
299
+ * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.
300
+ *
301
+ * NOTE: if this function ever returns a non-pause type error, it will continue
302
+ * to return the same error upon each successive call up until `llhttp_init()`
303
+ * call.
304
+ */
305
+ llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
306
+
307
+ /* This method should be called when the other side has no further bytes to
308
+ * send (e.g. shutdown of readable side of the TCP connection.)
309
+ *
310
+ * Requests without `Content-Length` and other messages might require treating
311
+ * all incoming bytes as the part of the body, up to the last byte of the
312
+ * connection. This method will invoke `on_message_complete()` callback if the
313
+ * request was terminated safely. Otherwise a error code would be returned.
314
+ */
315
+ llhttp_errno_t llhttp_finish(llhttp_t* parser);
316
+
317
+ /* Returns `1` if the incoming message is parsed until the last byte, and has
318
+ * to be completed by calling `llhttp_finish()` on EOF
319
+ */
320
+ int llhttp_message_needs_eof(const llhttp_t* parser);
321
+
322
+ /* Returns `1` if there might be any other messages following the last that was
323
+ * successfuly parsed.
324
+ */
325
+ int llhttp_should_keep_alive(const llhttp_t* parser);
326
+
327
+ /* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
328
+ * appropriate error reason.
329
+ *
330
+ * Important: do not call this from user callbacks! User callbacks must return
331
+ * `HPE_PAUSED` if pausing is required.
332
+ */
333
+ void llhttp_pause(llhttp_t* parser);
334
+
335
+ /* Might be called to resume the execution after the pause in user's callback.
336
+ * See `llhttp_execute()` above for details.
337
+ *
338
+ * Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
339
+ */
340
+ void llhttp_resume(llhttp_t* parser);
341
+
342
+ /* Might be called to resume the execution after the pause in user's callback.
343
+ * See `llhttp_execute()` above for details.
344
+ *
345
+ * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
346
+ */
347
+ void llhttp_resume_after_upgrade(llhttp_t* parser);
348
+
349
+ /* Returns the latest return error */
350
+ llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
351
+
352
+ /* Returns the verbal explanation of the latest returned error.
353
+ *
354
+ * Note: User callback should set error reason when returning the error. See
355
+ * `llhttp_set_error_reason()` for details.
356
+ */
357
+ const char* llhttp_get_error_reason(const llhttp_t* parser);
358
+
359
+ /* Assign verbal description to the returned error. Must be called in user
360
+ * callbacks right before returning the errno.
361
+ *
362
+ * Note: `HPE_USER` error code might be useful in user callbacks.
363
+ */
364
+ void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
365
+
366
+ /* Returns the pointer to the last parsed byte before the returned error. The
367
+ * pointer is relative to the `data` argument of `llhttp_execute()`.
368
+ *
369
+ * Note: this method might be useful for counting the number of parsed bytes.
370
+ */
371
+ const char* llhttp_get_error_pos(const llhttp_t* parser);
372
+
373
+ /* Returns textual name of error code */
374
+ const char* llhttp_errno_name(llhttp_errno_t err);
375
+
376
+ /* Returns textual name of HTTP method */
377
+ const char* llhttp_method_name(llhttp_method_t method);
378
+
379
+ #ifdef __cplusplus
380
+ } /* extern "C" */
381
+ #endif
382
+ #endif /* INCLUDE_LLHTTP_API_H_ */
383
+
384
+ #endif /* INCLUDE_LLHTTP_H_ */
@@ -0,0 +1,243 @@
1
+ // This software is licensed under the MIT License.
2
+
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.
23
+
24
+ #include <ruby/ruby.h>
25
+
26
+ #include "llhttp.h"
27
+
28
+ static VALUE mLLHttp, cParser, eError;
29
+
30
+ static void rb_llhttp_free(llhttp_t *parser) {
31
+ if (parser) {
32
+ free(parser->settings);
33
+ free(parser);
34
+ }
35
+ }
36
+
37
+ VALUE rb_llhttp_allocate(VALUE klass) {
38
+ llhttp_t *parser = (llhttp_t *)malloc(sizeof(llhttp_t));
39
+ llhttp_settings_t *settings = (llhttp_settings_t *)malloc(sizeof(llhttp_settings_t));
40
+
41
+ llhttp_settings_init(settings);
42
+ llhttp_init(parser, HTTP_BOTH, settings);
43
+
44
+ return Data_Wrap_Struct(klass, 0, rb_llhttp_free, parser);
45
+ }
46
+
47
+ void rb_llhttp_callback_call(VALUE delegate, const char *name) {
48
+ rb_funcall(delegate, rb_intern(name), 0);
49
+ }
50
+
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));
53
+ }
54
+
55
+ int rb_llhttp_on_message_begin(llhttp_t *parser) {
56
+ VALUE delegate = (VALUE)parser->data;
57
+
58
+ rb_llhttp_callback_call(delegate, "on_message_begin");
59
+
60
+ return 0;
61
+ }
62
+
63
+ int rb_llhttp_on_url(llhttp_t *parser, char *data, size_t length) {
64
+ VALUE delegate = (VALUE)parser->data;
65
+
66
+ rb_llhttp_data_callback_call(delegate, "on_url", data, length);
67
+
68
+ return 0;
69
+ }
70
+
71
+ 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);
75
+
76
+ return 0;
77
+ }
78
+
79
+ 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);
83
+
84
+ return 0;
85
+ }
86
+
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);
91
+
92
+ return 0;
93
+ }
94
+
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");
99
+
100
+ return 0;
101
+ }
102
+
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);
107
+
108
+ return 0;
109
+ }
110
+
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");
115
+
116
+ return 0;
117
+ }
118
+
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");
123
+
124
+ return 0;
125
+ }
126
+
127
+ int rb_llhttp_on_chunk_complete(llhttp_t *parser) {
128
+ VALUE delegate = (VALUE)parser->data;
129
+
130
+ rb_llhttp_callback_call(delegate, "on_chunk_complete");
131
+
132
+ return 0;
133
+ }
134
+
135
+ VALUE rb_llhttp_parse(VALUE self, VALUE data) {
136
+ llhttp_t *parser;
137
+
138
+ Data_Get_Struct(self, llhttp_t, parser);
139
+
140
+ enum llhttp_errno err = llhttp_execute(parser, RSTRING_PTR(data), RSTRING_LEN(data));
141
+
142
+ if (err != HPE_OK) {
143
+ rb_raise(eError, "Error Parsing data: %s %s", llhttp_errno_name(err), parser->reason);
144
+ }
145
+
146
+ return Qtrue;
147
+ }
148
+
149
+ VALUE rb_llhttp_finish(VALUE self) {
150
+ llhttp_t *parser;
151
+
152
+ Data_Get_Struct(self, llhttp_t, parser);
153
+
154
+ enum llhttp_errno err = llhttp_finish(parser);
155
+
156
+ if (err != HPE_OK) {
157
+ rb_raise(eError, "Error Parsing data: %s %s", llhttp_errno_name(err), parser->reason);
158
+ }
159
+
160
+ return Qtrue;
161
+ }
162
+
163
+ VALUE rb_llhttp_content_length(VALUE self) {
164
+ llhttp_t *parser;
165
+
166
+ Data_Get_Struct(self, llhttp_t, parser);
167
+
168
+ return UINT2NUM(parser->content_length);
169
+ }
170
+
171
+ VALUE rb_llhttp_method(VALUE self) {
172
+ llhttp_t *parser;
173
+
174
+ Data_Get_Struct(self, llhttp_t, parser);
175
+
176
+ return rb_str_new_cstr(llhttp_method_name(parser->method));
177
+ }
178
+
179
+ VALUE rb_llhttp_status_code(VALUE self) {
180
+ llhttp_t *parser;
181
+
182
+ Data_Get_Struct(self, llhttp_t, parser);
183
+
184
+ return UINT2NUM(parser->status_code);
185
+ }
186
+
187
+ VALUE rb_llhttp_keep_alive(VALUE self) {
188
+ llhttp_t *parser;
189
+
190
+ Data_Get_Struct(self, llhttp_t, parser);
191
+
192
+ int ret = llhttp_should_keep_alive(parser);
193
+
194
+ return ret == 1 ? Qtrue : Qfalse;
195
+ }
196
+
197
+ static VALUE rb_llhttp_init(VALUE self, VALUE type) {
198
+ llhttp_t *parser;
199
+
200
+ Data_Get_Struct(self, llhttp_t, parser);
201
+
202
+ llhttp_settings_t *settings = parser->settings;
203
+
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;
214
+
215
+ llhttp_init(parser, FIX2INT(type), settings);
216
+
217
+ // Store a pointer to the delegate for lookup in callbacks.
218
+ //
219
+ VALUE delegate = rb_iv_get(self, "@delegate");
220
+ parser->data = (void*)delegate;
221
+
222
+ return Qtrue;
223
+ }
224
+
225
+ void Init_llhttp_ext(void) {
226
+ mLLHttp = rb_const_get(rb_cObject, rb_intern("LLHttp"));
227
+ cParser = rb_const_get(mLLHttp, rb_intern("Parser"));
228
+ eError = rb_const_get(mLLHttp, rb_intern("Error"));
229
+
230
+ rb_define_alloc_func(cParser, rb_llhttp_allocate);
231
+
232
+ rb_define_method(cParser, "<<", rb_llhttp_parse, 1);
233
+ rb_define_method(cParser, "parse", rb_llhttp_parse, 1);
234
+ rb_define_method(cParser, "finish", rb_llhttp_finish, 0);
235
+
236
+ rb_define_method(cParser, "content_length", rb_llhttp_content_length, 0);
237
+ rb_define_method(cParser, "method", rb_llhttp_method, 0);
238
+ rb_define_method(cParser, "status_code", rb_llhttp_status_code, 0);
239
+
240
+ rb_define_method(cParser, "keep_alive?", rb_llhttp_keep_alive, 0);
241
+
242
+ rb_define_private_method(cParser, "llhttp_init", rb_llhttp_init, 1);
243
+ }