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