xref: /unit/src/nodejs/unit-http/unit.cpp (revision 1547)
1802Salexander.borisov@nginx.com 
2802Salexander.borisov@nginx.com /*
3802Salexander.borisov@nginx.com  * Copyright (C) NGINX, Inc.
4802Salexander.borisov@nginx.com  */
5802Salexander.borisov@nginx.com 
6802Salexander.borisov@nginx.com #include "unit.h"
7802Salexander.borisov@nginx.com 
8828Salexander.borisov@nginx.com #include <unistd.h>
9828Salexander.borisov@nginx.com #include <fcntl.h>
10828Salexander.borisov@nginx.com 
11828Salexander.borisov@nginx.com #include <uv.h>
12828Salexander.borisov@nginx.com 
131132Smax.romanov@nginx.com #include <nxt_unit_websocket.h>
141132Smax.romanov@nginx.com 
15802Salexander.borisov@nginx.com 
161536Smax.romanov@nginx.com static void delete_port_data(uv_handle_t* handle);
171536Smax.romanov@nginx.com 
18802Salexander.borisov@nginx.com napi_ref Unit::constructor_;
19802Salexander.borisov@nginx.com 
20802Salexander.borisov@nginx.com 
211543Smax.romanov@nginx.com struct port_data_t {
221543Smax.romanov@nginx.com     nxt_unit_ctx_t      *ctx;
23*1547Smax.romanov@nginx.com     nxt_unit_port_t     *port;
24842Salexander.borisov@nginx.com     uv_poll_t           poll;
25842Salexander.borisov@nginx.com };
26842Salexander.borisov@nginx.com 
27842Salexander.borisov@nginx.com 
281132Smax.romanov@nginx.com struct req_data_t {
291132Smax.romanov@nginx.com     napi_ref  sock_ref;
301132Smax.romanov@nginx.com     napi_ref  resp_ref;
311132Smax.romanov@nginx.com     napi_ref  conn_ref;
321132Smax.romanov@nginx.com };
331132Smax.romanov@nginx.com 
341132Smax.romanov@nginx.com 
351020Smax.romanov@nginx.com Unit::Unit(napi_env env, napi_value jsthis):
361020Smax.romanov@nginx.com     nxt_napi(env),
371020Smax.romanov@nginx.com     wrapper_(wrap(jsthis, this, destroy)),
38802Salexander.borisov@nginx.com     unit_ctx_(nullptr)
39802Salexander.borisov@nginx.com {
401132Smax.romanov@nginx.com     nxt_unit_debug(NULL, "Unit::Unit()");
41802Salexander.borisov@nginx.com }
42802Salexander.borisov@nginx.com 
43802Salexander.borisov@nginx.com 
44802Salexander.borisov@nginx.com Unit::~Unit()
45802Salexander.borisov@nginx.com {
461020Smax.romanov@nginx.com     delete_reference(wrapper_);
471132Smax.romanov@nginx.com 
481132Smax.romanov@nginx.com     nxt_unit_debug(NULL, "Unit::~Unit()");
49802Salexander.borisov@nginx.com }
50802Salexander.borisov@nginx.com 
51802Salexander.borisov@nginx.com 
52802Salexander.borisov@nginx.com napi_value
53802Salexander.borisov@nginx.com Unit::init(napi_env env, napi_value exports)
54802Salexander.borisov@nginx.com {
551020Smax.romanov@nginx.com     nxt_napi    napi(env);
561132Smax.romanov@nginx.com     napi_value  ctor;
57802Salexander.borisov@nginx.com 
581132Smax.romanov@nginx.com     napi_property_descriptor  unit_props[] = {
59802Salexander.borisov@nginx.com         { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 },
60828Salexander.borisov@nginx.com         { "listen", 0, listen, 0, 0, 0, napi_default, 0 },
61802Salexander.borisov@nginx.com     };
62802Salexander.borisov@nginx.com 
631020Smax.romanov@nginx.com     try {
641132Smax.romanov@nginx.com         ctor = napi.define_class("Unit", create, 2, unit_props);
651132Smax.romanov@nginx.com         constructor_ = napi.create_reference(ctor);
66802Salexander.borisov@nginx.com 
671132Smax.romanov@nginx.com         napi.set_named_property(exports, "Unit", ctor);
681132Smax.romanov@nginx.com         napi.set_named_property(exports, "response_send_headers",
691020Smax.romanov@nginx.com                                 response_send_headers);
701132Smax.romanov@nginx.com         napi.set_named_property(exports, "response_write", response_write);
711132Smax.romanov@nginx.com         napi.set_named_property(exports, "response_end", response_end);
721132Smax.romanov@nginx.com         napi.set_named_property(exports, "websocket_send_frame",
731132Smax.romanov@nginx.com                                 websocket_send_frame);
741132Smax.romanov@nginx.com         napi.set_named_property(exports, "websocket_set_sock",
751132Smax.romanov@nginx.com                                 websocket_set_sock);
761322Smax.romanov@nginx.com         napi.set_named_property(exports, "buf_min", nxt_unit_buf_min());
771322Smax.romanov@nginx.com         napi.set_named_property(exports, "buf_max", nxt_unit_buf_max());
78802Salexander.borisov@nginx.com 
791020Smax.romanov@nginx.com     } catch (exception &e) {
801020Smax.romanov@nginx.com         napi.throw_error(e);
811020Smax.romanov@nginx.com         return nullptr;
82802Salexander.borisov@nginx.com     }
83802Salexander.borisov@nginx.com 
84802Salexander.borisov@nginx.com     return exports;
85802Salexander.borisov@nginx.com }
86802Salexander.borisov@nginx.com 
87802Salexander.borisov@nginx.com 
88802Salexander.borisov@nginx.com void
89802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint)
90802Salexander.borisov@nginx.com {
91802Salexander.borisov@nginx.com     Unit  *obj = reinterpret_cast<Unit *>(nativeObject);
92802Salexander.borisov@nginx.com 
93802Salexander.borisov@nginx.com     delete obj;
94802Salexander.borisov@nginx.com }
95802Salexander.borisov@nginx.com 
96802Salexander.borisov@nginx.com 
97802Salexander.borisov@nginx.com napi_value
98802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info)
99802Salexander.borisov@nginx.com {
1001020Smax.romanov@nginx.com     nxt_napi    napi(env);
1011132Smax.romanov@nginx.com     napi_value  target, ctor, instance, jsthis;
1021020Smax.romanov@nginx.com 
1031020Smax.romanov@nginx.com     try {
1041020Smax.romanov@nginx.com         target = napi.get_new_target(info);
105802Salexander.borisov@nginx.com 
1061020Smax.romanov@nginx.com         if (target != nullptr) {
1071020Smax.romanov@nginx.com             /* Invoked as constructor: `new Unit(...)`. */
1081020Smax.romanov@nginx.com             jsthis = napi.get_cb_info(info);
109802Salexander.borisov@nginx.com 
1101023Smax.romanov@nginx.com             new Unit(env, jsthis);
1111023Smax.romanov@nginx.com             napi.create_reference(jsthis);
1121020Smax.romanov@nginx.com 
1131020Smax.romanov@nginx.com             return jsthis;
114802Salexander.borisov@nginx.com         }
115802Salexander.borisov@nginx.com 
1161020Smax.romanov@nginx.com         /* Invoked as plain function `Unit(...)`, turn into construct call. */
1171132Smax.romanov@nginx.com         ctor = napi.get_reference_value(constructor_);
1181132Smax.romanov@nginx.com         instance = napi.new_instance(ctor);
1191023Smax.romanov@nginx.com         napi.create_reference(instance);
120841Salexander.borisov@nginx.com 
1211020Smax.romanov@nginx.com     } catch (exception &e) {
1221020Smax.romanov@nginx.com         napi.throw_error(e);
1231020Smax.romanov@nginx.com         return nullptr;
124841Salexander.borisov@nginx.com     }
125841Salexander.borisov@nginx.com 
126802Salexander.borisov@nginx.com     return instance;
127802Salexander.borisov@nginx.com }
128802Salexander.borisov@nginx.com 
129802Salexander.borisov@nginx.com 
130802Salexander.borisov@nginx.com napi_value
131802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info)
132802Salexander.borisov@nginx.com {
133802Salexander.borisov@nginx.com     Unit             *obj;
134802Salexander.borisov@nginx.com     size_t           argc;
1351020Smax.romanov@nginx.com     nxt_napi         napi(env);
136828Salexander.borisov@nginx.com     napi_value       jsthis, argv;
137802Salexander.borisov@nginx.com     nxt_unit_init_t  unit_init;
138802Salexander.borisov@nginx.com 
139802Salexander.borisov@nginx.com     argc = 1;
140802Salexander.borisov@nginx.com 
1411020Smax.romanov@nginx.com     try {
1421020Smax.romanov@nginx.com         jsthis = napi.get_cb_info(info, argc, &argv);
1431020Smax.romanov@nginx.com         obj = (Unit *) napi.unwrap(jsthis);
144802Salexander.borisov@nginx.com 
1451020Smax.romanov@nginx.com     } catch (exception &e) {
1461020Smax.romanov@nginx.com         napi.throw_error(e);
1471020Smax.romanov@nginx.com         return nullptr;
148802Salexander.borisov@nginx.com     }
149802Salexander.borisov@nginx.com 
150802Salexander.borisov@nginx.com     memset(&unit_init, 0, sizeof(nxt_unit_init_t));
151802Salexander.borisov@nginx.com 
152802Salexander.borisov@nginx.com     unit_init.data = obj;
1531132Smax.romanov@nginx.com     unit_init.callbacks.request_handler   = request_handler_cb;
1541132Smax.romanov@nginx.com     unit_init.callbacks.websocket_handler = websocket_handler_cb;
1551132Smax.romanov@nginx.com     unit_init.callbacks.close_handler     = close_handler_cb;
1561322Smax.romanov@nginx.com     unit_init.callbacks.shm_ack_handler   = shm_ack_handler_cb;
1571132Smax.romanov@nginx.com     unit_init.callbacks.add_port          = add_port;
1581132Smax.romanov@nginx.com     unit_init.callbacks.remove_port       = remove_port;
1591132Smax.romanov@nginx.com     unit_init.callbacks.quit              = quit_cb;
1601132Smax.romanov@nginx.com 
1611132Smax.romanov@nginx.com     unit_init.request_data_size = sizeof(req_data_t);
162802Salexander.borisov@nginx.com 
163802Salexander.borisov@nginx.com     obj->unit_ctx_ = nxt_unit_init(&unit_init);
164802Salexander.borisov@nginx.com     if (obj->unit_ctx_ == NULL) {
165802Salexander.borisov@nginx.com         goto failed;
166802Salexander.borisov@nginx.com     }
167802Salexander.borisov@nginx.com 
168802Salexander.borisov@nginx.com     return nullptr;
169802Salexander.borisov@nginx.com 
170802Salexander.borisov@nginx.com failed:
171802Salexander.borisov@nginx.com 
172802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to create Unit object");
173802Salexander.borisov@nginx.com 
174802Salexander.borisov@nginx.com     return nullptr;
175802Salexander.borisov@nginx.com }
176802Salexander.borisov@nginx.com 
177802Salexander.borisov@nginx.com 
178802Salexander.borisov@nginx.com napi_value
179802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info)
180802Salexander.borisov@nginx.com {
181828Salexander.borisov@nginx.com     return nullptr;
182828Salexander.borisov@nginx.com }
183828Salexander.borisov@nginx.com 
184802Salexander.borisov@nginx.com 
1851132Smax.romanov@nginx.com void
1861132Smax.romanov@nginx.com Unit::request_handler_cb(nxt_unit_request_info_t *req)
187828Salexander.borisov@nginx.com {
1881132Smax.romanov@nginx.com     Unit  *obj;
189828Salexander.borisov@nginx.com 
1901132Smax.romanov@nginx.com     obj = reinterpret_cast<Unit *>(req->unit->data);
191802Salexander.borisov@nginx.com 
1921132Smax.romanov@nginx.com     obj->request_handler(req);
193802Salexander.borisov@nginx.com }
194802Salexander.borisov@nginx.com 
195802Salexander.borisov@nginx.com 
196802Salexander.borisov@nginx.com void
197802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req)
198802Salexander.borisov@nginx.com {
1991132Smax.romanov@nginx.com     napi_value  socket, request, response, server_obj, emit_request;
200802Salexander.borisov@nginx.com 
2011132Smax.romanov@nginx.com     memset(req->data, 0, sizeof(req_data_t));
202802Salexander.borisov@nginx.com 
2031020Smax.romanov@nginx.com     try {
2041132Smax.romanov@nginx.com         nxt_handle_scope  scope(env());
205802Salexander.borisov@nginx.com 
2061132Smax.romanov@nginx.com         server_obj = get_server_object();
207802Salexander.borisov@nginx.com 
2081132Smax.romanov@nginx.com         socket = create_socket(server_obj, req);
2091132Smax.romanov@nginx.com         request = create_request(server_obj, socket);
2101132Smax.romanov@nginx.com         response = create_response(server_obj, request, req);
211828Salexander.borisov@nginx.com 
2121132Smax.romanov@nginx.com         create_headers(req, request);
213871Salexander.borisov@nginx.com 
2141132Smax.romanov@nginx.com         emit_request = get_named_property(server_obj, "emit_request");
2151132Smax.romanov@nginx.com 
2161132Smax.romanov@nginx.com         nxt_async_context   async_context(env(), "request_handler");
2171020Smax.romanov@nginx.com         nxt_callback_scope  async_scope(async_context);
218876Salexander.borisov@nginx.com 
2191132Smax.romanov@nginx.com         make_callback(async_context, server_obj, emit_request, request,
2201132Smax.romanov@nginx.com                       response);
221871Salexander.borisov@nginx.com 
2221020Smax.romanov@nginx.com     } catch (exception &e) {
2231132Smax.romanov@nginx.com         nxt_unit_req_warn(req, "request_handler: %s", e.str);
224871Salexander.borisov@nginx.com     }
225802Salexander.borisov@nginx.com }
226802Salexander.borisov@nginx.com 
227802Salexander.borisov@nginx.com 
228828Salexander.borisov@nginx.com void
2291132Smax.romanov@nginx.com Unit::websocket_handler_cb(nxt_unit_websocket_frame_t *ws)
2301132Smax.romanov@nginx.com {
2311132Smax.romanov@nginx.com     Unit  *obj;
2321132Smax.romanov@nginx.com 
2331132Smax.romanov@nginx.com     obj = reinterpret_cast<Unit *>(ws->req->unit->data);
2341132Smax.romanov@nginx.com 
2351132Smax.romanov@nginx.com     obj->websocket_handler(ws);
2361132Smax.romanov@nginx.com }
2371132Smax.romanov@nginx.com 
2381132Smax.romanov@nginx.com 
2391132Smax.romanov@nginx.com void
2401132Smax.romanov@nginx.com Unit::websocket_handler(nxt_unit_websocket_frame_t *ws)
2411132Smax.romanov@nginx.com {
2421132Smax.romanov@nginx.com     napi_value  frame, server_obj, process_frame, conn;
2431132Smax.romanov@nginx.com     req_data_t  *req_data;
2441132Smax.romanov@nginx.com 
2451132Smax.romanov@nginx.com     req_data = (req_data_t *) ws->req->data;
2461132Smax.romanov@nginx.com 
2471132Smax.romanov@nginx.com     try {
2481132Smax.romanov@nginx.com         nxt_handle_scope  scope(env());
2491132Smax.romanov@nginx.com 
2501132Smax.romanov@nginx.com         server_obj = get_server_object();
2511132Smax.romanov@nginx.com 
2521132Smax.romanov@nginx.com         frame = create_websocket_frame(server_obj, ws);
2531132Smax.romanov@nginx.com 
2541132Smax.romanov@nginx.com         conn = get_reference_value(req_data->conn_ref);
2551132Smax.romanov@nginx.com 
2561132Smax.romanov@nginx.com         process_frame = get_named_property(conn, "processFrame");
2571132Smax.romanov@nginx.com 
2581132Smax.romanov@nginx.com         nxt_async_context   async_context(env(), "websocket_handler");
2591132Smax.romanov@nginx.com         nxt_callback_scope  async_scope(async_context);
2601132Smax.romanov@nginx.com 
2611132Smax.romanov@nginx.com         make_callback(async_context, conn, process_frame, frame);
2621132Smax.romanov@nginx.com 
2631132Smax.romanov@nginx.com     } catch (exception &e) {
2641132Smax.romanov@nginx.com         nxt_unit_req_warn(ws->req, "websocket_handler: %s", e.str);
2651132Smax.romanov@nginx.com     }
2661132Smax.romanov@nginx.com 
2671132Smax.romanov@nginx.com     nxt_unit_websocket_done(ws);
2681132Smax.romanov@nginx.com }
2691132Smax.romanov@nginx.com 
2701132Smax.romanov@nginx.com 
2711132Smax.romanov@nginx.com void
2721132Smax.romanov@nginx.com Unit::close_handler_cb(nxt_unit_request_info_t *req)
2731132Smax.romanov@nginx.com {
2741132Smax.romanov@nginx.com     Unit  *obj;
2751132Smax.romanov@nginx.com 
2761132Smax.romanov@nginx.com     obj = reinterpret_cast<Unit *>(req->unit->data);
2771132Smax.romanov@nginx.com 
2781132Smax.romanov@nginx.com     obj->close_handler(req);
2791132Smax.romanov@nginx.com }
2801132Smax.romanov@nginx.com 
2811132Smax.romanov@nginx.com 
2821132Smax.romanov@nginx.com void
2831132Smax.romanov@nginx.com Unit::close_handler(nxt_unit_request_info_t *req)
2841132Smax.romanov@nginx.com {
2851132Smax.romanov@nginx.com     napi_value  conn_handle_close, conn;
2861132Smax.romanov@nginx.com     req_data_t  *req_data;
2871132Smax.romanov@nginx.com 
2881132Smax.romanov@nginx.com     req_data = (req_data_t *) req->data;
2891132Smax.romanov@nginx.com 
2901132Smax.romanov@nginx.com     try {
2911132Smax.romanov@nginx.com         nxt_handle_scope  scope(env());
2921132Smax.romanov@nginx.com 
2931132Smax.romanov@nginx.com         conn = get_reference_value(req_data->conn_ref);
2941132Smax.romanov@nginx.com 
2951132Smax.romanov@nginx.com         conn_handle_close = get_named_property(conn, "handleSocketClose");
2961132Smax.romanov@nginx.com 
2971132Smax.romanov@nginx.com         nxt_async_context   async_context(env(), "close_handler");
2981132Smax.romanov@nginx.com         nxt_callback_scope  async_scope(async_context);
2991132Smax.romanov@nginx.com 
3001132Smax.romanov@nginx.com         make_callback(async_context, conn, conn_handle_close,
3011132Smax.romanov@nginx.com                       nxt_napi::create(0));
3021132Smax.romanov@nginx.com 
3031132Smax.romanov@nginx.com         remove_wrap(req_data->sock_ref);
3041132Smax.romanov@nginx.com         remove_wrap(req_data->resp_ref);
3051132Smax.romanov@nginx.com         remove_wrap(req_data->conn_ref);
3061132Smax.romanov@nginx.com 
3071132Smax.romanov@nginx.com     } catch (exception &e) {
3081132Smax.romanov@nginx.com         nxt_unit_req_warn(req, "close_handler: %s", e.str);
3091132Smax.romanov@nginx.com 
3101132Smax.romanov@nginx.com         return;
3111132Smax.romanov@nginx.com     }
3121132Smax.romanov@nginx.com 
3131132Smax.romanov@nginx.com     nxt_unit_request_done(req, NXT_UNIT_OK);
3141132Smax.romanov@nginx.com }
3151132Smax.romanov@nginx.com 
3161132Smax.romanov@nginx.com 
3171322Smax.romanov@nginx.com void
3181322Smax.romanov@nginx.com Unit::shm_ack_handler_cb(nxt_unit_ctx_t *ctx)
3191322Smax.romanov@nginx.com {
3201322Smax.romanov@nginx.com     Unit  *obj;
3211322Smax.romanov@nginx.com 
3221322Smax.romanov@nginx.com     obj = reinterpret_cast<Unit *>(ctx->unit->data);
3231322Smax.romanov@nginx.com 
3241322Smax.romanov@nginx.com     obj->shm_ack_handler(ctx);
3251322Smax.romanov@nginx.com }
3261322Smax.romanov@nginx.com 
3271322Smax.romanov@nginx.com 
3281322Smax.romanov@nginx.com void
3291322Smax.romanov@nginx.com Unit::shm_ack_handler(nxt_unit_ctx_t *ctx)
3301322Smax.romanov@nginx.com {
3311322Smax.romanov@nginx.com     napi_value  server_obj, emit_drain;
3321322Smax.romanov@nginx.com 
3331322Smax.romanov@nginx.com     try {
3341322Smax.romanov@nginx.com         nxt_handle_scope  scope(env());
3351322Smax.romanov@nginx.com 
3361322Smax.romanov@nginx.com         server_obj = get_server_object();
3371322Smax.romanov@nginx.com 
3381322Smax.romanov@nginx.com         emit_drain = get_named_property(server_obj, "emit_drain");
3391322Smax.romanov@nginx.com 
3401322Smax.romanov@nginx.com         nxt_async_context   async_context(env(), "shm_ack_handler");
3411322Smax.romanov@nginx.com         nxt_callback_scope  async_scope(async_context);
3421322Smax.romanov@nginx.com 
3431322Smax.romanov@nginx.com         make_callback(async_context, server_obj, emit_drain);
3441322Smax.romanov@nginx.com 
3451322Smax.romanov@nginx.com     } catch (exception &e) {
3461322Smax.romanov@nginx.com         nxt_unit_warn(ctx, "shm_ack_handler: %s", e.str);
3471322Smax.romanov@nginx.com     }
3481322Smax.romanov@nginx.com }
3491322Smax.romanov@nginx.com 
3501322Smax.romanov@nginx.com 
3511132Smax.romanov@nginx.com static void
352828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events)
353828Salexander.borisov@nginx.com {
354*1547Smax.romanov@nginx.com     port_data_t  *data;
355*1547Smax.romanov@nginx.com 
356*1547Smax.romanov@nginx.com     data = (port_data_t *) handle->data;
357*1547Smax.romanov@nginx.com 
358*1547Smax.romanov@nginx.com     nxt_unit_process_port_msg(data->ctx, data->port);
359828Salexander.borisov@nginx.com }
360828Salexander.borisov@nginx.com 
361828Salexander.borisov@nginx.com 
362828Salexander.borisov@nginx.com int
363828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
364828Salexander.borisov@nginx.com {
365842Salexander.borisov@nginx.com     int               err;
366842Salexander.borisov@nginx.com     Unit              *obj;
367842Salexander.borisov@nginx.com     uv_loop_t         *loop;
3681543Smax.romanov@nginx.com     port_data_t       *data;
369842Salexander.borisov@nginx.com     napi_status       status;
370828Salexander.borisov@nginx.com 
371828Salexander.borisov@nginx.com     if (port->in_fd != -1) {
372828Salexander.borisov@nginx.com         obj = reinterpret_cast<Unit *>(ctx->unit->data);
373828Salexander.borisov@nginx.com 
374828Salexander.borisov@nginx.com         if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) {
3751132Smax.romanov@nginx.com             nxt_unit_warn(ctx, "fcntl(%d, O_NONBLOCK) failed: %s (%d)",
3761132Smax.romanov@nginx.com                           port->in_fd, strerror(errno), errno);
377828Salexander.borisov@nginx.com             return -1;
378828Salexander.borisov@nginx.com         }
379828Salexander.borisov@nginx.com 
3801020Smax.romanov@nginx.com         status = napi_get_uv_event_loop(obj->env(), &loop);
381828Salexander.borisov@nginx.com         if (status != napi_ok) {
3821132Smax.romanov@nginx.com             nxt_unit_warn(ctx, "Failed to get uv.loop");
383828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
384828Salexander.borisov@nginx.com         }
385828Salexander.borisov@nginx.com 
3861543Smax.romanov@nginx.com         data = new port_data_t;
387828Salexander.borisov@nginx.com 
3881543Smax.romanov@nginx.com         err = uv_poll_init(loop, &data->poll, port->in_fd);
389828Salexander.borisov@nginx.com         if (err < 0) {
3901132Smax.romanov@nginx.com             nxt_unit_warn(ctx, "Failed to init uv.poll");
391828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
392828Salexander.borisov@nginx.com         }
393828Salexander.borisov@nginx.com 
3941543Smax.romanov@nginx.com         err = uv_poll_start(&data->poll, UV_READABLE, nxt_uv_read_callback);
395828Salexander.borisov@nginx.com         if (err < 0) {
3961132Smax.romanov@nginx.com             nxt_unit_warn(ctx, "Failed to start uv.poll");
397828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
398828Salexander.borisov@nginx.com         }
399828Salexander.borisov@nginx.com 
4001543Smax.romanov@nginx.com         port->data = data;
401842Salexander.borisov@nginx.com 
4021543Smax.romanov@nginx.com         data->ctx = ctx;
403*1547Smax.romanov@nginx.com         data->port = port;
404*1547Smax.romanov@nginx.com         data->poll.data = data;
405828Salexander.borisov@nginx.com     }
406828Salexander.borisov@nginx.com 
4071543Smax.romanov@nginx.com     return NXT_UNIT_OK;
408828Salexander.borisov@nginx.com }
409828Salexander.borisov@nginx.com 
410828Salexander.borisov@nginx.com 
411828Salexander.borisov@nginx.com void
4121543Smax.romanov@nginx.com Unit::remove_port(nxt_unit_t *unit, nxt_unit_port_t *port)
413828Salexander.borisov@nginx.com {
4141543Smax.romanov@nginx.com     port_data_t  *data;
415828Salexander.borisov@nginx.com 
4161543Smax.romanov@nginx.com     if (port->data != NULL) {
4171543Smax.romanov@nginx.com         data = (port_data_t *) port->data;
418828Salexander.borisov@nginx.com 
419*1547Smax.romanov@nginx.com         if (data->port == port) {
4201543Smax.romanov@nginx.com             uv_poll_stop(&data->poll);
421828Salexander.borisov@nginx.com 
4221543Smax.romanov@nginx.com             uv_close((uv_handle_t *) &data->poll, delete_port_data);
423842Salexander.borisov@nginx.com         }
424828Salexander.borisov@nginx.com     }
425828Salexander.borisov@nginx.com }
426828Salexander.borisov@nginx.com 
427828Salexander.borisov@nginx.com 
4281536Smax.romanov@nginx.com static void
4291536Smax.romanov@nginx.com delete_port_data(uv_handle_t* handle)
4301536Smax.romanov@nginx.com {
4311543Smax.romanov@nginx.com     port_data_t  *data;
4321536Smax.romanov@nginx.com 
4331543Smax.romanov@nginx.com     data = (port_data_t *) handle->data;
4341536Smax.romanov@nginx.com 
4351543Smax.romanov@nginx.com     delete data;
4361536Smax.romanov@nginx.com }
4371536Smax.romanov@nginx.com 
4381536Smax.romanov@nginx.com 
439842Salexander.borisov@nginx.com void
4401132Smax.romanov@nginx.com Unit::quit_cb(nxt_unit_ctx_t *ctx)
441842Salexander.borisov@nginx.com {
4421132Smax.romanov@nginx.com     Unit  *obj;
4431021Smax.romanov@nginx.com 
4441021Smax.romanov@nginx.com     obj = reinterpret_cast<Unit *>(ctx->unit->data);
4451021Smax.romanov@nginx.com 
4461132Smax.romanov@nginx.com     obj->quit(ctx);
4471132Smax.romanov@nginx.com }
4481132Smax.romanov@nginx.com 
4491132Smax.romanov@nginx.com 
4501132Smax.romanov@nginx.com void
4511132Smax.romanov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx)
4521132Smax.romanov@nginx.com {
4531132Smax.romanov@nginx.com     napi_value  server_obj, emit_close;
4541021Smax.romanov@nginx.com 
4551132Smax.romanov@nginx.com     try {
4561132Smax.romanov@nginx.com         nxt_handle_scope  scope(env());
4571021Smax.romanov@nginx.com 
4581132Smax.romanov@nginx.com         server_obj = get_server_object();
4591021Smax.romanov@nginx.com 
4601132Smax.romanov@nginx.com         emit_close = get_named_property(server_obj, "emit_close");
4611132Smax.romanov@nginx.com 
4621132Smax.romanov@nginx.com         nxt_async_context   async_context(env(), "unit_quit");
4631021Smax.romanov@nginx.com         nxt_callback_scope  async_scope(async_context);
4641021Smax.romanov@nginx.com 
4651132Smax.romanov@nginx.com         make_callback(async_context, server_obj, emit_close);
4661021Smax.romanov@nginx.com 
4671021Smax.romanov@nginx.com     } catch (exception &e) {
4681132Smax.romanov@nginx.com         nxt_unit_debug(ctx, "quit: %s", e.str);
4691021Smax.romanov@nginx.com     }
4701021Smax.romanov@nginx.com 
471842Salexander.borisov@nginx.com     nxt_unit_done(ctx);
472842Salexander.borisov@nginx.com }
473842Salexander.borisov@nginx.com 
474842Salexander.borisov@nginx.com 
475802Salexander.borisov@nginx.com napi_value
476802Salexander.borisov@nginx.com Unit::get_server_object()
477802Salexander.borisov@nginx.com {
4781020Smax.romanov@nginx.com     napi_value  unit_obj;
479802Salexander.borisov@nginx.com 
4801020Smax.romanov@nginx.com     unit_obj = get_reference_value(wrapper_);
481802Salexander.borisov@nginx.com 
4821020Smax.romanov@nginx.com     return get_named_property(unit_obj, "server");
483802Salexander.borisov@nginx.com }
484802Salexander.borisov@nginx.com 
485802Salexander.borisov@nginx.com 
4861020Smax.romanov@nginx.com void
487802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
488802Salexander.borisov@nginx.com {
4891132Smax.romanov@nginx.com     void                *data;
490802Salexander.borisov@nginx.com     uint32_t            i;
4911132Smax.romanov@nginx.com     napi_value          headers, raw_headers, buffer;
492802Salexander.borisov@nginx.com     napi_status         status;
493802Salexander.borisov@nginx.com     nxt_unit_request_t  *r;
494802Salexander.borisov@nginx.com 
495802Salexander.borisov@nginx.com     r = req->request;
496802Salexander.borisov@nginx.com 
4971020Smax.romanov@nginx.com     headers = create_object();
498802Salexander.borisov@nginx.com 
4991020Smax.romanov@nginx.com     status = napi_create_array_with_length(env(), r->fields_count * 2,
500802Salexander.borisov@nginx.com                                            &raw_headers);
501802Salexander.borisov@nginx.com     if (status != napi_ok) {
5021020Smax.romanov@nginx.com         throw exception("Failed to create array");
503802Salexander.borisov@nginx.com     }
504802Salexander.borisov@nginx.com 
505802Salexander.borisov@nginx.com     for (i = 0; i < r->fields_count; i++) {
5061020Smax.romanov@nginx.com         append_header(r->fields + i, headers, raw_headers, i);
507802Salexander.borisov@nginx.com     }
508802Salexander.borisov@nginx.com 
5091020Smax.romanov@nginx.com     set_named_property(request, "headers", headers);
5101020Smax.romanov@nginx.com     set_named_property(request, "rawHeaders", raw_headers);
5111020Smax.romanov@nginx.com     set_named_property(request, "httpVersion", r->version, r->version_length);
5121020Smax.romanov@nginx.com     set_named_property(request, "method", r->method, r->method_length);
5131020Smax.romanov@nginx.com     set_named_property(request, "url", r->target, r->target_length);
5141132Smax.romanov@nginx.com 
5151132Smax.romanov@nginx.com     set_named_property(request, "_websocket_handshake", r->websocket_handshake);
5161132Smax.romanov@nginx.com 
5171132Smax.romanov@nginx.com     buffer = create_buffer((size_t) req->content_length, &data);
5181132Smax.romanov@nginx.com     nxt_unit_request_read(req, data, req->content_length);
5191132Smax.romanov@nginx.com 
5201132Smax.romanov@nginx.com     set_named_property(request, "_data", buffer);
521802Salexander.borisov@nginx.com }
522802Salexander.borisov@nginx.com 
523802Salexander.borisov@nginx.com 
5241038Smax.romanov@nginx.com inline char
5251038Smax.romanov@nginx.com lowcase(char c)
5261038Smax.romanov@nginx.com {
5271038Smax.romanov@nginx.com     return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c;
5281038Smax.romanov@nginx.com }
5291038Smax.romanov@nginx.com 
5301038Smax.romanov@nginx.com 
5311020Smax.romanov@nginx.com inline void
532802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers,
5331020Smax.romanov@nginx.com     napi_value raw_headers, uint32_t idx)
534802Salexander.borisov@nginx.com {
5351038Smax.romanov@nginx.com     char        *name;
5361038Smax.romanov@nginx.com     uint8_t     i;
5371038Smax.romanov@nginx.com     napi_value  str, vstr;
5381038Smax.romanov@nginx.com 
5391038Smax.romanov@nginx.com     name = (char *) nxt_unit_sptr_get(&f->name);
540802Salexander.borisov@nginx.com 
5411038Smax.romanov@nginx.com     str = create_string_latin1(name, f->name_length);
5421038Smax.romanov@nginx.com 
5431038Smax.romanov@nginx.com     for (i = 0; i < f->name_length; i++) {
5441038Smax.romanov@nginx.com         name[i] = lowcase(name[i]);
5451038Smax.romanov@nginx.com     }
546802Salexander.borisov@nginx.com 
5471020Smax.romanov@nginx.com     vstr = set_named_property(headers, name, f->value, f->value_length);
548802Salexander.borisov@nginx.com 
5491020Smax.romanov@nginx.com     set_element(raw_headers, idx * 2, str);
5501020Smax.romanov@nginx.com     set_element(raw_headers, idx * 2 + 1, vstr);
551802Salexander.borisov@nginx.com }
552802Salexander.borisov@nginx.com 
553802Salexander.borisov@nginx.com 
554802Salexander.borisov@nginx.com napi_value
555802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req)
556802Salexander.borisov@nginx.com {
5571022Smax.romanov@nginx.com     napi_value          constructor, res;
5581132Smax.romanov@nginx.com     req_data_t          *req_data;
5591022Smax.romanov@nginx.com     nxt_unit_request_t  *r;
5601022Smax.romanov@nginx.com 
5611022Smax.romanov@nginx.com     r = req->request;
562802Salexander.borisov@nginx.com 
5631132Smax.romanov@nginx.com     constructor = get_named_property(server_obj, "Socket");
564802Salexander.borisov@nginx.com 
5651022Smax.romanov@nginx.com     res = new_instance(constructor);
566802Salexander.borisov@nginx.com 
5671132Smax.romanov@nginx.com     req_data = (req_data_t *) req->data;
5681132Smax.romanov@nginx.com     req_data->sock_ref = wrap(res, req, sock_destroy);
5691132Smax.romanov@nginx.com 
5701022Smax.romanov@nginx.com     set_named_property(res, "remoteAddress", r->remote, r->remote_length);
5711022Smax.romanov@nginx.com     set_named_property(res, "localAddress", r->local, r->local_length);
572828Salexander.borisov@nginx.com 
5731022Smax.romanov@nginx.com     return res;
574802Salexander.borisov@nginx.com }
575802Salexander.borisov@nginx.com 
576802Salexander.borisov@nginx.com 
577802Salexander.borisov@nginx.com napi_value
578802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket)
579802Salexander.borisov@nginx.com {
5801132Smax.romanov@nginx.com     napi_value  constructor;
5811132Smax.romanov@nginx.com 
5821132Smax.romanov@nginx.com     constructor = get_named_property(server_obj, "ServerRequest");
583802Salexander.borisov@nginx.com 
5841132Smax.romanov@nginx.com     return new_instance(constructor, server_obj, socket);
5851132Smax.romanov@nginx.com }
5861132Smax.romanov@nginx.com 
587802Salexander.borisov@nginx.com 
5881132Smax.romanov@nginx.com napi_value
5891132Smax.romanov@nginx.com Unit::create_response(napi_value server_obj, napi_value request,
5901132Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
5911132Smax.romanov@nginx.com {
5921132Smax.romanov@nginx.com     napi_value  constructor, res;
5931132Smax.romanov@nginx.com     req_data_t  *req_data;
594802Salexander.borisov@nginx.com 
5951132Smax.romanov@nginx.com     constructor = get_named_property(server_obj, "ServerResponse");
5961132Smax.romanov@nginx.com 
5971132Smax.romanov@nginx.com     res = new_instance(constructor, request);
598802Salexander.borisov@nginx.com 
5991132Smax.romanov@nginx.com     req_data = (req_data_t *) req->data;
6001132Smax.romanov@nginx.com     req_data->resp_ref = wrap(res, req, resp_destroy);
6011132Smax.romanov@nginx.com 
6021132Smax.romanov@nginx.com     return res;
603802Salexander.borisov@nginx.com }
604802Salexander.borisov@nginx.com 
605802Salexander.borisov@nginx.com 
606802Salexander.borisov@nginx.com napi_value
6071132Smax.romanov@nginx.com Unit::create_websocket_frame(napi_value server_obj,
6081132Smax.romanov@nginx.com                              nxt_unit_websocket_frame_t *ws)
609802Salexander.borisov@nginx.com {
6101132Smax.romanov@nginx.com     void        *data;
6111132Smax.romanov@nginx.com     napi_value  constructor, res, buffer;
6121132Smax.romanov@nginx.com     uint8_t     sc[2];
6131132Smax.romanov@nginx.com 
6141132Smax.romanov@nginx.com     constructor = get_named_property(server_obj, "WebSocketFrame");
615802Salexander.borisov@nginx.com 
6161132Smax.romanov@nginx.com     res = new_instance(constructor);
6171132Smax.romanov@nginx.com 
6181132Smax.romanov@nginx.com     set_named_property(res, "fin", (bool) ws->header->fin);
6191132Smax.romanov@nginx.com     set_named_property(res, "opcode", ws->header->opcode);
6201132Smax.romanov@nginx.com     set_named_property(res, "length", (int64_t) ws->payload_len);
621802Salexander.borisov@nginx.com 
6221132Smax.romanov@nginx.com     if (ws->header->opcode == NXT_WEBSOCKET_OP_CLOSE) {
6231132Smax.romanov@nginx.com         if (ws->payload_len >= 2) {
6241132Smax.romanov@nginx.com             nxt_unit_websocket_read(ws, sc, 2);
6251132Smax.romanov@nginx.com 
6261132Smax.romanov@nginx.com             set_named_property(res, "closeStatus",
6271132Smax.romanov@nginx.com                                (((uint16_t) sc[0]) << 8) | sc[1]);
628802Salexander.borisov@nginx.com 
6291132Smax.romanov@nginx.com         } else {
6301132Smax.romanov@nginx.com             set_named_property(res, "closeStatus", -1);
6311132Smax.romanov@nginx.com         }
6321132Smax.romanov@nginx.com     }
633802Salexander.borisov@nginx.com 
6341132Smax.romanov@nginx.com     buffer = create_buffer((size_t) ws->content_length, &data);
6351132Smax.romanov@nginx.com     nxt_unit_websocket_read(ws, data, ws->content_length);
6361132Smax.romanov@nginx.com 
6371132Smax.romanov@nginx.com     set_named_property(res, "binaryPayload", buffer);
6381132Smax.romanov@nginx.com 
6391132Smax.romanov@nginx.com     return res;
640802Salexander.borisov@nginx.com }
641802Salexander.borisov@nginx.com 
642802Salexander.borisov@nginx.com 
643802Salexander.borisov@nginx.com napi_value
644802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info)
645802Salexander.borisov@nginx.com {
646802Salexander.borisov@nginx.com     int                      ret;
647802Salexander.borisov@nginx.com     char                     *ptr, *name_ptr;
648802Salexander.borisov@nginx.com     bool                     is_array;
649802Salexander.borisov@nginx.com     size_t                   argc, name_len, value_len;
650802Salexander.borisov@nginx.com     uint32_t                 status_code, header_len, keys_len, array_len;
651802Salexander.borisov@nginx.com     uint32_t                 keys_count, i, j;
652802Salexander.borisov@nginx.com     uint16_t                 hash;
6531020Smax.romanov@nginx.com     nxt_napi                 napi(env);
654802Salexander.borisov@nginx.com     napi_value               this_arg, headers, keys, name, value, array_val;
6551132Smax.romanov@nginx.com     napi_value               array_entry;
656843Salexander.borisov@nginx.com     napi_valuetype           val_type;
657802Salexander.borisov@nginx.com     nxt_unit_field_t         *f;
658802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
6591132Smax.romanov@nginx.com     napi_value               argv[4];
660802Salexander.borisov@nginx.com 
6611132Smax.romanov@nginx.com     argc = 4;
662802Salexander.borisov@nginx.com 
6631020Smax.romanov@nginx.com     try {
6641020Smax.romanov@nginx.com         this_arg = napi.get_cb_info(info, argc, argv);
6651132Smax.romanov@nginx.com         if (argc != 4) {
6661020Smax.romanov@nginx.com             napi.throw_error("Wrong args count. Expected: "
6671020Smax.romanov@nginx.com                              "statusCode, headers, headers count, "
6681020Smax.romanov@nginx.com                              "headers length");
6691020Smax.romanov@nginx.com             return nullptr;
6701020Smax.romanov@nginx.com         }
671802Salexander.borisov@nginx.com 
6721132Smax.romanov@nginx.com         req = napi.get_request_info(this_arg);
6731132Smax.romanov@nginx.com         status_code = napi.get_value_uint32(argv[0]);
6741132Smax.romanov@nginx.com         keys_count = napi.get_value_uint32(argv[2]);
6751132Smax.romanov@nginx.com         header_len = napi.get_value_uint32(argv[3]);
676802Salexander.borisov@nginx.com 
6771132Smax.romanov@nginx.com         headers = argv[1];
678802Salexander.borisov@nginx.com 
6791020Smax.romanov@nginx.com         ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
6801020Smax.romanov@nginx.com         if (ret != NXT_UNIT_OK) {
6811020Smax.romanov@nginx.com             napi.throw_error("Failed to create response");
6821020Smax.romanov@nginx.com             return nullptr;
683802Salexander.borisov@nginx.com         }
684802Salexander.borisov@nginx.com 
6851257Smax.romanov@nginx.com         /*
6861257Smax.romanov@nginx.com          * Each name and value are 0-terminated by libunit.
6871257Smax.romanov@nginx.com          * Need to add extra 2 bytes for each header.
6881257Smax.romanov@nginx.com          */
6891257Smax.romanov@nginx.com         header_len += keys_count * 2;
6901257Smax.romanov@nginx.com 
6911020Smax.romanov@nginx.com         keys = napi.get_property_names(headers);
6921020Smax.romanov@nginx.com         keys_len = napi.get_array_length(keys);
6931020Smax.romanov@nginx.com 
6941020Smax.romanov@nginx.com         ptr = req->response_buf->free;
695875Salexander.borisov@nginx.com 
6961020Smax.romanov@nginx.com         for (i = 0; i < keys_len; i++) {
6971020Smax.romanov@nginx.com             name = napi.get_element(keys, i);
6981020Smax.romanov@nginx.com 
6991020Smax.romanov@nginx.com             array_entry = napi.get_property(headers, name);
7001020Smax.romanov@nginx.com 
7011020Smax.romanov@nginx.com             name = napi.get_element(array_entry, 0);
7021020Smax.romanov@nginx.com             value = napi.get_element(array_entry, 1);
703875Salexander.borisov@nginx.com 
7041020Smax.romanov@nginx.com             name_len = napi.get_value_string_latin1(name, ptr, header_len);
7051020Smax.romanov@nginx.com             name_ptr = ptr;
7061020Smax.romanov@nginx.com 
7071257Smax.romanov@nginx.com             ptr += name_len + 1;
7081257Smax.romanov@nginx.com             header_len -= name_len + 1;
709802Salexander.borisov@nginx.com 
7101020Smax.romanov@nginx.com             hash = nxt_unit_field_hash(name_ptr, name_len);
7111020Smax.romanov@nginx.com 
7121020Smax.romanov@nginx.com             is_array = napi.is_array(value);
7131020Smax.romanov@nginx.com 
7141020Smax.romanov@nginx.com             if (is_array) {
7151020Smax.romanov@nginx.com                 array_len = napi.get_array_length(value);
716802Salexander.borisov@nginx.com 
7171020Smax.romanov@nginx.com                 for (j = 0; j < array_len; j++) {
7181020Smax.romanov@nginx.com                     array_val = napi.get_element(value, j);
7191020Smax.romanov@nginx.com 
7201020Smax.romanov@nginx.com                     val_type = napi.type_of(array_val);
721802Salexander.borisov@nginx.com 
7221020Smax.romanov@nginx.com                     if (val_type != napi_string) {
7231020Smax.romanov@nginx.com                         array_val = napi.coerce_to_string(array_val);
7241020Smax.romanov@nginx.com                     }
725802Salexander.borisov@nginx.com 
7261020Smax.romanov@nginx.com                     value_len = napi.get_value_string_latin1(array_val, ptr,
7271020Smax.romanov@nginx.com                                                              header_len);
728802Salexander.borisov@nginx.com 
7291020Smax.romanov@nginx.com                     f = req->response->fields + req->response->fields_count;
7301020Smax.romanov@nginx.com                     f->skip = 0;
7311020Smax.romanov@nginx.com 
7321020Smax.romanov@nginx.com                     nxt_unit_sptr_set(&f->name, name_ptr);
7331020Smax.romanov@nginx.com 
7341020Smax.romanov@nginx.com                     f->name_length = name_len;
7351020Smax.romanov@nginx.com                     f->hash = hash;
736802Salexander.borisov@nginx.com 
7371020Smax.romanov@nginx.com                     nxt_unit_sptr_set(&f->value, ptr);
7381020Smax.romanov@nginx.com                     f->value_length = (uint32_t) value_len;
739802Salexander.borisov@nginx.com 
7401257Smax.romanov@nginx.com                     ptr += value_len + 1;
7411257Smax.romanov@nginx.com                     header_len -= value_len + 1;
7421020Smax.romanov@nginx.com 
7431020Smax.romanov@nginx.com                     req->response->fields_count++;
744802Salexander.borisov@nginx.com                 }
745802Salexander.borisov@nginx.com 
7461020Smax.romanov@nginx.com             } else {
7471020Smax.romanov@nginx.com                 val_type = napi.type_of(value);
748843Salexander.borisov@nginx.com 
749843Salexander.borisov@nginx.com                 if (val_type != napi_string) {
7501020Smax.romanov@nginx.com                     value = napi.coerce_to_string(value);
751843Salexander.borisov@nginx.com                 }
752843Salexander.borisov@nginx.com 
7531020Smax.romanov@nginx.com                 value_len = napi.get_value_string_latin1(value, ptr, header_len);
754802Salexander.borisov@nginx.com 
755802Salexander.borisov@nginx.com                 f = req->response->fields + req->response->fields_count;
756802Salexander.borisov@nginx.com                 f->skip = 0;
757802Salexander.borisov@nginx.com 
758802Salexander.borisov@nginx.com                 nxt_unit_sptr_set(&f->name, name_ptr);
759802Salexander.borisov@nginx.com 
760802Salexander.borisov@nginx.com                 f->name_length = name_len;
761802Salexander.borisov@nginx.com                 f->hash = hash;
762802Salexander.borisov@nginx.com 
763802Salexander.borisov@nginx.com                 nxt_unit_sptr_set(&f->value, ptr);
764802Salexander.borisov@nginx.com                 f->value_length = (uint32_t) value_len;
765802Salexander.borisov@nginx.com 
7661257Smax.romanov@nginx.com                 ptr += value_len + 1;
7671257Smax.romanov@nginx.com                 header_len -= value_len + 1;
768802Salexander.borisov@nginx.com 
769802Salexander.borisov@nginx.com                 req->response->fields_count++;
770802Salexander.borisov@nginx.com             }
7711020Smax.romanov@nginx.com         }
772843Salexander.borisov@nginx.com 
7731020Smax.romanov@nginx.com     } catch (exception &e) {
7741020Smax.romanov@nginx.com         napi.throw_error(e);
7751020Smax.romanov@nginx.com         return nullptr;
776802Salexander.borisov@nginx.com     }
777802Salexander.borisov@nginx.com 
778802Salexander.borisov@nginx.com     req->response_buf->free = ptr;
779802Salexander.borisov@nginx.com 
780802Salexander.borisov@nginx.com     ret = nxt_unit_response_send(req);
781802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
7821020Smax.romanov@nginx.com         napi.throw_error("Failed to send response");
7831020Smax.romanov@nginx.com         return nullptr;
784802Salexander.borisov@nginx.com     }
785802Salexander.borisov@nginx.com 
786802Salexander.borisov@nginx.com     return this_arg;
787802Salexander.borisov@nginx.com }
788802Salexander.borisov@nginx.com 
789802Salexander.borisov@nginx.com 
790802Salexander.borisov@nginx.com napi_value
791802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info)
792802Salexander.borisov@nginx.com {
793802Salexander.borisov@nginx.com     int                      ret;
7941132Smax.romanov@nginx.com     void                     *ptr;
795802Salexander.borisov@nginx.com     size_t                   argc, have_buf_len;
7961322Smax.romanov@nginx.com     ssize_t                  res_len;
7971322Smax.romanov@nginx.com     uint32_t                 buf_start, buf_len;
7981020Smax.romanov@nginx.com     nxt_napi                 napi(env);
7991132Smax.romanov@nginx.com     napi_value               this_arg;
800802Salexander.borisov@nginx.com     nxt_unit_buf_t           *buf;
801802Salexander.borisov@nginx.com     napi_valuetype           buf_type;
802802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
8031322Smax.romanov@nginx.com     napi_value               argv[3];
804802Salexander.borisov@nginx.com 
8051322Smax.romanov@nginx.com     argc = 3;
806802Salexander.borisov@nginx.com 
8071020Smax.romanov@nginx.com     try {
8081020Smax.romanov@nginx.com         this_arg = napi.get_cb_info(info, argc, argv);
8091322Smax.romanov@nginx.com         if (argc != 3) {
8101020Smax.romanov@nginx.com             throw exception("Wrong args count. Expected: "
8111322Smax.romanov@nginx.com                             "chunk, start, length");
8121020Smax.romanov@nginx.com         }
813802Salexander.borisov@nginx.com 
8141132Smax.romanov@nginx.com         req = napi.get_request_info(this_arg);
8151132Smax.romanov@nginx.com         buf_type = napi.type_of(argv[0]);
8161322Smax.romanov@nginx.com         buf_start = napi.get_value_uint32(argv[1]);
8171322Smax.romanov@nginx.com         buf_len = napi.get_value_uint32(argv[2]) + 1;
8181132Smax.romanov@nginx.com 
8191132Smax.romanov@nginx.com         if (buf_type == napi_string) {
8201132Smax.romanov@nginx.com             /* TODO: will work only for utf8 content-type */
821802Salexander.borisov@nginx.com 
8221322Smax.romanov@nginx.com             if (req->response_buf != NULL
8231373Smax.romanov@nginx.com                 && req->response_buf->end >= req->response_buf->free + buf_len)
8241322Smax.romanov@nginx.com             {
8251322Smax.romanov@nginx.com                 buf = req->response_buf;
8261322Smax.romanov@nginx.com 
8271322Smax.romanov@nginx.com             } else {
8281322Smax.romanov@nginx.com                 buf = nxt_unit_response_buf_alloc(req, buf_len);
8291322Smax.romanov@nginx.com                 if (buf == NULL) {
8301322Smax.romanov@nginx.com                     throw exception("Failed to allocate response buffer");
8311322Smax.romanov@nginx.com                 }
8321322Smax.romanov@nginx.com             }
8331322Smax.romanov@nginx.com 
8341132Smax.romanov@nginx.com             have_buf_len = napi.get_value_string_utf8(argv[0], buf->free,
8351132Smax.romanov@nginx.com                                                       buf_len);
8361132Smax.romanov@nginx.com 
8371322Smax.romanov@nginx.com             buf->free += have_buf_len;
8381322Smax.romanov@nginx.com 
8391322Smax.romanov@nginx.com             ret = nxt_unit_buf_send(buf);
8401322Smax.romanov@nginx.com             if (ret == NXT_UNIT_OK) {
8411322Smax.romanov@nginx.com                 res_len = have_buf_len;
8421322Smax.romanov@nginx.com             }
8431322Smax.romanov@nginx.com 
8441132Smax.romanov@nginx.com         } else {
8451132Smax.romanov@nginx.com             ptr = napi.get_buffer_info(argv[0], have_buf_len);
846802Salexander.borisov@nginx.com 
8471322Smax.romanov@nginx.com             if (buf_start > 0) {
8481322Smax.romanov@nginx.com                 ptr = ((uint8_t *) ptr) + buf_start;
8491322Smax.romanov@nginx.com                 have_buf_len -= buf_start;
8501322Smax.romanov@nginx.com             }
8511322Smax.romanov@nginx.com 
8521322Smax.romanov@nginx.com             res_len = nxt_unit_response_write_nb(req, ptr, have_buf_len, 0);
8531322Smax.romanov@nginx.com 
8541342Smax.romanov@nginx.com             ret = res_len < 0 ? -res_len : (int) NXT_UNIT_OK;
8551132Smax.romanov@nginx.com         }
8561132Smax.romanov@nginx.com 
8571132Smax.romanov@nginx.com         if (ret != NXT_UNIT_OK) {
8581132Smax.romanov@nginx.com             throw exception("Failed to send body buf");
8591132Smax.romanov@nginx.com         }
8601020Smax.romanov@nginx.com     } catch (exception &e) {
8611020Smax.romanov@nginx.com         napi.throw_error(e);
8621020Smax.romanov@nginx.com         return nullptr;
863802Salexander.borisov@nginx.com     }
864802Salexander.borisov@nginx.com 
8651322Smax.romanov@nginx.com     return napi.create((int64_t) res_len);
866802Salexander.borisov@nginx.com }
867802Salexander.borisov@nginx.com 
868802Salexander.borisov@nginx.com 
869802Salexander.borisov@nginx.com napi_value
870802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info)
871802Salexander.borisov@nginx.com {
8721020Smax.romanov@nginx.com     nxt_napi                 napi(env);
8731132Smax.romanov@nginx.com     napi_value               this_arg;
8741132Smax.romanov@nginx.com     req_data_t               *req_data;
875802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
876802Salexander.borisov@nginx.com 
8771132Smax.romanov@nginx.com     try {
8781132Smax.romanov@nginx.com         this_arg = napi.get_cb_info(info);
8791132Smax.romanov@nginx.com 
8801132Smax.romanov@nginx.com         req = napi.get_request_info(this_arg);
881802Salexander.borisov@nginx.com 
8821132Smax.romanov@nginx.com         req_data = (req_data_t *) req->data;
8831020Smax.romanov@nginx.com 
8841132Smax.romanov@nginx.com         napi.remove_wrap(req_data->sock_ref);
8851132Smax.romanov@nginx.com         napi.remove_wrap(req_data->resp_ref);
8861132Smax.romanov@nginx.com         napi.remove_wrap(req_data->conn_ref);
8871020Smax.romanov@nginx.com 
8881020Smax.romanov@nginx.com     } catch (exception &e) {
8891020Smax.romanov@nginx.com         napi.throw_error(e);
890802Salexander.borisov@nginx.com         return nullptr;
891802Salexander.borisov@nginx.com     }
892802Salexander.borisov@nginx.com 
893802Salexander.borisov@nginx.com     nxt_unit_request_done(req, NXT_UNIT_OK);
894802Salexander.borisov@nginx.com 
895802Salexander.borisov@nginx.com     return this_arg;
896802Salexander.borisov@nginx.com }
8971132Smax.romanov@nginx.com 
8981132Smax.romanov@nginx.com 
8991132Smax.romanov@nginx.com napi_value
9001132Smax.romanov@nginx.com Unit::websocket_send_frame(napi_env env, napi_callback_info info)
9011132Smax.romanov@nginx.com {
9021132Smax.romanov@nginx.com     int                      ret, iovec_len;
9031132Smax.romanov@nginx.com     bool                     fin;
9041132Smax.romanov@nginx.com     size_t                   buf_len;
9051132Smax.romanov@nginx.com     uint32_t                 opcode, sc;
9061132Smax.romanov@nginx.com     nxt_napi                 napi(env);
9071132Smax.romanov@nginx.com     napi_value               this_arg, frame, payload;
9081132Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
9091132Smax.romanov@nginx.com     char                     status_code[2];
9101132Smax.romanov@nginx.com     struct iovec             iov[2];
9111132Smax.romanov@nginx.com 
9121132Smax.romanov@nginx.com     iovec_len = 0;
9131132Smax.romanov@nginx.com 
9141132Smax.romanov@nginx.com     try {
9151132Smax.romanov@nginx.com         this_arg = napi.get_cb_info(info, frame);
9161132Smax.romanov@nginx.com 
9171132Smax.romanov@nginx.com         req = napi.get_request_info(this_arg);
9181132Smax.romanov@nginx.com 
9191132Smax.romanov@nginx.com         opcode = napi.get_value_uint32(napi.get_named_property(frame,
9201132Smax.romanov@nginx.com                                                                "opcode"));
9211132Smax.romanov@nginx.com         if (opcode == NXT_WEBSOCKET_OP_CLOSE) {
9221132Smax.romanov@nginx.com             sc = napi.get_value_uint32(napi.get_named_property(frame,
9231132Smax.romanov@nginx.com                                                                "closeStatus"));
9241132Smax.romanov@nginx.com             status_code[0] = (sc >> 8) & 0xFF;
9251132Smax.romanov@nginx.com             status_code[1] = sc & 0xFF;
9261132Smax.romanov@nginx.com 
9271132Smax.romanov@nginx.com             iov[iovec_len].iov_base = status_code;
9281132Smax.romanov@nginx.com             iov[iovec_len].iov_len = 2;
9291132Smax.romanov@nginx.com             iovec_len++;
9301132Smax.romanov@nginx.com         }
9311132Smax.romanov@nginx.com 
9321132Smax.romanov@nginx.com         try {
9331132Smax.romanov@nginx.com             fin = napi.get_value_bool(napi.get_named_property(frame, "fin"));
9341132Smax.romanov@nginx.com 
9351132Smax.romanov@nginx.com         } catch (exception &e) {
9361132Smax.romanov@nginx.com             fin = true;
9371132Smax.romanov@nginx.com         }
9381132Smax.romanov@nginx.com 
9391132Smax.romanov@nginx.com         payload = napi.get_named_property(frame, "binaryPayload");
9401132Smax.romanov@nginx.com 
9411132Smax.romanov@nginx.com         if (napi.is_buffer(payload)) {
9421132Smax.romanov@nginx.com             iov[iovec_len].iov_base = napi.get_buffer_info(payload, buf_len);
9431132Smax.romanov@nginx.com 
9441132Smax.romanov@nginx.com         } else {
9451132Smax.romanov@nginx.com             buf_len = 0;
9461132Smax.romanov@nginx.com         }
9471132Smax.romanov@nginx.com 
9481132Smax.romanov@nginx.com     } catch (exception &e) {
9491132Smax.romanov@nginx.com         napi.throw_error(e);
9501132Smax.romanov@nginx.com         return nullptr;
9511132Smax.romanov@nginx.com     }
9521132Smax.romanov@nginx.com 
9531132Smax.romanov@nginx.com     if (buf_len > 0) {
9541132Smax.romanov@nginx.com         iov[iovec_len].iov_len = buf_len;
9551132Smax.romanov@nginx.com         iovec_len++;
9561132Smax.romanov@nginx.com     }
9571132Smax.romanov@nginx.com 
9581132Smax.romanov@nginx.com     ret = nxt_unit_websocket_sendv(req, opcode, fin ? 1 : 0, iov, iovec_len);
9591132Smax.romanov@nginx.com     if (ret != NXT_UNIT_OK) {
9601132Smax.romanov@nginx.com         goto failed;
9611132Smax.romanov@nginx.com     }
9621132Smax.romanov@nginx.com 
9631132Smax.romanov@nginx.com     return this_arg;
9641132Smax.romanov@nginx.com 
9651132Smax.romanov@nginx.com failed:
9661132Smax.romanov@nginx.com 
9671132Smax.romanov@nginx.com     napi.throw_error("Failed to send frame");
9681132Smax.romanov@nginx.com 
9691132Smax.romanov@nginx.com     return nullptr;
9701132Smax.romanov@nginx.com }
9711132Smax.romanov@nginx.com 
9721132Smax.romanov@nginx.com 
9731132Smax.romanov@nginx.com napi_value
9741132Smax.romanov@nginx.com Unit::websocket_set_sock(napi_env env, napi_callback_info info)
9751132Smax.romanov@nginx.com {
9761132Smax.romanov@nginx.com     nxt_napi                 napi(env);
9771132Smax.romanov@nginx.com     napi_value               this_arg, sock;
9781132Smax.romanov@nginx.com     req_data_t               *req_data;
9791132Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
9801132Smax.romanov@nginx.com 
9811132Smax.romanov@nginx.com     try {
9821132Smax.romanov@nginx.com         this_arg = napi.get_cb_info(info, sock);
9831132Smax.romanov@nginx.com 
9841132Smax.romanov@nginx.com         req = napi.get_request_info(sock);
9851132Smax.romanov@nginx.com 
9861132Smax.romanov@nginx.com         req_data = (req_data_t *) req->data;
9871132Smax.romanov@nginx.com         req_data->conn_ref = napi.wrap(this_arg, req, conn_destroy);
9881132Smax.romanov@nginx.com 
9891132Smax.romanov@nginx.com     } catch (exception &e) {
9901132Smax.romanov@nginx.com         napi.throw_error(e);
9911132Smax.romanov@nginx.com         return nullptr;
9921132Smax.romanov@nginx.com     }
9931132Smax.romanov@nginx.com 
9941132Smax.romanov@nginx.com     return this_arg;
9951132Smax.romanov@nginx.com }
9961132Smax.romanov@nginx.com 
9971132Smax.romanov@nginx.com 
9981132Smax.romanov@nginx.com void
9991132Smax.romanov@nginx.com Unit::conn_destroy(napi_env env, void *nativeObject, void *finalize_hint)
10001132Smax.romanov@nginx.com {
10011132Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
10021132Smax.romanov@nginx.com 
10031132Smax.romanov@nginx.com     req = (nxt_unit_request_info_t *) nativeObject;
10041132Smax.romanov@nginx.com 
10051132Smax.romanov@nginx.com     nxt_unit_warn(NULL, "conn_destroy: %p", req);
10061132Smax.romanov@nginx.com }
10071132Smax.romanov@nginx.com 
10081132Smax.romanov@nginx.com 
10091132Smax.romanov@nginx.com void
10101132Smax.romanov@nginx.com Unit::sock_destroy(napi_env env, void *nativeObject, void *finalize_hint)
10111132Smax.romanov@nginx.com {
10121132Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
10131132Smax.romanov@nginx.com 
10141132Smax.romanov@nginx.com     req = (nxt_unit_request_info_t *) nativeObject;
10151132Smax.romanov@nginx.com 
10161132Smax.romanov@nginx.com     nxt_unit_warn(NULL, "sock_destroy: %p", req);
10171132Smax.romanov@nginx.com }
10181132Smax.romanov@nginx.com 
10191132Smax.romanov@nginx.com 
10201132Smax.romanov@nginx.com void
10211132Smax.romanov@nginx.com Unit::resp_destroy(napi_env env, void *nativeObject, void *finalize_hint)
10221132Smax.romanov@nginx.com {
10231132Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
10241132Smax.romanov@nginx.com 
10251132Smax.romanov@nginx.com     req = (nxt_unit_request_info_t *) nativeObject;
10261132Smax.romanov@nginx.com 
10271132Smax.romanov@nginx.com     nxt_unit_warn(NULL, "resp_destroy: %p", req);
10281132Smax.romanov@nginx.com }
1029