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