diff options
author | OutOfFocus4 <jeff.iadarola@gmail.com> | 2021-11-14 10:47:07 -0500 |
---|---|---|
committer | Alejandro Colomar <alx@nginx.com> | 2022-12-14 11:30:30 +0100 |
commit | 6dae517ebd20baa2066541e703d6aa594326dd69 (patch) | |
tree | 6fe6a7cc8a767bc536545b640542590bbb222d30 /src/python | |
parent | 7a81d9d61d0c4e3cc7e6b74b6be367cbf26ea2ab (diff) | |
download | unit-6dae517ebd20baa2066541e703d6aa594326dd69.tar.gz unit-6dae517ebd20baa2066541e703d6aa594326dd69.tar.bz2 |
Python: Added "prefix" to configuration.
This patch gives users the option to set a `"prefix"` attribute
for Python applications, either at the top level or for specific
`"target"`s. If the attribute is present, the value of `"prefix"`
must be a string beginning with `"/"`. If the value of the `"prefix"`
attribute is longer than 1 character and ends in `"/"`, the
trailing `"/"` is stripped.
The purpose of the `"prefix"` attribute is to set the `SCRIPT_NAME`
context value for WSGI applications and the `root_path` context
value for ASGI applications, allowing applications to properly route
requests regardless of the path that the server uses to expose the
application.
The context value is only set if the request's URL path begins with
the value of the `"prefix"` attribute. In all other cases, the
`SCRIPT_NAME` or `root_path` values are not set. In addition, for
WSGI applications, the value of `"prefix"` will be stripped from
the beginning of the request's URL path before it is sent to the
application.
Reviewed-by: Andrei Zeliankou <zelenkov@nginx.com>
Reviewed-by: Artem Konev <artem.konev@nginx.com>
Signed-off-by: Alejandro Colomar <alx@nginx.com>
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/nxt_python.c | 60 | ||||
-rw-r--r-- | src/python/nxt_python.h | 2 | ||||
-rw-r--r-- | src/python/nxt_python_asgi.c | 28 | ||||
-rw-r--r-- | src/python/nxt_python_asgi_str.c | 2 | ||||
-rw-r--r-- | src/python/nxt_python_wsgi.c | 49 |
5 files changed, 118 insertions, 23 deletions
diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c index 8983815c..bdb04579 100644 --- a/src/python/nxt_python.c +++ b/src/python/nxt_python.c @@ -30,6 +30,8 @@ static nxt_int_t nxt_python_start(nxt_task_t *task, nxt_process_data_t *data); static nxt_int_t nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target, nxt_conf_value_t *conf); +nxt_inline nxt_int_t nxt_python_set_prefix(nxt_task_t *task, + nxt_python_target_t *target, nxt_conf_value_t *value); 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); @@ -389,6 +391,7 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target, static nxt_str_t module_str = nxt_string("module"); static nxt_str_t callable_str = nxt_string("callable"); + static nxt_str_t prefix_str = nxt_string("prefix"); module = obj = NULL; @@ -436,6 +439,11 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target, goto fail; } + value = nxt_conf_get_object_member(conf, &prefix_str, NULL); + if (nxt_slow_path(nxt_python_set_prefix(task, target, value) != NXT_OK)) { + goto fail; + } + target->application = obj; obj = NULL; @@ -453,6 +461,48 @@ fail: } +nxt_inline nxt_int_t +nxt_python_set_prefix(nxt_task_t *task, nxt_python_target_t *target, + nxt_conf_value_t *value) +{ + u_char *prefix; + nxt_str_t str; + + if (value == NULL) { + return NXT_OK; + } + + nxt_conf_get_string(value, &str); + + if (str.length == 0) { + return NXT_OK; + } + + if (str.start[str.length - 1] == '/') { + str.length--; + } + target->prefix.length = str.length; + prefix = nxt_malloc(str.length); + if (nxt_slow_path(prefix == NULL)) { + nxt_alert(task, "Failed to allocate target prefix string"); + return NXT_ERROR; + } + + target->py_prefix = PyString_FromStringAndSize((char *)str.start, + str.length); + if (nxt_slow_path(target->py_prefix == NULL)) { + nxt_free(prefix); + nxt_alert(task, "Python failed to allocate target prefix " + "string"); + return NXT_ERROR; + } + nxt_memcpy(prefix, str.start, str.length); + target->prefix.start = prefix; + + return NXT_OK; +} + + static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value) { @@ -730,7 +780,8 @@ nxt_python_done_strings(nxt_python_string_t *pstr) static void nxt_python_atexit(void) { - nxt_int_t i; + nxt_int_t i; + nxt_python_target_t *target; if (nxt_py_proto.done != NULL) { nxt_py_proto.done(); @@ -740,7 +791,12 @@ nxt_python_atexit(void) if (nxt_py_targets != NULL) { for (i = 0; i < nxt_py_targets->count; i++) { - Py_XDECREF(nxt_py_targets->target[i].application); + target = &nxt_py_targets->target[i]; + + Py_XDECREF(target->application); + Py_XDECREF(target->py_prefix); + + nxt_free(target->prefix.start); } nxt_unit_free(NULL, nxt_py_targets); diff --git a/src/python/nxt_python.h b/src/python/nxt_python.h index eddb1cfc..37e6265e 100644 --- a/src/python/nxt_python.h +++ b/src/python/nxt_python.h @@ -40,6 +40,8 @@ typedef struct { PyObject *application; + PyObject *py_prefix; + nxt_str_t prefix; nxt_bool_t asgi_legacy; } nxt_python_target_t; diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index 256bcdcc..587a17cf 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -27,7 +27,8 @@ static void nxt_py_asgi_remove_reader(nxt_unit_ctx_t *ctx, static void nxt_py_asgi_request_handler(nxt_unit_request_info_t *req); static void nxt_py_asgi_close_handler(nxt_unit_request_info_t *req); -static PyObject *nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req); +static PyObject *nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req, + nxt_python_target_t *app_target); static PyObject *nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port); static PyObject *nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, @@ -455,16 +456,16 @@ nxt_py_asgi_request_handler(nxt_unit_request_info_t *req) goto release_send; } - scope = nxt_py_asgi_create_http_scope(req); + req->data = asgi; + target = &nxt_py_targets->target[req->request->app_target]; + + scope = nxt_py_asgi_create_http_scope(req, target); if (nxt_slow_path(scope == NULL)) { nxt_unit_request_done(req, NXT_UNIT_ERROR); goto release_done; } - req->data = asgi; - target = &nxt_py_targets->target[req->request->app_target]; - if (!target->asgi_legacy) { nxt_unit_req_debug(req, "Python call ASGI 3.0 application"); @@ -573,12 +574,14 @@ nxt_py_asgi_close_handler(nxt_unit_request_info_t *req) static PyObject * -nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req) +nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req, + nxt_python_target_t *app_target) { char *p, *target, *query; - uint32_t target_length, i; + uint32_t target_length, i, path_length; PyObject *scope, *v, *type, *scheme; PyObject *headers, *header; + nxt_str_t prefix; nxt_unit_field_t *f; nxt_unit_request_t *r; @@ -612,6 +615,17 @@ nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req) return NULL; } + prefix = app_target->prefix; + path_length = r->path_length; + p = nxt_unit_sptr_get(&r->path); + if (prefix.length > 0 + && ((path_length > prefix.length && p[prefix.length] == '/') + || path_length == prefix.length) + && memcmp(prefix.start, p, prefix.length) == 0) + { + SET_ITEM(scope, root_path, app_target->py_prefix); + } + p = nxt_unit_sptr_get(&r->version); SET_ITEM(scope, http_version, p[7] == '1' ? nxt_py_1_1_str : nxt_py_1_0_str) diff --git a/src/python/nxt_python_asgi_str.c b/src/python/nxt_python_asgi_str.c index 34422973..7171d52b 100644 --- a/src/python/nxt_python_asgi_str.c +++ b/src/python/nxt_python_asgi_str.c @@ -99,7 +99,7 @@ static nxt_python_string_t nxt_py_asgi_strings[] = { { nxt_string("query_string"), &nxt_py_query_string_str }, { nxt_string("raw_path"), &nxt_py_raw_path_str }, { nxt_string("result"), &nxt_py_result_str }, - { nxt_string("root_path"), &nxt_py_root_path_str }, // not used + { nxt_string("root_path"), &nxt_py_root_path_str }, { nxt_string("scheme"), &nxt_py_scheme_str }, { nxt_string("server"), &nxt_py_server_str }, { nxt_string("set_exception"), &nxt_py_set_exception_str }, diff --git a/src/python/nxt_python_wsgi.c b/src/python/nxt_python_wsgi.c index 34afd9a9..dfb31509 100644 --- a/src/python/nxt_python_wsgi.c +++ b/src/python/nxt_python_wsgi.c @@ -60,7 +60,8 @@ 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 PyObject *nxt_python_get_environ(nxt_python_ctx_t *pctx, + nxt_python_target_t *app_target); static int nxt_python_add_sptr(nxt_python_ctx_t *pctx, PyObject *name, nxt_unit_sptr_t *sptr, uint32_t size); static int nxt_python_add_char(nxt_python_ctx_t *pctx, PyObject *name, @@ -141,6 +142,7 @@ static PyObject *nxt_py_query_string_str; static PyObject *nxt_py_remote_addr_str; static PyObject *nxt_py_request_method_str; static PyObject *nxt_py_request_uri_str; +static PyObject *nxt_py_script_name_str; static PyObject *nxt_py_server_addr_str; static PyObject *nxt_py_server_name_str; static PyObject *nxt_py_server_port_str; @@ -160,6 +162,7 @@ static nxt_python_string_t nxt_python_strings[] = { { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str }, { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str }, { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str }, + { nxt_string("SCRIPT_NAME"), &nxt_py_script_name_str }, { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str }, { nxt_string("SERVER_NAME"), &nxt_py_server_name_str }, { nxt_string("SERVER_PORT"), &nxt_py_server_port_str }, @@ -304,11 +307,12 @@ nxt_python_wsgi_done(void) static void nxt_python_request_handler(nxt_unit_request_info_t *req) { - int rc; - PyObject *environ, *args, *response, *iterator, *item; - PyObject *close, *result, *application; - nxt_bool_t prepare_environ; - nxt_python_ctx_t *pctx; + int rc; + PyObject *environ, *args, *response, *iterator, *item; + PyObject *close, *result; + nxt_bool_t prepare_environ; + nxt_python_ctx_t *pctx; + nxt_python_target_t *target; pctx = req->ctx->data; @@ -331,7 +335,9 @@ nxt_python_request_handler(nxt_unit_request_info_t *req) prepare_environ = 1; - environ = nxt_python_get_environ(pctx); + target = &nxt_py_targets->target[req->request->app_target]; + + environ = nxt_python_get_environ(pctx, target); if (nxt_slow_path(environ == NULL)) { rc = NXT_UNIT_ERROR; goto done; @@ -352,8 +358,7 @@ nxt_python_request_handler(nxt_unit_request_info_t *req) Py_INCREF(pctx->start_resp); PyTuple_SET_ITEM(args, 1, pctx->start_resp); - application = nxt_py_targets->target[req->request->app_target].application; - response = PyObject_CallObject(application, args); + response = PyObject_CallObject(target->application, args); Py_DECREF(args); @@ -584,11 +589,14 @@ nxt_python_copy_environ(nxt_unit_request_info_t *req) static PyObject * -nxt_python_get_environ(nxt_python_ctx_t *pctx) +nxt_python_get_environ(nxt_python_ctx_t *pctx, + nxt_python_target_t *app_target) { int rc; - uint32_t i, j, vl; + char *path; + uint32_t i, j, vl, path_length; PyObject *environ; + nxt_str_t prefix; nxt_unit_field_t *f, *f2; nxt_unit_request_t *r; @@ -608,8 +616,23 @@ nxt_python_get_environ(nxt_python_ctx_t *pctx) r->target_length)); RC(nxt_python_add_sptr(pctx, nxt_py_query_string_str, &r->query, r->query_length)); - RC(nxt_python_add_sptr(pctx, nxt_py_path_info_str, &r->path, - r->path_length)); + + prefix = app_target->prefix; + path_length = r->path_length; + path = nxt_unit_sptr_get(&r->path); + if (prefix.length > 0 + && ((path_length > prefix.length && path[prefix.length] == '/') + || path_length == prefix.length) + && memcmp(prefix.start, path, prefix.length) == 0) + { + RC(nxt_python_add_py_string(pctx, nxt_py_script_name_str, + app_target->py_prefix)); + + path += prefix.length; + path_length -= prefix.length; + } + + RC(nxt_python_add_char(pctx, nxt_py_path_info_str, path, path_length)); RC(nxt_python_add_sptr(pctx, nxt_py_remote_addr_str, &r->remote, r->remote_length)); |