diff options
author | Konstantin Pavlov <thresh@nginx.com> | 2018-11-15 16:23:35 +0300 |
---|---|---|
committer | Konstantin Pavlov <thresh@nginx.com> | 2018-11-15 16:23:35 +0300 |
commit | 6ccba253f8d415337a09fb935606447791ce308c (patch) | |
tree | e0f9a8c5e8ede8cef1500c316d7534dd8de7b972 | |
parent | bdde42999b36af85f2f04c0872fdd3e30af52027 (diff) | |
parent | a4b02e17382ccbfc19410c644004c4615b2c2c29 (diff) | |
download | unit-1.6-1.tar.gz unit-1.6-1.tar.bz2 |
Merged with the default branch.1.6-1
29 files changed, 509 insertions, 184 deletions
@@ -13,3 +13,4 @@ b3cf22b8a17e0e35ca80decb03ed2cceb662c3de 1.3 99d69d59aa5edee3405d304886d9319291e392ba 1.4-2 b3dee0cc5a4edd046345511769b5cfec49044f1c 1.5 e507438883ef0044c278f1accfc7bc7f90c0ffb6 1.5-1 +d411e7fdee9e03036adb652f8d9f4c45a420bdd5 1.6 @@ -1,4 +1,26 @@ +Changes with Unit 1.6 15 Nov 2018 + + *) Change: "make install" now installs Node.js module as well if it was + configured. + + *) Feature: "--local" ./configure option to install Node.js module + locally. + + *) Bugfix: Node.js module might have crashed due to broken reference + counting. + + *) Bugfix: asynchronous operations in Node.js might not have worked. + + *) Bugfix: various compatibility issues with Node.js applications. + + *) Bugfix: "freed pointer is out of pool" alerts might have appeared in + log. + + *) Bugfix: module discovery didn't work on 64-bit big-endian systems + like IBM/S390x. + + Changes with Unit 1.5 25 Oct 2018 *) Change: the "type" of application object for Go was changed to @@ -55,4 +55,7 @@ cat << END ruby OPTIONS configure Ruby module run "./configure ruby --help" to see available options + nodejs OPTIONS configure Node.js module + run "./configure nodejs --help" to see available options + END diff --git a/auto/modules/nodejs b/auto/modules/nodejs index 56f84876..443ee9d5 100644 --- a/auto/modules/nodejs +++ b/auto/modules/nodejs @@ -15,13 +15,15 @@ for nxt_option; do --node=*) NXT_NODE="$value" ;; --npm=*) NXT_NPM="$value" ;; --node-gyp=*) NXT_NODE_GYP="$value" ;; + --local=*) NXT_NODE_LOCAL="$value" ;; --help) cat << END - --node=NAME set node executable - --npm=NAME set npm executable - --node-gyp=NAME set node-gyp executable + --node=FILE set node executable + --npm=FILE set npm executable + --node-gyp=FILE set node-gyp executable + --local=DIRECTORY set directory path for local installation END exit 0 @@ -49,12 +51,14 @@ fi . $NXT_AUTOCONF_DATA -$echo "configuring nodejs module" -$echo "configuring nodejs module..." >> $NXT_AUTOCONF_ERR - NXT_NODE=${NXT_NODE=node} NXT_NPM=${NXT_NPM=npm} NXT_NODE_GYP=${NXT_NODE_GYP=node-gyp} +NXT_NODE_LOCAL=${NXT_NODE_LOCAL=} + + +$echo "configuring nodejs module" +$echo "configuring nodejs module..." >> $NXT_AUTOCONF_ERR $echo -n "checking for node ..." $echo "checking for node ..." >> $NXT_AUTOCONF_ERR @@ -73,6 +77,7 @@ else exit 1; fi + $echo -n "checking for npm ..." $echo "checking for npm ..." >> $NXT_AUTOCONF_ERR @@ -90,6 +95,7 @@ else exit 1; fi + $echo -n "checking for node-gyp ..." $echo "checking for node-gyp ..." >> $NXT_AUTOCONF_ERR @@ -114,19 +120,29 @@ if grep ^$NXT_NODE: $NXT_MAKEFILE 2>&1 > /dev/null; then exit 1; fi + NXT_NODE_TMP=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http NXT_NODE_TARBALL=${NXT_BUILD_DIR}/${NXT_NODE}-unit-http.tar.gz NXT_NODE_EXPORTS="export UNIT_SRC_PATH=${PWD}/src && \ export UNIT_LIB_STATIC_PATH=${PWD}/${NXT_BUILD_DIR}/libunit.a" +if [ -n "$NXT_NODE_LOCAL" ]; then + NXT_NODE_INSTALL=local-install +else + NXT_NODE_INSTALL=install +fi + cat << END >> $NXT_MAKEFILE .PHONY: ${NXT_NODE} .PHONY: ${NXT_NODE}-copy .PHONY: ${NXT_NODE}-install .PHONY: ${NXT_NODE}-uninstall +.PHONY: ${NXT_NODE}-local-check +.PHONY: ${NXT_NODE}-local-install +.PHONY: ${NXT_NODE}-build +.PHONY: ${NXT_NODE}-publish -all: ${NXT_NODE}: ${NXT_NODE}-copy $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC ${NXT_NODE_EXPORTS} && \\ @@ -139,23 +155,37 @@ ${NXT_NODE}-copy: ${NXT_NODE_TARBALL}: ${NXT_NODE}-copy tar -zcvf ${NXT_NODE_TARBALL} -C ${NXT_NODE_TMP} . + +install: ${NXT_NODE}-$NXT_NODE_INSTALL + ${NXT_NODE}-install: ${NXT_NODE_TARBALL} \ $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC ${NXT_NODE_EXPORTS} && \\ - ${NXT_NPM} install -g ${PWD}/${NXT_NODE_TARBALL} --unsafe-perm=true + ${NXT_NPM} install -g ${PWD}/${NXT_NODE_TARBALL} + +${NXT_NODE}-uninstall: + ${NXT_NPM} uninstall -g unit-http -${NXT_NODE}-local-install: ${NXT_NODE_TARBALL} \ +${NXT_NODE}-local-check: + @test -n "\$(DESTDIR)$NXT_NODE_LOCAL" \\ + || (echo; \\ + echo "error: to make ${NXT_NODE}-local-install you need either"; \\ + echo " to configure --local option"; \\ + echo " or to set DESTDIR environment variable."; \\ + echo; \\ + exit 1) + +${NXT_NODE}-local-install: ${NXT_NODE_TARBALL} ${NXT_NODE}-local-check \ $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC ${NXT_NODE_EXPORTS} && \\ - mkdir -p \$(DESTDIR) && \\ - cd \$(DESTDIR) && ${NXT_NPM} install ${PWD}/${NXT_NODE_TARBALL} + mkdir -p \$(DESTDIR)${NXT_NODE_LOCAL} && \\ + cd \$(DESTDIR)${NXT_NODE_LOCAL} && \\ + ${NXT_NPM} install ${PWD}/${NXT_NODE_TARBALL} + ${NXT_NODE}-build: ${NXT_NODE} ${NXT_NODE}-publish: ${NXT_NODE} cd ${NXT_NODE_TMP} && ${NXT_NPM} publish -${NXT_NODE}-uninstall: - ${NXT_NPM} uninstall -g unit-http - END diff --git a/docs/changes.xml b/docs/changes.xml index 5be0a94e..b3bc33ee 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -11,6 +11,74 @@ unit-go unit-go1.7 unit-go1.8 unit-go1.9 unit-go1.10 unit-perl unit-ruby" + ver="1.6" rev="1" + date="2018-11-15" time="18:00:00 +0300" + packager="Konstantin Pavlov <thresh@nginx.com>"> + +<change> +<para> +NGINX Unit updated to 1.6. +</para> +</change> + +</changes> + + +<changes apply="unit" ver="1.6" rev="1" + date="2018-11-15" time="18:00:00 +0300" + packager="Konstantin Pavlov <thresh@nginx.com>"> + +<change type="change"> +<para> +"make install" now installs Node.js module as well if it was configured. +</para> +</change> + +<change type="feature"> +<para> +"--local" ./configure option to install Node.js module locally. +</para> +</change> + +<change type="bugfix"> +<para> +Node.js module might have crashed due to broken reference counting. +</para> +</change> + +<change type="bugfix"> +<para> +asynchronous operations in Node.js might not have worked. +</para> +</change> + +<change type="bugfix"> +<para> +various compatibility issues with Node.js applications. +</para> +</change> + +<change type="bugfix"> +<para> +"freed pointer is out of pool" alerts might have appeared in log. +</para> +</change> + +<change type="bugfix"> +<para> +module discovery didn't work on 64-bit big-endian systems like IBM/S390x. +</para> +</change> + +</changes> + + +<changes apply="unit-php + unit-python unit-python2.7 + unit-python3.4 unit-python3.5 unit-python3.6 + unit-go unit-go1.7 unit-go1.8 unit-go1.9 unit-go1.10 + unit-perl + unit-ruby" ver="1.5" rev="1" date="2018-10-25" time="18:00:00 +0300" packager="Andrei Belov <defan@nginx.com>"> diff --git a/pkg/docker/Dockerfile.full b/pkg/docker/Dockerfile.full index 2ccfc16c..f3663eb4 100644 --- a/pkg/docker/Dockerfile.full +++ b/pkg/docker/Dockerfile.full @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.go1.7-dev b/pkg/docker/Dockerfile.go1.7-dev index aa915518..2c6975e2 100644 --- a/pkg/docker/Dockerfile.go1.7-dev +++ b/pkg/docker/Dockerfile.go1.7-dev @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.go1.8-dev b/pkg/docker/Dockerfile.go1.8-dev index e623182b..1cd1acfc 100644 --- a/pkg/docker/Dockerfile.go1.8-dev +++ b/pkg/docker/Dockerfile.go1.8-dev @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal index 0ff59411..0ffff5c9 100644 --- a/pkg/docker/Dockerfile.minimal +++ b/pkg/docker/Dockerfile.minimal @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.perl5.24 b/pkg/docker/Dockerfile.perl5.24 index 06067fc7..9cbbc645 100644 --- a/pkg/docker/Dockerfile.perl5.24 +++ b/pkg/docker/Dockerfile.perl5.24 @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.php7.0 b/pkg/docker/Dockerfile.php7.0 index a6b816bf..70ea8bbc 100644 --- a/pkg/docker/Dockerfile.php7.0 +++ b/pkg/docker/Dockerfile.php7.0 @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.python2.7 b/pkg/docker/Dockerfile.python2.7 index b02fe194..4cb4d5f3 100644 --- a/pkg/docker/Dockerfile.python2.7 +++ b/pkg/docker/Dockerfile.python2.7 @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.python3.5 b/pkg/docker/Dockerfile.python3.5 index 32ecfcf5..26c54174 100644 --- a/pkg/docker/Dockerfile.python3.5 +++ b/pkg/docker/Dockerfile.python3.5 @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.ruby2.3 b/pkg/docker/Dockerfile.ruby2.3 index ce5fefda..b0d9de49 100644 --- a/pkg/docker/Dockerfile.ruby2.3 +++ b/pkg/docker/Dockerfile.ruby2.3 @@ -2,7 +2,7 @@ FROM debian:stretch-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" -ENV UNIT_VERSION 1.5-1~stretch +ENV UNIT_VERSION 1.6-1~stretch RUN set -x \ && apt-get update \ @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ diff --git a/pkg/docker/Dockerfile.tmpl b/pkg/docker/Dockerfile.tmpl index 76722f88..18d6d34e 100644 --- a/pkg/docker/Dockerfile.tmpl +++ b/pkg/docker/Dockerfile.tmpl @@ -73,7 +73,7 @@ RUN set -x \ && apt-get install --no-install-recommends --no-install-suggests -y \ $unitPackages \ curl \ - && apt-get remove --purge --auto-remove -y apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ + && apt-get remove --purge --auto-remove -y apt-transport-https && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/unit.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) && if [ -n "$tempDir" ]; then \ 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 @@ +[<img src="https://unit.nginx.org/_static/logo.svg" width="40%">](https://unit.nginx.org) + # Node.js Package for NGINX Unit -[<img src="https://unit.nginx.org/_static/logo.svg" width=150px>](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 diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index fa7b8e9b..57163c0b 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; }; @@ -227,12 +227,11 @@ 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) { 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,34 @@ 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(() => { + req.emit("finish"); + + 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/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; }; diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 40f641a6..be64a59b 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -5,10 +5,21 @@ #include "unit.h" +#include <unistd.h> +#include <fcntl.h> + +#include <uv.h> + 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), @@ -31,11 +42,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; } @@ -105,6 +117,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; @@ -129,6 +142,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; } @@ -143,6 +161,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: @@ -158,14 +181,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 +201,9 @@ 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; + unit_init.callbacks.quit = quit; obj->unit_ctx_ = nxt_unit_init(&unit_init); if (obj->unit_ctx_ == NULL) { @@ -198,41 +223,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; +} + - status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, 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, &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<void **>(&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 +279,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<Unit *>(req->unit->data); @@ -284,73 +322,143 @@ 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; - napi_status status; + nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); +} - status = napi_get_reference_value(env_, wrapper_, &unit_obj); - if (status != napi_ok) { - return nullptr; + +int +Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) +{ + 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<Unit *>(ctx->unit->data); + + 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; + } + + node_ctx = new nxt_nodejs_ctx_t; + + 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(&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; + } + + ctx->data = node_ctx; + + node_ctx->port_id = port->id; + node_ctx->poll.data = ctx; } - status = napi_get_named_property(env_, unit_obj, "server", &server_obj); - if (status != napi_ok) { - return nullptr; + 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_nodejs_ctx_t *node_ctx; + + 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); + + delete node_ctx; + + ctx->data = NULL; + } } - return server_obj; + nxt_unit_remove_port(ctx, port_id); +} + + +void +Unit::quit(nxt_unit_ctx_t *ctx) +{ + nxt_unit_done(ctx); } napi_value -Unit::emit(napi_value obj, const char *name, size_t name_len, size_t argc, - napi_value *argv) +Unit::get_server_object() { - napi_value emitter, return_val, str; + napi_value unit_obj, server_obj; napi_status status; - status = napi_get_named_property(env_, obj, "emit", &emitter); - if (status != napi_ok) { - return nullptr; - } - - status = napi_create_string_latin1(env_, name, name_len, &str); + status = napi_get_reference_value(env_, wrapper_, &unit_obj); if (status != napi_ok) { return nullptr; } - if (argc != 0) { - argv[0] = str; - - } else { - argc = 1; - argv = &str; - } - - 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; } @@ -391,7 +499,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; } @@ -480,7 +588,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 +602,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 +682,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) { @@ -598,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]; @@ -707,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); @@ -732,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) { diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h index 753a14d8..5f541cc4 100644 --- a/src/nodejs/unit-http/unit.h +++ b/src/nodejs/unit-http/unit.h @@ -36,13 +36,14 @@ 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); + static void quit(nxt_unit_ctx_t *ctx); 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 +53,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_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; 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_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 <nxt_auto_config.h> -#define NXT_VERSION "1.5" -#define NXT_VERNUM 10500 +#define NXT_VERSION "1.6" +#define NXT_VERNUM 10600 #define NXT_SERVER "Unit/" NXT_VERSION 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); } diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c index 441da54b..99dd2077 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) { @@ -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); } 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 *); 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; diff --git a/test/unit.py b/test/unit.py index 98a0a4db..a5f96968 100644 --- a/test/unit.py +++ b/test/unit.py @@ -25,13 +25,36 @@ class TestUnit(unittest.TestCase): def tearDown(self): self.stop() + # detect errors and failures for current test + + def list2reason(exc_list): + if exc_list and exc_list[-1][0] is self: + return exc_list[-1][1] + + if hasattr(self, '_outcome'): + result = self.defaultTestResult() + self._feedErrorsToResult(result, self._outcome.errors) + else: + result = getattr(self, '_outcomeForDoCleanups', + self._resultForDoCleanups) + + success = not list2reason(result.errors) \ + and not list2reason(result.failures) + + # check unit.log for alerts + with open(self.testdir + '/unit.log', 'r', encoding='utf-8', errors='ignore') as f: self._check_alerts(f.read()) - if '--leave' not in sys.argv: + # remove unit.log + + if '--leave' not in sys.argv and success: shutil.rmtree(self.testdir) + else: + self._print_path_to_log() + def check_modules(self, *modules): self._run() @@ -171,11 +194,16 @@ class TestUnit(unittest.TestCase): for skip in self.skip_alerts: alerts = [al for al in alerts if re.search(skip, al) is None] - self.assertFalse(alerts, 'alert(s)') + if alerts: + self._print_path_to_log() + self.assertFalse(alerts, 'alert(s)') if not self.skip_sanitizer: - self.assertFalse(re.findall('.+Sanitizer.+', log), - 'sanitizer error(s)') + sanitizer_errors = re.findall('.+Sanitizer.+', log) + + if sanitizer_errors: + self._print_path_to_log() + self.assertFalse(sanitizer_error, 'sanitizer error(s)') if found: print('skipped.') @@ -199,6 +227,9 @@ class TestUnit(unittest.TestCase): return ret + def _print_path_to_log(self): + print('Path to unit.log:\n' + self.testdir + '/unit.log') + class TestUnitHTTP(TestUnit): def http(self, start_str, **kwargs): |