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