diff options
Diffstat (limited to '')
-rw-r--r-- | src/nxt_clone.c | 14 | ||||
-rw-r--r-- | src/nxt_clone.h | 3 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 18 | ||||
-rw-r--r-- | src/nxt_credential.c | 6 | ||||
-rw-r--r-- | src/nxt_http_request.c | 4 | ||||
-rw-r--r-- | src/nxt_isolation.c | 10 | ||||
-rw-r--r-- | src/nxt_js.c | 17 | ||||
-rw-r--r-- | src/nxt_js.h | 2 | ||||
-rw-r--r-- | src/nxt_main_process.c | 2 | ||||
-rw-r--r-- | src/nxt_php_sapi.c | 3 | ||||
-rw-r--r-- | src/nxt_process.c | 272 | ||||
-rw-r--r-- | src/nxt_process.h | 16 | ||||
-rw-r--r-- | src/nxt_router.c | 6 | ||||
-rw-r--r-- | src/nxt_tstr.c | 18 | ||||
-rw-r--r-- | src/nxt_tstr.h | 2 | ||||
-rw-r--r-- | src/nxt_websocket_header.h | 4 | ||||
-rw-r--r-- | src/python/nxt_python.c | 36 | ||||
-rw-r--r-- | src/python/nxt_python_asgi.c | 76 |
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++) { |