1 2 /* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 #include "unit.h" 7 8 #include <unistd.h> 9 #include <fcntl.h> 10 11 #include <uv.h> 12 13 14 napi_ref Unit::constructor_; 15 16 17 Unit::Unit(napi_env env): 18 env_(env), 19 wrapper_(nullptr), 20 unit_ctx_(nullptr) 21 { 22 } 23 24 25 Unit::~Unit() 26 { 27 napi_delete_reference(env_, wrapper_); 28 } 29 30 31 napi_value 32 Unit::init(napi_env env, napi_value exports) 33 { 34 napi_value cons, fn; 35 napi_status status; 36 37 napi_property_descriptor properties[] = { 38 { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, 39 { "listen", 0, listen, 0, 0, 0, napi_default, 0 }, 40 { "_read", 0, _read, 0, 0, 0, napi_default, 0 } 41 }; 42 43 status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr, 44 3, properties, &cons); 45 if (status != napi_ok) { 46 goto failed; 47 } 48 49 status = napi_create_reference(env, cons, 1, &constructor_); 50 if (status != napi_ok) { 51 goto failed; 52 } 53 54 status = napi_set_named_property(env, exports, "Unit", cons); 55 if (status != napi_ok) { 56 goto failed; 57 } 58 59 status = napi_create_function(env, NULL, 0, response_send_headers, NULL, 60 &fn); 61 if (status != napi_ok) { 62 goto failed; 63 } 64 65 status = napi_set_named_property(env, exports, 66 "unit_response_headers", fn); 67 if (status != napi_ok) { 68 goto failed; 69 } 70 71 status = napi_create_function(env, NULL, 0, response_write, NULL, &fn); 72 if (status != napi_ok) { 73 goto failed; 74 } 75 76 status = napi_set_named_property(env, exports, "unit_response_write", fn); 77 if (status != napi_ok) { 78 goto failed; 79 } 80 81 status = napi_create_function(env, NULL, 0, response_end, NULL, &fn); 82 if (status != napi_ok) { 83 goto failed; 84 } 85 86 status = napi_set_named_property(env, exports, "unit_response_end", fn); 87 if (status != napi_ok) { 88 goto failed; 89 } 90 91 return exports; 92 93 failed: 94 95 napi_throw_error(env, NULL, "Failed to define Unit class"); 96 97 return nullptr; 98 } 99 100 101 void 102 Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) 103 { 104 Unit *obj = reinterpret_cast<Unit *>(nativeObject); 105 106 delete obj; 107 } 108 109 110 napi_value 111 Unit::create(napi_env env, napi_callback_info info) 112 { 113 Unit *obj; 114 napi_ref ref; 115 napi_value target, cons, instance, jsthis; 116 napi_status status; 117 118 status = napi_get_new_target(env, info, &target); 119 if (status != napi_ok) { 120 goto failed; 121 } 122 123 if (target != nullptr) { 124 /* Invoked as constructor: `new Unit(...)` */ 125 status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, 126 nullptr); 127 if (status != napi_ok) { 128 goto failed; 129 } 130 131 obj = new Unit(env); 132 133 status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj), 134 destroy, nullptr, &obj->wrapper_); 135 if (status != napi_ok) { 136 goto failed; 137 } 138 139 status = napi_create_reference(env, jsthis, 1, &ref); 140 if (status != napi_ok) { 141 goto failed; 142 } 143 144 return jsthis; 145 } 146 147 /* Invoked as plain function `Unit(...)`, turn into construct call. */ 148 status = napi_get_reference_value(env, constructor_, &cons); 149 if (status != napi_ok) { 150 goto failed; 151 } 152 153 status = napi_new_instance(env, cons, 0, nullptr, &instance); 154 if (status != napi_ok) { 155 goto failed; 156 } 157 158 status = napi_create_reference(env, instance, 1, &ref); 159 if (status != napi_ok) { 160 goto failed; 161 } 162 163 return instance; 164 165 failed: 166 167 napi_throw_error(env, NULL, "Failed to create Unit object"); 168 169 return nullptr; 170 } 171 172 173 napi_value 174 Unit::create_server(napi_env env, napi_callback_info info) 175 { 176 Unit *obj; 177 size_t argc; 178 napi_value jsthis, argv; 179 napi_status status; 180 nxt_unit_init_t unit_init; 181 182 argc = 1; 183 184 status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); 185 if (status != napi_ok) { 186 goto failed; 187 } 188 189 status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); 190 if (status != napi_ok) { 191 goto failed; 192 } 193 194 memset(&unit_init, 0, sizeof(nxt_unit_init_t)); 195 196 unit_init.data = obj; 197 unit_init.callbacks.request_handler = request_handler; 198 unit_init.callbacks.add_port = add_port; 199 unit_init.callbacks.remove_port = remove_port; 200 201 obj->unit_ctx_ = nxt_unit_init(&unit_init); 202 if (obj->unit_ctx_ == NULL) { 203 goto failed; 204 } 205 206 return nullptr; 207 208 failed: 209 210 napi_throw_error(env, NULL, "Failed to create Unit object"); 211 212 return nullptr; 213 } 214 215 216 napi_value 217 Unit::listen(napi_env env, napi_callback_info info) 218 { 219 return nullptr; 220 } 221 222 223 napi_value 224 Unit::_read(napi_env env, napi_callback_info info) 225 { 226 Unit *obj; 227 void *data; 228 size_t argc; 229 int64_t req_pointer; 230 napi_value jsthis, buffer, argv; 231 napi_status status; 232 nxt_unit_request_info_t *req; 233 234 argc = 1; 235 236 status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); 237 if (status != napi_ok) { 238 napi_throw_error(env, NULL, "Failed to get arguments from js"); 239 return nullptr; 240 } 241 242 status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); 243 if (status != napi_ok) { 244 napi_throw_error(env, NULL, "Failed to get Unit object form js"); 245 return nullptr; 246 } 247 248 status = napi_get_value_int64(env, argv, &req_pointer); 249 if (status != napi_ok) { 250 napi_throw_error(env, NULL, "Failed to get request pointer"); 251 return nullptr; 252 } 253 254 req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer; 255 256 status = napi_create_buffer(env, (size_t) req->content_length, 257 &data, &buffer); 258 if (status != napi_ok) { 259 napi_throw_error(env, NULL, "Failed to create request buffer"); 260 return nullptr; 261 } 262 263 nxt_unit_request_read(req, data, req->content_length); 264 265 return buffer; 266 } 267 268 269 void 270 Unit::request_handler(nxt_unit_request_info_t *req) 271 { 272 Unit *obj; 273 napi_value socket, request, response; 274 napi_value global, server_obj; 275 napi_value run_events, events_res; 276 napi_status status; 277 napi_value events_args[3]; 278 279 obj = reinterpret_cast<Unit *>(req->unit->data); 280 281 napi_handle_scope scope; 282 status = napi_open_handle_scope(obj->env_, &scope); 283 if (status != napi_ok) { 284 napi_throw_error(obj->env_, NULL, "Failed to create handle scope"); 285 return; 286 } 287 288 server_obj = obj->get_server_object(); 289 if (server_obj == nullptr) { 290 napi_throw_error(obj->env_, NULL, "Failed to get server object"); 291 return; 292 } 293 294 status = napi_get_global(obj->env_, &global); 295 if (status != napi_ok) { 296 napi_throw_error(obj->env_, NULL, "Failed to get global variable"); 297 return; 298 } 299 300 socket = obj->create_socket(server_obj, req); 301 if (socket == nullptr) { 302 napi_throw_error(obj->env_, NULL, "Failed to create socket object"); 303 return; 304 } 305 306 request = obj->create_request(server_obj, socket); 307 if (request == nullptr) { 308 napi_throw_error(obj->env_, NULL, "Failed to create request object"); 309 return; 310 } 311 312 response = obj->create_response(server_obj, socket, request, req, obj); 313 if (response == nullptr) { 314 napi_throw_error(obj->env_, NULL, "Failed to create response object"); 315 return; 316 } 317 318 status = obj->create_headers(req, request); 319 if (status != napi_ok) { 320 napi_throw_error(obj->env_, NULL, "Failed to create headers"); 321 return; 322 } 323 324 status = napi_get_named_property(obj->env_, server_obj, "run_events", 325 &run_events); 326 if (status != napi_ok) { 327 napi_throw_error(obj->env_, NULL, "Failed to get" 328 " 'run_events' function"); 329 return; 330 } 331 332 events_args[0] = server_obj; 333 events_args[1] = request; 334 events_args[2] = response; 335 336 status = napi_call_function(obj->env_, server_obj, run_events, 3, 337 events_args, &events_res); 338 if (status != napi_ok) { 339 napi_throw_error(obj->env_, NULL, "Failed to call" 340 " 'run_events' function"); 341 return; 342 } 343 344 napi_close_handle_scope(obj->env_, scope); 345 } 346 347 348 void 349 nxt_uv_read_callback(uv_poll_t *handle, int status, int events) 350 { 351 nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); 352 } 353 354 355 int 356 Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 357 { 358 int err; 359 Unit *obj; 360 uv_loop_t *loop; 361 uv_poll_t *uv_handle; 362 napi_status status; 363 364 if (port->in_fd != -1) { 365 obj = reinterpret_cast<Unit *>(ctx->unit->data); 366 367 if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { 368 napi_throw_error(obj->env_, NULL, "Failed to upgrade read" 369 " file descriptor to O_NONBLOCK"); 370 return -1; 371 } 372 373 status = napi_get_uv_event_loop(obj->env_, &loop); 374 if (status != napi_ok) { 375 napi_throw_error(obj->env_, NULL, "Failed to get uv.loop"); 376 return NXT_UNIT_ERROR; 377 } 378 379 uv_handle = new uv_poll_t; 380 381 err = uv_poll_init(loop, uv_handle, port->in_fd); 382 if (err < 0) { 383 napi_throw_error(obj->env_, NULL, "Failed to init uv.poll"); 384 return NXT_UNIT_ERROR; 385 } 386 387 err = uv_poll_start(uv_handle, UV_READABLE, nxt_uv_read_callback); 388 if (err < 0) { 389 napi_throw_error(obj->env_, NULL, "Failed to start uv.poll"); 390 return NXT_UNIT_ERROR; 391 } 392 393 port->data = uv_handle; 394 uv_handle->data = ctx; 395 } 396 397 return nxt_unit_add_port(ctx, port); 398 } 399 400 401 void 402 Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) 403 { 404 nxt_unit_port_t *port; 405 406 port = nxt_unit_find_port(ctx, port_id); 407 if (port == NULL) { 408 return; 409 } 410 411 if (port->in_fd != -1 && port->data != NULL) { 412 uv_poll_stop((uv_poll_t *) port->data); 413 414 delete (uv_poll_t *) port->data; 415 } 416 417 nxt_unit_remove_port(ctx, port_id); 418 } 419 420 421 napi_value 422 Unit::get_server_object() 423 { 424 napi_value unit_obj, server_obj; 425 napi_status status; 426 427 status = napi_get_reference_value(env_, wrapper_, &unit_obj); 428 if (status != napi_ok) { 429 return nullptr; 430 } 431 432 status = napi_get_named_property(env_, unit_obj, "server", &server_obj); 433 if (status != napi_ok) { 434 return nullptr; 435 } 436 437 return server_obj; 438 } 439 440 441 napi_status 442 Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) 443 { 444 uint32_t i; 445 const char *p; 446 napi_value headers, raw_headers, str; 447 napi_status status; 448 nxt_unit_field_t *f; 449 nxt_unit_request_t *r; 450 451 r = req->request; 452 453 status = napi_create_object(env_, &headers); 454 if (status != napi_ok) { 455 return status; 456 } 457 458 status = napi_create_array_with_length(env_, r->fields_count * 2, 459 &raw_headers); 460 if (status != napi_ok) { 461 return status; 462 } 463 464 for (i = 0; i < r->fields_count; i++) { 465 f = r->fields + i; 466 467 status = this->append_header(f, headers, raw_headers, i); 468 if (status != napi_ok) { 469 return status; 470 } 471 } 472 473 status = napi_set_named_property(env_, request, "headers", headers); 474 if (status != napi_ok) { 475 return status; 476 } 477 478 status = napi_set_named_property(env_, request, "rawHeaders", raw_headers); 479 if (status != napi_ok) { 480 return status; 481 } 482 483 p = (const char *) nxt_unit_sptr_get(&r->version); 484 485 status = napi_create_string_latin1(env_, p, r->version_length, &str); 486 if (status != napi_ok) { 487 return status; 488 } 489 490 status = napi_set_named_property(env_, request, "httpVersion", str); 491 if (status != napi_ok) { 492 return status; 493 } 494 495 p = (const char *) nxt_unit_sptr_get(&r->method); 496 497 status = napi_create_string_latin1(env_, p, r->method_length, &str); 498 if (status != napi_ok) { 499 return status; 500 } 501 502 status = napi_set_named_property(env_, request, "method", str); 503 if (status != napi_ok) { 504 return status; 505 } 506 507 p = (const char *) nxt_unit_sptr_get(&r->target); 508 509 status = napi_create_string_latin1(env_, p, r->target_length, &str); 510 if (status != napi_ok) { 511 return status; 512 } 513 514 status = napi_set_named_property(env_, request, "url", str); 515 if (status != napi_ok) { 516 return status; 517 } 518 519 return napi_ok; 520 } 521 522 523 inline napi_status 524 Unit::append_header(nxt_unit_field_t *f, napi_value headers, 525 napi_value raw_headers, uint32_t idx) 526 { 527 const char *name, *value; 528 napi_value str, vstr; 529 napi_status status; 530 531 value = (const char *) nxt_unit_sptr_get(&f->value); 532 533 status = napi_create_string_latin1(env_, value, f->value_length, &vstr); 534 if (status != napi_ok) { 535 return status; 536 } 537 538 name = (const char *) nxt_unit_sptr_get(&f->name); 539 540 status = napi_set_named_property(env_, headers, name, vstr); 541 if (status != napi_ok) { 542 return status; 543 } 544 545 status = napi_create_string_latin1(env_, name, f->name_length, &str); 546 if (status != napi_ok) { 547 return status; 548 } 549 550 status = napi_set_element(env_, raw_headers, idx * 2, str); 551 if (status != napi_ok) { 552 return status; 553 } 554 555 status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr); 556 if (status != napi_ok) { 557 return status; 558 } 559 560 return napi_ok; 561 } 562 563 564 napi_value 565 Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) 566 { 567 napi_value constructor, return_val, req_pointer; 568 napi_status status; 569 570 status = napi_get_named_property(env_, server_obj, "socket", 571 &constructor); 572 if (status != napi_ok) { 573 return nullptr; 574 } 575 576 status = napi_new_instance(env_, constructor, 0, NULL, &return_val); 577 if (status != napi_ok) { 578 return nullptr; 579 } 580 581 status = napi_create_int64(env_, (uintptr_t) req, &req_pointer); 582 if (status != napi_ok) { 583 return nullptr; 584 } 585 586 status = napi_set_named_property(env_, return_val, "req_pointer", 587 req_pointer); 588 if (status != napi_ok) { 589 return nullptr; 590 } 591 592 return return_val; 593 } 594 595 596 napi_value 597 Unit::create_request(napi_value server_obj, napi_value socket) 598 { 599 napi_value constructor, return_val; 600 napi_status status; 601 602 status = napi_get_named_property(env_, server_obj, "request", 603 &constructor); 604 if (status != napi_ok) { 605 return nullptr; 606 } 607 608 status = napi_new_instance(env_, constructor, 1, &server_obj, 609 &return_val); 610 if (status != napi_ok) { 611 return nullptr; 612 } 613 614 status = napi_set_named_property(env_, return_val, "socket", socket); 615 if (status != napi_ok) { 616 return nullptr; 617 } 618 619 return return_val; 620 } 621 622 623 napi_value 624 Unit::create_response(napi_value server_obj, napi_value socket, 625 napi_value request, nxt_unit_request_info_t *req, 626 Unit *obj) 627 { 628 napi_value constructor, return_val, req_num; 629 napi_status status; 630 631 status = napi_get_named_property(env_, server_obj, "response", 632 &constructor); 633 if (status != napi_ok) { 634 return nullptr; 635 } 636 637 status = napi_new_instance(env_, constructor, 1, &request, &return_val); 638 if (status != napi_ok) { 639 return nullptr; 640 } 641 642 status = napi_set_named_property(env_, return_val, "socket", socket); 643 if (status != napi_ok) { 644 return nullptr; 645 } 646 647 status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num); 648 if (status != napi_ok) { 649 return nullptr; 650 } 651 652 status = napi_set_named_property(env_, return_val, "_req_point", req_num); 653 if (status != napi_ok) { 654 return nullptr; 655 } 656 657 return return_val; 658 } 659 660 661 napi_value 662 Unit::response_send_headers(napi_env env, napi_callback_info info) 663 { 664 int ret; 665 char *ptr, *name_ptr; 666 bool is_array; 667 size_t argc, name_len, value_len; 668 int64_t req_p; 669 uint32_t status_code, header_len, keys_len, array_len; 670 uint32_t keys_count, i, j; 671 uint16_t hash; 672 napi_value this_arg, headers, keys, name, value, array_val; 673 napi_value req_num; 674 napi_status status; 675 nxt_unit_field_t *f; 676 nxt_unit_request_info_t *req; 677 napi_value argv[5]; 678 679 argc = 5; 680 681 status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); 682 if (status != napi_ok) { 683 return nullptr; 684 } 685 686 if (argc != 5) { 687 napi_throw_error(env, NULL, "Wrong args count. Need three: " 688 "statusCode, headers, headers count, headers length"); 689 return nullptr; 690 } 691 692 status = napi_get_named_property(env, argv[0], "_req_point", &req_num); 693 if (status != napi_ok) { 694 napi_throw_error(env, NULL, "Failed to get request pointer"); 695 return nullptr; 696 } 697 698 status = napi_get_value_int64(env, req_num, &req_p); 699 if (status != napi_ok) { 700 napi_throw_error(env, NULL, "Failed to get request pointer"); 701 return nullptr; 702 } 703 704 req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 705 706 status = napi_get_value_uint32(env, argv[1], &status_code); 707 if (status != napi_ok) { 708 goto failed; 709 } 710 711 status = napi_get_value_uint32(env, argv[3], &keys_count); 712 if (status != napi_ok) { 713 goto failed; 714 } 715 716 status = napi_get_value_uint32(env, argv[4], &header_len); 717 if (status != napi_ok) { 718 goto failed; 719 } 720 721 /* Need to reserve extra byte for C-string 0-termination. */ 722 header_len++; 723 724 headers = argv[2]; 725 726 ret = nxt_unit_response_init(req, status_code, keys_count, header_len); 727 if (ret != NXT_UNIT_OK) { 728 goto failed; 729 } 730 731 status = napi_get_property_names(env, headers, &keys); 732 if (status != napi_ok) { 733 goto failed; 734 } 735 736 status = napi_get_array_length(env, keys, &keys_len); 737 if (status != napi_ok) { 738 goto failed; 739 } 740 741 ptr = req->response_buf->free; 742 743 for (i = 0; i < keys_len; i++) { 744 status = napi_get_element(env, keys, i, &name); 745 if (status != napi_ok) { 746 goto failed; 747 } 748 749 status = napi_get_property(env, headers, name, &value); 750 if (status != napi_ok) { 751 goto failed; 752 } 753 754 status = napi_get_value_string_latin1(env, name, ptr, header_len, 755 &name_len); 756 if (status != napi_ok) { 757 goto failed; 758 } 759 760 name_ptr = ptr; 761 762 ptr += name_len; 763 header_len -= name_len; 764 765 hash = nxt_unit_field_hash(name_ptr, name_len); 766 767 status = napi_is_array(env, value, &is_array); 768 if (status != napi_ok) { 769 goto failed; 770 } 771 772 if (is_array) { 773 status = napi_get_array_length(env, value, &array_len); 774 if (status != napi_ok) { 775 goto failed; 776 } 777 778 for (j = 0; j < array_len; j++) { 779 status = napi_get_element(env, value, j, &array_val); 780 if (status != napi_ok) { 781 goto failed; 782 } 783 784 status = napi_get_value_string_latin1(env, array_val, ptr, 785 header_len, 786 &value_len); 787 if (status != napi_ok) { 788 goto failed; 789 } 790 791 f = req->response->fields + req->response->fields_count; 792 f->skip = 0; 793 794 nxt_unit_sptr_set(&f->name, name_ptr); 795 796 f->name_length = name_len; 797 f->hash = hash; 798 799 nxt_unit_sptr_set(&f->value, ptr); 800 f->value_length = (uint32_t) value_len; 801 802 ptr += value_len; 803 header_len -= value_len; 804 805 req->response->fields_count++; 806 } 807 808 } else { 809 status = napi_get_value_string_latin1(env, value, ptr, header_len, 810 &value_len); 811 if (status != napi_ok) { 812 goto failed; 813 } 814 815 f = req->response->fields + req->response->fields_count; 816 f->skip = 0; 817 818 nxt_unit_sptr_set(&f->name, name_ptr); 819 820 f->name_length = name_len; 821 f->hash = hash; 822 823 nxt_unit_sptr_set(&f->value, ptr); 824 f->value_length = (uint32_t) value_len; 825 826 ptr += value_len; 827 header_len -= value_len; 828 829 req->response->fields_count++; 830 } 831 } 832 833 req->response_buf->free = ptr; 834 835 ret = nxt_unit_response_send(req); 836 if (ret != NXT_UNIT_OK) { 837 goto failed; 838 } 839 840 return this_arg; 841 842 failed: 843 844 req->response->fields_count = 0; 845 846 napi_throw_error(env, NULL, "Failed to write headers"); 847 848 return nullptr; 849 } 850 851 852 napi_value 853 Unit::response_write(napi_env env, napi_callback_info info) 854 { 855 int ret; 856 char *ptr; 857 size_t argc, have_buf_len; 858 int64_t req_p; 859 uint32_t buf_len; 860 napi_value this_arg, req_num; 861 napi_status status; 862 nxt_unit_buf_t *buf; 863 napi_valuetype buf_type; 864 nxt_unit_request_info_t *req; 865 napi_value argv[3]; 866 867 argc = 3; 868 869 status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); 870 if (status != napi_ok) { 871 goto failed; 872 } 873 874 if (argc != 3) { 875 napi_throw_error(env, NULL, "Wrong args count. Need two: " 876 "chunk, chunk length"); 877 return nullptr; 878 } 879 880 status = napi_get_named_property(env, argv[0], "_req_point", &req_num); 881 if (status != napi_ok) { 882 napi_throw_error(env, NULL, "Failed to get request pointer"); 883 return nullptr; 884 } 885 886 status = napi_get_value_int64(env, req_num, &req_p); 887 if (status != napi_ok) { 888 napi_throw_error(env, NULL, "Failed to get request pointer"); 889 return nullptr; 890 } 891 892 req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 893 894 status = napi_get_value_uint32(env, argv[2], &buf_len); 895 if (status != napi_ok) { 896 goto failed; 897 } 898 899 status = napi_typeof(env, argv[1], &buf_type); 900 if (status != napi_ok) { 901 goto failed; 902 } 903 904 buf_len++; 905 906 buf = nxt_unit_response_buf_alloc(req, buf_len); 907 if (buf == NULL) { 908 goto failed; 909 } 910 911 if (buf_type == napi_string) { 912 /* TODO: will work only for utf8 content-type */ 913 914 status = napi_get_value_string_utf8(env, argv[1], buf->free, 915 buf_len, &have_buf_len); 916 917 } else { 918 status = napi_get_buffer_info(env, argv[1], (void **) &ptr, 919 &have_buf_len); 920 921 memcpy(buf->free, ptr, have_buf_len); 922 } 923 924 if (status != napi_ok) { 925 goto failed; 926 } 927 928 buf->free += have_buf_len; 929 930 ret = nxt_unit_buf_send(buf); 931 if (ret != NXT_UNIT_OK) { 932 goto failed; 933 } 934 935 return this_arg; 936 937 failed: 938 939 napi_throw_error(env, NULL, "Failed to write body"); 940 941 return nullptr; 942 } 943 944 945 napi_value 946 Unit::response_end(napi_env env, napi_callback_info info) 947 { 948 size_t argc; 949 int64_t req_p; 950 napi_value resp, this_arg, req_num; 951 napi_status status; 952 nxt_unit_request_info_t *req; 953 954 argc = 1; 955 956 status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL); 957 if (status != napi_ok) { 958 napi_throw_error(env, NULL, "Failed to finalize sending body"); 959 return nullptr; 960 } 961 962 status = napi_get_named_property(env, resp, "_req_point", &req_num); 963 if (status != napi_ok) { 964 napi_throw_error(env, NULL, "Failed to get request pointer"); 965 return nullptr; 966 } 967 968 status = napi_get_value_int64(env, req_num, &req_p); 969 if (status != napi_ok) { 970 napi_throw_error(env, NULL, "Failed to get request pointer"); 971 return nullptr; 972 } 973 974 req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 975 976 nxt_unit_request_done(req, NXT_UNIT_OK); 977 978 return this_arg; 979 } 980