diff options
Diffstat (limited to '')
41 files changed, 679 insertions, 119 deletions
@@ -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 @@ -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 <nginx-packaging@f5.com>"> + +<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 <nginx-packaging@f5.com>"> + +<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 <nginx-packaging@f5.com>"> 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. @@ -1,5 +1,5 @@ # Copyright (C) NGINX, Inc. -NXT_VERSION=1.29.0 -NXT_VERNUM=12900 +NXT_VERSION=1.29.1 +NXT_VERNUM=12901 |