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 23802Salexander.borisov@nginx.com Unit::Unit(napi_env env): 24802Salexander.borisov@nginx.com env_(env), 25802Salexander.borisov@nginx.com wrapper_(nullptr), 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 { 33802Salexander.borisov@nginx.com napi_delete_reference(env_, 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 { 40802Salexander.borisov@nginx.com napi_value cons, fn; 41802Salexander.borisov@nginx.com napi_status status; 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 49802Salexander.borisov@nginx.com status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr, 50828Salexander.borisov@nginx.com 3, properties, &cons); 51802Salexander.borisov@nginx.com if (status != napi_ok) { 52802Salexander.borisov@nginx.com goto failed; 53802Salexander.borisov@nginx.com } 54802Salexander.borisov@nginx.com 55802Salexander.borisov@nginx.com status = napi_create_reference(env, cons, 1, &constructor_); 56802Salexander.borisov@nginx.com if (status != napi_ok) { 57802Salexander.borisov@nginx.com goto failed; 58802Salexander.borisov@nginx.com } 59802Salexander.borisov@nginx.com 60802Salexander.borisov@nginx.com status = napi_set_named_property(env, exports, "Unit", cons); 61802Salexander.borisov@nginx.com if (status != napi_ok) { 62802Salexander.borisov@nginx.com goto failed; 63802Salexander.borisov@nginx.com } 64802Salexander.borisov@nginx.com 65802Salexander.borisov@nginx.com status = napi_create_function(env, NULL, 0, response_send_headers, NULL, 66802Salexander.borisov@nginx.com &fn); 67802Salexander.borisov@nginx.com if (status != napi_ok) { 68802Salexander.borisov@nginx.com goto failed; 69802Salexander.borisov@nginx.com } 70802Salexander.borisov@nginx.com 71802Salexander.borisov@nginx.com status = napi_set_named_property(env, exports, 72802Salexander.borisov@nginx.com "unit_response_headers", fn); 73802Salexander.borisov@nginx.com if (status != napi_ok) { 74802Salexander.borisov@nginx.com goto failed; 75802Salexander.borisov@nginx.com } 76802Salexander.borisov@nginx.com 77802Salexander.borisov@nginx.com status = napi_create_function(env, NULL, 0, response_write, NULL, &fn); 78802Salexander.borisov@nginx.com if (status != napi_ok) { 79802Salexander.borisov@nginx.com goto failed; 80802Salexander.borisov@nginx.com } 81802Salexander.borisov@nginx.com 82802Salexander.borisov@nginx.com status = napi_set_named_property(env, exports, "unit_response_write", fn); 83802Salexander.borisov@nginx.com if (status != napi_ok) { 84802Salexander.borisov@nginx.com goto failed; 85802Salexander.borisov@nginx.com } 86802Salexander.borisov@nginx.com 87802Salexander.borisov@nginx.com status = napi_create_function(env, NULL, 0, response_end, NULL, &fn); 88802Salexander.borisov@nginx.com if (status != napi_ok) { 89802Salexander.borisov@nginx.com goto failed; 90802Salexander.borisov@nginx.com } 91802Salexander.borisov@nginx.com 92802Salexander.borisov@nginx.com status = napi_set_named_property(env, exports, "unit_response_end", fn); 93802Salexander.borisov@nginx.com if (status != napi_ok) { 94802Salexander.borisov@nginx.com goto failed; 95802Salexander.borisov@nginx.com } 96802Salexander.borisov@nginx.com 97802Salexander.borisov@nginx.com return exports; 98802Salexander.borisov@nginx.com 99802Salexander.borisov@nginx.com failed: 100802Salexander.borisov@nginx.com 101802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to define Unit class"); 102802Salexander.borisov@nginx.com 103802Salexander.borisov@nginx.com return nullptr; 104802Salexander.borisov@nginx.com } 105802Salexander.borisov@nginx.com 106802Salexander.borisov@nginx.com 107802Salexander.borisov@nginx.com void 108802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) 109802Salexander.borisov@nginx.com { 110802Salexander.borisov@nginx.com Unit *obj = reinterpret_cast<Unit *>(nativeObject); 111802Salexander.borisov@nginx.com 112802Salexander.borisov@nginx.com delete obj; 113802Salexander.borisov@nginx.com } 114802Salexander.borisov@nginx.com 115802Salexander.borisov@nginx.com 116802Salexander.borisov@nginx.com napi_value 117802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info) 118802Salexander.borisov@nginx.com { 119802Salexander.borisov@nginx.com Unit *obj; 120841Salexander.borisov@nginx.com napi_ref ref; 121802Salexander.borisov@nginx.com napi_value target, cons, instance, jsthis; 122802Salexander.borisov@nginx.com napi_status status; 123802Salexander.borisov@nginx.com 124802Salexander.borisov@nginx.com status = napi_get_new_target(env, info, &target); 125802Salexander.borisov@nginx.com if (status != napi_ok) { 126802Salexander.borisov@nginx.com goto failed; 127802Salexander.borisov@nginx.com } 128802Salexander.borisov@nginx.com 129802Salexander.borisov@nginx.com if (target != nullptr) { 130802Salexander.borisov@nginx.com /* Invoked as constructor: `new Unit(...)` */ 131802Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, 132802Salexander.borisov@nginx.com nullptr); 133802Salexander.borisov@nginx.com if (status != napi_ok) { 134802Salexander.borisov@nginx.com goto failed; 135802Salexander.borisov@nginx.com } 136802Salexander.borisov@nginx.com 137802Salexander.borisov@nginx.com obj = new Unit(env); 138802Salexander.borisov@nginx.com 139802Salexander.borisov@nginx.com status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj), 140802Salexander.borisov@nginx.com destroy, nullptr, &obj->wrapper_); 141802Salexander.borisov@nginx.com if (status != napi_ok) { 142802Salexander.borisov@nginx.com goto failed; 143802Salexander.borisov@nginx.com } 144802Salexander.borisov@nginx.com 145841Salexander.borisov@nginx.com status = napi_create_reference(env, jsthis, 1, &ref); 146841Salexander.borisov@nginx.com if (status != napi_ok) { 147841Salexander.borisov@nginx.com goto failed; 148841Salexander.borisov@nginx.com } 149841Salexander.borisov@nginx.com 150802Salexander.borisov@nginx.com return jsthis; 151802Salexander.borisov@nginx.com } 152802Salexander.borisov@nginx.com 153802Salexander.borisov@nginx.com /* Invoked as plain function `Unit(...)`, turn into construct call. */ 154802Salexander.borisov@nginx.com status = napi_get_reference_value(env, constructor_, &cons); 155802Salexander.borisov@nginx.com if (status != napi_ok) { 156802Salexander.borisov@nginx.com goto failed; 157802Salexander.borisov@nginx.com } 158802Salexander.borisov@nginx.com 159802Salexander.borisov@nginx.com status = napi_new_instance(env, cons, 0, nullptr, &instance); 160802Salexander.borisov@nginx.com if (status != napi_ok) { 161802Salexander.borisov@nginx.com goto failed; 162802Salexander.borisov@nginx.com } 163802Salexander.borisov@nginx.com 164841Salexander.borisov@nginx.com status = napi_create_reference(env, instance, 1, &ref); 165841Salexander.borisov@nginx.com if (status != napi_ok) { 166841Salexander.borisov@nginx.com goto failed; 167841Salexander.borisov@nginx.com } 168841Salexander.borisov@nginx.com 169802Salexander.borisov@nginx.com return instance; 170802Salexander.borisov@nginx.com 171802Salexander.borisov@nginx.com failed: 172802Salexander.borisov@nginx.com 173802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create Unit object"); 174802Salexander.borisov@nginx.com 175802Salexander.borisov@nginx.com return nullptr; 176802Salexander.borisov@nginx.com } 177802Salexander.borisov@nginx.com 178802Salexander.borisov@nginx.com 179802Salexander.borisov@nginx.com napi_value 180802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info) 181802Salexander.borisov@nginx.com { 182802Salexander.borisov@nginx.com Unit *obj; 183802Salexander.borisov@nginx.com size_t argc; 184828Salexander.borisov@nginx.com napi_value jsthis, argv; 185802Salexander.borisov@nginx.com napi_status status; 186802Salexander.borisov@nginx.com nxt_unit_init_t unit_init; 187802Salexander.borisov@nginx.com 188802Salexander.borisov@nginx.com argc = 1; 189802Salexander.borisov@nginx.com 190828Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); 191802Salexander.borisov@nginx.com if (status != napi_ok) { 192802Salexander.borisov@nginx.com goto failed; 193802Salexander.borisov@nginx.com } 194802Salexander.borisov@nginx.com 195802Salexander.borisov@nginx.com status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); 196802Salexander.borisov@nginx.com if (status != napi_ok) { 197802Salexander.borisov@nginx.com goto failed; 198802Salexander.borisov@nginx.com } 199802Salexander.borisov@nginx.com 200802Salexander.borisov@nginx.com memset(&unit_init, 0, sizeof(nxt_unit_init_t)); 201802Salexander.borisov@nginx.com 202802Salexander.borisov@nginx.com unit_init.data = obj; 203802Salexander.borisov@nginx.com unit_init.callbacks.request_handler = request_handler; 204828Salexander.borisov@nginx.com unit_init.callbacks.add_port = add_port; 205828Salexander.borisov@nginx.com unit_init.callbacks.remove_port = remove_port; 206842Salexander.borisov@nginx.com unit_init.callbacks.quit = quit; 207802Salexander.borisov@nginx.com 208802Salexander.borisov@nginx.com obj->unit_ctx_ = nxt_unit_init(&unit_init); 209802Salexander.borisov@nginx.com if (obj->unit_ctx_ == NULL) { 210802Salexander.borisov@nginx.com goto failed; 211802Salexander.borisov@nginx.com } 212802Salexander.borisov@nginx.com 213802Salexander.borisov@nginx.com return nullptr; 214802Salexander.borisov@nginx.com 215802Salexander.borisov@nginx.com failed: 216802Salexander.borisov@nginx.com 217802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create Unit object"); 218802Salexander.borisov@nginx.com 219802Salexander.borisov@nginx.com return nullptr; 220802Salexander.borisov@nginx.com } 221802Salexander.borisov@nginx.com 222802Salexander.borisov@nginx.com 223802Salexander.borisov@nginx.com napi_value 224802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info) 225802Salexander.borisov@nginx.com { 226828Salexander.borisov@nginx.com return nullptr; 227828Salexander.borisov@nginx.com } 228828Salexander.borisov@nginx.com 229802Salexander.borisov@nginx.com 230828Salexander.borisov@nginx.com napi_value 231828Salexander.borisov@nginx.com Unit::_read(napi_env env, napi_callback_info info) 232828Salexander.borisov@nginx.com { 233828Salexander.borisov@nginx.com Unit *obj; 234828Salexander.borisov@nginx.com void *data; 235828Salexander.borisov@nginx.com size_t argc; 236828Salexander.borisov@nginx.com int64_t req_pointer; 237828Salexander.borisov@nginx.com napi_value jsthis, buffer, argv; 238828Salexander.borisov@nginx.com napi_status status; 239828Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 240828Salexander.borisov@nginx.com 241828Salexander.borisov@nginx.com argc = 1; 242828Salexander.borisov@nginx.com 243828Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); 244802Salexander.borisov@nginx.com if (status != napi_ok) { 245828Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get arguments from js"); 246828Salexander.borisov@nginx.com return nullptr; 247802Salexander.borisov@nginx.com } 248802Salexander.borisov@nginx.com 249802Salexander.borisov@nginx.com status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj)); 250802Salexander.borisov@nginx.com if (status != napi_ok) { 251828Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get Unit object form js"); 252828Salexander.borisov@nginx.com return nullptr; 253802Salexander.borisov@nginx.com } 254802Salexander.borisov@nginx.com 255828Salexander.borisov@nginx.com status = napi_get_value_int64(env, argv, &req_pointer); 256828Salexander.borisov@nginx.com if (status != napi_ok) { 257828Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 258802Salexander.borisov@nginx.com return nullptr; 259802Salexander.borisov@nginx.com } 260802Salexander.borisov@nginx.com 261828Salexander.borisov@nginx.com req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer; 262828Salexander.borisov@nginx.com 263828Salexander.borisov@nginx.com status = napi_create_buffer(env, (size_t) req->content_length, 264828Salexander.borisov@nginx.com &data, &buffer); 265828Salexander.borisov@nginx.com if (status != napi_ok) { 266828Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to create request buffer"); 267802Salexander.borisov@nginx.com return nullptr; 268802Salexander.borisov@nginx.com } 269802Salexander.borisov@nginx.com 270828Salexander.borisov@nginx.com nxt_unit_request_read(req, data, req->content_length); 271802Salexander.borisov@nginx.com 272828Salexander.borisov@nginx.com return buffer; 273802Salexander.borisov@nginx.com } 274802Salexander.borisov@nginx.com 275802Salexander.borisov@nginx.com 276802Salexander.borisov@nginx.com void 277802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req) 278802Salexander.borisov@nginx.com { 279*871Salexander.borisov@nginx.com Unit *obj; 280*871Salexander.borisov@nginx.com napi_value socket, request, response, global, server_obj; 281*871Salexander.borisov@nginx.com napi_value emit_events, events_res, async_name, resource_object; 282*871Salexander.borisov@nginx.com napi_status status; 283*871Salexander.borisov@nginx.com napi_async_context async_context; 284*871Salexander.borisov@nginx.com napi_callback_scope async_scope; 285*871Salexander.borisov@nginx.com napi_value events_args[3]; 286802Salexander.borisov@nginx.com 287802Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(req->unit->data); 288802Salexander.borisov@nginx.com 289802Salexander.borisov@nginx.com napi_handle_scope scope; 290802Salexander.borisov@nginx.com status = napi_open_handle_scope(obj->env_, &scope); 291802Salexander.borisov@nginx.com if (status != napi_ok) { 292802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create handle scope"); 293802Salexander.borisov@nginx.com return; 294802Salexander.borisov@nginx.com } 295802Salexander.borisov@nginx.com 296802Salexander.borisov@nginx.com server_obj = obj->get_server_object(); 297802Salexander.borisov@nginx.com if (server_obj == nullptr) { 298802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to get server object"); 299802Salexander.borisov@nginx.com return; 300802Salexander.borisov@nginx.com } 301802Salexander.borisov@nginx.com 302802Salexander.borisov@nginx.com status = napi_get_global(obj->env_, &global); 303802Salexander.borisov@nginx.com if (status != napi_ok) { 304802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to get global variable"); 305802Salexander.borisov@nginx.com return; 306802Salexander.borisov@nginx.com } 307802Salexander.borisov@nginx.com 308802Salexander.borisov@nginx.com socket = obj->create_socket(server_obj, req); 309802Salexander.borisov@nginx.com if (socket == nullptr) { 310802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create socket object"); 311802Salexander.borisov@nginx.com return; 312802Salexander.borisov@nginx.com } 313802Salexander.borisov@nginx.com 314802Salexander.borisov@nginx.com request = obj->create_request(server_obj, socket); 315802Salexander.borisov@nginx.com if (request == nullptr) { 316802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create request object"); 317802Salexander.borisov@nginx.com return; 318802Salexander.borisov@nginx.com } 319802Salexander.borisov@nginx.com 320802Salexander.borisov@nginx.com response = obj->create_response(server_obj, socket, request, req, obj); 321802Salexander.borisov@nginx.com if (response == nullptr) { 322802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create response object"); 323802Salexander.borisov@nginx.com return; 324802Salexander.borisov@nginx.com } 325802Salexander.borisov@nginx.com 326802Salexander.borisov@nginx.com status = obj->create_headers(req, request); 327802Salexander.borisov@nginx.com if (status != napi_ok) { 328802Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create headers"); 329802Salexander.borisov@nginx.com return; 330802Salexander.borisov@nginx.com } 331802Salexander.borisov@nginx.com 332*871Salexander.borisov@nginx.com status = napi_get_named_property(obj->env_, server_obj, "emit_events", 333*871Salexander.borisov@nginx.com &emit_events); 334828Salexander.borisov@nginx.com if (status != napi_ok) { 335*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to get " 336*871Salexander.borisov@nginx.com "'emit_events' function"); 337828Salexander.borisov@nginx.com return; 338828Salexander.borisov@nginx.com } 339828Salexander.borisov@nginx.com 340828Salexander.borisov@nginx.com events_args[0] = server_obj; 341828Salexander.borisov@nginx.com events_args[1] = request; 342828Salexander.borisov@nginx.com events_args[2] = response; 343828Salexander.borisov@nginx.com 344*871Salexander.borisov@nginx.com status = napi_create_string_utf8(obj->env_, "unit_request_handler", 345*871Salexander.borisov@nginx.com sizeof("unit_request_handler") - 1, 346*871Salexander.borisov@nginx.com &async_name); 347828Salexander.borisov@nginx.com if (status != napi_ok) { 348*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create utf-8 string"); 349*871Salexander.borisov@nginx.com return; 350*871Salexander.borisov@nginx.com } 351*871Salexander.borisov@nginx.com 352*871Salexander.borisov@nginx.com status = napi_async_init(obj->env_, NULL, async_name, &async_context); 353*871Salexander.borisov@nginx.com if (status != napi_ok) { 354*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to init async object"); 355*871Salexander.borisov@nginx.com return; 356*871Salexander.borisov@nginx.com } 357*871Salexander.borisov@nginx.com 358*871Salexander.borisov@nginx.com status = napi_create_object(obj->env_, &resource_object); 359*871Salexander.borisov@nginx.com if (status != napi_ok) { 360*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to create object for " 361*871Salexander.borisov@nginx.com "callback scope"); 362828Salexander.borisov@nginx.com return; 363828Salexander.borisov@nginx.com } 364802Salexander.borisov@nginx.com 365*871Salexander.borisov@nginx.com status = napi_open_callback_scope(obj->env_, resource_object, async_context, 366*871Salexander.borisov@nginx.com &async_scope); 367*871Salexander.borisov@nginx.com if (status != napi_ok) { 368*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to open callback scope"); 369*871Salexander.borisov@nginx.com return; 370*871Salexander.borisov@nginx.com } 371*871Salexander.borisov@nginx.com 372*871Salexander.borisov@nginx.com status = napi_make_callback(obj->env_, async_context, server_obj, 373*871Salexander.borisov@nginx.com emit_events, 3, events_args, &events_res); 374*871Salexander.borisov@nginx.com if (status != napi_ok) { 375*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to make callback"); 376*871Salexander.borisov@nginx.com return; 377*871Salexander.borisov@nginx.com } 378*871Salexander.borisov@nginx.com 379*871Salexander.borisov@nginx.com status = napi_close_callback_scope(obj->env_, async_scope); 380*871Salexander.borisov@nginx.com if (status != napi_ok) { 381*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to close callback scope"); 382*871Salexander.borisov@nginx.com return; 383*871Salexander.borisov@nginx.com } 384*871Salexander.borisov@nginx.com 385*871Salexander.borisov@nginx.com status = napi_async_destroy(obj->env_, async_context); 386*871Salexander.borisov@nginx.com if (status != napi_ok) { 387*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to destroy async object"); 388*871Salexander.borisov@nginx.com return; 389*871Salexander.borisov@nginx.com } 390*871Salexander.borisov@nginx.com 391*871Salexander.borisov@nginx.com status = napi_close_handle_scope(obj->env_, scope); 392*871Salexander.borisov@nginx.com if (status != napi_ok) { 393*871Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to close handle scope"); 394*871Salexander.borisov@nginx.com } 395802Salexander.borisov@nginx.com } 396802Salexander.borisov@nginx.com 397802Salexander.borisov@nginx.com 398828Salexander.borisov@nginx.com void 399828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events) 400828Salexander.borisov@nginx.com { 401828Salexander.borisov@nginx.com nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); 402828Salexander.borisov@nginx.com } 403828Salexander.borisov@nginx.com 404828Salexander.borisov@nginx.com 405828Salexander.borisov@nginx.com int 406828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) 407828Salexander.borisov@nginx.com { 408842Salexander.borisov@nginx.com int err; 409842Salexander.borisov@nginx.com Unit *obj; 410842Salexander.borisov@nginx.com uv_loop_t *loop; 411842Salexander.borisov@nginx.com napi_status status; 412842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 413828Salexander.borisov@nginx.com 414828Salexander.borisov@nginx.com if (port->in_fd != -1) { 415828Salexander.borisov@nginx.com obj = reinterpret_cast<Unit *>(ctx->unit->data); 416828Salexander.borisov@nginx.com 417828Salexander.borisov@nginx.com if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { 418828Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to upgrade read" 419828Salexander.borisov@nginx.com " file descriptor to O_NONBLOCK"); 420828Salexander.borisov@nginx.com return -1; 421828Salexander.borisov@nginx.com } 422828Salexander.borisov@nginx.com 423828Salexander.borisov@nginx.com status = napi_get_uv_event_loop(obj->env_, &loop); 424828Salexander.borisov@nginx.com if (status != napi_ok) { 425828Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to get uv.loop"); 426828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 427828Salexander.borisov@nginx.com } 428828Salexander.borisov@nginx.com 429842Salexander.borisov@nginx.com node_ctx = new nxt_nodejs_ctx_t; 430828Salexander.borisov@nginx.com 431842Salexander.borisov@nginx.com err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); 432828Salexander.borisov@nginx.com if (err < 0) { 433828Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to init uv.poll"); 434828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 435828Salexander.borisov@nginx.com } 436828Salexander.borisov@nginx.com 437842Salexander.borisov@nginx.com err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); 438828Salexander.borisov@nginx.com if (err < 0) { 439828Salexander.borisov@nginx.com napi_throw_error(obj->env_, NULL, "Failed to start uv.poll"); 440828Salexander.borisov@nginx.com return NXT_UNIT_ERROR; 441828Salexander.borisov@nginx.com } 442828Salexander.borisov@nginx.com 443842Salexander.borisov@nginx.com ctx->data = node_ctx; 444842Salexander.borisov@nginx.com 445842Salexander.borisov@nginx.com node_ctx->port_id = port->id; 446842Salexander.borisov@nginx.com node_ctx->poll.data = ctx; 447828Salexander.borisov@nginx.com } 448828Salexander.borisov@nginx.com 449828Salexander.borisov@nginx.com return nxt_unit_add_port(ctx, port); 450828Salexander.borisov@nginx.com } 451828Salexander.borisov@nginx.com 452828Salexander.borisov@nginx.com 453842Salexander.borisov@nginx.com inline bool 454842Salexander.borisov@nginx.com operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) 455842Salexander.borisov@nginx.com { 456842Salexander.borisov@nginx.com return p1.pid == p2.pid && p1.id == p2.id; 457842Salexander.borisov@nginx.com } 458842Salexander.borisov@nginx.com 459842Salexander.borisov@nginx.com 460828Salexander.borisov@nginx.com void 461828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) 462828Salexander.borisov@nginx.com { 463842Salexander.borisov@nginx.com nxt_nodejs_ctx_t *node_ctx; 464842Salexander.borisov@nginx.com 465842Salexander.borisov@nginx.com if (ctx->data != NULL) { 466842Salexander.borisov@nginx.com node_ctx = (nxt_nodejs_ctx_t *) ctx->data; 467828Salexander.borisov@nginx.com 468842Salexander.borisov@nginx.com if (node_ctx->port_id == *port_id) { 469842Salexander.borisov@nginx.com uv_poll_stop(&node_ctx->poll); 470828Salexander.borisov@nginx.com 471842Salexander.borisov@nginx.com delete node_ctx; 472828Salexander.borisov@nginx.com 473842Salexander.borisov@nginx.com ctx->data = NULL; 474842Salexander.borisov@nginx.com } 475828Salexander.borisov@nginx.com } 476828Salexander.borisov@nginx.com 477828Salexander.borisov@nginx.com nxt_unit_remove_port(ctx, port_id); 478828Salexander.borisov@nginx.com } 479828Salexander.borisov@nginx.com 480828Salexander.borisov@nginx.com 481842Salexander.borisov@nginx.com void 482842Salexander.borisov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx) 483842Salexander.borisov@nginx.com { 484842Salexander.borisov@nginx.com nxt_unit_done(ctx); 485842Salexander.borisov@nginx.com } 486842Salexander.borisov@nginx.com 487842Salexander.borisov@nginx.com 488802Salexander.borisov@nginx.com napi_value 489802Salexander.borisov@nginx.com Unit::get_server_object() 490802Salexander.borisov@nginx.com { 491802Salexander.borisov@nginx.com napi_value unit_obj, server_obj; 492802Salexander.borisov@nginx.com napi_status status; 493802Salexander.borisov@nginx.com 494802Salexander.borisov@nginx.com status = napi_get_reference_value(env_, wrapper_, &unit_obj); 495802Salexander.borisov@nginx.com if (status != napi_ok) { 496802Salexander.borisov@nginx.com return nullptr; 497802Salexander.borisov@nginx.com } 498802Salexander.borisov@nginx.com 499802Salexander.borisov@nginx.com status = napi_get_named_property(env_, unit_obj, "server", &server_obj); 500802Salexander.borisov@nginx.com if (status != napi_ok) { 501802Salexander.borisov@nginx.com return nullptr; 502802Salexander.borisov@nginx.com } 503802Salexander.borisov@nginx.com 504802Salexander.borisov@nginx.com return server_obj; 505802Salexander.borisov@nginx.com } 506802Salexander.borisov@nginx.com 507802Salexander.borisov@nginx.com 508802Salexander.borisov@nginx.com napi_status 509802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) 510802Salexander.borisov@nginx.com { 511802Salexander.borisov@nginx.com uint32_t i; 512802Salexander.borisov@nginx.com const char *p; 513802Salexander.borisov@nginx.com napi_value headers, raw_headers, str; 514802Salexander.borisov@nginx.com napi_status status; 515802Salexander.borisov@nginx.com nxt_unit_field_t *f; 516802Salexander.borisov@nginx.com nxt_unit_request_t *r; 517802Salexander.borisov@nginx.com 518802Salexander.borisov@nginx.com r = req->request; 519802Salexander.borisov@nginx.com 520802Salexander.borisov@nginx.com status = napi_create_object(env_, &headers); 521802Salexander.borisov@nginx.com if (status != napi_ok) { 522802Salexander.borisov@nginx.com return status; 523802Salexander.borisov@nginx.com } 524802Salexander.borisov@nginx.com 525802Salexander.borisov@nginx.com status = napi_create_array_with_length(env_, r->fields_count * 2, 526802Salexander.borisov@nginx.com &raw_headers); 527802Salexander.borisov@nginx.com if (status != napi_ok) { 528802Salexander.borisov@nginx.com return status; 529802Salexander.borisov@nginx.com } 530802Salexander.borisov@nginx.com 531802Salexander.borisov@nginx.com for (i = 0; i < r->fields_count; i++) { 532802Salexander.borisov@nginx.com f = r->fields + i; 533802Salexander.borisov@nginx.com 534802Salexander.borisov@nginx.com status = this->append_header(f, headers, raw_headers, i); 535802Salexander.borisov@nginx.com if (status != napi_ok) { 536802Salexander.borisov@nginx.com return status; 537802Salexander.borisov@nginx.com } 538802Salexander.borisov@nginx.com } 539802Salexander.borisov@nginx.com 540802Salexander.borisov@nginx.com status = napi_set_named_property(env_, request, "headers", headers); 541802Salexander.borisov@nginx.com if (status != napi_ok) { 542802Salexander.borisov@nginx.com return status; 543802Salexander.borisov@nginx.com } 544802Salexander.borisov@nginx.com 545830Szelenkov@nginx.com status = napi_set_named_property(env_, request, "rawHeaders", raw_headers); 546802Salexander.borisov@nginx.com if (status != napi_ok) { 547802Salexander.borisov@nginx.com return status; 548802Salexander.borisov@nginx.com } 549802Salexander.borisov@nginx.com 550802Salexander.borisov@nginx.com p = (const char *) nxt_unit_sptr_get(&r->version); 551802Salexander.borisov@nginx.com 552802Salexander.borisov@nginx.com status = napi_create_string_latin1(env_, p, r->version_length, &str); 553802Salexander.borisov@nginx.com if (status != napi_ok) { 554802Salexander.borisov@nginx.com return status; 555802Salexander.borisov@nginx.com } 556802Salexander.borisov@nginx.com 557802Salexander.borisov@nginx.com status = napi_set_named_property(env_, request, "httpVersion", str); 558802Salexander.borisov@nginx.com if (status != napi_ok) { 559802Salexander.borisov@nginx.com return status; 560802Salexander.borisov@nginx.com } 561802Salexander.borisov@nginx.com 562802Salexander.borisov@nginx.com p = (const char *) nxt_unit_sptr_get(&r->method); 563802Salexander.borisov@nginx.com 564802Salexander.borisov@nginx.com status = napi_create_string_latin1(env_, p, r->method_length, &str); 565802Salexander.borisov@nginx.com if (status != napi_ok) { 566802Salexander.borisov@nginx.com return status; 567802Salexander.borisov@nginx.com } 568802Salexander.borisov@nginx.com 569802Salexander.borisov@nginx.com status = napi_set_named_property(env_, request, "method", str); 570802Salexander.borisov@nginx.com if (status != napi_ok) { 571802Salexander.borisov@nginx.com return status; 572802Salexander.borisov@nginx.com } 573802Salexander.borisov@nginx.com 574802Salexander.borisov@nginx.com p = (const char *) nxt_unit_sptr_get(&r->target); 575802Salexander.borisov@nginx.com 576802Salexander.borisov@nginx.com status = napi_create_string_latin1(env_, p, r->target_length, &str); 577802Salexander.borisov@nginx.com if (status != napi_ok) { 578802Salexander.borisov@nginx.com return status; 579802Salexander.borisov@nginx.com } 580802Salexander.borisov@nginx.com 581802Salexander.borisov@nginx.com status = napi_set_named_property(env_, request, "url", str); 582802Salexander.borisov@nginx.com if (status != napi_ok) { 583802Salexander.borisov@nginx.com return status; 584802Salexander.borisov@nginx.com } 585802Salexander.borisov@nginx.com 586802Salexander.borisov@nginx.com return napi_ok; 587802Salexander.borisov@nginx.com } 588802Salexander.borisov@nginx.com 589802Salexander.borisov@nginx.com 590802Salexander.borisov@nginx.com inline napi_status 591802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers, 592802Salexander.borisov@nginx.com napi_value raw_headers, uint32_t idx) 593802Salexander.borisov@nginx.com { 594802Salexander.borisov@nginx.com const char *name, *value; 595802Salexander.borisov@nginx.com napi_value str, vstr; 596802Salexander.borisov@nginx.com napi_status status; 597802Salexander.borisov@nginx.com 598802Salexander.borisov@nginx.com value = (const char *) nxt_unit_sptr_get(&f->value); 599802Salexander.borisov@nginx.com 600802Salexander.borisov@nginx.com status = napi_create_string_latin1(env_, value, f->value_length, &vstr); 601802Salexander.borisov@nginx.com if (status != napi_ok) { 602802Salexander.borisov@nginx.com return status; 603802Salexander.borisov@nginx.com } 604802Salexander.borisov@nginx.com 605802Salexander.borisov@nginx.com name = (const char *) nxt_unit_sptr_get(&f->name); 606802Salexander.borisov@nginx.com 607802Salexander.borisov@nginx.com status = napi_set_named_property(env_, headers, name, vstr); 608802Salexander.borisov@nginx.com if (status != napi_ok) { 609802Salexander.borisov@nginx.com return status; 610802Salexander.borisov@nginx.com } 611802Salexander.borisov@nginx.com 612802Salexander.borisov@nginx.com status = napi_create_string_latin1(env_, name, f->name_length, &str); 613802Salexander.borisov@nginx.com if (status != napi_ok) { 614802Salexander.borisov@nginx.com return status; 615802Salexander.borisov@nginx.com } 616802Salexander.borisov@nginx.com 617802Salexander.borisov@nginx.com status = napi_set_element(env_, raw_headers, idx * 2, str); 618802Salexander.borisov@nginx.com if (status != napi_ok) { 619802Salexander.borisov@nginx.com return status; 620802Salexander.borisov@nginx.com } 621802Salexander.borisov@nginx.com 622802Salexander.borisov@nginx.com status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr); 623802Salexander.borisov@nginx.com if (status != napi_ok) { 624802Salexander.borisov@nginx.com return status; 625802Salexander.borisov@nginx.com } 626802Salexander.borisov@nginx.com 627802Salexander.borisov@nginx.com return napi_ok; 628802Salexander.borisov@nginx.com } 629802Salexander.borisov@nginx.com 630802Salexander.borisov@nginx.com 631802Salexander.borisov@nginx.com napi_value 632802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) 633802Salexander.borisov@nginx.com { 634828Salexander.borisov@nginx.com napi_value constructor, return_val, req_pointer; 635802Salexander.borisov@nginx.com napi_status status; 636802Salexander.borisov@nginx.com 637802Salexander.borisov@nginx.com status = napi_get_named_property(env_, server_obj, "socket", 638802Salexander.borisov@nginx.com &constructor); 639802Salexander.borisov@nginx.com if (status != napi_ok) { 640802Salexander.borisov@nginx.com return nullptr; 641802Salexander.borisov@nginx.com } 642802Salexander.borisov@nginx.com 643802Salexander.borisov@nginx.com status = napi_new_instance(env_, constructor, 0, NULL, &return_val); 644802Salexander.borisov@nginx.com if (status != napi_ok) { 645802Salexander.borisov@nginx.com return nullptr; 646802Salexander.borisov@nginx.com } 647802Salexander.borisov@nginx.com 648828Salexander.borisov@nginx.com status = napi_create_int64(env_, (uintptr_t) req, &req_pointer); 649828Salexander.borisov@nginx.com if (status != napi_ok) { 650828Salexander.borisov@nginx.com return nullptr; 651828Salexander.borisov@nginx.com } 652828Salexander.borisov@nginx.com 653828Salexander.borisov@nginx.com status = napi_set_named_property(env_, return_val, "req_pointer", 654828Salexander.borisov@nginx.com req_pointer); 655828Salexander.borisov@nginx.com if (status != napi_ok) { 656828Salexander.borisov@nginx.com return nullptr; 657828Salexander.borisov@nginx.com } 658828Salexander.borisov@nginx.com 659802Salexander.borisov@nginx.com return return_val; 660802Salexander.borisov@nginx.com } 661802Salexander.borisov@nginx.com 662802Salexander.borisov@nginx.com 663802Salexander.borisov@nginx.com napi_value 664802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket) 665802Salexander.borisov@nginx.com { 666802Salexander.borisov@nginx.com napi_value constructor, return_val; 667802Salexander.borisov@nginx.com napi_status status; 668802Salexander.borisov@nginx.com 669802Salexander.borisov@nginx.com status = napi_get_named_property(env_, server_obj, "request", 670802Salexander.borisov@nginx.com &constructor); 671802Salexander.borisov@nginx.com if (status != napi_ok) { 672802Salexander.borisov@nginx.com return nullptr; 673802Salexander.borisov@nginx.com } 674802Salexander.borisov@nginx.com 675802Salexander.borisov@nginx.com status = napi_new_instance(env_, constructor, 1, &server_obj, 676802Salexander.borisov@nginx.com &return_val); 677802Salexander.borisov@nginx.com if (status != napi_ok) { 678802Salexander.borisov@nginx.com return nullptr; 679802Salexander.borisov@nginx.com } 680802Salexander.borisov@nginx.com 681802Salexander.borisov@nginx.com status = napi_set_named_property(env_, return_val, "socket", socket); 682802Salexander.borisov@nginx.com if (status != napi_ok) { 683802Salexander.borisov@nginx.com return nullptr; 684802Salexander.borisov@nginx.com } 685802Salexander.borisov@nginx.com 686802Salexander.borisov@nginx.com return return_val; 687802Salexander.borisov@nginx.com } 688802Salexander.borisov@nginx.com 689802Salexander.borisov@nginx.com 690802Salexander.borisov@nginx.com napi_value 691802Salexander.borisov@nginx.com Unit::create_response(napi_value server_obj, napi_value socket, 692802Salexander.borisov@nginx.com napi_value request, nxt_unit_request_info_t *req, 693802Salexander.borisov@nginx.com Unit *obj) 694802Salexander.borisov@nginx.com { 695802Salexander.borisov@nginx.com napi_value constructor, return_val, req_num; 696802Salexander.borisov@nginx.com napi_status status; 697802Salexander.borisov@nginx.com 698802Salexander.borisov@nginx.com status = napi_get_named_property(env_, server_obj, "response", 699802Salexander.borisov@nginx.com &constructor); 700802Salexander.borisov@nginx.com if (status != napi_ok) { 701802Salexander.borisov@nginx.com return nullptr; 702802Salexander.borisov@nginx.com } 703802Salexander.borisov@nginx.com 704802Salexander.borisov@nginx.com status = napi_new_instance(env_, constructor, 1, &request, &return_val); 705802Salexander.borisov@nginx.com if (status != napi_ok) { 706802Salexander.borisov@nginx.com return nullptr; 707802Salexander.borisov@nginx.com } 708802Salexander.borisov@nginx.com 709802Salexander.borisov@nginx.com status = napi_set_named_property(env_, return_val, "socket", socket); 710802Salexander.borisov@nginx.com if (status != napi_ok) { 711802Salexander.borisov@nginx.com return nullptr; 712802Salexander.borisov@nginx.com } 713802Salexander.borisov@nginx.com 714802Salexander.borisov@nginx.com status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num); 715802Salexander.borisov@nginx.com if (status != napi_ok) { 716802Salexander.borisov@nginx.com return nullptr; 717802Salexander.borisov@nginx.com } 718802Salexander.borisov@nginx.com 719802Salexander.borisov@nginx.com status = napi_set_named_property(env_, return_val, "_req_point", req_num); 720802Salexander.borisov@nginx.com if (status != napi_ok) { 721802Salexander.borisov@nginx.com return nullptr; 722802Salexander.borisov@nginx.com } 723802Salexander.borisov@nginx.com 724802Salexander.borisov@nginx.com return return_val; 725802Salexander.borisov@nginx.com } 726802Salexander.borisov@nginx.com 727802Salexander.borisov@nginx.com 728802Salexander.borisov@nginx.com napi_value 729802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info) 730802Salexander.borisov@nginx.com { 731802Salexander.borisov@nginx.com int ret; 732802Salexander.borisov@nginx.com char *ptr, *name_ptr; 733802Salexander.borisov@nginx.com bool is_array; 734802Salexander.borisov@nginx.com size_t argc, name_len, value_len; 735802Salexander.borisov@nginx.com int64_t req_p; 736802Salexander.borisov@nginx.com uint32_t status_code, header_len, keys_len, array_len; 737802Salexander.borisov@nginx.com uint32_t keys_count, i, j; 738802Salexander.borisov@nginx.com uint16_t hash; 739802Salexander.borisov@nginx.com napi_value this_arg, headers, keys, name, value, array_val; 740802Salexander.borisov@nginx.com napi_value req_num; 741802Salexander.borisov@nginx.com napi_status status; 742843Salexander.borisov@nginx.com napi_valuetype val_type; 743802Salexander.borisov@nginx.com nxt_unit_field_t *f; 744802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 745802Salexander.borisov@nginx.com napi_value argv[5]; 746802Salexander.borisov@nginx.com 747802Salexander.borisov@nginx.com argc = 5; 748802Salexander.borisov@nginx.com 749802Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); 750802Salexander.borisov@nginx.com if (status != napi_ok) { 751802Salexander.borisov@nginx.com return nullptr; 752802Salexander.borisov@nginx.com } 753802Salexander.borisov@nginx.com 754802Salexander.borisov@nginx.com if (argc != 5) { 755802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Wrong args count. Need three: " 756802Salexander.borisov@nginx.com "statusCode, headers, headers count, headers length"); 757802Salexander.borisov@nginx.com return nullptr; 758802Salexander.borisov@nginx.com } 759802Salexander.borisov@nginx.com 760802Salexander.borisov@nginx.com status = napi_get_named_property(env, argv[0], "_req_point", &req_num); 761802Salexander.borisov@nginx.com if (status != napi_ok) { 762802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 763802Salexander.borisov@nginx.com return nullptr; 764802Salexander.borisov@nginx.com } 765802Salexander.borisov@nginx.com 766802Salexander.borisov@nginx.com status = napi_get_value_int64(env, req_num, &req_p); 767802Salexander.borisov@nginx.com if (status != napi_ok) { 768802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 769802Salexander.borisov@nginx.com return nullptr; 770802Salexander.borisov@nginx.com } 771802Salexander.borisov@nginx.com 772802Salexander.borisov@nginx.com req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 773802Salexander.borisov@nginx.com 774802Salexander.borisov@nginx.com status = napi_get_value_uint32(env, argv[1], &status_code); 775802Salexander.borisov@nginx.com if (status != napi_ok) { 776802Salexander.borisov@nginx.com goto failed; 777802Salexander.borisov@nginx.com } 778802Salexander.borisov@nginx.com 779802Salexander.borisov@nginx.com status = napi_get_value_uint32(env, argv[3], &keys_count); 780802Salexander.borisov@nginx.com if (status != napi_ok) { 781802Salexander.borisov@nginx.com goto failed; 782802Salexander.borisov@nginx.com } 783802Salexander.borisov@nginx.com 784802Salexander.borisov@nginx.com status = napi_get_value_uint32(env, argv[4], &header_len); 785802Salexander.borisov@nginx.com if (status != napi_ok) { 786802Salexander.borisov@nginx.com goto failed; 787802Salexander.borisov@nginx.com } 788802Salexander.borisov@nginx.com 789802Salexander.borisov@nginx.com /* Need to reserve extra byte for C-string 0-termination. */ 790802Salexander.borisov@nginx.com header_len++; 791802Salexander.borisov@nginx.com 792802Salexander.borisov@nginx.com headers = argv[2]; 793802Salexander.borisov@nginx.com 794802Salexander.borisov@nginx.com ret = nxt_unit_response_init(req, status_code, keys_count, header_len); 795802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 796802Salexander.borisov@nginx.com goto failed; 797802Salexander.borisov@nginx.com } 798802Salexander.borisov@nginx.com 799802Salexander.borisov@nginx.com status = napi_get_property_names(env, headers, &keys); 800802Salexander.borisov@nginx.com if (status != napi_ok) { 801802Salexander.borisov@nginx.com goto failed; 802802Salexander.borisov@nginx.com } 803802Salexander.borisov@nginx.com 804802Salexander.borisov@nginx.com status = napi_get_array_length(env, keys, &keys_len); 805802Salexander.borisov@nginx.com if (status != napi_ok) { 806802Salexander.borisov@nginx.com goto failed; 807802Salexander.borisov@nginx.com } 808802Salexander.borisov@nginx.com 809802Salexander.borisov@nginx.com ptr = req->response_buf->free; 810802Salexander.borisov@nginx.com 811802Salexander.borisov@nginx.com for (i = 0; i < keys_len; i++) { 812802Salexander.borisov@nginx.com status = napi_get_element(env, keys, i, &name); 813802Salexander.borisov@nginx.com if (status != napi_ok) { 814802Salexander.borisov@nginx.com goto failed; 815802Salexander.borisov@nginx.com } 816802Salexander.borisov@nginx.com 817802Salexander.borisov@nginx.com status = napi_get_property(env, headers, name, &value); 818802Salexander.borisov@nginx.com if (status != napi_ok) { 819802Salexander.borisov@nginx.com goto failed; 820802Salexander.borisov@nginx.com } 821802Salexander.borisov@nginx.com 822802Salexander.borisov@nginx.com status = napi_get_value_string_latin1(env, name, ptr, header_len, 823802Salexander.borisov@nginx.com &name_len); 824802Salexander.borisov@nginx.com if (status != napi_ok) { 825802Salexander.borisov@nginx.com goto failed; 826802Salexander.borisov@nginx.com } 827802Salexander.borisov@nginx.com 828802Salexander.borisov@nginx.com name_ptr = ptr; 829802Salexander.borisov@nginx.com 830802Salexander.borisov@nginx.com ptr += name_len; 831802Salexander.borisov@nginx.com header_len -= name_len; 832802Salexander.borisov@nginx.com 833802Salexander.borisov@nginx.com hash = nxt_unit_field_hash(name_ptr, name_len); 834802Salexander.borisov@nginx.com 835802Salexander.borisov@nginx.com status = napi_is_array(env, value, &is_array); 836802Salexander.borisov@nginx.com if (status != napi_ok) { 837802Salexander.borisov@nginx.com goto failed; 838802Salexander.borisov@nginx.com } 839802Salexander.borisov@nginx.com 840802Salexander.borisov@nginx.com if (is_array) { 841802Salexander.borisov@nginx.com status = napi_get_array_length(env, value, &array_len); 842802Salexander.borisov@nginx.com if (status != napi_ok) { 843802Salexander.borisov@nginx.com goto failed; 844802Salexander.borisov@nginx.com } 845802Salexander.borisov@nginx.com 846802Salexander.borisov@nginx.com for (j = 0; j < array_len; j++) { 847802Salexander.borisov@nginx.com status = napi_get_element(env, value, j, &array_val); 848802Salexander.borisov@nginx.com if (status != napi_ok) { 849802Salexander.borisov@nginx.com goto failed; 850802Salexander.borisov@nginx.com } 851802Salexander.borisov@nginx.com 852843Salexander.borisov@nginx.com napi_typeof(env, array_val, &val_type); 853843Salexander.borisov@nginx.com if (status != napi_ok) { 854843Salexander.borisov@nginx.com goto failed; 855843Salexander.borisov@nginx.com } 856843Salexander.borisov@nginx.com 857843Salexander.borisov@nginx.com if (val_type != napi_string) { 858843Salexander.borisov@nginx.com status = napi_coerce_to_string(env, array_val, &array_val); 859843Salexander.borisov@nginx.com if (status != napi_ok) { 860843Salexander.borisov@nginx.com goto failed; 861843Salexander.borisov@nginx.com } 862843Salexander.borisov@nginx.com } 863843Salexander.borisov@nginx.com 864802Salexander.borisov@nginx.com status = napi_get_value_string_latin1(env, array_val, ptr, 865802Salexander.borisov@nginx.com header_len, 866802Salexander.borisov@nginx.com &value_len); 867802Salexander.borisov@nginx.com if (status != napi_ok) { 868802Salexander.borisov@nginx.com goto failed; 869802Salexander.borisov@nginx.com } 870802Salexander.borisov@nginx.com 871802Salexander.borisov@nginx.com f = req->response->fields + req->response->fields_count; 872802Salexander.borisov@nginx.com f->skip = 0; 873802Salexander.borisov@nginx.com 874802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 875802Salexander.borisov@nginx.com 876802Salexander.borisov@nginx.com f->name_length = name_len; 877802Salexander.borisov@nginx.com f->hash = hash; 878802Salexander.borisov@nginx.com 879802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 880802Salexander.borisov@nginx.com f->value_length = (uint32_t) value_len; 881802Salexander.borisov@nginx.com 882802Salexander.borisov@nginx.com ptr += value_len; 883802Salexander.borisov@nginx.com header_len -= value_len; 884802Salexander.borisov@nginx.com 885802Salexander.borisov@nginx.com req->response->fields_count++; 886802Salexander.borisov@nginx.com } 887802Salexander.borisov@nginx.com 888802Salexander.borisov@nginx.com } else { 889843Salexander.borisov@nginx.com napi_typeof(env, value, &val_type); 890843Salexander.borisov@nginx.com if (status != napi_ok) { 891843Salexander.borisov@nginx.com goto failed; 892843Salexander.borisov@nginx.com } 893843Salexander.borisov@nginx.com 894843Salexander.borisov@nginx.com if (val_type != napi_string) { 895843Salexander.borisov@nginx.com status = napi_coerce_to_string(env, value, &value); 896843Salexander.borisov@nginx.com if (status != napi_ok) { 897843Salexander.borisov@nginx.com goto failed; 898843Salexander.borisov@nginx.com } 899843Salexander.borisov@nginx.com } 900843Salexander.borisov@nginx.com 901802Salexander.borisov@nginx.com status = napi_get_value_string_latin1(env, value, ptr, header_len, 902802Salexander.borisov@nginx.com &value_len); 903802Salexander.borisov@nginx.com if (status != napi_ok) { 904802Salexander.borisov@nginx.com goto failed; 905802Salexander.borisov@nginx.com } 906802Salexander.borisov@nginx.com 907802Salexander.borisov@nginx.com f = req->response->fields + req->response->fields_count; 908802Salexander.borisov@nginx.com f->skip = 0; 909802Salexander.borisov@nginx.com 910802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->name, name_ptr); 911802Salexander.borisov@nginx.com 912802Salexander.borisov@nginx.com f->name_length = name_len; 913802Salexander.borisov@nginx.com f->hash = hash; 914802Salexander.borisov@nginx.com 915802Salexander.borisov@nginx.com nxt_unit_sptr_set(&f->value, ptr); 916802Salexander.borisov@nginx.com f->value_length = (uint32_t) value_len; 917802Salexander.borisov@nginx.com 918802Salexander.borisov@nginx.com ptr += value_len; 919802Salexander.borisov@nginx.com header_len -= value_len; 920802Salexander.borisov@nginx.com 921802Salexander.borisov@nginx.com req->response->fields_count++; 922802Salexander.borisov@nginx.com } 923802Salexander.borisov@nginx.com } 924802Salexander.borisov@nginx.com 925802Salexander.borisov@nginx.com req->response_buf->free = ptr; 926802Salexander.borisov@nginx.com 927802Salexander.borisov@nginx.com ret = nxt_unit_response_send(req); 928802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 929802Salexander.borisov@nginx.com goto failed; 930802Salexander.borisov@nginx.com } 931802Salexander.borisov@nginx.com 932802Salexander.borisov@nginx.com return this_arg; 933802Salexander.borisov@nginx.com 934802Salexander.borisov@nginx.com failed: 935802Salexander.borisov@nginx.com 936802Salexander.borisov@nginx.com req->response->fields_count = 0; 937802Salexander.borisov@nginx.com 938802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to write headers"); 939802Salexander.borisov@nginx.com 940802Salexander.borisov@nginx.com return nullptr; 941802Salexander.borisov@nginx.com } 942802Salexander.borisov@nginx.com 943802Salexander.borisov@nginx.com 944802Salexander.borisov@nginx.com napi_value 945802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info) 946802Salexander.borisov@nginx.com { 947802Salexander.borisov@nginx.com int ret; 948802Salexander.borisov@nginx.com char *ptr; 949802Salexander.borisov@nginx.com size_t argc, have_buf_len; 950802Salexander.borisov@nginx.com int64_t req_p; 951802Salexander.borisov@nginx.com uint32_t buf_len; 952802Salexander.borisov@nginx.com napi_value this_arg, req_num; 953802Salexander.borisov@nginx.com napi_status status; 954802Salexander.borisov@nginx.com nxt_unit_buf_t *buf; 955802Salexander.borisov@nginx.com napi_valuetype buf_type; 956802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 957802Salexander.borisov@nginx.com napi_value argv[3]; 958802Salexander.borisov@nginx.com 959802Salexander.borisov@nginx.com argc = 3; 960802Salexander.borisov@nginx.com 961802Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); 962802Salexander.borisov@nginx.com if (status != napi_ok) { 963802Salexander.borisov@nginx.com goto failed; 964802Salexander.borisov@nginx.com } 965802Salexander.borisov@nginx.com 966802Salexander.borisov@nginx.com if (argc != 3) { 967802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Wrong args count. Need two: " 968802Salexander.borisov@nginx.com "chunk, chunk length"); 969802Salexander.borisov@nginx.com return nullptr; 970802Salexander.borisov@nginx.com } 971802Salexander.borisov@nginx.com 972802Salexander.borisov@nginx.com status = napi_get_named_property(env, argv[0], "_req_point", &req_num); 973802Salexander.borisov@nginx.com if (status != napi_ok) { 974802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 975802Salexander.borisov@nginx.com return nullptr; 976802Salexander.borisov@nginx.com } 977802Salexander.borisov@nginx.com 978802Salexander.borisov@nginx.com status = napi_get_value_int64(env, req_num, &req_p); 979802Salexander.borisov@nginx.com if (status != napi_ok) { 980802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 981802Salexander.borisov@nginx.com return nullptr; 982802Salexander.borisov@nginx.com } 983802Salexander.borisov@nginx.com 984802Salexander.borisov@nginx.com req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 985802Salexander.borisov@nginx.com 986802Salexander.borisov@nginx.com status = napi_get_value_uint32(env, argv[2], &buf_len); 987802Salexander.borisov@nginx.com if (status != napi_ok) { 988802Salexander.borisov@nginx.com goto failed; 989802Salexander.borisov@nginx.com } 990802Salexander.borisov@nginx.com 991802Salexander.borisov@nginx.com status = napi_typeof(env, argv[1], &buf_type); 992802Salexander.borisov@nginx.com if (status != napi_ok) { 993802Salexander.borisov@nginx.com goto failed; 994802Salexander.borisov@nginx.com } 995802Salexander.borisov@nginx.com 996802Salexander.borisov@nginx.com buf_len++; 997802Salexander.borisov@nginx.com 998802Salexander.borisov@nginx.com buf = nxt_unit_response_buf_alloc(req, buf_len); 999802Salexander.borisov@nginx.com if (buf == NULL) { 1000802Salexander.borisov@nginx.com goto failed; 1001802Salexander.borisov@nginx.com } 1002802Salexander.borisov@nginx.com 1003802Salexander.borisov@nginx.com if (buf_type == napi_string) { 1004802Salexander.borisov@nginx.com /* TODO: will work only for utf8 content-type */ 1005802Salexander.borisov@nginx.com 1006802Salexander.borisov@nginx.com status = napi_get_value_string_utf8(env, argv[1], buf->free, 1007802Salexander.borisov@nginx.com buf_len, &have_buf_len); 1008802Salexander.borisov@nginx.com 1009802Salexander.borisov@nginx.com } else { 1010802Salexander.borisov@nginx.com status = napi_get_buffer_info(env, argv[1], (void **) &ptr, 1011802Salexander.borisov@nginx.com &have_buf_len); 1012802Salexander.borisov@nginx.com 1013802Salexander.borisov@nginx.com memcpy(buf->free, ptr, have_buf_len); 1014802Salexander.borisov@nginx.com } 1015802Salexander.borisov@nginx.com 1016802Salexander.borisov@nginx.com if (status != napi_ok) { 1017802Salexander.borisov@nginx.com goto failed; 1018802Salexander.borisov@nginx.com } 1019802Salexander.borisov@nginx.com 1020802Salexander.borisov@nginx.com buf->free += have_buf_len; 1021802Salexander.borisov@nginx.com 1022802Salexander.borisov@nginx.com ret = nxt_unit_buf_send(buf); 1023802Salexander.borisov@nginx.com if (ret != NXT_UNIT_OK) { 1024802Salexander.borisov@nginx.com goto failed; 1025802Salexander.borisov@nginx.com } 1026802Salexander.borisov@nginx.com 1027802Salexander.borisov@nginx.com return this_arg; 1028802Salexander.borisov@nginx.com 1029802Salexander.borisov@nginx.com failed: 1030802Salexander.borisov@nginx.com 1031802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to write body"); 1032802Salexander.borisov@nginx.com 1033802Salexander.borisov@nginx.com return nullptr; 1034802Salexander.borisov@nginx.com } 1035802Salexander.borisov@nginx.com 1036802Salexander.borisov@nginx.com 1037802Salexander.borisov@nginx.com napi_value 1038802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info) 1039802Salexander.borisov@nginx.com { 1040802Salexander.borisov@nginx.com size_t argc; 1041802Salexander.borisov@nginx.com int64_t req_p; 1042802Salexander.borisov@nginx.com napi_value resp, this_arg, req_num; 1043802Salexander.borisov@nginx.com napi_status status; 1044802Salexander.borisov@nginx.com nxt_unit_request_info_t *req; 1045802Salexander.borisov@nginx.com 1046802Salexander.borisov@nginx.com argc = 1; 1047802Salexander.borisov@nginx.com 1048802Salexander.borisov@nginx.com status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL); 1049802Salexander.borisov@nginx.com if (status != napi_ok) { 1050802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to finalize sending body"); 1051802Salexander.borisov@nginx.com return nullptr; 1052802Salexander.borisov@nginx.com } 1053802Salexander.borisov@nginx.com 1054802Salexander.borisov@nginx.com status = napi_get_named_property(env, resp, "_req_point", &req_num); 1055802Salexander.borisov@nginx.com if (status != napi_ok) { 1056802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 1057802Salexander.borisov@nginx.com return nullptr; 1058802Salexander.borisov@nginx.com } 1059802Salexander.borisov@nginx.com 1060802Salexander.borisov@nginx.com status = napi_get_value_int64(env, req_num, &req_p); 1061802Salexander.borisov@nginx.com if (status != napi_ok) { 1062802Salexander.borisov@nginx.com napi_throw_error(env, NULL, "Failed to get request pointer"); 1063802Salexander.borisov@nginx.com return nullptr; 1064802Salexander.borisov@nginx.com } 1065802Salexander.borisov@nginx.com 1066802Salexander.borisov@nginx.com req = (nxt_unit_request_info_t *) (uintptr_t) req_p; 1067802Salexander.borisov@nginx.com 1068802Salexander.borisov@nginx.com nxt_unit_request_done(req, NXT_UNIT_OK); 1069802Salexander.borisov@nginx.com 1070802Salexander.borisov@nginx.com return this_arg; 1071802Salexander.borisov@nginx.com } 1072