xref: /unit/src/nodejs/unit-http/unit.cpp (revision 841)
1802Salexander.borisov@nginx.com 
2802Salexander.borisov@nginx.com /*
3802Salexander.borisov@nginx.com  * Copyright (C) NGINX, Inc.
4802Salexander.borisov@nginx.com  */
5802Salexander.borisov@nginx.com 
6802Salexander.borisov@nginx.com #include "unit.h"
7802Salexander.borisov@nginx.com 
8828Salexander.borisov@nginx.com #include <unistd.h>
9828Salexander.borisov@nginx.com #include <fcntl.h>
10828Salexander.borisov@nginx.com 
11828Salexander.borisov@nginx.com #include <uv.h>
12828Salexander.borisov@nginx.com 
13802Salexander.borisov@nginx.com 
14802Salexander.borisov@nginx.com napi_ref Unit::constructor_;
15802Salexander.borisov@nginx.com 
16802Salexander.borisov@nginx.com 
17802Salexander.borisov@nginx.com Unit::Unit(napi_env env):
18802Salexander.borisov@nginx.com     env_(env),
19802Salexander.borisov@nginx.com     wrapper_(nullptr),
20802Salexander.borisov@nginx.com     unit_ctx_(nullptr)
21802Salexander.borisov@nginx.com {
22802Salexander.borisov@nginx.com }
23802Salexander.borisov@nginx.com 
24802Salexander.borisov@nginx.com 
25802Salexander.borisov@nginx.com Unit::~Unit()
26802Salexander.borisov@nginx.com {
27802Salexander.borisov@nginx.com     napi_delete_reference(env_, wrapper_);
28802Salexander.borisov@nginx.com }
29802Salexander.borisov@nginx.com 
30802Salexander.borisov@nginx.com 
31802Salexander.borisov@nginx.com napi_value
32802Salexander.borisov@nginx.com Unit::init(napi_env env, napi_value exports)
33802Salexander.borisov@nginx.com {
34802Salexander.borisov@nginx.com     napi_value   cons, fn;
35802Salexander.borisov@nginx.com     napi_status  status;
36802Salexander.borisov@nginx.com 
37802Salexander.borisov@nginx.com     napi_property_descriptor  properties[] = {
38802Salexander.borisov@nginx.com         { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 },
39828Salexander.borisov@nginx.com         { "listen", 0, listen, 0, 0, 0, napi_default, 0 },
40828Salexander.borisov@nginx.com         { "_read", 0, _read, 0, 0, 0, napi_default, 0 }
41802Salexander.borisov@nginx.com     };
42802Salexander.borisov@nginx.com 
43802Salexander.borisov@nginx.com     status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr,
44828Salexander.borisov@nginx.com                                3, properties, &cons);
45802Salexander.borisov@nginx.com     if (status != napi_ok) {
46802Salexander.borisov@nginx.com         goto failed;
47802Salexander.borisov@nginx.com     }
48802Salexander.borisov@nginx.com 
49802Salexander.borisov@nginx.com     status = napi_create_reference(env, cons, 1, &constructor_);
50802Salexander.borisov@nginx.com     if (status != napi_ok) {
51802Salexander.borisov@nginx.com         goto failed;
52802Salexander.borisov@nginx.com     }
53802Salexander.borisov@nginx.com 
54802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "Unit", cons);
55802Salexander.borisov@nginx.com     if (status != napi_ok) {
56802Salexander.borisov@nginx.com         goto failed;
57802Salexander.borisov@nginx.com     }
58802Salexander.borisov@nginx.com 
59802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_send_headers, NULL,
60802Salexander.borisov@nginx.com                                   &fn);
61802Salexander.borisov@nginx.com     if (status != napi_ok) {
62802Salexander.borisov@nginx.com         goto failed;
63802Salexander.borisov@nginx.com     }
64802Salexander.borisov@nginx.com 
65802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports,
66802Salexander.borisov@nginx.com                                      "unit_response_headers", fn);
67802Salexander.borisov@nginx.com     if (status != napi_ok) {
68802Salexander.borisov@nginx.com         goto failed;
69802Salexander.borisov@nginx.com     }
70802Salexander.borisov@nginx.com 
71802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_write, NULL, &fn);
72802Salexander.borisov@nginx.com     if (status != napi_ok) {
73802Salexander.borisov@nginx.com         goto failed;
74802Salexander.borisov@nginx.com     }
75802Salexander.borisov@nginx.com 
76802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "unit_response_write", fn);
77802Salexander.borisov@nginx.com     if (status != napi_ok) {
78802Salexander.borisov@nginx.com         goto failed;
79802Salexander.borisov@nginx.com     }
80802Salexander.borisov@nginx.com 
81802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_end, NULL, &fn);
82802Salexander.borisov@nginx.com     if (status != napi_ok) {
83802Salexander.borisov@nginx.com         goto failed;
84802Salexander.borisov@nginx.com     }
85802Salexander.borisov@nginx.com 
86802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "unit_response_end", fn);
87802Salexander.borisov@nginx.com     if (status != napi_ok) {
88802Salexander.borisov@nginx.com         goto failed;
89802Salexander.borisov@nginx.com     }
90802Salexander.borisov@nginx.com 
91802Salexander.borisov@nginx.com     return exports;
92802Salexander.borisov@nginx.com 
93802Salexander.borisov@nginx.com failed:
94802Salexander.borisov@nginx.com 
95802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to define Unit class");
96802Salexander.borisov@nginx.com 
97802Salexander.borisov@nginx.com     return nullptr;
98802Salexander.borisov@nginx.com }
99802Salexander.borisov@nginx.com 
100802Salexander.borisov@nginx.com 
101802Salexander.borisov@nginx.com void
102802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint)
103802Salexander.borisov@nginx.com {
104802Salexander.borisov@nginx.com     Unit  *obj = reinterpret_cast<Unit *>(nativeObject);
105802Salexander.borisov@nginx.com 
106802Salexander.borisov@nginx.com     delete obj;
107802Salexander.borisov@nginx.com }
108802Salexander.borisov@nginx.com 
109802Salexander.borisov@nginx.com 
110802Salexander.borisov@nginx.com napi_value
111802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info)
112802Salexander.borisov@nginx.com {
113802Salexander.borisov@nginx.com     Unit         *obj;
114*841Salexander.borisov@nginx.com     napi_ref     ref;
115802Salexander.borisov@nginx.com     napi_value   target, cons, instance, jsthis;
116802Salexander.borisov@nginx.com     napi_status  status;
117802Salexander.borisov@nginx.com 
118802Salexander.borisov@nginx.com     status = napi_get_new_target(env, info, &target);
119802Salexander.borisov@nginx.com     if (status != napi_ok) {
120802Salexander.borisov@nginx.com         goto failed;
121802Salexander.borisov@nginx.com     }
122802Salexander.borisov@nginx.com 
123802Salexander.borisov@nginx.com     if (target != nullptr) {
124802Salexander.borisov@nginx.com         /* Invoked as constructor: `new Unit(...)` */
125802Salexander.borisov@nginx.com         status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis,
126802Salexander.borisov@nginx.com                                   nullptr);
127802Salexander.borisov@nginx.com         if (status != napi_ok) {
128802Salexander.borisov@nginx.com             goto failed;
129802Salexander.borisov@nginx.com         }
130802Salexander.borisov@nginx.com 
131802Salexander.borisov@nginx.com         obj = new Unit(env);
132802Salexander.borisov@nginx.com 
133802Salexander.borisov@nginx.com         status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj),
134802Salexander.borisov@nginx.com                            destroy, nullptr, &obj->wrapper_);
135802Salexander.borisov@nginx.com         if (status != napi_ok) {
136802Salexander.borisov@nginx.com             goto failed;
137802Salexander.borisov@nginx.com         }
138802Salexander.borisov@nginx.com 
139*841Salexander.borisov@nginx.com         status = napi_create_reference(env, jsthis, 1, &ref);
140*841Salexander.borisov@nginx.com         if (status != napi_ok) {
141*841Salexander.borisov@nginx.com             goto failed;
142*841Salexander.borisov@nginx.com         }
143*841Salexander.borisov@nginx.com 
144802Salexander.borisov@nginx.com         return jsthis;
145802Salexander.borisov@nginx.com     }
146802Salexander.borisov@nginx.com 
147802Salexander.borisov@nginx.com     /* Invoked as plain function `Unit(...)`, turn into construct call. */
148802Salexander.borisov@nginx.com     status = napi_get_reference_value(env, constructor_, &cons);
149802Salexander.borisov@nginx.com     if (status != napi_ok) {
150802Salexander.borisov@nginx.com         goto failed;
151802Salexander.borisov@nginx.com     }
152802Salexander.borisov@nginx.com 
153802Salexander.borisov@nginx.com     status = napi_new_instance(env, cons, 0, nullptr, &instance);
154802Salexander.borisov@nginx.com     if (status != napi_ok) {
155802Salexander.borisov@nginx.com         goto failed;
156802Salexander.borisov@nginx.com     }
157802Salexander.borisov@nginx.com 
158*841Salexander.borisov@nginx.com     status = napi_create_reference(env, instance, 1, &ref);
159*841Salexander.borisov@nginx.com     if (status != napi_ok) {
160*841Salexander.borisov@nginx.com         goto failed;
161*841Salexander.borisov@nginx.com     }
162*841Salexander.borisov@nginx.com 
163802Salexander.borisov@nginx.com     return instance;
164802Salexander.borisov@nginx.com 
165802Salexander.borisov@nginx.com failed:
166802Salexander.borisov@nginx.com 
167802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to create Unit object");
168802Salexander.borisov@nginx.com 
169802Salexander.borisov@nginx.com     return nullptr;
170802Salexander.borisov@nginx.com }
171802Salexander.borisov@nginx.com 
172802Salexander.borisov@nginx.com 
173802Salexander.borisov@nginx.com napi_value
174802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info)
175802Salexander.borisov@nginx.com {
176802Salexander.borisov@nginx.com     Unit             *obj;
177802Salexander.borisov@nginx.com     size_t           argc;
178828Salexander.borisov@nginx.com     napi_value       jsthis, argv;
179802Salexander.borisov@nginx.com     napi_status      status;
180802Salexander.borisov@nginx.com     nxt_unit_init_t  unit_init;
181802Salexander.borisov@nginx.com 
182802Salexander.borisov@nginx.com     argc = 1;
183802Salexander.borisov@nginx.com 
184828Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
185802Salexander.borisov@nginx.com     if (status != napi_ok) {
186802Salexander.borisov@nginx.com         goto failed;
187802Salexander.borisov@nginx.com     }
188802Salexander.borisov@nginx.com 
189802Salexander.borisov@nginx.com     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
190802Salexander.borisov@nginx.com     if (status != napi_ok) {
191802Salexander.borisov@nginx.com         goto failed;
192802Salexander.borisov@nginx.com     }
193802Salexander.borisov@nginx.com 
194802Salexander.borisov@nginx.com     memset(&unit_init, 0, sizeof(nxt_unit_init_t));
195802Salexander.borisov@nginx.com 
196802Salexander.borisov@nginx.com     unit_init.data = obj;
197802Salexander.borisov@nginx.com     unit_init.callbacks.request_handler = request_handler;
198828Salexander.borisov@nginx.com     unit_init.callbacks.add_port        = add_port;
199828Salexander.borisov@nginx.com     unit_init.callbacks.remove_port     = remove_port;
200802Salexander.borisov@nginx.com 
201802Salexander.borisov@nginx.com     obj->unit_ctx_ = nxt_unit_init(&unit_init);
202802Salexander.borisov@nginx.com     if (obj->unit_ctx_ == NULL) {
203802Salexander.borisov@nginx.com         goto failed;
204802Salexander.borisov@nginx.com     }
205802Salexander.borisov@nginx.com 
206802Salexander.borisov@nginx.com     return nullptr;
207802Salexander.borisov@nginx.com 
208802Salexander.borisov@nginx.com failed:
209802Salexander.borisov@nginx.com 
210802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to create Unit object");
211802Salexander.borisov@nginx.com 
212802Salexander.borisov@nginx.com     return nullptr;
213802Salexander.borisov@nginx.com }
214802Salexander.borisov@nginx.com 
215802Salexander.borisov@nginx.com 
216802Salexander.borisov@nginx.com napi_value
217802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info)
218802Salexander.borisov@nginx.com {
219828Salexander.borisov@nginx.com     return nullptr;
220828Salexander.borisov@nginx.com }
221828Salexander.borisov@nginx.com 
222802Salexander.borisov@nginx.com 
223828Salexander.borisov@nginx.com napi_value
224828Salexander.borisov@nginx.com Unit::_read(napi_env env, napi_callback_info info)
225828Salexander.borisov@nginx.com {
226828Salexander.borisov@nginx.com     Unit                     *obj;
227828Salexander.borisov@nginx.com     void                     *data;
228828Salexander.borisov@nginx.com     size_t                   argc;
229828Salexander.borisov@nginx.com     int64_t                  req_pointer;
230828Salexander.borisov@nginx.com     napi_value               jsthis, buffer, argv;
231828Salexander.borisov@nginx.com     napi_status              status;
232828Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
233828Salexander.borisov@nginx.com 
234828Salexander.borisov@nginx.com     argc = 1;
235828Salexander.borisov@nginx.com 
236828Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
237802Salexander.borisov@nginx.com     if (status != napi_ok) {
238828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get arguments from js");
239828Salexander.borisov@nginx.com         return nullptr;
240802Salexander.borisov@nginx.com     }
241802Salexander.borisov@nginx.com 
242802Salexander.borisov@nginx.com     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
243802Salexander.borisov@nginx.com     if (status != napi_ok) {
244828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get Unit object form js");
245828Salexander.borisov@nginx.com         return nullptr;
246802Salexander.borisov@nginx.com     }
247802Salexander.borisov@nginx.com 
248828Salexander.borisov@nginx.com     status = napi_get_value_int64(env, argv, &req_pointer);
249828Salexander.borisov@nginx.com     if (status != napi_ok) {
250828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
251802Salexander.borisov@nginx.com         return nullptr;
252802Salexander.borisov@nginx.com     }
253802Salexander.borisov@nginx.com 
254828Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer;
255828Salexander.borisov@nginx.com 
256828Salexander.borisov@nginx.com     status = napi_create_buffer(env, (size_t) req->content_length,
257828Salexander.borisov@nginx.com                                 &data, &buffer);
258828Salexander.borisov@nginx.com     if (status != napi_ok) {
259828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to create request buffer");
260802Salexander.borisov@nginx.com         return nullptr;
261802Salexander.borisov@nginx.com     }
262802Salexander.borisov@nginx.com 
263828Salexander.borisov@nginx.com     nxt_unit_request_read(req, data, req->content_length);
264802Salexander.borisov@nginx.com 
265828Salexander.borisov@nginx.com     return buffer;
266802Salexander.borisov@nginx.com }
267802Salexander.borisov@nginx.com 
268802Salexander.borisov@nginx.com 
269802Salexander.borisov@nginx.com void
270802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req)
271802Salexander.borisov@nginx.com {
272802Salexander.borisov@nginx.com     Unit         *obj;
273802Salexander.borisov@nginx.com     napi_value   socket, request, response;
274802Salexander.borisov@nginx.com     napi_value   global, server_obj;
275828Salexander.borisov@nginx.com     napi_value   run_events, events_res;
276802Salexander.borisov@nginx.com     napi_status  status;
277828Salexander.borisov@nginx.com     napi_value   events_args[3];
278802Salexander.borisov@nginx.com 
279802Salexander.borisov@nginx.com     obj = reinterpret_cast<Unit *>(req->unit->data);
280802Salexander.borisov@nginx.com 
281802Salexander.borisov@nginx.com     napi_handle_scope scope;
282802Salexander.borisov@nginx.com     status = napi_open_handle_scope(obj->env_, &scope);
283802Salexander.borisov@nginx.com     if (status != napi_ok) {
284802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create handle scope");
285802Salexander.borisov@nginx.com         return;
286802Salexander.borisov@nginx.com     }
287802Salexander.borisov@nginx.com 
288802Salexander.borisov@nginx.com     server_obj = obj->get_server_object();
289802Salexander.borisov@nginx.com     if (server_obj == nullptr) {
290802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get server object");
291802Salexander.borisov@nginx.com         return;
292802Salexander.borisov@nginx.com     }
293802Salexander.borisov@nginx.com 
294802Salexander.borisov@nginx.com     status = napi_get_global(obj->env_, &global);
295802Salexander.borisov@nginx.com     if (status != napi_ok) {
296802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get global variable");
297802Salexander.borisov@nginx.com         return;
298802Salexander.borisov@nginx.com     }
299802Salexander.borisov@nginx.com 
300802Salexander.borisov@nginx.com     socket = obj->create_socket(server_obj, req);
301802Salexander.borisov@nginx.com     if (socket == nullptr) {
302802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create socket object");
303802Salexander.borisov@nginx.com         return;
304802Salexander.borisov@nginx.com     }
305802Salexander.borisov@nginx.com 
306802Salexander.borisov@nginx.com     request = obj->create_request(server_obj, socket);
307802Salexander.borisov@nginx.com     if (request == nullptr) {
308802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create request object");
309802Salexander.borisov@nginx.com         return;
310802Salexander.borisov@nginx.com     }
311802Salexander.borisov@nginx.com 
312802Salexander.borisov@nginx.com     response = obj->create_response(server_obj, socket, request, req, obj);
313802Salexander.borisov@nginx.com     if (response == nullptr) {
314802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create response object");
315802Salexander.borisov@nginx.com         return;
316802Salexander.borisov@nginx.com     }
317802Salexander.borisov@nginx.com 
318802Salexander.borisov@nginx.com     status = obj->create_headers(req, request);
319802Salexander.borisov@nginx.com     if (status != napi_ok) {
320802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create headers");
321802Salexander.borisov@nginx.com         return;
322802Salexander.borisov@nginx.com     }
323802Salexander.borisov@nginx.com 
324828Salexander.borisov@nginx.com     status = napi_get_named_property(obj->env_, server_obj, "run_events",
325828Salexander.borisov@nginx.com                                      &run_events);
326828Salexander.borisov@nginx.com     if (status != napi_ok) {
327828Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get"
328828Salexander.borisov@nginx.com                          " 'run_events' function");
329828Salexander.borisov@nginx.com         return;
330828Salexander.borisov@nginx.com     }
331828Salexander.borisov@nginx.com 
332828Salexander.borisov@nginx.com     events_args[0] = server_obj;
333828Salexander.borisov@nginx.com     events_args[1] = request;
334828Salexander.borisov@nginx.com     events_args[2] = response;
335828Salexander.borisov@nginx.com 
336828Salexander.borisov@nginx.com     status = napi_call_function(obj->env_, server_obj, run_events, 3,
337828Salexander.borisov@nginx.com                                 events_args, &events_res);
338828Salexander.borisov@nginx.com     if (status != napi_ok) {
339828Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to call"
340828Salexander.borisov@nginx.com                          " 'run_events' function");
341828Salexander.borisov@nginx.com         return;
342828Salexander.borisov@nginx.com     }
343802Salexander.borisov@nginx.com 
344802Salexander.borisov@nginx.com     napi_close_handle_scope(obj->env_, scope);
345802Salexander.borisov@nginx.com }
346802Salexander.borisov@nginx.com 
347802Salexander.borisov@nginx.com 
348828Salexander.borisov@nginx.com void
349828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events)
350828Salexander.borisov@nginx.com {
351828Salexander.borisov@nginx.com     nxt_unit_run_once((nxt_unit_ctx_t *) handle->data);
352828Salexander.borisov@nginx.com }
353828Salexander.borisov@nginx.com 
354828Salexander.borisov@nginx.com 
355828Salexander.borisov@nginx.com int
356828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
357828Salexander.borisov@nginx.com {
358828Salexander.borisov@nginx.com     int          err;
359828Salexander.borisov@nginx.com     Unit         *obj;
360828Salexander.borisov@nginx.com     uv_loop_t    *loop;
361828Salexander.borisov@nginx.com     uv_poll_t    *uv_handle;
362828Salexander.borisov@nginx.com     napi_status  status;
363828Salexander.borisov@nginx.com 
364828Salexander.borisov@nginx.com     if (port->in_fd != -1) {
365828Salexander.borisov@nginx.com         obj = reinterpret_cast<Unit *>(ctx->unit->data);
366828Salexander.borisov@nginx.com 
367828Salexander.borisov@nginx.com         if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) {
368828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to upgrade read"
369828Salexander.borisov@nginx.com                              " file descriptor to O_NONBLOCK");
370828Salexander.borisov@nginx.com             return -1;
371828Salexander.borisov@nginx.com         }
372828Salexander.borisov@nginx.com 
373828Salexander.borisov@nginx.com         status = napi_get_uv_event_loop(obj->env_, &loop);
374828Salexander.borisov@nginx.com         if (status != napi_ok) {
375828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to get uv.loop");
376828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
377828Salexander.borisov@nginx.com         }
378828Salexander.borisov@nginx.com 
379828Salexander.borisov@nginx.com         uv_handle = new uv_poll_t;
380828Salexander.borisov@nginx.com 
381828Salexander.borisov@nginx.com         err = uv_poll_init(loop, uv_handle, port->in_fd);
382828Salexander.borisov@nginx.com         if (err < 0) {
383828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to init uv.poll");
384828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
385828Salexander.borisov@nginx.com         }
386828Salexander.borisov@nginx.com 
387828Salexander.borisov@nginx.com         err = uv_poll_start(uv_handle, UV_READABLE, nxt_uv_read_callback);
388828Salexander.borisov@nginx.com         if (err < 0) {
389828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to start uv.poll");
390828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
391828Salexander.borisov@nginx.com         }
392828Salexander.borisov@nginx.com 
393828Salexander.borisov@nginx.com         port->data = uv_handle;
394828Salexander.borisov@nginx.com         uv_handle->data = ctx;
395828Salexander.borisov@nginx.com     }
396828Salexander.borisov@nginx.com 
397828Salexander.borisov@nginx.com     return nxt_unit_add_port(ctx, port);
398828Salexander.borisov@nginx.com }
399828Salexander.borisov@nginx.com 
400828Salexander.borisov@nginx.com 
401828Salexander.borisov@nginx.com void
402828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id)
403828Salexander.borisov@nginx.com {
404828Salexander.borisov@nginx.com     nxt_unit_port_t  *port;
405828Salexander.borisov@nginx.com 
406828Salexander.borisov@nginx.com     port = nxt_unit_find_port(ctx, port_id);
407828Salexander.borisov@nginx.com     if (port == NULL) {
408828Salexander.borisov@nginx.com         return;
409828Salexander.borisov@nginx.com     }
410828Salexander.borisov@nginx.com 
411828Salexander.borisov@nginx.com     if (port->in_fd != -1 && port->data != NULL) {
412828Salexander.borisov@nginx.com         uv_poll_stop((uv_poll_t *) port->data);
413828Salexander.borisov@nginx.com 
414828Salexander.borisov@nginx.com         delete (uv_poll_t *) port->data;
415828Salexander.borisov@nginx.com     }
416828Salexander.borisov@nginx.com 
417828Salexander.borisov@nginx.com     nxt_unit_remove_port(ctx, port_id);
418828Salexander.borisov@nginx.com }
419828Salexander.borisov@nginx.com 
420828Salexander.borisov@nginx.com 
421802Salexander.borisov@nginx.com napi_value
422802Salexander.borisov@nginx.com Unit::get_server_object()
423802Salexander.borisov@nginx.com {
424802Salexander.borisov@nginx.com     napi_value   unit_obj, server_obj;
425802Salexander.borisov@nginx.com     napi_status  status;
426802Salexander.borisov@nginx.com 
427802Salexander.borisov@nginx.com     status = napi_get_reference_value(env_, wrapper_, &unit_obj);
428802Salexander.borisov@nginx.com     if (status != napi_ok) {
429802Salexander.borisov@nginx.com         return nullptr;
430802Salexander.borisov@nginx.com     }
431802Salexander.borisov@nginx.com 
432802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, unit_obj, "server", &server_obj);
433802Salexander.borisov@nginx.com     if (status != napi_ok) {
434802Salexander.borisov@nginx.com         return nullptr;
435802Salexander.borisov@nginx.com     }
436802Salexander.borisov@nginx.com 
437802Salexander.borisov@nginx.com     return server_obj;
438802Salexander.borisov@nginx.com }
439802Salexander.borisov@nginx.com 
440802Salexander.borisov@nginx.com 
441802Salexander.borisov@nginx.com napi_status
442802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
443802Salexander.borisov@nginx.com {
444802Salexander.borisov@nginx.com     uint32_t            i;
445802Salexander.borisov@nginx.com     const char          *p;
446802Salexander.borisov@nginx.com     napi_value          headers, raw_headers, str;
447802Salexander.borisov@nginx.com     napi_status         status;
448802Salexander.borisov@nginx.com     nxt_unit_field_t    *f;
449802Salexander.borisov@nginx.com     nxt_unit_request_t  *r;
450802Salexander.borisov@nginx.com 
451802Salexander.borisov@nginx.com     r = req->request;
452802Salexander.borisov@nginx.com 
453802Salexander.borisov@nginx.com     status = napi_create_object(env_, &headers);
454802Salexander.borisov@nginx.com     if (status != napi_ok) {
455802Salexander.borisov@nginx.com         return status;
456802Salexander.borisov@nginx.com     }
457802Salexander.borisov@nginx.com 
458802Salexander.borisov@nginx.com     status = napi_create_array_with_length(env_, r->fields_count * 2,
459802Salexander.borisov@nginx.com                                            &raw_headers);
460802Salexander.borisov@nginx.com     if (status != napi_ok) {
461802Salexander.borisov@nginx.com         return status;
462802Salexander.borisov@nginx.com     }
463802Salexander.borisov@nginx.com 
464802Salexander.borisov@nginx.com     for (i = 0; i < r->fields_count; i++) {
465802Salexander.borisov@nginx.com         f = r->fields + i;
466802Salexander.borisov@nginx.com 
467802Salexander.borisov@nginx.com         status = this->append_header(f, headers, raw_headers, i);
468802Salexander.borisov@nginx.com         if (status != napi_ok) {
469802Salexander.borisov@nginx.com             return status;
470802Salexander.borisov@nginx.com         }
471802Salexander.borisov@nginx.com     }
472802Salexander.borisov@nginx.com 
473802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "headers", headers);
474802Salexander.borisov@nginx.com     if (status != napi_ok) {
475802Salexander.borisov@nginx.com         return status;
476802Salexander.borisov@nginx.com     }
477802Salexander.borisov@nginx.com 
478830Szelenkov@nginx.com     status = napi_set_named_property(env_, request, "rawHeaders", raw_headers);
479802Salexander.borisov@nginx.com     if (status != napi_ok) {
480802Salexander.borisov@nginx.com         return status;
481802Salexander.borisov@nginx.com     }
482802Salexander.borisov@nginx.com 
483802Salexander.borisov@nginx.com     p = (const char *) nxt_unit_sptr_get(&r->version);
484802Salexander.borisov@nginx.com 
485802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->version_length, &str);
486802Salexander.borisov@nginx.com     if (status != napi_ok) {
487802Salexander.borisov@nginx.com         return status;
488802Salexander.borisov@nginx.com     }
489802Salexander.borisov@nginx.com 
490802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "httpVersion", str);
491802Salexander.borisov@nginx.com     if (status != napi_ok) {
492802Salexander.borisov@nginx.com         return status;
493802Salexander.borisov@nginx.com     }
494802Salexander.borisov@nginx.com 
495802Salexander.borisov@nginx.com     p = (const char *) nxt_unit_sptr_get(&r->method);
496802Salexander.borisov@nginx.com 
497802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->method_length, &str);
498802Salexander.borisov@nginx.com     if (status != napi_ok) {
499802Salexander.borisov@nginx.com         return status;
500802Salexander.borisov@nginx.com     }
501802Salexander.borisov@nginx.com 
502802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "method", str);
503802Salexander.borisov@nginx.com     if (status != napi_ok) {
504802Salexander.borisov@nginx.com         return status;
505802Salexander.borisov@nginx.com     }
506802Salexander.borisov@nginx.com 
507802Salexander.borisov@nginx.com     p = (const char *) nxt_unit_sptr_get(&r->target);
508802Salexander.borisov@nginx.com 
509802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->target_length, &str);
510802Salexander.borisov@nginx.com     if (status != napi_ok) {
511802Salexander.borisov@nginx.com         return status;
512802Salexander.borisov@nginx.com     }
513802Salexander.borisov@nginx.com 
514802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "url", str);
515802Salexander.borisov@nginx.com     if (status != napi_ok) {
516802Salexander.borisov@nginx.com         return status;
517802Salexander.borisov@nginx.com     }
518802Salexander.borisov@nginx.com 
519802Salexander.borisov@nginx.com     return napi_ok;
520802Salexander.borisov@nginx.com }
521802Salexander.borisov@nginx.com 
522802Salexander.borisov@nginx.com 
523802Salexander.borisov@nginx.com inline napi_status
524802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers,
525802Salexander.borisov@nginx.com                     napi_value raw_headers, uint32_t idx)
526802Salexander.borisov@nginx.com {
527802Salexander.borisov@nginx.com     const char   *name, *value;
528802Salexander.borisov@nginx.com     napi_value   str, vstr;
529802Salexander.borisov@nginx.com     napi_status  status;
530802Salexander.borisov@nginx.com 
531802Salexander.borisov@nginx.com     value = (const char *) nxt_unit_sptr_get(&f->value);
532802Salexander.borisov@nginx.com 
533802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, value, f->value_length, &vstr);
534802Salexander.borisov@nginx.com     if (status != napi_ok) {
535802Salexander.borisov@nginx.com         return status;
536802Salexander.borisov@nginx.com     }
537802Salexander.borisov@nginx.com 
538802Salexander.borisov@nginx.com     name = (const char *) nxt_unit_sptr_get(&f->name);
539802Salexander.borisov@nginx.com 
540802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, headers, name, vstr);
541802Salexander.borisov@nginx.com     if (status != napi_ok) {
542802Salexander.borisov@nginx.com         return status;
543802Salexander.borisov@nginx.com     }
544802Salexander.borisov@nginx.com 
545802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, name, f->name_length, &str);
546802Salexander.borisov@nginx.com     if (status != napi_ok) {
547802Salexander.borisov@nginx.com         return status;
548802Salexander.borisov@nginx.com     }
549802Salexander.borisov@nginx.com 
550802Salexander.borisov@nginx.com     status = napi_set_element(env_, raw_headers, idx * 2, str);
551802Salexander.borisov@nginx.com     if (status != napi_ok) {
552802Salexander.borisov@nginx.com         return status;
553802Salexander.borisov@nginx.com     }
554802Salexander.borisov@nginx.com 
555802Salexander.borisov@nginx.com     status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr);
556802Salexander.borisov@nginx.com     if (status != napi_ok) {
557802Salexander.borisov@nginx.com         return status;
558802Salexander.borisov@nginx.com     }
559802Salexander.borisov@nginx.com 
560802Salexander.borisov@nginx.com     return napi_ok;
561802Salexander.borisov@nginx.com }
562802Salexander.borisov@nginx.com 
563802Salexander.borisov@nginx.com 
564802Salexander.borisov@nginx.com napi_value
565802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req)
566802Salexander.borisov@nginx.com {
567828Salexander.borisov@nginx.com     napi_value   constructor, return_val, req_pointer;
568802Salexander.borisov@nginx.com     napi_status  status;
569802Salexander.borisov@nginx.com 
570802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "socket",
571802Salexander.borisov@nginx.com                                      &constructor);
572802Salexander.borisov@nginx.com     if (status != napi_ok) {
573802Salexander.borisov@nginx.com         return nullptr;
574802Salexander.borisov@nginx.com     }
575802Salexander.borisov@nginx.com 
576802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 0, NULL, &return_val);
577802Salexander.borisov@nginx.com     if (status != napi_ok) {
578802Salexander.borisov@nginx.com         return nullptr;
579802Salexander.borisov@nginx.com     }
580802Salexander.borisov@nginx.com 
581828Salexander.borisov@nginx.com     status = napi_create_int64(env_, (uintptr_t) req, &req_pointer);
582828Salexander.borisov@nginx.com     if (status != napi_ok) {
583828Salexander.borisov@nginx.com         return nullptr;
584828Salexander.borisov@nginx.com     }
585828Salexander.borisov@nginx.com 
586828Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "req_pointer",
587828Salexander.borisov@nginx.com                                      req_pointer);
588828Salexander.borisov@nginx.com     if (status != napi_ok) {
589828Salexander.borisov@nginx.com         return nullptr;
590828Salexander.borisov@nginx.com     }
591828Salexander.borisov@nginx.com 
592802Salexander.borisov@nginx.com     return return_val;
593802Salexander.borisov@nginx.com }
594802Salexander.borisov@nginx.com 
595802Salexander.borisov@nginx.com 
596802Salexander.borisov@nginx.com napi_value
597802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket)
598802Salexander.borisov@nginx.com {
599802Salexander.borisov@nginx.com     napi_value   constructor, return_val;
600802Salexander.borisov@nginx.com     napi_status  status;
601802Salexander.borisov@nginx.com 
602802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "request",
603802Salexander.borisov@nginx.com                                      &constructor);
604802Salexander.borisov@nginx.com     if (status != napi_ok) {
605802Salexander.borisov@nginx.com         return nullptr;
606802Salexander.borisov@nginx.com     }
607802Salexander.borisov@nginx.com 
608802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 1, &server_obj,
609802Salexander.borisov@nginx.com                                &return_val);
610802Salexander.borisov@nginx.com     if (status != napi_ok) {
611802Salexander.borisov@nginx.com         return nullptr;
612802Salexander.borisov@nginx.com     }
613802Salexander.borisov@nginx.com 
614802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "socket", socket);
615802Salexander.borisov@nginx.com     if (status != napi_ok) {
616802Salexander.borisov@nginx.com         return nullptr;
617802Salexander.borisov@nginx.com     }
618802Salexander.borisov@nginx.com 
619802Salexander.borisov@nginx.com     return return_val;
620802Salexander.borisov@nginx.com }
621802Salexander.borisov@nginx.com 
622802Salexander.borisov@nginx.com 
623802Salexander.borisov@nginx.com napi_value
624802Salexander.borisov@nginx.com Unit::create_response(napi_value server_obj, napi_value socket,
625802Salexander.borisov@nginx.com                       napi_value request, nxt_unit_request_info_t *req,
626802Salexander.borisov@nginx.com                       Unit *obj)
627802Salexander.borisov@nginx.com {
628802Salexander.borisov@nginx.com     napi_value   constructor, return_val, req_num;
629802Salexander.borisov@nginx.com     napi_status  status;
630802Salexander.borisov@nginx.com 
631802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "response",
632802Salexander.borisov@nginx.com                                      &constructor);
633802Salexander.borisov@nginx.com     if (status != napi_ok) {
634802Salexander.borisov@nginx.com         return nullptr;
635802Salexander.borisov@nginx.com     }
636802Salexander.borisov@nginx.com 
637802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 1, &request, &return_val);
638802Salexander.borisov@nginx.com     if (status != napi_ok) {
639802Salexander.borisov@nginx.com         return nullptr;
640802Salexander.borisov@nginx.com     }
641802Salexander.borisov@nginx.com 
642802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "socket", socket);
643802Salexander.borisov@nginx.com     if (status != napi_ok) {
644802Salexander.borisov@nginx.com         return nullptr;
645802Salexander.borisov@nginx.com     }
646802Salexander.borisov@nginx.com 
647802Salexander.borisov@nginx.com     status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num);
648802Salexander.borisov@nginx.com     if (status != napi_ok) {
649802Salexander.borisov@nginx.com         return nullptr;
650802Salexander.borisov@nginx.com     }
651802Salexander.borisov@nginx.com 
652802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "_req_point", req_num);
653802Salexander.borisov@nginx.com     if (status != napi_ok) {
654802Salexander.borisov@nginx.com         return nullptr;
655802Salexander.borisov@nginx.com     }
656802Salexander.borisov@nginx.com 
657802Salexander.borisov@nginx.com     return return_val;
658802Salexander.borisov@nginx.com }
659802Salexander.borisov@nginx.com 
660802Salexander.borisov@nginx.com 
661802Salexander.borisov@nginx.com napi_value
662802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info)
663802Salexander.borisov@nginx.com {
664802Salexander.borisov@nginx.com     int                      ret;
665802Salexander.borisov@nginx.com     char                     *ptr, *name_ptr;
666802Salexander.borisov@nginx.com     bool                     is_array;
667802Salexander.borisov@nginx.com     size_t                   argc, name_len, value_len;
668802Salexander.borisov@nginx.com     int64_t                  req_p;
669802Salexander.borisov@nginx.com     uint32_t                 status_code, header_len, keys_len, array_len;
670802Salexander.borisov@nginx.com     uint32_t                 keys_count, i, j;
671802Salexander.borisov@nginx.com     uint16_t                 hash;
672802Salexander.borisov@nginx.com     napi_value               this_arg, headers, keys, name, value, array_val;
673802Salexander.borisov@nginx.com     napi_value               req_num;
674802Salexander.borisov@nginx.com     napi_status              status;
675802Salexander.borisov@nginx.com     nxt_unit_field_t         *f;
676802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
677802Salexander.borisov@nginx.com     napi_value               argv[5];
678802Salexander.borisov@nginx.com 
679802Salexander.borisov@nginx.com     argc = 5;
680802Salexander.borisov@nginx.com 
681802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
682802Salexander.borisov@nginx.com     if (status != napi_ok) {
683802Salexander.borisov@nginx.com         return nullptr;
684802Salexander.borisov@nginx.com     }
685802Salexander.borisov@nginx.com 
686802Salexander.borisov@nginx.com     if (argc != 5) {
687802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Wrong args count. Need three: "
688802Salexander.borisov@nginx.com                          "statusCode, headers, headers count, headers length");
689802Salexander.borisov@nginx.com         return nullptr;
690802Salexander.borisov@nginx.com     }
691802Salexander.borisov@nginx.com 
692802Salexander.borisov@nginx.com     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
693802Salexander.borisov@nginx.com     if (status != napi_ok) {
694802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
695802Salexander.borisov@nginx.com         return nullptr;
696802Salexander.borisov@nginx.com     }
697802Salexander.borisov@nginx.com 
698802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
699802Salexander.borisov@nginx.com     if (status != napi_ok) {
700802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
701802Salexander.borisov@nginx.com         return nullptr;
702802Salexander.borisov@nginx.com     }
703802Salexander.borisov@nginx.com 
704802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
705802Salexander.borisov@nginx.com 
706802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[1], &status_code);
707802Salexander.borisov@nginx.com     if (status != napi_ok) {
708802Salexander.borisov@nginx.com         goto failed;
709802Salexander.borisov@nginx.com     }
710802Salexander.borisov@nginx.com 
711802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[3], &keys_count);
712802Salexander.borisov@nginx.com     if (status != napi_ok) {
713802Salexander.borisov@nginx.com         goto failed;
714802Salexander.borisov@nginx.com     }
715802Salexander.borisov@nginx.com 
716802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[4], &header_len);
717802Salexander.borisov@nginx.com     if (status != napi_ok) {
718802Salexander.borisov@nginx.com         goto failed;
719802Salexander.borisov@nginx.com     }
720802Salexander.borisov@nginx.com 
721802Salexander.borisov@nginx.com     /* Need to reserve extra byte for C-string 0-termination. */
722802Salexander.borisov@nginx.com     header_len++;
723802Salexander.borisov@nginx.com 
724802Salexander.borisov@nginx.com     headers = argv[2];
725802Salexander.borisov@nginx.com 
726802Salexander.borisov@nginx.com     ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
727802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
728802Salexander.borisov@nginx.com         goto failed;
729802Salexander.borisov@nginx.com     }
730802Salexander.borisov@nginx.com 
731802Salexander.borisov@nginx.com     status = napi_get_property_names(env, headers, &keys);
732802Salexander.borisov@nginx.com     if (status != napi_ok) {
733802Salexander.borisov@nginx.com         goto failed;
734802Salexander.borisov@nginx.com     }
735802Salexander.borisov@nginx.com 
736802Salexander.borisov@nginx.com     status = napi_get_array_length(env, keys, &keys_len);
737802Salexander.borisov@nginx.com     if (status != napi_ok) {
738802Salexander.borisov@nginx.com         goto failed;
739802Salexander.borisov@nginx.com     }
740802Salexander.borisov@nginx.com 
741802Salexander.borisov@nginx.com     ptr = req->response_buf->free;
742802Salexander.borisov@nginx.com 
743802Salexander.borisov@nginx.com     for (i = 0; i < keys_len; i++) {
744802Salexander.borisov@nginx.com         status = napi_get_element(env, keys, i, &name);
745802Salexander.borisov@nginx.com         if (status != napi_ok) {
746802Salexander.borisov@nginx.com             goto failed;
747802Salexander.borisov@nginx.com         }
748802Salexander.borisov@nginx.com 
749802Salexander.borisov@nginx.com         status = napi_get_property(env, headers, name, &value);
750802Salexander.borisov@nginx.com         if (status != napi_ok) {
751802Salexander.borisov@nginx.com             goto failed;
752802Salexander.borisov@nginx.com         }
753802Salexander.borisov@nginx.com 
754802Salexander.borisov@nginx.com         status = napi_get_value_string_latin1(env, name, ptr, header_len,
755802Salexander.borisov@nginx.com                                               &name_len);
756802Salexander.borisov@nginx.com         if (status != napi_ok) {
757802Salexander.borisov@nginx.com             goto failed;
758802Salexander.borisov@nginx.com         }
759802Salexander.borisov@nginx.com 
760802Salexander.borisov@nginx.com         name_ptr = ptr;
761802Salexander.borisov@nginx.com 
762802Salexander.borisov@nginx.com         ptr += name_len;
763802Salexander.borisov@nginx.com         header_len -= name_len;
764802Salexander.borisov@nginx.com 
765802Salexander.borisov@nginx.com         hash = nxt_unit_field_hash(name_ptr, name_len);
766802Salexander.borisov@nginx.com 
767802Salexander.borisov@nginx.com         status = napi_is_array(env, value, &is_array);
768802Salexander.borisov@nginx.com         if (status != napi_ok) {
769802Salexander.borisov@nginx.com             goto failed;
770802Salexander.borisov@nginx.com         }
771802Salexander.borisov@nginx.com 
772802Salexander.borisov@nginx.com         if (is_array) {
773802Salexander.borisov@nginx.com             status = napi_get_array_length(env, value, &array_len);
774802Salexander.borisov@nginx.com             if (status != napi_ok) {
775802Salexander.borisov@nginx.com                 goto failed;
776802Salexander.borisov@nginx.com             }
777802Salexander.borisov@nginx.com 
778802Salexander.borisov@nginx.com             for (j = 0; j < array_len; j++) {
779802Salexander.borisov@nginx.com                 status = napi_get_element(env, value, j, &array_val);
780802Salexander.borisov@nginx.com                 if (status != napi_ok) {
781802Salexander.borisov@nginx.com                     goto failed;
782802Salexander.borisov@nginx.com                 }
783802Salexander.borisov@nginx.com 
784802Salexander.borisov@nginx.com                 status = napi_get_value_string_latin1(env, array_val, ptr,
785802Salexander.borisov@nginx.com                                                       header_len,
786802Salexander.borisov@nginx.com                                                       &value_len);
787802Salexander.borisov@nginx.com                 if (status != napi_ok) {
788802Salexander.borisov@nginx.com                     goto failed;
789802Salexander.borisov@nginx.com                 }
790802Salexander.borisov@nginx.com 
791802Salexander.borisov@nginx.com                 f = req->response->fields + req->response->fields_count;
792802Salexander.borisov@nginx.com                 f->skip = 0;
793802Salexander.borisov@nginx.com 
794802Salexander.borisov@nginx.com                 nxt_unit_sptr_set(&f->name, name_ptr);
795802Salexander.borisov@nginx.com 
796802Salexander.borisov@nginx.com                 f->name_length = name_len;
797802Salexander.borisov@nginx.com                 f->hash = hash;
798802Salexander.borisov@nginx.com 
799802Salexander.borisov@nginx.com                 nxt_unit_sptr_set(&f->value, ptr);
800802Salexander.borisov@nginx.com                 f->value_length = (uint32_t) value_len;
801802Salexander.borisov@nginx.com 
802802Salexander.borisov@nginx.com                 ptr += value_len;
803802Salexander.borisov@nginx.com                 header_len -= value_len;
804802Salexander.borisov@nginx.com 
805802Salexander.borisov@nginx.com                 req->response->fields_count++;
806802Salexander.borisov@nginx.com             }
807802Salexander.borisov@nginx.com 
808802Salexander.borisov@nginx.com         } else {
809802Salexander.borisov@nginx.com             status = napi_get_value_string_latin1(env, value, ptr, header_len,
810802Salexander.borisov@nginx.com                                                   &value_len);
811802Salexander.borisov@nginx.com             if (status != napi_ok) {
812802Salexander.borisov@nginx.com                 goto failed;
813802Salexander.borisov@nginx.com             }
814802Salexander.borisov@nginx.com 
815802Salexander.borisov@nginx.com             f = req->response->fields + req->response->fields_count;
816802Salexander.borisov@nginx.com             f->skip = 0;
817802Salexander.borisov@nginx.com 
818802Salexander.borisov@nginx.com             nxt_unit_sptr_set(&f->name, name_ptr);
819802Salexander.borisov@nginx.com 
820802Salexander.borisov@nginx.com             f->name_length = name_len;
821802Salexander.borisov@nginx.com             f->hash = hash;
822802Salexander.borisov@nginx.com 
823802Salexander.borisov@nginx.com             nxt_unit_sptr_set(&f->value, ptr);
824802Salexander.borisov@nginx.com             f->value_length = (uint32_t) value_len;
825802Salexander.borisov@nginx.com 
826802Salexander.borisov@nginx.com             ptr += value_len;
827802Salexander.borisov@nginx.com             header_len -= value_len;
828802Salexander.borisov@nginx.com 
829802Salexander.borisov@nginx.com             req->response->fields_count++;
830802Salexander.borisov@nginx.com         }
831802Salexander.borisov@nginx.com     }
832802Salexander.borisov@nginx.com 
833802Salexander.borisov@nginx.com     req->response_buf->free = ptr;
834802Salexander.borisov@nginx.com 
835802Salexander.borisov@nginx.com     ret = nxt_unit_response_send(req);
836802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
837802Salexander.borisov@nginx.com         goto failed;
838802Salexander.borisov@nginx.com     }
839802Salexander.borisov@nginx.com 
840802Salexander.borisov@nginx.com     return this_arg;
841802Salexander.borisov@nginx.com 
842802Salexander.borisov@nginx.com failed:
843802Salexander.borisov@nginx.com 
844802Salexander.borisov@nginx.com     req->response->fields_count = 0;
845802Salexander.borisov@nginx.com 
846802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to write headers");
847802Salexander.borisov@nginx.com 
848802Salexander.borisov@nginx.com     return nullptr;
849802Salexander.borisov@nginx.com }
850802Salexander.borisov@nginx.com 
851802Salexander.borisov@nginx.com 
852802Salexander.borisov@nginx.com napi_value
853802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info)
854802Salexander.borisov@nginx.com {
855802Salexander.borisov@nginx.com     int                      ret;
856802Salexander.borisov@nginx.com     char                     *ptr;
857802Salexander.borisov@nginx.com     size_t                   argc, have_buf_len;
858802Salexander.borisov@nginx.com     int64_t                  req_p;
859802Salexander.borisov@nginx.com     uint32_t                 buf_len;
860802Salexander.borisov@nginx.com     napi_value               this_arg, req_num;
861802Salexander.borisov@nginx.com     napi_status              status;
862802Salexander.borisov@nginx.com     nxt_unit_buf_t           *buf;
863802Salexander.borisov@nginx.com     napi_valuetype           buf_type;
864802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
865802Salexander.borisov@nginx.com     napi_value               argv[3];
866802Salexander.borisov@nginx.com 
867802Salexander.borisov@nginx.com     argc = 3;
868802Salexander.borisov@nginx.com 
869802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
870802Salexander.borisov@nginx.com     if (status != napi_ok) {
871802Salexander.borisov@nginx.com         goto failed;
872802Salexander.borisov@nginx.com     }
873802Salexander.borisov@nginx.com 
874802Salexander.borisov@nginx.com     if (argc != 3) {
875802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Wrong args count. Need two: "
876802Salexander.borisov@nginx.com                          "chunk, chunk length");
877802Salexander.borisov@nginx.com         return nullptr;
878802Salexander.borisov@nginx.com     }
879802Salexander.borisov@nginx.com 
880802Salexander.borisov@nginx.com     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
881802Salexander.borisov@nginx.com     if (status != napi_ok) {
882802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
883802Salexander.borisov@nginx.com         return nullptr;
884802Salexander.borisov@nginx.com     }
885802Salexander.borisov@nginx.com 
886802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
887802Salexander.borisov@nginx.com     if (status != napi_ok) {
888802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
889802Salexander.borisov@nginx.com         return nullptr;
890802Salexander.borisov@nginx.com     }
891802Salexander.borisov@nginx.com 
892802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
893802Salexander.borisov@nginx.com 
894802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[2], &buf_len);
895802Salexander.borisov@nginx.com     if (status != napi_ok) {
896802Salexander.borisov@nginx.com         goto failed;
897802Salexander.borisov@nginx.com     }
898802Salexander.borisov@nginx.com 
899802Salexander.borisov@nginx.com     status = napi_typeof(env, argv[1], &buf_type);
900802Salexander.borisov@nginx.com     if (status != napi_ok) {
901802Salexander.borisov@nginx.com         goto failed;
902802Salexander.borisov@nginx.com     }
903802Salexander.borisov@nginx.com 
904802Salexander.borisov@nginx.com     buf_len++;
905802Salexander.borisov@nginx.com 
906802Salexander.borisov@nginx.com     buf = nxt_unit_response_buf_alloc(req, buf_len);
907802Salexander.borisov@nginx.com     if (buf == NULL) {
908802Salexander.borisov@nginx.com         goto failed;
909802Salexander.borisov@nginx.com     }
910802Salexander.borisov@nginx.com 
911802Salexander.borisov@nginx.com     if (buf_type == napi_string) {
912802Salexander.borisov@nginx.com         /* TODO: will work only for utf8 content-type */
913802Salexander.borisov@nginx.com 
914802Salexander.borisov@nginx.com         status = napi_get_value_string_utf8(env, argv[1], buf->free,
915802Salexander.borisov@nginx.com                                             buf_len, &have_buf_len);
916802Salexander.borisov@nginx.com 
917802Salexander.borisov@nginx.com     } else {
918802Salexander.borisov@nginx.com         status = napi_get_buffer_info(env, argv[1], (void **) &ptr,
919802Salexander.borisov@nginx.com                                       &have_buf_len);
920802Salexander.borisov@nginx.com 
921802Salexander.borisov@nginx.com         memcpy(buf->free, ptr, have_buf_len);
922802Salexander.borisov@nginx.com     }
923802Salexander.borisov@nginx.com 
924802Salexander.borisov@nginx.com     if (status != napi_ok) {
925802Salexander.borisov@nginx.com         goto failed;
926802Salexander.borisov@nginx.com     }
927802Salexander.borisov@nginx.com 
928802Salexander.borisov@nginx.com     buf->free += have_buf_len;
929802Salexander.borisov@nginx.com 
930802Salexander.borisov@nginx.com     ret = nxt_unit_buf_send(buf);
931802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
932802Salexander.borisov@nginx.com         goto failed;
933802Salexander.borisov@nginx.com     }
934802Salexander.borisov@nginx.com 
935802Salexander.borisov@nginx.com     return this_arg;
936802Salexander.borisov@nginx.com 
937802Salexander.borisov@nginx.com failed:
938802Salexander.borisov@nginx.com 
939802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to write body");
940802Salexander.borisov@nginx.com 
941802Salexander.borisov@nginx.com     return nullptr;
942802Salexander.borisov@nginx.com }
943802Salexander.borisov@nginx.com 
944802Salexander.borisov@nginx.com 
945802Salexander.borisov@nginx.com napi_value
946802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info)
947802Salexander.borisov@nginx.com {
948802Salexander.borisov@nginx.com     size_t                   argc;
949802Salexander.borisov@nginx.com     int64_t                  req_p;
950802Salexander.borisov@nginx.com     napi_value               resp, this_arg, req_num;
951802Salexander.borisov@nginx.com     napi_status              status;
952802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
953802Salexander.borisov@nginx.com 
954802Salexander.borisov@nginx.com     argc = 1;
955802Salexander.borisov@nginx.com 
956802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL);
957802Salexander.borisov@nginx.com     if (status != napi_ok) {
958802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to finalize sending body");
959802Salexander.borisov@nginx.com         return nullptr;
960802Salexander.borisov@nginx.com     }
961802Salexander.borisov@nginx.com 
962802Salexander.borisov@nginx.com     status = napi_get_named_property(env, resp, "_req_point", &req_num);
963802Salexander.borisov@nginx.com     if (status != napi_ok) {
964802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
965802Salexander.borisov@nginx.com         return nullptr;
966802Salexander.borisov@nginx.com     }
967802Salexander.borisov@nginx.com 
968802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
969802Salexander.borisov@nginx.com     if (status != napi_ok) {
970802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
971802Salexander.borisov@nginx.com         return nullptr;
972802Salexander.borisov@nginx.com     }
973802Salexander.borisov@nginx.com 
974802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
975802Salexander.borisov@nginx.com 
976802Salexander.borisov@nginx.com     nxt_unit_request_done(req, NXT_UNIT_OK);
977802Salexander.borisov@nginx.com 
978802Salexander.borisov@nginx.com     return this_arg;
979802Salexander.borisov@nginx.com }
980