From 3b0afb16814353a5d34a7384f4e84e9c17f3fb8e Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 31 Oct 2018 16:31:14 +0300 Subject: Version bump. --- src/nxt_main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nxt_main.h b/src/nxt_main.h index 670010f8..12c0ce6d 100644 --- a/src/nxt_main.h +++ b/src/nxt_main.h @@ -11,8 +11,8 @@ #include -#define NXT_VERSION "1.5" -#define NXT_VERNUM 10500 +#define NXT_VERSION "1.6" +#define NXT_VERNUM 10600 #define NXT_SERVER "Unit/" NXT_VERSION -- cgit From c838c3bd1580735e8020687f94e6307f13aba156 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Wed, 31 Oct 2018 15:51:51 +0300 Subject: Node.js: added async request execution. --- src/nodejs/unit-http/http_server.js | 29 ++++- src/nodejs/unit-http/unit.cpp | 227 +++++++++++++++++++++++------------- src/nodejs/unit-http/unit.h | 8 +- src/nxt_unit.c | 3 +- src/nxt_unit.h | 2 + 5 files changed, 176 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index fa7b8e9b..ddacb420 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -232,7 +232,6 @@ ServerResponse.prototype.write = function write(chunk, encoding, callback) { ServerResponse.prototype.end = function end(chunk, encoding, callback) { this._writeBody(chunk, encoding, callback); - unit_lib.unit_response_end(this) this.finished = true; @@ -290,10 +289,10 @@ function Server(requestListener) { EventEmitter.call(this); this.unit = new unit_lib.Unit(); - this.unit.createServer(); - this.unit.server = this; + this.unit.createServer(); + this.socket = Socket; this.request = ServerRequest; this.response = ServerResponse; @@ -318,10 +317,32 @@ Server.prototype.listen = function () { this.unit.listen(); }; +Server.prototype.run_events = function (server, req, res) { + /* Important!!! setImmediate starts the next iteration in Node.js loop. */ + setImmediate(function () { + server.emit("request", req, res); + + Promise.resolve().then(() => { + let buf = server.unit._read(req.socket.req_pointer); + + if (buf.length != 0) { + req.emit("data", buf); + } + + req.emit("end"); + }); + + Promise.resolve().then(() => { + if (res.finished) { + unit_lib.unit_response_end(res); + } + }); + }); +}; + function connectionListener(socket) { } - module.exports = { STATUS_CODES: http.STATUS_CODES, Server, diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 40f641a6..5d7f15c0 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -5,6 +5,11 @@ #include "unit.h" +#include +#include + +#include + napi_ref Unit::constructor_; @@ -31,11 +36,12 @@ Unit::init(napi_env env, napi_value exports) napi_property_descriptor properties[] = { { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, - { "listen", 0, listen, 0, 0, 0, napi_default, 0 } + { "listen", 0, listen, 0, 0, 0, napi_default, 0 }, + { "_read", 0, _read, 0, 0, 0, napi_default, 0 } }; status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr, - 2, properties, &cons); + 3, properties, &cons); if (status != napi_ok) { goto failed; } @@ -158,14 +164,13 @@ Unit::create_server(napi_env env, napi_callback_info info) { Unit *obj; size_t argc; - napi_value jsthis; + napi_value jsthis, argv; napi_status status; - napi_value argv[1]; nxt_unit_init_t unit_init; argc = 1; - status = napi_get_cb_info(env, info, &argc, argv, &jsthis, nullptr); + status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); if (status != napi_ok) { goto failed; } @@ -179,6 +184,8 @@ Unit::create_server(napi_env env, napi_callback_info info) unit_init.data = obj; unit_init.callbacks.request_handler = request_handler; + unit_init.callbacks.add_port = add_port; + unit_init.callbacks.remove_port = remove_port; obj->unit_ctx_ = nxt_unit_init(&unit_init); if (obj->unit_ctx_ == NULL) { @@ -198,41 +205,53 @@ failed: napi_value Unit::listen(napi_env env, napi_callback_info info) { - int ret; - Unit *obj; - napi_value jsthis; - napi_status status; + return nullptr; +} + + +napi_value +Unit::_read(napi_env env, napi_callback_info info) +{ + Unit *obj; + void *data; + size_t argc; + int64_t req_pointer; + napi_value jsthis, buffer, argv; + napi_status status; + nxt_unit_request_info_t *req; + + argc = 1; - status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr); + status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); if (status != napi_ok) { - goto failed; + napi_throw_error(env, NULL, "Failed to get arguments from js"); + return nullptr; } status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); if (status != napi_ok) { - goto failed; - } - - if (obj->unit_ctx_ == NULL) { - napi_throw_error(env, NULL, "Unit context was not created"); + napi_throw_error(env, NULL, "Failed to get Unit object form js"); return nullptr; } - ret = nxt_unit_run(obj->unit_ctx_); - if (ret != NXT_UNIT_OK) { - napi_throw_error(env, NULL, "Failed to run Unit"); + 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; } - nxt_unit_done(obj->unit_ctx_); - - return nullptr; + req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer; -failed: + 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"); + return nullptr; + } - napi_throw_error(env, NULL, "Failed to listen Unit socket"); + nxt_unit_request_read(req, data, req->content_length); - return nullptr; + return buffer; } @@ -242,8 +261,9 @@ Unit::request_handler(nxt_unit_request_info_t *req) Unit *obj; napi_value socket, request, response; napi_value global, server_obj; - napi_value req_argv[3]; + napi_value run_events, events_res; napi_status status; + napi_value events_args[3]; obj = reinterpret_cast(req->unit->data); @@ -284,73 +304,126 @@ Unit::request_handler(nxt_unit_request_info_t *req) return; } - req_argv[1] = request; - req_argv[2] = response; - status = obj->create_headers(req, request); if (status != napi_ok) { napi_throw_error(obj->env_, NULL, "Failed to create headers"); return; } - obj->emit(server_obj, "request", sizeof("request") - 1, 3, req_argv); - obj->emit_post_data(request, req); + status = napi_get_named_property(obj->env_, server_obj, "run_events", + &run_events); + if (status != napi_ok) { + napi_throw_error(obj->env_, NULL, "Failed to get" + " 'run_events' function"); + return; + } + + events_args[0] = server_obj; + events_args[1] = request; + events_args[2] = response; + + status = napi_call_function(obj->env_, server_obj, run_events, 3, + events_args, &events_res); + if (status != napi_ok) { + napi_throw_error(obj->env_, NULL, "Failed to call" + " 'run_events' function"); + return; + } napi_close_handle_scope(obj->env_, scope); } -napi_value -Unit::get_server_object() +void +nxt_uv_read_callback(uv_poll_t *handle, int status, int events) { - napi_value unit_obj, server_obj; + nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); +} + + +int +Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) +{ + int err; + Unit *obj; + uv_loop_t *loop; + uv_poll_t *uv_handle; napi_status status; - status = napi_get_reference_value(env_, wrapper_, &unit_obj); - if (status != napi_ok) { - return nullptr; - } + if (port->in_fd != -1) { + obj = reinterpret_cast(ctx->unit->data); - status = napi_get_named_property(env_, unit_obj, "server", &server_obj); - if (status != napi_ok) { - return nullptr; + if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { + napi_throw_error(obj->env_, NULL, "Failed to upgrade read" + " file descriptor to O_NONBLOCK"); + return -1; + } + + status = napi_get_uv_event_loop(obj->env_, &loop); + if (status != napi_ok) { + napi_throw_error(obj->env_, NULL, "Failed to get uv.loop"); + return NXT_UNIT_ERROR; + } + + uv_handle = new uv_poll_t; + + err = uv_poll_init(loop, uv_handle, port->in_fd); + if (err < 0) { + napi_throw_error(obj->env_, NULL, "Failed to init uv.poll"); + return NXT_UNIT_ERROR; + } + + err = uv_poll_start(uv_handle, UV_READABLE, nxt_uv_read_callback); + if (err < 0) { + napi_throw_error(obj->env_, NULL, "Failed to start uv.poll"); + return NXT_UNIT_ERROR; + } + + port->data = uv_handle; + uv_handle->data = ctx; } - return server_obj; + return nxt_unit_add_port(ctx, port); } -napi_value -Unit::emit(napi_value obj, const char *name, size_t name_len, size_t argc, - napi_value *argv) +void +Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) { - napi_value emitter, return_val, str; - napi_status status; + nxt_unit_port_t *port; - status = napi_get_named_property(env_, obj, "emit", &emitter); - if (status != napi_ok) { - return nullptr; + port = nxt_unit_find_port(ctx, port_id); + if (port == NULL) { + return; } - status = napi_create_string_latin1(env_, name, name_len, &str); - if (status != napi_ok) { - return nullptr; + if (port->in_fd != -1 && port->data != NULL) { + uv_poll_stop((uv_poll_t *) port->data); + + delete (uv_poll_t *) port->data; } - if (argc != 0) { - argv[0] = str; + nxt_unit_remove_port(ctx, port_id); +} - } else { - argc = 1; - argv = &str; + +napi_value +Unit::get_server_object() +{ + napi_value unit_obj, server_obj; + napi_status status; + + status = napi_get_reference_value(env_, wrapper_, &unit_obj); + if (status != napi_ok) { + return nullptr; } - status = napi_call_function(env_, obj, emitter, argc, argv, &return_val); + status = napi_get_named_property(env_, unit_obj, "server", &server_obj); if (status != napi_ok) { return nullptr; } - return return_val; + return server_obj; } @@ -480,7 +553,7 @@ Unit::append_header(nxt_unit_field_t *f, napi_value headers, napi_value Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) { - napi_value constructor, return_val; + napi_value constructor, return_val, req_pointer; napi_status status; status = napi_get_named_property(env_, server_obj, "socket", @@ -494,6 +567,17 @@ Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) return nullptr; } + status = napi_create_int64(env_, (uintptr_t) req, &req_pointer); + if (status != napi_ok) { + return nullptr; + } + + status = napi_set_named_property(env_, return_val, "req_pointer", + req_pointer); + if (status != napi_ok) { + return nullptr; + } + return return_val; } @@ -563,27 +647,6 @@ Unit::create_response(napi_value server_obj, napi_value socket, } -void -Unit::emit_post_data(napi_value request, nxt_unit_request_info_t *req) -{ - void *data; - napi_value req_argv[2]; - napi_status status; - - status = napi_create_buffer(env_, (size_t) req->content_length, - &data, &req_argv[1]); - if (status != napi_ok) { - napi_throw_error(env_, NULL, "Failed to create request buffer"); - return; - } - - nxt_unit_request_read(req, data, req->content_length); - - emit(request, "data", sizeof("data") - 1, 2, req_argv); - emit(request, "end", sizeof("end") - 1, 0, nullptr); -} - - napi_value Unit::response_send_headers(napi_env env, napi_callback_info info) { diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h index 753a14d8..90c67efc 100644 --- a/src/nodejs/unit-http/unit.h +++ b/src/nodejs/unit-http/unit.h @@ -36,13 +36,13 @@ private: static napi_value create_server(napi_env env, napi_callback_info info); static napi_value listen(napi_env env, napi_callback_info info); + static napi_value _read(napi_env env, napi_callback_info info); static void request_handler(nxt_unit_request_info_t *req); + static int add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); + static void remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id); napi_value get_server_object(); - napi_value emit(napi_value obj, const char *name, size_t name_len, - size_t argc, napi_value *argv); - napi_value create_socket(napi_value server_obj, nxt_unit_request_info_t *req); @@ -52,8 +52,6 @@ private: napi_value request, nxt_unit_request_info_t *req, Unit *obj); - void emit_post_data(napi_value request, nxt_unit_request_info_t *req); - static napi_value response_send_headers(napi_env env, napi_callback_info info); diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 0d1be557..24e51075 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -74,7 +74,6 @@ static nxt_unit_process_t *nxt_unit_process_get(nxt_unit_ctx_t *ctx, static nxt_unit_process_t *nxt_unit_process_find(nxt_unit_ctx_t *ctx, pid_t pid, int remove); static nxt_unit_process_t *nxt_unit_process_pop_first(nxt_unit_impl_t *lib); -static int nxt_unit_run_once(nxt_unit_ctx_t *ctx); static int nxt_unit_create_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id, int *fd); @@ -2697,7 +2696,7 @@ nxt_unit_run(nxt_unit_ctx_t *ctx) } -static int +int nxt_unit_run_once(nxt_unit_ctx_t *ctx) { int rc; diff --git a/src/nxt_unit.h b/src/nxt_unit.h index 1b4923a2..2806d035 100644 --- a/src/nxt_unit.h +++ b/src/nxt_unit.h @@ -196,6 +196,8 @@ int nxt_unit_process_msg(nxt_unit_ctx_t *, nxt_unit_port_id_t *port_id, */ int nxt_unit_run(nxt_unit_ctx_t *); +int nxt_unit_run_once(nxt_unit_ctx_t *ctx); + /* Destroy application library object. */ void nxt_unit_done(nxt_unit_ctx_t *); -- cgit From b7442743cfdf52185f293c770a883f1467776c5e Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Thu, 1 Nov 2018 19:10:32 +0300 Subject: Node.js: fixed typo in naming rawHeaders() method of request. --- src/nodejs/unit-http/unit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 5d7f15c0..97238834 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -464,7 +464,7 @@ Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) return status; } - status = napi_set_named_property(env_, request, "raw_headers", raw_headers); + status = napi_set_named_property(env_, request, "rawHeaders", raw_headers); if (status != napi_ok) { return status; } -- cgit From 4a77c447babd494b66156c43796deabaa47697a3 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Tue, 6 Nov 2018 19:04:01 +0300 Subject: Node.js: socket.js improvements. - Fixed handling of the "options" parameter in Socket() constructor; - Now the connect() method returns "this"; - Deduplicated the address() method; - Added missing "callback" argument to the end() method; - Now the destroy() method returns "this"; - Added "timeout" argument type check in the setTimeout() method. --- src/nodejs/unit-http/socket.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/socket.js b/src/nodejs/unit-http/socket.js index 89702834..aef065bf 100755 --- a/src/nodejs/unit-http/socket.js +++ b/src/nodejs/unit-http/socket.js @@ -12,15 +12,16 @@ const unit_lib = require('unit-http/build/Release/unit-http.node'); function Socket(options) { EventEmitter.call(this); - if (typeof options === 'number') { - options = { fd: options }; + options = options || {}; - } else if (options === undefined) { - options = {}; + if (typeof options !== 'object') { + throw new TypeError('Options must be object'); } - this.readable = options.readable !== false; - this.writable = options.writable !== false; + this.readable = (typeof options.readable === 'boolean' ? options.readable + : false); + this.writable = (typeof options.writable === 'boolean' ? options.writable + : false); } util.inherits(Socket, EventEmitter); @@ -38,25 +39,24 @@ Socket.prototype.remotePort = 0; Socket.prototype.address = function address() { }; -Socket.prototype.connect = function connect(options, callback) { - if (callback !== null) { - this.once('connect', cb); - } +Socket.prototype.connect = function connect(options, connectListener) { + this.once('connect', connectListener); this.connecting = true; this.writable = true; -}; -Socket.prototype.address = function address() { + return this; }; Socket.prototype.destroy = function destroy(exception) { this.connecting = false; this.readable = false; this.writable = false; + + return this; }; -Socket.prototype.end = function end(data, encoding) { +Socket.prototype.end = function end(data, encoding, callback) { }; Socket.prototype.pause = function pause() { @@ -77,13 +77,15 @@ Socket.prototype.setKeepAlive = function setKeepAlive(enable, initialDelay) { Socket.prototype.setNoDelay = function setNoDelay(noDelay) { }; -Socket.prototype.setTimeout = function setTimeout(msecs, callback) { - this.timeout = msecs; - - if (callback) { - this.on('timeout', callback); +Socket.prototype.setTimeout = function setTimeout(timeout, callback) { + if (typeof timeout !== 'number') { + throw new TypeError('Timeout must be number'); } + this.timeout = timeout; + + this.on('timeout', callback); + return this; }; -- cgit From 4f4a2d8c63e55401fe0fccb47d747701cdf3171e Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Sat, 10 Nov 2018 07:38:43 +0300 Subject: Fixed "freed pointer is out of pool" alerts. The issue was caused by misplacement of allocated blocks in rbtree due to broken comparison function if the distance between two allocations did not fit into intptr_t. As the result, nxt_mp_free() could have failed to find the allocation. In particular, it was mostly observed when Unit was compiled with musl C library on 32-bits systems. This closes #118 issue on GitHub. --- src/nxt_mp.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nxt_mp.c b/src/nxt_mp.c index a0f19ac2..5c1a4d00 100644 --- a/src/nxt_mp.c +++ b/src/nxt_mp.c @@ -768,7 +768,15 @@ nxt_mp_rbtree_compare(nxt_rbtree_node_t *node1, nxt_rbtree_node_t *node2) block1 = (nxt_mp_block_t *) node1; block2 = (nxt_mp_block_t *) node2; - return (uintptr_t) block1->start - (uintptr_t) block2->start; + /* + * Shifting is necessary to prevent overflow of intptr_t when block1->start + * is much greater than block2->start or vice versa. + * + * It is safe to drop one bit since there cannot be adjacent addresses + * because of alignments and allocation sizes. Effectively this reduces + * the absolute values to fit into the magnitude of intptr_t. + */ + return ((uintptr_t) block1->start >> 1) - ((uintptr_t) block2->start >> 1); } -- cgit From ff9bed64da495b6c234bcfa4dcf18932730e58e7 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Tue, 13 Nov 2018 18:43:39 +0300 Subject: Fixed nxt_openssl_chain_file() return type. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This closes #182 issue on GitHub. Thanks to 洪志道 (Hong Zhi Dao). --- src/nxt_openssl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 441da54b..401de2de 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -40,7 +40,7 @@ static void nxt_openssl_locks_free(void); #endif static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf); -static nxt_uint_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd); +static nxt_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd); static void nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf); static void nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c); @@ -359,14 +359,14 @@ fail: } -static nxt_uint_t +static nxt_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd) { BIO *bio; X509 *cert, *ca; long reason; EVP_PKEY *key; - nxt_uint_t ret; + nxt_int_t ret; bio = BIO_new(BIO_s_fd()); if (bio == NULL) { -- cgit From 92ddc15a84d50306b3d1e22387dd0373994968af Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Tue, 13 Nov 2018 19:04:48 +0300 Subject: Checking error states in I/O handlers. --- src/nxt_conn_read.c | 4 ++++ src/nxt_openssl.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/nxt_conn_read.c b/src/nxt_conn_read.c index e458bf81..8228326b 100644 --- a/src/nxt_conn_read.c +++ b/src/nxt_conn_read.c @@ -48,6 +48,10 @@ nxt_conn_io_read(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "conn read fd:%d rdy:%d cl:%d", c->socket.fd, c->socket.read_ready, c->socket.closed); + if (c->socket.error != 0) { + return; + } + engine = task->thread->engine; /* diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 401de2de..99dd2077 100644 --- a/src/nxt_openssl.c +++ b/src/nxt_openssl.c @@ -503,13 +503,19 @@ fail: nxt_inline void -nxt_openssl_conn_free(nxt_task_t *task, nxt_openssl_conn_t *tls) +nxt_openssl_conn_free(nxt_task_t *task, nxt_conn_t *c) { + nxt_openssl_conn_t *tls; + nxt_debug(task, "openssl conn free"); - nxt_free(tls->buffer.start); + tls = c->u.tls; - SSL_free(tls->session); + if (tls != NULL) { + c->u.tls = NULL; + nxt_free(tls->buffer.start); + SSL_free(tls->session); + } } @@ -526,9 +532,20 @@ nxt_openssl_conn_handshake(nxt_task_t *task, void *obj, void *data) const nxt_conn_state_t *state; c = obj; + + nxt_debug(task, "openssl conn handshake fd:%d", c->socket.fd); + + if (c->socket.error != 0) { + return; + } + tls = c->u.tls; - nxt_debug(task, "openssl conn handshake: %d", tls->times); + if (tls == NULL) { + return; + } + + nxt_debug(task, "openssl conn handshake: %d times", tls->times); /* "tls->times == 1" is suitable to run SSL_do_handshake() in job. */ @@ -715,10 +732,19 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) c = obj; - nxt_debug(task, "openssl conn shutdown"); + nxt_debug(task, "openssl conn shutdown fd:%d", c->socket.fd); + + if (c->socket.error != 0) { + return; + } c->read_state = NULL; tls = c->u.tls; + + if (tls == NULL) { + return; + } + s = tls->session; if (s == NULL || !tls->handshake) { @@ -807,7 +833,7 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data) done: - nxt_openssl_conn_free(task, tls); + nxt_openssl_conn_free(task, c); nxt_work_queue_add(c->write_work_queue, handler, task, c, data); } -- cgit From 08e0082e070354919de9584a8d26436a1dadeac0 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 15 Nov 2018 11:59:03 +0300 Subject: Fixed discovering of modules on 64-bit big-endian systems. The nxt_conf_map_object() function used nxt_int_t for NXT_CONF_MAP_INT, which was 8 bytes long on 64-bit systems. But the nxt_port_main_start_worker_handler() used it to map into the int field of the nxt_common_app_conf_t structure, which was 4 bytes. As the result, on a 64-bit big-endian system all the meaningful module type numbers were assigned into the gap above the "type" field. The bug was discovered on IBM/S390x. --- src/nxt_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 1aeafc06..2255e12f 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -525,7 +525,7 @@ nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, uint8_t ui8; int32_t i32; int64_t i64; - nxt_int_t i; + int i; ssize_t size; off_t off; nxt_msec_t msec; -- cgit From b033fb329fc14e6469596821508c487e3ed6ff82 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 15 Nov 2018 13:00:58 +0300 Subject: Fixed lvlhsh test on 64-bit big-endian systems. The nxt_murmur_hash2() generated 4-byte hash that was stored in uintptr_t, which was 8 bytes long on 64-bit systems. At each iteration, it took the previous key and hashed it again. The problem was that it took only the first 4 bytes of the key, and these 4 bytes were always zero on 64-bit big-endian system. That resulted in equal keys at each iteration. The bug was discovered on IBM/S390x. --- src/test/nxt_lvlhsh_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/nxt_lvlhsh_test.c b/src/test/nxt_lvlhsh_test.c index 3dc56076..2e1e0b20 100644 --- a/src/test/nxt_lvlhsh_test.c +++ b/src/test/nxt_lvlhsh_test.c @@ -131,7 +131,7 @@ nxt_int_t nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, nxt_bool_t use_pool) { void *value; - uintptr_t key; + uint32_t key; nxt_mp_t *mp; nxt_nsec_t start, end; nxt_uint_t i; -- cgit From 71f4cb91340b656397eaaa356755b4a1e31c8010 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Thu, 15 Nov 2018 15:24:45 +0300 Subject: Node.js: added reference count increment for the Unit object. We increase the number to the Unit object so that it lives forever. This is necessary so that the garbage collector does not delete the Unit object. --- src/nodejs/unit-http/http_server.js | 2 ++ src/nodejs/unit-http/unit.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index ddacb420..b35ad259 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -333,6 +333,8 @@ Server.prototype.run_events = function (server, req, res) { }); Promise.resolve().then(() => { + req.emit("finish"); + if (res.finished) { unit_lib.unit_response_end(res); } diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 97238834..bc6fc7db 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -111,6 +111,7 @@ 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; @@ -135,6 +136,11 @@ Unit::create(napi_env env, napi_callback_info info) goto failed; } + status = napi_create_reference(env, jsthis, 1, &ref); + if (status != napi_ok) { + goto failed; + } + return jsthis; } @@ -149,6 +155,11 @@ Unit::create(napi_env env, napi_callback_info info) goto failed; } + status = napi_create_reference(env, instance, 1, &ref); + if (status != napi_ok) { + goto failed; + } + return instance; failed: -- cgit From 06b404feb17dec9e3a84da31e213f21a0a9b4846 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Thu, 15 Nov 2018 15:39:34 +0300 Subject: Node.js: added correct exit processing. Node.js processes didn't exit after the changes in b9f7635e6be2, as the quit command from port wasn't handled by the module. --- src/nodejs/unit-http/unit.cpp | 60 ++++++++++++++++++++++++++++++------------- src/nodejs/unit-http/unit.h | 1 + 2 files changed, 43 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index bc6fc7db..788a5cc8 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -14,6 +14,12 @@ napi_ref Unit::constructor_; +struct nxt_nodejs_ctx_t { + nxt_unit_port_id_t port_id; + uv_poll_t poll; +}; + + Unit::Unit(napi_env env): env_(env), wrapper_(nullptr), @@ -197,6 +203,7 @@ Unit::create_server(napi_env env, napi_callback_info info) unit_init.callbacks.request_handler = request_handler; unit_init.callbacks.add_port = add_port; unit_init.callbacks.remove_port = remove_port; + unit_init.callbacks.quit = quit; obj->unit_ctx_ = nxt_unit_init(&unit_init); if (obj->unit_ctx_ == NULL) { @@ -355,11 +362,11 @@ nxt_uv_read_callback(uv_poll_t *handle, int status, int events) int Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) { - int err; - Unit *obj; - uv_loop_t *loop; - uv_poll_t *uv_handle; - napi_status status; + int err; + Unit *obj; + uv_loop_t *loop; + napi_status status; + nxt_nodejs_ctx_t *node_ctx; if (port->in_fd != -1) { obj = reinterpret_cast(ctx->unit->data); @@ -376,48 +383,65 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) return NXT_UNIT_ERROR; } - uv_handle = new uv_poll_t; + node_ctx = new nxt_nodejs_ctx_t; - err = uv_poll_init(loop, uv_handle, port->in_fd); + 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"); return NXT_UNIT_ERROR; } - err = uv_poll_start(uv_handle, UV_READABLE, nxt_uv_read_callback); + 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"); return NXT_UNIT_ERROR; } - port->data = uv_handle; - uv_handle->data = ctx; + ctx->data = node_ctx; + + node_ctx->port_id = port->id; + node_ctx->poll.data = ctx; } return nxt_unit_add_port(ctx, port); } +inline bool +operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) +{ + return p1.pid == p2.pid && p1.id == p2.id; +} + + void Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) { - nxt_unit_port_t *port; + nxt_nodejs_ctx_t *node_ctx; - port = nxt_unit_find_port(ctx, port_id); - if (port == NULL) { - return; - } + if (ctx->data != NULL) { + node_ctx = (nxt_nodejs_ctx_t *) ctx->data; + + if (node_ctx->port_id == *port_id) { + uv_poll_stop(&node_ctx->poll); - if (port->in_fd != -1 && port->data != NULL) { - uv_poll_stop((uv_poll_t *) port->data); + delete node_ctx; - delete (uv_poll_t *) port->data; + ctx->data = NULL; + } } nxt_unit_remove_port(ctx, port_id); } +void +Unit::quit(nxt_unit_ctx_t *ctx) +{ + nxt_unit_done(ctx); +} + + napi_value Unit::get_server_object() { diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h index 90c67efc..5f541cc4 100644 --- a/src/nodejs/unit-http/unit.h +++ b/src/nodejs/unit-http/unit.h @@ -40,6 +40,7 @@ private: static void request_handler(nxt_unit_request_info_t *req); static int add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); static void remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id); + static void quit(nxt_unit_ctx_t *ctx); napi_value get_server_object(); -- cgit From fb18a09cd748ff0107d4e27e514c9f5caf3aa5e6 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Thu, 15 Nov 2018 15:21:52 +0300 Subject: Node.js: fixed handling of response header fields. This fixes two issues: - values for mutiple header fields with the same name passed as arrays were converted to string; - the type of field value wasn't preserved as required by specification. --- src/nodejs/unit-http/http_server.js | 2 +- src/nodejs/unit-http/unit.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index b35ad259..331778a3 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -78,7 +78,7 @@ ServerResponse.prototype.setHeader = function setHeader(key, value) { this.removeHeader(key); - this.headers[key] = value + ""; + this.headers[key] = value; this.headers_len += header_len + (header_key_len * header_count); this.headers_count += header_count; }; diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 788a5cc8..be64a59b 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -696,6 +696,7 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) napi_value this_arg, headers, keys, name, value, array_val; napi_value req_num; napi_status status; + napi_valuetype val_type; nxt_unit_field_t *f; nxt_unit_request_info_t *req; napi_value argv[5]; @@ -805,6 +806,18 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) goto failed; } + napi_typeof(env, array_val, &val_type); + if (status != napi_ok) { + goto failed; + } + + if (val_type != napi_string) { + status = napi_coerce_to_string(env, array_val, &array_val); + if (status != napi_ok) { + goto failed; + } + } + status = napi_get_value_string_latin1(env, array_val, ptr, header_len, &value_len); @@ -830,6 +843,18 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) } } 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) { -- cgit From 5c2021f8340566cbdac9dcc8e32c710d4b763a43 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Thu, 15 Nov 2018 14:42:51 +0300 Subject: Node.js: res.write() must return a bool value. --- src/nodejs/unit-http/http_server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index 331778a3..57163c0b 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -227,7 +227,7 @@ ServerResponse.prototype._writeBody = function(chunk, encoding, callback) { ServerResponse.prototype.write = function write(chunk, encoding, callback) { this._writeBody(chunk, encoding, callback); - return this; + return true; }; ServerResponse.prototype.end = function end(chunk, encoding, callback) { -- cgit From 2b4d83cbd8a228b0004e3831c9d933400dede3c1 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Thu, 15 Nov 2018 15:53:35 +0300 Subject: Node.js: npm package readme cleanup. --- src/nodejs/unit-http/README.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/README.md b/src/nodejs/unit-http/README.md index 71a4067a..b6b975e4 100644 --- a/src/nodejs/unit-http/README.md +++ b/src/nodejs/unit-http/README.md @@ -1,21 +1,5 @@ +[](https://unit.nginx.org) + # Node.js Package for NGINX Unit -[](https://unit.nginx.org) -Node.js support package for NGINX Unit. For details, see [NGINX Unit documentation](https://unit.nginx.org). - -## Installation - -```bash -npm i unit-http -``` - -## Usage - -```javascript -var http = require('unit-http'); -``` - -## License - -Apache 2.0 -- cgit