1 /* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 #include "iotjs_def.h"
18 #include "iotjs_module_httpparser.h"
19 #include "iotjs_module_buffer.h"
25 #define THIS iotjs_httpparserwrap_t* httpparserwrap
28 static void iotjs_httpparserwrap_destroy(THIS);
31 iotjs_httpparserwrap_t* iotjs_httpparserwrap_create(const iotjs_jval_t* jparser,
32 http_parser_type type) {
33 iotjs_httpparserwrap_t* httpparserwrap = IOTJS_ALLOC(iotjs_httpparserwrap_t);
34 IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_httpparserwrap_t, httpparserwrap);
36 iotjs_jobjectwrap_initialize(&_this->jobjectwrap, jparser,
37 (JFreeHandlerType)iotjs_httpparserwrap_destroy);
39 _this->url = iotjs_string_create();
40 _this->status_msg = iotjs_string_create();
41 for (size_t i = 0; i < HEADER_MAX; i++) {
42 _this->fields[i] = iotjs_string_create();
43 _this->values[i] = iotjs_string_create();
46 iotjs_httpparserwrap_initialize(httpparserwrap, type);
47 _this->parser.data = httpparserwrap;
49 return httpparserwrap;
53 static void iotjs_httpparserwrap_destroy(THIS) {
54 IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_httpparserwrap_t, httpparserwrap);
56 iotjs_string_destroy(&_this->url);
57 iotjs_string_destroy(&_this->status_msg);
58 for (size_t i = 0; i < HEADER_MAX; i++) {
59 iotjs_string_destroy(&_this->fields[i]);
60 iotjs_string_destroy(&_this->values[i]);
62 iotjs_jobjectwrap_destroy(&_this->jobjectwrap);
64 IOTJS_RELEASE(httpparserwrap);
68 void iotjs_httpparserwrap_initialize(THIS, http_parser_type type) {
69 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
71 http_parser_init(&_this->parser, type);
72 iotjs_string_make_empty(&_this->url);
73 iotjs_string_make_empty(&_this->status_msg);
76 _this->flushed = false;
77 _this->cur_jbuf = NULL;
78 _this->cur_buf = NULL;
79 _this->cur_buf_len = 0;
83 // http-parser callbacks
84 static int iotjs_httpparserwrap_on_message_begin(http_parser* parser) {
85 iotjs_httpparserwrap_t* httpparserwrap =
86 (iotjs_httpparserwrap_t*)(parser->data);
87 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
88 iotjs_string_make_empty(&_this->url);
89 iotjs_string_make_empty(&_this->status_msg);
94 static int iotjs_httpparserwrap_on_url(http_parser* parser, const char* at,
96 iotjs_httpparserwrap_t* httpparserwrap =
97 (iotjs_httpparserwrap_t*)(parser->data);
98 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
99 iotjs_string_append(&_this->url, at, length);
104 static int iotjs_httpparserwrap_on_status(http_parser* parser, const char* at,
106 iotjs_httpparserwrap_t* httpparserwrap =
107 (iotjs_httpparserwrap_t*)(parser->data);
108 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
109 iotjs_string_append(&_this->status_msg, at, length);
114 static int iotjs_httpparserwrap_on_header_field(http_parser* parser,
115 const char* at, size_t length) {
116 iotjs_httpparserwrap_t* httpparserwrap =
117 (iotjs_httpparserwrap_t*)(parser->data);
118 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
119 if (_this->n_fields == _this->n_values) {
121 // values and fields are flushed to JS
122 // before corresponding OnHeaderValue is called.
123 if (_this->n_fields == HEADER_MAX) {
124 iotjs_httpparserwrap_flush(httpparserwrap); // to JS world
128 iotjs_string_make_empty(&_this->fields[_this->n_fields - 1]);
130 IOTJS_ASSERT(_this->n_fields == _this->n_values + 1);
131 iotjs_string_append(&_this->fields[_this->n_fields - 1], at, length);
137 static int iotjs_httpparserwrap_on_header_value(http_parser* parser,
138 const char* at, size_t length) {
139 iotjs_httpparserwrap_t* httpparserwrap =
140 (iotjs_httpparserwrap_t*)(parser->data);
141 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
142 if (_this->n_fields != _this->n_values) {
144 iotjs_string_make_empty(&_this->values[_this->n_values - 1]);
147 IOTJS_ASSERT(_this->n_fields == _this->n_values);
149 iotjs_string_append(&_this->values[_this->n_values - 1], at, length);
155 static int iotjs_httpparserwrap_on_headers_complete(http_parser* parser) {
156 iotjs_httpparserwrap_t* httpparserwrap =
157 (iotjs_httpparserwrap_t*)(parser->data);
158 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
160 const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap);
162 iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE);
163 IOTJS_ASSERT(iotjs_jval_is_function(&func));
166 iotjs_jargs_t argv = iotjs_jargs_create(1);
167 iotjs_jval_t info = iotjs_jval_create_object();
169 if (_this->flushed) {
170 // If some headers already are flushed,
171 // flush the remaining headers.
172 // In Flush function, url is already flushed to JS.
173 iotjs_httpparserwrap_flush(httpparserwrap);
175 // Here, there was no flushed header.
176 // We need to make a new header object with all header fields
177 iotjs_jval_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap);
178 iotjs_jval_set_property_jval(&info, IOTJS_MAGIC_STRING_HEADERS, &jheader);
179 iotjs_jval_destroy(&jheader);
180 if (_this->parser.type == HTTP_REQUEST) {
181 IOTJS_ASSERT(!iotjs_string_is_empty(&_this->url));
182 iotjs_jval_set_property_string(&info, IOTJS_MAGIC_STRING_URL,
186 _this->n_fields = _this->n_values = 0;
189 if (_this->parser.type == HTTP_REQUEST) {
190 iotjs_jval_set_property_number(&info, IOTJS_MAGIC_STRING_METHOD,
191 _this->parser.method);
195 if (_this->parser.type == HTTP_RESPONSE) {
196 iotjs_jval_set_property_number(&info, IOTJS_MAGIC_STRING_STATUS,
197 _this->parser.status_code);
198 iotjs_jval_set_property_string(&info, IOTJS_MAGIC_STRING_STATUS_MSG,
203 // For future support, current http_server module does not support
204 // upgrade and keepalive.
206 iotjs_jval_set_property_boolean(&info, IOTJS_MAGIC_STRING_UPGRADE,
207 _this->parser.upgrade);
209 iotjs_jval_set_property_boolean(&info, IOTJS_MAGIC_STRING_SHOULDKEEPALIVE,
210 http_should_keep_alive(&_this->parser));
213 iotjs_jargs_append_jval(&argv, &info);
215 iotjs_jval_t res = iotjs_make_callback_with_result(&func, jobj, &argv);
216 bool ret = iotjs_jval_as_boolean(&res);
218 iotjs_jargs_destroy(&argv);
219 iotjs_jval_destroy(&func);
220 iotjs_jval_destroy(&res);
221 iotjs_jval_destroy(&info);
227 static int iotjs_httpparserwrap_on_body(http_parser* parser, const char* at,
229 iotjs_httpparserwrap_t* httpparserwrap =
230 (iotjs_httpparserwrap_t*)(parser->data);
231 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
233 const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap);
234 iotjs_jval_t func = iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONBODY);
235 IOTJS_ASSERT(iotjs_jval_is_function(&func));
237 iotjs_jargs_t argv = iotjs_jargs_create(3);
238 iotjs_jargs_append_jval(&argv, _this->cur_jbuf);
239 iotjs_jargs_append_number(&argv, at - _this->cur_buf);
240 iotjs_jargs_append_number(&argv, length);
243 iotjs_make_callback(&func, jobj, &argv);
245 iotjs_jargs_destroy(&argv);
246 iotjs_jval_destroy(&func);
252 static int iotjs_httpparserwrap_on_message_complete(http_parser* parser) {
253 iotjs_httpparserwrap_t* httpparserwrap =
254 (iotjs_httpparserwrap_t*)(parser->data);
255 IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_httpparserwrap_t,
258 const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap);
260 iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE);
261 IOTJS_ASSERT(iotjs_jval_is_function(&func));
263 iotjs_make_callback(&func, jobj, iotjs_jargs_get_empty());
265 iotjs_jval_destroy(&func);
271 iotjs_jval_t iotjs_httpparserwrap_make_header(THIS) {
272 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
274 iotjs_jval_t jheader = iotjs_jval_create_array(_this->n_values * 2);
275 for (size_t i = 0; i < _this->n_values; i++) {
276 iotjs_jval_t f = iotjs_jval_create_string(&_this->fields[i]);
277 iotjs_jval_t v = iotjs_jval_create_string(&_this->values[i]);
278 iotjs_jval_set_property_by_index(&jheader, i * 2, &f);
279 iotjs_jval_set_property_by_index(&jheader, i * 2 + 1, &v);
280 iotjs_jval_destroy(&f);
281 iotjs_jval_destroy(&v);
287 void iotjs_httpparserwrap_flush(THIS) {
288 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
290 const iotjs_jval_t* jobj = iotjs_httpparserwrap_jobject(httpparserwrap);
292 iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERS);
293 IOTJS_ASSERT(iotjs_jval_is_function(&func));
295 iotjs_jargs_t argv = iotjs_jargs_create(2);
296 iotjs_jval_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap);
297 iotjs_jargs_append_jval(&argv, &jheader);
298 iotjs_jval_destroy(&jheader);
299 if (_this->parser.type == HTTP_REQUEST &&
300 !iotjs_string_is_empty(&_this->url)) {
301 iotjs_jargs_append_string(&argv, &_this->url);
304 iotjs_make_callback(&func, jobj, &argv);
306 iotjs_string_make_empty(&_this->url);
307 iotjs_jargs_destroy(&argv);
308 iotjs_jval_destroy(&func);
309 _this->flushed = true;
313 void iotjs_httpparserwrap_set_buf(THIS, iotjs_jval_t* jbuf, char* buf, int sz) {
314 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
315 _this->cur_jbuf = jbuf;
316 _this->cur_buf = buf;
317 _this->cur_buf_len = sz;
321 iotjs_jval_t* iotjs_httpparserwrap_jobject(THIS) {
322 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
324 return iotjs_jobjectwrap_jobject(&_this->jobjectwrap);
328 http_parser* iotjs_httpparserwrap_parser(THIS) {
329 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_httpparserwrap_t, httpparserwrap);
330 return &_this->parser;
337 const struct http_parser_settings settings = {
338 iotjs_httpparserwrap_on_message_begin,
339 iotjs_httpparserwrap_on_url,
340 iotjs_httpparserwrap_on_status,
341 iotjs_httpparserwrap_on_header_field,
342 iotjs_httpparserwrap_on_header_value,
343 iotjs_httpparserwrap_on_headers_complete,
344 iotjs_httpparserwrap_on_body,
345 iotjs_httpparserwrap_on_message_complete,
346 NULL, /* on_chunk_header */
347 NULL, /* on_chunk_complete */
351 static iotjs_httpparserwrap_t* get_parser_wrap(const iotjs_jval_t* jparser) {
352 uintptr_t handle = iotjs_jval_get_object_native_handle(jparser);
353 return (iotjs_httpparserwrap_t*)(handle);
357 JHANDLER_FUNCTION(Reinitialize) {
358 JHANDLER_CHECK_THIS(object);
359 JHANDLER_CHECK_ARGS(1, number);
361 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
363 http_parser_type httpparser_type =
364 (http_parser_type)(JHANDLER_GET_ARG(0, number));
365 IOTJS_ASSERT(httpparser_type == HTTP_REQUEST ||
366 httpparser_type == HTTP_RESPONSE);
368 iotjs_httpparserwrap_t* parser = get_parser_wrap(jparser);
369 iotjs_httpparserwrap_initialize(parser, httpparser_type);
373 JHANDLER_FUNCTION(Finish) {
374 JHANDLER_CHECK_THIS(object);
375 JHANDLER_CHECK_ARGS(0);
377 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
378 iotjs_httpparserwrap_t* parser = get_parser_wrap(jparser);
380 http_parser* nativeparser = iotjs_httpparserwrap_parser(parser);
381 int rv = http_parser_execute(nativeparser, &settings, NULL, 0);
384 enum http_errno err = HTTP_PARSER_ERRNO(nativeparser);
386 iotjs_jval_t eobj = iotjs_jval_create_error("Parse Error");
387 iotjs_jval_set_property_number(&eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0);
388 iotjs_jval_set_property_string_raw(&eobj, IOTJS_MAGIC_STRING_CODE,
389 http_errno_name(err));
390 iotjs_jhandler_return_jval(jhandler, &eobj);
391 iotjs_jval_destroy(&eobj);
396 JHANDLER_FUNCTION(Execute) {
397 JHANDLER_CHECK_THIS(object);
398 JHANDLER_CHECK_ARGS(1, object);
400 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
401 iotjs_httpparserwrap_t* parser = get_parser_wrap(jparser);
404 const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object);
405 iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
406 char* buf_data = iotjs_bufferwrap_buffer(buffer_wrap);
407 int buf_len = iotjs_bufferwrap_length(buffer_wrap);
408 JHANDLER_CHECK(buf_data != NULL);
409 JHANDLER_CHECK(buf_len > 0);
411 iotjs_httpparserwrap_set_buf(parser, (iotjs_jval_t*)jbuffer, buf_data,
414 http_parser* nativeparser = iotjs_httpparserwrap_parser(parser);
415 int nparsed = http_parser_execute(nativeparser, &settings, buf_data, buf_len);
417 iotjs_httpparserwrap_set_buf(parser, NULL, NULL, 0);
420 if (!nativeparser->upgrade && nparsed != buf_len) {
421 // nparsed should equal to buf_len except UPGRADE protocol
422 enum http_errno err = HTTP_PARSER_ERRNO(nativeparser);
423 iotjs_jval_t eobj = iotjs_jval_create_error("Parse Error");
424 iotjs_jval_set_property_number(&eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0);
425 iotjs_jval_set_property_string_raw(&eobj, IOTJS_MAGIC_STRING_CODE,
426 http_errno_name(err));
427 iotjs_jhandler_return_jval(jhandler, &eobj);
428 iotjs_jval_destroy(&eobj);
430 iotjs_jhandler_return_number(jhandler, nparsed);
435 JHANDLER_FUNCTION(Pause) {
436 JHANDLER_CHECK_THIS(object);
437 JHANDLER_CHECK_ARGS(0);
438 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
439 iotjs_httpparserwrap_t* parser = get_parser_wrap(jparser);
440 http_parser* nativeparser = iotjs_httpparserwrap_parser(parser);
441 http_parser_pause(nativeparser, 1);
445 JHANDLER_FUNCTION(Resume) {
446 JHANDLER_CHECK_THIS(object);
447 JHANDLER_CHECK_ARGS(0);
448 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
449 iotjs_httpparserwrap_t* parser = get_parser_wrap(jparser);
450 http_parser* nativeparser = iotjs_httpparserwrap_parser(parser);
451 http_parser_pause(nativeparser, 0);
455 JHANDLER_FUNCTION(HTTPParserCons) {
456 JHANDLER_CHECK_THIS(object);
457 JHANDLER_CHECK_ARGS(1, number);
459 const iotjs_jval_t* jparser = JHANDLER_GET_THIS(object);
461 http_parser_type httpparser_type =
462 (http_parser_type)(JHANDLER_GET_ARG(0, number));
463 IOTJS_ASSERT(httpparser_type == HTTP_REQUEST ||
464 httpparser_type == HTTP_RESPONSE);
465 iotjs_httpparserwrap_t* parser =
466 iotjs_httpparserwrap_create(jparser, httpparser_type);
467 IOTJS_ASSERT(iotjs_jval_is_object(iotjs_httpparserwrap_jobject(parser)));
468 IOTJS_ASSERT(get_parser_wrap(jparser) == parser);
472 iotjs_jval_t InitHttpparser() {
473 iotjs_jval_t httpparser = iotjs_jval_create_object();
475 iotjs_jval_t jParserCons =
476 iotjs_jval_create_function_with_dispatch(HTTPParserCons);
477 iotjs_jval_set_property_jval(&httpparser, IOTJS_MAGIC_STRING_HTTPPARSER,
480 iotjs_jval_set_property_number(&jParserCons, IOTJS_MAGIC_STRING_REQUEST,
482 iotjs_jval_set_property_number(&jParserCons, IOTJS_MAGIC_STRING_RESPONSE,
485 iotjs_jval_t methods = iotjs_jval_create_object();
486 #define V(num, name, string) \
487 iotjs_jval_set_property_string_raw(&methods, #num, #string);
491 iotjs_jval_set_property_jval(&jParserCons, IOTJS_MAGIC_STRING_METHODS,
494 iotjs_jval_t prototype = iotjs_jval_create_object();
496 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_EXECUTE, Execute);
497 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_REINITIALIZE,
499 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_FINISH, Finish);
500 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_PAUSE, Pause);
501 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RESUME, Resume);
503 iotjs_jval_set_property_jval(&jParserCons, IOTJS_MAGIC_STRING_PROTOTYPE,
506 iotjs_jval_destroy(&jParserCons);
507 iotjs_jval_destroy(&methods);
508 iotjs_jval_destroy(&prototype);