diff options
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/nxt_python.c | 103 | ||||
-rw-r--r-- | src/python/nxt_python_asgi.c | 41 | ||||
-rw-r--r-- | src/python/nxt_python_wsgi.c | 65 |
3 files changed, 157 insertions, 52 deletions
diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c index faf0c0e1..d8204937 100644 --- a/src/python/nxt_python.c +++ b/src/python/nxt_python.c @@ -24,6 +24,7 @@ typedef struct { static nxt_int_t nxt_python_start(nxt_task_t *task, nxt_process_data_t *data); +static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value); static int nxt_python_init_threads(nxt_python_app_conf_t *c); static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx); static void *nxt_python_thread_func(void *main_ctx); @@ -67,7 +68,7 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) int rc; char *nxt_py_module; size_t len; - PyObject *obj, *pypath, *module; + PyObject *obj, *module; nxt_str_t proto; const char *callable; nxt_unit_ctx_t *unit_ctx; @@ -162,38 +163,18 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) } nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush"); + + /* obj is a Borrowed reference. */ + obj = NULL; + if (nxt_slow_path(nxt_py_stderr_flush == NULL)) { nxt_alert(task, "Python failed to get \"flush\" attribute of " "\"sys.stderr\" object"); goto fail; } - /* obj is a Borrowed reference. */ - - if (c->path.length > 0) { - obj = PyString_FromStringAndSize((char *) c->path.start, - c->path.length); - - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, "Python failed to create string object \"%V\"", - &c->path); - goto fail; - } - - pypath = PySys_GetObject((char *) "path"); - - if (nxt_slow_path(pypath == NULL)) { - nxt_alert(task, "Python failed to get \"sys.path\" list"); - goto fail; - } - - if (nxt_slow_path(PyList_Insert(pypath, 0, obj) != 0)) { - nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", - &c->path); - goto fail; - } - - Py_DECREF(obj); + if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) { + goto fail; } obj = Py_BuildValue("[s]", "unit"); @@ -317,6 +298,74 @@ fail: } +static nxt_int_t +nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value) +{ + int ret; + PyObject *path, *sys; + nxt_str_t str; + nxt_uint_t n; + nxt_conf_value_t *array; + + if (value == NULL) { + return NXT_OK; + } + + sys = PySys_GetObject((char *) "path"); + if (nxt_slow_path(sys == NULL)) { + nxt_alert(task, "Python failed to get \"sys.path\" list"); + return NXT_ERROR; + } + + /* sys is a Borrowed reference. */ + + if (nxt_conf_type(value) == NXT_CONF_STRING) { + n = 0; + goto value_is_string; + } + + /* NXT_CONF_ARRAY */ + array = value; + + n = nxt_conf_array_elements_count(array); + + while (n != 0) { + n--; + + /* + * Insertion in front of existing paths starting from the last element + * to preserve original order while giving priority to the values + * specified in the "path" option. + */ + + value = nxt_conf_get_array_element(array, n); + + value_is_string: + + nxt_conf_get_string(value, &str); + + path = PyString_FromStringAndSize((char *) str.start, str.length); + if (nxt_slow_path(path == NULL)) { + nxt_alert(task, "Python failed to create string object \"%V\"", + &str); + return NXT_ERROR; + } + + ret = PyList_Insert(sys, 0, path); + + Py_DECREF(path); + + if (nxt_slow_path(ret != 0)) { + nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", + &str); + return NXT_ERROR; + } + } + + return NXT_OK; +} + + static int nxt_python_init_threads(nxt_python_app_conf_t *c) { diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index 98aeedf4..a6f94507 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -1131,11 +1131,12 @@ nxt_py_asgi_shm_ack_handler(nxt_unit_ctx_t *ctx) static PyObject * nxt_py_asgi_port_read(PyObject *self, PyObject *args) { - int rc; - PyObject *arg; - Py_ssize_t n; - nxt_unit_ctx_t *ctx; - nxt_unit_port_t *port; + int rc; + PyObject *arg0, *arg1, *res; + Py_ssize_t n; + nxt_unit_ctx_t *ctx; + nxt_unit_port_t *port; + nxt_py_asgi_ctx_data_t *ctx_data; n = PyTuple_GET_SIZE(args); @@ -1147,31 +1148,45 @@ nxt_py_asgi_port_read(PyObject *self, PyObject *args) return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); } - arg = PyTuple_GET_ITEM(args, 0); - if (nxt_slow_path(arg == NULL || PyLong_Check(arg) == 0)) { + arg0 = PyTuple_GET_ITEM(args, 0); + if (nxt_slow_path(arg0 == NULL || PyLong_Check(arg0) == 0)) { return PyErr_Format(PyExc_TypeError, "the first argument is not a long"); } - ctx = PyLong_AsVoidPtr(arg); + ctx = PyLong_AsVoidPtr(arg0); - arg = PyTuple_GET_ITEM(args, 1); - if (nxt_slow_path(arg == NULL || PyLong_Check(arg) == 0)) { + arg1 = PyTuple_GET_ITEM(args, 1); + if (nxt_slow_path(arg1 == NULL || PyLong_Check(arg1) == 0)) { return PyErr_Format(PyExc_TypeError, "the second argument is not a long"); } - port = PyLong_AsVoidPtr(arg); - - nxt_unit_debug(ctx, "asgi_port_read %p %p", ctx, port); + port = PyLong_AsVoidPtr(arg1); rc = nxt_unit_process_port_msg(ctx, port); + nxt_unit_debug(ctx, "asgi_port_read(%p,%p): %d", ctx, port, rc); + if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { return PyErr_Format(PyExc_RuntimeError, "error processing port %d message", port->id.id); } + if (rc == NXT_UNIT_OK) { + ctx_data = ctx->data; + + res = PyObject_CallFunctionObjArgs(ctx_data->loop_call_soon, + nxt_py_port_read, + arg0, arg1, NULL); + if (nxt_slow_path(res == NULL)) { + nxt_unit_alert(ctx, "Python failed to call 'loop.call_soon'"); + nxt_python_print_exception(); + } + + Py_XDECREF(res); + } + Py_RETURN_NONE; } diff --git a/src/python/nxt_python_wsgi.c b/src/python/nxt_python_wsgi.c index da7b183c..77c45af5 100644 --- a/src/python/nxt_python_wsgi.c +++ b/src/python/nxt_python_wsgi.c @@ -59,6 +59,7 @@ static void nxt_python_wsgi_done(void); static void nxt_python_request_handler(nxt_unit_request_info_t *req); static PyObject *nxt_python_create_environ(nxt_python_app_conf_t *c); +static PyObject *nxt_python_copy_environ(nxt_unit_request_info_t *req); static PyObject *nxt_python_get_environ(nxt_python_ctx_t *pctx); static int nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name, nxt_unit_sptr_t *sptr, uint32_t size); @@ -221,6 +222,7 @@ nxt_python_wsgi_ctx_data_alloc(void **pdata) } pctx->write = NULL; + pctx->environ = NULL; pctx->start_resp = PyCFunction_New(nxt_py_start_resp_method, (PyObject *) pctx); @@ -237,6 +239,11 @@ nxt_python_wsgi_ctx_data_alloc(void **pdata) goto fail; } + pctx->environ = nxt_python_copy_environ(NULL); + if (nxt_slow_path(pctx->environ == NULL)) { + goto fail; + } + *pdata = pctx; return NXT_UNIT_OK; @@ -258,6 +265,7 @@ nxt_python_wsgi_ctx_data_free(void *data) Py_XDECREF(pctx->start_resp); Py_XDECREF(pctx->write); + Py_XDECREF(pctx->environ); Py_XDECREF(pctx); } @@ -295,6 +303,7 @@ nxt_python_request_handler(nxt_unit_request_info_t *req) int rc; PyObject *environ, *args, *response, *iterator, *item; PyObject *close, *result; + nxt_bool_t prepare_environ; nxt_python_ctx_t *pctx; pctx = req->ctx->data; @@ -305,6 +314,19 @@ nxt_python_request_handler(nxt_unit_request_info_t *req) PyEval_RestoreThread(pctx->thread_state); + if (nxt_slow_path(pctx->environ == NULL)) { + pctx->environ = nxt_python_copy_environ(req); + + if (pctx->environ == NULL) { + prepare_environ = 0; + + rc = NXT_UNIT_ERROR; + goto done; + } + } + + prepare_environ = 1; + environ = nxt_python_get_environ(pctx); if (nxt_slow_path(environ == NULL)) { rc = NXT_UNIT_ERROR; @@ -418,6 +440,14 @@ done: pctx->req = NULL; nxt_unit_request_done(req, rc); + + if (nxt_fast_path(prepare_environ)) { + PyEval_RestoreThread(pctx->thread_state); + + pctx->environ = nxt_python_copy_environ(NULL); + + pctx->thread_state = PyEval_SaveThread(); + } } @@ -532,23 +562,30 @@ fail: static PyObject * -nxt_python_get_environ(nxt_python_ctx_t *pctx) +nxt_python_copy_environ(nxt_unit_request_info_t *req) { - int rc; - uint32_t i, j, vl; - PyObject *environ; - nxt_unit_field_t *f, *f2; - nxt_unit_request_t *r; + PyObject *environ; environ = PyDict_Copy(nxt_py_environ_ptyp); + if (nxt_slow_path(environ == NULL)) { - nxt_unit_req_error(pctx->req, + nxt_unit_req_alert(req, "Python failed to copy the \"environ\" dictionary"); - - return NULL; + nxt_python_print_exception(); } - pctx->environ = environ; + return environ; +} + + +static PyObject * +nxt_python_get_environ(nxt_python_ctx_t *pctx) +{ + int rc; + uint32_t i, j, vl; + PyObject *environ; + nxt_unit_field_t *f, *f2; + nxt_unit_request_t *r; r = pctx->req->request; @@ -628,7 +665,7 @@ nxt_python_get_environ(nxt_python_ctx_t *pctx) #undef RC - if (nxt_slow_path(PyDict_SetItem(environ, nxt_py_wsgi_input_str, + if (nxt_slow_path(PyDict_SetItem(pctx->environ, nxt_py_wsgi_input_str, (PyObject *) pctx) != 0)) { nxt_unit_req_error(pctx->req, @@ -636,11 +673,15 @@ nxt_python_get_environ(nxt_python_ctx_t *pctx) goto fail; } + environ = pctx->environ; + pctx->environ = NULL; + return environ; fail: - Py_DECREF(environ); + Py_DECREF(pctx->environ); + pctx->environ = NULL; return NULL; } |