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