1*1591Smax.romanov@nginx.com 2*1591Smax.romanov@nginx.com /* 3*1591Smax.romanov@nginx.com * Copyright (C) Max Romanov 4*1591Smax.romanov@nginx.com * Copyright (C) Valentin V. Bartenev 5*1591Smax.romanov@nginx.com * Copyright (C) NGINX, Inc. 6*1591Smax.romanov@nginx.com */ 7*1591Smax.romanov@nginx.com 8*1591Smax.romanov@nginx.com 9*1591Smax.romanov@nginx.com #include <Python.h> 10*1591Smax.romanov@nginx.com 11*1591Smax.romanov@nginx.com #include <compile.h> 12*1591Smax.romanov@nginx.com #include <node.h> 13*1591Smax.romanov@nginx.com 14*1591Smax.romanov@nginx.com #include <nxt_main.h> 15*1591Smax.romanov@nginx.com #include <nxt_runtime.h> 16*1591Smax.romanov@nginx.com #include <nxt_router.h> 17*1591Smax.romanov@nginx.com #include <nxt_unit.h> 18*1591Smax.romanov@nginx.com #include <nxt_unit_field.h> 19*1591Smax.romanov@nginx.com #include <nxt_unit_request.h> 20*1591Smax.romanov@nginx.com #include <nxt_unit_response.h> 21*1591Smax.romanov@nginx.com 22*1591Smax.romanov@nginx.com #include NXT_PYTHON_MOUNTS_H 23*1591Smax.romanov@nginx.com 24*1591Smax.romanov@nginx.com /* 25*1591Smax.romanov@nginx.com * According to "PEP 3333 / A Note On String Types" 26*1591Smax.romanov@nginx.com * [https://www.python.org/dev/peps/pep-3333/#a-note-on-string-types] 27*1591Smax.romanov@nginx.com * 28*1591Smax.romanov@nginx.com * WSGI therefore defines two kinds of "string": 29*1591Smax.romanov@nginx.com * 30*1591Smax.romanov@nginx.com * - "Native" strings (which are always implemented using the type named str ) 31*1591Smax.romanov@nginx.com * that are used for request/response headers and metadata 32*1591Smax.romanov@nginx.com * 33*1591Smax.romanov@nginx.com * will use PyString_* or corresponding PyUnicode_* functions 34*1591Smax.romanov@nginx.com * 35*1591Smax.romanov@nginx.com * - "Bytestrings" (which are implemented using the bytes type in Python 3, and 36*1591Smax.romanov@nginx.com * str elsewhere), that are used for the bodies of requests and responses 37*1591Smax.romanov@nginx.com * (e.g. POST/PUT input data and HTML page outputs). 38*1591Smax.romanov@nginx.com * 39*1591Smax.romanov@nginx.com * will use PyString_* or corresponding PyBytes_* functions 40*1591Smax.romanov@nginx.com */ 41*1591Smax.romanov@nginx.com 42*1591Smax.romanov@nginx.com 43*1591Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3 44*1591Smax.romanov@nginx.com #define NXT_PYTHON_BYTES_TYPE "bytestring" 45*1591Smax.romanov@nginx.com 46*1591Smax.romanov@nginx.com #define PyString_FromStringAndSize(str, size) \ 47*1591Smax.romanov@nginx.com PyUnicode_DecodeLatin1((str), (size), "strict") 48*1591Smax.romanov@nginx.com 49*1591Smax.romanov@nginx.com #else 50*1591Smax.romanov@nginx.com #define NXT_PYTHON_BYTES_TYPE "string" 51*1591Smax.romanov@nginx.com 52*1591Smax.romanov@nginx.com #define PyBytes_FromStringAndSize PyString_FromStringAndSize 53*1591Smax.romanov@nginx.com #define PyBytes_Check PyString_Check 54*1591Smax.romanov@nginx.com #define PyBytes_GET_SIZE PyString_GET_SIZE 55*1591Smax.romanov@nginx.com #define PyBytes_AS_STRING PyString_AS_STRING 56*1591Smax.romanov@nginx.com #define PyUnicode_InternInPlace PyString_InternInPlace 57*1591Smax.romanov@nginx.com #define PyUnicode_AsUTF8 PyString_AS_STRING 58*1591Smax.romanov@nginx.com #endif 59*1591Smax.romanov@nginx.com 60*1591Smax.romanov@nginx.com typedef struct nxt_python_run_ctx_s nxt_python_run_ctx_t; 61*1591Smax.romanov@nginx.com 62*1591Smax.romanov@nginx.com typedef struct { 63*1591Smax.romanov@nginx.com PyObject_HEAD 64*1591Smax.romanov@nginx.com } nxt_py_input_t; 65*1591Smax.romanov@nginx.com 66*1591Smax.romanov@nginx.com 67*1591Smax.romanov@nginx.com typedef struct { 68*1591Smax.romanov@nginx.com PyObject_HEAD 69*1591Smax.romanov@nginx.com } nxt_py_error_t; 70*1591Smax.romanov@nginx.com 71*1591Smax.romanov@nginx.com static nxt_int_t nxt_python_start(nxt_task_t *task, 72*1591Smax.romanov@nginx.com nxt_process_data_t *data); 73*1591Smax.romanov@nginx.com static nxt_int_t nxt_python_init_strings(void); 74*1591Smax.romanov@nginx.com static void nxt_python_request_handler(nxt_unit_request_info_t *req); 75*1591Smax.romanov@nginx.com static void nxt_python_atexit(void); 76*1591Smax.romanov@nginx.com 77*1591Smax.romanov@nginx.com static PyObject *nxt_python_create_environ(nxt_task_t *task); 78*1591Smax.romanov@nginx.com static PyObject *nxt_python_get_environ(nxt_python_run_ctx_t *ctx); 79*1591Smax.romanov@nginx.com static int nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name, 80*1591Smax.romanov@nginx.com nxt_unit_sptr_t *sptr, uint32_t size); 81*1591Smax.romanov@nginx.com static int nxt_python_add_field(nxt_python_run_ctx_t *ctx, 82*1591Smax.romanov@nginx.com nxt_unit_field_t *field); 83*1591Smax.romanov@nginx.com static int nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name, 84*1591Smax.romanov@nginx.com PyObject *value); 85*1591Smax.romanov@nginx.com 86*1591Smax.romanov@nginx.com static PyObject *nxt_py_start_resp(PyObject *self, PyObject *args); 87*1591Smax.romanov@nginx.com static int nxt_python_response_add_field(nxt_python_run_ctx_t *ctx, 88*1591Smax.romanov@nginx.com PyObject *name, PyObject *value, int i); 89*1591Smax.romanov@nginx.com static int nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len, 90*1591Smax.romanov@nginx.com PyObject **bytes); 91*1591Smax.romanov@nginx.com static PyObject *nxt_py_write(PyObject *self, PyObject *args); 92*1591Smax.romanov@nginx.com 93*1591Smax.romanov@nginx.com static void nxt_py_input_dealloc(nxt_py_input_t *self); 94*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_read(nxt_py_input_t *self, PyObject *args); 95*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_readline(nxt_py_input_t *self, PyObject *args); 96*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_getline(nxt_python_run_ctx_t *ctx, size_t size); 97*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_readlines(nxt_py_input_t *self, PyObject *args); 98*1591Smax.romanov@nginx.com 99*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_iter(PyObject *self); 100*1591Smax.romanov@nginx.com static PyObject *nxt_py_input_next(PyObject *self); 101*1591Smax.romanov@nginx.com 102*1591Smax.romanov@nginx.com static void nxt_python_print_exception(void); 103*1591Smax.romanov@nginx.com static int nxt_python_write(nxt_python_run_ctx_t *ctx, PyObject *bytes); 104*1591Smax.romanov@nginx.com 105*1591Smax.romanov@nginx.com struct nxt_python_run_ctx_s { 106*1591Smax.romanov@nginx.com uint64_t content_length; 107*1591Smax.romanov@nginx.com uint64_t bytes_sent; 108*1591Smax.romanov@nginx.com PyObject *environ; 109*1591Smax.romanov@nginx.com nxt_unit_request_info_t *req; 110*1591Smax.romanov@nginx.com }; 111*1591Smax.romanov@nginx.com 112*1591Smax.romanov@nginx.com static uint32_t compat[] = { 113*1591Smax.romanov@nginx.com NXT_VERNUM, NXT_DEBUG, 114*1591Smax.romanov@nginx.com }; 115*1591Smax.romanov@nginx.com 116*1591Smax.romanov@nginx.com 117*1591Smax.romanov@nginx.com NXT_EXPORT nxt_app_module_t nxt_app_module = { 118*1591Smax.romanov@nginx.com sizeof(compat), 119*1591Smax.romanov@nginx.com compat, 120*1591Smax.romanov@nginx.com nxt_string("python"), 121*1591Smax.romanov@nginx.com PY_VERSION, 122*1591Smax.romanov@nginx.com nxt_python_mounts, 123*1591Smax.romanov@nginx.com nxt_nitems(nxt_python_mounts), 124*1591Smax.romanov@nginx.com NULL, 125*1591Smax.romanov@nginx.com nxt_python_start, 126*1591Smax.romanov@nginx.com }; 127*1591Smax.romanov@nginx.com 128*1591Smax.romanov@nginx.com 129*1591Smax.romanov@nginx.com static PyMethodDef nxt_py_start_resp_method[] = { 130*1591Smax.romanov@nginx.com {"unit_start_response", nxt_py_start_resp, METH_VARARGS, ""} 131*1591Smax.romanov@nginx.com }; 132*1591Smax.romanov@nginx.com 133*1591Smax.romanov@nginx.com 134*1591Smax.romanov@nginx.com static PyMethodDef nxt_py_write_method[] = { 135*1591Smax.romanov@nginx.com {"unit_write", nxt_py_write, METH_O, ""} 136*1591Smax.romanov@nginx.com }; 137*1591Smax.romanov@nginx.com 138*1591Smax.romanov@nginx.com 139*1591Smax.romanov@nginx.com static PyMethodDef nxt_py_input_methods[] = { 140*1591Smax.romanov@nginx.com { "read", (PyCFunction) nxt_py_input_read, METH_VARARGS, 0 }, 141*1591Smax.romanov@nginx.com { "readline", (PyCFunction) nxt_py_input_readline, METH_VARARGS, 0 }, 142*1591Smax.romanov@nginx.com { "readlines", (PyCFunction) nxt_py_input_readlines, METH_VARARGS, 0 }, 143*1591Smax.romanov@nginx.com { NULL, NULL, 0, 0 } 144*1591Smax.romanov@nginx.com }; 145*1591Smax.romanov@nginx.com 146*1591Smax.romanov@nginx.com 147*1591Smax.romanov@nginx.com static PyTypeObject nxt_py_input_type = { 148*1591Smax.romanov@nginx.com PyVarObject_HEAD_INIT(NULL, 0) 149*1591Smax.romanov@nginx.com 150*1591Smax.romanov@nginx.com .tp_name = "unit._input", 151*1591Smax.romanov@nginx.com .tp_basicsize = sizeof(nxt_py_input_t), 152*1591Smax.romanov@nginx.com .tp_dealloc = (destructor) nxt_py_input_dealloc, 153*1591Smax.romanov@nginx.com .tp_flags = Py_TPFLAGS_DEFAULT, 154*1591Smax.romanov@nginx.com .tp_doc = "unit input object.", 155*1591Smax.romanov@nginx.com .tp_iter = nxt_py_input_iter, 156*1591Smax.romanov@nginx.com .tp_iternext = nxt_py_input_next, 157*1591Smax.romanov@nginx.com .tp_methods = nxt_py_input_methods, 158*1591Smax.romanov@nginx.com }; 159*1591Smax.romanov@nginx.com 160*1591Smax.romanov@nginx.com 161*1591Smax.romanov@nginx.com static PyObject *nxt_py_stderr_flush; 162*1591Smax.romanov@nginx.com static PyObject *nxt_py_application; 163*1591Smax.romanov@nginx.com static PyObject *nxt_py_start_resp_obj; 164*1591Smax.romanov@nginx.com static PyObject *nxt_py_write_obj; 165*1591Smax.romanov@nginx.com static PyObject *nxt_py_environ_ptyp; 166*1591Smax.romanov@nginx.com 167*1591Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3 168*1591Smax.romanov@nginx.com static wchar_t *nxt_py_home; 169*1591Smax.romanov@nginx.com #else 170*1591Smax.romanov@nginx.com static char *nxt_py_home; 171*1591Smax.romanov@nginx.com #endif 172*1591Smax.romanov@nginx.com 173*1591Smax.romanov@nginx.com static PyThreadState *nxt_python_thread_state; 174*1591Smax.romanov@nginx.com static nxt_python_run_ctx_t *nxt_python_run_ctx; 175*1591Smax.romanov@nginx.com 176*1591Smax.romanov@nginx.com 177*1591Smax.romanov@nginx.com static PyObject *nxt_py_80_str; 178*1591Smax.romanov@nginx.com static PyObject *nxt_py_close_str; 179*1591Smax.romanov@nginx.com static PyObject *nxt_py_content_length_str; 180*1591Smax.romanov@nginx.com static PyObject *nxt_py_content_type_str; 181*1591Smax.romanov@nginx.com static PyObject *nxt_py_http_str; 182*1591Smax.romanov@nginx.com static PyObject *nxt_py_https_str; 183*1591Smax.romanov@nginx.com static PyObject *nxt_py_path_info_str; 184*1591Smax.romanov@nginx.com static PyObject *nxt_py_query_string_str; 185*1591Smax.romanov@nginx.com static PyObject *nxt_py_remote_addr_str; 186*1591Smax.romanov@nginx.com static PyObject *nxt_py_request_method_str; 187*1591Smax.romanov@nginx.com static PyObject *nxt_py_request_uri_str; 188*1591Smax.romanov@nginx.com static PyObject *nxt_py_server_addr_str; 189*1591Smax.romanov@nginx.com static PyObject *nxt_py_server_name_str; 190*1591Smax.romanov@nginx.com static PyObject *nxt_py_server_port_str; 191*1591Smax.romanov@nginx.com static PyObject *nxt_py_server_protocol_str; 192*1591Smax.romanov@nginx.com static PyObject *nxt_py_wsgi_uri_scheme_str; 193*1591Smax.romanov@nginx.com 194*1591Smax.romanov@nginx.com typedef struct { 195*1591Smax.romanov@nginx.com nxt_str_t string; 196*1591Smax.romanov@nginx.com PyObject **object_p; 197*1591Smax.romanov@nginx.com } nxt_python_string_t; 198*1591Smax.romanov@nginx.com 199*1591Smax.romanov@nginx.com static nxt_python_string_t nxt_python_strings[] = { 200*1591Smax.romanov@nginx.com { nxt_string("80"), &nxt_py_80_str }, 201*1591Smax.romanov@nginx.com { nxt_string("close"), &nxt_py_close_str }, 202*1591Smax.romanov@nginx.com { nxt_string("CONTENT_LENGTH"), &nxt_py_content_length_str }, 203*1591Smax.romanov@nginx.com { nxt_string("CONTENT_TYPE"), &nxt_py_content_type_str }, 204*1591Smax.romanov@nginx.com { nxt_string("http"), &nxt_py_http_str }, 205*1591Smax.romanov@nginx.com { nxt_string("https"), &nxt_py_https_str }, 206*1591Smax.romanov@nginx.com { nxt_string("PATH_INFO"), &nxt_py_path_info_str }, 207*1591Smax.romanov@nginx.com { nxt_string("QUERY_STRING"), &nxt_py_query_string_str }, 208*1591Smax.romanov@nginx.com { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str }, 209*1591Smax.romanov@nginx.com { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str }, 210*1591Smax.romanov@nginx.com { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str }, 211*1591Smax.romanov@nginx.com { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str }, 212*1591Smax.romanov@nginx.com { nxt_string("SERVER_NAME"), &nxt_py_server_name_str }, 213*1591Smax.romanov@nginx.com { nxt_string("SERVER_PORT"), &nxt_py_server_port_str }, 214*1591Smax.romanov@nginx.com { nxt_string("SERVER_PROTOCOL"), &nxt_py_server_protocol_str }, 215*1591Smax.romanov@nginx.com { nxt_string("wsgi.url_scheme"), &nxt_py_wsgi_uri_scheme_str }, 216*1591Smax.romanov@nginx.com }; 217*1591Smax.romanov@nginx.com 218*1591Smax.romanov@nginx.com 219*1591Smax.romanov@nginx.com static nxt_int_t 220*1591Smax.romanov@nginx.com nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) 221*1591Smax.romanov@nginx.com { 222*1591Smax.romanov@nginx.com int rc; 223*1591Smax.romanov@nginx.com char *nxt_py_module; 224*1591Smax.romanov@nginx.com size_t len; 225*1591Smax.romanov@nginx.com PyObject *obj, *pypath, *module; 226*1591Smax.romanov@nginx.com nxt_unit_ctx_t *unit_ctx; 227*1591Smax.romanov@nginx.com nxt_unit_init_t python_init; 228*1591Smax.romanov@nginx.com nxt_common_app_conf_t *app_conf; 229*1591Smax.romanov@nginx.com nxt_python_app_conf_t *c; 230*1591Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3 231*1591Smax.romanov@nginx.com char *path; 232*1591Smax.romanov@nginx.com size_t size; 233*1591Smax.romanov@nginx.com nxt_int_t pep405; 234*1591Smax.romanov@nginx.com 235*1591Smax.romanov@nginx.com static const char pyvenv[] = "/pyvenv.cfg"; 236*1591Smax.romanov@nginx.com static const char bin_python[] = "/bin/python"; 237*1591Smax.romanov@nginx.com #endif 238*1591Smax.romanov@nginx.com 239*1591Smax.romanov@nginx.com app_conf = data->app; 240*1591Smax.romanov@nginx.com c = &app_conf->u.python; 241*1591Smax.romanov@nginx.com 242*1591Smax.romanov@nginx.com if (c->home != NULL) { 243*1591Smax.romanov@nginx.com len = nxt_strlen(c->home); 244*1591Smax.romanov@nginx.com 245*1591Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3 246*1591Smax.romanov@nginx.com 247*1591Smax.romanov@nginx.com path = nxt_malloc(len + sizeof(pyvenv)); 248*1591Smax.romanov@nginx.com if (nxt_slow_path(path == NULL)) { 249*1591Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory"); 250*1591Smax.romanov@nginx.com return NXT_ERROR; 251*1591Smax.romanov@nginx.com } 252*1591Smax.romanov@nginx.com 253*1591Smax.romanov@nginx.com nxt_memcpy(path, c->home, len); 254*1591Smax.romanov@nginx.com nxt_memcpy(path + len, pyvenv, sizeof(pyvenv)); 255*1591Smax.romanov@nginx.com 256*1591Smax.romanov@nginx.com pep405 = (access(path, R_OK) == 0); 257*1591Smax.romanov@nginx.com 258*1591Smax.romanov@nginx.com nxt_free(path); 259*1591Smax.romanov@nginx.com 260*1591Smax.romanov@nginx.com if (pep405) { 261*1591Smax.romanov@nginx.com size = (len + sizeof(bin_python)) * sizeof(wchar_t); 262*1591Smax.romanov@nginx.com 263*1591Smax.romanov@nginx.com } else { 264*1591Smax.romanov@nginx.com size = (len + 1) * sizeof(wchar_t); 265*1591Smax.romanov@nginx.com } 266*1591Smax.romanov@nginx.com 267*1591Smax.romanov@nginx.com nxt_py_home = nxt_malloc(size); 268*1591Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_home == NULL)) { 269*1591Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory"); 270*1591Smax.romanov@nginx.com return NXT_ERROR; 271*1591Smax.romanov@nginx.com } 272*1591Smax.romanov@nginx.com 273*1591Smax.romanov@nginx.com if (pep405) { 274*1591Smax.romanov@nginx.com mbstowcs(nxt_py_home, c->home, len); 275*1591Smax.romanov@nginx.com mbstowcs(nxt_py_home + len, bin_python, sizeof(bin_python)); 276*1591Smax.romanov@nginx.com Py_SetProgramName(nxt_py_home); 277*1591Smax.romanov@nginx.com 278*1591Smax.romanov@nginx.com } else { 279*1591Smax.romanov@nginx.com mbstowcs(nxt_py_home, c->home, len + 1); 280*1591Smax.romanov@nginx.com Py_SetPythonHome(nxt_py_home); 281*1591Smax.romanov@nginx.com } 282*1591Smax.romanov@nginx.com 283*1591Smax.romanov@nginx.com #else 284*1591Smax.romanov@nginx.com nxt_py_home = nxt_malloc(len + 1); 285*1591Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_home == NULL)) { 286*1591Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory"); 287*1591Smax.romanov@nginx.com return NXT_ERROR; 288*1591Smax.romanov@nginx.com } 289*1591Smax.romanov@nginx.com 290*1591Smax.romanov@nginx.com nxt_memcpy(nxt_py_home, c->home, len + 1); 291*1591Smax.romanov@nginx.com Py_SetPythonHome(nxt_py_home); 292*1591Smax.romanov@nginx.com #endif 293*1591Smax.romanov@nginx.com } 294*1591Smax.romanov@nginx.com 295*1591Smax.romanov@nginx.com Py_InitializeEx(0); 296*1591Smax.romanov@nginx.com 297*1591Smax.romanov@nginx.com module = NULL; 298*1591Smax.romanov@nginx.com obj = NULL; 299*1591Smax.romanov@nginx.com 300*1591Smax.romanov@nginx.com if (nxt_slow_path(nxt_python_init_strings() != NXT_OK)) { 301*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to init string objects"); 302*1591Smax.romanov@nginx.com goto fail; 303*1591Smax.romanov@nginx.com } 304*1591Smax.romanov@nginx.com 305*1591Smax.romanov@nginx.com obj = PySys_GetObject((char *) "stderr"); 306*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 307*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"sys.stderr\" object"); 308*1591Smax.romanov@nginx.com goto fail; 309*1591Smax.romanov@nginx.com } 310*1591Smax.romanov@nginx.com 311*1591Smax.romanov@nginx.com nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush"); 312*1591Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_stderr_flush == NULL)) { 313*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"flush\" attribute of " 314*1591Smax.romanov@nginx.com "\"sys.stderr\" object"); 315*1591Smax.romanov@nginx.com goto fail; 316*1591Smax.romanov@nginx.com } 317*1591Smax.romanov@nginx.com 318*1591Smax.romanov@nginx.com Py_DECREF(obj); 319*1591Smax.romanov@nginx.com 320*1591Smax.romanov@nginx.com if (c->path.length > 0) { 321*1591Smax.romanov@nginx.com obj = PyString_FromStringAndSize((char *) c->path.start, 322*1591Smax.romanov@nginx.com c->path.length); 323*1591Smax.romanov@nginx.com 324*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 325*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to create string object \"%V\"", 326*1591Smax.romanov@nginx.com &c->path); 327*1591Smax.romanov@nginx.com goto fail; 328*1591Smax.romanov@nginx.com } 329*1591Smax.romanov@nginx.com 330*1591Smax.romanov@nginx.com pypath = PySys_GetObject((char *) "path"); 331*1591Smax.romanov@nginx.com 332*1591Smax.romanov@nginx.com if (nxt_slow_path(pypath == NULL)) { 333*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"sys.path\" list"); 334*1591Smax.romanov@nginx.com goto fail; 335*1591Smax.romanov@nginx.com } 336*1591Smax.romanov@nginx.com 337*1591Smax.romanov@nginx.com if (nxt_slow_path(PyList_Insert(pypath, 0, obj) != 0)) { 338*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", 339*1591Smax.romanov@nginx.com &c->path); 340*1591Smax.romanov@nginx.com goto fail; 341*1591Smax.romanov@nginx.com } 342*1591Smax.romanov@nginx.com 343*1591Smax.romanov@nginx.com Py_DECREF(obj); 344*1591Smax.romanov@nginx.com } 345*1591Smax.romanov@nginx.com 346*1591Smax.romanov@nginx.com obj = PyCFunction_New(nxt_py_start_resp_method, NULL); 347*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 348*1591Smax.romanov@nginx.com nxt_alert(task, 349*1591Smax.romanov@nginx.com "Python failed to initialize the \"start_response\" function"); 350*1591Smax.romanov@nginx.com goto fail; 351*1591Smax.romanov@nginx.com } 352*1591Smax.romanov@nginx.com 353*1591Smax.romanov@nginx.com nxt_py_start_resp_obj = obj; 354*1591Smax.romanov@nginx.com 355*1591Smax.romanov@nginx.com obj = PyCFunction_New(nxt_py_write_method, NULL); 356*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 357*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to initialize the \"write\" function"); 358*1591Smax.romanov@nginx.com goto fail; 359*1591Smax.romanov@nginx.com } 360*1591Smax.romanov@nginx.com 361*1591Smax.romanov@nginx.com nxt_py_write_obj = obj; 362*1591Smax.romanov@nginx.com 363*1591Smax.romanov@nginx.com obj = nxt_python_create_environ(task); 364*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 365*1591Smax.romanov@nginx.com goto fail; 366*1591Smax.romanov@nginx.com } 367*1591Smax.romanov@nginx.com 368*1591Smax.romanov@nginx.com nxt_py_environ_ptyp = obj; 369*1591Smax.romanov@nginx.com 370*1591Smax.romanov@nginx.com obj = Py_BuildValue("[s]", "unit"); 371*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 372*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to create the \"sys.argv\" list"); 373*1591Smax.romanov@nginx.com goto fail; 374*1591Smax.romanov@nginx.com } 375*1591Smax.romanov@nginx.com 376*1591Smax.romanov@nginx.com if (nxt_slow_path(PySys_SetObject((char *) "argv", obj) != 0)) { 377*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to set the \"sys.argv\" list"); 378*1591Smax.romanov@nginx.com goto fail; 379*1591Smax.romanov@nginx.com } 380*1591Smax.romanov@nginx.com 381*1591Smax.romanov@nginx.com Py_CLEAR(obj); 382*1591Smax.romanov@nginx.com 383*1591Smax.romanov@nginx.com nxt_py_module = nxt_alloca(c->module.length + 1); 384*1591Smax.romanov@nginx.com nxt_memcpy(nxt_py_module, c->module.start, c->module.length); 385*1591Smax.romanov@nginx.com nxt_py_module[c->module.length] = '\0'; 386*1591Smax.romanov@nginx.com 387*1591Smax.romanov@nginx.com module = PyImport_ImportModule(nxt_py_module); 388*1591Smax.romanov@nginx.com if (nxt_slow_path(module == NULL)) { 389*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to import module \"%s\"", nxt_py_module); 390*1591Smax.romanov@nginx.com nxt_python_print_exception(); 391*1591Smax.romanov@nginx.com goto fail; 392*1591Smax.romanov@nginx.com } 393*1591Smax.romanov@nginx.com 394*1591Smax.romanov@nginx.com obj = PyDict_GetItemString(PyModule_GetDict(module), "application"); 395*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 396*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"application\" " 397*1591Smax.romanov@nginx.com "from module \"%s\"", nxt_py_module); 398*1591Smax.romanov@nginx.com goto fail; 399*1591Smax.romanov@nginx.com } 400*1591Smax.romanov@nginx.com 401*1591Smax.romanov@nginx.com if (nxt_slow_path(PyCallable_Check(obj) == 0)) { 402*1591Smax.romanov@nginx.com nxt_alert(task, "\"application\" in module \"%s\" " 403*1591Smax.romanov@nginx.com "is not a callable object", nxt_py_module); 404*1591Smax.romanov@nginx.com goto fail; 405*1591Smax.romanov@nginx.com } 406*1591Smax.romanov@nginx.com 407*1591Smax.romanov@nginx.com Py_INCREF(obj); 408*1591Smax.romanov@nginx.com Py_CLEAR(module); 409*1591Smax.romanov@nginx.com 410*1591Smax.romanov@nginx.com nxt_py_application = obj; 411*1591Smax.romanov@nginx.com obj = NULL; 412*1591Smax.romanov@nginx.com 413*1591Smax.romanov@nginx.com nxt_unit_default_init(task, &python_init); 414*1591Smax.romanov@nginx.com 415*1591Smax.romanov@nginx.com python_init.callbacks.request_handler = nxt_python_request_handler; 416*1591Smax.romanov@nginx.com python_init.shm_limit = data->app->shm_limit; 417*1591Smax.romanov@nginx.com 418*1591Smax.romanov@nginx.com unit_ctx = nxt_unit_init(&python_init); 419*1591Smax.romanov@nginx.com if (nxt_slow_path(unit_ctx == NULL)) { 420*1591Smax.romanov@nginx.com goto fail; 421*1591Smax.romanov@nginx.com } 422*1591Smax.romanov@nginx.com 423*1591Smax.romanov@nginx.com nxt_python_thread_state = PyEval_SaveThread(); 424*1591Smax.romanov@nginx.com 425*1591Smax.romanov@nginx.com rc = nxt_unit_run(unit_ctx); 426*1591Smax.romanov@nginx.com 427*1591Smax.romanov@nginx.com nxt_unit_done(unit_ctx); 428*1591Smax.romanov@nginx.com 429*1591Smax.romanov@nginx.com PyEval_RestoreThread(nxt_python_thread_state); 430*1591Smax.romanov@nginx.com 431*1591Smax.romanov@nginx.com nxt_python_atexit(); 432*1591Smax.romanov@nginx.com 433*1591Smax.romanov@nginx.com exit(rc); 434*1591Smax.romanov@nginx.com 435*1591Smax.romanov@nginx.com return NXT_OK; 436*1591Smax.romanov@nginx.com 437*1591Smax.romanov@nginx.com fail: 438*1591Smax.romanov@nginx.com 439*1591Smax.romanov@nginx.com Py_XDECREF(obj); 440*1591Smax.romanov@nginx.com Py_XDECREF(module); 441*1591Smax.romanov@nginx.com 442*1591Smax.romanov@nginx.com nxt_python_atexit(); 443*1591Smax.romanov@nginx.com 444*1591Smax.romanov@nginx.com return NXT_ERROR; 445*1591Smax.romanov@nginx.com } 446*1591Smax.romanov@nginx.com 447*1591Smax.romanov@nginx.com 448*1591Smax.romanov@nginx.com static nxt_int_t 449*1591Smax.romanov@nginx.com nxt_python_init_strings(void) 450*1591Smax.romanov@nginx.com { 451*1591Smax.romanov@nginx.com PyObject *obj; 452*1591Smax.romanov@nginx.com nxt_uint_t i; 453*1591Smax.romanov@nginx.com nxt_python_string_t *pstr; 454*1591Smax.romanov@nginx.com 455*1591Smax.romanov@nginx.com for (i = 0; i < nxt_nitems(nxt_python_strings); i++) { 456*1591Smax.romanov@nginx.com pstr = &nxt_python_strings[i]; 457*1591Smax.romanov@nginx.com 458*1591Smax.romanov@nginx.com obj = PyString_FromStringAndSize((char *) pstr->string.start, 459*1591Smax.romanov@nginx.com pstr->string.length); 460*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 461*1591Smax.romanov@nginx.com return NXT_ERROR; 462*1591Smax.romanov@nginx.com } 463*1591Smax.romanov@nginx.com 464*1591Smax.romanov@nginx.com PyUnicode_InternInPlace(&obj); 465*1591Smax.romanov@nginx.com 466*1591Smax.romanov@nginx.com *pstr->object_p = obj; 467*1591Smax.romanov@nginx.com } 468*1591Smax.romanov@nginx.com 469*1591Smax.romanov@nginx.com return NXT_OK; 470*1591Smax.romanov@nginx.com } 471*1591Smax.romanov@nginx.com 472*1591Smax.romanov@nginx.com 473*1591Smax.romanov@nginx.com static void 474*1591Smax.romanov@nginx.com nxt_python_request_handler(nxt_unit_request_info_t *req) 475*1591Smax.romanov@nginx.com { 476*1591Smax.romanov@nginx.com int rc; 477*1591Smax.romanov@nginx.com PyObject *environ, *args, *response, *iterator, *item; 478*1591Smax.romanov@nginx.com PyObject *close, *result; 479*1591Smax.romanov@nginx.com nxt_python_run_ctx_t run_ctx = {-1, 0, NULL, req}; 480*1591Smax.romanov@nginx.com 481*1591Smax.romanov@nginx.com PyEval_RestoreThread(nxt_python_thread_state); 482*1591Smax.romanov@nginx.com 483*1591Smax.romanov@nginx.com environ = nxt_python_get_environ(&run_ctx); 484*1591Smax.romanov@nginx.com if (nxt_slow_path(environ == NULL)) { 485*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 486*1591Smax.romanov@nginx.com goto done; 487*1591Smax.romanov@nginx.com } 488*1591Smax.romanov@nginx.com 489*1591Smax.romanov@nginx.com args = PyTuple_New(2); 490*1591Smax.romanov@nginx.com if (nxt_slow_path(args == NULL)) { 491*1591Smax.romanov@nginx.com Py_DECREF(environ); 492*1591Smax.romanov@nginx.com 493*1591Smax.romanov@nginx.com nxt_unit_req_error(req, "Python failed to create arguments tuple"); 494*1591Smax.romanov@nginx.com 495*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 496*1591Smax.romanov@nginx.com goto done; 497*1591Smax.romanov@nginx.com } 498*1591Smax.romanov@nginx.com 499*1591Smax.romanov@nginx.com PyTuple_SET_ITEM(args, 0, environ); 500*1591Smax.romanov@nginx.com 501*1591Smax.romanov@nginx.com Py_INCREF(nxt_py_start_resp_obj); 502*1591Smax.romanov@nginx.com PyTuple_SET_ITEM(args, 1, nxt_py_start_resp_obj); 503*1591Smax.romanov@nginx.com 504*1591Smax.romanov@nginx.com nxt_python_run_ctx = &run_ctx; 505*1591Smax.romanov@nginx.com 506*1591Smax.romanov@nginx.com response = PyObject_CallObject(nxt_py_application, args); 507*1591Smax.romanov@nginx.com 508*1591Smax.romanov@nginx.com Py_DECREF(args); 509*1591Smax.romanov@nginx.com 510*1591Smax.romanov@nginx.com if (nxt_slow_path(response == NULL)) { 511*1591Smax.romanov@nginx.com nxt_unit_req_error(req, "Python failed to call the application"); 512*1591Smax.romanov@nginx.com nxt_python_print_exception(); 513*1591Smax.romanov@nginx.com 514*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 515*1591Smax.romanov@nginx.com goto done; 516*1591Smax.romanov@nginx.com } 517*1591Smax.romanov@nginx.com 518*1591Smax.romanov@nginx.com /* Shortcut: avoid iterate over response string symbols. */ 519*1591Smax.romanov@nginx.com if (PyBytes_Check(response)) { 520*1591Smax.romanov@nginx.com rc = nxt_python_write(&run_ctx, response); 521*1591Smax.romanov@nginx.com 522*1591Smax.romanov@nginx.com } else { 523*1591Smax.romanov@nginx.com iterator = PyObject_GetIter(response); 524*1591Smax.romanov@nginx.com 525*1591Smax.romanov@nginx.com if (nxt_fast_path(iterator != NULL)) { 526*1591Smax.romanov@nginx.com rc = NXT_UNIT_OK; 527*1591Smax.romanov@nginx.com 528*1591Smax.romanov@nginx.com while (run_ctx.bytes_sent < run_ctx.content_length) { 529*1591Smax.romanov@nginx.com item = PyIter_Next(iterator); 530*1591Smax.romanov@nginx.com 531*1591Smax.romanov@nginx.com if (item == NULL) { 532*1591Smax.romanov@nginx.com if (nxt_slow_path(PyErr_Occurred() != NULL)) { 533*1591Smax.romanov@nginx.com nxt_unit_req_error(req, "Python failed to iterate over " 534*1591Smax.romanov@nginx.com "the application response object"); 535*1591Smax.romanov@nginx.com nxt_python_print_exception(); 536*1591Smax.romanov@nginx.com 537*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 538*1591Smax.romanov@nginx.com } 539*1591Smax.romanov@nginx.com 540*1591Smax.romanov@nginx.com break; 541*1591Smax.romanov@nginx.com } 542*1591Smax.romanov@nginx.com 543*1591Smax.romanov@nginx.com if (nxt_fast_path(PyBytes_Check(item))) { 544*1591Smax.romanov@nginx.com rc = nxt_python_write(&run_ctx, item); 545*1591Smax.romanov@nginx.com 546*1591Smax.romanov@nginx.com } else { 547*1591Smax.romanov@nginx.com nxt_unit_req_error(req, "the application returned " 548*1591Smax.romanov@nginx.com "not a bytestring object"); 549*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 550*1591Smax.romanov@nginx.com } 551*1591Smax.romanov@nginx.com 552*1591Smax.romanov@nginx.com Py_DECREF(item); 553*1591Smax.romanov@nginx.com 554*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 555*1591Smax.romanov@nginx.com break; 556*1591Smax.romanov@nginx.com } 557*1591Smax.romanov@nginx.com } 558*1591Smax.romanov@nginx.com 559*1591Smax.romanov@nginx.com Py_DECREF(iterator); 560*1591Smax.romanov@nginx.com 561*1591Smax.romanov@nginx.com } else { 562*1591Smax.romanov@nginx.com nxt_unit_req_error(req, 563*1591Smax.romanov@nginx.com "the application returned not an iterable object"); 564*1591Smax.romanov@nginx.com nxt_python_print_exception(); 565*1591Smax.romanov@nginx.com 566*1591Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 567*1591Smax.romanov@nginx.com } 568*1591Smax.romanov@nginx.com 569*1591Smax.romanov@nginx.com close = PyObject_GetAttr(response, nxt_py_close_str); 570*1591Smax.romanov@nginx.com 571*1591Smax.romanov@nginx.com if (close != NULL) { 572*1591Smax.romanov@nginx.com result = PyObject_CallFunction(close, NULL); 573*1591Smax.romanov@nginx.com if (nxt_slow_path(result == NULL)) { 574*1591Smax.romanov@nginx.com nxt_unit_req_error(req, "Python failed to call the close() " 575*1591Smax.romanov@nginx.com "method of the application response"); 576*1591Smax.romanov@nginx.com nxt_python_print_exception(); 577*1591Smax.romanov@nginx.com 578*1591Smax.romanov@nginx.com } else { 579*1591Smax.romanov@nginx.com Py_DECREF(result); 580*1591Smax.romanov@nginx.com } 581*1591Smax.romanov@nginx.com 582*1591Smax.romanov@nginx.com Py_DECREF(close); 583*1591Smax.romanov@nginx.com 584*1591Smax.romanov@nginx.com } else { 585*1591Smax.romanov@nginx.com PyErr_Clear(); 586*1591Smax.romanov@nginx.com } 587*1591Smax.romanov@nginx.com } 588*1591Smax.romanov@nginx.com 589*1591Smax.romanov@nginx.com Py_DECREF(response); 590*1591Smax.romanov@nginx.com 591*1591Smax.romanov@nginx.com done: 592*1591Smax.romanov@nginx.com 593*1591Smax.romanov@nginx.com nxt_python_thread_state = PyEval_SaveThread(); 594*1591Smax.romanov@nginx.com 595*1591Smax.romanov@nginx.com nxt_python_run_ctx = NULL; 596*1591Smax.romanov@nginx.com nxt_unit_request_done(req, rc); 597*1591Smax.romanov@nginx.com } 598*1591Smax.romanov@nginx.com 599*1591Smax.romanov@nginx.com 600*1591Smax.romanov@nginx.com static void 601*1591Smax.romanov@nginx.com nxt_python_atexit(void) 602*1591Smax.romanov@nginx.com { 603*1591Smax.romanov@nginx.com nxt_uint_t i; 604*1591Smax.romanov@nginx.com 605*1591Smax.romanov@nginx.com for (i = 0; i < nxt_nitems(nxt_python_strings); i++) { 606*1591Smax.romanov@nginx.com Py_XDECREF(*nxt_python_strings[i].object_p); 607*1591Smax.romanov@nginx.com } 608*1591Smax.romanov@nginx.com 609*1591Smax.romanov@nginx.com Py_XDECREF(nxt_py_stderr_flush); 610*1591Smax.romanov@nginx.com Py_XDECREF(nxt_py_application); 611*1591Smax.romanov@nginx.com Py_XDECREF(nxt_py_start_resp_obj); 612*1591Smax.romanov@nginx.com Py_XDECREF(nxt_py_write_obj); 613*1591Smax.romanov@nginx.com Py_XDECREF(nxt_py_environ_ptyp); 614*1591Smax.romanov@nginx.com 615*1591Smax.romanov@nginx.com Py_Finalize(); 616*1591Smax.romanov@nginx.com 617*1591Smax.romanov@nginx.com if (nxt_py_home != NULL) { 618*1591Smax.romanov@nginx.com nxt_free(nxt_py_home); 619*1591Smax.romanov@nginx.com } 620*1591Smax.romanov@nginx.com } 621*1591Smax.romanov@nginx.com 622*1591Smax.romanov@nginx.com 623*1591Smax.romanov@nginx.com static PyObject * 624*1591Smax.romanov@nginx.com nxt_python_create_environ(nxt_task_t *task) 625*1591Smax.romanov@nginx.com { 626*1591Smax.romanov@nginx.com PyObject *obj, *err, *environ; 627*1591Smax.romanov@nginx.com 628*1591Smax.romanov@nginx.com environ = PyDict_New(); 629*1591Smax.romanov@nginx.com 630*1591Smax.romanov@nginx.com if (nxt_slow_path(environ == NULL)) { 631*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to create the \"environ\" dictionary"); 632*1591Smax.romanov@nginx.com return NULL; 633*1591Smax.romanov@nginx.com } 634*1591Smax.romanov@nginx.com 635*1591Smax.romanov@nginx.com obj = PyString_FromStringAndSize((char *) nxt_server.start, 636*1591Smax.romanov@nginx.com nxt_server.length); 637*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 638*1591Smax.romanov@nginx.com nxt_alert(task, 639*1591Smax.romanov@nginx.com "Python failed to create the \"SERVER_SOFTWARE\" environ value"); 640*1591Smax.romanov@nginx.com goto fail; 641*1591Smax.romanov@nginx.com } 642*1591Smax.romanov@nginx.com 643*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "SERVER_SOFTWARE", obj) 644*1591Smax.romanov@nginx.com != 0)) 645*1591Smax.romanov@nginx.com { 646*1591Smax.romanov@nginx.com nxt_alert(task, 647*1591Smax.romanov@nginx.com "Python failed to set the \"SERVER_SOFTWARE\" environ value"); 648*1591Smax.romanov@nginx.com goto fail; 649*1591Smax.romanov@nginx.com } 650*1591Smax.romanov@nginx.com 651*1591Smax.romanov@nginx.com Py_DECREF(obj); 652*1591Smax.romanov@nginx.com 653*1591Smax.romanov@nginx.com obj = Py_BuildValue("(ii)", 1, 0); 654*1591Smax.romanov@nginx.com 655*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 656*1591Smax.romanov@nginx.com nxt_alert(task, 657*1591Smax.romanov@nginx.com "Python failed to build the \"wsgi.version\" environ value"); 658*1591Smax.romanov@nginx.com goto fail; 659*1591Smax.romanov@nginx.com } 660*1591Smax.romanov@nginx.com 661*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.version", obj) != 0)) 662*1591Smax.romanov@nginx.com { 663*1591Smax.romanov@nginx.com nxt_alert(task, 664*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.version\" environ value"); 665*1591Smax.romanov@nginx.com goto fail; 666*1591Smax.romanov@nginx.com } 667*1591Smax.romanov@nginx.com 668*1591Smax.romanov@nginx.com Py_DECREF(obj); 669*1591Smax.romanov@nginx.com obj = NULL; 670*1591Smax.romanov@nginx.com 671*1591Smax.romanov@nginx.com 672*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multithread", 673*1591Smax.romanov@nginx.com Py_False) 674*1591Smax.romanov@nginx.com != 0)) 675*1591Smax.romanov@nginx.com { 676*1591Smax.romanov@nginx.com nxt_alert(task, 677*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.multithread\" environ value"); 678*1591Smax.romanov@nginx.com goto fail; 679*1591Smax.romanov@nginx.com } 680*1591Smax.romanov@nginx.com 681*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.multiprocess", 682*1591Smax.romanov@nginx.com Py_True) 683*1591Smax.romanov@nginx.com != 0)) 684*1591Smax.romanov@nginx.com { 685*1591Smax.romanov@nginx.com nxt_alert(task, 686*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.multiprocess\" environ value"); 687*1591Smax.romanov@nginx.com goto fail; 688*1591Smax.romanov@nginx.com } 689*1591Smax.romanov@nginx.com 690*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.run_once", 691*1591Smax.romanov@nginx.com Py_False) 692*1591Smax.romanov@nginx.com != 0)) 693*1591Smax.romanov@nginx.com { 694*1591Smax.romanov@nginx.com nxt_alert(task, 695*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.run_once\" environ value"); 696*1591Smax.romanov@nginx.com goto fail; 697*1591Smax.romanov@nginx.com } 698*1591Smax.romanov@nginx.com 699*1591Smax.romanov@nginx.com 700*1591Smax.romanov@nginx.com if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) { 701*1591Smax.romanov@nginx.com nxt_alert(task, 702*1591Smax.romanov@nginx.com "Python failed to initialize the \"wsgi.input\" type object"); 703*1591Smax.romanov@nginx.com goto fail; 704*1591Smax.romanov@nginx.com } 705*1591Smax.romanov@nginx.com 706*1591Smax.romanov@nginx.com obj = (PyObject *) PyObject_New(nxt_py_input_t, &nxt_py_input_type); 707*1591Smax.romanov@nginx.com 708*1591Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) { 709*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to create the \"wsgi.input\" object"); 710*1591Smax.romanov@nginx.com goto fail; 711*1591Smax.romanov@nginx.com } 712*1591Smax.romanov@nginx.com 713*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.input", obj) != 0)) { 714*1591Smax.romanov@nginx.com nxt_alert(task, 715*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.input\" environ value"); 716*1591Smax.romanov@nginx.com goto fail; 717*1591Smax.romanov@nginx.com } 718*1591Smax.romanov@nginx.com 719*1591Smax.romanov@nginx.com Py_DECREF(obj); 720*1591Smax.romanov@nginx.com obj = NULL; 721*1591Smax.romanov@nginx.com 722*1591Smax.romanov@nginx.com 723*1591Smax.romanov@nginx.com err = PySys_GetObject((char *) "stderr"); 724*1591Smax.romanov@nginx.com 725*1591Smax.romanov@nginx.com if (nxt_slow_path(err == NULL)) { 726*1591Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"sys.stderr\" object"); 727*1591Smax.romanov@nginx.com goto fail; 728*1591Smax.romanov@nginx.com } 729*1591Smax.romanov@nginx.com 730*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.errors", err) != 0)) 731*1591Smax.romanov@nginx.com { 732*1591Smax.romanov@nginx.com nxt_alert(task, 733*1591Smax.romanov@nginx.com "Python failed to set the \"wsgi.errors\" environ value"); 734*1591Smax.romanov@nginx.com goto fail; 735*1591Smax.romanov@nginx.com } 736*1591Smax.romanov@nginx.com 737*1591Smax.romanov@nginx.com return environ; 738*1591Smax.romanov@nginx.com 739*1591Smax.romanov@nginx.com fail: 740*1591Smax.romanov@nginx.com 741*1591Smax.romanov@nginx.com Py_XDECREF(obj); 742*1591Smax.romanov@nginx.com Py_DECREF(environ); 743*1591Smax.romanov@nginx.com 744*1591Smax.romanov@nginx.com return NULL; 745*1591Smax.romanov@nginx.com } 746*1591Smax.romanov@nginx.com 747*1591Smax.romanov@nginx.com 748*1591Smax.romanov@nginx.com static PyObject * 749*1591Smax.romanov@nginx.com nxt_python_get_environ(nxt_python_run_ctx_t *ctx) 750*1591Smax.romanov@nginx.com { 751*1591Smax.romanov@nginx.com int rc; 752*1591Smax.romanov@nginx.com uint32_t i; 753*1591Smax.romanov@nginx.com PyObject *environ; 754*1591Smax.romanov@nginx.com nxt_unit_field_t *f; 755*1591Smax.romanov@nginx.com nxt_unit_request_t *r; 756*1591Smax.romanov@nginx.com 757*1591Smax.romanov@nginx.com environ = PyDict_Copy(nxt_py_environ_ptyp); 758*1591Smax.romanov@nginx.com if (nxt_slow_path(environ == NULL)) { 759*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 760*1591Smax.romanov@nginx.com "Python failed to copy the \"environ\" dictionary"); 761*1591Smax.romanov@nginx.com 762*1591Smax.romanov@nginx.com return NULL; 763*1591Smax.romanov@nginx.com } 764*1591Smax.romanov@nginx.com 765*1591Smax.romanov@nginx.com ctx->environ = environ; 766*1591Smax.romanov@nginx.com 767*1591Smax.romanov@nginx.com r = ctx->req->request; 768*1591Smax.romanov@nginx.com 769*1591Smax.romanov@nginx.com #define RC(S) \ 770*1591Smax.romanov@nginx.com do { \ 771*1591Smax.romanov@nginx.com rc = (S); \ 772*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { \ 773*1591Smax.romanov@nginx.com goto fail; \ 774*1591Smax.romanov@nginx.com } \ 775*1591Smax.romanov@nginx.com } while(0) 776*1591Smax.romanov@nginx.com 777*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_request_method_str, &r->method, 778*1591Smax.romanov@nginx.com r->method_length)); 779*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_request_uri_str, &r->target, 780*1591Smax.romanov@nginx.com r->target_length)); 781*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_query_string_str, &r->query, 782*1591Smax.romanov@nginx.com r->query_length)); 783*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_path_info_str, &r->path, 784*1591Smax.romanov@nginx.com r->path_length)); 785*1591Smax.romanov@nginx.com 786*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_remote_addr_str, &r->remote, 787*1591Smax.romanov@nginx.com r->remote_length)); 788*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_server_addr_str, &r->local, 789*1591Smax.romanov@nginx.com r->local_length)); 790*1591Smax.romanov@nginx.com 791*1591Smax.romanov@nginx.com if (r->tls) { 792*1591Smax.romanov@nginx.com RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str, 793*1591Smax.romanov@nginx.com nxt_py_https_str)); 794*1591Smax.romanov@nginx.com } else { 795*1591Smax.romanov@nginx.com RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str, 796*1591Smax.romanov@nginx.com nxt_py_http_str)); 797*1591Smax.romanov@nginx.com } 798*1591Smax.romanov@nginx.com 799*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_server_protocol_str, &r->version, 800*1591Smax.romanov@nginx.com r->version_length)); 801*1591Smax.romanov@nginx.com 802*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_server_name_str, &r->server_name, 803*1591Smax.romanov@nginx.com r->server_name_length)); 804*1591Smax.romanov@nginx.com RC(nxt_python_add_obj(ctx, nxt_py_server_port_str, nxt_py_80_str)); 805*1591Smax.romanov@nginx.com 806*1591Smax.romanov@nginx.com for (i = 0; i < r->fields_count; i++) { 807*1591Smax.romanov@nginx.com f = r->fields + i; 808*1591Smax.romanov@nginx.com 809*1591Smax.romanov@nginx.com RC(nxt_python_add_field(ctx, f)); 810*1591Smax.romanov@nginx.com } 811*1591Smax.romanov@nginx.com 812*1591Smax.romanov@nginx.com if (r->content_length_field != NXT_UNIT_NONE_FIELD) { 813*1591Smax.romanov@nginx.com f = r->fields + r->content_length_field; 814*1591Smax.romanov@nginx.com 815*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_content_length_str, &f->value, 816*1591Smax.romanov@nginx.com f->value_length)); 817*1591Smax.romanov@nginx.com } 818*1591Smax.romanov@nginx.com 819*1591Smax.romanov@nginx.com if (r->content_type_field != NXT_UNIT_NONE_FIELD) { 820*1591Smax.romanov@nginx.com f = r->fields + r->content_type_field; 821*1591Smax.romanov@nginx.com 822*1591Smax.romanov@nginx.com RC(nxt_python_add_sptr(ctx, nxt_py_content_type_str, &f->value, 823*1591Smax.romanov@nginx.com f->value_length)); 824*1591Smax.romanov@nginx.com } 825*1591Smax.romanov@nginx.com 826*1591Smax.romanov@nginx.com #undef RC 827*1591Smax.romanov@nginx.com 828*1591Smax.romanov@nginx.com return environ; 829*1591Smax.romanov@nginx.com 830*1591Smax.romanov@nginx.com fail: 831*1591Smax.romanov@nginx.com 832*1591Smax.romanov@nginx.com Py_DECREF(environ); 833*1591Smax.romanov@nginx.com 834*1591Smax.romanov@nginx.com return NULL; 835*1591Smax.romanov@nginx.com } 836*1591Smax.romanov@nginx.com 837*1591Smax.romanov@nginx.com 838*1591Smax.romanov@nginx.com static int 839*1591Smax.romanov@nginx.com nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name, 840*1591Smax.romanov@nginx.com nxt_unit_sptr_t *sptr, uint32_t size) 841*1591Smax.romanov@nginx.com { 842*1591Smax.romanov@nginx.com char *src; 843*1591Smax.romanov@nginx.com PyObject *value; 844*1591Smax.romanov@nginx.com 845*1591Smax.romanov@nginx.com src = nxt_unit_sptr_get(sptr); 846*1591Smax.romanov@nginx.com 847*1591Smax.romanov@nginx.com value = PyString_FromStringAndSize(src, size); 848*1591Smax.romanov@nginx.com if (nxt_slow_path(value == NULL)) { 849*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 850*1591Smax.romanov@nginx.com "Python failed to create value string \"%.*s\"", 851*1591Smax.romanov@nginx.com (int) size, src); 852*1591Smax.romanov@nginx.com nxt_python_print_exception(); 853*1591Smax.romanov@nginx.com 854*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 855*1591Smax.romanov@nginx.com } 856*1591Smax.romanov@nginx.com 857*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) { 858*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 859*1591Smax.romanov@nginx.com "Python failed to set the \"%s\" environ value", 860*1591Smax.romanov@nginx.com PyUnicode_AsUTF8(name)); 861*1591Smax.romanov@nginx.com Py_DECREF(value); 862*1591Smax.romanov@nginx.com 863*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 864*1591Smax.romanov@nginx.com } 865*1591Smax.romanov@nginx.com 866*1591Smax.romanov@nginx.com Py_DECREF(value); 867*1591Smax.romanov@nginx.com 868*1591Smax.romanov@nginx.com return NXT_UNIT_OK; 869*1591Smax.romanov@nginx.com } 870*1591Smax.romanov@nginx.com 871*1591Smax.romanov@nginx.com 872*1591Smax.romanov@nginx.com static int 873*1591Smax.romanov@nginx.com nxt_python_add_field(nxt_python_run_ctx_t *ctx, nxt_unit_field_t *field) 874*1591Smax.romanov@nginx.com { 875*1591Smax.romanov@nginx.com char *src; 876*1591Smax.romanov@nginx.com PyObject *name, *value; 877*1591Smax.romanov@nginx.com 878*1591Smax.romanov@nginx.com src = nxt_unit_sptr_get(&field->name); 879*1591Smax.romanov@nginx.com 880*1591Smax.romanov@nginx.com name = PyString_FromStringAndSize(src, field->name_length); 881*1591Smax.romanov@nginx.com if (nxt_slow_path(name == NULL)) { 882*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 883*1591Smax.romanov@nginx.com "Python failed to create name string \"%.*s\"", 884*1591Smax.romanov@nginx.com (int) field->name_length, src); 885*1591Smax.romanov@nginx.com nxt_python_print_exception(); 886*1591Smax.romanov@nginx.com 887*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 888*1591Smax.romanov@nginx.com } 889*1591Smax.romanov@nginx.com 890*1591Smax.romanov@nginx.com src = nxt_unit_sptr_get(&field->value); 891*1591Smax.romanov@nginx.com 892*1591Smax.romanov@nginx.com value = PyString_FromStringAndSize(src, field->value_length); 893*1591Smax.romanov@nginx.com if (nxt_slow_path(value == NULL)) { 894*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 895*1591Smax.romanov@nginx.com "Python failed to create value string \"%.*s\"", 896*1591Smax.romanov@nginx.com (int) field->value_length, src); 897*1591Smax.romanov@nginx.com nxt_python_print_exception(); 898*1591Smax.romanov@nginx.com 899*1591Smax.romanov@nginx.com goto fail; 900*1591Smax.romanov@nginx.com } 901*1591Smax.romanov@nginx.com 902*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) { 903*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 904*1591Smax.romanov@nginx.com "Python failed to set the \"%s\" environ value", 905*1591Smax.romanov@nginx.com PyUnicode_AsUTF8(name)); 906*1591Smax.romanov@nginx.com goto fail; 907*1591Smax.romanov@nginx.com } 908*1591Smax.romanov@nginx.com 909*1591Smax.romanov@nginx.com Py_DECREF(name); 910*1591Smax.romanov@nginx.com Py_DECREF(value); 911*1591Smax.romanov@nginx.com 912*1591Smax.romanov@nginx.com return NXT_UNIT_OK; 913*1591Smax.romanov@nginx.com 914*1591Smax.romanov@nginx.com fail: 915*1591Smax.romanov@nginx.com 916*1591Smax.romanov@nginx.com Py_DECREF(name); 917*1591Smax.romanov@nginx.com Py_XDECREF(value); 918*1591Smax.romanov@nginx.com 919*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 920*1591Smax.romanov@nginx.com } 921*1591Smax.romanov@nginx.com 922*1591Smax.romanov@nginx.com 923*1591Smax.romanov@nginx.com static int 924*1591Smax.romanov@nginx.com nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name, PyObject *value) 925*1591Smax.romanov@nginx.com { 926*1591Smax.romanov@nginx.com if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) { 927*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, 928*1591Smax.romanov@nginx.com "Python failed to set the \"%s\" environ value", 929*1591Smax.romanov@nginx.com PyUnicode_AsUTF8(name)); 930*1591Smax.romanov@nginx.com 931*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 932*1591Smax.romanov@nginx.com } 933*1591Smax.romanov@nginx.com 934*1591Smax.romanov@nginx.com return NXT_UNIT_OK; 935*1591Smax.romanov@nginx.com } 936*1591Smax.romanov@nginx.com 937*1591Smax.romanov@nginx.com 938*1591Smax.romanov@nginx.com static PyObject * 939*1591Smax.romanov@nginx.com nxt_py_start_resp(PyObject *self, PyObject *args) 940*1591Smax.romanov@nginx.com { 941*1591Smax.romanov@nginx.com int rc, status; 942*1591Smax.romanov@nginx.com char *status_str, *space_ptr; 943*1591Smax.romanov@nginx.com uint32_t status_len; 944*1591Smax.romanov@nginx.com PyObject *headers, *tuple, *string, *status_bytes; 945*1591Smax.romanov@nginx.com Py_ssize_t i, n, fields_size, fields_count; 946*1591Smax.romanov@nginx.com nxt_python_run_ctx_t *ctx; 947*1591Smax.romanov@nginx.com 948*1591Smax.romanov@nginx.com ctx = nxt_python_run_ctx; 949*1591Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 950*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 951*1591Smax.romanov@nginx.com "start_response() is called " 952*1591Smax.romanov@nginx.com "outside of WSGI request processing"); 953*1591Smax.romanov@nginx.com } 954*1591Smax.romanov@nginx.com 955*1591Smax.romanov@nginx.com n = PyTuple_GET_SIZE(args); 956*1591Smax.romanov@nginx.com 957*1591Smax.romanov@nginx.com if (n < 2 || n > 3) { 958*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); 959*1591Smax.romanov@nginx.com } 960*1591Smax.romanov@nginx.com 961*1591Smax.romanov@nginx.com string = PyTuple_GET_ITEM(args, 0); 962*1591Smax.romanov@nginx.com if (!PyBytes_Check(string) && !PyUnicode_Check(string)) { 963*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 964*1591Smax.romanov@nginx.com "failed to write first argument (not a string?)"); 965*1591Smax.romanov@nginx.com } 966*1591Smax.romanov@nginx.com 967*1591Smax.romanov@nginx.com headers = PyTuple_GET_ITEM(args, 1); 968*1591Smax.romanov@nginx.com if (!PyList_Check(headers)) { 969*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 970*1591Smax.romanov@nginx.com "the second argument is not a response headers list"); 971*1591Smax.romanov@nginx.com } 972*1591Smax.romanov@nginx.com 973*1591Smax.romanov@nginx.com fields_size = 0; 974*1591Smax.romanov@nginx.com fields_count = PyList_GET_SIZE(headers); 975*1591Smax.romanov@nginx.com 976*1591Smax.romanov@nginx.com for (i = 0; i < fields_count; i++) { 977*1591Smax.romanov@nginx.com tuple = PyList_GET_ITEM(headers, i); 978*1591Smax.romanov@nginx.com 979*1591Smax.romanov@nginx.com if (!PyTuple_Check(tuple)) { 980*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 981*1591Smax.romanov@nginx.com "the response headers must be a list of tuples"); 982*1591Smax.romanov@nginx.com } 983*1591Smax.romanov@nginx.com 984*1591Smax.romanov@nginx.com if (PyTuple_GET_SIZE(tuple) != 2) { 985*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 986*1591Smax.romanov@nginx.com "each header must be a tuple of two items"); 987*1591Smax.romanov@nginx.com } 988*1591Smax.romanov@nginx.com 989*1591Smax.romanov@nginx.com string = PyTuple_GET_ITEM(tuple, 0); 990*1591Smax.romanov@nginx.com if (PyBytes_Check(string)) { 991*1591Smax.romanov@nginx.com fields_size += PyBytes_GET_SIZE(string); 992*1591Smax.romanov@nginx.com 993*1591Smax.romanov@nginx.com } else if (PyUnicode_Check(string)) { 994*1591Smax.romanov@nginx.com fields_size += PyUnicode_GET_SIZE(string); 995*1591Smax.romanov@nginx.com 996*1591Smax.romanov@nginx.com } else { 997*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 998*1591Smax.romanov@nginx.com "header #%d name is not a string", (int) i); 999*1591Smax.romanov@nginx.com } 1000*1591Smax.romanov@nginx.com 1001*1591Smax.romanov@nginx.com string = PyTuple_GET_ITEM(tuple, 1); 1002*1591Smax.romanov@nginx.com if (PyBytes_Check(string)) { 1003*1591Smax.romanov@nginx.com fields_size += PyBytes_GET_SIZE(string); 1004*1591Smax.romanov@nginx.com 1005*1591Smax.romanov@nginx.com } else if (PyUnicode_Check(string)) { 1006*1591Smax.romanov@nginx.com fields_size += PyUnicode_GET_SIZE(string); 1007*1591Smax.romanov@nginx.com 1008*1591Smax.romanov@nginx.com } else { 1009*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, 1010*1591Smax.romanov@nginx.com "header #%d value is not a string", (int) i); 1011*1591Smax.romanov@nginx.com } 1012*1591Smax.romanov@nginx.com } 1013*1591Smax.romanov@nginx.com 1014*1591Smax.romanov@nginx.com ctx->content_length = -1; 1015*1591Smax.romanov@nginx.com 1016*1591Smax.romanov@nginx.com string = PyTuple_GET_ITEM(args, 0); 1017*1591Smax.romanov@nginx.com rc = nxt_python_str_buf(string, &status_str, &status_len, &status_bytes); 1018*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1019*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "status is not a string"); 1020*1591Smax.romanov@nginx.com } 1021*1591Smax.romanov@nginx.com 1022*1591Smax.romanov@nginx.com space_ptr = memchr(status_str, ' ', status_len); 1023*1591Smax.romanov@nginx.com if (space_ptr != NULL) { 1024*1591Smax.romanov@nginx.com status_len = space_ptr - status_str; 1025*1591Smax.romanov@nginx.com } 1026*1591Smax.romanov@nginx.com 1027*1591Smax.romanov@nginx.com status = nxt_int_parse((u_char *) status_str, status_len); 1028*1591Smax.romanov@nginx.com if (nxt_slow_path(status < 0)) { 1029*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "failed to parse status code"); 1030*1591Smax.romanov@nginx.com } 1031*1591Smax.romanov@nginx.com 1032*1591Smax.romanov@nginx.com Py_XDECREF(status_bytes); 1033*1591Smax.romanov@nginx.com 1034*1591Smax.romanov@nginx.com /* 1035*1591Smax.romanov@nginx.com * PEP 3333: 1036*1591Smax.romanov@nginx.com * 1037*1591Smax.romanov@nginx.com * ... applications can replace their originally intended output with error 1038*1591Smax.romanov@nginx.com * output, up until the last possible moment. 1039*1591Smax.romanov@nginx.com */ 1040*1591Smax.romanov@nginx.com rc = nxt_unit_response_init(ctx->req, status, fields_count, fields_size); 1041*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1042*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1043*1591Smax.romanov@nginx.com "failed to allocate response object"); 1044*1591Smax.romanov@nginx.com } 1045*1591Smax.romanov@nginx.com 1046*1591Smax.romanov@nginx.com for (i = 0; i < fields_count; i++) { 1047*1591Smax.romanov@nginx.com tuple = PyList_GET_ITEM(headers, i); 1048*1591Smax.romanov@nginx.com 1049*1591Smax.romanov@nginx.com rc = nxt_python_response_add_field(ctx, PyTuple_GET_ITEM(tuple, 0), 1050*1591Smax.romanov@nginx.com PyTuple_GET_ITEM(tuple, 1), i); 1051*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1052*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1053*1591Smax.romanov@nginx.com "failed to add header #%d", (int) i); 1054*1591Smax.romanov@nginx.com } 1055*1591Smax.romanov@nginx.com } 1056*1591Smax.romanov@nginx.com 1057*1591Smax.romanov@nginx.com /* 1058*1591Smax.romanov@nginx.com * PEP 3333: 1059*1591Smax.romanov@nginx.com * 1060*1591Smax.romanov@nginx.com * However, the start_response callable must not actually transmit the 1061*1591Smax.romanov@nginx.com * response headers. Instead, it must store them for the server or gateway 1062*1591Smax.romanov@nginx.com * to transmit only after the first iteration of the application return 1063*1591Smax.romanov@nginx.com * value that yields a non-empty bytestring, or upon the application's 1064*1591Smax.romanov@nginx.com * first invocation of the write() callable. In other words, response 1065*1591Smax.romanov@nginx.com * headers must not be sent until there is actual body data available, or 1066*1591Smax.romanov@nginx.com * until the application's returned iterable is exhausted. (The only 1067*1591Smax.romanov@nginx.com * possible exception to this rule is if the response headers explicitly 1068*1591Smax.romanov@nginx.com * include a Content-Length of zero.) 1069*1591Smax.romanov@nginx.com */ 1070*1591Smax.romanov@nginx.com if (ctx->content_length == 0) { 1071*1591Smax.romanov@nginx.com rc = nxt_unit_response_send(ctx->req); 1072*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1073*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1074*1591Smax.romanov@nginx.com "failed to send response headers"); 1075*1591Smax.romanov@nginx.com } 1076*1591Smax.romanov@nginx.com } 1077*1591Smax.romanov@nginx.com 1078*1591Smax.romanov@nginx.com Py_INCREF(nxt_py_write_obj); 1079*1591Smax.romanov@nginx.com return nxt_py_write_obj; 1080*1591Smax.romanov@nginx.com } 1081*1591Smax.romanov@nginx.com 1082*1591Smax.romanov@nginx.com 1083*1591Smax.romanov@nginx.com static int 1084*1591Smax.romanov@nginx.com nxt_python_response_add_field(nxt_python_run_ctx_t *ctx, PyObject *name, 1085*1591Smax.romanov@nginx.com PyObject *value, int i) 1086*1591Smax.romanov@nginx.com { 1087*1591Smax.romanov@nginx.com int rc; 1088*1591Smax.romanov@nginx.com char *name_str, *value_str; 1089*1591Smax.romanov@nginx.com uint32_t name_length, value_length; 1090*1591Smax.romanov@nginx.com PyObject *name_bytes, *value_bytes; 1091*1591Smax.romanov@nginx.com nxt_off_t content_length; 1092*1591Smax.romanov@nginx.com 1093*1591Smax.romanov@nginx.com name_bytes = NULL; 1094*1591Smax.romanov@nginx.com value_bytes = NULL; 1095*1591Smax.romanov@nginx.com 1096*1591Smax.romanov@nginx.com rc = nxt_python_str_buf(name, &name_str, &name_length, &name_bytes); 1097*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1098*1591Smax.romanov@nginx.com goto fail; 1099*1591Smax.romanov@nginx.com } 1100*1591Smax.romanov@nginx.com 1101*1591Smax.romanov@nginx.com rc = nxt_python_str_buf(value, &value_str, &value_length, &value_bytes); 1102*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1103*1591Smax.romanov@nginx.com goto fail; 1104*1591Smax.romanov@nginx.com } 1105*1591Smax.romanov@nginx.com 1106*1591Smax.romanov@nginx.com rc = nxt_unit_response_add_field(ctx->req, name_str, name_length, 1107*1591Smax.romanov@nginx.com value_str, value_length); 1108*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1109*1591Smax.romanov@nginx.com goto fail; 1110*1591Smax.romanov@nginx.com } 1111*1591Smax.romanov@nginx.com 1112*1591Smax.romanov@nginx.com if (ctx->req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) { 1113*1591Smax.romanov@nginx.com content_length = nxt_off_t_parse((u_char *) value_str, value_length); 1114*1591Smax.romanov@nginx.com if (nxt_slow_path(content_length < 0)) { 1115*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, "failed to parse Content-Length " 1116*1591Smax.romanov@nginx.com "value %.*s", (int) value_length, value_str); 1117*1591Smax.romanov@nginx.com 1118*1591Smax.romanov@nginx.com } else { 1119*1591Smax.romanov@nginx.com ctx->content_length = content_length; 1120*1591Smax.romanov@nginx.com } 1121*1591Smax.romanov@nginx.com } 1122*1591Smax.romanov@nginx.com 1123*1591Smax.romanov@nginx.com fail: 1124*1591Smax.romanov@nginx.com 1125*1591Smax.romanov@nginx.com Py_XDECREF(name_bytes); 1126*1591Smax.romanov@nginx.com Py_XDECREF(value_bytes); 1127*1591Smax.romanov@nginx.com 1128*1591Smax.romanov@nginx.com return rc; 1129*1591Smax.romanov@nginx.com } 1130*1591Smax.romanov@nginx.com 1131*1591Smax.romanov@nginx.com 1132*1591Smax.romanov@nginx.com static int 1133*1591Smax.romanov@nginx.com nxt_python_str_buf(PyObject *str, char **buf, uint32_t *len, PyObject **bytes) 1134*1591Smax.romanov@nginx.com { 1135*1591Smax.romanov@nginx.com if (PyBytes_Check(str)) { 1136*1591Smax.romanov@nginx.com *buf = PyBytes_AS_STRING(str); 1137*1591Smax.romanov@nginx.com *len = PyBytes_GET_SIZE(str); 1138*1591Smax.romanov@nginx.com *bytes = NULL; 1139*1591Smax.romanov@nginx.com 1140*1591Smax.romanov@nginx.com } else { 1141*1591Smax.romanov@nginx.com *bytes = PyUnicode_AsLatin1String(str); 1142*1591Smax.romanov@nginx.com if (nxt_slow_path(*bytes == NULL)) { 1143*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 1144*1591Smax.romanov@nginx.com } 1145*1591Smax.romanov@nginx.com 1146*1591Smax.romanov@nginx.com *buf = PyBytes_AS_STRING(*bytes); 1147*1591Smax.romanov@nginx.com *len = PyBytes_GET_SIZE(*bytes); 1148*1591Smax.romanov@nginx.com } 1149*1591Smax.romanov@nginx.com 1150*1591Smax.romanov@nginx.com return NXT_UNIT_OK; 1151*1591Smax.romanov@nginx.com } 1152*1591Smax.romanov@nginx.com 1153*1591Smax.romanov@nginx.com 1154*1591Smax.romanov@nginx.com static PyObject * 1155*1591Smax.romanov@nginx.com nxt_py_write(PyObject *self, PyObject *str) 1156*1591Smax.romanov@nginx.com { 1157*1591Smax.romanov@nginx.com int rc; 1158*1591Smax.romanov@nginx.com 1159*1591Smax.romanov@nginx.com if (nxt_fast_path(!PyBytes_Check(str))) { 1160*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "the argument is not a %s", 1161*1591Smax.romanov@nginx.com NXT_PYTHON_BYTES_TYPE); 1162*1591Smax.romanov@nginx.com } 1163*1591Smax.romanov@nginx.com 1164*1591Smax.romanov@nginx.com rc = nxt_python_write(nxt_python_run_ctx, str); 1165*1591Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1166*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1167*1591Smax.romanov@nginx.com "failed to write response value"); 1168*1591Smax.romanov@nginx.com } 1169*1591Smax.romanov@nginx.com 1170*1591Smax.romanov@nginx.com Py_RETURN_NONE; 1171*1591Smax.romanov@nginx.com } 1172*1591Smax.romanov@nginx.com 1173*1591Smax.romanov@nginx.com 1174*1591Smax.romanov@nginx.com static void 1175*1591Smax.romanov@nginx.com nxt_py_input_dealloc(nxt_py_input_t *self) 1176*1591Smax.romanov@nginx.com { 1177*1591Smax.romanov@nginx.com PyObject_Del(self); 1178*1591Smax.romanov@nginx.com } 1179*1591Smax.romanov@nginx.com 1180*1591Smax.romanov@nginx.com 1181*1591Smax.romanov@nginx.com static PyObject * 1182*1591Smax.romanov@nginx.com nxt_py_input_read(nxt_py_input_t *self, PyObject *args) 1183*1591Smax.romanov@nginx.com { 1184*1591Smax.romanov@nginx.com char *buf; 1185*1591Smax.romanov@nginx.com PyObject *content, *obj; 1186*1591Smax.romanov@nginx.com Py_ssize_t size, n; 1187*1591Smax.romanov@nginx.com nxt_python_run_ctx_t *ctx; 1188*1591Smax.romanov@nginx.com 1189*1591Smax.romanov@nginx.com ctx = nxt_python_run_ctx; 1190*1591Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 1191*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1192*1591Smax.romanov@nginx.com "wsgi.input.read() is called " 1193*1591Smax.romanov@nginx.com "outside of WSGI request processing"); 1194*1591Smax.romanov@nginx.com } 1195*1591Smax.romanov@nginx.com 1196*1591Smax.romanov@nginx.com size = ctx->req->content_length; 1197*1591Smax.romanov@nginx.com 1198*1591Smax.romanov@nginx.com n = PyTuple_GET_SIZE(args); 1199*1591Smax.romanov@nginx.com 1200*1591Smax.romanov@nginx.com if (n > 0) { 1201*1591Smax.romanov@nginx.com if (n != 1) { 1202*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); 1203*1591Smax.romanov@nginx.com } 1204*1591Smax.romanov@nginx.com 1205*1591Smax.romanov@nginx.com obj = PyTuple_GET_ITEM(args, 0); 1206*1591Smax.romanov@nginx.com 1207*1591Smax.romanov@nginx.com size = PyNumber_AsSsize_t(obj, PyExc_OverflowError); 1208*1591Smax.romanov@nginx.com 1209*1591Smax.romanov@nginx.com if (nxt_slow_path(size < 0)) { 1210*1591Smax.romanov@nginx.com if (size == -1 && PyErr_Occurred()) { 1211*1591Smax.romanov@nginx.com return NULL; 1212*1591Smax.romanov@nginx.com } 1213*1591Smax.romanov@nginx.com 1214*1591Smax.romanov@nginx.com if (size != -1) { 1215*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_ValueError, 1216*1591Smax.romanov@nginx.com "the read body size cannot be zero or less"); 1217*1591Smax.romanov@nginx.com } 1218*1591Smax.romanov@nginx.com } 1219*1591Smax.romanov@nginx.com 1220*1591Smax.romanov@nginx.com if (size == -1 || size > (Py_ssize_t) ctx->req->content_length) { 1221*1591Smax.romanov@nginx.com size = ctx->req->content_length; 1222*1591Smax.romanov@nginx.com } 1223*1591Smax.romanov@nginx.com } 1224*1591Smax.romanov@nginx.com 1225*1591Smax.romanov@nginx.com content = PyBytes_FromStringAndSize(NULL, size); 1226*1591Smax.romanov@nginx.com if (nxt_slow_path(content == NULL)) { 1227*1591Smax.romanov@nginx.com return NULL; 1228*1591Smax.romanov@nginx.com } 1229*1591Smax.romanov@nginx.com 1230*1591Smax.romanov@nginx.com buf = PyBytes_AS_STRING(content); 1231*1591Smax.romanov@nginx.com 1232*1591Smax.romanov@nginx.com size = nxt_unit_request_read(ctx->req, buf, size); 1233*1591Smax.romanov@nginx.com 1234*1591Smax.romanov@nginx.com return content; 1235*1591Smax.romanov@nginx.com } 1236*1591Smax.romanov@nginx.com 1237*1591Smax.romanov@nginx.com 1238*1591Smax.romanov@nginx.com static PyObject * 1239*1591Smax.romanov@nginx.com nxt_py_input_readline(nxt_py_input_t *self, PyObject *args) 1240*1591Smax.romanov@nginx.com { 1241*1591Smax.romanov@nginx.com ssize_t ssize; 1242*1591Smax.romanov@nginx.com PyObject *obj; 1243*1591Smax.romanov@nginx.com Py_ssize_t n; 1244*1591Smax.romanov@nginx.com nxt_python_run_ctx_t *ctx; 1245*1591Smax.romanov@nginx.com 1246*1591Smax.romanov@nginx.com ctx = nxt_python_run_ctx; 1247*1591Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 1248*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1249*1591Smax.romanov@nginx.com "wsgi.input.readline() is called " 1250*1591Smax.romanov@nginx.com "outside of WSGI request processing"); 1251*1591Smax.romanov@nginx.com } 1252*1591Smax.romanov@nginx.com 1253*1591Smax.romanov@nginx.com n = PyTuple_GET_SIZE(args); 1254*1591Smax.romanov@nginx.com 1255*1591Smax.romanov@nginx.com if (n > 0) { 1256*1591Smax.romanov@nginx.com if (n != 1) { 1257*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); 1258*1591Smax.romanov@nginx.com } 1259*1591Smax.romanov@nginx.com 1260*1591Smax.romanov@nginx.com obj = PyTuple_GET_ITEM(args, 0); 1261*1591Smax.romanov@nginx.com 1262*1591Smax.romanov@nginx.com ssize = PyNumber_AsSsize_t(obj, PyExc_OverflowError); 1263*1591Smax.romanov@nginx.com 1264*1591Smax.romanov@nginx.com if (nxt_fast_path(ssize > 0)) { 1265*1591Smax.romanov@nginx.com return nxt_py_input_getline(ctx, ssize); 1266*1591Smax.romanov@nginx.com } 1267*1591Smax.romanov@nginx.com 1268*1591Smax.romanov@nginx.com if (ssize == 0) { 1269*1591Smax.romanov@nginx.com return PyBytes_FromStringAndSize("", 0); 1270*1591Smax.romanov@nginx.com } 1271*1591Smax.romanov@nginx.com 1272*1591Smax.romanov@nginx.com if (ssize != -1) { 1273*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_ValueError, 1274*1591Smax.romanov@nginx.com "the read line size cannot be zero or less"); 1275*1591Smax.romanov@nginx.com } 1276*1591Smax.romanov@nginx.com 1277*1591Smax.romanov@nginx.com if (PyErr_Occurred()) { 1278*1591Smax.romanov@nginx.com return NULL; 1279*1591Smax.romanov@nginx.com } 1280*1591Smax.romanov@nginx.com } 1281*1591Smax.romanov@nginx.com 1282*1591Smax.romanov@nginx.com return nxt_py_input_getline(ctx, SSIZE_MAX); 1283*1591Smax.romanov@nginx.com } 1284*1591Smax.romanov@nginx.com 1285*1591Smax.romanov@nginx.com 1286*1591Smax.romanov@nginx.com static PyObject * 1287*1591Smax.romanov@nginx.com nxt_py_input_getline(nxt_python_run_ctx_t *ctx, size_t size) 1288*1591Smax.romanov@nginx.com { 1289*1591Smax.romanov@nginx.com void *buf; 1290*1591Smax.romanov@nginx.com ssize_t res; 1291*1591Smax.romanov@nginx.com PyObject *content; 1292*1591Smax.romanov@nginx.com 1293*1591Smax.romanov@nginx.com res = nxt_unit_request_readline_size(ctx->req, size); 1294*1591Smax.romanov@nginx.com if (nxt_slow_path(res < 0)) { 1295*1591Smax.romanov@nginx.com return NULL; 1296*1591Smax.romanov@nginx.com } 1297*1591Smax.romanov@nginx.com 1298*1591Smax.romanov@nginx.com if (res == 0) { 1299*1591Smax.romanov@nginx.com return PyBytes_FromStringAndSize("", 0); 1300*1591Smax.romanov@nginx.com } 1301*1591Smax.romanov@nginx.com 1302*1591Smax.romanov@nginx.com content = PyBytes_FromStringAndSize(NULL, res); 1303*1591Smax.romanov@nginx.com if (nxt_slow_path(content == NULL)) { 1304*1591Smax.romanov@nginx.com return NULL; 1305*1591Smax.romanov@nginx.com } 1306*1591Smax.romanov@nginx.com 1307*1591Smax.romanov@nginx.com buf = PyBytes_AS_STRING(content); 1308*1591Smax.romanov@nginx.com 1309*1591Smax.romanov@nginx.com res = nxt_unit_request_read(ctx->req, buf, res); 1310*1591Smax.romanov@nginx.com 1311*1591Smax.romanov@nginx.com return content; 1312*1591Smax.romanov@nginx.com } 1313*1591Smax.romanov@nginx.com 1314*1591Smax.romanov@nginx.com 1315*1591Smax.romanov@nginx.com static PyObject * 1316*1591Smax.romanov@nginx.com nxt_py_input_readlines(nxt_py_input_t *self, PyObject *args) 1317*1591Smax.romanov@nginx.com { 1318*1591Smax.romanov@nginx.com PyObject *res; 1319*1591Smax.romanov@nginx.com nxt_python_run_ctx_t *ctx; 1320*1591Smax.romanov@nginx.com 1321*1591Smax.romanov@nginx.com ctx = nxt_python_run_ctx; 1322*1591Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 1323*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1324*1591Smax.romanov@nginx.com "wsgi.input.readlines() is called " 1325*1591Smax.romanov@nginx.com "outside of WSGI request processing"); 1326*1591Smax.romanov@nginx.com } 1327*1591Smax.romanov@nginx.com 1328*1591Smax.romanov@nginx.com res = PyList_New(0); 1329*1591Smax.romanov@nginx.com if (nxt_slow_path(res == NULL)) { 1330*1591Smax.romanov@nginx.com return NULL; 1331*1591Smax.romanov@nginx.com } 1332*1591Smax.romanov@nginx.com 1333*1591Smax.romanov@nginx.com for ( ;; ) { 1334*1591Smax.romanov@nginx.com PyObject *line = nxt_py_input_getline(ctx, SSIZE_MAX); 1335*1591Smax.romanov@nginx.com if (nxt_slow_path(line == NULL)) { 1336*1591Smax.romanov@nginx.com Py_DECREF(res); 1337*1591Smax.romanov@nginx.com return NULL; 1338*1591Smax.romanov@nginx.com } 1339*1591Smax.romanov@nginx.com 1340*1591Smax.romanov@nginx.com if (PyBytes_GET_SIZE(line) == 0) { 1341*1591Smax.romanov@nginx.com Py_DECREF(line); 1342*1591Smax.romanov@nginx.com return res; 1343*1591Smax.romanov@nginx.com } 1344*1591Smax.romanov@nginx.com 1345*1591Smax.romanov@nginx.com PyList_Append(res, line); 1346*1591Smax.romanov@nginx.com Py_DECREF(line); 1347*1591Smax.romanov@nginx.com } 1348*1591Smax.romanov@nginx.com 1349*1591Smax.romanov@nginx.com return res; 1350*1591Smax.romanov@nginx.com } 1351*1591Smax.romanov@nginx.com 1352*1591Smax.romanov@nginx.com 1353*1591Smax.romanov@nginx.com static PyObject * 1354*1591Smax.romanov@nginx.com nxt_py_input_iter(PyObject *self) 1355*1591Smax.romanov@nginx.com { 1356*1591Smax.romanov@nginx.com Py_INCREF(self); 1357*1591Smax.romanov@nginx.com return self; 1358*1591Smax.romanov@nginx.com } 1359*1591Smax.romanov@nginx.com 1360*1591Smax.romanov@nginx.com 1361*1591Smax.romanov@nginx.com static PyObject * 1362*1591Smax.romanov@nginx.com nxt_py_input_next(PyObject *self) 1363*1591Smax.romanov@nginx.com { 1364*1591Smax.romanov@nginx.com PyObject *line; 1365*1591Smax.romanov@nginx.com nxt_python_run_ctx_t *ctx; 1366*1591Smax.romanov@nginx.com 1367*1591Smax.romanov@nginx.com ctx = nxt_python_run_ctx; 1368*1591Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) { 1369*1591Smax.romanov@nginx.com return PyErr_Format(PyExc_RuntimeError, 1370*1591Smax.romanov@nginx.com "wsgi.input.next() is called " 1371*1591Smax.romanov@nginx.com "outside of WSGI request processing"); 1372*1591Smax.romanov@nginx.com } 1373*1591Smax.romanov@nginx.com 1374*1591Smax.romanov@nginx.com line = nxt_py_input_getline(ctx, SSIZE_MAX); 1375*1591Smax.romanov@nginx.com if (nxt_slow_path(line == NULL)) { 1376*1591Smax.romanov@nginx.com return NULL; 1377*1591Smax.romanov@nginx.com } 1378*1591Smax.romanov@nginx.com 1379*1591Smax.romanov@nginx.com if (PyBytes_GET_SIZE(line) == 0) { 1380*1591Smax.romanov@nginx.com Py_DECREF(line); 1381*1591Smax.romanov@nginx.com PyErr_SetNone(PyExc_StopIteration); 1382*1591Smax.romanov@nginx.com return NULL; 1383*1591Smax.romanov@nginx.com } 1384*1591Smax.romanov@nginx.com 1385*1591Smax.romanov@nginx.com return line; 1386*1591Smax.romanov@nginx.com } 1387*1591Smax.romanov@nginx.com 1388*1591Smax.romanov@nginx.com 1389*1591Smax.romanov@nginx.com static void 1390*1591Smax.romanov@nginx.com nxt_python_print_exception(void) 1391*1591Smax.romanov@nginx.com { 1392*1591Smax.romanov@nginx.com PyErr_Print(); 1393*1591Smax.romanov@nginx.com 1394*1591Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3 1395*1591Smax.romanov@nginx.com /* The backtrace may be buffered in sys.stderr file object. */ 1396*1591Smax.romanov@nginx.com { 1397*1591Smax.romanov@nginx.com PyObject *result; 1398*1591Smax.romanov@nginx.com 1399*1591Smax.romanov@nginx.com result = PyObject_CallFunction(nxt_py_stderr_flush, NULL); 1400*1591Smax.romanov@nginx.com if (nxt_slow_path(result == NULL)) { 1401*1591Smax.romanov@nginx.com PyErr_Clear(); 1402*1591Smax.romanov@nginx.com return; 1403*1591Smax.romanov@nginx.com } 1404*1591Smax.romanov@nginx.com 1405*1591Smax.romanov@nginx.com Py_DECREF(result); 1406*1591Smax.romanov@nginx.com } 1407*1591Smax.romanov@nginx.com #endif 1408*1591Smax.romanov@nginx.com } 1409*1591Smax.romanov@nginx.com 1410*1591Smax.romanov@nginx.com 1411*1591Smax.romanov@nginx.com static int 1412*1591Smax.romanov@nginx.com nxt_python_write(nxt_python_run_ctx_t *ctx, PyObject *bytes) 1413*1591Smax.romanov@nginx.com { 1414*1591Smax.romanov@nginx.com int rc; 1415*1591Smax.romanov@nginx.com char *str_buf; 1416*1591Smax.romanov@nginx.com uint32_t str_length; 1417*1591Smax.romanov@nginx.com 1418*1591Smax.romanov@nginx.com str_buf = PyBytes_AS_STRING(bytes); 1419*1591Smax.romanov@nginx.com str_length = PyBytes_GET_SIZE(bytes); 1420*1591Smax.romanov@nginx.com 1421*1591Smax.romanov@nginx.com if (nxt_slow_path(str_length == 0)) { 1422*1591Smax.romanov@nginx.com return NXT_UNIT_OK; 1423*1591Smax.romanov@nginx.com } 1424*1591Smax.romanov@nginx.com 1425*1591Smax.romanov@nginx.com /* 1426*1591Smax.romanov@nginx.com * PEP 3333: 1427*1591Smax.romanov@nginx.com * 1428*1591Smax.romanov@nginx.com * If the application supplies a Content-Length header, the server should 1429*1591Smax.romanov@nginx.com * not transmit more bytes to the client than the header allows, and should 1430*1591Smax.romanov@nginx.com * stop iterating over the response when enough data has been sent, or raise 1431*1591Smax.romanov@nginx.com * an error if the application tries to write() past that point. 1432*1591Smax.romanov@nginx.com */ 1433*1591Smax.romanov@nginx.com if (nxt_slow_path(str_length > ctx->content_length - ctx->bytes_sent)) { 1434*1591Smax.romanov@nginx.com nxt_unit_req_error(ctx->req, "content length %"PRIu64" exceeded", 1435*1591Smax.romanov@nginx.com ctx->content_length); 1436*1591Smax.romanov@nginx.com 1437*1591Smax.romanov@nginx.com return NXT_UNIT_ERROR; 1438*1591Smax.romanov@nginx.com } 1439*1591Smax.romanov@nginx.com 1440*1591Smax.romanov@nginx.com rc = nxt_unit_response_write(ctx->req, str_buf, str_length); 1441*1591Smax.romanov@nginx.com if (nxt_fast_path(rc == NXT_UNIT_OK)) { 1442*1591Smax.romanov@nginx.com ctx->bytes_sent += str_length; 1443*1591Smax.romanov@nginx.com } 1444*1591Smax.romanov@nginx.com 1445*1591Smax.romanov@nginx.com return rc; 1446*1591Smax.romanov@nginx.com } 1447