diff options
author | Max Romanov <max.romanov@nginx.com> | 2019-04-01 16:40:33 +0300 |
---|---|---|
committer | Max Romanov <max.romanov@nginx.com> | 2019-04-01 16:40:33 +0300 |
commit | aca42de18ad9877db7e4a7f598a4c5cb55644fe8 (patch) | |
tree | 298e98c7e5163f2d87afeaebe056638247de1a90 /src/nodejs/unit-http | |
parent | 19eba1730a1ca839ed62a37f34c204f580d1b653 (diff) | |
download | unit-aca42de18ad9877db7e4a7f598a4c5cb55644fe8.tar.gz unit-aca42de18ad9877db7e4a7f598a4c5cb55644fe8.tar.bz2 |
Adding syntax sugar.
With exceptions and overloads.
Diffstat (limited to '')
-rw-r--r-- | src/nodejs/unit-http/binding.gyp | 9 | ||||
-rw-r--r-- | src/nodejs/unit-http/binding_pub.gyp | 9 | ||||
-rw-r--r-- | src/nodejs/unit-http/nxt_napi.h | 656 | ||||
-rw-r--r-- | src/nodejs/unit-http/unit.cpp | 827 | ||||
-rw-r--r-- | src/nodejs/unit-http/unit.h | 35 |
5 files changed, 882 insertions, 654 deletions
diff --git a/src/nodejs/unit-http/binding.gyp b/src/nodejs/unit-http/binding.gyp index ee09bfed..55d965bd 100644 --- a/src/nodejs/unit-http/binding.gyp +++ b/src/nodejs/unit-http/binding.gyp @@ -1,6 +1,15 @@ { 'targets': [{ 'target_name': "unit-http", + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' + } + }] + ], 'sources': ["unit.cpp", "addon.cpp"], 'include_dirs': [ "<!(echo $UNIT_SRC_PATH)", "<!(echo $UNIT_BUILD_PATH)" diff --git a/src/nodejs/unit-http/binding_pub.gyp b/src/nodejs/unit-http/binding_pub.gyp index 6fe3d9bc..3c39933a 100644 --- a/src/nodejs/unit-http/binding_pub.gyp +++ b/src/nodejs/unit-http/binding_pub.gyp @@ -1,6 +1,15 @@ { 'targets': [{ 'target_name': "unit-http", + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' + } + }] + ], 'sources': ["unit.cpp", "addon.cpp"], 'libraries': ["-lunit"] }] diff --git a/src/nodejs/unit-http/nxt_napi.h b/src/nodejs/unit-http/nxt_napi.h new file mode 100644 index 00000000..9bcf3a21 --- /dev/null +++ b/src/nodejs/unit-http/nxt_napi.h @@ -0,0 +1,656 @@ + +/* + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_NODEJS_NAPI_H_INCLUDED_ +#define _NXT_NODEJS_NAPI_H_INCLUDED_ + +#include <node_api.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "version.h" +#include <nxt_unit.h> + +#if NXT_VERNUM != NXT_NODE_VERNUM +#error "libunit version mismatch." +#endif + +#include <nxt_unit_response.h> +#include <nxt_unit_request.h> + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +struct nxt_napi { + + struct exception { + exception(const char *s) : str(s) { } + + const char *str; + }; + + + nxt_napi(napi_env env) : env_(env) { } + + + inline napi_value + coerce_to_string(napi_value val) + { + napi_value res; + napi_status status; + + status = napi_coerce_to_string(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to coerce to string"); + } + + return res; + } + + + inline napi_value + create_buffer(size_t size, void **data) + { + napi_value res; + napi_status status; + + status = napi_create_buffer(env_, size, data, &res); + if (status != napi_ok) { + throw exception("Failed to create buffer"); + } + + return res; + } + + + inline napi_value + create_function(const char *name, size_t len, napi_callback cb, void *data) + { + napi_value res; + napi_status status; + + status = napi_create_function(env_, name, len, cb, data, &res); + if (status != napi_ok) { + throw exception("Failed to create function"); + } + + return res; + } + + + inline napi_value + create_function(napi_callback cb) + { + return create_function(NULL, 0, cb, NULL); + } + + + inline napi_value + create_object() + { + napi_value res; + napi_status status; + + status = napi_create_object(env_, &res); + if (status != napi_ok) { + throw exception("Failed to create object"); + } + + return res; + } + + + inline napi_ref + create_reference(napi_value val, int ref_count = 1) + { + napi_ref res; + napi_status status; + + status = napi_create_reference(env_, val, ref_count, &res); + if (status != napi_ok) { + throw exception("Failed to create reference"); + } + + return res; + } + + + inline napi_value + create_string_latin1(const char *str, size_t len) + { + napi_value res; + napi_status status; + + status = napi_create_string_latin1(env_, str, len, &res); + if (status != napi_ok) { + throw exception("Failed to create latin1 string"); + } + + return res; + } + + + inline napi_value + create_string_latin1(nxt_unit_sptr_t &str, size_t len) + { + const char *p; + + p = (const char *) nxt_unit_sptr_get(&str); + + return create_string_latin1(p, len); + } + + + inline napi_value + define_class(const char *name, napi_callback ctor, size_t prop_count, + const napi_property_descriptor* props) + { + napi_value res; + napi_status status; + + status = napi_define_class(env_, name, NAPI_AUTO_LENGTH, ctor, nullptr, + prop_count, props, &res); + if (status != napi_ok) { + throw exception("Failed to define class"); + } + + return res; + } + + + inline void + delete_reference(napi_ref ref) + { + napi_delete_reference(env_, ref); + } + + + inline uint32_t + get_array_length(napi_value val) + { + uint32_t res; + napi_status status; + + status = napi_get_array_length(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get array length"); + } + + return res; + } + + + inline napi_value + get_cb_info(napi_callback_info info, size_t &argc, napi_value *argv) + { + napi_value res; + napi_status status; + + status = napi_get_cb_info(env_, info, &argc, argv, &res, nullptr); + if (status != napi_ok) { + throw exception("Failed to get arguments from js"); + } + + return res; + } + + + inline napi_value + get_cb_info(napi_callback_info info) + { + napi_value res; + napi_status status; + + status = napi_get_cb_info(env_, info, nullptr, nullptr, &res, nullptr); + if (status != napi_ok) { + throw exception("Failed to get arguments from js"); + } + + return res; + } + + + inline napi_value + get_element(napi_value obj, uint32_t i) + { + napi_value res; + napi_status status; + + status = napi_get_element(env_, obj, i, &res); + if (status != napi_ok) { + throw exception("Failed to get element"); + } + + return res; + } + + + inline napi_value + get_named_property(napi_value obj, const char *name) + { + napi_value res; + napi_status status; + + status = napi_get_named_property(env_, obj, name, &res); + if (status != napi_ok) { + throw exception("Failed to get named property"); + } + + return res; + } + + + inline napi_value + get_new_target(napi_callback_info info) + { + napi_value res; + napi_status status; + + status = napi_get_new_target(env_, info, &res); + if (status != napi_ok) { + throw exception("Failed to get new target"); + } + + return res; + } + + + inline napi_value + get_property(napi_value val, napi_value key) + { + napi_value res; + napi_status status; + + status = napi_get_property(env_, val, key, &res); + if (status != napi_ok) { + throw exception("Failed to get property"); + } + + return res; + } + + + inline napi_value + get_property_names(napi_value val) + { + napi_value res; + napi_status status; + + status = napi_get_property_names(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get property names"); + } + + return res; + } + + + inline napi_value + get_reference_value(napi_ref ref) + { + napi_value res; + napi_status status; + + status = napi_get_reference_value(env_, ref, &res); + if (status != napi_ok) { + throw exception("Failed to get reference value"); + } + + return res; + } + + + inline nxt_unit_request_info_t * + get_request_info(napi_value obj) + { + int64_t n; + napi_status status; + + status = napi_get_value_int64(env_, obj, &n); + if (status != napi_ok) { + throw exception("Failed to get request pointer"); + } + + return (nxt_unit_request_info_t *) (intptr_t) n; + } + + + inline size_t + get_value_string_latin1(napi_value val, char *buf, size_t bufsize) + { + size_t res; + napi_status status; + + status = napi_get_value_string_latin1(env_, val, buf, bufsize, &res); + if (status != napi_ok) { + throw exception("Failed to get string latin1"); + } + + return res; + } + + + inline uint32_t + get_value_uint32(napi_value obj) + { + uint32_t res; + napi_status status; + + status = napi_get_value_uint32(env_, obj, &res); + if (status != napi_ok) { + throw exception("Failed to get uint32_t"); + } + + return res; + } + + + inline bool + is_array(napi_value val) + { + bool res; + napi_status status; + + status = napi_is_array(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to confirm value is array"); + } + + return res; + } + + + inline napi_value + make_callback(napi_async_context ctx, napi_value val, napi_value func, + int argc, const napi_value *argv) + { + napi_value res, ex; + napi_status status; + + status = napi_make_callback(env_, ctx, val, func, argc, argv, &res); + if (status != napi_ok) { + if (status != napi_pending_exception) { + throw exception("Failed to make callback"); + } + + status = napi_get_and_clear_last_exception(env_, &ex); + if (status != napi_ok) { + throw exception("Failed to get and clear last exception"); + } + + /* Logging a description of the error and call stack. */ + status = napi_fatal_exception(env_, ex); + if (status != napi_ok) { + throw exception("Failed napi_fatal_exception()"); + } + } + + return res; + } + + + inline napi_value + new_instance(napi_value ctor) + { + napi_value res; + napi_status status; + + status = napi_new_instance(env_, ctor, 0, NULL, &res); + if (status != napi_ok) { + throw exception("Failed to create instance"); + } + + return res; + } + + + inline napi_value + new_instance(napi_value ctor, napi_value param) + { + napi_value res; + napi_status status; + + status = napi_new_instance(env_, ctor, 1, ¶m, &res); + if (status != napi_ok) { + throw exception("Failed to create instance"); + } + + return res; + } + + + inline void + set_element(napi_value obj, uint32_t i, napi_value val) + { + napi_status status; + + status = napi_set_element(env_, obj, i, val); + if (status != napi_ok) { + throw exception("Failed to set element"); + } + } + + + inline void + set_named_property(napi_value obj, const char *name, napi_value val) + { + napi_status status; + + status = napi_set_named_property(env_, obj, name, val); + if (status != napi_ok) { + throw exception("Failed to set named property"); + } + } + + + inline void + set_named_property(napi_value obj, const char *name, napi_callback cb) + { + set_named_property(obj, name, create_function(cb)); + } + + + inline napi_value + set_named_property(napi_value obj, const char *name, nxt_unit_sptr_t &val, + size_t len) + { + napi_value str; + + str = create_string_latin1(val, len); + + set_named_property(obj, name, str); + + return str; + } + + + inline void + set_named_property(napi_value obj, const char *name, intptr_t val) + { + napi_value ptr; + napi_status status; + + status = napi_create_int64(env_, val, &ptr); + if (status != napi_ok) { + throw exception("Failed to create int64"); + } + + set_named_property(obj, name, ptr); + } + + + inline void + throw_error(const char *str) + { + napi_throw_error(env_, NULL, str); + } + + + inline void + throw_error(const exception &e) + { + napi_throw_error(env_, NULL, e.str); + } + + + inline napi_valuetype + type_of(napi_value val) + { + napi_status status; + napi_valuetype res; + + status = napi_typeof(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get typeof"); + } + + return res; + } + + + inline void * + unwrap(napi_value val) + { + void *res; + napi_status status; + + status = napi_unwrap(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to unwrap"); + } + + return res; + } + + + inline napi_ref + wrap(napi_value val, void *obj, napi_finalize fin_cb, void *hint = nullptr) + { + napi_ref res; + napi_status status; + + status = napi_wrap(env_, val, obj, fin_cb, hint, &res); + if (status != napi_ok) { + throw exception("Failed to wrap"); + } + + return res; + } + + + inline + operator napi_env() + { + return env_; + } + + + napi_env env() + { + return env_; + } + +private: + napi_env env_; +}; + + +struct nxt_handle_scope : public nxt_napi { + nxt_handle_scope(napi_env env) : nxt_napi(env) + { + napi_status status; + + status = napi_open_handle_scope(env, &scope_); + if (status != napi_ok) { + throw exception("Failed to open handle scope"); + } + } + + ~nxt_handle_scope() + { + napi_status status; + + status = napi_close_handle_scope(env(), scope_); + if (status != napi_ok) { + throw_error("Failed to close handle scope"); + } + } + +private: + napi_handle_scope scope_; +}; + + +struct nxt_async_context : public nxt_napi { + nxt_async_context(napi_env env, const char *name) : + nxt_napi(env) + { + napi_value name_val; + napi_status status; + + name_val = create_string_latin1(name, NAPI_AUTO_LENGTH); + + status = napi_async_init(env, NULL, name_val, &context_); + if (status != napi_ok) { + throw exception("Failed to init async object"); + } + } + + operator napi_async_context() { + return context_; + } + + ~nxt_async_context() + { + napi_status status; + + status = napi_async_destroy(env(), context_); + if (status != napi_ok) { + throw_error("Failed to destroy async object"); + } + } + +private: + napi_async_context context_; +}; + + +struct nxt_callback_scope : public nxt_napi { + nxt_callback_scope(nxt_async_context& ctx) : + nxt_napi(ctx.env()) + { + napi_value resource; + napi_status status; + + resource = create_object(); + + status = napi_open_callback_scope(env(), resource, ctx, &scope_); + if (status != napi_ok) { + throw exception("Failed to open callback scope"); + } + } + + ~nxt_callback_scope() + { + napi_status status; + + status = napi_close_callback_scope(env(), scope_); + if (status != napi_ok) { + throw_error("Failed to close callback scope"); + } + } + +private: + napi_callback_scope scope_; +}; + + +#endif /* _NXT_NODEJS_NAPI_H_INCLUDED_ */ diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index dcff1186..e4072851 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -20,9 +20,9 @@ struct nxt_nodejs_ctx_t { }; -Unit::Unit(napi_env env): - env_(env), - wrapper_(nullptr), +Unit::Unit(napi_env env, napi_value jsthis): + nxt_napi(env), + wrapper_(wrap(jsthis, this, destroy)), unit_ctx_(nullptr) { } @@ -30,15 +30,15 @@ Unit::Unit(napi_env env): Unit::~Unit() { - napi_delete_reference(env_, wrapper_); + delete_reference(wrapper_); } napi_value Unit::init(napi_env env, napi_value exports) { - napi_value cons, fn; - napi_status status; + nxt_napi napi(env); + napi_value cons; napi_property_descriptor properties[] = { { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, @@ -46,61 +46,22 @@ Unit::init(napi_env env, napi_value exports) { "_read", 0, _read, 0, 0, 0, napi_default, 0 } }; - status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr, - 3, properties, &cons); - if (status != napi_ok) { - goto failed; - } + try { + cons = napi.define_class("Unit", create, 3, properties); + constructor_ = napi.create_reference(cons); - status = napi_create_reference(env, cons, 1, &constructor_); - if (status != napi_ok) { - goto failed; - } + napi.set_named_property(exports, "Unit", cons); + napi.set_named_property(exports, "unit_response_headers", + response_send_headers); + napi.set_named_property(exports, "unit_response_write", response_write); + napi.set_named_property(exports, "unit_response_end", response_end); - status = napi_set_named_property(env, exports, "Unit", cons); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_send_headers, NULL, - &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, - "unit_response_headers", fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_write, NULL, &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, "unit_response_write", fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_end, NULL, &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, "unit_response_end", fn); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } return exports; - -failed: - - napi_throw_error(env, NULL, "Failed to define Unit class"); - - return nullptr; } @@ -116,63 +77,36 @@ Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) napi_value Unit::create(napi_env env, napi_callback_info info) { - Unit *obj; - napi_ref ref; - napi_value target, cons, instance, jsthis; - napi_status status; + Unit *obj; + nxt_napi napi(env); + napi_ref ref; + napi_value target, cons, instance, jsthis; - status = napi_get_new_target(env, info, &target); - if (status != napi_ok) { - goto failed; - } + try { + target = napi.get_new_target(info); - if (target != nullptr) { - /* Invoked as constructor: `new Unit(...)` */ - status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, - nullptr); - if (status != napi_ok) { - goto failed; - } + if (target != nullptr) { + /* Invoked as constructor: `new Unit(...)`. */ + jsthis = napi.get_cb_info(info); - obj = new Unit(env); + obj = new Unit(env, jsthis); - status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj), - destroy, nullptr, &obj->wrapper_); - if (status != napi_ok) { - goto failed; - } + ref = napi.create_reference(jsthis); - status = napi_create_reference(env, jsthis, 1, &ref); - if (status != napi_ok) { - goto failed; + return jsthis; } - return jsthis; - } - - /* Invoked as plain function `Unit(...)`, turn into construct call. */ - status = napi_get_reference_value(env, constructor_, &cons); - if (status != napi_ok) { - goto failed; - } - - status = napi_new_instance(env, cons, 0, nullptr, &instance); - if (status != napi_ok) { - goto failed; - } + /* Invoked as plain function `Unit(...)`, turn into construct call. */ + cons = napi.get_reference_value(constructor_); + instance = napi.new_instance(cons); + ref = napi.create_reference(instance); - status = napi_create_reference(env, instance, 1, &ref); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } return instance; - -failed: - - napi_throw_error(env, NULL, "Failed to create Unit object"); - - return nullptr; } @@ -181,20 +115,19 @@ Unit::create_server(napi_env env, napi_callback_info info) { Unit *obj; size_t argc; + nxt_napi napi(env); napi_value jsthis, argv; - napi_status status; nxt_unit_init_t unit_init; argc = 1; - status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); - if (status != napi_ok) { - goto failed; - } + try { + jsthis = napi.get_cb_info(info, argc, &argv); + obj = (Unit *) napi.unwrap(jsthis); - status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } memset(&unit_init, 0, sizeof(nxt_unit_init_t)); @@ -230,40 +163,22 @@ Unit::listen(napi_env env, napi_callback_info info) napi_value Unit::_read(napi_env env, napi_callback_info info) { - Unit *obj; void *data; size_t argc; - int64_t req_pointer; + nxt_napi napi(env); napi_value jsthis, buffer, argv; - napi_status status; nxt_unit_request_info_t *req; argc = 1; - status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get arguments from js"); - return nullptr; - } - - status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get Unit object form js"); - return nullptr; - } - - status = napi_get_value_int64(env, argv, &req_pointer); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + try { + jsthis = napi.get_cb_info(info, argc, &argv); - req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer; + req = napi.get_request_info(argv); + buffer = napi.create_buffer((size_t) req->content_length, &data); - status = napi_create_buffer(env, (size_t) req->content_length, - &data, &buffer); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to create request buffer"); + } catch (exception &e) { + napi.throw_error(e); return nullptr; } @@ -276,138 +191,38 @@ Unit::_read(napi_env env, napi_callback_info info) void Unit::request_handler(nxt_unit_request_info_t *req) { - Unit *obj; - napi_value socket, request, response, global, server_obj, except; - napi_value emit_events, events_res, async_name, resource_object; - napi_status status; - napi_async_context async_context; - napi_callback_scope async_scope; - napi_value events_args[3]; + Unit *obj; + napi_value socket, request, response, server_obj; + napi_value emit_events; + napi_value events_args[3]; obj = reinterpret_cast<Unit *>(req->unit->data); - napi_handle_scope scope; - status = napi_open_handle_scope(obj->env_, &scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create handle scope"); - return; - } + try { + nxt_handle_scope scope(obj->env()); - server_obj = obj->get_server_object(); - if (server_obj == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to get server object"); - return; - } + server_obj = obj->get_server_object(); - status = napi_get_global(obj->env_, &global); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get global variable"); - return; - } + socket = obj->create_socket(server_obj, req); + request = obj->create_request(server_obj, socket); + response = obj->create_response(server_obj, socket, request, req); - socket = obj->create_socket(server_obj, req); - if (socket == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create socket object"); - return; - } + obj->create_headers(req, request); - request = obj->create_request(server_obj, socket); - if (request == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create request object"); - return; - } + emit_events = obj->get_named_property(server_obj, "emit_events"); - response = obj->create_response(server_obj, socket, request, req, obj); - if (response == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create response object"); - return; - } - - status = obj->create_headers(req, request); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create headers"); - return; - } - - status = napi_get_named_property(obj->env_, server_obj, "emit_events", - &emit_events); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get " - "'emit_events' function"); - return; - } + events_args[0] = server_obj; + events_args[1] = request; + events_args[2] = response; - events_args[0] = server_obj; - events_args[1] = request; - events_args[2] = response; + nxt_async_context async_context(obj->env(), "unit_request_handler"); + nxt_callback_scope async_scope(async_context); - status = napi_create_string_utf8(obj->env_, "unit_request_handler", - sizeof("unit_request_handler") - 1, - &async_name); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create utf-8 string"); - return; - } + obj->make_callback(async_context, server_obj, emit_events, + 3, events_args); - status = napi_async_init(obj->env_, NULL, async_name, &async_context); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to init async object"); - return; - } - - status = napi_create_object(obj->env_, &resource_object); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create object for " - "callback scope"); - return; - } - - status = napi_open_callback_scope(obj->env_, resource_object, async_context, - &async_scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to open callback scope"); - return; - } - - status = napi_make_callback(obj->env_, async_context, server_obj, - emit_events, 3, events_args, &events_res); - if (status != napi_ok) { - if (status != napi_pending_exception) { - napi_throw_error(obj->env_, NULL, "Failed to make callback"); - return; - } - - status = napi_get_and_clear_last_exception(obj->env_, &except); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, - "Failed to get and clear last exception"); - return; - } - - /* Logging a description of the error and call stack. */ - status = napi_fatal_exception(obj->env_, except); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to call " - "napi_fatal_exception() function"); - return; - } - } - - status = napi_close_callback_scope(obj->env_, async_scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to close callback scope"); - return; - } - - status = napi_async_destroy(obj->env_, async_context); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to destroy async object"); - return; - } - - status = napi_close_handle_scope(obj->env_, scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to close handle scope"); + } catch (exception &e) { + obj->throw_error(e); } } @@ -432,14 +247,14 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) obj = reinterpret_cast<Unit *>(ctx->unit->data); if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { - napi_throw_error(obj->env_, NULL, "Failed to upgrade read" + obj->throw_error("Failed to upgrade read" " file descriptor to O_NONBLOCK"); return -1; } - status = napi_get_uv_event_loop(obj->env_, &loop); + status = napi_get_uv_event_loop(obj->env(), &loop); if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get uv.loop"); + obj->throw_error("Failed to get uv.loop"); return NXT_UNIT_ERROR; } @@ -447,13 +262,13 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); if (err < 0) { - napi_throw_error(obj->env_, NULL, "Failed to init uv.poll"); + obj->throw_error("Failed to init uv.poll"); return NXT_UNIT_ERROR; } err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); if (err < 0) { - napi_throw_error(obj->env_, NULL, "Failed to start uv.poll"); + obj->throw_error("Failed to start uv.poll"); return NXT_UNIT_ERROR; } @@ -505,173 +320,71 @@ Unit::quit(nxt_unit_ctx_t *ctx) napi_value Unit::get_server_object() { - napi_value unit_obj, server_obj; - napi_status status; + napi_value unit_obj; - status = napi_get_reference_value(env_, wrapper_, &unit_obj); - if (status != napi_ok) { - return nullptr; - } - - status = napi_get_named_property(env_, unit_obj, "server", &server_obj); - if (status != napi_ok) { - return nullptr; - } + unit_obj = get_reference_value(wrapper_); - return server_obj; + return get_named_property(unit_obj, "server"); } -napi_status +void Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) { uint32_t i; - const char *p; - napi_value headers, raw_headers, str; + napi_value headers, raw_headers; napi_status status; - nxt_unit_field_t *f; nxt_unit_request_t *r; r = req->request; - status = napi_create_object(env_, &headers); - if (status != napi_ok) { - return status; - } + headers = create_object(); - status = napi_create_array_with_length(env_, r->fields_count * 2, + status = napi_create_array_with_length(env(), r->fields_count * 2, &raw_headers); if (status != napi_ok) { - return status; + throw exception("Failed to create array"); } for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - status = this->append_header(f, headers, raw_headers, i); - if (status != napi_ok) { - return status; - } - } - - status = napi_set_named_property(env_, request, "headers", headers); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "rawHeaders", raw_headers); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->version); - - status = napi_create_string_latin1(env_, p, r->version_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "httpVersion", str); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->method); - - status = napi_create_string_latin1(env_, p, r->method_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "method", str); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->target); - - status = napi_create_string_latin1(env_, p, r->target_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "url", str); - if (status != napi_ok) { - return status; + append_header(r->fields + i, headers, raw_headers, i); } - return napi_ok; + set_named_property(request, "headers", headers); + set_named_property(request, "rawHeaders", raw_headers); + set_named_property(request, "httpVersion", r->version, r->version_length); + set_named_property(request, "method", r->method, r->method_length); + set_named_property(request, "url", r->target, r->target_length); } -inline napi_status +inline void Unit::append_header(nxt_unit_field_t *f, napi_value headers, - napi_value raw_headers, uint32_t idx) + napi_value raw_headers, uint32_t idx) { - const char *name, *value; + const char *name; napi_value str, vstr; - napi_status status; - - value = (const char *) nxt_unit_sptr_get(&f->value); - - status = napi_create_string_latin1(env_, value, f->value_length, &vstr); - if (status != napi_ok) { - return status; - } name = (const char *) nxt_unit_sptr_get(&f->name); - status = napi_set_named_property(env_, headers, name, vstr); - if (status != napi_ok) { - return status; - } + vstr = set_named_property(headers, name, f->value, f->value_length); + str = create_string_latin1(name, f->name_length); - status = napi_create_string_latin1(env_, name, f->name_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_element(env_, raw_headers, idx * 2, str); - if (status != napi_ok) { - return status; - } - - status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr); - if (status != napi_ok) { - return status; - } - - return napi_ok; + set_element(raw_headers, idx * 2, str); + set_element(raw_headers, idx * 2 + 1, vstr); } napi_value Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) { - napi_value constructor, return_val, req_pointer; - napi_status status; + napi_value constructor, return_val; - status = napi_get_named_property(env_, server_obj, "socket", - &constructor); - if (status != napi_ok) { - return nullptr; - } - - status = napi_new_instance(env_, constructor, 0, NULL, &return_val); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "socket"); - status = napi_create_int64(env_, (uintptr_t) req, &req_pointer); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor); - status = napi_set_named_property(env_, return_val, "req_pointer", - req_pointer); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "req_pointer", (intptr_t) req); return return_val; } @@ -680,25 +393,13 @@ Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) napi_value Unit::create_request(napi_value server_obj, napi_value socket) { - napi_value constructor, return_val; - napi_status status; + napi_value constructor, return_val; - status = napi_get_named_property(env_, server_obj, "request", - &constructor); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "request"); - status = napi_new_instance(env_, constructor, 1, &server_obj, - &return_val); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor, server_obj); - status = napi_set_named_property(env_, return_val, "socket", socket); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "socket", socket); return return_val; } @@ -706,37 +407,16 @@ Unit::create_request(napi_value server_obj, napi_value socket) napi_value Unit::create_response(napi_value server_obj, napi_value socket, - napi_value request, nxt_unit_request_info_t *req, - Unit *obj) + napi_value request, nxt_unit_request_info_t *req) { - napi_value constructor, return_val, req_num; - napi_status status; - - status = napi_get_named_property(env_, server_obj, "response", - &constructor); - if (status != napi_ok) { - return nullptr; - } + napi_value constructor, return_val; - status = napi_new_instance(env_, constructor, 1, &request, &return_val); - if (status != napi_ok) { - return nullptr; - } - - status = napi_set_named_property(env_, return_val, "socket", socket); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "response"); - status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor, request); - status = napi_set_named_property(env_, return_val, "_req_point", req_num); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "socket", socket); + set_named_property(return_val, "_req_point", (intptr_t) req); return return_val; } @@ -749,13 +429,12 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) char *ptr, *name_ptr; bool is_array; size_t argc, name_len, value_len; - int64_t req_p; uint32_t status_code, header_len, keys_len, array_len; uint32_t keys_count, i, j; uint16_t hash; + nxt_napi napi(env); napi_value this_arg, headers, keys, name, value, array_val; napi_value req_num, array_entry; - napi_status status; napi_valuetype val_type; nxt_unit_field_t *f; nxt_unit_request_info_t *req; @@ -763,137 +442,97 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) argc = 5; - status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); - if (status != napi_ok) { - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, argv); + if (argc != 5) { + napi.throw_error("Wrong args count. Expected: " + "statusCode, headers, headers count, " + "headers length"); + return nullptr; + } - if (argc != 5) { - napi_throw_error(env, NULL, "Wrong args count. Need three: " - "statusCode, headers, headers count, headers length"); - return nullptr; - } + req_num = napi.get_named_property(argv[0], "_req_point"); - status = napi_get_named_property(env, argv[0], "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req = napi.get_request_info(req_num); - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + status_code = napi.get_value_uint32(argv[1]); + keys_count = napi.get_value_uint32(argv[3]); + header_len = napi.get_value_uint32(argv[4]); - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; + /* Need to reserve extra byte for C-string 0-termination. */ + header_len++; - status = napi_get_value_uint32(env, argv[1], &status_code); - if (status != napi_ok) { - goto failed; - } + headers = argv[2]; - status = napi_get_value_uint32(env, argv[3], &keys_count); - if (status != napi_ok) { - goto failed; - } + ret = nxt_unit_response_init(req, status_code, keys_count, header_len); + if (ret != NXT_UNIT_OK) { + napi.throw_error("Failed to create response"); + return nullptr; + } - status = napi_get_value_uint32(env, argv[4], &header_len); - if (status != napi_ok) { - goto failed; - } + keys = napi.get_property_names(headers); + keys_len = napi.get_array_length(keys); - /* Need to reserve extra byte for C-string 0-termination. */ - header_len++; + ptr = req->response_buf->free; - headers = argv[2]; + for (i = 0; i < keys_len; i++) { + name = napi.get_element(keys, i); - ret = nxt_unit_response_init(req, status_code, keys_count, header_len); - if (ret != NXT_UNIT_OK) { - goto failed; - } + array_entry = napi.get_property(headers, name); - status = napi_get_property_names(env, headers, &keys); - if (status != napi_ok) { - goto failed; - } + name = napi.get_element(array_entry, 0); + value = napi.get_element(array_entry, 1); - status = napi_get_array_length(env, keys, &keys_len); - if (status != napi_ok) { - goto failed; - } + name_len = napi.get_value_string_latin1(name, ptr, header_len); + name_ptr = ptr; - ptr = req->response_buf->free; + ptr += name_len; + header_len -= name_len; - for (i = 0; i < keys_len; i++) { - status = napi_get_element(env, keys, i, &name); - if (status != napi_ok) { - goto failed; - } + hash = nxt_unit_field_hash(name_ptr, name_len); - status = napi_get_property(env, headers, name, &array_entry); - if (status != napi_ok) { - goto failed; - } + is_array = napi.is_array(value); - status = napi_get_element(env, array_entry, 0, &name); - if (status != napi_ok) { - goto failed; - } + if (is_array) { + array_len = napi.get_array_length(value); - status = napi_get_element(env, array_entry, 1, &value); - if (status != napi_ok) { - goto failed; - } + for (j = 0; j < array_len; j++) { + array_val = napi.get_element(value, j); - status = napi_get_value_string_latin1(env, name, ptr, header_len, - &name_len); - if (status != napi_ok) { - goto failed; - } + val_type = napi.type_of(array_val); - name_ptr = ptr; + if (val_type != napi_string) { + array_val = napi.coerce_to_string(array_val); + } - ptr += name_len; - header_len -= name_len; + value_len = napi.get_value_string_latin1(array_val, ptr, + header_len); - hash = nxt_unit_field_hash(name_ptr, name_len); + f = req->response->fields + req->response->fields_count; + f->skip = 0; - status = napi_is_array(env, value, &is_array); - if (status != napi_ok) { - goto failed; - } + nxt_unit_sptr_set(&f->name, name_ptr); - if (is_array) { - status = napi_get_array_length(env, value, &array_len); - if (status != napi_ok) { - goto failed; - } + f->name_length = name_len; + f->hash = hash; - for (j = 0; j < array_len; j++) { - status = napi_get_element(env, value, j, &array_val); - if (status != napi_ok) { - goto failed; - } + nxt_unit_sptr_set(&f->value, ptr); + f->value_length = (uint32_t) value_len; + + ptr += value_len; + header_len -= value_len; - napi_typeof(env, array_val, &val_type); - if (status != napi_ok) { - goto failed; + req->response->fields_count++; } + } else { + val_type = napi.type_of(value); + if (val_type != napi_string) { - status = napi_coerce_to_string(env, array_val, &array_val); - if (status != napi_ok) { - goto failed; - } + value = napi.coerce_to_string(value); } - status = napi_get_value_string_latin1(env, array_val, ptr, - header_len, - &value_len); - if (status != napi_ok) { - goto failed; - } + value_len = napi.get_value_string_latin1(value, ptr, header_len); f = req->response->fields + req->response->fields_count; f->skip = 0; @@ -911,60 +550,22 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) req->response->fields_count++; } - - } else { - napi_typeof(env, value, &val_type); - if (status != napi_ok) { - goto failed; - } - - if (val_type != napi_string) { - status = napi_coerce_to_string(env, value, &value); - if (status != napi_ok) { - goto failed; - } - } - - status = napi_get_value_string_latin1(env, value, ptr, header_len, - &value_len); - if (status != napi_ok) { - goto failed; - } - - f = req->response->fields + req->response->fields_count; - f->skip = 0; - - nxt_unit_sptr_set(&f->name, name_ptr); - - f->name_length = name_len; - f->hash = hash; - - nxt_unit_sptr_set(&f->value, ptr); - f->value_length = (uint32_t) value_len; - - ptr += value_len; - header_len -= value_len; - - req->response->fields_count++; } + + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } req->response_buf->free = ptr; ret = nxt_unit_response_send(req); if (ret != NXT_UNIT_OK) { - goto failed; + napi.throw_error("Failed to send response"); + return nullptr; } return this_arg; - -failed: - - req->response->fields_count = 0; - - napi_throw_error(env, NULL, "Failed to write headers"); - - return nullptr; } @@ -974,8 +575,8 @@ Unit::response_write(napi_env env, napi_callback_info info) int ret; char *ptr; size_t argc, have_buf_len; - int64_t req_p; uint32_t buf_len; + nxt_napi napi(env); napi_value this_arg, req_num; napi_status status; nxt_unit_buf_t *buf; @@ -985,39 +586,23 @@ Unit::response_write(napi_env env, napi_callback_info info) argc = 3; - status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); - if (status != napi_ok) { - goto failed; - } - - if (argc != 3) { - napi_throw_error(env, NULL, "Wrong args count. Need two: " - "chunk, chunk length"); - return nullptr; - } - - status = napi_get_named_property(env, argv[0], "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, argv); + if (argc != 3) { + throw exception("Wrong args count. Expected: " + "chunk, chunk length"); + } - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req_num = napi.get_named_property(argv[0], "_req_point"); + req = napi.get_request_info(req_num); - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; + buf_len = napi.get_value_uint32(argv[2]); - status = napi_get_value_uint32(env, argv[2], &buf_len); - if (status != napi_ok) { - goto failed; - } + buf_type = napi.type_of(argv[1]); - status = napi_typeof(env, argv[1], &buf_type); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } buf_len++; @@ -1055,7 +640,7 @@ Unit::response_write(napi_env env, napi_callback_info info) failed: - napi_throw_error(env, NULL, "Failed to write body"); + napi.throw_error("Failed to write body"); return nullptr; } @@ -1065,33 +650,23 @@ napi_value Unit::response_end(napi_env env, napi_callback_info info) { size_t argc; - int64_t req_p; + nxt_napi napi(env); napi_value resp, this_arg, req_num; - napi_status status; nxt_unit_request_info_t *req; argc = 1; - status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to finalize sending body"); - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, &resp); - status = napi_get_named_property(env, resp, "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req_num = napi.get_named_property(resp, "_req_point"); + req = napi.get_request_info(req_num); - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); + } catch (exception &e) { + napi.throw_error(e); return nullptr; } - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; - nxt_unit_request_done(req, NXT_UNIT_OK); return this_arg; diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h index db85e85c..e76d805a 100644 --- a/src/nodejs/unit-http/unit.h +++ b/src/nodejs/unit-http/unit.h @@ -6,34 +6,15 @@ #ifndef _NXT_NODEJS_UNIT_H_INCLUDED_ #define _NXT_NODEJS_UNIT_H_INCLUDED_ -#include <node_api.h> +#include "nxt_napi.h" -#ifdef __cplusplus -extern "C" { -#endif -#include "version.h" -#include <nxt_unit.h> - -#if NXT_VERNUM != NXT_NODE_VERNUM -#error "libunit version mismatch." -#endif - -#include <nxt_unit_response.h> -#include <nxt_unit_request.h> - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -class Unit { +class Unit : public nxt_napi { public: static napi_value init(napi_env env, napi_value exports); private: - Unit(napi_env env); + Unit(napi_env env, napi_value jsthis); ~Unit(); static napi_value create(napi_env env, napi_callback_info info); @@ -56,7 +37,7 @@ private: napi_value create_response(napi_value server_obj, napi_value socket, napi_value request, - nxt_unit_request_info_t *req, Unit *obj); + nxt_unit_request_info_t *req); static napi_value response_send_headers(napi_env env, napi_callback_info info); @@ -64,18 +45,16 @@ private: static napi_value response_write(napi_env env, napi_callback_info info); static napi_value response_end(napi_env env, napi_callback_info info); - napi_status create_headers(nxt_unit_request_info_t *req, - napi_value request); + void create_headers(nxt_unit_request_info_t *req, napi_value request); - inline napi_status append_header(nxt_unit_field_t *f, napi_value headers, + void append_header(nxt_unit_field_t *f, napi_value headers, napi_value raw_headers, uint32_t idx); static napi_ref constructor_; - napi_env env_; napi_ref wrapper_; nxt_unit_ctx_t *unit_ctx_; }; -#endif /* _NXT_NODEJS_H_INCLUDED_ */ +#endif /* _NXT_NODEJS_UNIT_H_INCLUDED_ */ |