xref: /unit/src/python/nxt_python_wsgi.c (revision 1591)
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