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 13802Salexander.borisov@nginx.com 14802Salexander.borisov@nginx.com napi_ref Unit::constructor_; 15802Salexander.borisov@nginx.com 16802Salexander.borisov@nginx.com 17842Salexander.borisov@nginx.com struct nxt_nodejs_ctx_t { 18842Salexander.borisov@nginx.com nxt_unit_port_id_t port_id; 19842Salexander.borisov@nginx.com uv_poll_t poll; 20842Salexander.borisov@nginx.com }; 21842Salexander.borisov@nginx.com 22842Salexander.borisov@nginx.com 231020Smax.romanov@nginx.com Unit::Unit(napi_env env, napi_value jsthis): 241020Smax.romanov@nginx.com nxt_napi(env), 251020Smax.romanov@nginx.com wrapper_(wrap(jsthis, this, destroy)), 26802Salexander.borisov@nginx.com unit_ctx_(nullptr) 27802Salexander.borisov@nginx.com { 28802Salexander.borisov@nginx.com } 29802Salexander.borisov@nginx.com 30802Salexander.borisov@nginx.com 31802Salexander.borisov@nginx.com Unit::~Unit() 32802Salexander.borisov@nginx.com { 331020Smax.romanov@nginx.com delete_reference(wrapper_); 34802Salexander.borisov@nginx.com } 35802Salexander.borisov@nginx.com 36802Salexander.borisov@nginx.com 37802Salexander.borisov@nginx.com napi_value 38802Salexander.borisov@nginx.com Unit::init(napi_env env, napi_value exports) 39802Salexander.borisov@nginx.com { 401020Smax.romanov@nginx.com nxt_napi napi(env); 411020Smax.romanov@nginx.com napi_value cons; 42802Salexander.borisov@nginx.com 43802Salexander.borisov@nginx.com napi_property_descriptor properties[] = { 44802Salexander.borisov@nginx.com { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, 45828Salexander.borisov@nginx.com { "listen", 0, listen, 0, 0, 0, napi_default, 0 }, 46828Salexander.borisov@nginx.com { "_read", 0, _read, 0, 0, 0, napi_default, 0 } 47802Salexander.borisov@nginx.com }; 48802Salexander.borisov@nginx.com 491020Smax.romanov@nginx.com try { 501020Smax.romanov@nginx.com cons = napi.define_class("Unit", create, 3, properties); 511020Smax.romanov@nginx.com constructor_ = napi.create_reference(cons); 52802Salexander.borisov@nginx.com 531020Smax.romanov@nginx.com napi.set_named_property(exports, "Unit", cons); 541020Smax.romanov@nginx.com napi.set_named_property(exports, "unit_response_headers", 551020Smax.romanov@nginx.com response_send_headers); 561020Smax.romanov@nginx.com napi.set_named_property(exports, "unit_response_write", response_write); 571020Smax.romanov@nginx.com napi.set_named_property(exports, "unit_response_end", response_end); 58802Salexander.borisov@nginx.com 591020Smax.romanov@nginx.com } catch (exception &e) { 601020Smax.romanov@nginx.com napi.throw_error(e); 611020Smax.romanov@nginx.com return nullptr; 62802Salexander.borisov@nginx.com } 63802Salexander.borisov@nginx.com 64802Salexander.borisov@nginx.com return exports; 65802Salexander.borisov@nginx.com } 66802Salexander.borisov@nginx.com 67802Salexander.borisov@nginx.com 68802Salexander.borisov@nginx.com void 69802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) 70802Salexander.borisov@nginx.com { 71802Salexander.borisov@nginx.com Unit *obj = reinterpret_cast<Unit *>(nativeObject); 72802Salexander.borisov@nginx.com 73802Salexander.borisov@nginx.com delete obj; 74802Salexander.borisov@nginx.com } 75802Salexander.borisov@nginx.com 76802Salexander.borisov@nginx.com 77802Salexander.borisov@nginx.com napi_value 78802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info) 79802Salexander.borisov@nginx.com { 801020Smax.romanov@nginx.com nxt_napi napi(env); 811020Smax.romanov@nginx.com napi_value target, cons, instance, jsthis; 821020Smax.romanov@nginx.com 831020Smax.romanov@nginx.com try { 841020Smax.romanov@nginx.com target = napi.get_new_target(info); 85802Salexander.borisov@nginx.com 861020Smax.romanov@nginx.com if (target != nullptr) { 871020Smax.romanov@nginx.com /* Invoked as constructor: `new Unit(...)`. */ 881020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info); 89802Salexander.borisov@nginx.com 901023Smax.romanov@nginx.com new Unit(env, jsthis); 911023Smax.romanov@nginx.com napi.create_reference(jsthis); 921020Smax.romanov@nginx.com 931020Smax.romanov@nginx.com return jsthis; 94802Salexander.borisov@nginx.com } 95802Salexander.borisov@nginx.com 961020Smax.romanov@nginx.com /* Invoked as plain function `Unit(...)`, turn into construct call. */ 971020Smax.romanov@nginx.com cons = napi.get_reference_value(constructor_); 981020Smax.romanov@nginx.com instance = napi.new_instance(cons); 991023Smax.romanov@nginx.com napi.create_reference(instance); 100841Salexander.borisov@nginx.com 1011020Smax.romanov@nginx.com } catch (exception &e) { 1021020Smax.romanov@nginx.com napi.throw_error(e); 1031020Smax.romanov@nginx.com return nullptr; 104841Salexander.borisov@nginx.com } 105841Salexander.borisov@nginx.com 106802Salexander.borisov@nginx.com return instance; 107802Salexander.borisov@nginx.com } 108802Salexander.borisov@nginx.com 109802Salexander.borisov@nginx.com 110802Salexander.borisov@nginx.com napi_value 111802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info) 112802Salexander.borisov@nginx.com { 113802Salexander.borisov@nginx.com Unit *obj; 114802Salexander.borisov@nginx.com size_t argc; 1151020Smax.romanov@nginx.com nxt_napi napi(env); 116828Salexander.borisov@nginx.com napi_value jsthis, argv; 117802Salexander.borisov@nginx.com nxt_unit_init_t unit_init; 118802Salexander.borisov@nginx.com 119802Salexander.borisov@nginx.com argc = 1; 120802Salexander.borisov@nginx.com 1211020Smax.romanov@nginx.com try { 1221020Smax.romanov@nginx.com jsthis = napi.get_cb_info(info, argc, &argv); 1231020Smax.romanov@nginx.com obj = (Unit *) napi.unwrap(jsthis); 124802Salexander.borisov@nginx.com 1251020Smax.romanov@nginx.com } catch (exception &e) { 1261020Smax.romanov@nginx.com napi.throw_error(e); 1271020Smax.romanov@nginx.com return nullptr; 128802Salexander.borisov@nginx.com } 129802Salexander.borisov@nginx.com 130802Salexander.borisov@nginx.com memset(&unit_init, 0, sizeof(nxt_unit_init_t)); 131802Salexander.borisov@nginx.com 132802Salexander.borisov@nginx.com unit_init.data = obj; 133802Salexander.borisov@nginx.com unit_init.callbacks.request_handler = request_handler; 134828Salexander.borisov@nginx.com unit_init.callbacks.add_port = add_port; 135828Salexander.borisov@nginx.com unit_init.callbacks.remove_port = remove_port; 136842Salexander.borisov@nginx.com unit_init.callbacks.quit = quit; 137802Salexander.borisov@nginx.com 138802Salexander.borisov@nginx.com obj->unit_ctx_ = nxt_unit_init(&unit_init); 139802Salexander.borisov@nginx.com if (obj->unit_ctx_ == NULL) { 140802Salexander.borisov@nginx.com goto failed; 141802Salexander.borisov@nginx.com } 142802Salexander.borisov@nginx.com 143802Salexander.borisov@nginx.com return nullptr; 144802Salexander.borisov@nginx.com 145802Salexander.borisov@nginx.com failed: 146802Salexander.borisov@nginx.com 147802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create Unit object"); 148802Salexander.borisov@nginx.com 149802Salexander.borisov@nginx.com return nullptr; 150802Salexander.borisov@nginx.com } 151802Salexander.borisov@nginx.com 152802Salexander.borisov@nginx.com 153802Salexander.borisov@nginx.com napi_value 154802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info) 155802Salexander.borisov@nginx.com { 156828Salexander.borisov@nginx.com return nullptr; 157828Salexander.borisov@nginx.com } 158828Salexander.borisov@nginx.com 159802Salexander.borisov@nginx.com 160828Salexander.borisov@nginx.com napi_value 161828Salexander.borisov@nginx.com Unit::_read(napi_env env, napi_callback_info info) 162828Salexander.borisov@nginx.com { 163828Salexander.borisov@nginx.com void *data; 164828Salexander.borisov@nginx.com size_t argc; 1651020Smax.romanov@nginx.com nxt_napi napi(env); 1661023Smax.romanov@nginx.com napi_value buffer, argv; 167828Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 168828Salexander.borisov@nginx.com 169828Salexander.borisov@nginx.com argc = 1; 170828Salexander.borisov@nginx.com 1711020Smax.romanov@nginx.com try { 1721023Smax.romanov@nginx.com napi.get_cb_info(info, argc, &argv); 173802Salexander.borisov@nginx.com 1741020Smax.romanov@nginx.com req = napi.get_request_info(argv); 1751020Smax.romanov@nginx.com buffer = napi.create_buffer((size_t) req->content_length, &data); 176802Salexander.borisov@nginx.com 1771020Smax.romanov@nginx.com } catch (exception &e) { 1781020Smax.romanov@nginx.com napi.throw_error(e); 179802Salexander.borisov@nginx.com return nullptr; 180802Salexander.borisov@nginx.com } 181802Salexander.borisov@nginx.com 182828Salexander.borisov@nginx.com nxt_unit_request_read(req, data, req->content_length); 183802Salexander.borisov@nginx.com 184828Salexander.borisov@nginx.com return buffer; 185802Salexander.borisov@nginx.com } 186802Salexander.borisov@nginx.com 187802Salexander.borisov@nginx.com 188802Salexander.borisov@nginx.com void 189802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req) 190802Salexander.borisov@nginx.com { 1911020Smax.romanov@nginx.com Unit *obj; 1921020Smax.romanov@nginx.com napi_value socket, request, response, server_obj; 1931020Smax.romanov@nginx.com napi_value emit_events; 1941020Smax.romanov@nginx.com napi_value events_args[3]; 195802Salexander.borisov@nginx.com 196802Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 197802Salexander.borisov@nginx.com 1981020Smax.romanov@nginx.com try { 1991020Smax.romanov@nginx.com nxt_handle_scope scope(obj->env()); 200802Salexander.borisov@nginx.com 2011020Smax.romanov@nginx.com server_obj = obj->get_server_object(); 202802Salexander.borisov@nginx.com 2031020Smax.romanov@nginx.com socket = obj->create_socket(server_obj, req); 2041020Smax.romanov@nginx.com request = obj->create_request(server_obj, socket); 2051020Smax.romanov@nginx.com response = obj->create_response(server_obj, socket, request, req); 206802Salexander.borisov@nginx.com 2071020Smax.romanov@nginx.com obj->create_headers(req, request); 208802Salexander.borisov@nginx.com 2091020Smax.romanov@nginx.com emit_events = obj->get_named_property(server_obj, "emit_events"); 210828Salexander.borisov@nginx.com 2111020Smax.romanov@nginx.com events_args[0] = server_obj; 2121020Smax.romanov@nginx.com events_args[1] = request; 2131020Smax.romanov@nginx.com events_args[2] = response; 214871Salexander.borisov@nginx.com 2151020Smax.romanov@nginx.com nxt_async_context async_context(obj->env(), "unit_request_handler"); 2161020Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 217876Salexander.borisov@nginx.com 2181020Smax.romanov@nginx.com obj->make_callback(async_context, server_obj, emit_events, 2191020Smax.romanov@nginx.com 3, events_args); 220871Salexander.borisov@nginx.com 2211020Smax.romanov@nginx.com } catch (exception &e) { 2221020Smax.romanov@nginx.com obj->throw_error(e); 223871Salexander.borisov@nginx.com } 224802Salexander.borisov@nginx.com } 225802Salexander.borisov@nginx.com 226802Salexander.borisov@nginx.com 227828Salexander.borisov@nginx.com void 228828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events) 229828Salexander.borisov@nginx.com { 230828Salexander.borisov@nginx.com nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); 231828Salexander.borisov@nginx.com } 232828Salexander.borisov@nginx.com 233828Salexander.borisov@nginx.com 234828Salexander.borisov@nginx.com int 235828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 236828Salexander.borisov@nginx.com { 237842Salexander.borisov@nginx.com int err; 238842Salexander.borisov@nginx.com Unit *obj; 239842Salexander.borisov@nginx.com uv_loop_t *loop; 240842Salexander.borisov@nginx.com napi_status status; 241842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 242828Salexander.borisov@nginx.com 243828Salexander.borisov@nginx.com if (port->in_fd != -1) { 244828Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 245828Salexander.borisov@nginx.com 246828Salexander.borisov@nginx.com if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { 2471020Smax.romanov@nginx.com obj->throw_error("Failed to upgrade read" 248828Salexander.borisov@nginx.com " file descriptor to O_NONBLOCK"); 249828Salexander.borisov@nginx.com return -1; 250828Salexander.borisov@nginx.com } 251828Salexander.borisov@nginx.com 2521020Smax.romanov@nginx.com status = napi_get_uv_event_loop(obj->env(), &loop); 253828Salexander.borisov@nginx.com if (status != napi_ok) { 2541020Smax.romanov@nginx.com obj->throw_error("Failed to get uv.loop"); 255828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 256828Salexander.borisov@nginx.com } 257828Salexander.borisov@nginx.com 258842Salexander.borisov@nginx.com node_ctx = new nxt_nodejs_ctx_t; 259828Salexander.borisov@nginx.com 260842Salexander.borisov@nginx.com err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); 261828Salexander.borisov@nginx.com if (err < 0) { 2621020Smax.romanov@nginx.com obj->throw_error("Failed to init uv.poll"); 263828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 264828Salexander.borisov@nginx.com } 265828Salexander.borisov@nginx.com 266842Salexander.borisov@nginx.com err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); 267828Salexander.borisov@nginx.com if (err < 0) { 2681020Smax.romanov@nginx.com obj->throw_error("Failed to start uv.poll"); 269828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 270828Salexander.borisov@nginx.com } 271828Salexander.borisov@nginx.com 272842Salexander.borisov@nginx.com ctx->data = node_ctx; 273842Salexander.borisov@nginx.com 274842Salexander.borisov@nginx.com node_ctx->port_id = port->id; 275842Salexander.borisov@nginx.com node_ctx->poll.data = ctx; 276828Salexander.borisov@nginx.com } 277828Salexander.borisov@nginx.com 278828Salexander.borisov@nginx.com return nxt_unit_add_port(ctx, port); 279828Salexander.borisov@nginx.com } 280828Salexander.borisov@nginx.com 281828Salexander.borisov@nginx.com 2821008Szelenkov@nginx.com inline bool 283842Salexander.borisov@nginx.com operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) 284842Salexander.borisov@nginx.com { 285842Salexander.borisov@nginx.com return p1.pid == p2.pid && p1.id == p2.id; 286842Salexander.borisov@nginx.com } 287842Salexander.borisov@nginx.com 288842Salexander.borisov@nginx.com 289828Salexander.borisov@nginx.com void 290828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) 291828Salexander.borisov@nginx.com { 292842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 293842Salexander.borisov@nginx.com 294842Salexander.borisov@nginx.com if (ctx->data != NULL) { 295842Salexander.borisov@nginx.com node_ctx = (nxt_nodejs_ctx_t *) ctx->data; 296828Salexander.borisov@nginx.com 297842Salexander.borisov@nginx.com if (node_ctx->port_id == *port_id) { 298842Salexander.borisov@nginx.com uv_poll_stop(&node_ctx->poll); 299828Salexander.borisov@nginx.com 300842Salexander.borisov@nginx.com delete node_ctx; 301828Salexander.borisov@nginx.com 302842Salexander.borisov@nginx.com ctx->data = NULL; 303842Salexander.borisov@nginx.com } 304828Salexander.borisov@nginx.com } 305828Salexander.borisov@nginx.com 306828Salexander.borisov@nginx.com nxt_unit_remove_port(ctx, port_id); 307828Salexander.borisov@nginx.com } 308828Salexander.borisov@nginx.com 309828Salexander.borisov@nginx.com 310842Salexander.borisov@nginx.com void 311842Salexander.borisov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx) 312842Salexander.borisov@nginx.com { 3131021Smax.romanov@nginx.com Unit *obj; 3141021Smax.romanov@nginx.com napi_value server_obj, emit_close; 3151021Smax.romanov@nginx.com 3161021Smax.romanov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 3171021Smax.romanov@nginx.com 3181021Smax.romanov@nginx.com try { 3191021Smax.romanov@nginx.com nxt_handle_scope scope(obj->env()); 3201021Smax.romanov@nginx.com 3211021Smax.romanov@nginx.com server_obj = obj->get_server_object(); 3221021Smax.romanov@nginx.com 3231021Smax.romanov@nginx.com emit_close = obj->get_named_property(server_obj, "emit_close"); 3241021Smax.romanov@nginx.com 3251021Smax.romanov@nginx.com nxt_async_context async_context(obj->env(), "unit_quit"); 3261021Smax.romanov@nginx.com nxt_callback_scope async_scope(async_context); 3271021Smax.romanov@nginx.com 3281021Smax.romanov@nginx.com obj->make_callback(async_context, server_obj, emit_close, 0, NULL); 3291021Smax.romanov@nginx.com 3301021Smax.romanov@nginx.com } catch (exception &e) { 3311021Smax.romanov@nginx.com obj->throw_error(e); 3321021Smax.romanov@nginx.com } 3331021Smax.romanov@nginx.com 334842Salexander.borisov@nginx.com nxt_unit_done(ctx); 335842Salexander.borisov@nginx.com } 336842Salexander.borisov@nginx.com 337842Salexander.borisov@nginx.com 338802Salexander.borisov@nginx.com napi_value 339802Salexander.borisov@nginx.com Unit::get_server_object() 340802Salexander.borisov@nginx.com { 3411020Smax.romanov@nginx.com napi_value unit_obj; 342802Salexander.borisov@nginx.com 3431020Smax.romanov@nginx.com unit_obj = get_reference_value(wrapper_); 344802Salexander.borisov@nginx.com 3451020Smax.romanov@nginx.com return get_named_property(unit_obj, "server"); 346802Salexander.borisov@nginx.com } 347802Salexander.borisov@nginx.com 348802Salexander.borisov@nginx.com 3491020Smax.romanov@nginx.com void 350802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) 351802Salexander.borisov@nginx.com { 352802Salexander.borisov@nginx.com uint32_t i; 3531020Smax.romanov@nginx.com napi_value headers, raw_headers; 354802Salexander.borisov@nginx.com napi_status status; 355802Salexander.borisov@nginx.com nxt_unit_request_t *r; 356802Salexander.borisov@nginx.com 357802Salexander.borisov@nginx.com r = req->request; 358802Salexander.borisov@nginx.com 3591020Smax.romanov@nginx.com headers = create_object(); 360802Salexander.borisov@nginx.com 3611020Smax.romanov@nginx.com status = napi_create_array_with_length(env(), r->fields_count * 2, 362802Salexander.borisov@nginx.com &raw_headers); 363802Salexander.borisov@nginx.com if (status != napi_ok) { 3641020Smax.romanov@nginx.com throw exception("Failed to create array"); 365802Salexander.borisov@nginx.com } 366802Salexander.borisov@nginx.com 367802Salexander.borisov@nginx.com for (i = 0; i < r->fields_count; i++) { 3681020Smax.romanov@nginx.com append_header(r->fields + i, headers, raw_headers, i); 369802Salexander.borisov@nginx.com } 370802Salexander.borisov@nginx.com 3711020Smax.romanov@nginx.com set_named_property(request, "headers", headers); 3721020Smax.romanov@nginx.com set_named_property(request, "rawHeaders", raw_headers); 3731020Smax.romanov@nginx.com set_named_property(request, "httpVersion", r->version, r->version_length); 3741020Smax.romanov@nginx.com set_named_property(request, "method", r->method, r->method_length); 3751020Smax.romanov@nginx.com set_named_property(request, "url", r->target, r->target_length); 376802Salexander.borisov@nginx.com } 377802Salexander.borisov@nginx.com 378802Salexander.borisov@nginx.com 379*1038Smax.romanov@nginx.com inline char 380*1038Smax.romanov@nginx.com lowcase(char c) 381*1038Smax.romanov@nginx.com { 382*1038Smax.romanov@nginx.com return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; 383*1038Smax.romanov@nginx.com } 384*1038Smax.romanov@nginx.com 385*1038Smax.romanov@nginx.com 3861020Smax.romanov@nginx.com inline void 387802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers, 3881020Smax.romanov@nginx.com napi_value raw_headers, uint32_t idx) 389802Salexander.borisov@nginx.com { 390*1038Smax.romanov@nginx.com char *name; 391*1038Smax.romanov@nginx.com uint8_t i; 392*1038Smax.romanov@nginx.com napi_value str, vstr; 393*1038Smax.romanov@nginx.com 394*1038Smax.romanov@nginx.com name = (char *) nxt_unit_sptr_get(&f->name); 395802Salexander.borisov@nginx.com 396*1038Smax.romanov@nginx.com str = create_string_latin1(name, f->name_length); 397*1038Smax.romanov@nginx.com 398*1038Smax.romanov@nginx.com for (i = 0; i < f->name_length; i++) { 399*1038Smax.romanov@nginx.com name[i] = lowcase(name[i]); 400*1038Smax.romanov@nginx.com } 401802Salexander.borisov@nginx.com 4021020Smax.romanov@nginx.com vstr = set_named_property(headers, name, f->value, f->value_length); 403802Salexander.borisov@nginx.com 4041020Smax.romanov@nginx.com set_element(raw_headers, idx * 2, str); 4051020Smax.romanov@nginx.com set_element(raw_headers, idx * 2 + 1, vstr); 406802Salexander.borisov@nginx.com } 407802Salexander.borisov@nginx.com 408802Salexander.borisov@nginx.com 409802Salexander.borisov@nginx.com napi_value 410802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) 411802Salexander.borisov@nginx.com { 4121022Smax.romanov@nginx.com napi_value constructor, res; 4131022Smax.romanov@nginx.com nxt_unit_request_t *r; 4141022Smax.romanov@nginx.com 4151022Smax.romanov@nginx.com r = req->request; 416802Salexander.borisov@nginx.com 4171020Smax.romanov@nginx.com constructor = get_named_property(server_obj, "socket"); 418802Salexander.borisov@nginx.com 4191022Smax.romanov@nginx.com res = new_instance(constructor); 420802Salexander.borisov@nginx.com 4211022Smax.romanov@nginx.com set_named_property(res, "req_pointer", (intptr_t) req); 4221022Smax.romanov@nginx.com set_named_property(res, "remoteAddress", r->remote, r->remote_length); 4231022Smax.romanov@nginx.com set_named_property(res, "localAddress", r->local, r->local_length); 424828Salexander.borisov@nginx.com 4251022Smax.romanov@nginx.com return res; 426802Salexander.borisov@nginx.com } 427802Salexander.borisov@nginx.com 428802Salexander.borisov@nginx.com 429802Salexander.borisov@nginx.com napi_value 430802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket) 431802Salexander.borisov@nginx.com { 4321020Smax.romanov@nginx.com napi_value constructor, return_val; 433802Salexander.borisov@nginx.com 4341020Smax.romanov@nginx.com constructor = get_named_property(server_obj, "request"); 435802Salexander.borisov@nginx.com 4361020Smax.romanov@nginx.com return_val = new_instance(constructor, server_obj); 437802Salexander.borisov@nginx.com 4381020Smax.romanov@nginx.com set_named_property(return_val, "socket", socket); 4391022Smax.romanov@nginx.com set_named_property(return_val, "connection", socket); 440802Salexander.borisov@nginx.com 441802Salexander.borisov@nginx.com return return_val; 442802Salexander.borisov@nginx.com } 443802Salexander.borisov@nginx.com 444802Salexander.borisov@nginx.com 445802Salexander.borisov@nginx.com napi_value 446802Salexander.borisov@nginx.com Unit::create_response(napi_value server_obj, napi_value socket, 4471020Smax.romanov@nginx.com napi_value request, nxt_unit_request_info_t *req) 448802Salexander.borisov@nginx.com { 4491020Smax.romanov@nginx.com napi_value constructor, return_val; 450802Salexander.borisov@nginx.com 4511020Smax.romanov@nginx.com constructor = get_named_property(server_obj, "response"); 452802Salexander.borisov@nginx.com 4531020Smax.romanov@nginx.com return_val = new_instance(constructor, request); 454802Salexander.borisov@nginx.com 4551020Smax.romanov@nginx.com set_named_property(return_val, "socket", socket); 4561022Smax.romanov@nginx.com set_named_property(return_val, "connection", socket); 4571020Smax.romanov@nginx.com set_named_property(return_val, "_req_point", (intptr_t) req); 458802Salexander.borisov@nginx.com 459802Salexander.borisov@nginx.com return return_val; 460802Salexander.borisov@nginx.com } 461802Salexander.borisov@nginx.com 462802Salexander.borisov@nginx.com 463802Salexander.borisov@nginx.com napi_value 464802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info) 465802Salexander.borisov@nginx.com { 466802Salexander.borisov@nginx.com int ret; 467802Salexander.borisov@nginx.com char *ptr, *name_ptr; 468802Salexander.borisov@nginx.com bool is_array; 469802Salexander.borisov@nginx.com size_t argc, name_len, value_len; 470802Salexander.borisov@nginx.com uint32_t status_code, header_len, keys_len, array_len; 471802Salexander.borisov@nginx.com uint32_t keys_count, i, j; 472802Salexander.borisov@nginx.com uint16_t hash; 4731020Smax.romanov@nginx.com nxt_napi napi(env); 474802Salexander.borisov@nginx.com napi_value this_arg, headers, keys, name, value, array_val; 475875Salexander.borisov@nginx.com napi_value req_num, array_entry; 476843Salexander.borisov@nginx.com napi_valuetype val_type; 477802Salexander.borisov@nginx.com nxt_unit_field_t *f; 478802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 479802Salexander.borisov@nginx.com napi_value argv[5]; 480802Salexander.borisov@nginx.com 481802Salexander.borisov@nginx.com argc = 5; 482802Salexander.borisov@nginx.com 4831020Smax.romanov@nginx.com try { 4841020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 4851020Smax.romanov@nginx.com if (argc != 5) { 4861020Smax.romanov@nginx.com napi.throw_error("Wrong args count. Expected: " 4871020Smax.romanov@nginx.com "statusCode, headers, headers count, " 4881020Smax.romanov@nginx.com "headers length"); 4891020Smax.romanov@nginx.com return nullptr; 4901020Smax.romanov@nginx.com } 491802Salexander.borisov@nginx.com 4921020Smax.romanov@nginx.com req_num = napi.get_named_property(argv[0], "_req_point"); 493802Salexander.borisov@nginx.com 4941020Smax.romanov@nginx.com req = napi.get_request_info(req_num); 495802Salexander.borisov@nginx.com 4961020Smax.romanov@nginx.com status_code = napi.get_value_uint32(argv[1]); 4971020Smax.romanov@nginx.com keys_count = napi.get_value_uint32(argv[3]); 4981020Smax.romanov@nginx.com header_len = napi.get_value_uint32(argv[4]); 499802Salexander.borisov@nginx.com 5001020Smax.romanov@nginx.com /* Need to reserve extra byte for C-string 0-termination. */ 5011020Smax.romanov@nginx.com header_len++; 502802Salexander.borisov@nginx.com 5031020Smax.romanov@nginx.com headers = argv[2]; 504802Salexander.borisov@nginx.com 5051020Smax.romanov@nginx.com ret = nxt_unit_response_init(req, status_code, keys_count, header_len); 5061020Smax.romanov@nginx.com if (ret != NXT_UNIT_OK) { 5071020Smax.romanov@nginx.com napi.throw_error("Failed to create response"); 5081020Smax.romanov@nginx.com return nullptr; 509802Salexander.borisov@nginx.com } 510802Salexander.borisov@nginx.com 5111020Smax.romanov@nginx.com keys = napi.get_property_names(headers); 5121020Smax.romanov@nginx.com keys_len = napi.get_array_length(keys); 5131020Smax.romanov@nginx.com 5141020Smax.romanov@nginx.com ptr = req->response_buf->free; 515875Salexander.borisov@nginx.com 5161020Smax.romanov@nginx.com for (i = 0; i < keys_len; i++) { 5171020Smax.romanov@nginx.com name = napi.get_element(keys, i); 5181020Smax.romanov@nginx.com 5191020Smax.romanov@nginx.com array_entry = napi.get_property(headers, name); 5201020Smax.romanov@nginx.com 5211020Smax.romanov@nginx.com name = napi.get_element(array_entry, 0); 5221020Smax.romanov@nginx.com value = napi.get_element(array_entry, 1); 523875Salexander.borisov@nginx.com 5241020Smax.romanov@nginx.com name_len = napi.get_value_string_latin1(name, ptr, header_len); 5251020Smax.romanov@nginx.com name_ptr = ptr; 5261020Smax.romanov@nginx.com 5271020Smax.romanov@nginx.com ptr += name_len; 5281020Smax.romanov@nginx.com header_len -= name_len; 529802Salexander.borisov@nginx.com 5301020Smax.romanov@nginx.com hash = nxt_unit_field_hash(name_ptr, name_len); 5311020Smax.romanov@nginx.com 5321020Smax.romanov@nginx.com is_array = napi.is_array(value); 5331020Smax.romanov@nginx.com 5341020Smax.romanov@nginx.com if (is_array) { 5351020Smax.romanov@nginx.com array_len = napi.get_array_length(value); 536802Salexander.borisov@nginx.com 5371020Smax.romanov@nginx.com for (j = 0; j < array_len; j++) { 5381020Smax.romanov@nginx.com array_val = napi.get_element(value, j); 5391020Smax.romanov@nginx.com 5401020Smax.romanov@nginx.com val_type = napi.type_of(array_val); 541802Salexander.borisov@nginx.com 5421020Smax.romanov@nginx.com if (val_type != napi_string) { 5431020Smax.romanov@nginx.com array_val = napi.coerce_to_string(array_val); 5441020Smax.romanov@nginx.com } 545802Salexander.borisov@nginx.com 5461020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(array_val, ptr, 5471020Smax.romanov@nginx.com header_len); 548802Salexander.borisov@nginx.com 5491020Smax.romanov@nginx.com f = req->response->fields + req->response->fields_count; 5501020Smax.romanov@nginx.com f->skip = 0; 5511020Smax.romanov@nginx.com 5521020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 5531020Smax.romanov@nginx.com 5541020Smax.romanov@nginx.com f->name_length = name_len; 5551020Smax.romanov@nginx.com f->hash = hash; 556802Salexander.borisov@nginx.com 5571020Smax.romanov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 5581020Smax.romanov@nginx.com f->value_length = (uint32_t) value_len; 559802Salexander.borisov@nginx.com 5601020Smax.romanov@nginx.com ptr += value_len; 5611020Smax.romanov@nginx.com header_len -= value_len; 5621020Smax.romanov@nginx.com 5631020Smax.romanov@nginx.com req->response->fields_count++; 564802Salexander.borisov@nginx.com } 565802Salexander.borisov@nginx.com 5661020Smax.romanov@nginx.com } else { 5671020Smax.romanov@nginx.com val_type = napi.type_of(value); 568843Salexander.borisov@nginx.com 569843Salexander.borisov@nginx.com if (val_type != napi_string) { 5701020Smax.romanov@nginx.com value = napi.coerce_to_string(value); 571843Salexander.borisov@nginx.com } 572843Salexander.borisov@nginx.com 5731020Smax.romanov@nginx.com value_len = napi.get_value_string_latin1(value, ptr, header_len); 574802Salexander.borisov@nginx.com 575802Salexander.borisov@nginx.com f = req->response->fields + req->response->fields_count; 576802Salexander.borisov@nginx.com f->skip = 0; 577802Salexander.borisov@nginx.com 578802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 579802Salexander.borisov@nginx.com 580802Salexander.borisov@nginx.com f->name_length = name_len; 581802Salexander.borisov@nginx.com f->hash = hash; 582802Salexander.borisov@nginx.com 583802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 584802Salexander.borisov@nginx.com f->value_length = (uint32_t) value_len; 585802Salexander.borisov@nginx.com 586802Salexander.borisov@nginx.com ptr += value_len; 587802Salexander.borisov@nginx.com header_len -= value_len; 588802Salexander.borisov@nginx.com 589802Salexander.borisov@nginx.com req->response->fields_count++; 590802Salexander.borisov@nginx.com } 5911020Smax.romanov@nginx.com } 592843Salexander.borisov@nginx.com 5931020Smax.romanov@nginx.com } catch (exception &e) { 5941020Smax.romanov@nginx.com napi.throw_error(e); 5951020Smax.romanov@nginx.com return nullptr; 596802Salexander.borisov@nginx.com } 597802Salexander.borisov@nginx.com 598802Salexander.borisov@nginx.com req->response_buf->free = ptr; 599802Salexander.borisov@nginx.com 600802Salexander.borisov@nginx.com ret = nxt_unit_response_send(req); 601802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 6021020Smax.romanov@nginx.com napi.throw_error("Failed to send response"); 6031020Smax.romanov@nginx.com return nullptr; 604802Salexander.borisov@nginx.com } 605802Salexander.borisov@nginx.com 606802Salexander.borisov@nginx.com return this_arg; 607802Salexander.borisov@nginx.com } 608802Salexander.borisov@nginx.com 609802Salexander.borisov@nginx.com 610802Salexander.borisov@nginx.com napi_value 611802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info) 612802Salexander.borisov@nginx.com { 613802Salexander.borisov@nginx.com int ret; 614802Salexander.borisov@nginx.com char *ptr; 615802Salexander.borisov@nginx.com size_t argc, have_buf_len; 616802Salexander.borisov@nginx.com uint32_t buf_len; 6171020Smax.romanov@nginx.com nxt_napi napi(env); 618802Salexander.borisov@nginx.com napi_value this_arg, req_num; 619802Salexander.borisov@nginx.com napi_status status; 620802Salexander.borisov@nginx.com nxt_unit_buf_t *buf; 621802Salexander.borisov@nginx.com napi_valuetype buf_type; 622802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 623802Salexander.borisov@nginx.com napi_value argv[3]; 624802Salexander.borisov@nginx.com 625802Salexander.borisov@nginx.com argc = 3; 626802Salexander.borisov@nginx.com 6271020Smax.romanov@nginx.com try { 6281020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, argv); 6291020Smax.romanov@nginx.com if (argc != 3) { 6301020Smax.romanov@nginx.com throw exception("Wrong args count. Expected: " 6311020Smax.romanov@nginx.com "chunk, chunk length"); 6321020Smax.romanov@nginx.com } 633802Salexander.borisov@nginx.com 6341020Smax.romanov@nginx.com req_num = napi.get_named_property(argv[0], "_req_point"); 6351020Smax.romanov@nginx.com req = napi.get_request_info(req_num); 636802Salexander.borisov@nginx.com 6371020Smax.romanov@nginx.com buf_len = napi.get_value_uint32(argv[2]); 638802Salexander.borisov@nginx.com 6391020Smax.romanov@nginx.com buf_type = napi.type_of(argv[1]); 640802Salexander.borisov@nginx.com 6411020Smax.romanov@nginx.com } catch (exception &e) { 6421020Smax.romanov@nginx.com napi.throw_error(e); 6431020Smax.romanov@nginx.com return nullptr; 644802Salexander.borisov@nginx.com } 645802Salexander.borisov@nginx.com 646802Salexander.borisov@nginx.com buf_len++; 647802Salexander.borisov@nginx.com 648802Salexander.borisov@nginx.com buf = nxt_unit_response_buf_alloc(req, buf_len); 649802Salexander.borisov@nginx.com if (buf == NULL) { 650802Salexander.borisov@nginx.com goto failed; 651802Salexander.borisov@nginx.com } 652802Salexander.borisov@nginx.com 653802Salexander.borisov@nginx.com if (buf_type == napi_string) { 654802Salexander.borisov@nginx.com /* TODO: will work only for utf8 content-type */ 655802Salexander.borisov@nginx.com 656802Salexander.borisov@nginx.com status = napi_get_value_string_utf8(env, argv[1], buf->free, 657802Salexander.borisov@nginx.com buf_len, &have_buf_len); 658802Salexander.borisov@nginx.com 659802Salexander.borisov@nginx.com } else { 660802Salexander.borisov@nginx.com status = napi_get_buffer_info(env, argv[1], (void **) &ptr, 661802Salexander.borisov@nginx.com &have_buf_len); 662802Salexander.borisov@nginx.com 663802Salexander.borisov@nginx.com memcpy(buf->free, ptr, have_buf_len); 664802Salexander.borisov@nginx.com } 665802Salexander.borisov@nginx.com 666802Salexander.borisov@nginx.com if (status != napi_ok) { 667802Salexander.borisov@nginx.com goto failed; 668802Salexander.borisov@nginx.com } 669802Salexander.borisov@nginx.com 670802Salexander.borisov@nginx.com buf->free += have_buf_len; 671802Salexander.borisov@nginx.com 672802Salexander.borisov@nginx.com ret = nxt_unit_buf_send(buf); 673802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 674802Salexander.borisov@nginx.com goto failed; 675802Salexander.borisov@nginx.com } 676802Salexander.borisov@nginx.com 677802Salexander.borisov@nginx.com return this_arg; 678802Salexander.borisov@nginx.com 679802Salexander.borisov@nginx.com failed: 680802Salexander.borisov@nginx.com 6811020Smax.romanov@nginx.com napi.throw_error("Failed to write body"); 682802Salexander.borisov@nginx.com 683802Salexander.borisov@nginx.com return nullptr; 684802Salexander.borisov@nginx.com } 685802Salexander.borisov@nginx.com 686802Salexander.borisov@nginx.com 687802Salexander.borisov@nginx.com napi_value 688802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info) 689802Salexander.borisov@nginx.com { 690802Salexander.borisov@nginx.com size_t argc; 6911020Smax.romanov@nginx.com nxt_napi napi(env); 692802Salexander.borisov@nginx.com napi_value resp, this_arg, req_num; 693802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 694802Salexander.borisov@nginx.com 695802Salexander.borisov@nginx.com argc = 1; 696802Salexander.borisov@nginx.com 6971020Smax.romanov@nginx.com try { 6981020Smax.romanov@nginx.com this_arg = napi.get_cb_info(info, argc, &resp); 6991020Smax.romanov@nginx.com 7001020Smax.romanov@nginx.com req_num = napi.get_named_property(resp, "_req_point"); 7011020Smax.romanov@nginx.com req = napi.get_request_info(req_num); 7021020Smax.romanov@nginx.com 7031020Smax.romanov@nginx.com } catch (exception &e) { 7041020Smax.romanov@nginx.com napi.throw_error(e); 705802Salexander.borisov@nginx.com return nullptr; 706802Salexander.borisov@nginx.com } 707802Salexander.borisov@nginx.com 708802Salexander.borisov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 709802Salexander.borisov@nginx.com 710802Salexander.borisov@nginx.com return this_arg; 711802Salexander.borisov@nginx.com } 712