xref: /unit/src/nodejs/unit-http/unit.cpp (revision 842)
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 
17*842Salexander.borisov@nginx.com struct nxt_nodejs_ctx_t {
18*842Salexander.borisov@nginx.com     nxt_unit_port_id_t  port_id;
19*842Salexander.borisov@nginx.com     uv_poll_t           poll;
20*842Salexander.borisov@nginx.com };
21*842Salexander.borisov@nginx.com 
22*842Salexander.borisov@nginx.com 
23802Salexander.borisov@nginx.com Unit::Unit(napi_env env):
24802Salexander.borisov@nginx.com     env_(env),
25802Salexander.borisov@nginx.com     wrapper_(nullptr),
26802Salexander.borisov@nginx.com     unit_ctx_(nullptr)
27802Salexander.borisov@nginx.com {
28802Salexander.borisov@nginx.com }
29802Salexander.borisov@nginx.com 
30802Salexander.borisov@nginx.com 
31802Salexander.borisov@nginx.com Unit::~Unit()
32802Salexander.borisov@nginx.com {
33802Salexander.borisov@nginx.com     napi_delete_reference(env_, wrapper_);
34802Salexander.borisov@nginx.com }
35802Salexander.borisov@nginx.com 
36802Salexander.borisov@nginx.com 
37802Salexander.borisov@nginx.com napi_value
38802Salexander.borisov@nginx.com Unit::init(napi_env env, napi_value exports)
39802Salexander.borisov@nginx.com {
40802Salexander.borisov@nginx.com     napi_value   cons, fn;
41802Salexander.borisov@nginx.com     napi_status  status;
42802Salexander.borisov@nginx.com 
43802Salexander.borisov@nginx.com     napi_property_descriptor  properties[] = {
44802Salexander.borisov@nginx.com         { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 },
45828Salexander.borisov@nginx.com         { "listen", 0, listen, 0, 0, 0, napi_default, 0 },
46828Salexander.borisov@nginx.com         { "_read", 0, _read, 0, 0, 0, napi_default, 0 }
47802Salexander.borisov@nginx.com     };
48802Salexander.borisov@nginx.com 
49802Salexander.borisov@nginx.com     status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr,
50828Salexander.borisov@nginx.com                                3, properties, &cons);
51802Salexander.borisov@nginx.com     if (status != napi_ok) {
52802Salexander.borisov@nginx.com         goto failed;
53802Salexander.borisov@nginx.com     }
54802Salexander.borisov@nginx.com 
55802Salexander.borisov@nginx.com     status = napi_create_reference(env, cons, 1, &constructor_);
56802Salexander.borisov@nginx.com     if (status != napi_ok) {
57802Salexander.borisov@nginx.com         goto failed;
58802Salexander.borisov@nginx.com     }
59802Salexander.borisov@nginx.com 
60802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "Unit", cons);
61802Salexander.borisov@nginx.com     if (status != napi_ok) {
62802Salexander.borisov@nginx.com         goto failed;
63802Salexander.borisov@nginx.com     }
64802Salexander.borisov@nginx.com 
65802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_send_headers, NULL,
66802Salexander.borisov@nginx.com                                   &fn);
67802Salexander.borisov@nginx.com     if (status != napi_ok) {
68802Salexander.borisov@nginx.com         goto failed;
69802Salexander.borisov@nginx.com     }
70802Salexander.borisov@nginx.com 
71802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports,
72802Salexander.borisov@nginx.com                                      "unit_response_headers", fn);
73802Salexander.borisov@nginx.com     if (status != napi_ok) {
74802Salexander.borisov@nginx.com         goto failed;
75802Salexander.borisov@nginx.com     }
76802Salexander.borisov@nginx.com 
77802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_write, NULL, &fn);
78802Salexander.borisov@nginx.com     if (status != napi_ok) {
79802Salexander.borisov@nginx.com         goto failed;
80802Salexander.borisov@nginx.com     }
81802Salexander.borisov@nginx.com 
82802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "unit_response_write", fn);
83802Salexander.borisov@nginx.com     if (status != napi_ok) {
84802Salexander.borisov@nginx.com         goto failed;
85802Salexander.borisov@nginx.com     }
86802Salexander.borisov@nginx.com 
87802Salexander.borisov@nginx.com     status = napi_create_function(env, NULL, 0, response_end, NULL, &fn);
88802Salexander.borisov@nginx.com     if (status != napi_ok) {
89802Salexander.borisov@nginx.com         goto failed;
90802Salexander.borisov@nginx.com     }
91802Salexander.borisov@nginx.com 
92802Salexander.borisov@nginx.com     status = napi_set_named_property(env, exports, "unit_response_end", fn);
93802Salexander.borisov@nginx.com     if (status != napi_ok) {
94802Salexander.borisov@nginx.com         goto failed;
95802Salexander.borisov@nginx.com     }
96802Salexander.borisov@nginx.com 
97802Salexander.borisov@nginx.com     return exports;
98802Salexander.borisov@nginx.com 
99802Salexander.borisov@nginx.com failed:
100802Salexander.borisov@nginx.com 
101802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to define Unit class");
102802Salexander.borisov@nginx.com 
103802Salexander.borisov@nginx.com     return nullptr;
104802Salexander.borisov@nginx.com }
105802Salexander.borisov@nginx.com 
106802Salexander.borisov@nginx.com 
107802Salexander.borisov@nginx.com void
108802Salexander.borisov@nginx.com Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint)
109802Salexander.borisov@nginx.com {
110802Salexander.borisov@nginx.com     Unit  *obj = reinterpret_cast<Unit *>(nativeObject);
111802Salexander.borisov@nginx.com 
112802Salexander.borisov@nginx.com     delete obj;
113802Salexander.borisov@nginx.com }
114802Salexander.borisov@nginx.com 
115802Salexander.borisov@nginx.com 
116802Salexander.borisov@nginx.com napi_value
117802Salexander.borisov@nginx.com Unit::create(napi_env env, napi_callback_info info)
118802Salexander.borisov@nginx.com {
119802Salexander.borisov@nginx.com     Unit         *obj;
120841Salexander.borisov@nginx.com     napi_ref     ref;
121802Salexander.borisov@nginx.com     napi_value   target, cons, instance, jsthis;
122802Salexander.borisov@nginx.com     napi_status  status;
123802Salexander.borisov@nginx.com 
124802Salexander.borisov@nginx.com     status = napi_get_new_target(env, info, &target);
125802Salexander.borisov@nginx.com     if (status != napi_ok) {
126802Salexander.borisov@nginx.com         goto failed;
127802Salexander.borisov@nginx.com     }
128802Salexander.borisov@nginx.com 
129802Salexander.borisov@nginx.com     if (target != nullptr) {
130802Salexander.borisov@nginx.com         /* Invoked as constructor: `new Unit(...)` */
131802Salexander.borisov@nginx.com         status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis,
132802Salexander.borisov@nginx.com                                   nullptr);
133802Salexander.borisov@nginx.com         if (status != napi_ok) {
134802Salexander.borisov@nginx.com             goto failed;
135802Salexander.borisov@nginx.com         }
136802Salexander.borisov@nginx.com 
137802Salexander.borisov@nginx.com         obj = new Unit(env);
138802Salexander.borisov@nginx.com 
139802Salexander.borisov@nginx.com         status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj),
140802Salexander.borisov@nginx.com                            destroy, nullptr, &obj->wrapper_);
141802Salexander.borisov@nginx.com         if (status != napi_ok) {
142802Salexander.borisov@nginx.com             goto failed;
143802Salexander.borisov@nginx.com         }
144802Salexander.borisov@nginx.com 
145841Salexander.borisov@nginx.com         status = napi_create_reference(env, jsthis, 1, &ref);
146841Salexander.borisov@nginx.com         if (status != napi_ok) {
147841Salexander.borisov@nginx.com             goto failed;
148841Salexander.borisov@nginx.com         }
149841Salexander.borisov@nginx.com 
150802Salexander.borisov@nginx.com         return jsthis;
151802Salexander.borisov@nginx.com     }
152802Salexander.borisov@nginx.com 
153802Salexander.borisov@nginx.com     /* Invoked as plain function `Unit(...)`, turn into construct call. */
154802Salexander.borisov@nginx.com     status = napi_get_reference_value(env, constructor_, &cons);
155802Salexander.borisov@nginx.com     if (status != napi_ok) {
156802Salexander.borisov@nginx.com         goto failed;
157802Salexander.borisov@nginx.com     }
158802Salexander.borisov@nginx.com 
159802Salexander.borisov@nginx.com     status = napi_new_instance(env, cons, 0, nullptr, &instance);
160802Salexander.borisov@nginx.com     if (status != napi_ok) {
161802Salexander.borisov@nginx.com         goto failed;
162802Salexander.borisov@nginx.com     }
163802Salexander.borisov@nginx.com 
164841Salexander.borisov@nginx.com     status = napi_create_reference(env, instance, 1, &ref);
165841Salexander.borisov@nginx.com     if (status != napi_ok) {
166841Salexander.borisov@nginx.com         goto failed;
167841Salexander.borisov@nginx.com     }
168841Salexander.borisov@nginx.com 
169802Salexander.borisov@nginx.com     return instance;
170802Salexander.borisov@nginx.com 
171802Salexander.borisov@nginx.com failed:
172802Salexander.borisov@nginx.com 
173802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to create Unit object");
174802Salexander.borisov@nginx.com 
175802Salexander.borisov@nginx.com     return nullptr;
176802Salexander.borisov@nginx.com }
177802Salexander.borisov@nginx.com 
178802Salexander.borisov@nginx.com 
179802Salexander.borisov@nginx.com napi_value
180802Salexander.borisov@nginx.com Unit::create_server(napi_env env, napi_callback_info info)
181802Salexander.borisov@nginx.com {
182802Salexander.borisov@nginx.com     Unit             *obj;
183802Salexander.borisov@nginx.com     size_t           argc;
184828Salexander.borisov@nginx.com     napi_value       jsthis, argv;
185802Salexander.borisov@nginx.com     napi_status      status;
186802Salexander.borisov@nginx.com     nxt_unit_init_t  unit_init;
187802Salexander.borisov@nginx.com 
188802Salexander.borisov@nginx.com     argc = 1;
189802Salexander.borisov@nginx.com 
190828Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
191802Salexander.borisov@nginx.com     if (status != napi_ok) {
192802Salexander.borisov@nginx.com         goto failed;
193802Salexander.borisov@nginx.com     }
194802Salexander.borisov@nginx.com 
195802Salexander.borisov@nginx.com     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
196802Salexander.borisov@nginx.com     if (status != napi_ok) {
197802Salexander.borisov@nginx.com         goto failed;
198802Salexander.borisov@nginx.com     }
199802Salexander.borisov@nginx.com 
200802Salexander.borisov@nginx.com     memset(&unit_init, 0, sizeof(nxt_unit_init_t));
201802Salexander.borisov@nginx.com 
202802Salexander.borisov@nginx.com     unit_init.data = obj;
203802Salexander.borisov@nginx.com     unit_init.callbacks.request_handler = request_handler;
204828Salexander.borisov@nginx.com     unit_init.callbacks.add_port        = add_port;
205828Salexander.borisov@nginx.com     unit_init.callbacks.remove_port     = remove_port;
206*842Salexander.borisov@nginx.com     unit_init.callbacks.quit            = quit;
207802Salexander.borisov@nginx.com 
208802Salexander.borisov@nginx.com     obj->unit_ctx_ = nxt_unit_init(&unit_init);
209802Salexander.borisov@nginx.com     if (obj->unit_ctx_ == NULL) {
210802Salexander.borisov@nginx.com         goto failed;
211802Salexander.borisov@nginx.com     }
212802Salexander.borisov@nginx.com 
213802Salexander.borisov@nginx.com     return nullptr;
214802Salexander.borisov@nginx.com 
215802Salexander.borisov@nginx.com failed:
216802Salexander.borisov@nginx.com 
217802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to create Unit object");
218802Salexander.borisov@nginx.com 
219802Salexander.borisov@nginx.com     return nullptr;
220802Salexander.borisov@nginx.com }
221802Salexander.borisov@nginx.com 
222802Salexander.borisov@nginx.com 
223802Salexander.borisov@nginx.com napi_value
224802Salexander.borisov@nginx.com Unit::listen(napi_env env, napi_callback_info info)
225802Salexander.borisov@nginx.com {
226828Salexander.borisov@nginx.com     return nullptr;
227828Salexander.borisov@nginx.com }
228828Salexander.borisov@nginx.com 
229802Salexander.borisov@nginx.com 
230828Salexander.borisov@nginx.com napi_value
231828Salexander.borisov@nginx.com Unit::_read(napi_env env, napi_callback_info info)
232828Salexander.borisov@nginx.com {
233828Salexander.borisov@nginx.com     Unit                     *obj;
234828Salexander.borisov@nginx.com     void                     *data;
235828Salexander.borisov@nginx.com     size_t                   argc;
236828Salexander.borisov@nginx.com     int64_t                  req_pointer;
237828Salexander.borisov@nginx.com     napi_value               jsthis, buffer, argv;
238828Salexander.borisov@nginx.com     napi_status              status;
239828Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
240828Salexander.borisov@nginx.com 
241828Salexander.borisov@nginx.com     argc = 1;
242828Salexander.borisov@nginx.com 
243828Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
244802Salexander.borisov@nginx.com     if (status != napi_ok) {
245828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get arguments from js");
246828Salexander.borisov@nginx.com         return nullptr;
247802Salexander.borisov@nginx.com     }
248802Salexander.borisov@nginx.com 
249802Salexander.borisov@nginx.com     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
250802Salexander.borisov@nginx.com     if (status != napi_ok) {
251828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get Unit object form js");
252828Salexander.borisov@nginx.com         return nullptr;
253802Salexander.borisov@nginx.com     }
254802Salexander.borisov@nginx.com 
255828Salexander.borisov@nginx.com     status = napi_get_value_int64(env, argv, &req_pointer);
256828Salexander.borisov@nginx.com     if (status != napi_ok) {
257828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
258802Salexander.borisov@nginx.com         return nullptr;
259802Salexander.borisov@nginx.com     }
260802Salexander.borisov@nginx.com 
261828Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer;
262828Salexander.borisov@nginx.com 
263828Salexander.borisov@nginx.com     status = napi_create_buffer(env, (size_t) req->content_length,
264828Salexander.borisov@nginx.com                                 &data, &buffer);
265828Salexander.borisov@nginx.com     if (status != napi_ok) {
266828Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to create request buffer");
267802Salexander.borisov@nginx.com         return nullptr;
268802Salexander.borisov@nginx.com     }
269802Salexander.borisov@nginx.com 
270828Salexander.borisov@nginx.com     nxt_unit_request_read(req, data, req->content_length);
271802Salexander.borisov@nginx.com 
272828Salexander.borisov@nginx.com     return buffer;
273802Salexander.borisov@nginx.com }
274802Salexander.borisov@nginx.com 
275802Salexander.borisov@nginx.com 
276802Salexander.borisov@nginx.com void
277802Salexander.borisov@nginx.com Unit::request_handler(nxt_unit_request_info_t *req)
278802Salexander.borisov@nginx.com {
279802Salexander.borisov@nginx.com     Unit         *obj;
280802Salexander.borisov@nginx.com     napi_value   socket, request, response;
281802Salexander.borisov@nginx.com     napi_value   global, server_obj;
282828Salexander.borisov@nginx.com     napi_value   run_events, events_res;
283802Salexander.borisov@nginx.com     napi_status  status;
284828Salexander.borisov@nginx.com     napi_value   events_args[3];
285802Salexander.borisov@nginx.com 
286802Salexander.borisov@nginx.com     obj = reinterpret_cast<Unit *>(req->unit->data);
287802Salexander.borisov@nginx.com 
288802Salexander.borisov@nginx.com     napi_handle_scope scope;
289802Salexander.borisov@nginx.com     status = napi_open_handle_scope(obj->env_, &scope);
290802Salexander.borisov@nginx.com     if (status != napi_ok) {
291802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create handle scope");
292802Salexander.borisov@nginx.com         return;
293802Salexander.borisov@nginx.com     }
294802Salexander.borisov@nginx.com 
295802Salexander.borisov@nginx.com     server_obj = obj->get_server_object();
296802Salexander.borisov@nginx.com     if (server_obj == nullptr) {
297802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get server object");
298802Salexander.borisov@nginx.com         return;
299802Salexander.borisov@nginx.com     }
300802Salexander.borisov@nginx.com 
301802Salexander.borisov@nginx.com     status = napi_get_global(obj->env_, &global);
302802Salexander.borisov@nginx.com     if (status != napi_ok) {
303802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get global variable");
304802Salexander.borisov@nginx.com         return;
305802Salexander.borisov@nginx.com     }
306802Salexander.borisov@nginx.com 
307802Salexander.borisov@nginx.com     socket = obj->create_socket(server_obj, req);
308802Salexander.borisov@nginx.com     if (socket == nullptr) {
309802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create socket object");
310802Salexander.borisov@nginx.com         return;
311802Salexander.borisov@nginx.com     }
312802Salexander.borisov@nginx.com 
313802Salexander.borisov@nginx.com     request = obj->create_request(server_obj, socket);
314802Salexander.borisov@nginx.com     if (request == nullptr) {
315802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create request object");
316802Salexander.borisov@nginx.com         return;
317802Salexander.borisov@nginx.com     }
318802Salexander.borisov@nginx.com 
319802Salexander.borisov@nginx.com     response = obj->create_response(server_obj, socket, request, req, obj);
320802Salexander.borisov@nginx.com     if (response == nullptr) {
321802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create response object");
322802Salexander.borisov@nginx.com         return;
323802Salexander.borisov@nginx.com     }
324802Salexander.borisov@nginx.com 
325802Salexander.borisov@nginx.com     status = obj->create_headers(req, request);
326802Salexander.borisov@nginx.com     if (status != napi_ok) {
327802Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to create headers");
328802Salexander.borisov@nginx.com         return;
329802Salexander.borisov@nginx.com     }
330802Salexander.borisov@nginx.com 
331828Salexander.borisov@nginx.com     status = napi_get_named_property(obj->env_, server_obj, "run_events",
332828Salexander.borisov@nginx.com                                      &run_events);
333828Salexander.borisov@nginx.com     if (status != napi_ok) {
334828Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to get"
335828Salexander.borisov@nginx.com                          " 'run_events' function");
336828Salexander.borisov@nginx.com         return;
337828Salexander.borisov@nginx.com     }
338828Salexander.borisov@nginx.com 
339828Salexander.borisov@nginx.com     events_args[0] = server_obj;
340828Salexander.borisov@nginx.com     events_args[1] = request;
341828Salexander.borisov@nginx.com     events_args[2] = response;
342828Salexander.borisov@nginx.com 
343828Salexander.borisov@nginx.com     status = napi_call_function(obj->env_, server_obj, run_events, 3,
344828Salexander.borisov@nginx.com                                 events_args, &events_res);
345828Salexander.borisov@nginx.com     if (status != napi_ok) {
346828Salexander.borisov@nginx.com         napi_throw_error(obj->env_, NULL, "Failed to call"
347828Salexander.borisov@nginx.com                          " 'run_events' function");
348828Salexander.borisov@nginx.com         return;
349828Salexander.borisov@nginx.com     }
350802Salexander.borisov@nginx.com 
351802Salexander.borisov@nginx.com     napi_close_handle_scope(obj->env_, scope);
352802Salexander.borisov@nginx.com }
353802Salexander.borisov@nginx.com 
354802Salexander.borisov@nginx.com 
355828Salexander.borisov@nginx.com void
356828Salexander.borisov@nginx.com nxt_uv_read_callback(uv_poll_t *handle, int status, int events)
357828Salexander.borisov@nginx.com {
358828Salexander.borisov@nginx.com     nxt_unit_run_once((nxt_unit_ctx_t *) handle->data);
359828Salexander.borisov@nginx.com }
360828Salexander.borisov@nginx.com 
361828Salexander.borisov@nginx.com 
362828Salexander.borisov@nginx.com int
363828Salexander.borisov@nginx.com Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
364828Salexander.borisov@nginx.com {
365*842Salexander.borisov@nginx.com     int               err;
366*842Salexander.borisov@nginx.com     Unit              *obj;
367*842Salexander.borisov@nginx.com     uv_loop_t         *loop;
368*842Salexander.borisov@nginx.com     napi_status       status;
369*842Salexander.borisov@nginx.com     nxt_nodejs_ctx_t  *node_ctx;
370828Salexander.borisov@nginx.com 
371828Salexander.borisov@nginx.com     if (port->in_fd != -1) {
372828Salexander.borisov@nginx.com         obj = reinterpret_cast<Unit *>(ctx->unit->data);
373828Salexander.borisov@nginx.com 
374828Salexander.borisov@nginx.com         if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) {
375828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to upgrade read"
376828Salexander.borisov@nginx.com                              " file descriptor to O_NONBLOCK");
377828Salexander.borisov@nginx.com             return -1;
378828Salexander.borisov@nginx.com         }
379828Salexander.borisov@nginx.com 
380828Salexander.borisov@nginx.com         status = napi_get_uv_event_loop(obj->env_, &loop);
381828Salexander.borisov@nginx.com         if (status != napi_ok) {
382828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to get uv.loop");
383828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
384828Salexander.borisov@nginx.com         }
385828Salexander.borisov@nginx.com 
386*842Salexander.borisov@nginx.com         node_ctx = new nxt_nodejs_ctx_t;
387828Salexander.borisov@nginx.com 
388*842Salexander.borisov@nginx.com         err = uv_poll_init(loop, &node_ctx->poll, port->in_fd);
389828Salexander.borisov@nginx.com         if (err < 0) {
390828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to init uv.poll");
391828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
392828Salexander.borisov@nginx.com         }
393828Salexander.borisov@nginx.com 
394*842Salexander.borisov@nginx.com         err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback);
395828Salexander.borisov@nginx.com         if (err < 0) {
396828Salexander.borisov@nginx.com             napi_throw_error(obj->env_, NULL, "Failed to start uv.poll");
397828Salexander.borisov@nginx.com             return NXT_UNIT_ERROR;
398828Salexander.borisov@nginx.com         }
399828Salexander.borisov@nginx.com 
400*842Salexander.borisov@nginx.com         ctx->data = node_ctx;
401*842Salexander.borisov@nginx.com 
402*842Salexander.borisov@nginx.com         node_ctx->port_id = port->id;
403*842Salexander.borisov@nginx.com         node_ctx->poll.data = ctx;
404828Salexander.borisov@nginx.com     }
405828Salexander.borisov@nginx.com 
406828Salexander.borisov@nginx.com     return nxt_unit_add_port(ctx, port);
407828Salexander.borisov@nginx.com }
408828Salexander.borisov@nginx.com 
409828Salexander.borisov@nginx.com 
410*842Salexander.borisov@nginx.com inline bool
411*842Salexander.borisov@nginx.com operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2)
412*842Salexander.borisov@nginx.com {
413*842Salexander.borisov@nginx.com     return p1.pid == p2.pid && p1.id == p2.id;
414*842Salexander.borisov@nginx.com }
415*842Salexander.borisov@nginx.com 
416*842Salexander.borisov@nginx.com 
417828Salexander.borisov@nginx.com void
418828Salexander.borisov@nginx.com Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id)
419828Salexander.borisov@nginx.com {
420*842Salexander.borisov@nginx.com     nxt_nodejs_ctx_t  *node_ctx;
421*842Salexander.borisov@nginx.com 
422*842Salexander.borisov@nginx.com     if (ctx->data != NULL) {
423*842Salexander.borisov@nginx.com         node_ctx = (nxt_nodejs_ctx_t *) ctx->data;
424828Salexander.borisov@nginx.com 
425*842Salexander.borisov@nginx.com         if (node_ctx->port_id == *port_id) {
426*842Salexander.borisov@nginx.com             uv_poll_stop(&node_ctx->poll);
427828Salexander.borisov@nginx.com 
428*842Salexander.borisov@nginx.com             delete node_ctx;
429828Salexander.borisov@nginx.com 
430*842Salexander.borisov@nginx.com             ctx->data = NULL;
431*842Salexander.borisov@nginx.com         }
432828Salexander.borisov@nginx.com     }
433828Salexander.borisov@nginx.com 
434828Salexander.borisov@nginx.com     nxt_unit_remove_port(ctx, port_id);
435828Salexander.borisov@nginx.com }
436828Salexander.borisov@nginx.com 
437828Salexander.borisov@nginx.com 
438*842Salexander.borisov@nginx.com void
439*842Salexander.borisov@nginx.com Unit::quit(nxt_unit_ctx_t *ctx)
440*842Salexander.borisov@nginx.com {
441*842Salexander.borisov@nginx.com     nxt_unit_done(ctx);
442*842Salexander.borisov@nginx.com }
443*842Salexander.borisov@nginx.com 
444*842Salexander.borisov@nginx.com 
445802Salexander.borisov@nginx.com napi_value
446802Salexander.borisov@nginx.com Unit::get_server_object()
447802Salexander.borisov@nginx.com {
448802Salexander.borisov@nginx.com     napi_value   unit_obj, server_obj;
449802Salexander.borisov@nginx.com     napi_status  status;
450802Salexander.borisov@nginx.com 
451802Salexander.borisov@nginx.com     status = napi_get_reference_value(env_, wrapper_, &unit_obj);
452802Salexander.borisov@nginx.com     if (status != napi_ok) {
453802Salexander.borisov@nginx.com         return nullptr;
454802Salexander.borisov@nginx.com     }
455802Salexander.borisov@nginx.com 
456802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, unit_obj, "server", &server_obj);
457802Salexander.borisov@nginx.com     if (status != napi_ok) {
458802Salexander.borisov@nginx.com         return nullptr;
459802Salexander.borisov@nginx.com     }
460802Salexander.borisov@nginx.com 
461802Salexander.borisov@nginx.com     return server_obj;
462802Salexander.borisov@nginx.com }
463802Salexander.borisov@nginx.com 
464802Salexander.borisov@nginx.com 
465802Salexander.borisov@nginx.com napi_status
466802Salexander.borisov@nginx.com Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
467802Salexander.borisov@nginx.com {
468802Salexander.borisov@nginx.com     uint32_t            i;
469802Salexander.borisov@nginx.com     const char          *p;
470802Salexander.borisov@nginx.com     napi_value          headers, raw_headers, str;
471802Salexander.borisov@nginx.com     napi_status         status;
472802Salexander.borisov@nginx.com     nxt_unit_field_t    *f;
473802Salexander.borisov@nginx.com     nxt_unit_request_t  *r;
474802Salexander.borisov@nginx.com 
475802Salexander.borisov@nginx.com     r = req->request;
476802Salexander.borisov@nginx.com 
477802Salexander.borisov@nginx.com     status = napi_create_object(env_, &headers);
478802Salexander.borisov@nginx.com     if (status != napi_ok) {
479802Salexander.borisov@nginx.com         return status;
480802Salexander.borisov@nginx.com     }
481802Salexander.borisov@nginx.com 
482802Salexander.borisov@nginx.com     status = napi_create_array_with_length(env_, r->fields_count * 2,
483802Salexander.borisov@nginx.com                                            &raw_headers);
484802Salexander.borisov@nginx.com     if (status != napi_ok) {
485802Salexander.borisov@nginx.com         return status;
486802Salexander.borisov@nginx.com     }
487802Salexander.borisov@nginx.com 
488802Salexander.borisov@nginx.com     for (i = 0; i < r->fields_count; i++) {
489802Salexander.borisov@nginx.com         f = r->fields + i;
490802Salexander.borisov@nginx.com 
491802Salexander.borisov@nginx.com         status = this->append_header(f, headers, raw_headers, i);
492802Salexander.borisov@nginx.com         if (status != napi_ok) {
493802Salexander.borisov@nginx.com             return status;
494802Salexander.borisov@nginx.com         }
495802Salexander.borisov@nginx.com     }
496802Salexander.borisov@nginx.com 
497802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "headers", headers);
498802Salexander.borisov@nginx.com     if (status != napi_ok) {
499802Salexander.borisov@nginx.com         return status;
500802Salexander.borisov@nginx.com     }
501802Salexander.borisov@nginx.com 
502830Szelenkov@nginx.com     status = napi_set_named_property(env_, request, "rawHeaders", raw_headers);
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->version);
508802Salexander.borisov@nginx.com 
509802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->version_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, "httpVersion", 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     p = (const char *) nxt_unit_sptr_get(&r->method);
520802Salexander.borisov@nginx.com 
521802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->method_length, &str);
522802Salexander.borisov@nginx.com     if (status != napi_ok) {
523802Salexander.borisov@nginx.com         return status;
524802Salexander.borisov@nginx.com     }
525802Salexander.borisov@nginx.com 
526802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, request, "method", str);
527802Salexander.borisov@nginx.com     if (status != napi_ok) {
528802Salexander.borisov@nginx.com         return status;
529802Salexander.borisov@nginx.com     }
530802Salexander.borisov@nginx.com 
531802Salexander.borisov@nginx.com     p = (const char *) nxt_unit_sptr_get(&r->target);
532802Salexander.borisov@nginx.com 
533802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, p, r->target_length, &str);
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     status = napi_set_named_property(env_, request, "url", str);
539802Salexander.borisov@nginx.com     if (status != napi_ok) {
540802Salexander.borisov@nginx.com         return status;
541802Salexander.borisov@nginx.com     }
542802Salexander.borisov@nginx.com 
543802Salexander.borisov@nginx.com     return napi_ok;
544802Salexander.borisov@nginx.com }
545802Salexander.borisov@nginx.com 
546802Salexander.borisov@nginx.com 
547802Salexander.borisov@nginx.com inline napi_status
548802Salexander.borisov@nginx.com Unit::append_header(nxt_unit_field_t *f, napi_value headers,
549802Salexander.borisov@nginx.com                     napi_value raw_headers, uint32_t idx)
550802Salexander.borisov@nginx.com {
551802Salexander.borisov@nginx.com     const char   *name, *value;
552802Salexander.borisov@nginx.com     napi_value   str, vstr;
553802Salexander.borisov@nginx.com     napi_status  status;
554802Salexander.borisov@nginx.com 
555802Salexander.borisov@nginx.com     value = (const char *) nxt_unit_sptr_get(&f->value);
556802Salexander.borisov@nginx.com 
557802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, value, f->value_length, &vstr);
558802Salexander.borisov@nginx.com     if (status != napi_ok) {
559802Salexander.borisov@nginx.com         return status;
560802Salexander.borisov@nginx.com     }
561802Salexander.borisov@nginx.com 
562802Salexander.borisov@nginx.com     name = (const char *) nxt_unit_sptr_get(&f->name);
563802Salexander.borisov@nginx.com 
564802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, headers, name, vstr);
565802Salexander.borisov@nginx.com     if (status != napi_ok) {
566802Salexander.borisov@nginx.com         return status;
567802Salexander.borisov@nginx.com     }
568802Salexander.borisov@nginx.com 
569802Salexander.borisov@nginx.com     status = napi_create_string_latin1(env_, name, f->name_length, &str);
570802Salexander.borisov@nginx.com     if (status != napi_ok) {
571802Salexander.borisov@nginx.com         return status;
572802Salexander.borisov@nginx.com     }
573802Salexander.borisov@nginx.com 
574802Salexander.borisov@nginx.com     status = napi_set_element(env_, raw_headers, idx * 2, str);
575802Salexander.borisov@nginx.com     if (status != napi_ok) {
576802Salexander.borisov@nginx.com         return status;
577802Salexander.borisov@nginx.com     }
578802Salexander.borisov@nginx.com 
579802Salexander.borisov@nginx.com     status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr);
580802Salexander.borisov@nginx.com     if (status != napi_ok) {
581802Salexander.borisov@nginx.com         return status;
582802Salexander.borisov@nginx.com     }
583802Salexander.borisov@nginx.com 
584802Salexander.borisov@nginx.com     return napi_ok;
585802Salexander.borisov@nginx.com }
586802Salexander.borisov@nginx.com 
587802Salexander.borisov@nginx.com 
588802Salexander.borisov@nginx.com napi_value
589802Salexander.borisov@nginx.com Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req)
590802Salexander.borisov@nginx.com {
591828Salexander.borisov@nginx.com     napi_value   constructor, return_val, req_pointer;
592802Salexander.borisov@nginx.com     napi_status  status;
593802Salexander.borisov@nginx.com 
594802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "socket",
595802Salexander.borisov@nginx.com                                      &constructor);
596802Salexander.borisov@nginx.com     if (status != napi_ok) {
597802Salexander.borisov@nginx.com         return nullptr;
598802Salexander.borisov@nginx.com     }
599802Salexander.borisov@nginx.com 
600802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 0, NULL, &return_val);
601802Salexander.borisov@nginx.com     if (status != napi_ok) {
602802Salexander.borisov@nginx.com         return nullptr;
603802Salexander.borisov@nginx.com     }
604802Salexander.borisov@nginx.com 
605828Salexander.borisov@nginx.com     status = napi_create_int64(env_, (uintptr_t) req, &req_pointer);
606828Salexander.borisov@nginx.com     if (status != napi_ok) {
607828Salexander.borisov@nginx.com         return nullptr;
608828Salexander.borisov@nginx.com     }
609828Salexander.borisov@nginx.com 
610828Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "req_pointer",
611828Salexander.borisov@nginx.com                                      req_pointer);
612828Salexander.borisov@nginx.com     if (status != napi_ok) {
613828Salexander.borisov@nginx.com         return nullptr;
614828Salexander.borisov@nginx.com     }
615828Salexander.borisov@nginx.com 
616802Salexander.borisov@nginx.com     return return_val;
617802Salexander.borisov@nginx.com }
618802Salexander.borisov@nginx.com 
619802Salexander.borisov@nginx.com 
620802Salexander.borisov@nginx.com napi_value
621802Salexander.borisov@nginx.com Unit::create_request(napi_value server_obj, napi_value socket)
622802Salexander.borisov@nginx.com {
623802Salexander.borisov@nginx.com     napi_value   constructor, return_val;
624802Salexander.borisov@nginx.com     napi_status  status;
625802Salexander.borisov@nginx.com 
626802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "request",
627802Salexander.borisov@nginx.com                                      &constructor);
628802Salexander.borisov@nginx.com     if (status != napi_ok) {
629802Salexander.borisov@nginx.com         return nullptr;
630802Salexander.borisov@nginx.com     }
631802Salexander.borisov@nginx.com 
632802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 1, &server_obj,
633802Salexander.borisov@nginx.com                                &return_val);
634802Salexander.borisov@nginx.com     if (status != napi_ok) {
635802Salexander.borisov@nginx.com         return nullptr;
636802Salexander.borisov@nginx.com     }
637802Salexander.borisov@nginx.com 
638802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "socket", socket);
639802Salexander.borisov@nginx.com     if (status != napi_ok) {
640802Salexander.borisov@nginx.com         return nullptr;
641802Salexander.borisov@nginx.com     }
642802Salexander.borisov@nginx.com 
643802Salexander.borisov@nginx.com     return return_val;
644802Salexander.borisov@nginx.com }
645802Salexander.borisov@nginx.com 
646802Salexander.borisov@nginx.com 
647802Salexander.borisov@nginx.com napi_value
648802Salexander.borisov@nginx.com Unit::create_response(napi_value server_obj, napi_value socket,
649802Salexander.borisov@nginx.com                       napi_value request, nxt_unit_request_info_t *req,
650802Salexander.borisov@nginx.com                       Unit *obj)
651802Salexander.borisov@nginx.com {
652802Salexander.borisov@nginx.com     napi_value   constructor, return_val, req_num;
653802Salexander.borisov@nginx.com     napi_status  status;
654802Salexander.borisov@nginx.com 
655802Salexander.borisov@nginx.com     status = napi_get_named_property(env_, server_obj, "response",
656802Salexander.borisov@nginx.com                                      &constructor);
657802Salexander.borisov@nginx.com     if (status != napi_ok) {
658802Salexander.borisov@nginx.com         return nullptr;
659802Salexander.borisov@nginx.com     }
660802Salexander.borisov@nginx.com 
661802Salexander.borisov@nginx.com     status = napi_new_instance(env_, constructor, 1, &request, &return_val);
662802Salexander.borisov@nginx.com     if (status != napi_ok) {
663802Salexander.borisov@nginx.com         return nullptr;
664802Salexander.borisov@nginx.com     }
665802Salexander.borisov@nginx.com 
666802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "socket", socket);
667802Salexander.borisov@nginx.com     if (status != napi_ok) {
668802Salexander.borisov@nginx.com         return nullptr;
669802Salexander.borisov@nginx.com     }
670802Salexander.borisov@nginx.com 
671802Salexander.borisov@nginx.com     status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num);
672802Salexander.borisov@nginx.com     if (status != napi_ok) {
673802Salexander.borisov@nginx.com         return nullptr;
674802Salexander.borisov@nginx.com     }
675802Salexander.borisov@nginx.com 
676802Salexander.borisov@nginx.com     status = napi_set_named_property(env_, return_val, "_req_point", req_num);
677802Salexander.borisov@nginx.com     if (status != napi_ok) {
678802Salexander.borisov@nginx.com         return nullptr;
679802Salexander.borisov@nginx.com     }
680802Salexander.borisov@nginx.com 
681802Salexander.borisov@nginx.com     return return_val;
682802Salexander.borisov@nginx.com }
683802Salexander.borisov@nginx.com 
684802Salexander.borisov@nginx.com 
685802Salexander.borisov@nginx.com napi_value
686802Salexander.borisov@nginx.com Unit::response_send_headers(napi_env env, napi_callback_info info)
687802Salexander.borisov@nginx.com {
688802Salexander.borisov@nginx.com     int                      ret;
689802Salexander.borisov@nginx.com     char                     *ptr, *name_ptr;
690802Salexander.borisov@nginx.com     bool                     is_array;
691802Salexander.borisov@nginx.com     size_t                   argc, name_len, value_len;
692802Salexander.borisov@nginx.com     int64_t                  req_p;
693802Salexander.borisov@nginx.com     uint32_t                 status_code, header_len, keys_len, array_len;
694802Salexander.borisov@nginx.com     uint32_t                 keys_count, i, j;
695802Salexander.borisov@nginx.com     uint16_t                 hash;
696802Salexander.borisov@nginx.com     napi_value               this_arg, headers, keys, name, value, array_val;
697802Salexander.borisov@nginx.com     napi_value               req_num;
698802Salexander.borisov@nginx.com     napi_status              status;
699802Salexander.borisov@nginx.com     nxt_unit_field_t         *f;
700802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
701802Salexander.borisov@nginx.com     napi_value               argv[5];
702802Salexander.borisov@nginx.com 
703802Salexander.borisov@nginx.com     argc = 5;
704802Salexander.borisov@nginx.com 
705802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
706802Salexander.borisov@nginx.com     if (status != napi_ok) {
707802Salexander.borisov@nginx.com         return nullptr;
708802Salexander.borisov@nginx.com     }
709802Salexander.borisov@nginx.com 
710802Salexander.borisov@nginx.com     if (argc != 5) {
711802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Wrong args count. Need three: "
712802Salexander.borisov@nginx.com                          "statusCode, headers, headers count, headers length");
713802Salexander.borisov@nginx.com         return nullptr;
714802Salexander.borisov@nginx.com     }
715802Salexander.borisov@nginx.com 
716802Salexander.borisov@nginx.com     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
717802Salexander.borisov@nginx.com     if (status != napi_ok) {
718802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
719802Salexander.borisov@nginx.com         return nullptr;
720802Salexander.borisov@nginx.com     }
721802Salexander.borisov@nginx.com 
722802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
723802Salexander.borisov@nginx.com     if (status != napi_ok) {
724802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
725802Salexander.borisov@nginx.com         return nullptr;
726802Salexander.borisov@nginx.com     }
727802Salexander.borisov@nginx.com 
728802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
729802Salexander.borisov@nginx.com 
730802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[1], &status_code);
731802Salexander.borisov@nginx.com     if (status != napi_ok) {
732802Salexander.borisov@nginx.com         goto failed;
733802Salexander.borisov@nginx.com     }
734802Salexander.borisov@nginx.com 
735802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[3], &keys_count);
736802Salexander.borisov@nginx.com     if (status != napi_ok) {
737802Salexander.borisov@nginx.com         goto failed;
738802Salexander.borisov@nginx.com     }
739802Salexander.borisov@nginx.com 
740802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[4], &header_len);
741802Salexander.borisov@nginx.com     if (status != napi_ok) {
742802Salexander.borisov@nginx.com         goto failed;
743802Salexander.borisov@nginx.com     }
744802Salexander.borisov@nginx.com 
745802Salexander.borisov@nginx.com     /* Need to reserve extra byte for C-string 0-termination. */
746802Salexander.borisov@nginx.com     header_len++;
747802Salexander.borisov@nginx.com 
748802Salexander.borisov@nginx.com     headers = argv[2];
749802Salexander.borisov@nginx.com 
750802Salexander.borisov@nginx.com     ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
751802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
752802Salexander.borisov@nginx.com         goto failed;
753802Salexander.borisov@nginx.com     }
754802Salexander.borisov@nginx.com 
755802Salexander.borisov@nginx.com     status = napi_get_property_names(env, headers, &keys);
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     status = napi_get_array_length(env, keys, &keys_len);
761802Salexander.borisov@nginx.com     if (status != napi_ok) {
762802Salexander.borisov@nginx.com         goto failed;
763802Salexander.borisov@nginx.com     }
764802Salexander.borisov@nginx.com 
765802Salexander.borisov@nginx.com     ptr = req->response_buf->free;
766802Salexander.borisov@nginx.com 
767802Salexander.borisov@nginx.com     for (i = 0; i < keys_len; i++) {
768802Salexander.borisov@nginx.com         status = napi_get_element(env, keys, i, &name);
769802Salexander.borisov@nginx.com         if (status != napi_ok) {
770802Salexander.borisov@nginx.com             goto failed;
771802Salexander.borisov@nginx.com         }
772802Salexander.borisov@nginx.com 
773802Salexander.borisov@nginx.com         status = napi_get_property(env, headers, name, &value);
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         status = napi_get_value_string_latin1(env, name, ptr, header_len,
779802Salexander.borisov@nginx.com                                               &name_len);
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         name_ptr = ptr;
785802Salexander.borisov@nginx.com 
786802Salexander.borisov@nginx.com         ptr += name_len;
787802Salexander.borisov@nginx.com         header_len -= name_len;
788802Salexander.borisov@nginx.com 
789802Salexander.borisov@nginx.com         hash = nxt_unit_field_hash(name_ptr, name_len);
790802Salexander.borisov@nginx.com 
791802Salexander.borisov@nginx.com         status = napi_is_array(env, value, &is_array);
792802Salexander.borisov@nginx.com         if (status != napi_ok) {
793802Salexander.borisov@nginx.com             goto failed;
794802Salexander.borisov@nginx.com         }
795802Salexander.borisov@nginx.com 
796802Salexander.borisov@nginx.com         if (is_array) {
797802Salexander.borisov@nginx.com             status = napi_get_array_length(env, value, &array_len);
798802Salexander.borisov@nginx.com             if (status != napi_ok) {
799802Salexander.borisov@nginx.com                 goto failed;
800802Salexander.borisov@nginx.com             }
801802Salexander.borisov@nginx.com 
802802Salexander.borisov@nginx.com             for (j = 0; j < array_len; j++) {
803802Salexander.borisov@nginx.com                 status = napi_get_element(env, value, j, &array_val);
804802Salexander.borisov@nginx.com                 if (status != napi_ok) {
805802Salexander.borisov@nginx.com                     goto failed;
806802Salexander.borisov@nginx.com                 }
807802Salexander.borisov@nginx.com 
808802Salexander.borisov@nginx.com                 status = napi_get_value_string_latin1(env, array_val, ptr,
809802Salexander.borisov@nginx.com                                                       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         } else {
833802Salexander.borisov@nginx.com             status = napi_get_value_string_latin1(env, value, ptr, header_len,
834802Salexander.borisov@nginx.com                                                   &value_len);
835802Salexander.borisov@nginx.com             if (status != napi_ok) {
836802Salexander.borisov@nginx.com                 goto failed;
837802Salexander.borisov@nginx.com             }
838802Salexander.borisov@nginx.com 
839802Salexander.borisov@nginx.com             f = req->response->fields + req->response->fields_count;
840802Salexander.borisov@nginx.com             f->skip = 0;
841802Salexander.borisov@nginx.com 
842802Salexander.borisov@nginx.com             nxt_unit_sptr_set(&f->name, name_ptr);
843802Salexander.borisov@nginx.com 
844802Salexander.borisov@nginx.com             f->name_length = name_len;
845802Salexander.borisov@nginx.com             f->hash = hash;
846802Salexander.borisov@nginx.com 
847802Salexander.borisov@nginx.com             nxt_unit_sptr_set(&f->value, ptr);
848802Salexander.borisov@nginx.com             f->value_length = (uint32_t) value_len;
849802Salexander.borisov@nginx.com 
850802Salexander.borisov@nginx.com             ptr += value_len;
851802Salexander.borisov@nginx.com             header_len -= value_len;
852802Salexander.borisov@nginx.com 
853802Salexander.borisov@nginx.com             req->response->fields_count++;
854802Salexander.borisov@nginx.com         }
855802Salexander.borisov@nginx.com     }
856802Salexander.borisov@nginx.com 
857802Salexander.borisov@nginx.com     req->response_buf->free = ptr;
858802Salexander.borisov@nginx.com 
859802Salexander.borisov@nginx.com     ret = nxt_unit_response_send(req);
860802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
861802Salexander.borisov@nginx.com         goto failed;
862802Salexander.borisov@nginx.com     }
863802Salexander.borisov@nginx.com 
864802Salexander.borisov@nginx.com     return this_arg;
865802Salexander.borisov@nginx.com 
866802Salexander.borisov@nginx.com failed:
867802Salexander.borisov@nginx.com 
868802Salexander.borisov@nginx.com     req->response->fields_count = 0;
869802Salexander.borisov@nginx.com 
870802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to write headers");
871802Salexander.borisov@nginx.com 
872802Salexander.borisov@nginx.com     return nullptr;
873802Salexander.borisov@nginx.com }
874802Salexander.borisov@nginx.com 
875802Salexander.borisov@nginx.com 
876802Salexander.borisov@nginx.com napi_value
877802Salexander.borisov@nginx.com Unit::response_write(napi_env env, napi_callback_info info)
878802Salexander.borisov@nginx.com {
879802Salexander.borisov@nginx.com     int                      ret;
880802Salexander.borisov@nginx.com     char                     *ptr;
881802Salexander.borisov@nginx.com     size_t                   argc, have_buf_len;
882802Salexander.borisov@nginx.com     int64_t                  req_p;
883802Salexander.borisov@nginx.com     uint32_t                 buf_len;
884802Salexander.borisov@nginx.com     napi_value               this_arg, req_num;
885802Salexander.borisov@nginx.com     napi_status              status;
886802Salexander.borisov@nginx.com     nxt_unit_buf_t           *buf;
887802Salexander.borisov@nginx.com     napi_valuetype           buf_type;
888802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
889802Salexander.borisov@nginx.com     napi_value               argv[3];
890802Salexander.borisov@nginx.com 
891802Salexander.borisov@nginx.com     argc = 3;
892802Salexander.borisov@nginx.com 
893802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
894802Salexander.borisov@nginx.com     if (status != napi_ok) {
895802Salexander.borisov@nginx.com         goto failed;
896802Salexander.borisov@nginx.com     }
897802Salexander.borisov@nginx.com 
898802Salexander.borisov@nginx.com     if (argc != 3) {
899802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Wrong args count. Need two: "
900802Salexander.borisov@nginx.com                          "chunk, chunk length");
901802Salexander.borisov@nginx.com         return nullptr;
902802Salexander.borisov@nginx.com     }
903802Salexander.borisov@nginx.com 
904802Salexander.borisov@nginx.com     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
905802Salexander.borisov@nginx.com     if (status != napi_ok) {
906802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
907802Salexander.borisov@nginx.com         return nullptr;
908802Salexander.borisov@nginx.com     }
909802Salexander.borisov@nginx.com 
910802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
911802Salexander.borisov@nginx.com     if (status != napi_ok) {
912802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
913802Salexander.borisov@nginx.com         return nullptr;
914802Salexander.borisov@nginx.com     }
915802Salexander.borisov@nginx.com 
916802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
917802Salexander.borisov@nginx.com 
918802Salexander.borisov@nginx.com     status = napi_get_value_uint32(env, argv[2], &buf_len);
919802Salexander.borisov@nginx.com     if (status != napi_ok) {
920802Salexander.borisov@nginx.com         goto failed;
921802Salexander.borisov@nginx.com     }
922802Salexander.borisov@nginx.com 
923802Salexander.borisov@nginx.com     status = napi_typeof(env, argv[1], &buf_type);
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_len++;
929802Salexander.borisov@nginx.com 
930802Salexander.borisov@nginx.com     buf = nxt_unit_response_buf_alloc(req, buf_len);
931802Salexander.borisov@nginx.com     if (buf == NULL) {
932802Salexander.borisov@nginx.com         goto failed;
933802Salexander.borisov@nginx.com     }
934802Salexander.borisov@nginx.com 
935802Salexander.borisov@nginx.com     if (buf_type == napi_string) {
936802Salexander.borisov@nginx.com         /* TODO: will work only for utf8 content-type */
937802Salexander.borisov@nginx.com 
938802Salexander.borisov@nginx.com         status = napi_get_value_string_utf8(env, argv[1], buf->free,
939802Salexander.borisov@nginx.com                                             buf_len, &have_buf_len);
940802Salexander.borisov@nginx.com 
941802Salexander.borisov@nginx.com     } else {
942802Salexander.borisov@nginx.com         status = napi_get_buffer_info(env, argv[1], (void **) &ptr,
943802Salexander.borisov@nginx.com                                       &have_buf_len);
944802Salexander.borisov@nginx.com 
945802Salexander.borisov@nginx.com         memcpy(buf->free, ptr, have_buf_len);
946802Salexander.borisov@nginx.com     }
947802Salexander.borisov@nginx.com 
948802Salexander.borisov@nginx.com     if (status != napi_ok) {
949802Salexander.borisov@nginx.com         goto failed;
950802Salexander.borisov@nginx.com     }
951802Salexander.borisov@nginx.com 
952802Salexander.borisov@nginx.com     buf->free += have_buf_len;
953802Salexander.borisov@nginx.com 
954802Salexander.borisov@nginx.com     ret = nxt_unit_buf_send(buf);
955802Salexander.borisov@nginx.com     if (ret != NXT_UNIT_OK) {
956802Salexander.borisov@nginx.com         goto failed;
957802Salexander.borisov@nginx.com     }
958802Salexander.borisov@nginx.com 
959802Salexander.borisov@nginx.com     return this_arg;
960802Salexander.borisov@nginx.com 
961802Salexander.borisov@nginx.com failed:
962802Salexander.borisov@nginx.com 
963802Salexander.borisov@nginx.com     napi_throw_error(env, NULL, "Failed to write body");
964802Salexander.borisov@nginx.com 
965802Salexander.borisov@nginx.com     return nullptr;
966802Salexander.borisov@nginx.com }
967802Salexander.borisov@nginx.com 
968802Salexander.borisov@nginx.com 
969802Salexander.borisov@nginx.com napi_value
970802Salexander.borisov@nginx.com Unit::response_end(napi_env env, napi_callback_info info)
971802Salexander.borisov@nginx.com {
972802Salexander.borisov@nginx.com     size_t                   argc;
973802Salexander.borisov@nginx.com     int64_t                  req_p;
974802Salexander.borisov@nginx.com     napi_value               resp, this_arg, req_num;
975802Salexander.borisov@nginx.com     napi_status              status;
976802Salexander.borisov@nginx.com     nxt_unit_request_info_t  *req;
977802Salexander.borisov@nginx.com 
978802Salexander.borisov@nginx.com     argc = 1;
979802Salexander.borisov@nginx.com 
980802Salexander.borisov@nginx.com     status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL);
981802Salexander.borisov@nginx.com     if (status != napi_ok) {
982802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to finalize sending body");
983802Salexander.borisov@nginx.com         return nullptr;
984802Salexander.borisov@nginx.com     }
985802Salexander.borisov@nginx.com 
986802Salexander.borisov@nginx.com     status = napi_get_named_property(env, resp, "_req_point", &req_num);
987802Salexander.borisov@nginx.com     if (status != napi_ok) {
988802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
989802Salexander.borisov@nginx.com         return nullptr;
990802Salexander.borisov@nginx.com     }
991802Salexander.borisov@nginx.com 
992802Salexander.borisov@nginx.com     status = napi_get_value_int64(env, req_num, &req_p);
993802Salexander.borisov@nginx.com     if (status != napi_ok) {
994802Salexander.borisov@nginx.com         napi_throw_error(env, NULL, "Failed to get request pointer");
995802Salexander.borisov@nginx.com         return nullptr;
996802Salexander.borisov@nginx.com     }
997802Salexander.borisov@nginx.com 
998802Salexander.borisov@nginx.com     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
999802Salexander.borisov@nginx.com 
1000802Salexander.borisov@nginx.com     nxt_unit_request_done(req, NXT_UNIT_OK);
1001802Salexander.borisov@nginx.com 
1002802Salexander.borisov@nginx.com     return this_arg;
1003802Salexander.borisov@nginx.com }
1004