summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.hgtags1
-rw-r--r--CHANGES40
-rw-r--r--auto/help1
-rw-r--r--auto/make33
-rw-r--r--auto/modules/java8
-rw-r--r--auto/modules/java_jar.sha51228
-rw-r--r--auto/modules/nodejs38
-rw-r--r--auto/options6
-rw-r--r--auto/summary1
-rwxr-xr-xconfigure1
-rw-r--r--docs/changes.xml106
-rw-r--r--docs/man/unitd.8.in80
-rw-r--r--pkg/deb/Makefile2
-rw-r--r--pkg/deb/debian/rules.in4
-rw-r--r--pkg/docker/Dockerfile.go1.154
-rw-r--r--pkg/docker/Dockerfile.jsc114
-rw-r--r--pkg/docker/Dockerfile.minimal4
-rw-r--r--pkg/docker/Dockerfile.node154
-rw-r--r--pkg/docker/Dockerfile.perl5.324
-rw-r--r--pkg/docker/Dockerfile.php8.04
-rw-r--r--pkg/docker/Dockerfile.python3.94
-rw-r--r--pkg/docker/Dockerfile.ruby2.74
-rw-r--r--pkg/docker/template.Dockerfile2
-rw-r--r--pkg/rpm/Makefile2
-rw-r--r--pkg/rpm/unit.spec.in3
-rw-r--r--src/nodejs/unit-http/package.json2
-rw-r--r--src/nxt_app_log.c9
-rw-r--r--src/nxt_cert.c110
-rw-r--r--src/nxt_conf_validation.c33
-rw-r--r--src/nxt_log.c9
-rw-r--r--src/nxt_openssl.c419
-rw-r--r--src/nxt_php_sapi.c4
-rw-r--r--src/nxt_port_memory.c5
-rw-r--r--src/nxt_port_socket.c97
-rw-r--r--src/nxt_router.c140
-rw-r--r--src/nxt_router_request.h1
-rw-r--r--src/nxt_thread.h8
-rw-r--r--src/nxt_tls.h29
-rw-r--r--src/nxt_unit.c2
-rw-r--r--src/ruby/nxt_ruby.c4
-rw-r--r--test/conftest.py139
-rw-r--r--test/test_asgi_application.py2
-rw-r--r--test/test_asgi_websockets.py14
-rw-r--r--test/test_java_websockets.py14
-rw-r--r--test/test_node_websockets.py14
-rw-r--r--test/test_proxy.py1
-rw-r--r--test/test_python_application.py2
-rw-r--r--test/test_routing.py12
-rw-r--r--test/test_share_fallback.py7
-rw-r--r--test/test_tls.py2
-rw-r--r--test/unit/applications/lang/java.py2
-rw-r--r--test/unit/applications/proto.py4
-rw-r--r--test/unit/check/regex.py13
-rw-r--r--test/unit/utils.py2
-rw-r--r--version4
55 files changed, 1246 insertions, 246 deletions
diff --git a/.hgtags b/.hgtags
index 3efbabc7..b4e2b386 100644
--- a/.hgtags
+++ b/.hgtags
@@ -51,3 +51,4 @@ f804aaf7eee10a7d8116820840d6312dd4914a41 1.21.0
e3f504b6082ee97ed0d6c8660890585ef6a5796f 1.21.0-1
331bdadeca30a49dd11b86af99124c2ffeb22d05 1.22.0
86b359acc93fe53f1f21b22abc8d1b40ca26158c 1.22.0-1
+49ee24c03f5749f8a1b69dc1c600ad48517d9d7a 1.23.0
diff --git a/CHANGES b/CHANGES
index 0f558c6f..b411e816 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,44 @@
+Changes with Unit 1.23.0 25 Mar 2021
+
+ *) Feature: support for multiple certificate bundles on a listener via
+ the Server Name Indication (SNI) TLS extension.
+
+ *) Feature: "--mandir" ./configure option to specify the directory for
+ man page installation.
+
+ *) Bugfix: the router process could crash on premature TLS connection
+ close; the bug had appeared in 1.17.0.
+
+ *) Bugfix: a connection leak occurred on premature TLS connection close;
+ the bug had appeared in 1.6.
+
+ *) Bugfix: a descriptor and memory leak occurred in the router process
+ when processing small WebSocket frames from a client; the bug had
+ appeared in 1.19.0.
+
+ *) Bugfix: a descriptor leak occurred in the router process when
+ removing or reconfiguring an application; the bug had appeared in
+ 1.19.0.
+
+ *) Bugfix: persistent storage of certificates might've not worked with
+ some filesystems in Linux, and all uploaded certificate bundles were
+ forgotten after restart.
+
+ *) Bugfix: the controller process could crash while requesting
+ information about a certificate with a non-DNS SAN entry.
+
+ *) Bugfix: the controller process could crash on manipulations with a
+ certificate containing a SAN and no standard name attributes in
+ subject or issuer.
+
+ *) Bugfix: the Ruby module didn't respect the user locale for defaults
+ in the Encoding class.
+
+ *) Bugfix: the PHP 5 module failed to build with thread safety enabled;
+ the bug had appeared in 1.22.0.
+
+
Changes with Unit 1.22.0 04 Feb 2021
*) Feature: the ServerRequest and ServerResponse objects of Node.js
diff --git a/auto/help b/auto/help
index 31c68567..e2b81bc7 100644
--- a/auto/help
+++ b/auto/help
@@ -18,6 +18,7 @@ cat << END
default: "$NXT_SBINDIR"
--libdir=DIRECTORY set library directory name, default: "$NXT_LIBDIR"
--incdir=DIRECTORY set includes directory name, default: "$NXT_INCDIR"
+ --mandir=DIRECTORY set man pages directory name, default: "$NXT_MANDIR"
--modules=DIRECTORY set modules directory name, default: "$NXT_MODULES"
--state=DIRECTORY set state directory name, default: "$NXT_STATE"
--tmp=DIRECTORY set tmp directory name, default: "$NXT_TMP"
diff --git a/auto/make b/auto/make
index fcf258fa..18d23917 100644
--- a/auto/make
+++ b/auto/make
@@ -22,10 +22,11 @@ NXT_EXEC_LINK = $NXT_EXEC_LINK $NXT_LD_OPT
NXT_SHARED_LOCAL_LINK = $NXT_SHARED_LOCAL_LINK $NXT_LD_OPT
NXT_MODULE_LINK = $NXT_MODULE_LINK
-all: $NXT_DAEMON
+all: $NXT_DAEMON manpage
-.PHONY: $NXT_DAEMON
+.PHONY: $NXT_DAEMON manpage
$NXT_DAEMON: $NXT_BUILD_DIR/$NXT_DAEMON
+manpage: $NXT_BUILD_DIR/unitd.8
END
@@ -305,6 +306,19 @@ $NXT_BUILD_DIR/$NXT_DAEMON: $NXT_BUILD_DIR/$NXT_LIB_STATIC \\
END
+# unitd man page
+
+cat << END >> $NXT_MAKEFILE
+
+$NXT_BUILD_DIR/unitd.8: docs/man/unitd.8.in $NXT_BUILD_DIR/nxt_auto_config.h
+ sed -e "s|%%ERROR_LOG_PATH%%|$NXT_LOG|" \\
+ -e "s|%%PID_PATH%%|$NXT_PID|" \\
+ -e "s|%%SOCKET_PATH%%|$NXT_CONTROL|" \\
+ < docs/man/unitd.8.in > \$@
+
+END
+
+
# unit object files.
for nxt_src in $NXT_MAKE_SRCS
@@ -334,9 +348,9 @@ done
cat << END >> $NXT_MAKEFILE
-.PHONY: install ${NXT_DAEMON}-install install-check
+.PHONY: install ${NXT_DAEMON}-install install-check manpage-install
-install: ${NXT_DAEMON}-install
+install: ${NXT_DAEMON}-install manpage-install
install-check:
@test -n "\$(DESTDIR)$NXT_PREFIX" \\
@@ -352,15 +366,22 @@ ${NXT_DAEMON}-install: $NXT_DAEMON install-check
install -p $NXT_BUILD_DIR/$NXT_DAEMON \$(DESTDIR)$NXT_SBINDIR/
install -d \$(DESTDIR)$NXT_STATE
+manpage-install: manpage install-check
+ install -d \$(DESTDIR)$NXT_MANDIR/man8
+ install -p $NXT_BUILD_DIR/unitd.8 \$(DESTDIR)$NXT_MANDIR/man8/
-.PHONY: uninstall ${NXT_DAEMON}-uninstall
+.PHONY: uninstall ${NXT_DAEMON}-uninstall manpage-uninstall
-uninstall: ${NXT_DAEMON}-uninstall
+uninstall: ${NXT_DAEMON}-uninstall manpage-uninstall
${NXT_DAEMON}-uninstall:
rm -f \$(DESTDIR)$NXT_SBINDIR/$NXT_DAEMON
@rmdir -p \$(DESTDIR)$NXT_SBINDIR 2>/dev/null || true
+manpage-uninstall:
+ rm -f \$(DESTDIR)$NXT_MANDIR/man8/unitd.8
+ @rmdir -p \$(DESTDIR)$NXT_MANDIR/man8 2>/dev/null || true
+
END
cat << END >> $NXT_MAKEFILE
diff --git a/auto/modules/java b/auto/modules/java
index 60415c35..05b3100c 100644
--- a/auto/modules/java
+++ b/auto/modules/java
@@ -238,7 +238,7 @@ cat << END > $NXT_JAVA_JARS
static const char *nxt_java_system_jars[] = {
END
-NXT_TOMCAT_VERSION=9.0.39
+NXT_TOMCAT_VERSION=9.0.44
NXT_JAR_VERSION=$NXT_TOMCAT_VERSION
@@ -271,7 +271,7 @@ NXT_JAR_NAME=tomcat-util
. auto/modules/java_get_jar
NXT_JAR_NAME=ecj
-NXT_JAR_VERSION=3.23.0
+NXT_JAR_VERSION=3.25.0
NXT_JAR_NAMESPACE=org/eclipse/jdt/
. auto/modules/java_get_jar
@@ -284,7 +284,7 @@ static const char *nxt_java_unit_jars[] = {
"$NXT_UNIT_JAR",
END
-NXT_JAR_VERSION=9.4.33.v20201020
+NXT_JAR_VERSION=9.4.38.v20210224
NXT_JAR_NAMESPACE=org/eclipse/jetty/
NXT_JAR_NAME=jetty-util
@@ -297,7 +297,7 @@ NXT_JAR_NAME=jetty-http
. auto/modules/java_get_jar
NXT_JAR_NAME=classgraph
-NXT_JAR_VERSION=4.8.90
+NXT_JAR_VERSION=4.8.102
NXT_JAR_NAMESPACE=io/github/classgraph/
. auto/modules/java_get_jar
diff --git a/auto/modules/java_jar.sha512 b/auto/modules/java_jar.sha512
index 214cff33..98d27149 100644
--- a/auto/modules/java_jar.sha512
+++ b/auto/modules/java_jar.sha512
@@ -1,14 +1,14 @@
-083f2102a50f2c3a4fc3993d328ddee17707b0529fdcee4868bd3b6901ff20a3d97e9733f83b2e46828469ecc273a1a3a5da26e4ba3d63f725a81b0b9e3e49e6 classgraph-4.8.90.jar
-5e63e06eccd76a61249c7c6bd97e5b77dc37335bfdf316d941b00a16bae4f152d4306bac4e45c8422976187b0d77fe30cf7e6f6d4425f7732a3cb0cfa954385b ecj-3.23.0.jar
-9abb4ba6802c39526b755429e3f41d641408f91f1c48844cd56cda116fb1479f05f1a3d90c18f30386b07d5593221c1f85ef565da0c6121b6ff005ec7d9c3bd9 jetty-http-9.4.33.v20201020.jar
-e60e73ed3fd18e029c8e3cae04eac01d05f985dd0d9059eea620f4f9acac60799706d4b56b5a0f10cc33ff9272afdf11e712c604e31a77fa1afa1f95a57294ce jetty-server-9.4.33.v20201020.jar
-35c5ad89d92e77f542d3ce42249f01c478706e2a013c5ab6a9504cf43520e3de90280d82a11389e9909060835421e3caada68e77d86df76a84856be60361d550 jetty-util-9.4.33.v20201020.jar
-2d28d12196a7c2d342876d7e63c3a87fd613aadb32afad28d428d5dd9d9d0ebfa8300de3681d885455ac81d215326b11b845346416d5bd12d0e27c1763602caa tomcat-api-9.0.39.jar
-661e613ae966e9b1fcc8815823c273fd7a05a6f8d3c469d86ce50650c1f350cbfb624fde8ee86235603078d9c5ccae5dfec8e03e10b5cb1e11109ae6ae4e85bb tomcat-el-api-9.0.39.jar
-541d4794e1e15f26d7853cd7841f031e66fd3fc345102871cf58013591c8b57b6ab470d8ac28781c077f25e8d7fc06c19c6444db8e4a28ce4767ddbd907be004 tomcat-jasper-9.0.39.jar
-57b916cb87f178604751f52f23f57fbd05da3001c9419602836e25d779727500bc1fceae195d5758aff28393b396751538f2ab7a9390738ebe4d0b4bd17b8ee4 tomcat-jasper-el-9.0.39.jar
-d34deeecdecd59e40225ca3ad0ac197fc7f7845f09f551f5f17290ff9971741e62fac4bde16499d585b3d7c5574927c09740c0976dbddacecb19b4772f60c3e3 tomcat-jsp-api-9.0.39.jar
-ee43f08f26e1d48c5cd3719e1eeec26e4ef389647a0bcd31435ed85c6c8770ab48fe287c60432aa8821b8fc8fce8ef0977a29b29c8c3b3cb246be53fb0182d1a tomcat-juli-9.0.39.jar
-c387931fba85eae7ce030601dbd760cc7c2b0242a670b0c62321a8972e534076a40150044886053b3771099aa57c89057892d4f7fda84f65fa67b9c53dd51400 tomcat-servlet-api-9.0.39.jar
-aa0b5ff10cdc686ba1dbc8a35d75aa42196126cbbde0d1ab1b9211ba57987a246bbe825c89a88104a0a60869fcbff4a8067bb247e42b69c887d6b48ee5c4a417 tomcat-util-9.0.39.jar
-42c4b698cfb0a1fb154e290ac265c14693a9ef094e54116a324864f5b483f37d7a7decf67f7fe43b546cf1d2f25e9d763adc598a5e92979f756299e981dde43d tomcat-util-scan-9.0.39.jar
+5105e9edf0fc6a4a51eb2bb1e2c23bb78a604fe2df3b1e814cf638ce22845a6ae57e75af31db9dd00d5c650403e751659cca8d3bc465fb96525c695188d2055f classgraph-4.8.102.jar
+48cee25d195a5c713a962b035ecba633797753474f290c107a0ee96272cd9ae1b6b62b060ef37e0699f6a5af4d4b45e514ef710309f41bdd9440925cf60a111a ecj-3.25.0.jar
+3f2a4a5b7f71c6a1317cec29ea12eb04eac68f4cee94c30ffb75fdd36dbc9c622059fb762e27f74f7b7a38eb84966732ba963cc294f5aaf8b7f5f8c9d60c8899 jetty-http-9.4.38.v20210224.jar
+cc416b324841e9c259538a3ec678a9d8e07d3bea9b0bb687bc15a759c5065c7de6ea7bbbb15b369b8c6d2023c3294906d8f9cfda28e1b7859283008790581a4d jetty-server-9.4.38.v20210224.jar
+efdbeae97c959459c10b05aae62189c535a0935dadf7debf4257257c31a98a4167ca1318daa81dae32161f51117b17468d5fb5a6bb4eea40864ce1265623d684 jetty-util-9.4.38.v20210224.jar
+f2534f246c0cec9be576f18d67759b5a997074bb7870cbf7b9469f062ddc6932e5cec45fd439a5beacc8c6248d39dc458af81245a6eb988e294667f2bcd251df tomcat-api-9.0.44.jar
+0c8050b04b02a6a1f1384d1a4041594c09868cfeb139978274c5e5797eb95e0668495f489eb61cfe742905e453184edc0ad8a9fd3b2796e960981a20ae4a0334 tomcat-el-api-9.0.44.jar
+cc81a06795553f06d3dfe930429fdf47a8e0c1813c554b640d98090cc661c1eb27a91b9a9055bd14d918fc9451073632a635741dd413fd7b4a380d8907862e14 tomcat-jasper-9.0.44.jar
+de50107ff31b8c5a7eb97fe86c2fdfa38305be632c8d62329219884dfb6bbe76372b40a67e808263a55b510a41cde639d55e7925d89db06472392519f0410063 tomcat-jasper-el-9.0.44.jar
+69a79e58cea950b713f26a94e1db90221c297375a338f010d1332027ef5d93fd262163ec787b06d8cd41a4a31faa81bb4fc83836148eb14a6757591f6fe5f3c6 tomcat-jsp-api-9.0.44.jar
+ca036312596dbd92ae43dda79a9a5ad168cf90a12369636fdc6febbedb559b83d5fa22d77629659b588d70990f8a077fd8356be1c56b0227e07688b67dd7c76e tomcat-juli-9.0.44.jar
+952c122413805de16de603cfc233785e53b558b39f146b6fa4e11324e26572e4aee76fec2ee69adecc8f4271cd28acb917e1a9e61a908710b3582ab1f76c9706 tomcat-servlet-api-9.0.44.jar
+6920bfb2b1ae173d716fedbf4f238003f569a161f277a888c2d53dac0af80ef0480c9ca3be0ede4583716c1b97c1cfa1665439d14274b7d73ec948fd9f952b89 tomcat-util-9.0.44.jar
+915304750cbdffc4c9926fcb22eb928d2895cccd8b3f6f13aefb4e5302cccf5f513502b70812630026dd2968712c4c3b1cfe98d37ecf7b349988e7255ddc5b18 tomcat-util-scan-9.0.44.jar
diff --git a/auto/modules/nodejs b/auto/modules/nodejs
index edaf99ac..b2309143 100644
--- a/auto/modules/nodejs
+++ b/auto/modules/nodejs
@@ -122,8 +122,11 @@ fi
NXT_NODE_TMP=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http
+NXT_NODE_TMP_G=${NXT_BUILD_DIR}/src/${NXT_NODE}/unit-http-g
NXT_NODE_TARBALL=${NXT_BUILD_DIR}/${NXT_NODE}-unit-http.tar.gz
-NXT_NODE_VERSION_FILE=${NXT_NODE_TMP}/version.h
+NXT_NODE_TARBALL_G=${NXT_BUILD_DIR}/${NXT_NODE}-unit-http-g.tar.gz
+NXT_NODE_VERSION_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/version.h
+NXT_NODE_PACKAGE_FILE=${NXT_BUILD_DIR}/src/${NXT_NODE}/package.json
NXT_NODE_EXPORTS="export UNIT_SRC_PATH=${PWD}/src \
&& export UNIT_BUILD_PATH=${PWD}/${NXT_BUILD_DIR} \
&& export UNIT_LIB_STATIC_PATH=${PWD}/${NXT_BUILD_DIR}/libunit.a"
@@ -138,6 +141,7 @@ cat << END >> $NXT_MAKEFILE
.PHONY: ${NXT_NODE}
.PHONY: ${NXT_NODE}-copy
+.PHONY: ${NXT_NODE}-copy-g
.PHONY: ${NXT_NODE}-install
.PHONY: ${NXT_NODE}-uninstall
.PHONY: ${NXT_NODE}-local-check
@@ -149,27 +153,37 @@ ${NXT_NODE}: ${NXT_NODE}-copy $NXT_BUILD_DIR/$NXT_LIB_UNIT_STATIC
${NXT_NODE_EXPORTS} && \\
cd ${NXT_NODE_TMP} && ${NXT_NODE_GYP} configure build clean
-${NXT_NODE}-copy: ${NXT_NODE_VERSION_FILE}
- mkdir -p ${NXT_BUILD_DIR}/src/
- cp -rp src/nodejs/* ${NXT_BUILD_DIR}/src/${NXT_NODE}
+${NXT_NODE}-copy: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE}
+ mkdir -p ${NXT_NODE_TMP}
+ cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP}/
+ cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP}/
+
+${NXT_NODE}-copy-g: ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE}
+ mkdir -p ${NXT_NODE_TMP_G}
+ cp -rp src/nodejs/unit-http/* ${NXT_NODE_TMP_G}/
+ cp -p ${NXT_NODE_VERSION_FILE} ${NXT_NODE_PACKAGE_FILE} ${NXT_NODE_TMP_G}/
+ mv ${NXT_NODE_TMP_G}/binding_pub.gyp ${NXT_NODE_TMP_G}/binding.gyp
${NXT_NODE_VERSION_FILE}: ${NXT_VERSION_H}
- mkdir -p ${NXT_NODE_TMP}
+ mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE}
$echo '#define NXT_NODE_VERNUM \$(NXT_VERNUM)' > $NXT_NODE_VERSION_FILE
+${NXT_NODE_PACKAGE_FILE}: ${NXT_VERSION_H} src/nodejs/unit-http/package.json
+ mkdir -p ${NXT_BUILD_DIR}/src/${NXT_NODE}
+ sed -e "s|%%VERSION%%|\$(NXT_VERSION)|" \
+ src/nodejs/unit-http/package.json > ${NXT_NODE_PACKAGE_FILE}
+
${NXT_NODE_TARBALL}: ${NXT_NODE}-copy
- sed -e 's/"version"\s*:.*/"version": "\$(NXT_VERSION)",/' \
- ${NXT_NODE_TMP}/package.json > ${NXT_NODE_TMP}/package.json.tmp
- mv ${NXT_NODE_TMP}/package.json.tmp ${NXT_NODE_TMP}/package.json
tar -zcvf ${NXT_NODE_TARBALL} -C ${NXT_NODE_TMP} .
+${NXT_NODE_TARBALL_G}: ${NXT_NODE}-copy-g
+ tar -zcvf ${NXT_NODE_TARBALL_G} -C ${NXT_NODE_TMP_G} .
+
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 --unsafe-perm ${PWD}/${NXT_NODE_TARBALL}
+${NXT_NODE}-install: ${NXT_NODE_TARBALL_G} libunit-install
+ ${NXT_NPM} install -g --unsafe-perm ${PWD}/${NXT_NODE_TARBALL_G}
${NXT_NODE}-uninstall:
${NXT_NPM} uninstall -g unit-http
diff --git a/auto/options b/auto/options
index b6007bc2..572d8a9b 100644
--- a/auto/options
+++ b/auto/options
@@ -59,6 +59,7 @@ do
--sbindir=*) NXT_SBINDIR="$value" ;;
--libdir=*) NXT_LIBDIR="$value" ;;
--incdir=*) NXT_INCDIR="$value" ;;
+ --mandir=*) NXT_MANDIR="$value" ;;
--modules=*) NXT_MODULES="$value" ;;
--state=*) NXT_STATE="$value" ;;
--tmp=*) NXT_TMP="$value" ;;
@@ -144,6 +145,11 @@ case "$NXT_INCDIR" in
*) NXT_INCDIR="$NXT_PREFIX$NXT_INCDIR" ;;
esac
+case "$NXT_MANDIR" in
+ /*) ;;
+ *) NXT_MANDIR="$NXT_PREFIX$NXT_MANDIR" ;;
+esac
+
case "$NXT_MODULES" in
/*) ;;
*) NXT_MODULES="$NXT_PREFIX$NXT_MODULES" ;;
diff --git a/auto/summary b/auto/summary
index 833d20c0..84bfbb7f 100644
--- a/auto/summary
+++ b/auto/summary
@@ -11,6 +11,7 @@ Unit configuration summary:
sbin directory: ............ "$NXT_SBINDIR"
lib directory: ............. "$NXT_LIBDIR"
include directory: ......... "$NXT_INCDIR"
+ man pages directory: ....... "$NXT_MANDIR"
modules directory: ......... "$NXT_MODULES"
state directory: ........... "$NXT_STATE"
tmp directory: ............. "$NXT_TMP"
diff --git a/configure b/configure
index ece4f12a..c9264d59 100755
--- a/configure
+++ b/configure
@@ -35,6 +35,7 @@ NXT_BINDIR="bin"
NXT_SBINDIR="sbin"
NXT_LIBDIR="lib"
NXT_INCDIR="include"
+NXT_MANDIR="share/man"
NXT_MODULES="modules"
NXT_STATE="state"
NXT_TMP="tmp"
diff --git a/docs/changes.xml b/docs/changes.xml
index 4db9cf3e..6c79b560 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -5,6 +5,112 @@
<change_log title="unit">
+<changes apply="unit-php
+ unit-python unit-python2.7
+ unit-python3.4 unit-python3.5 unit-python3.6 unit-python3.7
+ unit-python3.8 unit-python3.9
+ unit-go
+ unit-perl
+ unit-ruby
+ unit-jsc-common unit-jsc8 unit-jsc10 unit-jsc11 unit-jsc13
+ unit-jsc14 unit-jsc15"
+ ver="1.23.0" rev="1"
+ date="2021-03-25" time="18:00:00 +0300"
+ packager="Andrei Belov &lt;defan@nginx.com&gt;">
+
+<change>
+<para>
+NGINX Unit updated to 1.23.0.
+</para>
+</change>
+
+</changes>
+
+
+<changes apply="unit" ver="1.23.0" rev="1"
+ date="2021-03-25" time="18:00:00 +0300"
+ packager="Andrei Belov &lt;defan@nginx.com&gt;">
+
+<change type="feature">
+<para>
+support for multiple certificate bundles on a listener via the Server Name
+Indication (SNI) TLS extension.
+</para>
+</change>
+
+<change type="feature">
+<para>
+"--mandir" ./configure option to specify the directory for man page
+installation.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+the router process could crash on premature TLS connection close; the bug had
+appeared in 1.17.0.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+a connection leak occurred on premature TLS connection close; the bug had
+appeared in 1.6.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+a descriptor and memory leak occurred in the router process when processing
+small WebSocket frames from a client; the bug had appeared in 1.19.0.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+a descriptor leak occurred in the router process when removing or
+reconfiguring an application; the bug had appeared in 1.19.0.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+persistent storage of certificates might've not worked with some filesystems in
+Linux, and all uploaded certificate bundles were forgotten after restart.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+the controller process could crash while requesting information about a
+certificate with a non-DNS SAN entry.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+the controller process could crash on manipulations with a certificate
+containing a SAN and no standard name attributes in subject or issuer.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+the Ruby module didn't respect the user locale for defaults in the Encoding
+class.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+the PHP 5 module failed to build with thread safety enabled; the bug had
+appeared in 1.22.0.
+</para>
+</change>
+
+</changes>
+
+
<changes apply="unit-python3.9" ver="1.22.0" rev="1"
date="2021-02-04" time="18:00:00 +0300"
packager="Andrei Belov &lt;defan@nginx.com&gt;">
diff --git a/docs/man/unitd.8.in b/docs/man/unitd.8.in
new file mode 100644
index 00000000..46182781
--- /dev/null
+++ b/docs/man/unitd.8.in
@@ -0,0 +1,80 @@
+.\" (C) 2017-2021, NGINX, Inc.
+.\"
+.Dd March 16, 2021
+.Dt UNITD 8
+.Os
+.Sh NAME
+.Nm unitd
+.Nd "runs the NGINX Unit daemon"
+.Sh SYNOPSIS
+.Nm
+.Op Fl Fl no-daemon
+.Op Fl Fl control Ar socket
+.Op Fl Fl group Ar name
+.Op Fl Fl user Ar name
+.Op Fl Fl log Ar file
+.Op Fl Fl modules Ar directory
+.Op Fl Fl pid Ar file
+.Op Fl Fl state Ar directory
+.Nm
+.Op Fl h | Fl Fl help | v | Fl Fl version
+.Sh DESCRIPTION
+NGINX Unit is a polyglot app server, a reverse proxy, and a static file server
+for UNIX-like systems.
+It was built by
+.Xr nginx 8
+team members from
+scratch to be highly efficient and fully configurable at runtime.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl h , Fl Fl help
+Displays a summary of Unit's command-line options and their
+compile-time defaults.
+.It Fl v , Fl Fl version
+Displays Unit's version and the
+.Pa ./configure
+settings it was built with.
+.It Fl Fl no-daemon
+Runs Unit in non-daemon mode.
+.It Fl Fl control Ar socket
+Overrides the control API's socket address in IPv4, IPv6,
+or UNIX-domain format.
+.It Fl Fl group Ar name , Fl Fl user Ar name
+Override group name and user name used to run Unit's non-privileged processes.
+.It Fl Fl log Ar file
+Overrides the pathname for Unit's log.
+.It Fl Fl modules Ar directory
+Overrides the directory path for Unit's language modules
+.Po Pa *.unit.so
+.Pc files .
+.It Fl Fl pid Ar file
+Overrides the pathname for the PID file of Unit's main process.
+.It Fl Fl state Ar directory
+Overrides the directory path for Unit's state storage.
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success, or 1 if the daemon encounters an error.
+.Sh FILES
+.Bl -tag -width indent
+.It Pa %%PID_PATH%%
+The PID file of Unit's main process.
+.It Pa %%ERROR_LOG_PATH%%
+A general-purpose log for diagnostics and troubleshooting.
+.El
+.Sh SOCKETS
+.Bl -tag -width indent
+.It Pa %%SOCKET_PATH%%
+The socket address of Unit's control API.
+.El
+.Sh AUTHORS
+(C) 2017-2021, NGINX, Inc.
+.Sh SEE ALSO
+.Pp
+Website:
+.Pa https://unit.nginx.org
+.Pp
+User mailing list:
+.Pa https://mailman.nginx.org/mailman/listinfo/unit
+.Pp
+GitHub:
+.Pa https://github.com/nginx/unit
diff --git a/pkg/deb/Makefile b/pkg/deb/Makefile
index 16e73b94..8c33fc53 100644
--- a/pkg/deb/Makefile
+++ b/pkg/deb/Makefile
@@ -227,7 +227,7 @@ endif
debuild/unit_$(VERSION).orig.tar.gz: | debuild/$(SRCDIR)/debian
cd ../.. && tar -czf pkg/deb/debuild/$(SRCDIR).tar.gz \
--transform "s#^#$(SRCDIR)/#" \
- LICENSE NOTICE CHANGES README configure auto src test version go
+ LICENSE NOTICE CHANGES README configure auto src test version go docs/man/unitd.8.in
mv debuild/$(SRCDIR).tar.gz debuild/unit_$(VERSION).orig.tar.gz
cd debuild && tar zxf unit_$(VERSION).orig.tar.gz
diff --git a/pkg/deb/debian/rules.in b/pkg/deb/debian/rules.in
index aa7921d1..c7a56b6b 100644
--- a/pkg/deb/debian/rules.in
+++ b/pkg/deb/debian/rules.in
@@ -33,6 +33,8 @@ config.env.%:
cp -Pa $(CURDIR)/NOTICE $(BUILDDIR_$*)/
cp -Pa $(CURDIR)/README $(BUILDDIR_$*)/
cp -Pa $(CURDIR)/go $(BUILDDIR_$*)/
+ mkdir -p $(BUILDDIR_$*)/docs/man
+ cp -Pa $(CURDIR)/docs/man/unitd.8.in $(BUILDDIR_$*)/docs/man/
touch $@
configure.unit: config.env.unit
@@ -117,7 +119,7 @@ binary-indep: build install
dh_testdir
dh_testroot
dh_installdocs
- dh_installchangelogs
+ dh_installchangelogs
dh_link
dh_strip --dbg-package=unit-dbg
dh_shlibdeps
diff --git a/pkg/docker/Dockerfile.go1.15 b/pkg/docker/Dockerfile.go1.15
index 270dc428..45642662 100644
--- a/pkg/docker/Dockerfile.go1.15
+++ b/pkg/docker/Dockerfile.go1.15
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -63,7 +63,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11
index cde7c590..4cfc541d 100644
--- a/pkg/docker/Dockerfile.jsc11
+++ b/pkg/docker/Dockerfile.jsc11
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal
index 91fd79d0..59aaa6a3 100644
--- a/pkg/docker/Dockerfile.minimal
+++ b/pkg/docker/Dockerfile.minimal
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.node15 b/pkg/docker/Dockerfile.node15
index 59b12012..7eddfb26 100644
--- a/pkg/docker/Dockerfile.node15
+++ b/pkg/docker/Dockerfile.node15
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -63,7 +63,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.perl5.32 b/pkg/docker/Dockerfile.perl5.32
index 589eb989..aa000f63 100644
--- a/pkg/docker/Dockerfile.perl5.32
+++ b/pkg/docker/Dockerfile.perl5.32
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.php8.0 b/pkg/docker/Dockerfile.php8.0
index c31513d4..4534f9b5 100644
--- a/pkg/docker/Dockerfile.php8.0
+++ b/pkg/docker/Dockerfile.php8.0
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.python3.9 b/pkg/docker/Dockerfile.python3.9
index 76f50733..e8650d44 100644
--- a/pkg/docker/Dockerfile.python3.9
+++ b/pkg/docker/Dockerfile.python3.9
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/Dockerfile.ruby2.7 b/pkg/docker/Dockerfile.ruby2.7
index aa823756..aa8cdb3f 100644
--- a/pkg/docker/Dockerfile.ruby2.7
+++ b/pkg/docker/Dockerfile.ruby2.7
@@ -8,7 +8,7 @@ RUN set -ex \
&& mkdir -p /usr/lib/unit/modules /usr/lib/unit/debug-modules \
&& hg clone https://hg.nginx.org/unit \
&& cd unit \
- && hg up 1.22.0 \
+ && hg up 1.23.0 \
&& NCPU="$(getconf _NPROCESSORS_ONLN)" \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -q DEB_HOST_MULTIARCH)" \
&& CC_OPT="$(DEB_BUILD_MAINT_OPTIONS="hardening=+all,-pie" DEB_CFLAGS_MAINT_APPEND="-Wp,-D_FORTIFY_SOURCE=2 -fPIC" dpkg-buildflags --get CFLAGS)" \
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/docker/template.Dockerfile b/pkg/docker/template.Dockerfile
index d96d7982..55feecc6 100644
--- a/pkg/docker/template.Dockerfile
+++ b/pkg/docker/template.Dockerfile
@@ -61,7 +61,7 @@ RUN set -x \
--shell /bin/false \
unit \
&& apt update \
- && apt --no-install-recommends --no-install-suggests -y install $(cat /requirements.apt) \
+ && apt --no-install-recommends --no-install-suggests -y install curl $(cat /requirements.apt) \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& rm -f /requirements.apt \
&& ln -sf /dev/stdout /var/log/unit.log
diff --git a/pkg/rpm/Makefile b/pkg/rpm/Makefile
index f0bd0cf9..75327c49 100644
--- a/pkg/rpm/Makefile
+++ b/pkg/rpm/Makefile
@@ -214,7 +214,7 @@ endif
rpmbuild/SOURCES/unit-$(VERSION).tar.gz:
cd ../.. && tar -czf pkg/rpm/rpmbuild/SOURCES/unit-$(VERSION).tar.gz \
--transform "s#^#unit-$(VERSION)/#" \
- LICENSE NOTICE CHANGES README configure auto src test version go
+ LICENSE NOTICE CHANGES README configure auto src test version go docs/man/unitd.8.in
unit: check-build-depends-unit rpmbuild/SPECS/unit.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz
@echo "===> Building $@ package" ; \
diff --git a/pkg/rpm/unit.spec.in b/pkg/rpm/unit.spec.in
index 08db73e2..3a148b9d 100644
--- a/pkg/rpm/unit.spec.in
+++ b/pkg/rpm/unit.spec.in
@@ -98,7 +98,7 @@ Library and include files required for NGINX Unit modules development.
%install
%{__rm} -rf %{buildroot}
%{__ln_s} build-nodebug build
-DESTDIR=%{buildroot} make unitd-install libunit-install
+DESTDIR=%{buildroot} make unitd-install libunit-install manpage-install
%{__install} -m755 %{bdir}/build-debug/unitd \
%{buildroot}%{_sbindir}/unitd-debug
%{__install} -m644 %{bdir}/build-debug/libunit.a \
@@ -205,6 +205,7 @@ BANNER
%dir %{_sharedstatedir}/unit
%dir %attr(0700,root,root) %{_localstatedir}/log/unit
%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
+%{_mandir}/man8/unitd.8*
%files devel
%{_libdir}/libunit.a
diff --git a/src/nodejs/unit-http/package.json b/src/nodejs/unit-http/package.json
index 7ee01346..81f06bd4 100644
--- a/src/nodejs/unit-http/package.json
+++ b/src/nodejs/unit-http/package.json
@@ -1,6 +1,6 @@
{
"name": "unit-http",
- "version": "1.0.0",
+ "version": "%%VERSION%%",
"description": "HTTP module for NGINX Unit",
"main": "http.js",
"files": [
diff --git a/src/nxt_app_log.c b/src/nxt_app_log.c
index 0ecd9aac..ae57c2a2 100644
--- a/src/nxt_app_log.c
+++ b/src/nxt_app_log.c
@@ -19,7 +19,10 @@ static u_char *nxt_log_debug_time(u_char *buf, nxt_realtime_t *now,
void nxt_cdecl
nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
{
- u_char *p, *syslogmsg, *end;
+ u_char *p, *end;
+#if 0
+ u_char *syslogmsg;
+#endif
va_list args;
nxt_thread_t *thr;
nxt_time_string_t *time_cache;
@@ -34,7 +37,9 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
p = nxt_thread_time_string(thr, time_cache, msg);
+#if 0
syslogmsg = p;
+#endif
#if 0
nxt_fid_t fid;
@@ -79,6 +84,7 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
(void) nxt_write_console(nxt_stderr, msg, p - msg);
+#if 0
if (level == NXT_LOG_ALERT) {
*(p - nxt_length("\n")) = '\0';
@@ -88,6 +94,7 @@ nxt_log_time_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
*/
nxt_write_syslog(LOG_ALERT, syslogmsg);
}
+#endif
}
diff --git a/src/nxt_cert.c b/src/nxt_cert.c
index 9e825d80..3cdb69c1 100644
--- a/src/nxt_cert.c
+++ b/src/nxt_cert.c
@@ -46,6 +46,8 @@ static int nxt_nxt_cert_pem_suffix(char *pem_str, const char *suffix);
static nxt_conf_value_t *nxt_cert_details(nxt_mp_t *mp, nxt_cert_t *cert);
static nxt_conf_value_t *nxt_cert_name_details(nxt_mp_t *mp, X509 *x509,
nxt_bool_t issuer);
+static nxt_conf_value_t *nxt_cert_alt_names_details(nxt_mp_t *mp,
+ STACK_OF(GENERAL_NAME) *alt_names);
static nxt_lvlhsh_t nxt_cert_info;
@@ -654,7 +656,6 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer)
nxt_str_t str;
nxt_int_t ret;
nxt_uint_t i, n, count;
- GENERAL_NAME *name;
nxt_conf_value_t *object, *names;
STACK_OF(GENERAL_NAME) *alt_names;
u_char buf[256];
@@ -689,12 +690,23 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer)
NULL, NULL);
if (alt_names != NULL) {
+ names = nxt_cert_alt_names_details(mp, alt_names);
+
+ sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+
+ if (nxt_slow_path(names == NULL)) {
+ return NULL;
+ }
+
count++;
+
+ } else {
+ names = NULL;
}
object = nxt_conf_create_object(mp, count);
if (nxt_slow_path(object == NULL)) {
- goto fail;
+ return NULL;
}
for (n = 0, i = 0; n != nxt_nitems(nids) && i != count; n++) {
@@ -702,12 +714,12 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer)
len = X509_NAME_get_text_by_NID(x509_name, nids[n].nid,
(char *) buf, sizeof(buf));
- if (len < 0) {
- continue;
+ if (n == 1 && names != NULL) {
+ nxt_conf_set_member(object, &alt_names_str, names, i++);
}
- if (i == 1 && alt_names != NULL) {
- i++;
+ if (len < 0) {
+ continue;
}
str.length = len;
@@ -716,60 +728,62 @@ nxt_cert_name_details(nxt_mp_t *mp, X509 *x509, nxt_bool_t issuer)
ret = nxt_conf_set_member_string_dup(object, mp, &nids[n].name,
&str, i++);
if (nxt_slow_path(ret != NXT_OK)) {
- goto fail;
+ return NULL;
}
}
- if (alt_names != NULL) {
- count = sk_GENERAL_NAME_num(alt_names);
-
- for (n = 0; n != count; n++) {
- name = sk_GENERAL_NAME_value(alt_names, n);
+ return object;
+}
- if (name->type != GEN_DNS) {
- continue;
- }
- }
- names = nxt_conf_create_array(mp, n);
- if (nxt_slow_path(names == NULL)) {
- goto fail;
- }
+static nxt_conf_value_t *
+nxt_cert_alt_names_details(nxt_mp_t *mp, STACK_OF(GENERAL_NAME) *alt_names)
+{
+ nxt_str_t str;
+ nxt_int_t ret;
+ nxt_uint_t i, n, count;
+ GENERAL_NAME *name;
+ nxt_conf_value_t *array;
- for (n = 0, i = 0; n != count; n++) {
- name = sk_GENERAL_NAME_value(alt_names, n);
+ count = sk_GENERAL_NAME_num(alt_names);
+ n = 0;
- if (name->type != GEN_DNS) {
- continue;
- }
+ for (i = 0; i != count; i++) {
+ name = sk_GENERAL_NAME_value(alt_names, i);
- str.length = ASN1_STRING_length(name->d.dNSName);
-#if OPENSSL_VERSION_NUMBER > 0x10100000L
- str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
-#else
- str.start = ASN1_STRING_data(name->d.dNSName);
-#endif
-
- ret = nxt_conf_set_element_string_dup(names, mp, i++, &str);
- if (nxt_slow_path(ret != NXT_OK)) {
- goto fail;
- }
+ if (name->type != GEN_DNS) {
+ continue;
}
- sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+ n++;
+ }
- nxt_conf_set_member(object, &alt_names_str, names, 1);
+ array = nxt_conf_create_array(mp, n);
+ if (nxt_slow_path(array == NULL)) {
+ return NULL;
}
- return object;
+ for (n = 0, i = 0; n != count; n++) {
+ name = sk_GENERAL_NAME_value(alt_names, n);
-fail:
+ if (name->type != GEN_DNS) {
+ continue;
+ }
- if (alt_names != NULL) {
- sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+ str.length = ASN1_STRING_length(name->d.dNSName);
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+ str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
+#else
+ str.start = ASN1_STRING_data(name->d.dNSName);
+#endif
+
+ ret = nxt_conf_set_element_string_dup(array, mp, i++, &str);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NULL;
+ }
}
- return NULL;
+ return array;
}
@@ -838,7 +852,12 @@ nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp)
break;
}
- if (de->d_type != DT_REG) {
+ nxt_debug(task, "readdir(\"%s\"): \"%s\"", rt->certs.start, de->d_name);
+
+ name.length = nxt_strlen(de->d_name);
+ name.start = (u_char *) de->d_name;
+
+ if (nxt_str_eq(&name, ".", 1) || nxt_str_eq(&name, "..", 2)) {
continue;
}
@@ -849,9 +868,6 @@ nxt_cert_store_load(nxt_task_t *task, nxt_mp_t *mp)
item->fd = -1;
- name.length = nxt_strlen(de->d_name);
- name.start = (u_char *) de->d_name;
-
size = rt->certs.length + name.length + 1;
if (size > alloc) {
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 67fa3095..8c5d1ec7 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -87,6 +87,8 @@ static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
#if (NXT_TLS)
static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value);
#endif
static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
@@ -354,7 +356,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = {
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = {
{
.name = nxt_string("certificate"),
- .type = NXT_CONF_VLDT_STRING,
+ .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
.validator = nxt_conf_vldt_certificate,
},
@@ -1459,10 +1461,10 @@ nxt_conf_vldt_thread_stack_size(nxt_conf_validation_t *vldt,
size = nxt_conf_get_number(value);
- if (size < PTHREAD_STACK_MIN) {
+ if (size < NXT_THREAD_STACK_MIN) {
return nxt_conf_vldt_error(vldt, "The \"thread_stack_size\" number "
"must be equal to or greater than %d.",
- PTHREAD_STACK_MIN);
+ NXT_THREAD_STACK_MIN);
}
if ((size % nxt_pagesize) != 0) {
@@ -1827,9 +1829,34 @@ static nxt_int_t
nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
+ if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
+ if (nxt_conf_array_elements_count(value) == 0) {
+ return nxt_conf_vldt_error(vldt, "The \"certificate\" array "
+ "must contain at least one element.");
+ }
+
+ return nxt_conf_vldt_array_iterator(vldt, value,
+ &nxt_conf_vldt_certificate_element);
+ }
+
+ /* NXT_CONF_STRING */
+
+ return nxt_conf_vldt_certificate_element(vldt, value);
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value)
+{
nxt_str_t name;
nxt_conf_value_t *cert;
+ if (nxt_conf_type(value) != NXT_CONF_STRING) {
+ return nxt_conf_vldt_error(vldt, "The \"certificate\" array must "
+ "contain only string values.");
+ }
+
nxt_conf_get_string(value, &name);
cert = nxt_cert_info_get(&name);
diff --git a/src/nxt_log.c b/src/nxt_log.c
index 1c666961..58756816 100644
--- a/src/nxt_log.c
+++ b/src/nxt_log.c
@@ -66,7 +66,10 @@ nxt_log_set_ctx(nxt_log_t *log, nxt_log_ctx_handler_t handler, void *ctx)
void nxt_cdecl
nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
{
- u_char *p, *syslogmsg, *end;
+ u_char *p, *end;
+#if 0
+ u_char *syslogmsg;
+#endif
va_list args;
u_char msg[NXT_MAX_ERROR_STR];
@@ -79,7 +82,9 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
*p++ = ' ';
}
+#if 0
syslogmsg = p;
+#endif
p = nxt_sprintf(p, end, (log->ident != 0) ? "[%V] *%D " : "[%V] ",
&nxt_log_levels[level], log->ident);
@@ -100,6 +105,7 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
(void) nxt_write_console(nxt_stderr, msg, p - msg);
+#if 0
if (level == NXT_LOG_ALERT) {
*(p - nxt_length("\n")) = '\0';
@@ -109,4 +115,5 @@ nxt_log_handler(nxt_uint_t level, nxt_log_t *log, const char *fmt, ...)
*/
nxt_write_syslog(LOG_ALERT, syslogmsg);
}
+#endif
}
diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c
index 832d1f0d..9b86150f 100644
--- a/src/nxt_openssl.c
+++ b/src/nxt_openssl.c
@@ -8,17 +8,20 @@
#include <openssl/ssl.h>
#include <openssl/conf.h>
#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
typedef struct {
- SSL *session;
- nxt_conn_t *conn;
+ SSL *session;
+ nxt_conn_t *conn;
- int ssl_error;
- uint8_t times; /* 2 bits */
- uint8_t handshake; /* 1 bit */
+ int ssl_error;
+ uint8_t times; /* 2 bits */
+ uint8_t handshake; /* 1 bit */
- nxt_buf_mem_t buffer;
+ nxt_tls_conf_t *conf;
+ nxt_buf_mem_t buffer;
} nxt_openssl_conn_t;
@@ -39,8 +42,18 @@ static unsigned long nxt_openssl_thread_id(void);
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_int_t nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd);
+ nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t last);
+static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx,
+ nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single);
+static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert,
+ nxt_tls_conf_t *conf, nxt_mp_t *mp);
+static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq,
+ void *data);
+static nxt_int_t nxt_openssl_bundle_hash_insert(nxt_task_t *task,
+ nxt_lvlhsh_t *lvlhsh, nxt_tls_bundle_hash_item_t *item, nxt_mp_t * mp);
+static nxt_int_t nxt_openssl_servername(SSL *s, int *ad, void *arg);
+static nxt_tls_bundle_conf_t *nxt_openssl_find_ctx(nxt_tls_conf_t *conf,
+ nxt_str_t *sn);
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);
@@ -244,12 +257,13 @@ nxt_openssl_locks_free(void)
static nxt_int_t
-nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
+nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf,
+ nxt_mp_t *mp, nxt_bool_t last)
{
- SSL_CTX *ctx;
- nxt_fd_t fd;
- const char *ciphers, *ca_certificate;
- STACK_OF(X509_NAME) *list;
+ SSL_CTX *ctx;
+ const char *ciphers, *ca_certificate;
+ STACK_OF(X509_NAME) *list;
+ nxt_tls_bundle_conf_t *bundle;
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL) {
@@ -257,8 +271,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
return NXT_ERROR;
}
- conf->ctx = ctx;
- conf->conn_init = nxt_openssl_conn_init;
+ bundle = conf->bundle;
+ nxt_assert(bundle != NULL);
+
+ bundle->ctx = ctx;
#ifdef SSL_OP_NO_RENEGOTIATION
/* Renegration is not currently supported. */
@@ -286,11 +302,10 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
#endif
- fd = conf->chain_file;
-
- if (nxt_openssl_chain_file(ctx, fd) != NXT_OK) {
- nxt_openssl_log_error(task, NXT_LOG_ALERT,
- "nxt_openssl_chain_file() failed");
+ if (nxt_openssl_chain_file(task, ctx, conf, mp,
+ last && bundle->next == NULL)
+ != NXT_OK)
+ {
goto fail;
}
/*
@@ -349,33 +364,51 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf)
SSL_CTX_set_client_CA_list(ctx, list);
}
+ if (last) {
+ conf->conn_init = nxt_openssl_conn_init;
+
+ if (bundle->next != NULL) {
+ SSL_CTX_set_tlsext_servername_callback(ctx, nxt_openssl_servername);
+ }
+ }
+
return NXT_OK;
fail:
SSL_CTX_free(ctx);
+#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
+ && OPENSSL_VERSION_NUMBER < 0x1010101fL)
+ RAND_keep_random_devices_open(0);
+#endif
+
return NXT_ERROR;
}
static nxt_int_t
-nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd)
+nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_conf_t *conf,
+ nxt_mp_t *mp, nxt_bool_t single)
{
- BIO *bio;
- X509 *cert, *ca;
- long reason;
- EVP_PKEY *key;
- nxt_int_t ret;
+ BIO *bio;
+ X509 *cert, *ca;
+ long reason;
+ EVP_PKEY *key;
+ nxt_int_t ret;
+ nxt_tls_bundle_conf_t *bundle;
+
+ ret = NXT_ERROR;
+ cert = NULL;
bio = BIO_new(BIO_s_fd());
if (bio == NULL) {
- return NXT_ERROR;
+ goto end;
}
- BIO_set_fd(bio, fd, BIO_CLOSE);
+ bundle = conf->bundle;
- ret = NXT_ERROR;
+ BIO_set_fd(bio, bundle->chain_file, BIO_CLOSE);
cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (cert == NULL) {
@@ -386,6 +419,10 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd)
goto end;
}
+ if (!single && nxt_openssl_cert_get_names(task, cert, conf, mp) != NXT_OK) {
+ goto clean;
+ }
+
for ( ;; ) {
ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
@@ -431,17 +468,324 @@ nxt_openssl_chain_file(SSL_CTX *ctx, nxt_fd_t fd)
end:
- X509_free(cert);
+ if (ret != NXT_OK) {
+ nxt_openssl_log_error(task, NXT_LOG_ALERT,
+ "nxt_openssl_chain_file() failed");
+ }
+
+clean:
+
BIO_free(bio);
+ X509_free(cert);
return ret;
}
+static nxt_uint_t
+nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf,
+ nxt_mp_t *mp)
+{
+ int len;
+ nxt_str_t domain, str;
+ X509_NAME *x509_name;
+ nxt_uint_t i, n;
+ GENERAL_NAME *name;
+ nxt_tls_bundle_conf_t *bundle;
+ STACK_OF(GENERAL_NAME) *alt_names;
+ nxt_tls_bundle_hash_item_t *item;
+
+ bundle = conf->bundle;
+
+ alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+ if (alt_names != NULL) {
+ n = sk_GENERAL_NAME_num(alt_names);
+
+ for (i = 0; i != n; i++) {
+ name = sk_GENERAL_NAME_value(alt_names, i);
+
+ if (name->type != GEN_DNS) {
+ continue;
+ }
+
+ str.length = ASN1_STRING_length(name->d.dNSName);
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+ str.start = (u_char *) ASN1_STRING_get0_data(name->d.dNSName);
+#else
+ str.start = ASN1_STRING_data(name->d.dNSName);
+#endif
+
+ domain.start = nxt_mp_nget(mp, str.length);
+ if (nxt_slow_path(domain.start == NULL)) {
+ goto fail;
+ }
+
+ domain.length = str.length;
+ nxt_memcpy_lowcase(domain.start, str.start, str.length);
+
+ item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
+ if (nxt_slow_path(item == NULL)) {
+ goto fail;
+ }
+
+ item->name = domain;
+ item->bundle = bundle;
+
+ if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash,
+ item, mp)
+ == NXT_ERROR)
+ {
+ goto fail;
+ }
+ }
+
+ sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+
+ } else {
+ x509_name = X509_get_subject_name(cert);
+ len = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
+ NULL, 0);
+ if (len <= 0) {
+ nxt_log(task, NXT_LOG_WARN, "certificate \"%V\" has neither "
+ "Subject Alternative Name nor Common Name", bundle->name);
+ return NXT_OK;
+ }
+
+ domain.start = nxt_mp_nget(mp, len + 1);
+ if (nxt_slow_path(domain.start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ domain.length = X509_NAME_get_text_by_NID(x509_name, NID_commonName,
+ (char *) domain.start,
+ len + 1);
+ nxt_memcpy_lowcase(domain.start, domain.start, domain.length);
+
+ item = nxt_mp_get(mp, sizeof(nxt_tls_bundle_hash_item_t));
+ if (nxt_slow_path(item == NULL)) {
+ return NXT_ERROR;
+ }
+
+ item->name = domain;
+ item->bundle = bundle;
+
+ if (nxt_openssl_bundle_hash_insert(task, &conf->bundle_hash, item,
+ mp)
+ == NXT_ERROR)
+ {
+ return NXT_ERROR;
+ }
+ }
+
+ return NXT_OK;
+
+fail:
+
+ sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+
+ return NXT_ERROR;
+}
+
+
+static const nxt_lvlhsh_proto_t nxt_openssl_bundle_hash_proto
+ nxt_aligned(64) =
+{
+ NXT_LVLHSH_DEFAULT,
+ nxt_openssl_bundle_hash_test,
+ nxt_mp_lvlhsh_alloc,
+ nxt_mp_lvlhsh_free,
+};
+
+
+static nxt_int_t
+nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
+{
+ nxt_tls_bundle_hash_item_t *item;
+
+ item = data;
+
+ return nxt_strstr_eq(&lhq->key, &item->name) ? NXT_OK : NXT_DECLINED;
+}
+
+
+static nxt_int_t
+nxt_openssl_bundle_hash_insert(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
+ nxt_tls_bundle_hash_item_t *item, nxt_mp_t *mp)
+{
+ nxt_str_t str;
+ nxt_int_t ret;
+ nxt_lvlhsh_query_t lhq;
+ nxt_tls_bundle_hash_item_t *old;
+
+ str = item->name;
+
+ if (item->name.start[0] == '*') {
+ item->name.start++;
+ item->name.length--;
+
+ if (item->name.length == 0 || item->name.start[0] != '.') {
+ nxt_log(task, NXT_LOG_WARN, "ignored invalid name \"%V\" "
+ "in certificate \"%V\": missing \".\" "
+ "after wildcard symbol", &str, item->bundle->name);
+ return NXT_OK;
+ }
+ }
+
+ lhq.pool = mp;
+ lhq.key = item->name;
+ lhq.value = item;
+ lhq.proto = &nxt_openssl_bundle_hash_proto;
+ lhq.replace = 0;
+ lhq.key_hash = nxt_murmur_hash2(item->name.start, item->name.length);
+
+ ret = nxt_lvlhsh_insert(lvlhsh, &lhq);
+ if (nxt_fast_path(ret == NXT_OK)) {
+ nxt_debug(task, "name \"%V\" for certificate \"%V\" is inserted",
+ &str, item->bundle->name);
+ return NXT_OK;
+ }
+
+ if (nxt_fast_path(ret == NXT_DECLINED)) {
+ old = lhq.value;
+ if (old->bundle != item->bundle) {
+ nxt_log(task, NXT_LOG_WARN, "ignored duplicate name \"%V\" "
+ "in certificate \"%V\", identical name appears in \"%V\"",
+ &str, old->bundle->name, item->bundle->name);
+
+ old->bundle = item->bundle;
+ }
+
+ return NXT_OK;
+ }
+
+ return NXT_ERROR;
+}
+
+
+static nxt_int_t
+nxt_openssl_servername(SSL *s, int *ad, void *arg)
+{
+ nxt_str_t str;
+ nxt_uint_t i;
+ nxt_conn_t *c;
+ const char *servername;
+ nxt_tls_conf_t *conf;
+ nxt_openssl_conn_t *tls;
+ nxt_tls_bundle_conf_t *bundle;
+
+ c = SSL_get_ex_data(s, nxt_openssl_connection_index);
+
+ if (nxt_slow_path(c == NULL)) {
+ nxt_thread_log_alert("SSL_get_ex_data() failed");
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+ if (nxt_slow_path(servername == NULL)) {
+ nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned "
+ "NULL in server name callback");
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ str.length = nxt_strlen(servername);
+ if (str.length == 0) {
+ nxt_debug(c->socket.task, "client sent zero-length server name");
+ goto done;
+ }
+
+ if (servername[0] == '.') {
+ nxt_debug(c->socket.task, "ignored the server name \"%s\": "
+ "leading \".\"", servername);
+ goto done;
+ }
+
+ nxt_debug(c->socket.task, "tls with servername \"%s\"", servername);
+
+ str.start = nxt_mp_nget(c->mem_pool, str.length);
+ if (nxt_slow_path(str.start == NULL)) {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ nxt_memcpy_lowcase(str.start, (const u_char *) servername, str.length);
+
+ tls = c->u.tls;
+ conf = tls->conf;
+
+ bundle = nxt_openssl_find_ctx(conf, &str);
+
+ if (bundle == NULL) {
+ for (i = 1; i < str.length; i++) {
+ if (str.start[i] == '.') {
+ str.start += i;
+ str.length -= i;
+
+ bundle = nxt_openssl_find_ctx(conf, &str);
+ break;
+ }
+ }
+ }
+
+ if (bundle != NULL) {
+ nxt_debug(c->socket.task, "new tls context found for \"%V\": \"%V\" "
+ "(old: \"%V\")", &str, bundle->name,
+ conf->bundle->name);
+
+ if (bundle != conf->bundle) {
+ if (SSL_set_SSL_CTX(s, bundle->ctx) == NULL) {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "SSL_set_SSL_CTX() failed");
+
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
+ }
+
+done:
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+
+static nxt_tls_bundle_conf_t *
+nxt_openssl_find_ctx(nxt_tls_conf_t *conf, nxt_str_t *sn)
+{
+ nxt_int_t ret;
+ nxt_lvlhsh_query_t lhq;
+ nxt_tls_bundle_hash_item_t *item;
+
+ lhq.key_hash = nxt_murmur_hash2(sn->start, sn->length);
+ lhq.key = *sn;
+ lhq.proto = &nxt_openssl_bundle_hash_proto;
+
+ ret = nxt_lvlhsh_find(&conf->bundle_hash, &lhq);
+ if (ret != NXT_OK) {
+ return NULL;
+ }
+
+ item = lhq.value;
+
+ return item->bundle;
+}
+
+
static void
nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf)
{
- SSL_CTX_free(conf->ctx);
+ nxt_tls_bundle_conf_t *bundle;
+
+ bundle = conf->bundle;
+ nxt_assert(bundle != NULL);
+
+ do {
+ SSL_CTX_free(bundle->ctx);
+ bundle = bundle->next;
+ } while (bundle != NULL);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
+ && OPENSSL_VERSION_NUMBER < 0x1010101fL)
+ RAND_keep_random_devices_open(0);
+#endif
}
@@ -463,7 +807,7 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c)
c->u.tls = tls;
nxt_buf_mem_set_size(&tls->buffer, conf->buffer_size);
- ctx = conf->ctx;
+ ctx = conf->bundle->ctx;
s = SSL_new(ctx);
if (s == NULL) {
@@ -472,6 +816,8 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c)
}
tls->session = s;
+ /* To pass TLS config to the nxt_openssl_servername() callback. */
+ tls->conf = conf;
tls->conn = c;
ret = SSL_set_fd(s, c->socket.fd);
@@ -493,6 +839,11 @@ nxt_openssl_conn_init(nxt_task_t *task, nxt_tls_conf_t *conf, nxt_conn_t *c)
c->sendfile = NXT_CONN_SENDFILE_OFF;
nxt_openssl_conn_handshake(task, c, c->socket.data);
+ /*
+ * TLS configuration might be destroyed after the TLS connection
+ * is established.
+ */
+ tls->conf = NULL;
return;
fail:
@@ -720,10 +1071,6 @@ nxt_openssl_conn_io_shutdown(nxt_task_t *task, void *obj, void *data)
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;
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index 369e7f32..8fbe7f65 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -1041,7 +1041,11 @@ nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
if (r->authorization_field != NXT_UNIT_NONE_FIELD) {
f = r->fields + r->authorization_field;
+#ifdef NXT_PHP7
php_handle_auth_data(nxt_unit_sptr_get(&f->value));
+#else
+ php_handle_auth_data(nxt_unit_sptr_get(&f->value) TSRMLS_CC);
+#endif
} else {
SG(request_info).auth_digest = NULL;
diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c
index ae9f079c..bffae8a1 100644
--- a/src/nxt_port_memory.c
+++ b/src/nxt_port_memory.c
@@ -34,6 +34,10 @@ nxt_port_mmap_handler_use(nxt_port_mmap_handler_t *mmap_handler, int i)
mmap_handler->hdr = NULL;
}
+ if (mmap_handler->fd != -1) {
+ nxt_fd_close(mmap_handler->fd);
+ }
+
nxt_free(mmap_handler);
}
}
@@ -238,6 +242,7 @@ nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process,
}
mmap_handler->hdr = hdr;
+ mmap_handler->fd = -1;
if (nxt_slow_path(hdr->src_pid != process->pid
|| hdr->dst_pid != nxt_pid))
diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c
index 9d8096b2..3cf2e79a 100644
--- a/src/nxt_port_socket.c
+++ b/src/nxt_port_socket.c
@@ -6,8 +6,16 @@
#include <nxt_main.h>
#include <nxt_port_queue.h>
+#include <nxt_port_memory_int.h>
+#define NXT_PORT_MAX_ENQUEUE_BUF_SIZE \
+ (int) (NXT_PORT_QUEUE_MSG_SIZE - sizeof(nxt_port_msg_t))
+
+
+static nxt_bool_t nxt_port_can_enqueue_buf(nxt_buf_t *b);
+static uint8_t nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm,
+ void *qbuf, nxt_buf_t *b);
static nxt_int_t nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port,
nxt_port_send_msg_t *msg);
static nxt_port_send_msg_t *nxt_port_msg_alloc(nxt_port_send_msg_t *m);
@@ -151,10 +159,13 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type,
nxt_buf_t *b)
{
int notify;
- uint8_t *p;
+ uint8_t qmsg_size;
nxt_int_t res;
nxt_port_send_msg_t msg;
- uint8_t qmsg[NXT_PORT_QUEUE_MSG_SIZE];
+ struct {
+ nxt_port_msg_t pm;
+ uint8_t buf[NXT_PORT_MAX_ENQUEUE_BUF_SIZE];
+ } qmsg;
msg.link.next = NULL;
msg.link.prev = NULL;
@@ -177,21 +188,31 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type,
if (port->queue != NULL && type != _NXT_PORT_MSG_READ_QUEUE) {
- if (fd == -1
- && (b == NULL
- || nxt_buf_mem_used_size(&b->mem)
- <= (int) (NXT_PORT_QUEUE_MSG_SIZE - sizeof(nxt_port_msg_t))))
- {
- p = nxt_cpymem(qmsg, &msg.port_msg, sizeof(nxt_port_msg_t));
+ if (fd == -1 && nxt_port_can_enqueue_buf(b)) {
+ qmsg.pm = msg.port_msg;
+
+ qmsg_size = sizeof(qmsg.pm);
+
if (b != NULL) {
- p = nxt_cpymem(p, b->mem.pos, nxt_buf_mem_used_size(&b->mem));
+ qmsg_size += nxt_port_enqueue_buf(task, &qmsg.pm, qmsg.buf, b);
}
- res = nxt_port_queue_send(port->queue, qmsg, p - qmsg, &notify);
+ res = nxt_port_queue_send(port->queue, &qmsg, qmsg_size, &notify);
nxt_debug(task, "port{%d,%d} %d: enqueue %d notify %d, %d",
(int) port->pid, (int) port->id, port->socket.fd,
- (int) (p - qmsg), notify, res);
+ (int) qmsg_size, notify, res);
+
+ if (b != NULL && nxt_fast_path(res == NXT_OK)) {
+ if (qmsg.pm.mmap) {
+ b->is_port_mmap_sent = 1;
+ }
+
+ b->mem.pos = b->mem.free;
+
+ nxt_work_queue_add(&task->thread->engine->fast_work_queue,
+ b->completion_handler, task, b, b->parent);
+ }
if (notify == 0) {
return res;
@@ -201,9 +222,9 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type,
msg.buf = NULL;
} else {
- qmsg[0] = _NXT_PORT_MSG_READ_SOCKET;
+ qmsg.buf[0] = _NXT_PORT_MSG_READ_SOCKET;
- res = nxt_port_queue_send(port->queue, qmsg, 1, &notify);
+ res = nxt_port_queue_send(port->queue, qmsg.buf, 1, &notify);
nxt_debug(task, "port{%d,%d} %d: enqueue 1 notify %d, %d",
(int) port->pid, (int) port->id, port->socket.fd,
@@ -225,6 +246,56 @@ nxt_port_socket_write2(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type,
}
+static nxt_bool_t
+nxt_port_can_enqueue_buf(nxt_buf_t *b)
+{
+ if (b == NULL) {
+ return 1;
+ }
+
+ if (b->next != NULL) {
+ return 0;
+ }
+
+ return (nxt_buf_mem_used_size(&b->mem) <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE
+ || nxt_buf_is_port_mmap(b));
+}
+
+
+static uint8_t
+nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, void *qbuf,
+ nxt_buf_t *b)
+{
+ ssize_t size;
+ nxt_port_mmap_msg_t *mm;
+ nxt_port_mmap_header_t *hdr;
+ nxt_port_mmap_handler_t *mmap_handler;
+
+ size = nxt_buf_mem_used_size(&b->mem);
+
+ if (size <= NXT_PORT_MAX_ENQUEUE_BUF_SIZE) {
+ nxt_memcpy(qbuf, b->mem.pos, size);
+
+ return size;
+ }
+
+ mmap_handler = b->parent;
+ hdr = mmap_handler->hdr;
+ mm = qbuf;
+
+ mm->mmap_id = hdr->id;
+ mm->chunk_id = nxt_port_mmap_chunk_id(hdr, b->mem.pos);
+ mm->size = nxt_buf_mem_used_size(&b->mem);
+
+ pm->mmap = 1;
+
+ nxt_debug(task, "mmap_msg={%D, %D, %D}", mm->mmap_id, mm->chunk_id,
+ mm->size);
+
+ return sizeof(nxt_port_mmap_msg_t);
+}
+
+
static nxt_int_t
nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port,
nxt_port_send_msg_t *msg)
diff --git a/src/nxt_router.c b/src/nxt_router.c
index 03fe2a6c..8524b358 100644
--- a/src/nxt_router.c
+++ b/src/nxt_router.c
@@ -51,8 +51,10 @@ typedef struct {
typedef struct {
+ nxt_str_t *name;
nxt_socket_conf_t *socket_conf;
nxt_router_temp_conf_t *temp_conf;
+ nxt_bool_t last;
} nxt_socket_rpc_t;
@@ -116,9 +118,11 @@ static void nxt_router_listen_socket_error(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
#if (NXT_TLS)
static void nxt_router_tls_rpc_create(nxt_task_t *task,
- nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls);
+ nxt_router_temp_conf_t *tmcf, nxt_router_tlssock_t *tls, nxt_bool_t last);
static void nxt_router_tls_rpc_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
+static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
+ nxt_conf_value_t *value, nxt_socket_conf_t *skcf);
#endif
static void nxt_router_app_rpc_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
@@ -519,12 +523,11 @@ nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
next = b->next;
b->next = NULL;
- b->completion_handler = msg_info->completion_handler;
-
if (b->is_port_mmap_sent) {
b->is_port_mmap_sent = cancelled == 0;
- b->completion_handler(task, b, b->parent);
}
+
+ b->completion_handler(task, b, b->parent);
}
msg_info->buf = NULL;
@@ -944,14 +947,15 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
}
#if (NXT_TLS)
- qlk = nxt_queue_first(&tmcf->tls);
+ qlk = nxt_queue_last(&tmcf->tls);
- if (qlk != nxt_queue_tail(&tmcf->tls)) {
+ if (qlk != nxt_queue_head(&tmcf->tls)) {
nxt_queue_remove(qlk);
tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
- nxt_router_tls_rpc_create(task, tmcf, tls);
+ nxt_router_tls_rpc_create(task, tmcf, tls,
+ nxt_queue_is_empty(&tmcf->tls));
return;
}
#endif
@@ -990,7 +994,7 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
nxt_router_apps_sort(task, router, tmcf);
- nxt_router_apps_hash_use(task, rtcf, 1);
+ nxt_router_apps_hash_use(task, rtcf, 1);
nxt_router_engines_post(router, tmcf);
@@ -1332,6 +1336,9 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_port_t *port;
nxt_router_t *router;
nxt_app_joint_t *app_joint;
+#if (NXT_TLS)
+ nxt_conf_value_t *certificate;
+#endif
nxt_conf_value_t *conf, *http, *value, *websocket;
nxt_conf_value_t *applications, *application;
nxt_conf_value_t *listeners, *listener;
@@ -1343,9 +1350,6 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_router_app_conf_t apcf;
nxt_router_access_log_t *access_log;
nxt_router_listener_conf_t lscf;
-#if (NXT_TLS)
- nxt_router_tlssock_t *tls;
-#endif
static nxt_str_t http_path = nxt_string("/settings/http");
static nxt_str_t applications_path = nxt_string("/applications");
@@ -1729,20 +1733,30 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
}
#if (NXT_TLS)
- value = nxt_conf_get_path(listener, &certificate_path);
+ certificate = nxt_conf_get_path(listener, &certificate_path);
- if (value != NULL) {
- nxt_conf_get_string(value, &name);
+ if (certificate != NULL) {
+ if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) {
+ n = nxt_conf_array_elements_count(certificate);
- tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
- if (nxt_slow_path(tls == NULL)) {
- goto fail;
- }
+ for (i = 0; i < n; i++) {
+ value = nxt_conf_get_array_element(certificate, i);
+
+ nxt_assert(value != NULL);
- tls->name = name;
- tls->conf = skcf;
+ ret = nxt_router_conf_tls_insert(tmcf, value, skcf);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto fail;
+ }
+ }
- nxt_queue_insert_tail(&tmcf->tls, &tls->link);
+ } else {
+ /* NXT_CONF_STRING */
+ ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto fail;
+ }
+ }
}
#endif
@@ -1828,6 +1842,38 @@ fail:
}
+#if (NXT_TLS)
+
+static nxt_int_t
+nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
+ nxt_conf_value_t *value, nxt_socket_conf_t *skcf)
+{
+ nxt_mp_t *mp;
+ nxt_str_t str;
+ nxt_router_tlssock_t *tls;
+
+ mp = tmcf->router_conf->mem_pool;
+
+ tls = nxt_mp_get(mp, sizeof(nxt_router_tlssock_t));
+ if (nxt_slow_path(tls == NULL)) {
+ return NXT_ERROR;
+ }
+
+ tls->conf = skcf;
+ nxt_conf_get_string(value, &str);
+
+ if (nxt_slow_path(nxt_str_dup(mp, &tls->name, &str) == NULL)) {
+ return NXT_ERROR;
+ }
+
+ nxt_queue_insert_tail(&tmcf->tls, &tls->link);
+
+ return NXT_OK;
+}
+
+#endif
+
+
static nxt_int_t
nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
nxt_conf_value_t *conf)
@@ -2383,7 +2429,7 @@ nxt_router_listen_socket_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
static void
nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
- nxt_router_tlssock_t *tls)
+ nxt_router_tlssock_t *tls, nxt_bool_t last)
{
nxt_socket_rpc_t *rpc;
@@ -2393,8 +2439,10 @@ nxt_router_tls_rpc_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
return;
}
+ rpc->name = &tls->name;
rpc->socket_conf = tls->conf;
rpc->temp_conf = tmcf;
+ rpc->last = last;
nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
nxt_router_tls_rpc_handler, rpc);
@@ -2405,11 +2453,12 @@ static void
nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
- nxt_mp_t *mp;
- nxt_int_t ret;
- nxt_tls_conf_t *tlscf;
- nxt_socket_rpc_t *rpc;
- nxt_router_temp_conf_t *tmcf;
+ nxt_mp_t *mp;
+ nxt_int_t ret;
+ nxt_tls_conf_t *tlscf;
+ nxt_socket_rpc_t *rpc;
+ nxt_tls_bundle_conf_t *bundle;
+ nxt_router_temp_conf_t *tmcf;
nxt_debug(task, "tls rpc handler");
@@ -2422,20 +2471,33 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
mp = tmcf->router_conf->mem_pool;
- tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
- if (nxt_slow_path(tlscf == NULL)) {
+ if (rpc->socket_conf->tls == NULL){
+ tlscf = nxt_mp_zget(mp, sizeof(nxt_tls_conf_t));
+ if (nxt_slow_path(tlscf == NULL)) {
+ goto fail;
+ }
+
+ rpc->socket_conf->tls = tlscf;
+
+ } else {
+ tlscf = rpc->socket_conf->tls;
+ }
+
+ bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t));
+ if (nxt_slow_path(bundle == NULL)) {
goto fail;
}
- tlscf->chain_file = msg->fd[0];
+ bundle->name = rpc->name;
+ bundle->chain_file = msg->fd[0];
+ bundle->next = tlscf->bundle;
+ tlscf->bundle = bundle;
- ret = task->thread->runtime->tls->server_init(task, tlscf);
+ ret = task->thread->runtime->tls->server_init(task, tlscf, mp, rpc->last);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
}
- rpc->socket_conf->tls = tlscf;
-
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
nxt_router_conf_apply, task, tmcf, NULL);
return;
@@ -3726,7 +3788,7 @@ nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data)
nxt_event_engine_t *engine;
nxt_thread_handle_t handle;
- handle = (nxt_thread_handle_t) obj;
+ handle = (nxt_thread_handle_t) (uintptr_t) obj;
link = data;
nxt_thread_wait(handle);
@@ -4050,6 +4112,8 @@ nxt_router_req_headers_ack_handler(nxt_task_t *task,
if (b != NULL) {
/* First buffer is already sent. Start from second. */
b = b->next;
+
+ req_rpc_data->msg_info.buf->next = NULL;
}
if (req_rpc_data->msg_info.body_fd != -1 || b != NULL) {
@@ -4962,14 +5026,6 @@ nxt_router_app_prepare_request(nxt_task_t *task,
port->socket.fd);
req_rpc_data->msg_info.buf = buf;
- req_rpc_data->msg_info.completion_handler = buf->completion_handler;
-
- do {
- buf->completion_handler = nxt_router_dummy_buf_completion;
- buf = buf->next;
- } while (buf != NULL);
-
- buf = req_rpc_data->msg_info.buf;
body = req_rpc_data->request->body;
diff --git a/src/nxt_router_request.h b/src/nxt_router_request.h
index 95044dbb..6e226bae 100644
--- a/src/nxt_router_request.h
+++ b/src/nxt_router_request.h
@@ -11,7 +11,6 @@ typedef struct {
nxt_buf_t *buf;
nxt_fd_t body_fd;
uint32_t tracking_cookie;
- nxt_work_handler_t completion_handler;
} nxt_msg_info_t;
diff --git a/src/nxt_thread.h b/src/nxt_thread.h
index 2ebc331d..d7800cc6 100644
--- a/src/nxt_thread.h
+++ b/src/nxt_thread.h
@@ -142,6 +142,14 @@ nxt_thread_yield() \
#endif
+#if (PTHREAD_STACK_MIN)
+#define NXT_THREAD_STACK_MIN PTHREAD_STACK_MIN
+
+#else
+#define NXT_THREAD_STACK_MIN sysconf(_SC_THREAD_STACK_MIN)
+#endif
+
+
struct nxt_thread_s {
nxt_log_t *log;
nxt_log_t main_log;
diff --git a/src/nxt_tls.h b/src/nxt_tls.h
index d9fcc6a8..c44bfe56 100644
--- a/src/nxt_tls.h
+++ b/src/nxt_tls.h
@@ -23,28 +23,47 @@
#define NXT_TLS_BUFFER_SIZE 4096
-typedef struct nxt_tls_conf_s nxt_tls_conf_t;
-
+typedef struct nxt_tls_conf_s nxt_tls_conf_t;
+typedef struct nxt_tls_bundle_conf_s nxt_tls_bundle_conf_t;
typedef struct {
nxt_int_t (*library_init)(nxt_task_t *task);
void (*library_free)(nxt_task_t *task);
nxt_int_t (*server_init)(nxt_task_t *task,
- nxt_tls_conf_t *conf);
+ nxt_tls_conf_t *conf, nxt_mp_t *mp,
+ nxt_bool_t last);
void (*server_free)(nxt_task_t *task,
nxt_tls_conf_t *conf);
} nxt_tls_lib_t;
-struct nxt_tls_conf_s {
+typedef struct {
+ nxt_tls_bundle_conf_t *bundle;
+
+ nxt_str_t name;
+} nxt_tls_bundle_hash_item_t;
+
+
+struct nxt_tls_bundle_conf_s {
void *ctx;
+
+ nxt_fd_t chain_file;
+ nxt_str_t *name;
+
+ nxt_tls_bundle_conf_t *next;
+};
+
+
+struct nxt_tls_conf_s {
+ nxt_tls_bundle_conf_t *bundle;
+ nxt_lvlhsh_t bundle_hash;
+
void (*conn_init)(nxt_task_t *task,
nxt_tls_conf_t *conf, nxt_conn_t *c);
const nxt_tls_lib_t *lib;
- nxt_fd_t chain_file;
char *ciphers;
char *ca_certificate;
diff --git a/src/nxt_unit.c b/src/nxt_unit.c
index 2fef17c5..ae4499d8 100644
--- a/src/nxt_unit.c
+++ b/src/nxt_unit.c
@@ -3785,7 +3785,7 @@ nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size)
char name[64];
snprintf(name, sizeof(name), NXT_SHM_PREFIX "unit.%d.%p",
- lib->pid, (void *) pthread_self());
+ lib->pid, (void *) (uintptr_t) pthread_self());
#endif
#if (NXT_HAVE_MEMFD_CREATE)
diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c
index 0aad887d..ca14af5b 100644
--- a/src/ruby/nxt_ruby.c
+++ b/src/ruby/nxt_ruby.c
@@ -12,6 +12,8 @@
#include NXT_RUBY_MOUNTS_H
+#include <locale.h>
+
#define NXT_RUBY_RACK_API_VERSION_MAJOR 1
#define NXT_RUBY_RACK_API_VERSION_MINOR 3
@@ -200,6 +202,8 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data)
nxt_ruby_threads = c->threads;
+ setlocale(LC_CTYPE, "");
+
RUBY_INIT_STACK
ruby_init();
ruby_options(2, argv);
diff --git a/test/conftest.py b/test/conftest.py
index b36aabad..20ac6e81 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -1,9 +1,12 @@
import fcntl
+import inspect
+import json
import os
import platform
import re
import shutil
import signal
+import socket
import stat
import subprocess
import sys
@@ -16,6 +19,8 @@ from unit.check.go import check_go
from unit.check.isolation import check_isolation
from unit.check.node import check_node
from unit.check.tls import check_openssl
+from unit.check.regex import check_regex
+from unit.http import TestHTTP
from unit.option import option
from unit.utils import public_dir
from unit.utils import waitforfiles
@@ -51,10 +56,18 @@ def pytest_addoption(parser):
type=str,
help="Default user for non-privileged processes of unitd",
)
+ parser.addoption(
+ "--restart",
+ default=False,
+ action="store_true",
+ help="Force Unit to restart after every test",
+ )
unit_instance = {}
+unit_log_copy = "unit.log.copy"
_processes = []
+http = TestHTTP()
def pytest_configure(config):
option.config = config.option
@@ -64,6 +77,7 @@ def pytest_configure(config):
option.save_log = config.option.save_log
option.unsafe = config.option.unsafe
option.user = config.option.user
+ option.restart = config.option.restart
option.generated_tests = {}
option.current_dir = os.path.abspath(
@@ -163,6 +177,7 @@ def pytest_sessionstart(session):
option.current_dir, unit['temp_dir'], option.test_dir
)
option.available['modules']['node'] = check_node(option.current_dir)
+ option.available['modules']['regex'] = check_regex(unit['unitd'])
# remove None values
@@ -172,12 +187,17 @@ def pytest_sessionstart(session):
check_isolation()
+ _clear_conf(unit['temp_dir'] + '/control.unit.sock')
+
unit_stop()
_check_alerts()
- shutil.rmtree(unit_instance['temp_dir'])
+ if option.restart:
+ shutil.rmtree(unit_instance['temp_dir'])
+ elif option.save_log:
+ open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'w').close()
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
@@ -241,38 +261,70 @@ def run(request):
# stop unit
- error = unit_stop()
+ error_stop_unit = unit_stop()
+ error_stop_processes = stop_processes()
- if error:
- _print_log()
+ # prepare log
- assert error is None, 'stop unit'
+ with open(
+ unit_instance['log'], 'r', encoding='utf-8', errors='ignore'
+ ) as f:
+ log = f.read()
- # stop all processes
+ if not option.restart and option.save_log:
+ with open(unit_instance['temp_dir'] + '/' + unit_log_copy, 'a') as f:
+ f.write(log)
- error = stop_processes()
+ # remove unit.log
- if error:
- _print_log()
+ if not option.save_log and option.restart:
+ shutil.rmtree(unit['temp_dir'])
- assert error is None, 'stop unit'
+ # clean temp_dir before the next test
- # check unit.log for alerts
+ if not option.restart:
+ _clear_conf(unit['temp_dir'] + '/control.unit.sock', log)
- _check_alerts()
+ open(unit['log'], 'w').close()
+
+ for item in os.listdir(unit['temp_dir']):
+ if item not in [
+ 'control.unit.sock',
+ 'state',
+ 'unit.pid',
+ 'unit.log',
+ unit_log_copy,
+ ]:
+ path = os.path.join(unit['temp_dir'], item)
+
+ public_dir(path)
+
+ if os.path.isfile(path) or stat.S_ISSOCK(os.stat(path).st_mode):
+ os.remove(path)
+ else:
+ shutil.rmtree(path)
# print unit.log in case of error
if hasattr(request.node, 'rep_call') and request.node.rep_call.failed:
- _print_log()
+ _print_log(log)
- # remove unit.log
+ if error_stop_unit or error_stop_processes:
+ _print_log(log)
- if not option.save_log:
- shutil.rmtree(unit['temp_dir'])
+ # check unit.log for errors
+
+ assert error_stop_unit is None, 'stop unit'
+ assert error_stop_processes is None, 'stop processes'
+
+ _check_alerts(log=log)
def unit_run():
global unit_instance
+
+ if not option.restart and 'unitd' in unit_instance:
+ return unit_instance
+
build_dir = option.current_dir + '/build'
unitd = build_dir + '/unitd'
@@ -323,6 +375,12 @@ def unit_run():
def unit_stop():
+ if not option.restart:
+ if inspect.stack()[1].function.startswith('test_'):
+ pytest.skip('no restart mode')
+
+ return
+
p = unit_instance['process']
if p.poll() is not None:
@@ -345,12 +403,13 @@ def unit_stop():
-def _check_alerts(path=None):
+def _check_alerts(path=None, log=None):
if path is None:
path = unit_instance['log']
- with open(path, 'r', encoding='utf-8', errors='ignore') as f:
- log = f.read()
+ if log is None:
+ with open(path, 'r', encoding='utf-8', errors='ignore') as f:
+ log = f.read()
found = False
@@ -396,6 +455,43 @@ def _print_log(data=None):
sys.stdout.write(data)
+def _clear_conf(sock, log=None):
+ def check_success(resp):
+ if 'success' not in resp:
+ _print_log(log)
+ assert 'success' in resp
+
+ resp = http.put(
+ url='/config',
+ sock_type='unix',
+ addr=sock,
+ body=json.dumps({"listeners": {}, "applications": {}}),
+ )['body']
+
+ check_success(resp)
+
+ if 'openssl' not in option.available['modules']:
+ return
+
+ try:
+ certs = json.loads(http.get(
+ url='/certificates',
+ sock_type='unix',
+ addr=sock,
+ )['body']).keys()
+
+ except json.JSONDecodeError:
+ pytest.fail('Can\'t parse certificates list.')
+
+ for cert in certs:
+ resp = http.delete(
+ url='/certificates/' + cert,
+ sock_type='unix',
+ addr=sock,
+ )['body']
+
+ check_success(resp)
+
def run_process(target, *args):
global _processes
@@ -446,5 +542,10 @@ def unit_pid(request):
return unit_instance['process'].pid
def pytest_sessionfinish(session):
+ if not option.restart and option.save_log:
+ print('Path to unit.log:\n' + unit_instance['log'] + '\n')
+
+ option.restart = True
+
unit_stop()
shutil.rmtree(option.cache_dir)
diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py
index 5770265d..886a160b 100644
--- a/test/test_asgi_application.py
+++ b/test/test_asgi_application.py
@@ -377,7 +377,7 @@ Connection: close
self.get(no_recv=True)
assert (
- self.wait_for_record(r'\(5\) Thread: 100') is not None
+ self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None
), 'last thread finished'
def test_asgi_application_threads(self):
diff --git a/test/test_asgi_websockets.py b/test/test_asgi_websockets.py
index 6121fcc5..7218d526 100644
--- a/test/test_asgi_websockets.py
+++ b/test/test_asgi_websockets.py
@@ -30,8 +30,9 @@ class TestASGIWebsockets(TestApplicationPython):
self.check_close(sock)
- def check_close(self, sock, code=1000, no_close=False):
- frame = self.ws.frame_read(sock)
+ def check_close(self, sock, code=1000, no_close=False, frame=None):
+ if frame == None:
+ frame = self.ws.frame_read(sock)
assert frame['fin'] == True, 'close fin'
assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
@@ -930,7 +931,14 @@ class TestASGIWebsockets(TestApplicationPython):
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True)
- self.check_close(sock, 1002)
+
+ frame = self.ws.frame_read(sock)
+
+ if frame['opcode'] == self.ws.OP_TEXT:
+ self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
+ frame = None
+
+ self.check_close(sock, 1002, frame=frame)
# 5_16
diff --git a/test/test_java_websockets.py b/test/test_java_websockets.py
index 315c496d..df9e0885 100644
--- a/test/test_java_websockets.py
+++ b/test/test_java_websockets.py
@@ -27,8 +27,9 @@ class TestJavaWebsockets(TestApplicationJava):
self.check_close(sock)
- def check_close(self, sock, code=1000, no_close=False):
- frame = self.ws.frame_read(sock)
+ def check_close(self, sock, code=1000, no_close=False, frame=None):
+ if frame == None:
+ frame = self.ws.frame_read(sock)
assert frame['fin'] == True, 'close fin'
assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
@@ -862,7 +863,14 @@ class TestJavaWebsockets(TestApplicationJava):
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True)
- self.check_close(sock, 1002)
+
+ frame = self.ws.frame_read(sock)
+
+ if frame['opcode'] == self.ws.OP_TEXT:
+ self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
+ frame = None
+
+ self.check_close(sock, 1002, frame=frame)
# 5_16
diff --git a/test/test_node_websockets.py b/test/test_node_websockets.py
index 4f1e5906..d5f79811 100644
--- a/test/test_node_websockets.py
+++ b/test/test_node_websockets.py
@@ -27,8 +27,9 @@ class TestNodeWebsockets(TestApplicationNode):
self.check_close(sock)
- def check_close(self, sock, code=1000, no_close=False):
- frame = self.ws.frame_read(sock)
+ def check_close(self, sock, code=1000, no_close=False, frame=None):
+ if frame == None:
+ frame = self.ws.frame_read(sock)
assert frame['fin'] == True, 'close fin'
assert frame['opcode'] == self.ws.OP_CLOSE, 'close opcode'
@@ -881,7 +882,14 @@ class TestNodeWebsockets(TestApplicationNode):
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment2', fin=True)
self.ws.frame_write(sock, self.ws.OP_CONT, 'fragment3', fin=False)
self.ws.frame_write(sock, self.ws.OP_TEXT, 'fragment4', fin=True)
- self.check_close(sock, 1002)
+
+ frame = self.ws.frame_read(sock)
+
+ if frame['opcode'] == self.ws.OP_TEXT:
+ self.check_frame(frame, True, self.ws.OP_TEXT, 'fragment1fragment2')
+ frame = None
+
+ self.check_close(sock, 1002, frame=frame)
# 5_16
diff --git a/test/test_proxy.py b/test/test_proxy.py
index 2d305e98..7e7c7246 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -482,6 +482,7 @@ Content-Length: 10
check_proxy('http://[:]:7080')
check_proxy('http://[::7080')
+ @pytest.mark.skip('not yet')
def test_proxy_loop(self, skip_alert):
skip_alert(
r'socket.*failed',
diff --git a/test/test_python_application.py b/test/test_python_application.py
index 709df3ff..41f6f538 100644
--- a/test/test_python_application.py
+++ b/test/test_python_application.py
@@ -569,7 +569,7 @@ last line: 987654321
self.get(no_recv=True)
assert (
- self.wait_for_record(r'\(5\) Thread: 100') is not None
+ self.wait_for_record(r'\(5\) Thread: 100', wait=50) is not None
), 'last thread finished'
def test_python_application_iter_exception(self):
diff --git a/test/test_routing.py b/test/test_routing.py
index 4d27cb61..be9a1faf 100644
--- a/test/test_routing.py
+++ b/test/test_routing.py
@@ -229,6 +229,9 @@ class TestRouting(TestApplicationProto):
assert self.get(url='/ABc')['status'] == 404
def test_routes_empty_regex(self):
+ if not option.available['modules']['regex']:
+ pytest.skip('requires regex')
+
self.route_match({"uri":"~"})
assert self.get(url='/')['status'] == 200, 'empty regexp'
assert self.get(url='/anything')['status'] == 200, '/anything'
@@ -238,6 +241,9 @@ class TestRouting(TestApplicationProto):
assert self.get(url='/nothing')['status'] == 404, '/nothing'
def test_routes_bad_regex(self):
+ if not option.available['modules']['regex']:
+ pytest.skip('requires regex')
+
assert 'error' in self.route(
{"match": {"uri": "~/bl[ah"}, "action": {"return": 200}}
), 'bad regex'
@@ -255,6 +261,9 @@ class TestRouting(TestApplicationProto):
assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z'
def test_routes_match_regex_case_sensitive(self):
+ if not option.available['modules']['regex']:
+ pytest.skip('requires regex')
+
self.route_match({"uri": "~/bl[ah]"})
assert self.get(url='/rlah')['status'] == 404, '/rlah'
@@ -263,6 +272,9 @@ class TestRouting(TestApplicationProto):
assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
def test_routes_match_regex_negative_case_sensitive(self):
+ if not option.available['modules']['regex']:
+ pytest.skip('requires regex')
+
self.route_match({"uri": "!~/bl[ah]"})
assert self.get(url='/rlah')['status'] == 200, '/rlah'
diff --git a/test/test_share_fallback.py b/test/test_share_fallback.py
index a02cb1a3..46464670 100644
--- a/test/test_share_fallback.py
+++ b/test/test_share_fallback.py
@@ -1,5 +1,6 @@
import os
+import pytest
from unit.applications.proto import TestApplicationProto
from unit.option import option
@@ -27,7 +28,10 @@ class TestStatic(TestApplicationProto):
)
def teardown_method(self):
- os.chmod(option.temp_dir + '/assets/403', 0o777)
+ try:
+ os.chmod(option.temp_dir + '/assets/403', 0o777)
+ except FileNotFoundError:
+ pass
def action_update(self, conf):
assert 'success' in self.conf(conf, 'routes/0/action')
@@ -116,6 +120,7 @@ class TestStatic(TestApplicationProto):
assert resp['status'] == 200, 'fallback proxy status'
assert resp['body'] == '', 'fallback proxy'
+ @pytest.mark.skip('not yet')
def test_fallback_proxy_loop(self, skip_alert):
skip_alert(
r'open.*/blah/index.html.*failed',
diff --git a/test/test_tls.py b/test/test_tls.py
index 89c57d07..206ea828 100644
--- a/test/test_tls.py
+++ b/test/test_tls.py
@@ -199,7 +199,7 @@ class TestTLS(TestApplicationTLS):
self.sec_epoch()
- self.openssl_date_to_sec_epoch(cert['validity']['since'])
)
- < 5
+ < 60
), 'certificate validity since'
assert (
self.openssl_date_to_sec_epoch(cert['validity']['until'])
diff --git a/test/unit/applications/lang/java.py b/test/unit/applications/lang/java.py
index b2e17f23..c9c2095e 100644
--- a/test/unit/applications/lang/java.py
+++ b/test/unit/applications/lang/java.py
@@ -52,7 +52,7 @@ class TestApplicationJava(TestApplicationProto):
os.makedirs(classes_path)
classpath = (
- option.current_dir + '/build/tomcat-servlet-api-9.0.39.jar'
+ option.current_dir + '/build/tomcat-servlet-api-9.0.44.jar'
)
ws_jars = glob.glob(
diff --git a/test/unit/applications/proto.py b/test/unit/applications/proto.py
index af05d071..5c400621 100644
--- a/test/unit/applications/proto.py
+++ b/test/unit/applications/proto.py
@@ -19,8 +19,8 @@ class TestApplicationProto(TestControl):
with open(option.temp_dir + '/' + name, 'r', errors='ignore') as f:
return re.search(pattern, f.read())
- def wait_for_record(self, pattern, name='unit.log'):
- for i in range(50):
+ def wait_for_record(self, pattern, name='unit.log', wait=150):
+ for i in range(wait):
found = self.search_in_log(pattern, name)
if found is not None:
diff --git a/test/unit/check/regex.py b/test/unit/check/regex.py
new file mode 100644
index 00000000..734c0150
--- /dev/null
+++ b/test/unit/check/regex.py
@@ -0,0 +1,13 @@
+import re
+import subprocess
+
+
+def check_regex(unitd):
+ output = subprocess.check_output(
+ [unitd, '--version'], stderr=subprocess.STDOUT
+ )
+
+ if re.search('--no-regex', output.decode()):
+ return False
+
+ return True
diff --git a/test/unit/utils.py b/test/unit/utils.py
index 7a0a3fe5..e80fc469 100644
--- a/test/unit/utils.py
+++ b/test/unit/utils.py
@@ -47,7 +47,7 @@ def waitforsocket(port):
except KeyboardInterrupt:
raise
- pytest.fail('Can\'t connect to the 127.0.0.1:' + port)
+ pytest.fail('Can\'t connect to the 127.0.0.1:' + str(port))
def findmnt():
diff --git a/version b/version
index 55e5da42..6d66d5f1 100644
--- a/version
+++ b/version
@@ -1,5 +1,5 @@
# Copyright (C) NGINX, Inc.
-NXT_VERSION=1.22.0
-NXT_VERNUM=12200
+NXT_VERSION=1.23.0
+NXT_VERNUM=12300