summaryrefslogtreecommitdiffhomepage
path: root/src/python
diff options
context:
space:
mode:
Diffstat (limited to 'src/python')
-rw-r--r--src/python/nxt_python.c103
-rw-r--r--src/python/nxt_python_asgi.c41
-rw-r--r--src/python/nxt_python_wsgi.c65
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;
}