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 13*1132Smax.romanov@nginx.com #include <nxt_unit_websocket.h> 14*1132Smax.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 25*1132Smax.romanov@nginx.com struct req_data_t { 26*1132Smax.romanov@nginx.com napi_ref sock_ref; 27*1132Smax.romanov@nginx.com napi_ref resp_ref; 28*1132Smax.romanov@nginx.com napi_ref conn_ref; 29*1132Smax.romanov@nginx.com }; 30*1132Smax.romanov@nginx.com 31*1132Smax.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 { 37*1132Smax.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_); 44*1132Smax.romanov@nginx.com 45*1132Smax.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); 53*1132Smax.romanov@nginx.com napi_value ctor; 54802Salexander.borisov@nginx.com 55*1132Smax.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 { 61*1132Smax.romanov@nginx.com ctor = napi.define_class("Unit", create, 2, unit_props); 62*1132Smax.romanov@nginx.com constructor_ = napi.create_reference(ctor); 63802Salexander.borisov@nginx.com 64*1132Smax.romanov@nginx.com napi.set_named_property(exports, "Unit", ctor); 65*1132Smax.romanov@nginx.com napi.set_named_property(exports, "response_send_headers", 661020Smax.romanov@nginx.com response_send_headers); 67*1132Smax.romanov@nginx.com napi.set_named_property(exports, "response_write", response_write); 68*1132Smax.romanov@nginx.com napi.set_named_property(exports, "response_end", response_end); 69*1132Smax.romanov@nginx.com napi.set_named_property(exports, "websocket_send_frame", 70*1132Smax.romanov@nginx.com websocket_send_frame); 71*1132Smax.romanov@nginx.com napi.set_named_property(exports, "websocket_set_sock", 72*1132Smax.romanov@nginx.com websocket_set_sock); 73802Salexander.borisov@nginx.com 741020Smax.romanov@nginx.com } catch (exception &e) { 751020Smax.romanov@nginx.com napi.throw_error(e); 761020Smax.romanov@nginx.com return nullptr; 77802Salexander.borisov@nginx.com } 78802Salexander.borisov@nginx.com 79802Salexander.borisov@nginx.com return exports; 80802Salexander.borisov@nginx.com } 81802Salexander.borisov@nginx.com 82802Salexander.borisov@nginx.com 83802Salexander.borisov@nginx.com void 84802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) 85802Salexander.borisov@nginx.com { 86802Salexander.borisov@nginx.com Unit *obj = reinterpret_cast<Unit *>(nativeObject); 87802Salexander.borisov@nginx.com 88802Salexander.borisov@nginx.com delete obj; 89802Salexander.borisov@nginx.com } 90802Salexander.borisov@nginx.com 91802Salexander.borisov@nginx.com 92802Salexander.borisov@nginx.com napi_value 93802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info) 94802Salexander.borisov@nginx.com { 951020Smax.romanov@nginx.com nxt_napi napi(env); 96*1132Smax.romanov@nginx.com napi_value target, ctor, instance, jsthis; 971020Smax.romanov@nginx.com 981020Smax.romanov@nginx.com try { 991020Smax.romanov@nginx.com target = napi.get_new_target(info); 100802Salexander.borisov@nginx.com 1011020Smax.romanov@nginx.com if (target != nullptr) { 1021020Smax.romanov@nginx.com /* Invoked as constructor: `new Unit(...)`. */ 1031020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info); 104802Salexander.borisov@nginx.com 1051023Smax.romanov@nginx.com new Unit(env, jsthis); 1061023Smax.romanov@nginx.com napi.create_reference(jsthis); 1071020Smax.romanov@nginx.com 1081020Smax.romanov@nginx.com return jsthis; 109802Salexander.borisov@nginx.com } 110802Salexander.borisov@nginx.com 1111020Smax.romanov@nginx.com /* Invoked as plain function `Unit(...)`, turn into construct call. */ 112*1132Smax.romanov@nginx.com ctor = napi.get_reference_value(constructor_); 113*1132Smax.romanov@nginx.com instance = napi.new_instance(ctor); 1141023Smax.romanov@nginx.com napi.create_reference(instance); 115841Salexander.borisov@nginx.com 1161020Smax.romanov@nginx.com } catch (exception &e) { 1171020Smax.romanov@nginx.com napi.throw_error(e); 1181020Smax.romanov@nginx.com return nullptr; 119841Salexander.borisov@nginx.com } 120841Salexander.borisov@nginx.com 121802Salexander.borisov@nginx.com return instance; 122802Salexander.borisov@nginx.com } 123802Salexander.borisov@nginx.com 124802Salexander.borisov@nginx.com 125802Salexander.borisov@nginx.com napi_value 126802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info) 127802Salexander.borisov@nginx.com { 128802Salexander.borisov@nginx.com Unit *obj; 129802Salexander.borisov@nginx.com size_t argc; 1301020Smax.romanov@nginx.com nxt_napi napi(env); 131828Salexander.borisov@nginx.com napi_value jsthis, argv; 132802Salexander.borisov@nginx.com nxt_unit_init_t unit_init; 133802Salexander.borisov@nginx.com 134802Salexander.borisov@nginx.com argc = 1; 135802Salexander.borisov@nginx.com 1361020Smax.romanov@nginx.com try { 1371020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info, argc, &argv); 1381020Smax.romanov@nginx.com obj = (Unit *) napi.unwrap(jsthis); 139802Salexander.borisov@nginx.com 1401020Smax.romanov@nginx.com } catch (exception &e) { 1411020Smax.romanov@nginx.com napi.throw_error(e); 1421020Smax.romanov@nginx.com return nullptr; 143802Salexander.borisov@nginx.com } 144802Salexander.borisov@nginx.com 145802Salexander.borisov@nginx.com memset(&unit_init, 0, sizeof(nxt_unit_init_t)); 146802Salexander.borisov@nginx.com 147802Salexander.borisov@nginx.com unit_init.data = obj; 148*1132Smax.romanov@nginx.com unit_init.callbacks.request_handler = request_handler_cb; 149*1132Smax.romanov@nginx.com unit_init.callbacks.websocket_handler = websocket_handler_cb; 150*1132Smax.romanov@nginx.com unit_init.callbacks.close_handler = close_handler_cb; 151*1132Smax.romanov@nginx.com unit_init.callbacks.add_port = add_port; 152*1132Smax.romanov@nginx.com unit_init.callbacks.remove_port = remove_port; 153*1132Smax.romanov@nginx.com unit_init.callbacks.quit = quit_cb; 154*1132Smax.romanov@nginx.com 155*1132Smax.romanov@nginx.com unit_init.request_data_size = sizeof(req_data_t); 156802Salexander.borisov@nginx.com 157802Salexander.borisov@nginx.com obj->unit_ctx_ = nxt_unit_init(&unit_init); 158802Salexander.borisov@nginx.com if (obj->unit_ctx_ == NULL) { 159802Salexander.borisov@nginx.com goto failed; 160802Salexander.borisov@nginx.com } 161802Salexander.borisov@nginx.com 162802Salexander.borisov@nginx.com return nullptr; 163802Salexander.borisov@nginx.com 164802Salexander.borisov@nginx.com failed: 165802Salexander.borisov@nginx.com 166802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create Unit object"); 167802Salexander.borisov@nginx.com 168802Salexander.borisov@nginx.com return nullptr; 169802Salexander.borisov@nginx.com } 170802Salexander.borisov@nginx.com 171802Salexander.borisov@nginx.com 172802Salexander.borisov@nginx.com napi_value 173802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info) 174802Salexander.borisov@nginx.com { 175828Salexander.borisov@nginx.com return nullptr; 176828Salexander.borisov@nginx.com } 177828Salexander.borisov@nginx.com 178802Salexander.borisov@nginx.com 179*1132Smax.romanov@nginx.com void 180*1132Smax.romanov@nginx.com Unit::request_handler_cb(nxt_unit_request_info_t *req) 181828Salexander.borisov@nginx.com { 182*1132Smax.romanov@nginx.com Unit *obj; 183828Salexander.borisov@nginx.com 184*1132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 185802Salexander.borisov@nginx.com 186*1132Smax.romanov@nginx.com obj->request_handler(req); 187802Salexander.borisov@nginx.com } 188802Salexander.borisov@nginx.com 189802Salexander.borisov@nginx.com 190802Salexander.borisov@nginx.com void 191802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req) 192802Salexander.borisov@nginx.com { 193*1132Smax.romanov@nginx.com napi_value socket, request, response, server_obj, emit_request; 194802Salexander.borisov@nginx.com 195*1132Smax.romanov@nginx.com memset(req->data, 0, sizeof(req_data_t)); 196802Salexander.borisov@nginx.com 1971020Smax.romanov@nginx.com try { 198*1132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 199802Salexander.borisov@nginx.com 200*1132Smax.romanov@nginx.com server_obj = get_server_object(); 201802Salexander.borisov@nginx.com 202*1132Smax.romanov@nginx.com socket = create_socket(server_obj, req); 203*1132Smax.romanov@nginx.com request = create_request(server_obj, socket); 204*1132Smax.romanov@nginx.com response = create_response(server_obj, request, req); 205828Salexander.borisov@nginx.com 206*1132Smax.romanov@nginx.com create_headers(req, request); 207871Salexander.borisov@nginx.com 208*1132Smax.romanov@nginx.com emit_request = get_named_property(server_obj, "emit_request"); 209*1132Smax.romanov@nginx.com 210*1132Smax.romanov@nginx.com nxt_async_context async_context(env(), "request_handler"); 2111020Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 212876Salexander.borisov@nginx.com 213*1132Smax.romanov@nginx.com make_callback(async_context, server_obj, emit_request, request, 214*1132Smax.romanov@nginx.com response); 215871Salexander.borisov@nginx.com 2161020Smax.romanov@nginx.com } catch (exception &e) { 217*1132Smax.romanov@nginx.com nxt_unit_req_warn(req, "request_handler: %s", e.str); 218871Salexander.borisov@nginx.com } 219802Salexander.borisov@nginx.com } 220802Salexander.borisov@nginx.com 221802Salexander.borisov@nginx.com 222828Salexander.borisov@nginx.com void 223*1132Smax.romanov@nginx.com Unit::websocket_handler_cb(nxt_unit_websocket_frame_t *ws) 224*1132Smax.romanov@nginx.com { 225*1132Smax.romanov@nginx.com Unit *obj; 226*1132Smax.romanov@nginx.com 227*1132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ws->req->unit->data); 228*1132Smax.romanov@nginx.com 229*1132Smax.romanov@nginx.com obj->websocket_handler(ws); 230*1132Smax.romanov@nginx.com } 231*1132Smax.romanov@nginx.com 232*1132Smax.romanov@nginx.com 233*1132Smax.romanov@nginx.com void 234*1132Smax.romanov@nginx.com Unit::websocket_handler(nxt_unit_websocket_frame_t *ws) 235*1132Smax.romanov@nginx.com { 236*1132Smax.romanov@nginx.com napi_value frame, server_obj, process_frame, conn; 237*1132Smax.romanov@nginx.com req_data_t *req_data; 238*1132Smax.romanov@nginx.com 239*1132Smax.romanov@nginx.com req_data = (req_data_t *) ws->req->data; 240*1132Smax.romanov@nginx.com 241*1132Smax.romanov@nginx.com try { 242*1132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 243*1132Smax.romanov@nginx.com 244*1132Smax.romanov@nginx.com server_obj = get_server_object(); 245*1132Smax.romanov@nginx.com 246*1132Smax.romanov@nginx.com frame = create_websocket_frame(server_obj, ws); 247*1132Smax.romanov@nginx.com 248*1132Smax.romanov@nginx.com conn = get_reference_value(req_data->conn_ref); 249*1132Smax.romanov@nginx.com 250*1132Smax.romanov@nginx.com process_frame = get_named_property(conn, "processFrame"); 251*1132Smax.romanov@nginx.com 252*1132Smax.romanov@nginx.com nxt_async_context async_context(env(), "websocket_handler"); 253*1132Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 254*1132Smax.romanov@nginx.com 255*1132Smax.romanov@nginx.com make_callback(async_context, conn, process_frame, frame); 256*1132Smax.romanov@nginx.com 257*1132Smax.romanov@nginx.com } catch (exception &e) { 258*1132Smax.romanov@nginx.com nxt_unit_req_warn(ws->req, "websocket_handler: %s", e.str); 259*1132Smax.romanov@nginx.com } 260*1132Smax.romanov@nginx.com 261*1132Smax.romanov@nginx.com nxt_unit_websocket_done(ws); 262*1132Smax.romanov@nginx.com } 263*1132Smax.romanov@nginx.com 264*1132Smax.romanov@nginx.com 265*1132Smax.romanov@nginx.com void 266*1132Smax.romanov@nginx.com Unit::close_handler_cb(nxt_unit_request_info_t *req) 267*1132Smax.romanov@nginx.com { 268*1132Smax.romanov@nginx.com Unit *obj; 269*1132Smax.romanov@nginx.com 270*1132Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 271*1132Smax.romanov@nginx.com 272*1132Smax.romanov@nginx.com obj->close_handler(req); 273*1132Smax.romanov@nginx.com } 274*1132Smax.romanov@nginx.com 275*1132Smax.romanov@nginx.com 276*1132Smax.romanov@nginx.com void 277*1132Smax.romanov@nginx.com Unit::close_handler(nxt_unit_request_info_t *req) 278*1132Smax.romanov@nginx.com { 279*1132Smax.romanov@nginx.com napi_value conn_handle_close, conn; 280*1132Smax.romanov@nginx.com req_data_t *req_data; 281*1132Smax.romanov@nginx.com 282*1132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 283*1132Smax.romanov@nginx.com 284*1132Smax.romanov@nginx.com try { 285*1132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 286*1132Smax.romanov@nginx.com 287*1132Smax.romanov@nginx.com conn = get_reference_value(req_data->conn_ref); 288*1132Smax.romanov@nginx.com 289*1132Smax.romanov@nginx.com conn_handle_close = get_named_property(conn, "handleSocketClose"); 290*1132Smax.romanov@nginx.com 291*1132Smax.romanov@nginx.com nxt_async_context async_context(env(), "close_handler"); 292*1132Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 293*1132Smax.romanov@nginx.com 294*1132Smax.romanov@nginx.com make_callback(async_context, conn, conn_handle_close, 295*1132Smax.romanov@nginx.com nxt_napi::create(0)); 296*1132Smax.romanov@nginx.com 297*1132Smax.romanov@nginx.com remove_wrap(req_data->sock_ref); 298*1132Smax.romanov@nginx.com remove_wrap(req_data->resp_ref); 299*1132Smax.romanov@nginx.com remove_wrap(req_data->conn_ref); 300*1132Smax.romanov@nginx.com 301*1132Smax.romanov@nginx.com } catch (exception &e) { 302*1132Smax.romanov@nginx.com nxt_unit_req_warn(req, "close_handler: %s", e.str); 303*1132Smax.romanov@nginx.com 304*1132Smax.romanov@nginx.com return; 305*1132Smax.romanov@nginx.com } 306*1132Smax.romanov@nginx.com 307*1132Smax.romanov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 308*1132Smax.romanov@nginx.com } 309*1132Smax.romanov@nginx.com 310*1132Smax.romanov@nginx.com 311*1132Smax.romanov@nginx.com static void 312828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events) 313828Salexander.borisov@nginx.com { 314828Salexander.borisov@nginx.com nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); 315828Salexander.borisov@nginx.com } 316828Salexander.borisov@nginx.com 317828Salexander.borisov@nginx.com 318828Salexander.borisov@nginx.com int 319828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 320828Salexander.borisov@nginx.com { 321842Salexander.borisov@nginx.com int err; 322842Salexander.borisov@nginx.com Unit *obj; 323842Salexander.borisov@nginx.com uv_loop_t *loop; 324842Salexander.borisov@nginx.com napi_status status; 325842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 326828Salexander.borisov@nginx.com 327828Salexander.borisov@nginx.com if (port->in_fd != -1) { 328828Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 329828Salexander.borisov@nginx.com 330828Salexander.borisov@nginx.com if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { 331*1132Smax.romanov@nginx.com nxt_unit_warn(ctx, "fcntl(%d, O_NONBLOCK) failed: %s (%d)", 332*1132Smax.romanov@nginx.com port->in_fd, strerror(errno), errno); 333828Salexander.borisov@nginx.com return -1; 334828Salexander.borisov@nginx.com } 335828Salexander.borisov@nginx.com 3361020Smax.romanov@nginx.com status = napi_get_uv_event_loop(obj->env(), &loop); 337828Salexander.borisov@nginx.com if (status != napi_ok) { 338*1132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to get uv.loop"); 339828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 340828Salexander.borisov@nginx.com } 341828Salexander.borisov@nginx.com 342842Salexander.borisov@nginx.com node_ctx = new nxt_nodejs_ctx_t; 343828Salexander.borisov@nginx.com 344842Salexander.borisov@nginx.com err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); 345828Salexander.borisov@nginx.com if (err < 0) { 346*1132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to init uv.poll"); 347828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 348828Salexander.borisov@nginx.com } 349828Salexander.borisov@nginx.com 350842Salexander.borisov@nginx.com err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); 351828Salexander.borisov@nginx.com if (err < 0) { 352*1132Smax.romanov@nginx.com nxt_unit_warn(ctx, "Failed to start uv.poll"); 353828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 354828Salexander.borisov@nginx.com } 355828Salexander.borisov@nginx.com 356842Salexander.borisov@nginx.com ctx->data = node_ctx; 357842Salexander.borisov@nginx.com 358842Salexander.borisov@nginx.com node_ctx->port_id = port->id; 359842Salexander.borisov@nginx.com node_ctx->poll.data = ctx; 360828Salexander.borisov@nginx.com } 361828Salexander.borisov@nginx.com 362828Salexander.borisov@nginx.com return nxt_unit_add_port(ctx, port); 363828Salexander.borisov@nginx.com } 364828Salexander.borisov@nginx.com 365828Salexander.borisov@nginx.com 3661008Szelenkov@nginx.com inline bool 367842Salexander.borisov@nginx.com operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) 368842Salexander.borisov@nginx.com { 369842Salexander.borisov@nginx.com return p1.pid == p2.pid && p1.id == p2.id; 370842Salexander.borisov@nginx.com } 371842Salexander.borisov@nginx.com 372842Salexander.borisov@nginx.com 373828Salexander.borisov@nginx.com void 374828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) 375828Salexander.borisov@nginx.com { 376842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 377842Salexander.borisov@nginx.com 378842Salexander.borisov@nginx.com if (ctx->data != NULL) { 379842Salexander.borisov@nginx.com node_ctx = (nxt_nodejs_ctx_t *) ctx->data; 380828Salexander.borisov@nginx.com 381842Salexander.borisov@nginx.com if (node_ctx->port_id == *port_id) { 382842Salexander.borisov@nginx.com uv_poll_stop(&node_ctx->poll); 383828Salexander.borisov@nginx.com 384842Salexander.borisov@nginx.com delete node_ctx; 385828Salexander.borisov@nginx.com 386842Salexander.borisov@nginx.com ctx->data = NULL; 387842Salexander.borisov@nginx.com } 388828Salexander.borisov@nginx.com } 389828Salexander.borisov@nginx.com 390828Salexander.borisov@nginx.com nxt_unit_remove_port(ctx, port_id); 391828Salexander.borisov@nginx.com } 392828Salexander.borisov@nginx.com 393828Salexander.borisov@nginx.com 394842Salexander.borisov@nginx.com void 395*1132Smax.romanov@nginx.com Unit::quit_cb(nxt_unit_ctx_t *ctx) 396842Salexander.borisov@nginx.com { 397*1132Smax.romanov@nginx.com Unit *obj; 3981021Smax.romanov@nginx.com 3991021Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 4001021Smax.romanov@nginx.com 401*1132Smax.romanov@nginx.com obj->quit(ctx); 402*1132Smax.romanov@nginx.com } 403*1132Smax.romanov@nginx.com 404*1132Smax.romanov@nginx.com 405*1132Smax.romanov@nginx.com void 406*1132Smax.romanov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx) 407*1132Smax.romanov@nginx.com { 408*1132Smax.romanov@nginx.com napi_value server_obj, emit_close; 4091021Smax.romanov@nginx.com 410*1132Smax.romanov@nginx.com try { 411*1132Smax.romanov@nginx.com nxt_handle_scope scope(env()); 4121021Smax.romanov@nginx.com 413*1132Smax.romanov@nginx.com server_obj = get_server_object(); 4141021Smax.romanov@nginx.com 415*1132Smax.romanov@nginx.com emit_close = get_named_property(server_obj, "emit_close"); 416*1132Smax.romanov@nginx.com 417*1132Smax.romanov@nginx.com nxt_async_context async_context(env(), "unit_quit"); 4181021Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 4191021Smax.romanov@nginx.com 420*1132Smax.romanov@nginx.com make_callback(async_context, server_obj, emit_close); 4211021Smax.romanov@nginx.com 4221021Smax.romanov@nginx.com } catch (exception &e) { 423*1132Smax.romanov@nginx.com nxt_unit_debug(ctx, "quit: %s", e.str); 4241021Smax.romanov@nginx.com } 4251021Smax.romanov@nginx.com 426842Salexander.borisov@nginx.com nxt_unit_done(ctx); 427842Salexander.borisov@nginx.com } 428842Salexander.borisov@nginx.com 429842Salexander.borisov@nginx.com 430802Salexander.borisov@nginx.com napi_value 431802Salexander.borisov@nginx.com Unit::get_server_object() 432802Salexander.borisov@nginx.com { 4331020Smax.romanov@nginx.com napi_value unit_obj; 434802Salexander.borisov@nginx.com 4351020Smax.romanov@nginx.com unit_obj = get_reference_value(wrapper_); 436802Salexander.borisov@nginx.com 4371020Smax.romanov@nginx.com return get_named_property(unit_obj, "server"); 438802Salexander.borisov@nginx.com } 439802Salexander.borisov@nginx.com 440802Salexander.borisov@nginx.com 4411020Smax.romanov@nginx.com void 442802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) 443802Salexander.borisov@nginx.com { 444*1132Smax.romanov@nginx.com void *data; 445802Salexander.borisov@nginx.com uint32_t i; 446*1132Smax.romanov@nginx.com napi_value headers, raw_headers, buffer; 447802Salexander.borisov@nginx.com napi_status status; 448802Salexander.borisov@nginx.com nxt_unit_request_t *r; 449802Salexander.borisov@nginx.com 450802Salexander.borisov@nginx.com r = req->request; 451802Salexander.borisov@nginx.com 4521020Smax.romanov@nginx.com headers = create_object(); 453802Salexander.borisov@nginx.com 4541020Smax.romanov@nginx.com status = napi_create_array_with_length(env(), r->fields_count * 2, 455802Salexander.borisov@nginx.com &raw_headers); 456802Salexander.borisov@nginx.com if (status != napi_ok) { 4571020Smax.romanov@nginx.com throw exception("Failed to create array"); 458802Salexander.borisov@nginx.com } 459802Salexander.borisov@nginx.com 460802Salexander.borisov@nginx.com for (i = 0; i < r->fields_count; i++) { 4611020Smax.romanov@nginx.com append_header(r->fields + i, headers, raw_headers, i); 462802Salexander.borisov@nginx.com } 463802Salexander.borisov@nginx.com 4641020Smax.romanov@nginx.com set_named_property(request, "headers", headers); 4651020Smax.romanov@nginx.com set_named_property(request, "rawHeaders", raw_headers); 4661020Smax.romanov@nginx.com set_named_property(request, "httpVersion", r->version, r->version_length); 4671020Smax.romanov@nginx.com set_named_property(request, "method", r->method, r->method_length); 4681020Smax.romanov@nginx.com set_named_property(request, "url", r->target, r->target_length); 469*1132Smax.romanov@nginx.com 470*1132Smax.romanov@nginx.com set_named_property(request, "_websocket_handshake", r->websocket_handshake); 471*1132Smax.romanov@nginx.com 472*1132Smax.romanov@nginx.com buffer = create_buffer((size_t) req->content_length, &data); 473*1132Smax.romanov@nginx.com nxt_unit_request_read(req, data, req->content_length); 474*1132Smax.romanov@nginx.com 475*1132Smax.romanov@nginx.com set_named_property(request, "_data", buffer); 476802Salexander.borisov@nginx.com } 477802Salexander.borisov@nginx.com 478802Salexander.borisov@nginx.com 4791038Smax.romanov@nginx.com inline char 4801038Smax.romanov@nginx.com lowcase(char c) 4811038Smax.romanov@nginx.com { 4821038Smax.romanov@nginx.com return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; 4831038Smax.romanov@nginx.com } 4841038Smax.romanov@nginx.com 4851038Smax.romanov@nginx.com 4861020Smax.romanov@nginx.com inline void 487802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers, 4881020Smax.romanov@nginx.com napi_value raw_headers, uint32_t idx) 489802Salexander.borisov@nginx.com { 4901038Smax.romanov@nginx.com char *name; 4911038Smax.romanov@nginx.com uint8_t i; 4921038Smax.romanov@nginx.com napi_value str, vstr; 4931038Smax.romanov@nginx.com 4941038Smax.romanov@nginx.com name = (char *) nxt_unit_sptr_get(&f->name); 495802Salexander.borisov@nginx.com 4961038Smax.romanov@nginx.com str = create_string_latin1(name, f->name_length); 4971038Smax.romanov@nginx.com 4981038Smax.romanov@nginx.com for (i = 0; i < f->name_length; i++) { 4991038Smax.romanov@nginx.com name[i] = lowcase(name[i]); 5001038Smax.romanov@nginx.com } 501802Salexander.borisov@nginx.com 5021020Smax.romanov@nginx.com vstr = set_named_property(headers, name, f->value, f->value_length); 503802Salexander.borisov@nginx.com 5041020Smax.romanov@nginx.com set_element(raw_headers, idx * 2, str); 5051020Smax.romanov@nginx.com set_element(raw_headers, idx * 2 + 1, vstr); 506802Salexander.borisov@nginx.com } 507802Salexander.borisov@nginx.com 508802Salexander.borisov@nginx.com 509802Salexander.borisov@nginx.com napi_value 510802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) 511802Salexander.borisov@nginx.com { 5121022Smax.romanov@nginx.com napi_value constructor, res; 513*1132Smax.romanov@nginx.com req_data_t *req_data; 5141022Smax.romanov@nginx.com nxt_unit_request_t *r; 5151022Smax.romanov@nginx.com 5161022Smax.romanov@nginx.com r = req->request; 517802Salexander.borisov@nginx.com 518*1132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "Socket"); 519802Salexander.borisov@nginx.com 5201022Smax.romanov@nginx.com res = new_instance(constructor); 521802Salexander.borisov@nginx.com 522*1132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 523*1132Smax.romanov@nginx.com req_data->sock_ref = wrap(res, req, sock_destroy); 524*1132Smax.romanov@nginx.com 5251022Smax.romanov@nginx.com set_named_property(res, "remoteAddress", r->remote, r->remote_length); 5261022Smax.romanov@nginx.com set_named_property(res, "localAddress", r->local, r->local_length); 527828Salexander.borisov@nginx.com 5281022Smax.romanov@nginx.com return res; 529802Salexander.borisov@nginx.com } 530802Salexander.borisov@nginx.com 531802Salexander.borisov@nginx.com 532802Salexander.borisov@nginx.com napi_value 533802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket) 534802Salexander.borisov@nginx.com { 535*1132Smax.romanov@nginx.com napi_value constructor; 536*1132Smax.romanov@nginx.com 537*1132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "ServerRequest"); 538802Salexander.borisov@nginx.com 539*1132Smax.romanov@nginx.com return new_instance(constructor, server_obj, socket); 540*1132Smax.romanov@nginx.com } 541*1132Smax.romanov@nginx.com 542802Salexander.borisov@nginx.com 543*1132Smax.romanov@nginx.com napi_value 544*1132Smax.romanov@nginx.com Unit::create_response(napi_value server_obj, napi_value request, 545*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req) 546*1132Smax.romanov@nginx.com { 547*1132Smax.romanov@nginx.com napi_value constructor, res; 548*1132Smax.romanov@nginx.com req_data_t *req_data; 549802Salexander.borisov@nginx.com 550*1132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "ServerResponse"); 551*1132Smax.romanov@nginx.com 552*1132Smax.romanov@nginx.com res = new_instance(constructor, request); 553802Salexander.borisov@nginx.com 554*1132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 555*1132Smax.romanov@nginx.com req_data->resp_ref = wrap(res, req, resp_destroy); 556*1132Smax.romanov@nginx.com 557*1132Smax.romanov@nginx.com return res; 558802Salexander.borisov@nginx.com } 559802Salexander.borisov@nginx.com 560802Salexander.borisov@nginx.com 561802Salexander.borisov@nginx.com napi_value 562*1132Smax.romanov@nginx.com Unit::create_websocket_frame(napi_value server_obj, 563*1132Smax.romanov@nginx.com nxt_unit_websocket_frame_t *ws) 564802Salexander.borisov@nginx.com { 565*1132Smax.romanov@nginx.com void *data; 566*1132Smax.romanov@nginx.com napi_value constructor, res, buffer; 567*1132Smax.romanov@nginx.com uint8_t sc[2]; 568*1132Smax.romanov@nginx.com 569*1132Smax.romanov@nginx.com constructor = get_named_property(server_obj, "WebSocketFrame"); 570802Salexander.borisov@nginx.com 571*1132Smax.romanov@nginx.com res = new_instance(constructor); 572*1132Smax.romanov@nginx.com 573*1132Smax.romanov@nginx.com set_named_property(res, "fin", (bool) ws->header->fin); 574*1132Smax.romanov@nginx.com set_named_property(res, "opcode", ws->header->opcode); 575*1132Smax.romanov@nginx.com set_named_property(res, "length", (int64_t) ws->payload_len); 576802Salexander.borisov@nginx.com 577*1132Smax.romanov@nginx.com if (ws->header->opcode == NXT_WEBSOCKET_OP_CLOSE) { 578*1132Smax.romanov@nginx.com if (ws->payload_len >= 2) { 579*1132Smax.romanov@nginx.com nxt_unit_websocket_read(ws, sc, 2); 580*1132Smax.romanov@nginx.com 581*1132Smax.romanov@nginx.com set_named_property(res, "closeStatus", 582*1132Smax.romanov@nginx.com (((uint16_t) sc[0]) << 8) | sc[1]); 583802Salexander.borisov@nginx.com 584*1132Smax.romanov@nginx.com } else { 585*1132Smax.romanov@nginx.com set_named_property(res, "closeStatus", -1); 586*1132Smax.romanov@nginx.com } 587*1132Smax.romanov@nginx.com } 588802Salexander.borisov@nginx.com 589*1132Smax.romanov@nginx.com buffer = create_buffer((size_t) ws->content_length, &data); 590*1132Smax.romanov@nginx.com nxt_unit_websocket_read(ws, data, ws->content_length); 591*1132Smax.romanov@nginx.com 592*1132Smax.romanov@nginx.com set_named_property(res, "binaryPayload", buffer); 593*1132Smax.romanov@nginx.com 594*1132Smax.romanov@nginx.com return res; 595802Salexander.borisov@nginx.com } 596802Salexander.borisov@nginx.com 597802Salexander.borisov@nginx.com 598802Salexander.borisov@nginx.com napi_value 599802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info) 600802Salexander.borisov@nginx.com { 601802Salexander.borisov@nginx.com int ret; 602802Salexander.borisov@nginx.com char *ptr, *name_ptr; 603802Salexander.borisov@nginx.com bool is_array; 604802Salexander.borisov@nginx.com size_t argc, name_len, value_len; 605802Salexander.borisov@nginx.com uint32_t status_code, header_len, keys_len, array_len; 606802Salexander.borisov@nginx.com uint32_t keys_count, i, j; 607802Salexander.borisov@nginx.com uint16_t hash; 6081020Smax.romanov@nginx.com nxt_napi napi(env); 609802Salexander.borisov@nginx.com napi_value this_arg, headers, keys, name, value, array_val; 610*1132Smax.romanov@nginx.com napi_value array_entry; 611843Salexander.borisov@nginx.com napi_valuetype val_type; 612802Salexander.borisov@nginx.com nxt_unit_field_t *f; 613802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 614*1132Smax.romanov@nginx.com napi_value argv[4]; 615802Salexander.borisov@nginx.com 616*1132Smax.romanov@nginx.com argc = 4; 617802Salexander.borisov@nginx.com 6181020Smax.romanov@nginx.com try { 6191020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 620*1132Smax.romanov@nginx.com if (argc != 4) { 6211020Smax.romanov@nginx.com napi.throw_error("Wrong args count. Expected: " 6221020Smax.romanov@nginx.com "statusCode, headers, headers count, " 6231020Smax.romanov@nginx.com "headers length"); 6241020Smax.romanov@nginx.com return nullptr; 6251020Smax.romanov@nginx.com } 626802Salexander.borisov@nginx.com 627*1132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 628*1132Smax.romanov@nginx.com status_code = napi.get_value_uint32(argv[0]); 629*1132Smax.romanov@nginx.com keys_count = napi.get_value_uint32(argv[2]); 630*1132Smax.romanov@nginx.com header_len = napi.get_value_uint32(argv[3]); 631802Salexander.borisov@nginx.com 6321020Smax.romanov@nginx.com /* Need to reserve extra byte for C-string 0-termination. */ 6331020Smax.romanov@nginx.com header_len++; 634802Salexander.borisov@nginx.com 635*1132Smax.romanov@nginx.com headers = argv[1]; 636802Salexander.borisov@nginx.com 6371020Smax.romanov@nginx.com ret = nxt_unit_response_init(req, status_code, keys_count, header_len); 6381020Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 6391020Smax.romanov@nginx.com napi.throw_error("Failed to create response"); 6401020Smax.romanov@nginx.com return nullptr; 641802Salexander.borisov@nginx.com } 642802Salexander.borisov@nginx.com 6431020Smax.romanov@nginx.com keys = napi.get_property_names(headers); 6441020Smax.romanov@nginx.com keys_len = napi.get_array_length(keys); 6451020Smax.romanov@nginx.com 6461020Smax.romanov@nginx.com ptr = req->response_buf->free; 647875Salexander.borisov@nginx.com 6481020Smax.romanov@nginx.com for (i = 0; i < keys_len; i++) { 6491020Smax.romanov@nginx.com name = napi.get_element(keys, i); 6501020Smax.romanov@nginx.com 6511020Smax.romanov@nginx.com array_entry = napi.get_property(headers, name); 6521020Smax.romanov@nginx.com 6531020Smax.romanov@nginx.com name = napi.get_element(array_entry, 0); 6541020Smax.romanov@nginx.com value = napi.get_element(array_entry, 1); 655875Salexander.borisov@nginx.com 6561020Smax.romanov@nginx.com name_len = napi.get_value_string_latin1(name, ptr, header_len); 6571020Smax.romanov@nginx.com name_ptr = ptr; 6581020Smax.romanov@nginx.com 6591020Smax.romanov@nginx.com ptr += name_len; 6601020Smax.romanov@nginx.com header_len -= name_len; 661802Salexander.borisov@nginx.com 6621020Smax.romanov@nginx.com hash = nxt_unit_field_hash(name_ptr, name_len); 6631020Smax.romanov@nginx.com 6641020Smax.romanov@nginx.com is_array = napi.is_array(value); 6651020Smax.romanov@nginx.com 6661020Smax.romanov@nginx.com if (is_array) { 6671020Smax.romanov@nginx.com array_len = napi.get_array_length(value); 668802Salexander.borisov@nginx.com 6691020Smax.romanov@nginx.com for (j = 0; j < array_len; j++) { 6701020Smax.romanov@nginx.com array_val = napi.get_element(value, j); 6711020Smax.romanov@nginx.com 6721020Smax.romanov@nginx.com val_type = napi.type_of(array_val); 673802Salexander.borisov@nginx.com 6741020Smax.romanov@nginx.com if (val_type != napi_string) { 6751020Smax.romanov@nginx.com array_val = napi.coerce_to_string(array_val); 6761020Smax.romanov@nginx.com } 677802Salexander.borisov@nginx.com 6781020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(array_val, ptr, 6791020Smax.romanov@nginx.com header_len); 680802Salexander.borisov@nginx.com 6811020Smax.romanov@nginx.com f = req->response->fields + req->response->fields_count; 6821020Smax.romanov@nginx.com f->skip = 0; 6831020Smax.romanov@nginx.com 6841020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 6851020Smax.romanov@nginx.com 6861020Smax.romanov@nginx.com f->name_length = name_len; 6871020Smax.romanov@nginx.com f->hash = hash; 688802Salexander.borisov@nginx.com 6891020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 6901020Smax.romanov@nginx.com f->value_length = (uint32_t) value_len; 691802Salexander.borisov@nginx.com 6921020Smax.romanov@nginx.com ptr += value_len; 6931020Smax.romanov@nginx.com header_len -= value_len; 6941020Smax.romanov@nginx.com 6951020Smax.romanov@nginx.com req->response->fields_count++; 696802Salexander.borisov@nginx.com } 697802Salexander.borisov@nginx.com 6981020Smax.romanov@nginx.com } else { 6991020Smax.romanov@nginx.com val_type = napi.type_of(value); 700843Salexander.borisov@nginx.com 701843Salexander.borisov@nginx.com if (val_type != napi_string) { 7021020Smax.romanov@nginx.com value = napi.coerce_to_string(value); 703843Salexander.borisov@nginx.com } 704843Salexander.borisov@nginx.com 7051020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(value, ptr, header_len); 706802Salexander.borisov@nginx.com 707802Salexander.borisov@nginx.com f = req->response->fields + req->response->fields_count; 708802Salexander.borisov@nginx.com f->skip = 0; 709802Salexander.borisov@nginx.com 710802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 711802Salexander.borisov@nginx.com 712802Salexander.borisov@nginx.com f->name_length = name_len; 713802Salexander.borisov@nginx.com f->hash = hash; 714802Salexander.borisov@nginx.com 715802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 716802Salexander.borisov@nginx.com f->value_length = (uint32_t) value_len; 717802Salexander.borisov@nginx.com 718802Salexander.borisov@nginx.com ptr += value_len; 719802Salexander.borisov@nginx.com header_len -= value_len; 720802Salexander.borisov@nginx.com 721802Salexander.borisov@nginx.com req->response->fields_count++; 722802Salexander.borisov@nginx.com } 7231020Smax.romanov@nginx.com } 724843Salexander.borisov@nginx.com 7251020Smax.romanov@nginx.com } catch (exception &e) { 7261020Smax.romanov@nginx.com napi.throw_error(e); 7271020Smax.romanov@nginx.com return nullptr; 728802Salexander.borisov@nginx.com } 729802Salexander.borisov@nginx.com 730802Salexander.borisov@nginx.com req->response_buf->free = ptr; 731802Salexander.borisov@nginx.com 732802Salexander.borisov@nginx.com ret = nxt_unit_response_send(req); 733802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 7341020Smax.romanov@nginx.com napi.throw_error("Failed to send response"); 7351020Smax.romanov@nginx.com return nullptr; 736802Salexander.borisov@nginx.com } 737802Salexander.borisov@nginx.com 738802Salexander.borisov@nginx.com return this_arg; 739802Salexander.borisov@nginx.com } 740802Salexander.borisov@nginx.com 741802Salexander.borisov@nginx.com 742802Salexander.borisov@nginx.com napi_value 743802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info) 744802Salexander.borisov@nginx.com { 745802Salexander.borisov@nginx.com int ret; 746*1132Smax.romanov@nginx.com void *ptr; 747802Salexander.borisov@nginx.com size_t argc, have_buf_len; 748802Salexander.borisov@nginx.com uint32_t buf_len; 7491020Smax.romanov@nginx.com nxt_napi napi(env); 750*1132Smax.romanov@nginx.com napi_value this_arg; 751802Salexander.borisov@nginx.com nxt_unit_buf_t *buf; 752802Salexander.borisov@nginx.com napi_valuetype buf_type; 753802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 754*1132Smax.romanov@nginx.com napi_value argv[2]; 755802Salexander.borisov@nginx.com 756*1132Smax.romanov@nginx.com argc = 2; 757802Salexander.borisov@nginx.com 7581020Smax.romanov@nginx.com try { 7591020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 760*1132Smax.romanov@nginx.com if (argc != 2) { 7611020Smax.romanov@nginx.com throw exception("Wrong args count. Expected: " 7621020Smax.romanov@nginx.com "chunk, chunk length"); 7631020Smax.romanov@nginx.com } 764802Salexander.borisov@nginx.com 765*1132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 766*1132Smax.romanov@nginx.com buf_type = napi.type_of(argv[0]); 767*1132Smax.romanov@nginx.com buf_len = napi.get_value_uint32(argv[1]) + 1; 768*1132Smax.romanov@nginx.com 769*1132Smax.romanov@nginx.com buf = nxt_unit_response_buf_alloc(req, buf_len); 770*1132Smax.romanov@nginx.com if (buf == NULL) { 771*1132Smax.romanov@nginx.com throw exception("Failed to allocate response buffer"); 772*1132Smax.romanov@nginx.com } 773*1132Smax.romanov@nginx.com 774*1132Smax.romanov@nginx.com if (buf_type == napi_string) { 775*1132Smax.romanov@nginx.com /* TODO: will work only for utf8 content-type */ 776802Salexander.borisov@nginx.com 777*1132Smax.romanov@nginx.com have_buf_len = napi.get_value_string_utf8(argv[0], buf->free, 778*1132Smax.romanov@nginx.com buf_len); 779*1132Smax.romanov@nginx.com 780*1132Smax.romanov@nginx.com } else { 781*1132Smax.romanov@nginx.com ptr = napi.get_buffer_info(argv[0], have_buf_len); 782802Salexander.borisov@nginx.com 783*1132Smax.romanov@nginx.com memcpy(buf->free, ptr, have_buf_len); 784*1132Smax.romanov@nginx.com } 785*1132Smax.romanov@nginx.com 786*1132Smax.romanov@nginx.com buf->free += have_buf_len; 787802Salexander.borisov@nginx.com 788*1132Smax.romanov@nginx.com ret = nxt_unit_buf_send(buf); 789*1132Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 790*1132Smax.romanov@nginx.com throw exception("Failed to send body buf"); 791*1132Smax.romanov@nginx.com } 7921020Smax.romanov@nginx.com } catch (exception &e) { 7931020Smax.romanov@nginx.com napi.throw_error(e); 7941020Smax.romanov@nginx.com return nullptr; 795802Salexander.borisov@nginx.com } 796802Salexander.borisov@nginx.com 797802Salexander.borisov@nginx.com return this_arg; 798802Salexander.borisov@nginx.com } 799802Salexander.borisov@nginx.com 800802Salexander.borisov@nginx.com 801802Salexander.borisov@nginx.com napi_value 802802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info) 803802Salexander.borisov@nginx.com { 8041020Smax.romanov@nginx.com nxt_napi napi(env); 805*1132Smax.romanov@nginx.com napi_value this_arg; 806*1132Smax.romanov@nginx.com req_data_t *req_data; 807802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 808802Salexander.borisov@nginx.com 809*1132Smax.romanov@nginx.com try { 810*1132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info); 811*1132Smax.romanov@nginx.com 812*1132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 813802Salexander.borisov@nginx.com 814*1132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 8151020Smax.romanov@nginx.com 816*1132Smax.romanov@nginx.com napi.remove_wrap(req_data->sock_ref); 817*1132Smax.romanov@nginx.com napi.remove_wrap(req_data->resp_ref); 818*1132Smax.romanov@nginx.com napi.remove_wrap(req_data->conn_ref); 8191020Smax.romanov@nginx.com 8201020Smax.romanov@nginx.com } catch (exception &e) { 8211020Smax.romanov@nginx.com napi.throw_error(e); 822802Salexander.borisov@nginx.com return nullptr; 823802Salexander.borisov@nginx.com } 824802Salexander.borisov@nginx.com 825802Salexander.borisov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 826802Salexander.borisov@nginx.com 827802Salexander.borisov@nginx.com return this_arg; 828802Salexander.borisov@nginx.com } 829*1132Smax.romanov@nginx.com 830*1132Smax.romanov@nginx.com 831*1132Smax.romanov@nginx.com napi_value 832*1132Smax.romanov@nginx.com Unit::websocket_send_frame(napi_env env, napi_callback_info info) 833*1132Smax.romanov@nginx.com { 834*1132Smax.romanov@nginx.com int ret, iovec_len; 835*1132Smax.romanov@nginx.com bool fin; 836*1132Smax.romanov@nginx.com size_t buf_len; 837*1132Smax.romanov@nginx.com uint32_t opcode, sc; 838*1132Smax.romanov@nginx.com nxt_napi napi(env); 839*1132Smax.romanov@nginx.com napi_value this_arg, frame, payload; 840*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 841*1132Smax.romanov@nginx.com char status_code[2]; 842*1132Smax.romanov@nginx.com struct iovec iov[2]; 843*1132Smax.romanov@nginx.com 844*1132Smax.romanov@nginx.com iovec_len = 0; 845*1132Smax.romanov@nginx.com 846*1132Smax.romanov@nginx.com try { 847*1132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, frame); 848*1132Smax.romanov@nginx.com 849*1132Smax.romanov@nginx.com req = napi.get_request_info(this_arg); 850*1132Smax.romanov@nginx.com 851*1132Smax.romanov@nginx.com opcode = napi.get_value_uint32(napi.get_named_property(frame, 852*1132Smax.romanov@nginx.com "opcode")); 853*1132Smax.romanov@nginx.com if (opcode == NXT_WEBSOCKET_OP_CLOSE) { 854*1132Smax.romanov@nginx.com sc = napi.get_value_uint32(napi.get_named_property(frame, 855*1132Smax.romanov@nginx.com "closeStatus")); 856*1132Smax.romanov@nginx.com status_code[0] = (sc >> 8) & 0xFF; 857*1132Smax.romanov@nginx.com status_code[1] = sc & 0xFF; 858*1132Smax.romanov@nginx.com 859*1132Smax.romanov@nginx.com iov[iovec_len].iov_base = status_code; 860*1132Smax.romanov@nginx.com iov[iovec_len].iov_len = 2; 861*1132Smax.romanov@nginx.com iovec_len++; 862*1132Smax.romanov@nginx.com } 863*1132Smax.romanov@nginx.com 864*1132Smax.romanov@nginx.com try { 865*1132Smax.romanov@nginx.com fin = napi.get_value_bool(napi.get_named_property(frame, "fin")); 866*1132Smax.romanov@nginx.com 867*1132Smax.romanov@nginx.com } catch (exception &e) { 868*1132Smax.romanov@nginx.com fin = true; 869*1132Smax.romanov@nginx.com } 870*1132Smax.romanov@nginx.com 871*1132Smax.romanov@nginx.com payload = napi.get_named_property(frame, "binaryPayload"); 872*1132Smax.romanov@nginx.com 873*1132Smax.romanov@nginx.com if (napi.is_buffer(payload)) { 874*1132Smax.romanov@nginx.com iov[iovec_len].iov_base = napi.get_buffer_info(payload, buf_len); 875*1132Smax.romanov@nginx.com 876*1132Smax.romanov@nginx.com } else { 877*1132Smax.romanov@nginx.com buf_len = 0; 878*1132Smax.romanov@nginx.com } 879*1132Smax.romanov@nginx.com 880*1132Smax.romanov@nginx.com } catch (exception &e) { 881*1132Smax.romanov@nginx.com napi.throw_error(e); 882*1132Smax.romanov@nginx.com return nullptr; 883*1132Smax.romanov@nginx.com } 884*1132Smax.romanov@nginx.com 885*1132Smax.romanov@nginx.com if (buf_len > 0) { 886*1132Smax.romanov@nginx.com iov[iovec_len].iov_len = buf_len; 887*1132Smax.romanov@nginx.com iovec_len++; 888*1132Smax.romanov@nginx.com } 889*1132Smax.romanov@nginx.com 890*1132Smax.romanov@nginx.com ret = nxt_unit_websocket_sendv(req, opcode, fin ? 1 : 0, iov, iovec_len); 891*1132Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 892*1132Smax.romanov@nginx.com goto failed; 893*1132Smax.romanov@nginx.com } 894*1132Smax.romanov@nginx.com 895*1132Smax.romanov@nginx.com return this_arg; 896*1132Smax.romanov@nginx.com 897*1132Smax.romanov@nginx.com failed: 898*1132Smax.romanov@nginx.com 899*1132Smax.romanov@nginx.com napi.throw_error("Failed to send frame"); 900*1132Smax.romanov@nginx.com 901*1132Smax.romanov@nginx.com return nullptr; 902*1132Smax.romanov@nginx.com } 903*1132Smax.romanov@nginx.com 904*1132Smax.romanov@nginx.com 905*1132Smax.romanov@nginx.com napi_value 906*1132Smax.romanov@nginx.com Unit::websocket_set_sock(napi_env env, napi_callback_info info) 907*1132Smax.romanov@nginx.com { 908*1132Smax.romanov@nginx.com nxt_napi napi(env); 909*1132Smax.romanov@nginx.com napi_value this_arg, sock; 910*1132Smax.romanov@nginx.com req_data_t *req_data; 911*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 912*1132Smax.romanov@nginx.com 913*1132Smax.romanov@nginx.com try { 914*1132Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, sock); 915*1132Smax.romanov@nginx.com 916*1132Smax.romanov@nginx.com req = napi.get_request_info(sock); 917*1132Smax.romanov@nginx.com 918*1132Smax.romanov@nginx.com req_data = (req_data_t *) req->data; 919*1132Smax.romanov@nginx.com req_data->conn_ref = napi.wrap(this_arg, req, conn_destroy); 920*1132Smax.romanov@nginx.com 921*1132Smax.romanov@nginx.com } catch (exception &e) { 922*1132Smax.romanov@nginx.com napi.throw_error(e); 923*1132Smax.romanov@nginx.com return nullptr; 924*1132Smax.romanov@nginx.com } 925*1132Smax.romanov@nginx.com 926*1132Smax.romanov@nginx.com return this_arg; 927*1132Smax.romanov@nginx.com } 928*1132Smax.romanov@nginx.com 929*1132Smax.romanov@nginx.com 930*1132Smax.romanov@nginx.com void 931*1132Smax.romanov@nginx.com Unit::conn_destroy(napi_env env, void *nativeObject, void *finalize_hint) 932*1132Smax.romanov@nginx.com { 933*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 934*1132Smax.romanov@nginx.com 935*1132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 936*1132Smax.romanov@nginx.com 937*1132Smax.romanov@nginx.com nxt_unit_warn(NULL, "conn_destroy: %p", req); 938*1132Smax.romanov@nginx.com } 939*1132Smax.romanov@nginx.com 940*1132Smax.romanov@nginx.com 941*1132Smax.romanov@nginx.com void 942*1132Smax.romanov@nginx.com Unit::sock_destroy(napi_env env, void *nativeObject, void *finalize_hint) 943*1132Smax.romanov@nginx.com { 944*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 945*1132Smax.romanov@nginx.com 946*1132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 947*1132Smax.romanov@nginx.com 948*1132Smax.romanov@nginx.com nxt_unit_warn(NULL, "sock_destroy: %p", req); 949*1132Smax.romanov@nginx.com } 950*1132Smax.romanov@nginx.com 951*1132Smax.romanov@nginx.com 952*1132Smax.romanov@nginx.com void 953*1132Smax.romanov@nginx.com Unit::resp_destroy(napi_env env, void *nativeObject, void *finalize_hint) 954*1132Smax.romanov@nginx.com { 955*1132Smax.romanov@nginx.com nxt_unit_request_info_t *req; 956*1132Smax.romanov@nginx.com 957*1132Smax.romanov@nginx.com req = (nxt_unit_request_info_t *) nativeObject; 958*1132Smax.romanov@nginx.com 959*1132Smax.romanov@nginx.com nxt_unit_warn(NULL, "resp_destroy: %p", req); 960*1132Smax.romanov@nginx.com } 961