summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-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
18 files changed, 415 insertions, 94 deletions
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++) {