1802Salexander.borisov@nginx.com 2802Salexander.borisov@nginx.com /* 3802Salexander.borisov@nginx.com * Copyright (C) NGINX, Inc. 4802Salexander.borisov@nginx.com */ 5802Salexander.borisov@nginx.com 6802Salexander.borisov@nginx.com #include "unit.h" 7802Salexander.borisov@nginx.com 8828Salexander.borisov@nginx.com #include <unistd.h> 9828Salexander.borisov@nginx.com #include <fcntl.h> 10828Salexander.borisov@nginx.com 11828Salexander.borisov@nginx.com #include <uv.h> 12828Salexander.borisov@nginx.com 131132Smax.romanov@nginx.com #include <nxt_unit_websocket.h> 141132Smax.romanov@nginx.com 15802Salexander.borisov@nginx.com 16802Salexander.borisov@nginx.com napi_ref Unit::constructor_; 17802Salexander.borisov@nginx.com 18802Salexander.borisov@nginx.com 19842Salexander.borisov@nginx.com struct nxt_nodejs_ctx_t { 20842Salexander.borisov@nginx.com nxt_unit_port_id_t port_id; 21842Salexander.borisov@nginx.com uv_poll_t poll; 22842Salexander.borisov@nginx.com }; 23842Salexander.borisov@nginx.com 24842Salexander.borisov@nginx.com 251132Smax.romanov@nginx.com struct req_data_t { 261132Smax.romanov@nginx.com napi_ref sock_ref; 271132Smax.romanov@nginx.com napi_ref resp_ref; 281132Smax.romanov@nginx.com napi_ref conn_ref; 291132Smax.romanov@nginx.com }; 301132Smax.romanov@nginx.com 311132Smax.romanov@nginx.com 321020Smax.romanov@nginx.com Unit::Unit(napi_env env, napi_value jsthis): 331020Smax.romanov@nginx.com nxt_napi(env), 341020Smax.romanov@nginx.com wrapper_(wrap(jsthis, this, destroy)), 35802Salexander.borisov@nginx.com unit_ctx_(nullptr) 36802Salexander.borisov@nginx.com { 371132Smax.romanov@nginx.com nxt_unit_debug(NULL, "Unit::Unit()"); 38802Salexander.borisov@nginx.com } 39802Salexander.borisov@nginx.com 40802Salexander.borisov@nginx.com 41802Salexander.borisov@nginx.com Unit::~Unit() 42802Salexander.borisov@nginx.com { 431020Smax.romanov@nginx.com delete_reference(wrapper_); 441132Smax.romanov@nginx.com 451132Smax.romanov@nginx.com nxt_unit_debug(NULL, "Unit::~Unit()"); 46802Salexander.borisov@nginx.com } 47802Salexander.borisov@nginx.com 48802Salexander.borisov@nginx.com 49802Salexander.borisov@nginx.com napi_value 50802Salexander.borisov@nginx.com Unit::init(napi_env env, napi_value exports) 51802Salexander.borisov@nginx.com { 521020Smax.romanov@nginx.com nxt_napi napi(env); 531132Smax.romanov@nginx.com napi_value ctor; 54802Salexander.borisov@nginx.com 551132Smax.romanov@nginx.com napi_property_descriptor unit_props[] = { 56802Salexander.borisov@nginx.com { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, 57828Salexander.borisov@nginx.com { "listen", 0, listen, 0, 0, 0, napi_default, 0 }, 58802Salexander.borisov@nginx.com }; 59802Salexander.borisov@nginx.com 601020Smax.romanov@nginx.com try { 611132Smax.romanov@nginx.com ctor = napi.define_class("Unit", create, 2, unit_props); 621132Smax.romanov@nginx.com constructor_ = napi.create_reference(ctor); 63802Salexander.borisov@nginx.com 641132Smax.romanov@nginx.com napi.set_named_property(exports, "Unit", ctor); 651132Smax.romanov@nginx.com napi.set_named_property(exports, "response_send_headers", 661020Smax.romanov@nginx.com response_send_headers); 671132Smax.romanov@nginx.com napi.set_named_property(exports, "response_write", response_write); 681132Smax.romanov@nginx.com napi.set_named_property(exports, "response_end", response_end); 691132Smax.romanov@nginx.com napi.set_named_property(exports, "websocket_send_frame", 701132Smax.romanov@nginx.com websocket_send_frame); 711132Smax.romanov@nginx.com napi.set_named_property(exports, "websocket_set_sock", 721132Smax.romanov@nginx.com websocket_set_sock); 73*1322Smax.romanov@nginx.com napi.set_named_property(exports, "buf_min", nxt_unit_buf_min()); 74*1322Smax.romanov@nginx.com napi.set_named_property(exports, "buf_max", nxt_unit_buf_max()); 75802Salexander.borisov@nginx.com 761020Smax.romanov@nginx.com } catch (exception &e) { 771020Smax.romanov@nginx.com napi.throw_error(e); 781020Smax.romanov@nginx.com return nullptr; 79802Salexander.borisov@nginx.com } 80802Salexander.borisov@nginx.com 81802Salexander.borisov@nginx.com return exports; 82802Salexander.borisov@nginx.com } 83802Salexander.borisov@nginx.com 84802Salexander.borisov@nginx.com 85802Salexander.borisov@nginx.com void 86802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) 87802Salexander.borisov@nginx.com { 88802Salexander.borisov@nginx.com Unit *obj = reinterpret_cast<Unit *>(nativeObject); 89802Salexander.borisov@nginx.com 90802Salexander.borisov@nginx.com delete obj; 91802Salexander.borisov@nginx.com } 92802Salexander.borisov@nginx.com 93802Salexander.borisov@nginx.com 94802Salexander.borisov@nginx.com napi_value 95802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info) 96802Salexander.borisov@nginx.com { 971020Smax.romanov@nginx.com nxt_napi napi(env); 981132Smax.romanov@nginx.com napi_value target, ctor, instance, jsthis; 991020Smax.romanov@nginx.com 1001020Smax.romanov@nginx.com try { 1011020Smax.romanov@nginx.com target = napi.get_new_target(info); 102802Salexander.borisov@nginx.com 1031020Smax.romanov@nginx.com if (target != nullptr) { 1041020Smax.romanov@nginx.com /* Invoked as constructor: `new Unit(...)`. */ 1051020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info); 106802Salexander.borisov@nginx.com 1071023Smax.romanov@nginx.com new Unit(env, jsthis); 1081023Smax.romanov@nginx.com napi.create_reference(jsthis); 1091020Smax.romanov@nginx.com 1101020Smax.romanov@nginx.com return jsthis; 111802Salexander.borisov@nginx.com } 112802Salexander.borisov@nginx.com 1131020Smax.romanov@nginx.com /* Invoked as plain function `Unit(...)`, turn into construct call. */ 1141132Smax.romanov@nginx.com ctor = napi.get_reference_value(constructor_); 1151132Smax.romanov@nginx.com instance = napi.new_instance(ctor); 1161023Smax.romanov@nginx.com napi.create_reference(instance); 117841Salexander.borisov@nginx.com 1181020Smax.romanov@nginx.com } catch (exception &e) { 1191020Smax.romanov@nginx.com napi.throw_error(e); 1201020Smax.romanov@nginx.com return nullptr; 121841Salexander.borisov@nginx.com } 122841Salexander.borisov@nginx.com 123802Salexander.borisov@nginx.com return instance; 124802Salexander.borisov@nginx.com } 125802Salexander.borisov@nginx.com 126802Salexander.borisov@nginx.com 127802Salexander.borisov@nginx.com napi_value 128802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info) 129802Salexander.borisov@nginx.com { 130802Salexander.borisov@nginx.com Unit *obj; 131802Salexander.borisov@nginx.com size_t argc; 1321020Smax.romanov@nginx.com nxt_napi napi(env); 133828Salexander.borisov@nginx.com napi_value jsthis, argv; 134802Salexander.borisov@nginx.com nxt_unit_init_t unit_init; 135802Salexander.borisov@nginx.com 136802Salexander.borisov@nginx.com argc = 1; 137802Salexander.borisov@nginx.com 1381020Smax.romanov@nginx.com try { 1391020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info, argc, &argv); 1401020Smax.romanov@nginx.com obj = (Unit *) napi.unwrap(jsthis); 141802Salexander.borisov@nginx.com 1421020Smax.romanov@nginx.com } catch (exception &e) { 1431020Smax.romanov@nginx.com napi.throw_error(e); 1441020Smax.romanov@nginx.com return nullptr; 145802Salexander.borisov@nginx.com } 146802Salexander.borisov@nginx.com 147802Salexander.borisov@nginx.com memset(&unit_init, 0, sizeof(nxt_unit_init_t)); 148802Salexander.borisov@nginx.com 149802Salexander.borisov@nginx.com unit_init.data = obj; 1501132Smax.romanov@nginx.com unit_init.callbacks.request_handler = request_handler_cb; 1511132Smax.romanov@nginx.com unit_init.callbacks.websocket_handler = websocket_handler_cb; 1521132Smax.romanov@nginx.com unit_init.callbacks.close_handler = close_handler_cb; 153*1322Smax.romanov@nginx.com unit_init.callbacks.shm_ack_handler = shm_ack_handler_cb; 1541132Smax.romanov@nginx.com unit_init.callbacks.add_port = add_port; 1551132Smax.romanov@nginx.com unit_init.callbacks.remove_port = remove_port; 1561132Smax.romanov@nginx.com unit_init.callbacks.quit = quit_cb; 1571132Smax.romanov@nginx.com 1581132Smax.romanov@nginx.com unit_init.request_data_size = sizeof(req_data_t); 159802Salexander.borisov@nginx.com 160802Salexander.borisov@nginx.com obj->unit_ctx_ = nxt_unit_init(&unit_init); 161802Salexander.borisov@nginx.com if (obj->unit_ctx_ == NULL) { 162802Salexander.borisov@nginx.com goto failed; 163802Salexander.borisov@nginx.com } 164802Salexander.borisov@nginx.com 165802Salexander.borisov@nginx.com return nullptr; 166802Salexander.borisov@nginx.com 167802Salexander.borisov@nginx.com failed: 168802Salexander.borisov@nginx.com 169802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create Unit object"); 170802Salexander.borisov@nginx.com 171802Salexander.borisov@nginx.com return nullptr; 172802Salexander.borisov@nginx.com } 173802Salexander.borisov@nginx.com 174802Salexander.borisov@nginx.com 175802Salexander.borisov@nginx.com napi_value 176802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info) 177802Salexander.borisov@nginx.com { 178828Salexander.borisov@nginx.com return nullptr; 179828Salexander.borisov@nginx.com } 180828Salexander.borisov@nginx.com 181802Salexander.borisov@nginx.com 1821132Smax.romanov@nginx.com void 1831132Smax.romanov@nginx.com Unit::request_handler_cb(nxt_unit_request_info_t *req) 184828Salexander.borisov@nginx.com { 1851132Smax.romanov@nginx.com Unit *obj; 186828Salexander.borisov@nginx.com 1871132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 188802Salexander.borisov@nginx.com 1891132Smax.romanov@nginx.com obj->request_handler(req); 190802Salexander.borisov@nginx.com } 191802Salexander.borisov@nginx.com 192802Salexander.borisov@nginx.com 193802Salexander.borisov@nginx.com void 194802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req) 195802Salexander.borisov@nginx.com { 1961132Smax.romanov@nginx.com napi_value socket, request, response, server_obj, emit_request; 197802Salexander.borisov@nginx.com 1981132Smax.romanov@nginx.com memset(req->data, 0, sizeof(req_data_t)); 199802Salexander.borisov@nginx.com 2001020Smax.romanov@nginx.com try { 2011132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 202802Salexander.borisov@nginx.com 2031132Smax.romanov@nginx.com server_obj = get_server_object(); 204802Salexander.borisov@nginx.com 2051132Smax.romanov@nginx.com socket = create_socket(server_obj, req); 2061132Smax.romanov@nginx.com request = create_request(server_obj, socket); 2071132Smax.romanov@nginx.com response = create_response(server_obj, request, req); 208828Salexander.borisov@nginx.com 2091132Smax.romanov@nginx.com create_headers(req, request); 210871Salexander.borisov@nginx.com 2111132Smax.romanov@nginx.com emit_request = get_named_property(server_obj, "emit_request"); 2121132Smax.romanov@nginx.com 2131132Smax.romanov@nginx.com nxt_async_context async_context(env(), "request_handler"); 2141020Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 215876Salexander.borisov@nginx.com 2161132Smax.romanov@nginx.com make_callback(async_context, server_obj, emit_request, request, 2171132Smax.romanov@nginx.com response); 218871Salexander.borisov@nginx.com 2191020Smax.romanov@nginx.com } catch (exception &e) { 2201132Smax.romanov@nginx.com nxt_unit_req_warn(req, "request_handler: %s", e.str); 221871Salexander.borisov@nginx.com } 222802Salexander.borisov@nginx.com } 223802Salexander.borisov@nginx.com 224802Salexander.borisov@nginx.com 225828Salexander.borisov@nginx.com void 2261132Smax.romanov@nginx.com Unit::websocket_handler_cb(nxt_unit_websocket_frame_t *ws) 2271132Smax.romanov@nginx.com { 2281132Smax.romanov@nginx.com Unit *obj; 2291132Smax.romanov@nginx.com 2301132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ws->req->unit->data); 2311132Smax.romanov@nginx.com 2321132Smax.romanov@nginx.com obj->websocket_handler(ws); 2331132Smax.romanov@nginx.com } 2341132Smax.romanov@nginx.com 2351132Smax.romanov@nginx.com 2361132Smax.romanov@nginx.com void 2371132Smax.romanov@nginx.com Unit::websocket_handler(nxt_unit_websocket_frame_t *ws) 2381132Smax.romanov@nginx.com { 2391132Smax.romanov@nginx.com napi_value frame, server_obj, process_frame, conn; 2401132Smax.romanov@nginx.com req_data_t *req_data; 2411132Smax.romanov@nginx.com 2421132Smax.romanov@nginx.com req_data = (req_data_t *) ws->req->data; 2431132Smax.romanov@nginx.com 2441132Smax.romanov@nginx.com try { 2451132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 2461132Smax.romanov@nginx.com 2471132Smax.romanov@nginx.com server_obj = get_server_object(); 2481132Smax.romanov@nginx.com 2491132Smax.romanov@nginx.com frame = create_websocket_frame(server_obj, ws); 2501132Smax.romanov@nginx.com 2511132Smax.romanov@nginx.com conn = get_reference_value(req_data->conn_ref); 2521132Smax.romanov@nginx.com 2531132Smax.romanov@nginx.com process_frame = get_named_property(conn, "processFrame"); 2541132Smax.romanov@nginx.com 2551132Smax.romanov@nginx.com nxt_async_context async_context(env(), "websocket_handler"); 2561132Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 2571132Smax.romanov@nginx.com 2581132Smax.romanov@nginx.com make_callback(async_context, conn, process_frame, frame); 2591132Smax.romanov@nginx.com 2601132Smax.romanov@nginx.com } catch (exception &e) { 2611132Smax.romanov@nginx.com nxt_unit_req_warn(ws->req, "websocket_handler: %s", e.str); 2621132Smax.romanov@nginx.com } 2631132Smax.romanov@nginx.com 2641132Smax.romanov@nginx.com nxt_unit_websocket_done(ws); 2651132Smax.romanov@nginx.com } 2661132Smax.romanov@nginx.com 2671132Smax.romanov@nginx.com 2681132Smax.romanov@nginx.com void 2691132Smax.romanov@nginx.com Unit::close_handler_cb(nxt_unit_request_info_t *req) 2701132Smax.romanov@nginx.com { 2711132Smax.romanov@nginx.com Unit *obj; 2721132Smax.romanov@nginx.com 2731132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 2741132Smax.romanov@nginx.com 2751132Smax.romanov@nginx.com obj->close_handler(req); 2761132Smax.romanov@nginx.com } 2771132Smax.romanov@nginx.com 2781132Smax.romanov@nginx.com 2791132Smax.romanov@nginx.com void 2801132Smax.romanov@nginx.com Unit::close_handler(nxt_unit_request_info_t *req) 2811132Smax.romanov@nginx.com { 2821132Smax.romanov@nginx.com napi_value conn_handle_close, conn; 2831132Smax.romanov@nginx.com req_data_t *req_data; 2841132Smax.romanov@nginx.com 2851132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 2861132Smax.romanov@nginx.com 2871132Smax.romanov@nginx.com try { 2881132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 2891132Smax.romanov@nginx.com 2901132Smax.romanov@nginx.com conn = get_reference_value(req_data->conn_ref); 2911132Smax.romanov@nginx.com 2921132Smax.romanov@nginx.com conn_handle_close = get_named_property(conn, "handleSocketClose"); 2931132Smax.romanov@nginx.com 2941132Smax.romanov@nginx.com nxt_async_context async_context(env(), "close_handler"); 2951132Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 2961132Smax.romanov@nginx.com 2971132Smax.romanov@nginx.com make_callback(async_context, conn, conn_handle_close, 2981132Smax.romanov@nginx.com nxt_napi::create(0)); 2991132Smax.romanov@nginx.com 3001132Smax.romanov@nginx.com remove_wrap(req_data->sock_ref); 3011132Smax.romanov@nginx.com remove_wrap(req_data->resp_ref); 3021132Smax.romanov@nginx.com remove_wrap(req_data->conn_ref); 3031132Smax.romanov@nginx.com 3041132Smax.romanov@nginx.com } catch (exception &e) { 3051132Smax.romanov@nginx.com nxt_unit_req_warn(req, "close_handler: %s", e.str); 3061132Smax.romanov@nginx.com 3071132Smax.romanov@nginx.com return; 3081132Smax.romanov@nginx.com } 3091132Smax.romanov@nginx.com 3101132Smax.romanov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 3111132Smax.romanov@nginx.com } 3121132Smax.romanov@nginx.com 3131132Smax.romanov@nginx.com 314*1322Smax.romanov@nginx.com void 315*1322Smax.romanov@nginx.com Unit::shm_ack_handler_cb(nxt_unit_ctx_t *ctx) 316*1322Smax.romanov@nginx.com { 317*1322Smax.romanov@nginx.com Unit *obj; 318*1322Smax.romanov@nginx.com 319*1322Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 320*1322Smax.romanov@nginx.com 321*1322Smax.romanov@nginx.com obj->shm_ack_handler(ctx); 322*1322Smax.romanov@nginx.com } 323*1322Smax.romanov@nginx.com 324*1322Smax.romanov@nginx.com 325*1322Smax.romanov@nginx.com void 326*1322Smax.romanov@nginx.com Unit::shm_ack_handler(nxt_unit_ctx_t *ctx) 327*1322Smax.romanov@nginx.com { 328*1322Smax.romanov@nginx.com napi_value server_obj, emit_drain; 329*1322Smax.romanov@nginx.com 330*1322Smax.romanov@nginx.com try { 331*1322Smax.romanov@nginx.com nxt_handle_scope scope(env()); 332*1322Smax.romanov@nginx.com 333*1322Smax.romanov@nginx.com server_obj = get_server_object(); 334*1322Smax.romanov@nginx.com 335*1322Smax.romanov@nginx.com emit_drain = get_named_property(server_obj, "emit_drain"); 336*1322Smax.romanov@nginx.com 337*1322Smax.romanov@nginx.com nxt_async_context async_context(env(), "shm_ack_handler"); 338*1322Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 339*1322Smax.romanov@nginx.com 340*1322Smax.romanov@nginx.com make_callback(async_context, server_obj, emit_drain); 341*1322Smax.romanov@nginx.com 342*1322Smax.romanov@nginx.com } catch (exception &e) { 343*1322Smax.romanov@nginx.com nxt_unit_warn(ctx, "shm_ack_handler: %s", e.str); 344*1322Smax.romanov@nginx.com } 345*1322Smax.romanov@nginx.com } 346*1322Smax.romanov@nginx.com 347*1322Smax.romanov@nginx.com 3481132Smax.romanov@nginx.com static void 349828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events) 350828Salexander.borisov@nginx.com { 351828Salexander.borisov@nginx.com nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); 352828Salexander.borisov@nginx.com } 353828Salexander.borisov@nginx.com 354828Salexander.borisov@nginx.com 355828Salexander.borisov@nginx.com int 356828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 357828Salexander.borisov@nginx.com { 358842Salexander.borisov@nginx.com int err; 359842Salexander.borisov@nginx.com Unit *obj; 360842Salexander.borisov@nginx.com uv_loop_t *loop; 361842Salexander.borisov@nginx.com napi_status status; 362842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 363828Salexander.borisov@nginx.com 364828Salexander.borisov@nginx.com if (port->in_fd != -1) { 365828Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 366828Salexander.borisov@nginx.com 367828Salexander.borisov@nginx.com if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { 3681132Smax.romanov@nginx.com nxt_unit_warn(ctx, "fcntl(%d, O_NONBLOCK) failed: %s (%d)", 3691132Smax.romanov@nginx.com port->in_fd, strerror(errno), errno); 370828Salexander.borisov@nginx.com return -1; 371828Salexander.borisov@nginx.com } 372828Salexander.borisov@nginx.com 3731020Smax.romanov@nginx.com status = napi_get_uv_event_loop(obj->env(), &loop); 374828Salexander.borisov@nginx.com if (status != napi_ok) { 3751132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to get uv.loop"); 376828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 377828Salexander.borisov@nginx.com } 378828Salexander.borisov@nginx.com 379842Salexander.borisov@nginx.com node_ctx = new nxt_nodejs_ctx_t; 380828Salexander.borisov@nginx.com 381842Salexander.borisov@nginx.com err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); 382828Salexander.borisov@nginx.com if (err < 0) { 3831132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to init uv.poll"); 384828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 385828Salexander.borisov@nginx.com } 386828Salexander.borisov@nginx.com 387842Salexander.borisov@nginx.com err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); 388828Salexander.borisov@nginx.com if (err < 0) { 3891132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to start uv.poll"); 390828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 391828Salexander.borisov@nginx.com } 392828Salexander.borisov@nginx.com 393842Salexander.borisov@nginx.com ctx->data = node_ctx; 394842Salexander.borisov@nginx.com 395842Salexander.borisov@nginx.com node_ctx->port_id = port->id; 396842Salexander.borisov@nginx.com node_ctx->poll.data = ctx; 397828Salexander.borisov@nginx.com } 398828Salexander.borisov@nginx.com 399828Salexander.borisov@nginx.com return nxt_unit_add_port(ctx, port); 400828Salexander.borisov@nginx.com } 401828Salexander.borisov@nginx.com 402828Salexander.borisov@nginx.com 4031008Szelenkov@nginx.com inline bool 404842Salexander.borisov@nginx.com operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) 405842Salexander.borisov@nginx.com { 406842Salexander.borisov@nginx.com return p1.pid == p2.pid && p1.id == p2.id; 407842Salexander.borisov@nginx.com } 408842Salexander.borisov@nginx.com 409842Salexander.borisov@nginx.com 410828Salexander.borisov@nginx.com void 411828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) 412828Salexander.borisov@nginx.com { 413842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 414842Salexander.borisov@nginx.com 415842Salexander.borisov@nginx.com if (ctx->data != NULL) { 416842Salexander.borisov@nginx.com node_ctx = (nxt_nodejs_ctx_t *) ctx->data; 417828Salexander.borisov@nginx.com 418842Salexander.borisov@nginx.com if (node_ctx->port_id == *port_id) { 419842Salexander.borisov@nginx.com uv_poll_stop(&node_ctx->poll); 420828Salexander.borisov@nginx.com 421842Salexander.borisov@nginx.com delete node_ctx; 422828Salexander.borisov@nginx.com 423842Salexander.borisov@nginx.com ctx->data = NULL; 424842Salexander.borisov@nginx.com } 425828Salexander.borisov@nginx.com } 426828Salexander.borisov@nginx.com 427828Salexander.borisov@nginx.com nxt_unit_remove_port(ctx, port_id); 428828Salexander.borisov@nginx.com } 429828Salexander.borisov@nginx.com 430828Salexander.borisov@nginx.com 431842Salexander.borisov@nginx.com void 4321132Smax.romanov@nginx.com Unit::quit_cb(nxt_unit_ctx_t *ctx) 433842Salexander.borisov@nginx.com { 4341132Smax.romanov@nginx.com Unit *obj; 4351021Smax.romanov@nginx.com 4361021Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 4371021Smax.romanov@nginx.com 4381132Smax.romanov@nginx.com obj->quit(ctx); 4391132Smax.romanov@nginx.com } 4401132Smax.romanov@nginx.com 4411132Smax.romanov@nginx.com 4421132Smax.romanov@nginx.com void 4431132Smax.romanov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx) 4441132Smax.romanov@nginx.com { 4451132Smax.romanov@nginx.com napi_value server_obj, emit_close; 4461021Smax.romanov@nginx.com 4471132Smax.romanov@nginx.com try { 4481132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 4491021Smax.romanov@nginx.com 4501132Smax.romanov@nginx.com server_obj = get_server_object(); 4511021Smax.romanov@nginx.com 4521132Smax.romanov@nginx.com emit_close = get_named_property(server_obj, "emit_close"); 4531132Smax.romanov@nginx.com 4541132Smax.romanov@nginx.com nxt_async_context async_context(env(), "unit_quit"); 4551021Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 4561021Smax.romanov@nginx.com 4571132Smax.romanov@nginx.com make_callback(async_context, server_obj, emit_close); 4581021Smax.romanov@nginx.com 4591021Smax.romanov@nginx.com } catch (exception &e) { 4601132Smax.romanov@nginx.com nxt_unit_debug(ctx, "quit: %s", e.str); 4611021Smax.romanov@nginx.com } 4621021Smax.romanov@nginx.com 463842Salexander.borisov@nginx.com nxt_unit_done(ctx); 464842Salexander.borisov@nginx.com } 465842Salexander.borisov@nginx.com 466842Salexander.borisov@nginx.com 467802Salexander.borisov@nginx.com napi_value 468802Salexander.borisov@nginx.com Unit::get_server_object() 469802Salexander.borisov@nginx.com { 4701020Smax.romanov@nginx.com napi_value unit_obj; 471802Salexander.borisov@nginx.com 4721020Smax.romanov@nginx.com unit_obj = get_reference_value(wrapper_); 473802Salexander.borisov@nginx.com 4741020Smax.romanov@nginx.com return get_named_property(unit_obj, "server"); 475802Salexander.borisov@nginx.com } 476802Salexander.borisov@nginx.com 477802Salexander.borisov@nginx.com 4781020Smax.romanov@nginx.com void 479802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) 480802Salexander.borisov@nginx.com { 4811132Smax.romanov@nginx.com void *data; 482802Salexander.borisov@nginx.com uint32_t i; 4831132Smax.romanov@nginx.com napi_value headers, raw_headers, buffer; 484802Salexander.borisov@nginx.com napi_status status; 485802Salexander.borisov@nginx.com nxt_unit_request_t *r; 486802Salexander.borisov@nginx.com 487802Salexander.borisov@nginx.com r = req->request; 488802Salexander.borisov@nginx.com 4891020Smax.romanov@nginx.com headers = create_object(); 490802Salexander.borisov@nginx.com 4911020Smax.romanov@nginx.com status = napi_create_array_with_length(env(), r->fields_count * 2, 492802Salexander.borisov@nginx.com &raw_headers); 493802Salexander.borisov@nginx.com if (status != napi_ok) { 4941020Smax.romanov@nginx.com throw exception("Failed to create array"); 495802Salexander.borisov@nginx.com } 496802Salexander.borisov@nginx.com 497802Salexander.borisov@nginx.com for (i = 0; i < r->fields_count; i++) { 4981020Smax.romanov@nginx.com append_header(r->fields + i, headers, raw_headers, i); 499802Salexander.borisov@nginx.com } 500802Salexander.borisov@nginx.com 5011020Smax.romanov@nginx.com set_named_property(request, "headers", headers); 5021020Smax.romanov@nginx.com set_named_property(request, "rawHeaders", raw_headers); 5031020Smax.romanov@nginx.com set_named_property(request, "httpVersion", r->version, r->version_length); 5041020Smax.romanov@nginx.com set_named_property(request, "method", r->method, r->method_length); 5051020Smax.romanov@nginx.com set_named_property(request, "url", r->target, r->target_length); 5061132Smax.romanov@nginx.com 5071132Smax.romanov@nginx.com set_named_property(request, "_websocket_handshake", r->websocket_handshake); 5081132Smax.romanov@nginx.com 5091132Smax.romanov@nginx.com buffer = create_buffer((size_t) req->content_length, &data); 5101132Smax.romanov@nginx.com nxt_unit_request_read(req, data, req->content_length); 5111132Smax.romanov@nginx.com 5121132Smax.romanov@nginx.com set_named_property(request, "_data", buffer); 513802Salexander.borisov@nginx.com } 514802Salexander.borisov@nginx.com 515802Salexander.borisov@nginx.com 5161038Smax.romanov@nginx.com inline char 5171038Smax.romanov@nginx.com lowcase(char c) 5181038Smax.romanov@nginx.com { 5191038Smax.romanov@nginx.com return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; 5201038Smax.romanov@nginx.com } 5211038Smax.romanov@nginx.com 5221038Smax.romanov@nginx.com 5231020Smax.romanov@nginx.com inline void 524802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers, 5251020Smax.romanov@nginx.com napi_value raw_headers, uint32_t idx) 526802Salexander.borisov@nginx.com { 5271038Smax.romanov@nginx.com char *name; 5281038Smax.romanov@nginx.com uint8_t i; 5291038Smax.romanov@nginx.com napi_value str, vstr; 5301038Smax.romanov@nginx.com 5311038Smax.romanov@nginx.com name = (char *) nxt_unit_sptr_get(&f->name); 532802Salexander.borisov@nginx.com 5331038Smax.romanov@nginx.com str = create_string_latin1(name, f->name_length); 5341038Smax.romanov@nginx.com 5351038Smax.romanov@nginx.com for (i = 0; i < f->name_length; i++) { 5361038Smax.romanov@nginx.com name[i] = lowcase(name[i]); 5371038Smax.romanov@nginx.com } 538802Salexander.borisov@nginx.com 5391020Smax.romanov@nginx.com vstr = set_named_property(headers, name, f->value, f->value_length); 540802Salexander.borisov@nginx.com 5411020Smax.romanov@nginx.com set_element(raw_headers, idx * 2, str); 5421020Smax.romanov@nginx.com set_element(raw_headers, idx * 2 + 1, vstr); 543802Salexander.borisov@nginx.com } 544802Salexander.borisov@nginx.com 545802Salexander.borisov@nginx.com 546802Salexander.borisov@nginx.com napi_value 547802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) 548802Salexander.borisov@nginx.com { 5491022Smax.romanov@nginx.com napi_value constructor, res; 5501132Smax.romanov@nginx.com req_data_t *req_data; 5511022Smax.romanov@nginx.com nxt_unit_request_t *r; 5521022Smax.romanov@nginx.com 5531022Smax.romanov@nginx.com r = req->request; 554802Salexander.borisov@nginx.com 5551132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "Socket"); 556802Salexander.borisov@nginx.com 5571022Smax.romanov@nginx.com res = new_instance(constructor); 558802Salexander.borisov@nginx.com 5591132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 5601132Smax.romanov@nginx.com req_data->sock_ref = wrap(res, req, sock_destroy); 5611132Smax.romanov@nginx.com 5621022Smax.romanov@nginx.com set_named_property(res, "remoteAddress", r->remote, r->remote_length); 5631022Smax.romanov@nginx.com set_named_property(res, "localAddress", r->local, r->local_length); 564828Salexander.borisov@nginx.com 5651022Smax.romanov@nginx.com return res; 566802Salexander.borisov@nginx.com } 567802Salexander.borisov@nginx.com 568802Salexander.borisov@nginx.com 569802Salexander.borisov@nginx.com napi_value 570802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket) 571802Salexander.borisov@nginx.com { 5721132Smax.romanov@nginx.com napi_value constructor; 5731132Smax.romanov@nginx.com 5741132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "ServerRequest"); 575802Salexander.borisov@nginx.com 5761132Smax.romanov@nginx.com return new_instance(constructor, server_obj, socket); 5771132Smax.romanov@nginx.com } 5781132Smax.romanov@nginx.com 579802Salexander.borisov@nginx.com 5801132Smax.romanov@nginx.com napi_value 5811132Smax.romanov@nginx.com Unit::create_response(napi_value server_obj, napi_value request, 5821132Smax.romanov@nginx.com nxt_unit_request_info_t *req) 5831132Smax.romanov@nginx.com { 5841132Smax.romanov@nginx.com napi_value constructor, res; 5851132Smax.romanov@nginx.com req_data_t *req_data; 586802Salexander.borisov@nginx.com 5871132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "ServerResponse"); 5881132Smax.romanov@nginx.com 5891132Smax.romanov@nginx.com res = new_instance(constructor, request); 590802Salexander.borisov@nginx.com 5911132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 5921132Smax.romanov@nginx.com req_data->resp_ref = wrap(res, req, resp_destroy); 5931132Smax.romanov@nginx.com 5941132Smax.romanov@nginx.com return res; 595802Salexander.borisov@nginx.com } 596802Salexander.borisov@nginx.com 597802Salexander.borisov@nginx.com 598802Salexander.borisov@nginx.com napi_value 5991132Smax.romanov@nginx.com Unit::create_websocket_frame(napi_value server_obj, 6001132Smax.romanov@nginx.com nxt_unit_websocket_frame_t *ws) 601802Salexander.borisov@nginx.com { 6021132Smax.romanov@nginx.com void *data; 6031132Smax.romanov@nginx.com napi_value constructor, res, buffer; 6041132Smax.romanov@nginx.com uint8_t sc[2]; 6051132Smax.romanov@nginx.com 6061132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "WebSocketFrame"); 607802Salexander.borisov@nginx.com 6081132Smax.romanov@nginx.com res = new_instance(constructor); 6091132Smax.romanov@nginx.com 6101132Smax.romanov@nginx.com set_named_property(res, "fin", (bool) ws->header->fin); 6111132Smax.romanov@nginx.com set_named_property(res, "opcode", ws->header->opcode); 6121132Smax.romanov@nginx.com set_named_property(res, "length", (int64_t) ws->payload_len); 613802Salexander.borisov@nginx.com 6141132Smax.romanov@nginx.com if (ws->header->opcode == NXT_WEBSOCKET_OP_CLOSE) { 6151132Smax.romanov@nginx.com if (ws->payload_len >= 2) { 6161132Smax.romanov@nginx.com nxt_unit_websocket_read(ws, sc, 2); 6171132Smax.romanov@nginx.com 6181132Smax.romanov@nginx.com set_named_property(res, "closeStatus", 6191132Smax.romanov@nginx.com (((uint16_t) sc[0]) << 8) | sc[1]); 620802Salexander.borisov@nginx.com 6211132Smax.romanov@nginx.com } else { 6221132Smax.romanov@nginx.com set_named_property(res, "closeStatus", -1); 6231132Smax.romanov@nginx.com } 6241132Smax.romanov@nginx.com } 625802Salexander.borisov@nginx.com 6261132Smax.romanov@nginx.com buffer = create_buffer((size_t) ws->content_length, &data); 6271132Smax.romanov@nginx.com nxt_unit_websocket_read(ws, data, ws->content_length); 6281132Smax.romanov@nginx.com 6291132Smax.romanov@nginx.com set_named_property(res, "binaryPayload", buffer); 6301132Smax.romanov@nginx.com 6311132Smax.romanov@nginx.com return res; 632802Salexander.borisov@nginx.com } 633802Salexander.borisov@nginx.com 634802Salexander.borisov@nginx.com 635802Salexander.borisov@nginx.com napi_value 636802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info) 637802Salexander.borisov@nginx.com { 638802Salexander.borisov@nginx.com int ret; 639802Salexander.borisov@nginx.com char *ptr, *name_ptr; 640802Salexander.borisov@nginx.com bool is_array; 641802Salexander.borisov@nginx.com size_t argc, name_len, value_len; 642802Salexander.borisov@nginx.com uint32_t status_code, header_len, keys_len, array_len; 643802Salexander.borisov@nginx.com uint32_t keys_count, i, j; 644802Salexander.borisov@nginx.com uint16_t hash; 6451020Smax.romanov@nginx.com nxt_napi napi(env); 646802Salexander.borisov@nginx.com napi_value this_arg, headers, keys, name, value, array_val; 6471132Smax.romanov@nginx.com napi_value array_entry; 648843Salexander.borisov@nginx.com napi_valuetype val_type; 649802Salexander.borisov@nginx.com nxt_unit_field_t *f; 650802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 6511132Smax.romanov@nginx.com napi_value argv[4]; 652802Salexander.borisov@nginx.com 6531132Smax.romanov@nginx.com argc = 4; 654802Salexander.borisov@nginx.com 6551020Smax.romanov@nginx.com try { 6561020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 6571132Smax.romanov@nginx.com if (argc != 4) { 6581020Smax.romanov@nginx.com napi.throw_error("Wrong args count. Expected: " 6591020Smax.romanov@nginx.com "statusCode, headers, headers count, " 6601020Smax.romanov@nginx.com "headers length"); 6611020Smax.romanov@nginx.com return nullptr; 6621020Smax.romanov@nginx.com } 663802Salexander.borisov@nginx.com 6641132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 6651132Smax.romanov@nginx.com status_code = napi.get_value_uint32(argv[0]); 6661132Smax.romanov@nginx.com keys_count = napi.get_value_uint32(argv[2]); 6671132Smax.romanov@nginx.com header_len = napi.get_value_uint32(argv[3]); 668802Salexander.borisov@nginx.com 6691132Smax.romanov@nginx.com headers = argv[1]; 670802Salexander.borisov@nginx.com 6711020Smax.romanov@nginx.com ret = nxt_unit_response_init(req, status_code, keys_count, header_len); 6721020Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 6731020Smax.romanov@nginx.com napi.throw_error("Failed to create response"); 6741020Smax.romanov@nginx.com return nullptr; 675802Salexander.borisov@nginx.com } 676802Salexander.borisov@nginx.com 6771257Smax.romanov@nginx.com /* 6781257Smax.romanov@nginx.com * Each name and value are 0-terminated by libunit. 6791257Smax.romanov@nginx.com * Need to add extra 2 bytes for each header. 6801257Smax.romanov@nginx.com */ 6811257Smax.romanov@nginx.com header_len += keys_count * 2; 6821257Smax.romanov@nginx.com 6831020Smax.romanov@nginx.com keys = napi.get_property_names(headers); 6841020Smax.romanov@nginx.com keys_len = napi.get_array_length(keys); 6851020Smax.romanov@nginx.com 6861020Smax.romanov@nginx.com ptr = req->response_buf->free; 687875Salexander.borisov@nginx.com 6881020Smax.romanov@nginx.com for (i = 0; i < keys_len; i++) { 6891020Smax.romanov@nginx.com name = napi.get_element(keys, i); 6901020Smax.romanov@nginx.com 6911020Smax.romanov@nginx.com array_entry = napi.get_property(headers, name); 6921020Smax.romanov@nginx.com 6931020Smax.romanov@nginx.com name = napi.get_element(array_entry, 0); 6941020Smax.romanov@nginx.com value = napi.get_element(array_entry, 1); 695875Salexander.borisov@nginx.com 6961020Smax.romanov@nginx.com name_len = napi.get_value_string_latin1(name, ptr, header_len); 6971020Smax.romanov@nginx.com name_ptr = ptr; 6981020Smax.romanov@nginx.com 6991257Smax.romanov@nginx.com ptr += name_len + 1; 7001257Smax.romanov@nginx.com header_len -= name_len + 1; 701802Salexander.borisov@nginx.com 7021020Smax.romanov@nginx.com hash = nxt_unit_field_hash(name_ptr, name_len); 7031020Smax.romanov@nginx.com 7041020Smax.romanov@nginx.com is_array = napi.is_array(value); 7051020Smax.romanov@nginx.com 7061020Smax.romanov@nginx.com if (is_array) { 7071020Smax.romanov@nginx.com array_len = napi.get_array_length(value); 708802Salexander.borisov@nginx.com 7091020Smax.romanov@nginx.com for (j = 0; j < array_len; j++) { 7101020Smax.romanov@nginx.com array_val = napi.get_element(value, j); 7111020Smax.romanov@nginx.com 7121020Smax.romanov@nginx.com val_type = napi.type_of(array_val); 713802Salexander.borisov@nginx.com 7141020Smax.romanov@nginx.com if (val_type != napi_string) { 7151020Smax.romanov@nginx.com array_val = napi.coerce_to_string(array_val); 7161020Smax.romanov@nginx.com } 717802Salexander.borisov@nginx.com 7181020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(array_val, ptr, 7191020Smax.romanov@nginx.com header_len); 720802Salexander.borisov@nginx.com 7211020Smax.romanov@nginx.com f = req->response->fields + req->response->fields_count; 7221020Smax.romanov@nginx.com f->skip = 0; 7231020Smax.romanov@nginx.com 7241020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 7251020Smax.romanov@nginx.com 7261020Smax.romanov@nginx.com f->name_length = name_len; 7271020Smax.romanov@nginx.com f->hash = hash; 728802Salexander.borisov@nginx.com 7291020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 7301020Smax.romanov@nginx.com f->value_length = (uint32_t) value_len; 731802Salexander.borisov@nginx.com 7321257Smax.romanov@nginx.com ptr += value_len + 1; 7331257Smax.romanov@nginx.com header_len -= value_len + 1; 7341020Smax.romanov@nginx.com 7351020Smax.romanov@nginx.com req->response->fields_count++; 736802Salexander.borisov@nginx.com } 737802Salexander.borisov@nginx.com 7381020Smax.romanov@nginx.com } else { 7391020Smax.romanov@nginx.com val_type = napi.type_of(value); 740843Salexander.borisov@nginx.com 741843Salexander.borisov@nginx.com if (val_type != napi_string) { 7421020Smax.romanov@nginx.com value = napi.coerce_to_string(value); 743843Salexander.borisov@nginx.com } 744843Salexander.borisov@nginx.com 7451020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(value, ptr, header_len); 746802Salexander.borisov@nginx.com 747802Salexander.borisov@nginx.com f = req->response->fields + req->response->fields_count; 748802Salexander.borisov@nginx.com f->skip = 0; 749802Salexander.borisov@nginx.com 750802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 751802Salexander.borisov@nginx.com 752802Salexander.borisov@nginx.com f->name_length = name_len; 753802Salexander.borisov@nginx.com f->hash = hash; 754802Salexander.borisov@nginx.com 755802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 756802Salexander.borisov@nginx.com f->value_length = (uint32_t) value_len; 757802Salexander.borisov@nginx.com 7581257Smax.romanov@nginx.com ptr += value_len + 1; 7591257Smax.romanov@nginx.com header_len -= value_len + 1; 760802Salexander.borisov@nginx.com 761802Salexander.borisov@nginx.com req->response->fields_count++; 762802Salexander.borisov@nginx.com } 7631020Smax.romanov@nginx.com } 764843Salexander.borisov@nginx.com 7651020Smax.romanov@nginx.com } catch (exception &e) { 7661020Smax.romanov@nginx.com napi.throw_error(e); 7671020Smax.romanov@nginx.com return nullptr; 768802Salexander.borisov@nginx.com } 769802Salexander.borisov@nginx.com 770802Salexander.borisov@nginx.com req->response_buf->free = ptr; 771802Salexander.borisov@nginx.com 772802Salexander.borisov@nginx.com ret = nxt_unit_response_send(req); 773802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 7741020Smax.romanov@nginx.com napi.throw_error("Failed to send response"); 7751020Smax.romanov@nginx.com return nullptr; 776802Salexander.borisov@nginx.com } 777802Salexander.borisov@nginx.com 778802Salexander.borisov@nginx.com return this_arg; 779802Salexander.borisov@nginx.com } 780802Salexander.borisov@nginx.com 781802Salexander.borisov@nginx.com 782802Salexander.borisov@nginx.com napi_value 783802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info) 784802Salexander.borisov@nginx.com { 785802Salexander.borisov@nginx.com int ret; 7861132Smax.romanov@nginx.com void *ptr; 787802Salexander.borisov@nginx.com size_t argc, have_buf_len; 788*1322Smax.romanov@nginx.com ssize_t res_len; 789*1322Smax.romanov@nginx.com uint32_t buf_start, buf_len; 7901020Smax.romanov@nginx.com nxt_napi napi(env); 7911132Smax.romanov@nginx.com napi_value this_arg; 792802Salexander.borisov@nginx.com nxt_unit_buf_t *buf; 793802Salexander.borisov@nginx.com napi_valuetype buf_type; 794802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 795*1322Smax.romanov@nginx.com napi_value argv[3]; 796802Salexander.borisov@nginx.com 797*1322Smax.romanov@nginx.com argc = 3; 798802Salexander.borisov@nginx.com 7991020Smax.romanov@nginx.com try { 8001020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 801*1322Smax.romanov@nginx.com if (argc != 3) { 8021020Smax.romanov@nginx.com throw exception("Wrong args count. Expected: " 803*1322Smax.romanov@nginx.com "chunk, start, length"); 8041020Smax.romanov@nginx.com } 805802Salexander.borisov@nginx.com 8061132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 8071132Smax.romanov@nginx.com buf_type = napi.type_of(argv[0]); 808*1322Smax.romanov@nginx.com buf_start = napi.get_value_uint32(argv[1]); 809*1322Smax.romanov@nginx.com buf_len = napi.get_value_uint32(argv[2]) + 1; 8101132Smax.romanov@nginx.com 8111132Smax.romanov@nginx.com if (buf_type == napi_string) { 8121132Smax.romanov@nginx.com /* TODO: will work only for utf8 content-type */ 813802Salexander.borisov@nginx.com 814*1322Smax.romanov@nginx.com if (req->response_buf != NULL 815*1322Smax.romanov@nginx.com && (req->response_buf->end - req->response_buf->free) 816*1322Smax.romanov@nginx.com >= buf_len) 817*1322Smax.romanov@nginx.com { 818*1322Smax.romanov@nginx.com buf = req->response_buf; 819*1322Smax.romanov@nginx.com 820*1322Smax.romanov@nginx.com } else { 821*1322Smax.romanov@nginx.com buf = nxt_unit_response_buf_alloc(req, buf_len); 822*1322Smax.romanov@nginx.com if (buf == NULL) { 823*1322Smax.romanov@nginx.com throw exception("Failed to allocate response buffer"); 824*1322Smax.romanov@nginx.com } 825*1322Smax.romanov@nginx.com } 826*1322Smax.romanov@nginx.com 8271132Smax.romanov@nginx.com have_buf_len = napi.get_value_string_utf8(argv[0], buf->free, 8281132Smax.romanov@nginx.com buf_len); 8291132Smax.romanov@nginx.com 830*1322Smax.romanov@nginx.com buf->free += have_buf_len; 831*1322Smax.romanov@nginx.com 832*1322Smax.romanov@nginx.com ret = nxt_unit_buf_send(buf); 833*1322Smax.romanov@nginx.com if (ret == NXT_UNIT_OK) { 834*1322Smax.romanov@nginx.com res_len = have_buf_len; 835*1322Smax.romanov@nginx.com } 836*1322Smax.romanov@nginx.com 8371132Smax.romanov@nginx.com } else { 8381132Smax.romanov@nginx.com ptr = napi.get_buffer_info(argv[0], have_buf_len); 839802Salexander.borisov@nginx.com 840*1322Smax.romanov@nginx.com if (buf_start > 0) { 841*1322Smax.romanov@nginx.com ptr = ((uint8_t *) ptr) + buf_start; 842*1322Smax.romanov@nginx.com have_buf_len -= buf_start; 843*1322Smax.romanov@nginx.com } 844*1322Smax.romanov@nginx.com 845*1322Smax.romanov@nginx.com res_len = nxt_unit_response_write_nb(req, ptr, have_buf_len, 0); 846*1322Smax.romanov@nginx.com 847*1322Smax.romanov@nginx.com ret = res_len < 0 ? -res_len : NXT_UNIT_OK; 8481132Smax.romanov@nginx.com } 8491132Smax.romanov@nginx.com 8501132Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 8511132Smax.romanov@nginx.com throw exception("Failed to send body buf"); 8521132Smax.romanov@nginx.com } 8531020Smax.romanov@nginx.com } catch (exception &e) { 8541020Smax.romanov@nginx.com napi.throw_error(e); 8551020Smax.romanov@nginx.com return nullptr; 856802Salexander.borisov@nginx.com } 857802Salexander.borisov@nginx.com 858*1322Smax.romanov@nginx.com return napi.create((int64_t) res_len); 859802Salexander.borisov@nginx.com } 860802Salexander.borisov@nginx.com 861802Salexander.borisov@nginx.com 862802Salexander.borisov@nginx.com napi_value 863802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info) 864802Salexander.borisov@nginx.com { 8651020Smax.romanov@nginx.com nxt_napi napi(env); 8661132Smax.romanov@nginx.com napi_value this_arg; 8671132Smax.romanov@nginx.com req_data_t *req_data; 868802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 869802Salexander.borisov@nginx.com 8701132Smax.romanov@nginx.com try { 8711132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info); 8721132Smax.romanov@nginx.com 8731132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 874802Salexander.borisov@nginx.com 8751132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 8761020Smax.romanov@nginx.com 8771132Smax.romanov@nginx.com napi.remove_wrap(req_data->sock_ref); 8781132Smax.romanov@nginx.com napi.remove_wrap(req_data->resp_ref); 8791132Smax.romanov@nginx.com napi.remove_wrap(req_data->conn_ref); 8801020Smax.romanov@nginx.com 8811020Smax.romanov@nginx.com } catch (exception &e) { 8821020Smax.romanov@nginx.com napi.throw_error(e); 883802Salexander.borisov@nginx.com return nullptr; 884802Salexander.borisov@nginx.com } 885802Salexander.borisov@nginx.com 886802Salexander.borisov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 887802Salexander.borisov@nginx.com 888802Salexander.borisov@nginx.com return this_arg; 889802Salexander.borisov@nginx.com } 8901132Smax.romanov@nginx.com 8911132Smax.romanov@nginx.com 8921132Smax.romanov@nginx.com napi_value 8931132Smax.romanov@nginx.com Unit::websocket_send_frame(napi_env env, napi_callback_info info) 8941132Smax.romanov@nginx.com { 8951132Smax.romanov@nginx.com int ret, iovec_len; 8961132Smax.romanov@nginx.com bool fin; 8971132Smax.romanov@nginx.com size_t buf_len; 8981132Smax.romanov@nginx.com uint32_t opcode, sc; 8991132Smax.romanov@nginx.com nxt_napi napi(env); 9001132Smax.romanov@nginx.com napi_value this_arg, frame, payload; 9011132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 9021132Smax.romanov@nginx.com char status_code[2]; 9031132Smax.romanov@nginx.com struct iovec iov[2]; 9041132Smax.romanov@nginx.com 9051132Smax.romanov@nginx.com iovec_len = 0; 9061132Smax.romanov@nginx.com 9071132Smax.romanov@nginx.com try { 9081132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, frame); 9091132Smax.romanov@nginx.com 9101132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 9111132Smax.romanov@nginx.com 9121132Smax.romanov@nginx.com opcode = napi.get_value_uint32(napi.get_named_property(frame, 9131132Smax.romanov@nginx.com "opcode")); 9141132Smax.romanov@nginx.com if (opcode == NXT_WEBSOCKET_OP_CLOSE) { 9151132Smax.romanov@nginx.com sc = napi.get_value_uint32(napi.get_named_property(frame, 9161132Smax.romanov@nginx.com "closeStatus")); 9171132Smax.romanov@nginx.com status_code[0] = (sc >> 8) & 0xFF; 9181132Smax.romanov@nginx.com status_code[1] = sc & 0xFF; 9191132Smax.romanov@nginx.com 9201132Smax.romanov@nginx.com iov[iovec_len].iov_base = status_code; 9211132Smax.romanov@nginx.com iov[iovec_len].iov_len = 2; 9221132Smax.romanov@nginx.com iovec_len++; 9231132Smax.romanov@nginx.com } 9241132Smax.romanov@nginx.com 9251132Smax.romanov@nginx.com try { 9261132Smax.romanov@nginx.com fin = napi.get_value_bool(napi.get_named_property(frame, "fin")); 9271132Smax.romanov@nginx.com 9281132Smax.romanov@nginx.com } catch (exception &e) { 9291132Smax.romanov@nginx.com fin = true; 9301132Smax.romanov@nginx.com } 9311132Smax.romanov@nginx.com 9321132Smax.romanov@nginx.com payload = napi.get_named_property(frame, "binaryPayload"); 9331132Smax.romanov@nginx.com 9341132Smax.romanov@nginx.com if (napi.is_buffer(payload)) { 9351132Smax.romanov@nginx.com iov[iovec_len].iov_base = napi.get_buffer_info(payload, buf_len); 9361132Smax.romanov@nginx.com 9371132Smax.romanov@nginx.com } else { 9381132Smax.romanov@nginx.com buf_len = 0; 9391132Smax.romanov@nginx.com } 9401132Smax.romanov@nginx.com 9411132Smax.romanov@nginx.com } catch (exception &e) { 9421132Smax.romanov@nginx.com napi.throw_error(e); 9431132Smax.romanov@nginx.com return nullptr; 9441132Smax.romanov@nginx.com } 9451132Smax.romanov@nginx.com 9461132Smax.romanov@nginx.com if (buf_len > 0) { 9471132Smax.romanov@nginx.com iov[iovec_len].iov_len = buf_len; 9481132Smax.romanov@nginx.com iovec_len++; 9491132Smax.romanov@nginx.com } 9501132Smax.romanov@nginx.com 9511132Smax.romanov@nginx.com ret = nxt_unit_websocket_sendv(req, opcode, fin ? 1 : 0, iov, iovec_len); 9521132Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 9531132Smax.romanov@nginx.com goto failed; 9541132Smax.romanov@nginx.com } 9551132Smax.romanov@nginx.com 9561132Smax.romanov@nginx.com return this_arg; 9571132Smax.romanov@nginx.com 9581132Smax.romanov@nginx.com failed: 9591132Smax.romanov@nginx.com 9601132Smax.romanov@nginx.com napi.throw_error("Failed to send frame"); 9611132Smax.romanov@nginx.com 9621132Smax.romanov@nginx.com return nullptr; 9631132Smax.romanov@nginx.com } 9641132Smax.romanov@nginx.com 9651132Smax.romanov@nginx.com 9661132Smax.romanov@nginx.com napi_value 9671132Smax.romanov@nginx.com Unit::websocket_set_sock(napi_env env, napi_callback_info info) 9681132Smax.romanov@nginx.com { 9691132Smax.romanov@nginx.com nxt_napi napi(env); 9701132Smax.romanov@nginx.com napi_value this_arg, sock; 9711132Smax.romanov@nginx.com req_data_t *req_data; 9721132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 9731132Smax.romanov@nginx.com 9741132Smax.romanov@nginx.com try { 9751132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, sock); 9761132Smax.romanov@nginx.com 9771132Smax.romanov@nginx.com req = napi.get_request_info(sock); 9781132Smax.romanov@nginx.com 9791132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 9801132Smax.romanov@nginx.com req_data->conn_ref = napi.wrap(this_arg, req, conn_destroy); 9811132Smax.romanov@nginx.com 9821132Smax.romanov@nginx.com } catch (exception &e) { 9831132Smax.romanov@nginx.com napi.throw_error(e); 9841132Smax.romanov@nginx.com return nullptr; 9851132Smax.romanov@nginx.com } 9861132Smax.romanov@nginx.com 9871132Smax.romanov@nginx.com return this_arg; 9881132Smax.romanov@nginx.com } 9891132Smax.romanov@nginx.com 9901132Smax.romanov@nginx.com 9911132Smax.romanov@nginx.com void 9921132Smax.romanov@nginx.com Unit::conn_destroy(napi_env env, void *nativeObject, void *finalize_hint) 9931132Smax.romanov@nginx.com { 9941132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 9951132Smax.romanov@nginx.com 9961132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 9971132Smax.romanov@nginx.com 9981132Smax.romanov@nginx.com nxt_unit_warn(NULL, "conn_destroy: %p", req); 9991132Smax.romanov@nginx.com } 10001132Smax.romanov@nginx.com 10011132Smax.romanov@nginx.com 10021132Smax.romanov@nginx.com void 10031132Smax.romanov@nginx.com Unit::sock_destroy(napi_env env, void *nativeObject, void *finalize_hint) 10041132Smax.romanov@nginx.com { 10051132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 10061132Smax.romanov@nginx.com 10071132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 10081132Smax.romanov@nginx.com 10091132Smax.romanov@nginx.com nxt_unit_warn(NULL, "sock_destroy: %p", req); 10101132Smax.romanov@nginx.com } 10111132Smax.romanov@nginx.com 10121132Smax.romanov@nginx.com 10131132Smax.romanov@nginx.com void 10141132Smax.romanov@nginx.com Unit::resp_destroy(napi_env env, void *nativeObject, void *finalize_hint) 10151132Smax.romanov@nginx.com { 10161132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 10171132Smax.romanov@nginx.com 10181132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 10191132Smax.romanov@nginx.com 10201132Smax.romanov@nginx.com nxt_unit_warn(NULL, "resp_destroy: %p", req); 10211132Smax.romanov@nginx.com } 1022