1 2 /* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 7 #include <python/nxt_python.h> 8 9 #if (NXT_HAVE_ASGI) 10 11 #include <nxt_main.h> 12 #include <nxt_unit.h> 13 #include <nxt_unit_request.h> 14 #include <nxt_unit_response.h> 15 #include <python/nxt_python_asgi.h> 16 #include <python/nxt_python_asgi_str.h> 17 18 19 static PyObject *nxt_python_asgi_get_func(PyObject *obj); 20 static int nxt_python_asgi_ctx_data_alloc(void **pdata); 21 static void nxt_python_asgi_ctx_data_free(void *data); 22 static int nxt_python_asgi_startup(void *data); 23 static int nxt_python_asgi_run(nxt_unit_ctx_t *ctx); 24 25 static void nxt_py_asgi_remove_reader(nxt_unit_ctx_t *ctx, 26 nxt_unit_port_t *port); 27 static void nxt_py_asgi_request_handler(nxt_unit_request_info_t *req); 28 static void nxt_py_asgi_close_handler(nxt_unit_request_info_t *req); 29 30 static PyObject *nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req); 31 static PyObject *nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, 32 uint16_t port); 33 static PyObject *nxt_py_asgi_create_header(nxt_unit_field_t *f); 34 static PyObject *nxt_py_asgi_create_subprotocols(nxt_unit_field_t *f); 35 36 static int nxt_python_asgi_ready(nxt_unit_ctx_t *ctx); 37 38 static int nxt_py_asgi_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port); 39 static void nxt_py_asgi_remove_port(nxt_unit_t *lib, nxt_unit_port_t *port); 40 static void nxt_py_asgi_quit(nxt_unit_ctx_t *ctx); 41 static void nxt_py_asgi_shm_ack_handler(nxt_unit_ctx_t *ctx); 42 43 static PyObject *nxt_py_asgi_port_read(PyObject *self, PyObject *args); 44 static void nxt_python_asgi_done(void); 45 46 static PyObject *nxt_py_port_read; 47 static nxt_unit_port_t *nxt_py_shared_port; 48 49 static PyMethodDef nxt_py_port_read_method = 50 {"unit_port_read", nxt_py_asgi_port_read, METH_VARARGS, ""}; 51 52 static nxt_python_proto_t nxt_py_asgi_proto = { 53 .ctx_data_alloc = nxt_python_asgi_ctx_data_alloc, 54 .ctx_data_free = nxt_python_asgi_ctx_data_free, 55 .startup = nxt_python_asgi_startup, 56 .run = nxt_python_asgi_run, 57 .ready = nxt_python_asgi_ready, 58 .done = nxt_python_asgi_done, 59 }; 60 61 #define NXT_UNIT_HASH_WS_PROTOCOL 0xED0A 62 63 64 int 65 nxt_python_asgi_check(PyObject *obj) 66 { 67 int res; 68 PyObject *func; 69 PyCodeObject *code; 70 71 func = nxt_python_asgi_get_func(obj); 72 73 if (func == NULL) { 74 return 0; 75 } 76 77 code = (PyCodeObject *) PyFunction_GET_CODE(func); 78 79 nxt_unit_debug(NULL, "asgi_check: callable is %sa coroutine function with " 80 "%d argument(s)", 81 (code->co_flags & CO_COROUTINE) != 0 ? "" : "not ", 82 code->co_argcount); 83 84 res = (code->co_flags & CO_COROUTINE) != 0 || code->co_argcount == 1; 85 86 Py_DECREF(func); 87 88 return res; 89 } 90 91 92 static PyObject * 93 nxt_python_asgi_get_func(PyObject *obj) 94 { 95 PyObject *call; 96 97 if (PyFunction_Check(obj)) { 98 Py_INCREF(obj); 99 return obj; 100 } 101 102 if (PyMethod_Check(obj)) { 103 obj = PyMethod_GET_FUNCTION(obj); 104 105 Py_INCREF(obj); 106 return obj; 107 } 108 109 call = PyObject_GetAttrString(obj, "__call__"); 110 111 if (call == NULL) { 112 return NULL; 113 } 114 115 if (PyFunction_Check(call)) { 116 return call; 117 } 118 119 if (PyMethod_Check(call)) { 120 obj = PyMethod_GET_FUNCTION(call); 121 122 Py_INCREF(obj); 123 Py_DECREF(call); 124 125 return obj; 126 } 127 128 Py_DECREF(call); 129 130 return NULL; 131 } 132 133 134 int 135 nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) 136 { 137 PyObject *func; 138 nxt_int_t i; 139 PyCodeObject *code; 140 141 nxt_unit_debug(NULL, "asgi_init"); 142 143 if (nxt_slow_path(nxt_py_asgi_str_init() != NXT_UNIT_OK)) { 144 nxt_unit_alert(NULL, "Python failed to init string objects"); 145 return NXT_UNIT_ERROR; 146 } 147 148 nxt_py_port_read = PyCFunction_New(&nxt_py_port_read_method, NULL); 149 if (nxt_slow_path(nxt_py_port_read == NULL)) { 150 nxt_unit_alert(NULL, 151 "Python failed to initialize the 'port_read' function"); 152 return NXT_UNIT_ERROR; 153 } 154 155 if (nxt_slow_path(nxt_py_asgi_http_init() == NXT_UNIT_ERROR)) { 156 return NXT_UNIT_ERROR; 157 } 158 159 if (nxt_slow_path(nxt_py_asgi_websocket_init() == NXT_UNIT_ERROR)) { 160 return NXT_UNIT_ERROR; 161 } 162 163 for (i = 0; i < nxt_py_targets->count; i++) { 164 func = nxt_python_asgi_get_func(nxt_py_targets->target[i].application); 165 if (nxt_slow_path(func == NULL)) { 166 nxt_unit_alert(NULL, "Python cannot find function for callable"); 167 return NXT_UNIT_ERROR; 168 } 169 170 code = (PyCodeObject *) PyFunction_GET_CODE(func); 171 172 if ((code->co_flags & CO_COROUTINE) == 0) { 173 nxt_unit_debug(NULL, "asgi: callable is not a coroutine function " 174 "switching to legacy mode"); 175 nxt_py_targets->target[i].asgi_legacy = 1; 176 } 177 178 Py_DECREF(func); 179 } 180 181 init->callbacks.request_handler = nxt_py_asgi_request_handler; 182 init->callbacks.data_handler = nxt_py_asgi_http_data_handler; 183 init->callbacks.websocket_handler = nxt_py_asgi_websocket_handler; 184 init->callbacks.close_handler = nxt_py_asgi_close_handler; 185 init->callbacks.quit = nxt_py_asgi_quit; 186 init->callbacks.shm_ack_handler = nxt_py_asgi_shm_ack_handler; 187 init->callbacks.add_port = nxt_py_asgi_add_port; 188 init->callbacks.remove_port = nxt_py_asgi_remove_port; 189 190 *proto = nxt_py_asgi_proto; 191 192 return NXT_UNIT_OK; 193 } 194 195 196 static int 197 nxt_python_asgi_ctx_data_alloc(void **pdata) 198 { 199 uint32_t i; 200 PyObject *asyncio, *loop, *new_event_loop, *obj; 201 nxt_py_asgi_ctx_data_t *ctx_data; 202 203 ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t)); 204 if (nxt_slow_path(ctx_data == NULL)) { 205 nxt_unit_alert(NULL, "Failed to allocate context data"); 206 return NXT_UNIT_ERROR; 207 } 208 209 memset(ctx_data, 0, sizeof(nxt_py_asgi_ctx_data_t)); 210 211 nxt_queue_init(&ctx_data->drain_queue); 212 213 struct { 214 const char *key; 215 PyObject **handler; 216 217 } handlers[] = { 218 { "create_task", &ctx_data->loop_create_task }, 219 { "add_reader", &ctx_data->loop_add_reader }, 220 { "remove_reader", &ctx_data->loop_remove_reader }, 221 { "call_soon", &ctx_data->loop_call_soon }, 222 { "run_until_complete", &ctx_data->loop_run_until_complete }, 223 { "create_future", &ctx_data->loop_create_future }, 224 }; 225 226 loop = NULL; 227 228 asyncio = PyImport_ImportModule("asyncio"); 229 if (nxt_slow_path(asyncio == NULL)) { 230 nxt_unit_alert(NULL, "Python failed to import module 'asyncio'"); 231 nxt_python_print_exception(); 232 goto fail; 233 } 234 235 new_event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio), 236 "new_event_loop"); 237 if (nxt_slow_path(new_event_loop == NULL)) { 238 nxt_unit_alert(NULL, 239 "Python failed to get 'new_event_loop' from module 'asyncio'"); 240 goto fail; 241 } 242 243 if (nxt_slow_path(PyCallable_Check(new_event_loop) == 0)) { 244 nxt_unit_alert(NULL, 245 "'asyncio.new_event_loop' is not a callable object"); 246 goto fail; 247 } 248 249 loop = PyObject_CallObject(new_event_loop, NULL); 250 if (nxt_slow_path(loop == NULL)) { 251 nxt_unit_alert(NULL, "Python failed to call 'asyncio.new_event_loop'"); 252 goto fail; 253 } 254 255 for (i = 0; i < nxt_nitems(handlers); i++) { 256 obj = PyObject_GetAttrString(loop, handlers[i].key); 257 if (nxt_slow_path(obj == NULL)) { 258 nxt_unit_alert(NULL, "Python failed to get 'loop.%s'", 259 handlers[i].key); 260 goto fail; 261 } 262 263 *handlers[i].handler = obj; 264 265 if (nxt_slow_path(PyCallable_Check(obj) == 0)) { 266 nxt_unit_alert(NULL, "'loop.%s' is not a callable object", 267 handlers[i].key); 268 goto fail; 269 } 270 } 271 272 obj = PyObject_CallObject(ctx_data->loop_create_future, NULL); 273 if (nxt_slow_path(obj == NULL)) { 274 nxt_unit_alert(NULL, "Python failed to create Future "); 275 nxt_python_print_exception(); 276 goto fail; 277 } 278 279 ctx_data->quit_future = obj; 280 281 obj = PyObject_GetAttrString(ctx_data->quit_future, "set_result"); 282 if (nxt_slow_path(obj == NULL)) { 283 nxt_unit_alert(NULL, "Python failed to get 'future.set_result'"); 284 goto fail; 285 } 286 287 ctx_data->quit_future_set_result = obj; 288 289 if (nxt_slow_path(PyCallable_Check(obj) == 0)) { 290 nxt_unit_alert(NULL, "'future.set_result' is not a callable object"); 291 goto fail; 292 } 293 294 Py_DECREF(loop); 295 Py_DECREF(asyncio); 296 297 *pdata = ctx_data; 298 299 return NXT_UNIT_OK; 300 301 fail: 302 303 nxt_python_asgi_ctx_data_free(ctx_data); 304 305 Py_XDECREF(loop); 306 Py_XDECREF(asyncio); 307 308 return NXT_UNIT_ERROR; 309 } 310 311 312 static void 313 nxt_python_asgi_ctx_data_free(void *data) 314 { 315 nxt_py_asgi_ctx_data_t *ctx_data; 316 317 ctx_data = data; 318 319 Py_XDECREF(ctx_data->loop_run_until_complete); 320 Py_XDECREF(ctx_data->loop_create_future); 321 Py_XDECREF(ctx_data->loop_create_task); 322 Py_XDECREF(ctx_data->loop_call_soon); 323 Py_XDECREF(ctx_data->loop_add_reader); 324 Py_XDECREF(ctx_data->loop_remove_reader); 325 Py_XDECREF(ctx_data->quit_future); 326 Py_XDECREF(ctx_data->quit_future_set_result); 327 328 nxt_unit_free(NULL, ctx_data); 329 } 330 331 332 static int 333 nxt_python_asgi_startup(void *data) 334 { 335 return nxt_py_asgi_lifespan_startup(data); 336 } 337 338 339 static int 340 nxt_python_asgi_run(nxt_unit_ctx_t *ctx) 341 { 342 PyObject *res; 343 nxt_py_asgi_ctx_data_t *ctx_data; 344 345 ctx_data = ctx->data; 346 347 res = PyObject_CallFunctionObjArgs(ctx_data->loop_run_until_complete, 348 ctx_data->quit_future, NULL); 349 if (nxt_slow_path(res == NULL)) { 350 nxt_unit_alert(ctx, "Python failed to call loop.run_until_complete"); 351 nxt_python_print_exception(); 352 353 return NXT_UNIT_ERROR; 354 } 355 356 Py_DECREF(res); 357 358 nxt_py_asgi_remove_reader(ctx, nxt_py_shared_port); 359 nxt_py_asgi_remove_reader(ctx, ctx_data->port); 360 361 if (ctx_data->port != NULL) { 362 ctx_data->port->data = NULL; 363 ctx_data->port = NULL; 364 } 365 366 nxt_py_asgi_lifespan_shutdown(ctx); 367 368 return NXT_UNIT_OK; 369 } 370 371 372 static void 373 nxt_py_asgi_remove_reader(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 374 { 375 PyObject *res, *fd; 376 nxt_py_asgi_ctx_data_t *ctx_data; 377 378 if (port == NULL || port->in_fd == -1) { 379 return; 380 } 381 382 ctx_data = ctx->data; 383 384 nxt_unit_debug(ctx, "asgi_remove_reader %d %p", port->in_fd, port); 385 386 fd = PyLong_FromLong(port->in_fd); 387 if (nxt_slow_path(fd == NULL)) { 388 nxt_unit_alert(ctx, "Python failed to create Long object"); 389 nxt_python_print_exception(); 390 391 return; 392 } 393 394 res = PyObject_CallFunctionObjArgs(ctx_data->loop_remove_reader, fd, NULL); 395 if (nxt_slow_path(res == NULL)) { 396 nxt_unit_alert(ctx, "Python failed to remove_reader"); 397 nxt_python_print_exception(); 398 399 } else { 400 Py_DECREF(res); 401 } 402 403 Py_DECREF(fd); 404 } 405 406 407 static void 408 nxt_py_asgi_request_handler(nxt_unit_request_info_t *req) 409 { 410 PyObject *scope, *res, *task, *receive, *send, *done, *asgi; 411 PyObject *stage2; 412 nxt_python_target_t *target; 413 nxt_py_asgi_ctx_data_t *ctx_data; 414 415 if (req->request->websocket_handshake) { 416 asgi = nxt_py_asgi_websocket_create(req); 417 418 } else { 419 asgi = nxt_py_asgi_http_create(req); 420 } 421 422 if (nxt_slow_path(asgi == NULL)) { 423 nxt_unit_req_alert(req, "Python failed to create asgi object"); 424 nxt_unit_request_done(req, NXT_UNIT_ERROR); 425 426 return; 427 } 428 429 receive = PyObject_GetAttrString(asgi, "receive"); 430 if (nxt_slow_path(receive == NULL)) { 431 nxt_unit_req_alert(req, "Python failed to get 'receive' method"); 432 nxt_unit_request_done(req, NXT_UNIT_ERROR); 433 434 goto release_asgi; 435 } 436 437 send = PyObject_GetAttrString(asgi, "send"); 438 if (nxt_slow_path(receive == NULL)) { 439 nxt_unit_req_alert(req, "Python failed to get 'send' method"); 440 nxt_unit_request_done(req, NXT_UNIT_ERROR); 441 442 goto release_receive; 443 } 444 445 done = PyObject_GetAttrString(asgi, "_done"); 446 if (nxt_slow_path(receive == NULL)) { 447 nxt_unit_req_alert(req, "Python failed to get '_done' method"); 448 nxt_unit_request_done(req, NXT_UNIT_ERROR); 449 450 goto release_send; 451 } 452 453 scope = nxt_py_asgi_create_http_scope(req); 454 if (nxt_slow_path(scope == NULL)) { 455 nxt_unit_request_done(req, NXT_UNIT_ERROR); 456 457 goto release_done; 458 } 459 460 req->data = asgi; 461 target = &nxt_py_targets->target[req->request->app_target]; 462 463 if (!target->asgi_legacy) { 464 nxt_unit_req_debug(req, "Python call ASGI 3.0 application"); 465 466 res = PyObject_CallFunctionObjArgs(target->application, 467 scope, receive, send, NULL); 468 469 } else { 470 nxt_unit_req_debug(req, "Python call legacy application"); 471 472 res = PyObject_CallFunctionObjArgs(target->application, scope, NULL); 473 474 if (nxt_slow_path(res == NULL)) { 475 nxt_unit_req_error(req, "Python failed to call legacy app stage1"); 476 nxt_python_print_exception(); 477 nxt_unit_request_done(req, NXT_UNIT_ERROR); 478 479 goto release_scope; 480 } 481 482 if (nxt_slow_path(PyCallable_Check(res) == 0)) { 483 nxt_unit_req_error(req, 484 "Legacy ASGI application returns not a callable"); 485 nxt_unit_request_done(req, NXT_UNIT_ERROR); 486 487 Py_DECREF(res); 488 489 goto release_scope; 490 } 491 492 stage2 = res; 493 494 res = PyObject_CallFunctionObjArgs(stage2, receive, send, NULL); 495 496 Py_DECREF(stage2); 497 } 498 499 if (nxt_slow_path(res == NULL)) { 500 nxt_unit_req_error(req, "Python failed to call the application"); 501 nxt_python_print_exception(); 502 nxt_unit_request_done(req, NXT_UNIT_ERROR); 503 504 goto release_scope; 505 } 506 507 if (nxt_slow_path(!PyCoro_CheckExact(res))) { 508 nxt_unit_req_error(req, "Application result type is not a coroutine"); 509 nxt_unit_request_done(req, NXT_UNIT_ERROR); 510 511 Py_DECREF(res); 512 513 goto release_scope; 514 } 515 516 ctx_data = req->ctx->data; 517 518 task = PyObject_CallFunctionObjArgs(ctx_data->loop_create_task, res, NULL); 519 if (nxt_slow_path(task == NULL)) { 520 nxt_unit_req_error(req, "Python failed to call the create_task"); 521 nxt_python_print_exception(); 522 nxt_unit_request_done(req, NXT_UNIT_ERROR); 523 524 Py_DECREF(res); 525 526 goto release_scope; 527 } 528 529 Py_DECREF(res); 530 531 res = PyObject_CallMethodObjArgs(task, nxt_py_add_done_callback_str, done, 532 NULL); 533 if (nxt_slow_path(res == NULL)) { 534 nxt_unit_req_error(req, 535 "Python failed to call 'task.add_done_callback'"); 536 nxt_python_print_exception(); 537 nxt_unit_request_done(req, NXT_UNIT_ERROR); 538 539 goto release_task; 540 } 541 542 Py_DECREF(res); 543 release_task: 544 Py_DECREF(task); 545 release_scope: 546 Py_DECREF(scope); 547 release_done: 548 Py_DECREF(done); 549 release_send: 550 Py_DECREF(send); 551 release_receive: 552 Py_DECREF(receive); 553 release_asgi: 554 Py_DECREF(asgi); 555 } 556 557 558 static void 559 nxt_py_asgi_close_handler(nxt_unit_request_info_t *req) 560 { 561 if (req->request->websocket_handshake) { 562 nxt_py_asgi_websocket_close_handler(req); 563 564 } else { 565 nxt_py_asgi_http_close_handler(req); 566 } 567 } 568 569 570 static PyObject * 571 nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req) 572 { 573 char *p, *target, *query; 574 uint32_t target_length, i; 575 PyObject *scope, *v, *type, *scheme; 576 PyObject *headers, *header; 577 nxt_unit_field_t *f; 578 nxt_unit_request_t *r; 579 580 static const nxt_str_t ws_protocol = nxt_string("sec-websocket-protocol"); 581 582 #define SET_ITEM(dict, key, value) \ 583 if (nxt_slow_path(PyDict_SetItem(dict, nxt_py_ ## key ## _str, value) \ 584 == -1)) \ 585 { \ 586 nxt_unit_req_alert(req, "Python failed to set '" \ 587 #dict "." #key "' item"); \ 588 goto fail; \ 589 } 590 591 v = NULL; 592 headers = NULL; 593 594 r = req->request; 595 596 if (r->websocket_handshake) { 597 type = nxt_py_websocket_str; 598 scheme = r->tls ? nxt_py_wss_str : nxt_py_ws_str; 599 600 } else { 601 type = nxt_py_http_str; 602 scheme = r->tls ? nxt_py_https_str : nxt_py_http_str; 603 } 604 605 scope = nxt_py_asgi_new_scope(req, type, nxt_py_2_1_str); 606 if (nxt_slow_path(scope == NULL)) { 607 return NULL; 608 } 609 610 p = nxt_unit_sptr_get(&r->version); 611 SET_ITEM(scope, http_version, p[7] == '1' ? nxt_py_1_1_str 612 : nxt_py_1_0_str) 613 SET_ITEM(scope, scheme, scheme) 614 615 v = PyString_FromStringAndSize(nxt_unit_sptr_get(&r->method), 616 r->method_length); 617 if (nxt_slow_path(v == NULL)) { 618 nxt_unit_req_alert(req, "Python failed to create 'method' string"); 619 goto fail; 620 } 621 622 SET_ITEM(scope, method, v) 623 Py_DECREF(v); 624 625 v = PyUnicode_DecodeUTF8(nxt_unit_sptr_get(&r->path), r->path_length, 626 "replace"); 627 if (nxt_slow_path(v == NULL)) { 628 nxt_unit_req_alert(req, "Python failed to create 'path' string"); 629 goto fail; 630 } 631 632 SET_ITEM(scope, path, v) 633 Py_DECREF(v); 634 635 target = nxt_unit_sptr_get(&r->target); 636 query = nxt_unit_sptr_get(&r->query); 637 638 if (r->query.offset != 0) { 639 target_length = query - target - 1; 640 641 } else { 642 target_length = r->target_length; 643 } 644 645 v = PyBytes_FromStringAndSize(target, target_length); 646 if (nxt_slow_path(v == NULL)) { 647 nxt_unit_req_alert(req, "Python failed to create 'raw_path' string"); 648 goto fail; 649 } 650 651 SET_ITEM(scope, raw_path, v) 652 Py_DECREF(v); 653 654 v = PyBytes_FromStringAndSize(query, r->query_length); 655 if (nxt_slow_path(v == NULL)) { 656 nxt_unit_req_alert(req, "Python failed to create 'query' string"); 657 goto fail; 658 } 659 660 SET_ITEM(scope, query_string, v) 661 Py_DECREF(v); 662 663 v = nxt_py_asgi_create_address(&r->remote, r->remote_length, 0); 664 if (nxt_slow_path(v == NULL)) { 665 nxt_unit_req_alert(req, "Python failed to create 'client' pair"); 666 goto fail; 667 } 668 669 SET_ITEM(scope, client, v) 670 Py_DECREF(v); 671 672 v = nxt_py_asgi_create_address(&r->local, r->local_length, 80); 673 if (nxt_slow_path(v == NULL)) { 674 nxt_unit_req_alert(req, "Python failed to create 'server' pair"); 675 goto fail; 676 } 677 678 SET_ITEM(scope, server, v) 679 Py_DECREF(v); 680 681 v = NULL; 682 683 headers = PyTuple_New(r->fields_count); 684 if (nxt_slow_path(headers == NULL)) { 685 nxt_unit_req_alert(req, "Python failed to create 'headers' object"); 686 goto fail; 687 } 688 689 for (i = 0; i < r->fields_count; i++) { 690 f = r->fields + i; 691 692 header = nxt_py_asgi_create_header(f); 693 if (nxt_slow_path(header == NULL)) { 694 nxt_unit_req_alert(req, "Python failed to create 'header' pair"); 695 goto fail; 696 } 697 698 PyTuple_SET_ITEM(headers, i, header); 699 700 if (f->hash == NXT_UNIT_HASH_WS_PROTOCOL 701 && f->name_length == ws_protocol.length 702 && f->value_length > 0 703 && r->websocket_handshake) 704 { 705 v = nxt_py_asgi_create_subprotocols(f); 706 if (nxt_slow_path(v == NULL)) { 707 nxt_unit_req_alert(req, "Failed to create subprotocols"); 708 goto fail; 709 } 710 711 SET_ITEM(scope, subprotocols, v); 712 Py_DECREF(v); 713 } 714 } 715 716 SET_ITEM(scope, headers, headers) 717 Py_DECREF(headers); 718 719 return scope; 720 721 fail: 722 723 Py_XDECREF(v); 724 Py_XDECREF(headers); 725 Py_DECREF(scope); 726 727 return NULL; 728 729 #undef SET_ITEM 730 } 731 732 733 static PyObject * 734 nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) 735 { 736 char *p, *s; 737 PyObject *pair, *v; 738 739 pair = PyTuple_New(2); 740 if (nxt_slow_path(pair == NULL)) { 741 return NULL; 742 } 743 744 p = nxt_unit_sptr_get(sptr); 745 s = memchr(p, ':', len); 746 747 v = PyString_FromStringAndSize(p, s == NULL ? len : s - p); 748 if (nxt_slow_path(v == NULL)) { 749 Py_DECREF(pair); 750 751 return NULL; 752 } 753 754 PyTuple_SET_ITEM(pair, 0, v); 755 756 if (s != NULL) { 757 p += len; 758 v = PyLong_FromString(s + 1, &p, 10); 759 760 } else { 761 v = PyLong_FromLong(port); 762 } 763 764 if (nxt_slow_path(v == NULL)) { 765 Py_DECREF(pair); 766 767 return NULL; 768 } 769 770 PyTuple_SET_ITEM(pair, 1, v); 771 772 return pair; 773 } 774 775 776 static PyObject * 777 nxt_py_asgi_create_header(nxt_unit_field_t *f) 778 { 779 char c, *name; 780 uint8_t pos; 781 PyObject *header, *v; 782 783 header = PyTuple_New(2); 784 if (nxt_slow_path(header == NULL)) { 785 return NULL; 786 } 787 788 name = nxt_unit_sptr_get(&f->name); 789 790 for (pos = 0; pos < f->name_length; pos++) { 791 c = name[pos]; 792 if (c >= 'A' && c <= 'Z') { 793 name[pos] = (c | 0x20); 794 } 795 } 796 797 v = PyBytes_FromStringAndSize(name, f->name_length); 798 if (nxt_slow_path(v == NULL)) { 799 Py_DECREF(header); 800 801 return NULL; 802 } 803 804 PyTuple_SET_ITEM(header, 0, v); 805 806 v = PyBytes_FromStringAndSize(nxt_unit_sptr_get(&f->value), 807 f->value_length); 808 if (nxt_slow_path(v == NULL)) { 809 Py_DECREF(header); 810 811 return NULL; 812 } 813 814 PyTuple_SET_ITEM(header, 1, v); 815 816 return header; 817 } 818 819 820 static PyObject * 821 nxt_py_asgi_create_subprotocols(nxt_unit_field_t *f) 822 { 823 char *v; 824 uint32_t i, n, start; 825 PyObject *res, *proto; 826 827 v = nxt_unit_sptr_get(&f->value); 828 n = 1; 829 830 for (i = 0; i < f->value_length; i++) { 831 if (v[i] == ',') { 832 n++; 833 } 834 } 835 836 res = PyTuple_New(n); 837 if (nxt_slow_path(res == NULL)) { 838 return NULL; 839 } 840 841 n = 0; 842 start = 0; 843 844 for (i = 0; i < f->value_length; ) { 845 if (v[i] != ',') { 846 i++; 847 848 continue; 849 } 850 851 if (i - start > 0) { 852 proto = PyString_FromStringAndSize(v + start, i - start); 853 if (nxt_slow_path(proto == NULL)) { 854 goto fail; 855 } 856 857 PyTuple_SET_ITEM(res, n, proto); 858 859 n++; 860 } 861 862 do { 863 i++; 864 } while (i < f->value_length && v[i] == ' '); 865 866 start = i; 867 } 868 869 if (i - start > 0) { 870 proto = PyString_FromStringAndSize(v + start, i - start); 871 if (nxt_slow_path(proto == NULL)) { 872 goto fail; 873 } 874 875 PyTuple_SET_ITEM(res, n, proto); 876 } 877 878 return res; 879 880 fail: 881 882 Py_DECREF(res); 883 884 return NULL; 885 } 886 887 888 static int 889 nxt_python_asgi_ready(nxt_unit_ctx_t *ctx) 890 { 891 int rc; 892 PyObject *res, *fd, *py_ctx, *py_port; 893 nxt_unit_port_t *port; 894 nxt_py_asgi_ctx_data_t *ctx_data; 895 896 if (nxt_slow_path(nxt_py_shared_port == NULL)) { 897 return NXT_UNIT_ERROR; 898 } 899 900 port = nxt_py_shared_port; 901 902 nxt_unit_debug(ctx, "asgi_ready %d %p %p", port->in_fd, ctx, port); 903 904 ctx_data = ctx->data; 905 906 rc = NXT_UNIT_ERROR; 907 908 fd = PyLong_FromLong(port->in_fd); 909 if (nxt_slow_path(fd == NULL)) { 910 nxt_unit_alert(ctx, "Python failed to create fd"); 911 nxt_python_print_exception(); 912 913 return rc; 914 } 915 916 py_ctx = PyLong_FromVoidPtr(ctx); 917 if (nxt_slow_path(py_ctx == NULL)) { 918 nxt_unit_alert(ctx, "Python failed to create py_ctx"); 919 nxt_python_print_exception(); 920 921 goto clean_fd; 922 } 923 924 py_port = PyLong_FromVoidPtr(port); 925 if (nxt_slow_path(py_port == NULL)) { 926 nxt_unit_alert(ctx, "Python failed to create py_port"); 927 nxt_python_print_exception(); 928 929 goto clean_py_ctx; 930 } 931 932 res = PyObject_CallFunctionObjArgs(ctx_data->loop_add_reader, 933 fd, nxt_py_port_read, 934 py_ctx, py_port, NULL); 935 if (nxt_slow_path(res == NULL)) { 936 nxt_unit_alert(ctx, "Python failed to add_reader"); 937 nxt_python_print_exception(); 938 939 } else { 940 Py_DECREF(res); 941 942 rc = NXT_UNIT_OK; 943 } 944 945 Py_DECREF(py_port); 946 947 clean_py_ctx: 948 949 Py_DECREF(py_ctx); 950 951 clean_fd: 952 953 Py_DECREF(fd); 954 955 return rc; 956 } 957 958 959 static int 960 nxt_py_asgi_add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 961 { 962 int nb, rc; 963 PyObject *res, *fd, *py_ctx, *py_port; 964 nxt_py_asgi_ctx_data_t *ctx_data; 965 966 if (port->in_fd == -1) { 967 return NXT_UNIT_OK; 968 } 969 970 nb = 1; 971 972 if (nxt_slow_path(ioctl(port->in_fd, FIONBIO, &nb) == -1)) { 973 nxt_unit_alert(ctx, "ioctl(%d, FIONBIO, 0) failed: %s (%d)", 974 port->in_fd, strerror(errno), errno); 975 976 return NXT_UNIT_ERROR; 977 } 978 979 nxt_unit_debug(ctx, "asgi_add_port %d %p %p", port->in_fd, ctx, port); 980 981 if (port->id.id == NXT_UNIT_SHARED_PORT_ID) { 982 nxt_py_shared_port = port; 983 984 return NXT_UNIT_OK; 985 } 986 987 ctx_data = ctx->data; 988 989 ctx_data->port = port; 990 port->data = ctx_data; 991 992 rc = NXT_UNIT_ERROR; 993 994 fd = PyLong_FromLong(port->in_fd); 995 if (nxt_slow_path(fd == NULL)) { 996 nxt_unit_alert(ctx, "Python failed to create fd"); 997 nxt_python_print_exception(); 998 999 return rc; 1000 } 1001 1002 py_ctx = PyLong_FromVoidPtr(ctx); 1003 if (nxt_slow_path(py_ctx == NULL)) { 1004 nxt_unit_alert(ctx, "Python failed to create py_ctx"); 1005 nxt_python_print_exception(); 1006 1007 goto clean_fd; 1008 } 1009 1010 py_port = PyLong_FromVoidPtr(port); 1011 if (nxt_slow_path(py_port == NULL)) { 1012 nxt_unit_alert(ctx, "Python failed to create py_port"); 1013 nxt_python_print_exception(); 1014 1015 goto clean_py_ctx; 1016 } 1017 1018 res = PyObject_CallFunctionObjArgs(ctx_data->loop_add_reader, 1019 fd, nxt_py_port_read, 1020 py_ctx, py_port, NULL); 1021 if (nxt_slow_path(res == NULL)) { 1022 nxt_unit_alert(ctx, "Python failed to add_reader"); 1023 nxt_python_print_exception(); 1024 1025 } else { 1026 Py_DECREF(res); 1027 1028 rc = NXT_UNIT_OK; 1029 } 1030 1031 Py_DECREF(py_port); 1032 1033 clean_py_ctx: 1034 1035 Py_DECREF(py_ctx); 1036 1037 clean_fd: 1038 1039 Py_DECREF(fd); 1040 1041 return rc; 1042 } 1043 1044 1045 static void 1046 nxt_py_asgi_remove_port(nxt_unit_t *lib, nxt_unit_port_t *port) 1047 { 1048 if (port->in_fd == -1) { 1049 return; 1050 } 1051 1052 nxt_unit_debug(NULL, "asgi_remove_port %d %p", port->in_fd, port); 1053 1054 if (nxt_py_shared_port == port) { 1055 nxt_py_shared_port = NULL; 1056 } 1057 } 1058 1059 1060 static void 1061 nxt_py_asgi_quit(nxt_unit_ctx_t *ctx) 1062 { 1063 PyObject *res, *p; 1064 nxt_py_asgi_ctx_data_t *ctx_data; 1065 1066 nxt_unit_debug(ctx, "asgi_quit %p", ctx); 1067 1068 ctx_data = ctx->data; 1069 1070 if (nxt_py_shared_port != NULL) { 1071 p = PyLong_FromLong(nxt_py_shared_port->in_fd); 1072 if (nxt_slow_path(p == NULL)) { 1073 nxt_unit_alert(NULL, "Python failed to create Long"); 1074 nxt_python_print_exception(); 1075 1076 } else { 1077 res = PyObject_CallFunctionObjArgs(ctx_data->loop_remove_reader, 1078 p, NULL); 1079 if (nxt_slow_path(res == NULL)) { 1080 nxt_unit_alert(NULL, "Python failed to remove_reader"); 1081 nxt_python_print_exception(); 1082 1083 } else { 1084 Py_DECREF(res); 1085 } 1086 1087 Py_DECREF(p); 1088 } 1089 } 1090 1091 p = PyLong_FromLong(0); 1092 if (nxt_slow_path(p == NULL)) { 1093 nxt_unit_alert(NULL, "Python failed to create Long"); 1094 nxt_python_print_exception(); 1095 1096 } else { 1097 res = PyObject_CallFunctionObjArgs(ctx_data->quit_future_set_result, 1098 p, NULL); 1099 if (nxt_slow_path(res == NULL)) { 1100 nxt_unit_alert(ctx, "Python failed to set_result"); 1101 nxt_python_print_exception(); 1102 1103 } else { 1104 Py_DECREF(res); 1105 } 1106 1107 Py_DECREF(p); 1108 } 1109 } 1110 1111 1112 static void 1113 nxt_py_asgi_shm_ack_handler(nxt_unit_ctx_t *ctx) 1114 { 1115 int rc; 1116 nxt_queue_link_t *lnk; 1117 nxt_py_asgi_ctx_data_t *ctx_data; 1118 1119 ctx_data = ctx->data; 1120 1121 while (!nxt_queue_is_empty(&ctx_data->drain_queue)) { 1122 lnk = nxt_queue_first(&ctx_data->drain_queue); 1123 1124 rc = nxt_py_asgi_http_drain(lnk); 1125 if (rc == NXT_UNIT_AGAIN) { 1126 return; 1127 } 1128 1129 nxt_queue_remove(lnk); 1130 } 1131 } 1132 1133 1134 static PyObject * 1135 nxt_py_asgi_port_read(PyObject *self, PyObject *args) 1136 { 1137 int rc; 1138 PyObject *arg0, *arg1, *res; 1139 Py_ssize_t n; 1140 nxt_unit_ctx_t *ctx; 1141 nxt_unit_port_t *port; 1142 nxt_py_asgi_ctx_data_t *ctx_data; 1143 1144 n = PyTuple_GET_SIZE(args); 1145 1146 if (n != 2) { 1147 nxt_unit_alert(NULL, 1148 "nxt_py_asgi_port_read: invalid number of arguments %d", 1149 (int) n); 1150 1151 return PyErr_Format(PyExc_TypeError, "invalid number of arguments"); 1152 } 1153 1154 arg0 = PyTuple_GET_ITEM(args, 0); 1155 if (nxt_slow_path(arg0 == NULL || PyLong_Check(arg0) == 0)) { 1156 return PyErr_Format(PyExc_TypeError, 1157 "the first argument is not a long"); 1158 } 1159 1160 ctx = PyLong_AsVoidPtr(arg0); 1161 1162 arg1 = PyTuple_GET_ITEM(args, 1); 1163 if (nxt_slow_path(arg1 == NULL || PyLong_Check(arg1) == 0)) { 1164 return PyErr_Format(PyExc_TypeError, 1165 "the second argument is not a long"); 1166 } 1167 1168 port = PyLong_AsVoidPtr(arg1); 1169 1170 rc = nxt_unit_process_port_msg(ctx, port); 1171 1172 nxt_unit_debug(ctx, "asgi_port_read(%p,%p): %d", ctx, port, rc); 1173 1174 if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { 1175 return PyErr_Format(PyExc_RuntimeError, 1176 "error processing port %d message", port->id.id); 1177 } 1178 1179 if (rc == NXT_UNIT_OK) { 1180 ctx_data = ctx->data; 1181 1182 res = PyObject_CallFunctionObjArgs(ctx_data->loop_call_soon, 1183 nxt_py_port_read, 1184 arg0, arg1, NULL); 1185 if (nxt_slow_path(res == NULL)) { 1186 nxt_unit_alert(ctx, "Python failed to call 'loop.call_soon'"); 1187 nxt_python_print_exception(); 1188 } 1189 1190 Py_XDECREF(res); 1191 } 1192 1193 Py_RETURN_NONE; 1194 } 1195 1196 1197 PyObject * 1198 nxt_py_asgi_enum_headers(PyObject *headers, nxt_py_asgi_enum_header_cb cb, 1199 void *data) 1200 { 1201 int i; 1202 PyObject *iter, *header, *h_iter, *name, *val, *res; 1203 1204 iter = PyObject_GetIter(headers); 1205 if (nxt_slow_path(iter == NULL)) { 1206 return PyErr_Format(PyExc_TypeError, "'headers' is not an iterable"); 1207 } 1208 1209 for (i = 0; /* void */; i++) { 1210 header = PyIter_Next(iter); 1211 if (header == NULL) { 1212 break; 1213 } 1214 1215 h_iter = PyObject_GetIter(header); 1216 if (nxt_slow_path(h_iter == NULL)) { 1217 Py_DECREF(header); 1218 Py_DECREF(iter); 1219 1220 return PyErr_Format(PyExc_TypeError, 1221 "'headers' item #%d is not an iterable", i); 1222 } 1223 1224 name = PyIter_Next(h_iter); 1225 if (nxt_slow_path(name == NULL || !PyBytes_Check(name))) { 1226 Py_XDECREF(name); 1227 Py_DECREF(h_iter); 1228 Py_DECREF(header); 1229 Py_DECREF(iter); 1230 1231 return PyErr_Format(PyExc_TypeError, 1232 "'headers' item #%d 'name' is not a byte string", i); 1233 } 1234 1235 val = PyIter_Next(h_iter); 1236 if (nxt_slow_path(val == NULL || !PyBytes_Check(val))) { 1237 Py_XDECREF(val); 1238 Py_DECREF(h_iter); 1239 Py_DECREF(header); 1240 Py_DECREF(iter); 1241 1242 return PyErr_Format(PyExc_TypeError, 1243 "'headers' item #%d 'value' is not a byte string", i); 1244 } 1245 1246 res = cb(data, i, name, val); 1247 1248 Py_DECREF(name); 1249 Py_DECREF(val); 1250 Py_DECREF(h_iter); 1251 Py_DECREF(header); 1252 1253 if (nxt_slow_path(res == NULL)) { 1254 Py_DECREF(iter); 1255 1256 return NULL; 1257 } 1258 1259 Py_DECREF(res); 1260 } 1261 1262 Py_DECREF(iter); 1263 1264 Py_RETURN_NONE; 1265 } 1266 1267 1268 PyObject * 1269 nxt_py_asgi_calc_size(void *data, int i, PyObject *name, PyObject *val) 1270 { 1271 nxt_py_asgi_calc_size_ctx_t *ctx; 1272 1273 ctx = data; 1274 1275 ctx->fields_count++; 1276 ctx->fields_size += PyBytes_GET_SIZE(name) + PyBytes_GET_SIZE(val); 1277 1278 Py_RETURN_NONE; 1279 } 1280 1281 1282 PyObject * 1283 nxt_py_asgi_add_field(void *data, int i, PyObject *name, PyObject *val) 1284 { 1285 int rc; 1286 char *name_str, *val_str; 1287 uint32_t name_len, val_len; 1288 nxt_off_t content_length; 1289 nxt_unit_request_info_t *req; 1290 nxt_py_asgi_add_field_ctx_t *ctx; 1291 1292 name_str = PyBytes_AS_STRING(name); 1293 name_len = PyBytes_GET_SIZE(name); 1294 1295 val_str = PyBytes_AS_STRING(val); 1296 val_len = PyBytes_GET_SIZE(val); 1297 1298 ctx = data; 1299 req = ctx->req; 1300 1301 rc = nxt_unit_response_add_field(req, name_str, name_len, 1302 val_str, val_len); 1303 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 1304 return PyErr_Format(PyExc_RuntimeError, 1305 "failed to add header #%d", i); 1306 } 1307 1308 if (req->response->fields[i].hash == NXT_UNIT_HASH_CONTENT_LENGTH) { 1309 content_length = nxt_off_t_parse((u_char *) val_str, val_len); 1310 if (nxt_slow_path(content_length < 0)) { 1311 nxt_unit_req_error(req, "failed to parse Content-Length " 1312 "value %.*s", (int) val_len, val_str); 1313 1314 return PyErr_Format(PyExc_ValueError, 1315 "Failed to parse Content-Length: '%.*s'", 1316 (int) val_len, val_str); 1317 } 1318 1319 ctx->content_length = content_length; 1320 } 1321 1322 Py_RETURN_NONE; 1323 } 1324 1325 1326 PyObject * 1327 nxt_py_asgi_set_result_soon(nxt_unit_request_info_t *req, 1328 nxt_py_asgi_ctx_data_t *ctx_data, PyObject *future, PyObject *result) 1329 { 1330 PyObject *set_result, *res; 1331 1332 if (nxt_slow_path(result == NULL)) { 1333 Py_DECREF(future); 1334 1335 return NULL; 1336 } 1337 1338 set_result = PyObject_GetAttrString(future, "set_result"); 1339 if (nxt_slow_path(set_result == NULL)) { 1340 nxt_unit_req_alert(req, "failed to get 'set_result' for future"); 1341 1342 Py_CLEAR(future); 1343 1344 goto cleanup_result; 1345 } 1346 1347 if (nxt_slow_path(PyCallable_Check(set_result) == 0)) { 1348 nxt_unit_req_alert(req, "'future.set_result' is not a callable"); 1349 1350 Py_CLEAR(future); 1351 1352 goto cleanup; 1353 } 1354 1355 res = PyObject_CallFunctionObjArgs(ctx_data->loop_call_soon, set_result, 1356 result, NULL); 1357 if (nxt_slow_path(res == NULL)) { 1358 nxt_unit_req_alert(req, "Python failed to call 'loop.call_soon'"); 1359 nxt_python_print_exception(); 1360 1361 Py_CLEAR(future); 1362 } 1363 1364 Py_XDECREF(res); 1365 1366 cleanup: 1367 1368 Py_DECREF(set_result); 1369 1370 cleanup_result: 1371 1372 Py_DECREF(result); 1373 1374 return future; 1375 } 1376 1377 1378 PyObject * 1379 nxt_py_asgi_new_msg(nxt_unit_request_info_t *req, PyObject *type) 1380 { 1381 PyObject *msg; 1382 1383 msg = PyDict_New(); 1384 if (nxt_slow_path(msg == NULL)) { 1385 nxt_unit_req_alert(req, "Python failed to create message dict"); 1386 nxt_python_print_exception(); 1387 1388 return PyErr_Format(PyExc_RuntimeError, 1389 "failed to create message dict"); 1390 } 1391 1392 if (nxt_slow_path(PyDict_SetItem(msg, nxt_py_type_str, type) == -1)) { 1393 nxt_unit_req_alert(req, "Python failed to set 'msg.type' item"); 1394 1395 Py_DECREF(msg); 1396 1397 return PyErr_Format(PyExc_RuntimeError, 1398 "failed to set 'msg.type' item"); 1399 } 1400 1401 return msg; 1402 } 1403 1404 1405 PyObject * 1406 nxt_py_asgi_new_scope(nxt_unit_request_info_t *req, PyObject *type, 1407 PyObject *spec_version) 1408 { 1409 PyObject *scope, *asgi; 1410 1411 scope = PyDict_New(); 1412 if (nxt_slow_path(scope == NULL)) { 1413 nxt_unit_req_alert(req, "Python failed to create 'scope' dict"); 1414 nxt_python_print_exception(); 1415 1416 return PyErr_Format(PyExc_RuntimeError, 1417 "failed to create 'scope' dict"); 1418 } 1419 1420 if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_type_str, type) == -1)) { 1421 nxt_unit_req_alert(req, "Python failed to set 'scope.type' item"); 1422 1423 Py_DECREF(scope); 1424 1425 return PyErr_Format(PyExc_RuntimeError, 1426 "failed to set 'scope.type' item"); 1427 } 1428 1429 asgi = PyDict_New(); 1430 if (nxt_slow_path(asgi == NULL)) { 1431 nxt_unit_req_alert(req, "Python failed to create 'asgi' dict"); 1432 nxt_python_print_exception(); 1433 1434 Py_DECREF(scope); 1435 1436 return PyErr_Format(PyExc_RuntimeError, 1437 "failed to create 'asgi' dict"); 1438 } 1439 1440 if (nxt_slow_path(PyDict_SetItem(scope, nxt_py_asgi_str, asgi) == -1)) { 1441 nxt_unit_req_alert(req, "Python failed to set 'scope.asgi' item"); 1442 1443 Py_DECREF(asgi); 1444 Py_DECREF(scope); 1445 1446 return PyErr_Format(PyExc_RuntimeError, 1447 "failed to set 'scope.asgi' item"); 1448 } 1449 1450 if (nxt_slow_path(PyDict_SetItem(asgi, nxt_py_version_str, 1451 nxt_py_3_0_str) == -1)) 1452 { 1453 nxt_unit_req_alert(req, "Python failed to set 'asgi.version' item"); 1454 1455 Py_DECREF(asgi); 1456 Py_DECREF(scope); 1457 1458 return PyErr_Format(PyExc_RuntimeError, 1459 "failed to set 'asgi.version' item"); 1460 } 1461 1462 if (nxt_slow_path(PyDict_SetItem(asgi, nxt_py_spec_version_str, 1463 spec_version) == -1)) 1464 { 1465 nxt_unit_req_alert(req, 1466 "Python failed to set 'asgi.spec_version' item"); 1467 1468 Py_DECREF(asgi); 1469 Py_DECREF(scope); 1470 1471 return PyErr_Format(PyExc_RuntimeError, 1472 "failed to set 'asgi.spec_version' item"); 1473 } 1474 1475 Py_DECREF(asgi); 1476 1477 return scope; 1478 } 1479 1480 1481 void 1482 nxt_py_asgi_drain_wait(nxt_unit_request_info_t *req, nxt_queue_link_t *link) 1483 { 1484 nxt_py_asgi_ctx_data_t *ctx_data; 1485 1486 ctx_data = req->ctx->data; 1487 1488 nxt_queue_insert_tail(&ctx_data->drain_queue, link); 1489 } 1490 1491 1492 void 1493 nxt_py_asgi_dealloc(PyObject *self) 1494 { 1495 PyObject_Del(self); 1496 } 1497 1498 1499 PyObject * 1500 nxt_py_asgi_await(PyObject *self) 1501 { 1502 Py_INCREF(self); 1503 return self; 1504 } 1505 1506 1507 PyObject * 1508 nxt_py_asgi_iter(PyObject *self) 1509 { 1510 Py_INCREF(self); 1511 return self; 1512 } 1513 1514 1515 PyObject * 1516 nxt_py_asgi_next(PyObject *self) 1517 { 1518 return NULL; 1519 } 1520 1521 1522 static void 1523 nxt_python_asgi_done(void) 1524 { 1525 nxt_py_asgi_str_done(); 1526 1527 Py_XDECREF(nxt_py_port_read); 1528 } 1529 1530 #else /* !(NXT_HAVE_ASGI) */ 1531 1532 1533 int 1534 nxt_python_asgi_check(PyObject *obj) 1535 { 1536 return 0; 1537 } 1538 1539 1540 int 1541 nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto) 1542 { 1543 nxt_unit_alert(NULL, "ASGI not implemented"); 1544 return NXT_UNIT_ERROR; 1545 } 1546 1547 1548 #endif /* NXT_HAVE_ASGI */ 1549