summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CHANGES21
-rw-r--r--auto/endian31
-rw-r--r--auto/isolation29
-rw-r--r--auto/sources2
-rwxr-xr-xconfigure2
-rw-r--r--docs/changes.xml75
-rw-r--r--pkg/contrib/src/njs/Makefile2
-rw-r--r--pkg/contrib/src/njs/SHA512SUMS2
-rw-r--r--pkg/contrib/src/njs/version2
-rw-r--r--pkg/docker/Dockerfile.go1.192
-rw-r--r--pkg/docker/Dockerfile.jsc112
-rw-r--r--pkg/docker/Dockerfile.minimal2
-rw-r--r--pkg/docker/Dockerfile.node182
-rw-r--r--pkg/docker/Dockerfile.perl5.362
-rw-r--r--pkg/docker/Dockerfile.php8.12
-rw-r--r--pkg/docker/Dockerfile.python3.112
-rw-r--r--pkg/docker/Dockerfile.ruby3.12
-rw-r--r--pkg/rpm/Makefile4
-rw-r--r--src/nxt_clone.c14
-rw-r--r--src/nxt_clone.h3
-rw-r--r--src/nxt_conf_validation.c18
-rw-r--r--src/nxt_credential.c6
-rw-r--r--src/nxt_http_request.c4
-rw-r--r--src/nxt_isolation.c10
-rw-r--r--src/nxt_js.c17
-rw-r--r--src/nxt_js.h2
-rw-r--r--src/nxt_main_process.c2
-rw-r--r--src/nxt_php_sapi.c3
-rw-r--r--src/nxt_process.c272
-rw-r--r--src/nxt_process.h16
-rw-r--r--src/nxt_router.c6
-rw-r--r--src/nxt_tstr.c18
-rw-r--r--src/nxt_tstr.h2
-rw-r--r--src/nxt_websocket_header.h4
-rw-r--r--src/python/nxt_python.c36
-rw-r--r--src/python/nxt_python_asgi.c76
-rw-r--r--test/python/encoding/wsgi.py12
-rw-r--r--test/python/unicode/wsgi.py8
-rw-r--r--test/test_php_targets.py1
-rw-r--r--test/test_python_application.py78
-rw-r--r--version4
41 files changed, 679 insertions, 119 deletions
diff --git a/CHANGES b/CHANGES
index 959fdd32..51fc753f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,25 @@
+Changes with Unit 1.29.1 28 Feb 2023
+
+ *) Bugfix: stop creating world-writeable directories.
+
+ *) Bugfix: memory leak related to NJS.
+
+ *) Bugfix: path parsing in PHP applications.
+
+ *) Bugfix: enabled UTF-8 for Python config by default to avoid
+ applications failing in some cases.
+
+ *) Bugfix: using asyncio.get_running_loop() instead of
+ asyncio.get_event_loop() when it's available to prevent errors in
+ some Python ASGI applications.
+
+ *) Bugfix: applications that make use of various low level APIs such as
+ pthreads could fail to work correctly.
+
+ *) Bugfix: websocket endianness detection for obscure operating systems.
+
+
Changes with Unit 1.29.0 15 Dec 2022
*) Change: removed $uri auto-append for "share" when loading
diff --git a/auto/endian b/auto/endian
new file mode 100644
index 00000000..cb23639b
--- /dev/null
+++ b/auto/endian
@@ -0,0 +1,31 @@
+# Copyright (C) Igor Sysoev
+# Copyright (C) Andrew Clayton
+# Copyright (C) Nginx, Inc.
+
+
+nxt_feature="endianness"
+nxt_feature_name=
+nxt_feature_run=value
+nxt_feature_incs=
+nxt_feature_libs=
+nxt_feature_test="#include <stdint.h>
+ #include <stdio.h>
+
+ int main(void) {
+ int i = 0x11223344;
+ uint8_t *p;
+
+ p = (uint8_t *)&i;
+ if (*p == 0x44)
+ printf(\"little endian\");
+ else
+ printf(\"big endian\");
+ return 0;
+ }"
+. auto/feature
+
+if [ "$nxt_feature_value" = "little endian" ]; then
+ nxt_have=NXT_HAVE_LITTLE_ENDIAN . auto/have
+else
+ nxt_have=NXT_HAVE_BIG_ENDIAN . auto/have
+fi
diff --git a/auto/isolation b/auto/isolation
index cbf42d9d..c535e80a 100644
--- a/auto/isolation
+++ b/auto/isolation
@@ -4,7 +4,7 @@
# Linux clone syscall.
NXT_ISOLATION=NO
-NXT_HAVE_CLONE=NO
+NXT_HAVE_LINUX_NS=NO
NXT_HAVE_CLONE_NEWUSER=NO
NXT_HAVE_MOUNT=NO
NXT_HAVE_UNMOUNT=NO
@@ -12,21 +12,21 @@ NXT_HAVE_ROOTFS=NO
nsflags="USER NS PID NET UTS CGROUP"
-nxt_feature="clone(2)"
-nxt_feature_name=NXT_HAVE_CLONE
+nxt_feature="Linux unshare()"
+nxt_feature_name=NXT_HAVE_LINUX_NS
nxt_feature_run=no
nxt_feature_incs=
nxt_feature_libs=
-nxt_feature_test="#include <sys/wait.h>
- #include <sys/syscall.h>
+nxt_feature_test="#define _GNU_SOURCE
+ #include <sched.h>
int main(void) {
- return SYS_clone | SIGCHLD;
+ return unshare(0);
}"
. auto/feature
if [ $nxt_found = yes ]; then
- NXT_HAVE_CLONE=YES
+ NXT_HAVE_LINUX_NS=YES
# Test all isolation flags
for flag in $nsflags; do
@@ -90,7 +90,7 @@ nxt_feature_test="#include <mntent.h>
nxt_feature="prctl(PR_SET_NO_NEW_PRIVS)"
-nxt_feature_name=NXT_HAVE_PR_SET_NO_NEW_PRIVS0
+nxt_feature_name=NXT_HAVE_PR_SET_NO_NEW_PRIVS
nxt_feature_run=no
nxt_feature_incs=
nxt_feature_libs=
@@ -102,6 +102,19 @@ nxt_feature_test="#include <sys/prctl.h>
. auto/feature
+nxt_feature="prctl(PR_SET_CHILD_SUBREAPER)"
+nxt_feature_name=NXT_HAVE_PR_SET_CHILD_SUBREAPER
+nxt_feature_run=no
+nxt_feature_incs=
+nxt_feature_libs=
+nxt_feature_test="#include <sys/prctl.h>
+
+ int main(void) {
+ return PR_SET_CHILD_SUBREAPER;
+ }"
+. auto/feature
+
+
nxt_feature="Linux mount()"
nxt_feature_name=NXT_HAVE_LINUX_MOUNT
nxt_feature_run=no
diff --git a/auto/sources b/auto/sources
index 29f3c7b5..2ca78844 100644
--- a/auto/sources
+++ b/auto/sources
@@ -299,7 +299,7 @@ if [ "$NXT_HAVE_HPUX_SENDFILE" = "YES" \
fi
-if [ "$NXT_HAVE_CLONE" = "YES" ]; then
+if [ "$NXT_HAVE_LINUX_NS" = "YES" ]; then
NXT_LIB_SRCS="$NXT_LIB_SRCS $NXT_LIB_CLONE_SRCS"
fi
diff --git a/configure b/configure
index 1d897f1d..8482b514 100755
--- a/configure
+++ b/configure
@@ -109,6 +109,7 @@ fi
NXT_LIBRT=
+. auto/endian
. auto/types
. auto/clang
. auto/atomic
@@ -136,7 +137,6 @@ fi
case "$NXT_SYSTEM_PLATFORM" in
i386 | amd64 | x86_64)
- nxt_have=NXT_HAVE_LITTLE_ENDIAN . auto/have
nxt_have=NXT_HAVE_NONALIGNED . auto/have
;;
esac
diff --git a/docs/changes.xml b/docs/changes.xml
index 8262ef56..91ad1966 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -15,6 +15,81 @@
unit-jsc-common unit-jsc8 unit-jsc10 unit-jsc11 unit-jsc13
unit-jsc14 unit-jsc15 unit-jsc16 unit-jsc17 unit-jsc18
unit-jsc19"
+ ver="1.29.1" rev="1"
+ date="2023-02-28" time="18:00:00 +0300"
+ packager="Nginx Packaging &lt;nginx-packaging@f5.com&gt;">
+
+<change>
+<para>
+NGINX Unit updated to 1.29.1.
+</para>
+</change>
+
+</changes>
+
+
+<changes apply="unit" ver="1.29.1" rev="1"
+ date="2023-02-28" time="18:00:00 +0300"
+ packager="Nginx Packaging &lt;nginx-packaging@f5.com&gt;">
+
+<change type="bugfix">
+<para>
+stop creating world-writeable directories.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+memory leak related to NJS.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+path parsing in PHP applications.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+enabled UTF-8 for Python config by default to avoid applications failing
+in some cases.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+using asyncio.get_running_loop() instead of asyncio.get_event_loop()
+when it's available to prevent errors in some Python ASGI applications.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+applications that make use of various low level APIs such as pthreads could
+fail to work correctly.
+</para>
+</change>
+
+<change type="bugfix">
+<para>
+websocket endianness detection for obscure operating systems.
+</para>
+</change>
+
+</changes>
+
+
+<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-python3.10 unit-python3.11
+ unit-go
+ unit-perl
+ unit-ruby
+ unit-jsc-common unit-jsc8 unit-jsc10 unit-jsc11 unit-jsc13
+ unit-jsc14 unit-jsc15 unit-jsc16 unit-jsc17 unit-jsc18
+ unit-jsc19"
ver="1.29.0" rev="1"
date="2022-12-15" time="18:00:00 +0300"
packager="Nginx Packaging &lt;nginx-packaging@f5.com&gt;">
diff --git a/pkg/contrib/src/njs/Makefile b/pkg/contrib/src/njs/Makefile
index 54255aef..4e752df5 100644
--- a/pkg/contrib/src/njs/Makefile
+++ b/pkg/contrib/src/njs/Makefile
@@ -15,5 +15,5 @@ njs: njs-$(NJS_VERSION).tar.gz .sum-njs
$(MOVE)
.njs: njs
- cd $< && ./configure && $(MAKE) libnjs
+ cd $< && ./configure --no-libxml2 && $(MAKE) libnjs
touch $@
diff --git a/pkg/contrib/src/njs/SHA512SUMS b/pkg/contrib/src/njs/SHA512SUMS
index 1bddec9b..0bba673b 100644
--- a/pkg/contrib/src/njs/SHA512SUMS
+++ b/pkg/contrib/src/njs/SHA512SUMS
@@ -1 +1 @@
-dc73029e7b570a7fbc94e90deb1e17c9a3d85072dc0e060f11dd96bd173e11b7c823c57115369d3c68af7acd97fabe619b70dfd73280694f8b5dc8b7929d850b njs-0.7.9.tar.gz
+5063fcfac18298d86157d05dc618f47815763a2192538befa5f046d081a7d5c6b624b65258674a6d9719147c102a703d5c3a80d937f4e9d43985da8e85dbc539 njs-0.7.10.tar.gz
diff --git a/pkg/contrib/src/njs/version b/pkg/contrib/src/njs/version
index 511715d0..6088389d 100644
--- a/pkg/contrib/src/njs/version
+++ b/pkg/contrib/src/njs/version
@@ -1 +1 @@
-NJS_VERSION := 0.7.9
+NJS_VERSION := 0.7.10
diff --git a/pkg/docker/Dockerfile.go1.19 b/pkg/docker/Dockerfile.go1.19
index ec2b40da..a6ff837c 100644
--- a/pkg/docker/Dockerfile.go1.19
+++ b/pkg/docker/Dockerfile.go1.19
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.jsc11 b/pkg/docker/Dockerfile.jsc11
index b8391997..501bfcda 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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.minimal b/pkg/docker/Dockerfile.minimal
index ca3dec01..6101953e 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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.node18 b/pkg/docker/Dockerfile.node18
index bdf968b2..27543df1 100644
--- a/pkg/docker/Dockerfile.node18
+++ b/pkg/docker/Dockerfile.node18
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.perl5.36 b/pkg/docker/Dockerfile.perl5.36
index 9c398c30..8f2b8a61 100644
--- a/pkg/docker/Dockerfile.perl5.36
+++ b/pkg/docker/Dockerfile.perl5.36
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.php8.1 b/pkg/docker/Dockerfile.php8.1
index 76c7c428..eefc4aa8 100644
--- a/pkg/docker/Dockerfile.php8.1
+++ b/pkg/docker/Dockerfile.php8.1
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.python3.11 b/pkg/docker/Dockerfile.python3.11
index 3a83ec57..744eda20 100644
--- a/pkg/docker/Dockerfile.python3.11
+++ b/pkg/docker/Dockerfile.python3.11
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/docker/Dockerfile.ruby3.1 b/pkg/docker/Dockerfile.ruby3.1
index 1eb6ce5c..132b2b34 100644
--- a/pkg/docker/Dockerfile.ruby3.1
+++ b/pkg/docker/Dockerfile.ruby3.1
@@ -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.29.0 \
+ && hg up 1.29.1 \
&& 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)" \
diff --git a/pkg/rpm/Makefile b/pkg/rpm/Makefile
index d00a25ac..5c104ca3 100644
--- a/pkg/rpm/Makefile
+++ b/pkg/rpm/Makefile
@@ -184,7 +184,7 @@ rpmbuild/SOURCES/unit-$(VERSION).tar.gz:
unit: check-build-depends-unit rpmbuild/SPECS/unit.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz
@echo "===> Building $@ package" ; \
- rpmbuild -D "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/unit.spec && \
+ rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/unit.spec && \
ln -s rpmbuild/BUILD/$@-$(VERSION)/build $@
rpmlint:
@@ -235,7 +235,7 @@ rpmbuild/SPECS/unit-%.spec: unit.module.spec.in ../../docs/changes.xml | rpmbuil
unit-%: check-build-depends-% rpmbuild/SPECS/unit-%.spec rpmbuild/SOURCES/unit-$(VERSION).tar.gz
@echo "===> Building $(subst _,-,$@) package" ; \
- rpmbuild -D "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/$@.spec && \
+ rpmbuild -D "_topdir `pwd`/rpmbuild" -ba --noclean rpmbuild/SPECS/$@.spec && \
ln -s rpmbuild/BUILD/$(subst _,-,$@)-$(VERSION)/build $@
test: unit modules
diff --git a/src/nxt_clone.c b/src/nxt_clone.c
index a9b39ac1..1cd70f6c 100644
--- a/src/nxt_clone.c
+++ b/src/nxt_clone.c
@@ -8,20 +8,6 @@
#include <nxt_conf.h>
#include <nxt_clone.h>
-#if (NXT_HAVE_CLONE)
-
-pid_t
-nxt_clone(nxt_int_t flags)
-{
-#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__)
- return syscall(SYS_clone, NULL, flags);
-#else
- return syscall(SYS_clone, flags, NULL);
-#endif
-}
-
-#endif
-
#if (NXT_HAVE_CLONE_NEWUSER)
diff --git a/src/nxt_clone.h b/src/nxt_clone.h
index c2066ce6..6cea1bd7 100644
--- a/src/nxt_clone.h
+++ b/src/nxt_clone.h
@@ -33,9 +33,6 @@ typedef struct {
} nxt_clone_t;
-pid_t nxt_clone(nxt_int_t flags);
-
-
#define nxt_is_clone_flag_set(flags, test) \
((flags & CLONE_##test) == CLONE_##test)
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index bf8aa760..537a3fb7 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -1284,25 +1284,35 @@ nxt_conf_validate(nxt_conf_validation_t *vldt)
vldt->tstr_state = nxt_tstr_state_new(vldt->pool, 1);
if (nxt_slow_path(vldt->tstr_state == NULL)) {
- return NXT_ERROR;
+ ret = NXT_ERROR;
+ goto fail;
}
ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) {
- return ret;
+ goto fail;
}
ret = nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
if (ret != NXT_OK) {
- return ret;
+ goto fail;
}
ret = nxt_tstr_state_done(vldt->tstr_state, error);
if (ret != NXT_OK) {
- return nxt_conf_vldt_error(vldt, "%s", error);
+ ret = nxt_conf_vldt_error(vldt, "%s", error);
+ goto fail;
}
+ nxt_tstr_state_release(vldt->tstr_state);
+
return NXT_OK;
+
+fail:
+
+ nxt_tstr_state_release(vldt->tstr_state);
+
+ return ret;
}
diff --git a/src/nxt_credential.c b/src/nxt_credential.c
index 168db9cf..bda97024 100644
--- a/src/nxt_credential.c
+++ b/src/nxt_credential.c
@@ -286,7 +286,7 @@ nxt_credential_setuid(nxt_task_t *task, nxt_credential_t *uc)
if (setuid(uc->uid) != 0) {
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
if (nxt_errno == EINVAL) {
nxt_log(task, NXT_LOG_ERR, "The uid %d (user \"%s\") isn't "
"valid in the application namespace.", uc->uid, uc->user);
@@ -314,7 +314,7 @@ nxt_credential_setgids(nxt_task_t *task, nxt_credential_t *uc)
if (setgid(uc->base_gid) != 0) {
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
if (nxt_errno == EINVAL) {
nxt_log(task, NXT_LOG_ERR, "The gid %d isn't valid in the "
"application namespace.", uc->base_gid);
@@ -333,7 +333,7 @@ nxt_credential_setgids(nxt_task_t *task, nxt_credential_t *uc)
if (nxt_slow_path(uc->ngroups > 0
&& setgroups(uc->ngroups, uc->gids) != 0)) {
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
if (nxt_errno == EINVAL) {
nxt_log(task, NXT_LOG_ERR, "The user \"%s\" (uid: %d) has "
"supplementary group ids not valid in the application "
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index 73ffd2f0..e78975aa 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -833,6 +833,10 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
r->body->file->fd = -1;
}
+ if (r->tstr_query != NULL) {
+ nxt_tstr_query_release(r->tstr_query);
+ }
+
if (nxt_fast_path(proto.any != NULL)) {
protocol = r->protocol;
diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c
index b6b13c59..614d6bb5 100644
--- a/src/nxt_isolation.c
+++ b/src/nxt_isolation.c
@@ -21,7 +21,7 @@ static nxt_int_t nxt_isolation_set_cgroup(nxt_task_t *task,
nxt_conf_value_t *isolation, nxt_process_t *process);
#endif
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
static nxt_int_t nxt_isolation_set_namespaces(nxt_task_t *task,
nxt_conf_value_t *isolation, nxt_process_t *process);
static nxt_int_t nxt_isolation_clone_flags(nxt_task_t *task,
@@ -169,7 +169,7 @@ nxt_isolation_set(nxt_task_t *task, nxt_conf_value_t *isolation,
}
#endif
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
if (nxt_slow_path(nxt_isolation_set_namespaces(task, isolation, process)
!= NXT_OK))
{
@@ -247,7 +247,7 @@ nxt_isolation_set_cgroup(nxt_task_t *task, nxt_conf_value_t *isolation,
#endif
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
static nxt_int_t
nxt_isolation_set_namespaces(nxt_task_t *task, nxt_conf_value_t *isolation,
@@ -409,7 +409,7 @@ nxt_isolation_vldt_creds(nxt_task_t *task, nxt_process_t *process)
#endif
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
static nxt_int_t
nxt_isolation_clone_flags(nxt_task_t *task, nxt_conf_value_t *namespaces,
@@ -652,7 +652,7 @@ nxt_isolation_set_lang_mounts(nxt_task_t *task, nxt_process_t *process,
mnt->flags = (NXT_FS_FLAGS_NOSUID
| NXT_FS_FLAGS_NODEV
| NXT_FS_FLAGS_NOEXEC);
- mnt->data = (u_char *) "size=1m,mode=777";
+ mnt->data = (u_char *) "size=1m,mode=1777";
mnt->builtin = 1;
mnt->deps = 0;
diff --git a/src/nxt_js.c b/src/nxt_js.c
index aa3c4af5..4327e848 100644
--- a/src/nxt_js.c
+++ b/src/nxt_js.c
@@ -46,6 +46,7 @@ nxt_js_conf_new(nxt_mp_t *mp)
jcf->funcs = nxt_array_create(mp, 4, sizeof(nxt_str_t));
if (nxt_slow_path(jcf->funcs == NULL)) {
+ njs_vm_destroy(jcf->vm);
return NULL;
}
@@ -54,6 +55,13 @@ nxt_js_conf_new(nxt_mp_t *mp)
void
+nxt_js_conf_release(nxt_js_conf_t *jcf)
+{
+ njs_vm_destroy(jcf->vm);
+}
+
+
+void
nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, njs_uint_t n)
{
jcf->protos = n;
@@ -297,3 +305,12 @@ nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js,
return NXT_OK;
}
+
+
+void
+nxt_js_release(nxt_js_cache_t *cache)
+{
+ if (cache->vm != NULL) {
+ njs_vm_destroy(cache->vm);
+ }
+}
diff --git a/src/nxt_js.h b/src/nxt_js.h
index dea43fe3..74d041ca 100644
--- a/src/nxt_js.h
+++ b/src/nxt_js.h
@@ -22,12 +22,14 @@ typedef struct {
nxt_js_conf_t *nxt_js_conf_new(nxt_mp_t *mp);
+void nxt_js_conf_release(nxt_js_conf_t *jcf);
void nxt_js_set_proto(nxt_js_conf_t *jcf, njs_external_t *proto, nxt_uint_t n);
nxt_js_t *nxt_js_add_tpl(nxt_js_conf_t *jcf, nxt_str_t *str, nxt_bool_t strz);
nxt_int_t nxt_js_compile(nxt_js_conf_t *jcf);
nxt_int_t nxt_js_test(nxt_js_conf_t *jcf, nxt_str_t *str, u_char *error);
nxt_int_t nxt_js_call(nxt_task_t *task, nxt_js_cache_t *cache, nxt_js_t *js,
nxt_str_t *str, void *ctx);
+void nxt_js_release(nxt_js_cache_t *cache);
extern njs_int_t nxt_js_proto_id;
diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c
index de41e8d7..4c89121e 100644
--- a/src/nxt_main_process.c
+++ b/src/nxt_main_process.c
@@ -556,7 +556,7 @@ nxt_main_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
nxt_assert(process != NULL);
nxt_assert(process->state == NXT_PROCESS_STATE_CREATING);
-#if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
+#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER)
if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
if (nxt_slow_path(nxt_clone_credential_map(task, process->pid,
process->user_cred,
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index 126a4684..d2494938 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -1025,7 +1025,8 @@ nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
nxt_str_null(&script_name);
- ctx->path_info.start = (u_char *) strstr((char *) path.start, ".php/");
+ ctx->path_info.start = memmem(path.start, path.length, ".php/",
+ strlen(".php/"));
if (ctx->path_info.start != NULL) {
ctx->path_info.start += 4;
path.length = ctx->path_info.start - path.start;
diff --git a/src/nxt_process.c b/src/nxt_process.c
index d8836ad2..025efe70 100644
--- a/src/nxt_process.c
+++ b/src/nxt_process.c
@@ -7,7 +7,7 @@
#include <nxt_main.h>
#include <nxt_cgroup.h>
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
#include <nxt_clone.h>
#endif
@@ -18,7 +18,7 @@
#endif
-#if (NXT_HAVE_CLONE) && (NXT_HAVE_CLONE_NEWPID)
+#if (NXT_HAVE_LINUX_NS) && (NXT_HAVE_CLONE_NEWPID)
#define nxt_is_pid_isolated(process) \
nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)
#else
@@ -27,6 +27,19 @@
#endif
+#if (NXT_HAVE_LINUX_NS)
+static nxt_int_t nxt_process_pipe_timer(nxt_fd_t fd, short event);
+static nxt_int_t nxt_process_check_pid_status(const nxt_fd_t *gc_pipe);
+static nxt_pid_t nxt_process_recv_pid(const nxt_fd_t *pid_pipe,
+ const nxt_fd_t *gc_pipe);
+static void nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid);
+static nxt_int_t nxt_process_unshare(nxt_task_t *task, nxt_process_t *process,
+ nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe, nxt_bool_t use_pidns);
+static nxt_int_t nxt_process_init_pidns(nxt_task_t *task,
+ const nxt_process_t *process, nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
+ nxt_bool_t *use_pidns);
+#endif
+
static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process);
static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process);
static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process);
@@ -256,7 +269,7 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
nxt_ppid = nxt_pid;
- nxt_pid = nxt_getpid();
+ nxt_pid = getpid();
process->pid = nxt_pid;
process->isolated_pid = nxt_pid;
@@ -311,6 +324,217 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
}
+#if (NXT_HAVE_LINUX_NS)
+
+static nxt_int_t
+nxt_process_pipe_timer(nxt_fd_t fd, short event)
+{
+ int ret;
+ sigset_t mask;
+ struct pollfd pfd;
+
+ static const struct timespec ts = { .tv_sec = 5 };
+
+ /*
+ * Temporarily block the signals we are handling, (except
+ * for SIGINT & SIGTERM) so that ppoll(2) doesn't get
+ * interrupted. After ppoll(2) returns, our old sigmask
+ * will be back in effect and any pending signals will be
+ * delivered.
+ *
+ * This is because while the kernel ppoll syscall updates
+ * the struct timespec with the time remaining if it got
+ * interrupted with EINTR, the glibc wrapper hides this
+ * from us so we have no way of knowing how long to retry
+ * the ppoll(2) for and if we just retry with the same
+ * timeout we could find ourselves in an infinite loop.
+ */
+ pthread_sigmask(SIG_SETMASK, NULL, &mask);
+ sigdelset(&mask, SIGINT);
+ sigdelset(&mask, SIGTERM);
+
+ pfd.fd = fd;
+ pfd.events = event;
+
+ ret = ppoll(&pfd, 1, &ts, &mask);
+ if (ret <= 0 || (ret == 1 && pfd.revents & POLLERR)) {
+ return NXT_ERROR;
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_process_check_pid_status(const nxt_fd_t *gc_pipe)
+{
+ int8_t status;
+ ssize_t ret;
+
+ close(gc_pipe[1]);
+
+ ret = nxt_process_pipe_timer(gc_pipe[0], POLLIN);
+ if (ret == NXT_OK) {
+ ret = read(gc_pipe[0], &status, sizeof(int8_t));
+ }
+
+ if (ret <= 0) {
+ status = -1;
+ }
+
+ close(gc_pipe[0]);
+
+ return status;
+}
+
+
+static nxt_pid_t
+nxt_process_recv_pid(const nxt_fd_t *pid_pipe, const nxt_fd_t *gc_pipe)
+{
+ int8_t status;
+ ssize_t ret;
+ nxt_pid_t pid;
+
+ close(pid_pipe[1]);
+ close(gc_pipe[0]);
+
+ status = 0;
+
+ ret = nxt_process_pipe_timer(pid_pipe[0], POLLIN);
+ if (ret == NXT_OK) {
+ ret = read(pid_pipe[0], &pid, sizeof(nxt_pid_t));
+ }
+
+ if (ret <= 0) {
+ status = -1;
+ pid = -1;
+ }
+
+ write(gc_pipe[1], &status, sizeof(int8_t));
+
+ close(pid_pipe[0]);
+ close(gc_pipe[1]);
+
+ return pid;
+}
+
+
+static void
+nxt_process_send_pid(const nxt_fd_t *pid_pipe, nxt_pid_t pid)
+{
+ nxt_int_t ret;
+
+ close(pid_pipe[0]);
+
+ ret = nxt_process_pipe_timer(pid_pipe[1], POLLOUT);
+ if (ret == NXT_OK) {
+ write(pid_pipe[1], &pid, sizeof(nxt_pid_t));
+ }
+
+ close(pid_pipe[1]);
+}
+
+
+static nxt_int_t
+nxt_process_unshare(nxt_task_t *task, nxt_process_t *process,
+ nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
+ nxt_bool_t use_pidns)
+{
+ int ret;
+ nxt_pid_t pid;
+
+ if (process->isolation.clone.flags == 0) {
+ return NXT_OK;
+ }
+
+ ret = unshare(process->isolation.clone.flags);
+ if (nxt_slow_path(ret == -1)) {
+ nxt_alert(task, "unshare() failed for %s %E", process->name,
+ nxt_errno);
+
+ if (use_pidns) {
+ nxt_pipe_close(task, gc_pipe);
+ nxt_pipe_close(task, pid_pipe);
+ }
+
+ return NXT_ERROR;
+ }
+
+ if (!use_pidns) {
+ return NXT_OK;
+ }
+
+ /*
+ * PID namespace requested. Employ a double fork(2) technique
+ * so that the prototype process will be placed into the new
+ * namespace and end up with PID 1 (as before with clone).
+ */
+ pid = fork();
+ if (nxt_slow_path(pid < 0)) {
+ nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
+ nxt_pipe_close(task, gc_pipe);
+ nxt_pipe_close(task, pid_pipe);
+
+ return NXT_ERROR;
+
+ } else if (pid > 0) {
+ nxt_pipe_close(task, gc_pipe);
+ nxt_process_send_pid(pid_pipe, pid);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ nxt_pipe_close(task, pid_pipe);
+ ret = nxt_process_check_pid_status(gc_pipe);
+ if (ret == -1) {
+ return NXT_ERROR;
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_process_init_pidns(nxt_task_t *task, const nxt_process_t *process,
+ nxt_fd_t *pid_pipe, nxt_fd_t *gc_pipe,
+ nxt_bool_t *use_pidns)
+{
+ int ret;
+
+ *use_pidns = 0;
+
+#if (NXT_HAVE_CLONE_NEWPID)
+ *use_pidns = nxt_is_pid_isolated(process);
+#endif
+
+ if (!*use_pidns) {
+ return NXT_OK;
+ }
+
+ ret = nxt_pipe_create(task, pid_pipe, 0, 0);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ ret = nxt_pipe_create(task, gc_pipe, 0, 0);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ return NXT_ERROR;
+ }
+
+#if (NXT_HAVE_PR_SET_CHILD_SUBREAPER)
+ ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+ if (nxt_slow_path(ret == -1)) {
+ nxt_alert(task, "prctl(PR_SET_CHILD_SUBREAPER) failed for %s %E",
+ process->name, nxt_errno);
+ }
+#endif
+
+ return NXT_OK;
+}
+
+#endif /* NXT_HAVE_LINUX_NS */
+
+
static nxt_pid_t
nxt_process_create(nxt_task_t *task, nxt_process_t *process)
{
@@ -318,23 +542,32 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process)
nxt_pid_t pid;
nxt_runtime_t *rt;
-#if (NXT_HAVE_CLONE)
- pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
- if (nxt_slow_path(pid < 0)) {
- nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno);
- return pid;
+#if (NXT_HAVE_LINUX_NS)
+ nxt_fd_t pid_pipe[2], gc_pipe[2];
+ nxt_bool_t use_pidns;
+
+ ret = nxt_process_init_pidns(task, process, pid_pipe, gc_pipe, &use_pidns);
+ if (ret == NXT_ERROR) {
+ return -1;
}
-#else
+#endif
+
pid = fork();
if (nxt_slow_path(pid < 0)) {
nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
return pid;
}
-#endif
if (pid == 0) {
/* Child. */
+#if (NXT_HAVE_LINUX_NS)
+ ret = nxt_process_unshare(task, process, pid_pipe, gc_pipe, use_pidns);
+ if (ret == NXT_ERROR) {
+ _exit(EXIT_FAILURE);
+ }
+#endif
+
ret = nxt_process_child_fixup(task, process);
if (nxt_slow_path(ret != NXT_OK)) {
nxt_process_quit(task, 1);
@@ -355,10 +588,15 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process)
/* Parent. */
-#if (NXT_HAVE_CLONE)
- nxt_debug(task, "clone(%s): %PI", process->name, pid);
-#else
nxt_debug(task, "fork(%s): %PI", process->name, pid);
+
+#if (NXT_HAVE_LINUX_NS)
+ if (use_pidns) {
+ pid = nxt_process_recv_pid(pid_pipe, gc_pipe);
+ if (pid == -1) {
+ return pid;
+ }
+ }
#endif
process->pid = pid;
@@ -781,7 +1019,7 @@ nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
cap_setid = rt->capabilities.setid;
-#if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
+#if (NXT_HAVE_LINUX_NS && NXT_HAVE_CLONE_NEWUSER)
if (!cap_setid
&& nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER))
{
@@ -918,10 +1156,10 @@ nxt_process_daemon(nxt_task_t *task)
}
/*
- * Reset file mode creation mask: any access
- * rights can be set on file creation.
+ * Set a sefe umask to give at most 755/644 permissions on
+ * directories/files.
*/
- umask(0);
+ umask(0022);
/* Redirect STDIN and STDOUT to the "/dev/null". */
diff --git a/src/nxt_process.h b/src/nxt_process.h
index 0db68d45..16d6110c 100644
--- a/src/nxt_process.h
+++ b/src/nxt_process.h
@@ -7,24 +7,12 @@
#ifndef _NXT_PROCESS_H_INCLUDED_
#define _NXT_PROCESS_H_INCLUDED_
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
#include <unistd.h>
#include <nxt_clone.h>
#endif
-#if (NXT_HAVE_CLONE)
-/*
- * Old glibc wrapper for getpid(2) returns a cached pid invalidated only by
- * fork(2) calls. As we use clone(2) for container, it returns the wrong pid.
- */
-#define nxt_getpid() \
- syscall(SYS_getpid)
-#else
-#define nxt_getpid() \
- getpid()
-#endif
-
typedef pid_t nxt_pid_t;
@@ -100,7 +88,7 @@ typedef struct {
nxt_cgroup_t cgroup;
#endif
-#if (NXT_HAVE_CLONE)
+#if (NXT_HAVE_LINUX_NS)
nxt_clone_t clone;
#endif
diff --git a/src/nxt_router.c b/src/nxt_router.c
index edc015c5..17f6c572 100644
--- a/src/nxt_router.c
+++ b/src/nxt_router.c
@@ -1111,6 +1111,10 @@ temp_fail:
fail:
+ if (rtcf->tstr_state != NULL) {
+ nxt_tstr_state_release(rtcf->tstr_state);
+ }
+
nxt_mp_destroy(mp);
return NULL;
@@ -3794,6 +3798,8 @@ nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint)
nxt_router_access_log_release(task, lock, rtcf->access_log);
+ nxt_tstr_state_release(rtcf->tstr_state);
+
nxt_mp_thread_adopt(rtcf->mem_pool);
nxt_mp_destroy(rtcf->mem_pool);
diff --git a/src/nxt_tstr.c b/src/nxt_tstr.c
index fd01797c..fda585b8 100644
--- a/src/nxt_tstr.c
+++ b/src/nxt_tstr.c
@@ -194,6 +194,15 @@ nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error)
}
+void
+nxt_tstr_state_release(nxt_tstr_state_t *state)
+{
+#if (NXT_HAVE_NJS)
+ nxt_js_conf_release(state->jcf);
+#endif
+}
+
+
nxt_bool_t
nxt_tstr_is_const(nxt_tstr_t *tstr)
{
@@ -315,3 +324,12 @@ nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query,
task, query->ctx, query->data);
}
}
+
+
+void
+nxt_tstr_query_release(nxt_tstr_query_t *query)
+{
+#if (NXT_HAVE_NJS)
+ nxt_js_release(&query->cache->js);
+#endif
+}
diff --git a/src/nxt_tstr.h b/src/nxt_tstr.h
index 0cc24292..ce8e6f3a 100644
--- a/src/nxt_tstr.h
+++ b/src/nxt_tstr.h
@@ -42,6 +42,7 @@ nxt_tstr_t *nxt_tstr_compile(nxt_tstr_state_t *state, nxt_str_t *str,
nxt_tstr_flags_t flags);
nxt_int_t nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error);
nxt_int_t nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error);
+void nxt_tstr_state_release(nxt_tstr_state_t *state);
nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr);
void nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str);
@@ -55,6 +56,7 @@ void nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query,
void *data, nxt_work_handler_t ready, nxt_work_handler_t error);
void nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query,
nxt_bool_t failed);
+void nxt_tstr_query_release(nxt_tstr_query_t *query);
nxt_inline nxt_bool_t
diff --git a/src/nxt_websocket_header.h b/src/nxt_websocket_header.h
index f75dfacd..cb7431dd 100644
--- a/src/nxt_websocket_header.h
+++ b/src/nxt_websocket_header.h
@@ -10,7 +10,7 @@
typedef struct {
-#if (BYTE_ORDER == BIG_ENDIAN)
+#if (NXT_HAVE_BIG_ENDIAN)
uint8_t fin:1;
uint8_t rsv1:1;
uint8_t rsv2:1;
@@ -21,7 +21,7 @@ typedef struct {
uint8_t payload_len:7;
#endif
-#if (BYTE_ORDER == LITTLE_ENDIAN)
+#if (NXT_HAVE_LITTLE_ENDIAN)
uint8_t opcode:4;
uint8_t rsv3:1;
uint8_t rsv2:1;
diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c
index bdb04579..7c059649 100644
--- a/src/python/nxt_python.c
+++ b/src/python/nxt_python.c
@@ -75,8 +75,25 @@ static nxt_python_proto_t nxt_py_proto;
static nxt_int_t
nxt_python3_init_config(nxt_int_t pep405)
{
- PyStatus status;
- PyConfig config;
+ PyConfig config;
+ PyStatus status;
+ nxt_int_t ret;
+ PyPreConfig preconfig;
+
+ ret = NXT_ERROR;
+
+ PyPreConfig_InitIsolatedConfig(&preconfig);
+ /*
+ * Determine whether to use UTF-8 mode or not, UTF-8
+ * will be enabled if LC_CTYPE is C, POSIX or some
+ * specific UTF-8 locale.
+ */
+ preconfig.utf8_mode = -1;
+
+ status = Py_PreInitialize(&preconfig);
+ if (PyStatus_Exception(status)) {
+ return ret;
+ }
PyConfig_InitIsolatedConfig(&config);
@@ -84,29 +101,28 @@ nxt_python3_init_config(nxt_int_t pep405)
status = PyConfig_SetString(&config, &config.program_name,
nxt_py_home);
if (PyStatus_Exception(status)) {
- goto pyinit_exception;
+ goto out_config_clear;
}
} else {
- status =PyConfig_SetString(&config, &config.home, nxt_py_home);
+ status = PyConfig_SetString(&config, &config.home, nxt_py_home);
if (PyStatus_Exception(status)) {
- goto pyinit_exception;
+ goto out_config_clear;
}
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
- goto pyinit_exception;
+ goto out_config_clear;
}
- PyConfig_Clear(&config);
- return NXT_OK;
+ ret = NXT_OK;
-pyinit_exception:
+out_config_clear:
PyConfig_Clear(&config);
- return NXT_ERROR;
+ return ret;
}
#elif PY_MAJOR_VERSION == 3
diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c
index 587a17cf..adf03e2b 100644
--- a/src/python/nxt_python_asgi.c
+++ b/src/python/nxt_python_asgi.c
@@ -17,6 +17,8 @@
static PyObject *nxt_python_asgi_get_func(PyObject *obj);
+static PyObject *nxt_python_asgi_get_event_loop(PyObject *asyncio,
+ const char *event_loop_func);
static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main);
static void nxt_python_asgi_ctx_data_free(void *data);
static int nxt_python_asgi_startup(void *data);
@@ -201,14 +203,53 @@ nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
}
+static PyObject *
+nxt_python_asgi_get_event_loop(PyObject *asyncio, const char *event_loop_func)
+{
+ PyObject *event_loop, *loop;
+
+ event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
+ event_loop_func);
+ if (nxt_slow_path(event_loop == NULL)) {
+ nxt_unit_alert(NULL, "Python failed to get '%s' from module 'asyncio'",
+ event_loop_func);
+ return NULL;
+ }
+
+ if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) {
+ nxt_unit_alert(NULL, "'asyncio.%s' is not a callable object",
+ event_loop_func);
+ return NULL;
+ }
+
+ loop = PyObject_CallObject(event_loop, NULL);
+ if (nxt_slow_path(loop == NULL)) {
+ if (strcmp(event_loop_func, "get_running_loop") != 0) {
+ nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'",
+ event_loop_func);
+ }
+
+ return NULL;
+ }
+
+ return loop;
+}
+
+
static int
nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
{
uint32_t i;
- PyObject *asyncio, *loop, *event_loop, *obj;
+ PyObject *asyncio, *loop, *obj;
const char *event_loop_func;
nxt_py_asgi_ctx_data_t *ctx_data;
+#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7)
+ static const char *main_event_loop_func = "get_event_loop";
+#else
+ static const char *main_event_loop_func = "get_running_loop";
+#endif
+
ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t));
if (nxt_slow_path(ctx_data == NULL)) {
nxt_unit_alert(NULL, "Failed to allocate context data");
@@ -241,29 +282,24 @@ nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
goto fail;
}
- event_loop_func = main ? "get_event_loop" : "new_event_loop";
+ event_loop_func = main ? main_event_loop_func : "new_event_loop";
- event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
- event_loop_func);
- if (nxt_slow_path(event_loop == NULL)) {
- nxt_unit_alert(NULL,
- "Python failed to get '%s' from module 'asyncio'",
- event_loop_func);
+ loop = nxt_python_asgi_get_event_loop(asyncio, event_loop_func);
+ if (loop == NULL) {
+#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7)
goto fail;
- }
+#else
+ if (!main) {
+ goto fail;
+ }
- if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) {
- nxt_unit_alert(NULL,
- "'asyncio.%s' is not a callable object",
- event_loop_func);
- goto fail;
- }
+ PyErr_Clear();
- loop = PyObject_CallObject(event_loop, NULL);
- if (nxt_slow_path(loop == NULL)) {
- nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'",
- event_loop_func);
- goto fail;
+ loop = nxt_python_asgi_get_event_loop(asyncio, "new_event_loop");
+ if (nxt_slow_path(loop == NULL)) {
+ goto fail;
+ }
+#endif
}
for (i = 0; i < nxt_nitems(handlers); i++) {
diff --git a/test/python/encoding/wsgi.py b/test/python/encoding/wsgi.py
new file mode 100644
index 00000000..0a916a9b
--- /dev/null
+++ b/test/python/encoding/wsgi.py
@@ -0,0 +1,12 @@
+import sys
+
+
+def application(environ, start_response):
+ start_response(
+ '200',
+ [
+ ('Content-Length', '0'),
+ ('X-Encoding', sys.getfilesystemencoding()),
+ ],
+ )
+ return []
diff --git a/test/python/unicode/wsgi.py b/test/python/unicode/wsgi.py
new file mode 100644
index 00000000..40043af9
--- /dev/null
+++ b/test/python/unicode/wsgi.py
@@ -0,0 +1,8 @@
+def application(environ, start_response):
+ temp_dir = environ.get('HTTP_TEMP_DIR')
+
+ with open(temp_dir + '/tempfile', 'w') as f:
+ f.write('\u26a0\ufe0f')
+
+ start_response('200', [('Content-Length', '0')])
+ return []
diff --git a/test/test_php_targets.py b/test/test_php_targets.py
index 918c5fda..eec1846f 100644
--- a/test/test_php_targets.py
+++ b/test/test_php_targets.py
@@ -47,6 +47,7 @@ class TestPHPTargets(TestApplicationPHP):
assert self.get(url='/2')['body'] == '2'
assert self.get(url='/blah')['status'] == 503 # TODO 404
assert self.get(url='/')['body'] == 'index'
+ assert self.get(url='/1.php?test=test.php/')['body'] == '1'
assert 'success' in self.conf(
"\"1.php\"", 'applications/targets/targets/default/index'
diff --git a/test/test_python_application.py b/test/test_python_application.py
index c9483b6a..c9065eae 100644
--- a/test/test_python_application.py
+++ b/test/test_python_application.py
@@ -2,9 +2,12 @@ import grp
import os
import pwd
import re
+import subprocess
import time
+import venv
import pytest
+from packaging import version
from unit.applications.lang.python import TestApplicationPython
@@ -526,6 +529,81 @@ last line: 987654321
assert self.get()['body'] == '0123456789', 'write'
+ def test_python_application_encoding(self):
+ self.load('encoding')
+
+ try:
+ locales = (
+ subprocess.check_output(
+ ['locale', '-a'],
+ stderr=subprocess.STDOUT,
+ )
+ .decode()
+ .splitlines()
+ )
+ except (
+ FileNotFoundError,
+ UnicodeDecodeError,
+ subprocess.CalledProcessError,
+ ):
+ pytest.skip('require locale')
+
+ to_check = [
+ re.compile(r'.*UTF[-_]?8'),
+ re.compile(r'.*ISO[-_]?8859[-_]?1'),
+ ]
+ matches = [
+ loc
+ for loc in locales
+ if any(pattern.match(loc.upper()) for pattern in to_check)
+ ]
+
+ if not matches:
+ pytest.skip('no available locales')
+
+ def unify(str):
+ str.upper().replace('-', '').replace('_', '')
+
+ for loc in matches:
+ assert 'success' in self.conf(
+ {"LC_CTYPE": loc, "LC_ALL": ""},
+ '/config/applications/encoding/environment',
+ )
+ resp = self.get()
+ assert resp['status'] == 200, 'status'
+ assert unify(resp['headers']['X-Encoding']) == unify(
+ loc.split('.')[-1]
+ )
+
+ def test_python_application_unicode(self, temp_dir):
+ try:
+ app_type = self.get_application_type()
+ v = version.Version(app_type.split()[-1])
+ if v.major != 3:
+ raise version.InvalidVersion
+
+ except version.InvalidVersion:
+ pytest.skip('require python module version 3')
+
+ venv_path = temp_dir + '/venv'
+ venv.create(venv_path)
+
+ self.load('unicode')
+ assert 'success' in self.conf(
+ '"' + venv_path + '"',
+ '/config/applications/unicode/home',
+ )
+ assert (
+ self.get(
+ headers={
+ 'Host': 'localhost',
+ 'Temp-dir': temp_dir,
+ 'Connection': 'close',
+ }
+ )['status']
+ == 200
+ )
+
def test_python_application_threading(self):
"""wait_for_record() timeouts after 5s while every thread works at
least 3s. So without releasing GIL test should fail.
diff --git a/version b/version
index d231f5c2..d6e99924 100644
--- a/version
+++ b/version
@@ -1,5 +1,5 @@
# Copyright (C) NGINX, Inc.
-NXT_VERSION=1.29.0
-NXT_VERNUM=12900
+NXT_VERSION=1.29.1
+NXT_VERNUM=12901