xref: /unit/src/nodejs/unit-http/unit.cpp (revision 802:fb9a6392d04a)
1 
2 /*
3  * Copyright (C) NGINX, Inc.
4  */
5 
6 #include "unit.h"
7 
8 
9 napi_ref Unit::constructor_;
10 
11 
12 Unit::Unit(napi_env env):
13     env_(env),
14     wrapper_(nullptr),
15     unit_ctx_(nullptr)
16 {
17 }
18 
19 
20 Unit::~Unit()
21 {
22     napi_delete_reference(env_, wrapper_);
23 }
24 
25 
26 napi_value
27 Unit::init(napi_env env, napi_value exports)
28 {
29     napi_value   cons, fn;
30     napi_status  status;
31 
32     napi_property_descriptor  properties[] = {
33         { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 },
34         { "listen", 0, listen, 0, 0, 0, napi_default, 0 }
35     };
36 
37     status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr,
38                                2, properties, &cons);
39     if (status != napi_ok) {
40         goto failed;
41     }
42 
43     status = napi_create_reference(env, cons, 1, &constructor_);
44     if (status != napi_ok) {
45         goto failed;
46     }
47 
48     status = napi_set_named_property(env, exports, "Unit", cons);
49     if (status != napi_ok) {
50         goto failed;
51     }
52 
53     status = napi_create_function(env, NULL, 0, response_send_headers, NULL,
54                                   &fn);
55     if (status != napi_ok) {
56         goto failed;
57     }
58 
59     status = napi_set_named_property(env, exports,
60                                      "unit_response_headers", fn);
61     if (status != napi_ok) {
62         goto failed;
63     }
64 
65     status = napi_create_function(env, NULL, 0, response_write, NULL, &fn);
66     if (status != napi_ok) {
67         goto failed;
68     }
69 
70     status = napi_set_named_property(env, exports, "unit_response_write", fn);
71     if (status != napi_ok) {
72         goto failed;
73     }
74 
75     status = napi_create_function(env, NULL, 0, response_end, NULL, &fn);
76     if (status != napi_ok) {
77         goto failed;
78     }
79 
80     status = napi_set_named_property(env, exports, "unit_response_end", fn);
81     if (status != napi_ok) {
82         goto failed;
83     }
84 
85     return exports;
86 
87 failed:
88 
89     napi_throw_error(env, NULL, "Failed to define Unit class");
90 
91     return nullptr;
92 }
93 
94 
95 void
96 Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint)
97 {
98     Unit  *obj = reinterpret_cast<Unit *>(nativeObject);
99 
100     delete obj;
101 }
102 
103 
104 napi_value
105 Unit::create(napi_env env, napi_callback_info info)
106 {
107     Unit         *obj;
108     napi_value   target, cons, instance, jsthis;
109     napi_status  status;
110 
111     status = napi_get_new_target(env, info, &target);
112     if (status != napi_ok) {
113         goto failed;
114     }
115 
116     if (target != nullptr) {
117         /* Invoked as constructor: `new Unit(...)` */
118         status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis,
119                                   nullptr);
120         if (status != napi_ok) {
121             goto failed;
122         }
123 
124         obj = new Unit(env);
125 
126         status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj),
127                            destroy, nullptr, &obj->wrapper_);
128         if (status != napi_ok) {
129             goto failed;
130         }
131 
132         return jsthis;
133     }
134 
135     /* Invoked as plain function `Unit(...)`, turn into construct call. */
136     status = napi_get_reference_value(env, constructor_, &cons);
137     if (status != napi_ok) {
138         goto failed;
139     }
140 
141     status = napi_new_instance(env, cons, 0, nullptr, &instance);
142     if (status != napi_ok) {
143         goto failed;
144     }
145 
146     return instance;
147 
148 failed:
149 
150     napi_throw_error(env, NULL, "Failed to create Unit object");
151 
152     return nullptr;
153 }
154 
155 
156 napi_value
157 Unit::create_server(napi_env env, napi_callback_info info)
158 {
159     Unit             *obj;
160     size_t           argc;
161     napi_value       jsthis;
162     napi_status      status;
163     napi_value       argv[1];
164     nxt_unit_init_t  unit_init;
165 
166     argc = 1;
167 
168     status = napi_get_cb_info(env, info, &argc, argv, &jsthis, nullptr);
169     if (status != napi_ok) {
170         goto failed;
171     }
172 
173     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
174     if (status != napi_ok) {
175         goto failed;
176     }
177 
178     memset(&unit_init, 0, sizeof(nxt_unit_init_t));
179 
180     unit_init.data = obj;
181     unit_init.callbacks.request_handler = request_handler;
182 
183     obj->unit_ctx_ = nxt_unit_init(&unit_init);
184     if (obj->unit_ctx_ == NULL) {
185         goto failed;
186     }
187 
188     return nullptr;
189 
190 failed:
191 
192     napi_throw_error(env, NULL, "Failed to create Unit object");
193 
194     return nullptr;
195 }
196 
197 
198 napi_value
199 Unit::listen(napi_env env, napi_callback_info info)
200 {
201     int          ret;
202     Unit         *obj;
203     napi_value   jsthis;
204     napi_status  status;
205 
206     status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, nullptr);
207     if (status != napi_ok) {
208         goto failed;
209     }
210 
211     status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
212     if (status != napi_ok) {
213         goto failed;
214     }
215 
216     if (obj->unit_ctx_ == NULL) {
217         napi_throw_error(env, NULL, "Unit context was not created");
218         return nullptr;
219     }
220 
221     ret = nxt_unit_run(obj->unit_ctx_);
222     if (ret != NXT_UNIT_OK) {
223         napi_throw_error(env, NULL, "Failed to run Unit");
224         return nullptr;
225     }
226 
227     nxt_unit_done(obj->unit_ctx_);
228 
229     return nullptr;
230 
231 failed:
232 
233     napi_throw_error(env, NULL, "Failed to listen Unit socket");
234 
235     return nullptr;
236 }
237 
238 
239 void
240 Unit::request_handler(nxt_unit_request_info_t *req)
241 {
242     Unit         *obj;
243     napi_value   socket, request, response;
244     napi_value   global, server_obj;
245     napi_value   req_argv[3];
246     napi_status  status;
247 
248     obj = reinterpret_cast<Unit *>(req->unit->data);
249 
250     napi_handle_scope scope;
251     status = napi_open_handle_scope(obj->env_, &scope);
252     if (status != napi_ok) {
253         napi_throw_error(obj->env_, NULL, "Failed to create handle scope");
254         return;
255     }
256 
257     server_obj = obj->get_server_object();
258     if (server_obj == nullptr) {
259         napi_throw_error(obj->env_, NULL, "Failed to get server object");
260         return;
261     }
262 
263     status = napi_get_global(obj->env_, &global);
264     if (status != napi_ok) {
265         napi_throw_error(obj->env_, NULL, "Failed to get global variable");
266         return;
267     }
268 
269     socket = obj->create_socket(server_obj, req);
270     if (socket == nullptr) {
271         napi_throw_error(obj->env_, NULL, "Failed to create socket object");
272         return;
273     }
274 
275     request = obj->create_request(server_obj, socket);
276     if (request == nullptr) {
277         napi_throw_error(obj->env_, NULL, "Failed to create request object");
278         return;
279     }
280 
281     response = obj->create_response(server_obj, socket, request, req, obj);
282     if (response == nullptr) {
283         napi_throw_error(obj->env_, NULL, "Failed to create response object");
284         return;
285     }
286 
287     req_argv[1] = request;
288     req_argv[2] = response;
289 
290     status = obj->create_headers(req, request);
291     if (status != napi_ok) {
292         napi_throw_error(obj->env_, NULL, "Failed to create headers");
293         return;
294     }
295 
296     obj->emit(server_obj, "request", sizeof("request") - 1, 3, req_argv);
297     obj->emit_post_data(request, req);
298 
299     napi_close_handle_scope(obj->env_, scope);
300 }
301 
302 
303 napi_value
304 Unit::get_server_object()
305 {
306     napi_value   unit_obj, server_obj;
307     napi_status  status;
308 
309     status = napi_get_reference_value(env_, wrapper_, &unit_obj);
310     if (status != napi_ok) {
311         return nullptr;
312     }
313 
314     status = napi_get_named_property(env_, unit_obj, "server", &server_obj);
315     if (status != napi_ok) {
316         return nullptr;
317     }
318 
319     return server_obj;
320 }
321 
322 
323 napi_value
324 Unit::emit(napi_value obj, const char *name, size_t name_len, size_t argc,
325            napi_value *argv)
326 {
327     napi_value   emitter, return_val, str;
328     napi_status  status;
329 
330     status = napi_get_named_property(env_, obj, "emit", &emitter);
331     if (status != napi_ok) {
332         return nullptr;
333     }
334 
335     status = napi_create_string_latin1(env_, name, name_len, &str);
336     if (status != napi_ok) {
337         return nullptr;
338     }
339 
340     if (argc != 0) {
341         argv[0] = str;
342 
343     } else {
344         argc = 1;
345         argv = &str;
346     }
347 
348     status = napi_call_function(env_, obj, emitter, argc, argv, &return_val);
349     if (status != napi_ok) {
350         return nullptr;
351     }
352 
353     return return_val;
354 }
355 
356 
357 napi_status
358 Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
359 {
360     uint32_t            i;
361     const char          *p;
362     napi_value          headers, raw_headers, str;
363     napi_status         status;
364     nxt_unit_field_t    *f;
365     nxt_unit_request_t  *r;
366 
367     r = req->request;
368 
369     status = napi_create_object(env_, &headers);
370     if (status != napi_ok) {
371         return status;
372     }
373 
374     status = napi_create_array_with_length(env_, r->fields_count * 2,
375                                            &raw_headers);
376     if (status != napi_ok) {
377         return status;
378     }
379 
380     for (i = 0; i < r->fields_count; i++) {
381         f = r->fields + i;
382 
383         status = this->append_header(f, headers, raw_headers, i);
384         if (status != napi_ok) {
385             return status;
386         }
387     }
388 
389     status = napi_set_named_property(env_, request, "headers", headers);
390     if (status != napi_ok) {
391         return status;
392     }
393 
394     status = napi_set_named_property(env_, request, "raw_headers", raw_headers);
395     if (status != napi_ok) {
396         return status;
397     }
398 
399     p = (const char *) nxt_unit_sptr_get(&r->version);
400 
401     status = napi_create_string_latin1(env_, p, r->version_length, &str);
402     if (status != napi_ok) {
403         return status;
404     }
405 
406     status = napi_set_named_property(env_, request, "httpVersion", str);
407     if (status != napi_ok) {
408         return status;
409     }
410 
411     p = (const char *) nxt_unit_sptr_get(&r->method);
412 
413     status = napi_create_string_latin1(env_, p, r->method_length, &str);
414     if (status != napi_ok) {
415         return status;
416     }
417 
418     status = napi_set_named_property(env_, request, "method", str);
419     if (status != napi_ok) {
420         return status;
421     }
422 
423     p = (const char *) nxt_unit_sptr_get(&r->target);
424 
425     status = napi_create_string_latin1(env_, p, r->target_length, &str);
426     if (status != napi_ok) {
427         return status;
428     }
429 
430     status = napi_set_named_property(env_, request, "url", str);
431     if (status != napi_ok) {
432         return status;
433     }
434 
435     return napi_ok;
436 }
437 
438 
439 inline napi_status
440 Unit::append_header(nxt_unit_field_t *f, napi_value headers,
441                     napi_value raw_headers, uint32_t idx)
442 {
443     const char   *name, *value;
444     napi_value   str, vstr;
445     napi_status  status;
446 
447     value = (const char *) nxt_unit_sptr_get(&f->value);
448 
449     status = napi_create_string_latin1(env_, value, f->value_length, &vstr);
450     if (status != napi_ok) {
451         return status;
452     }
453 
454     name = (const char *) nxt_unit_sptr_get(&f->name);
455 
456     status = napi_set_named_property(env_, headers, name, vstr);
457     if (status != napi_ok) {
458         return status;
459     }
460 
461     status = napi_create_string_latin1(env_, name, f->name_length, &str);
462     if (status != napi_ok) {
463         return status;
464     }
465 
466     status = napi_set_element(env_, raw_headers, idx * 2, str);
467     if (status != napi_ok) {
468         return status;
469     }
470 
471     status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr);
472     if (status != napi_ok) {
473         return status;
474     }
475 
476     return napi_ok;
477 }
478 
479 
480 napi_value
481 Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req)
482 {
483     napi_value   constructor, return_val;
484     napi_status  status;
485 
486     status = napi_get_named_property(env_, server_obj, "socket",
487                                      &constructor);
488     if (status != napi_ok) {
489         return nullptr;
490     }
491 
492     status = napi_new_instance(env_, constructor, 0, NULL, &return_val);
493     if (status != napi_ok) {
494         return nullptr;
495     }
496 
497     return return_val;
498 }
499 
500 
501 napi_value
502 Unit::create_request(napi_value server_obj, napi_value socket)
503 {
504     napi_value   constructor, return_val;
505     napi_status  status;
506 
507     status = napi_get_named_property(env_, server_obj, "request",
508                                      &constructor);
509     if (status != napi_ok) {
510         return nullptr;
511     }
512 
513     status = napi_new_instance(env_, constructor, 1, &server_obj,
514                                &return_val);
515     if (status != napi_ok) {
516         return nullptr;
517     }
518 
519     status = napi_set_named_property(env_, return_val, "socket", socket);
520     if (status != napi_ok) {
521         return nullptr;
522     }
523 
524     return return_val;
525 }
526 
527 
528 napi_value
529 Unit::create_response(napi_value server_obj, napi_value socket,
530                       napi_value request, nxt_unit_request_info_t *req,
531                       Unit *obj)
532 {
533     napi_value   constructor, return_val, req_num;
534     napi_status  status;
535 
536     status = napi_get_named_property(env_, server_obj, "response",
537                                      &constructor);
538     if (status != napi_ok) {
539         return nullptr;
540     }
541 
542     status = napi_new_instance(env_, constructor, 1, &request, &return_val);
543     if (status != napi_ok) {
544         return nullptr;
545     }
546 
547     status = napi_set_named_property(env_, return_val, "socket", socket);
548     if (status != napi_ok) {
549         return nullptr;
550     }
551 
552     status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num);
553     if (status != napi_ok) {
554         return nullptr;
555     }
556 
557     status = napi_set_named_property(env_, return_val, "_req_point", req_num);
558     if (status != napi_ok) {
559         return nullptr;
560     }
561 
562     return return_val;
563 }
564 
565 
566 void
567 Unit::emit_post_data(napi_value request, nxt_unit_request_info_t *req)
568 {
569     void         *data;
570     napi_value   req_argv[2];
571     napi_status  status;
572 
573     status = napi_create_buffer(env_, (size_t) req->content_length,
574                                 &data, &req_argv[1]);
575     if (status != napi_ok) {
576         napi_throw_error(env_, NULL, "Failed to create request buffer");
577         return;
578     }
579 
580     nxt_unit_request_read(req, data, req->content_length);
581 
582     emit(request, "data", sizeof("data") - 1, 2, req_argv);
583     emit(request, "end", sizeof("end") - 1, 0, nullptr);
584 }
585 
586 
587 napi_value
588 Unit::response_send_headers(napi_env env, napi_callback_info info)
589 {
590     int                      ret;
591     char                     *ptr, *name_ptr;
592     bool                     is_array;
593     size_t                   argc, name_len, value_len;
594     int64_t                  req_p;
595     uint32_t                 status_code, header_len, keys_len, array_len;
596     uint32_t                 keys_count, i, j;
597     uint16_t                 hash;
598     napi_value               this_arg, headers, keys, name, value, array_val;
599     napi_value               req_num;
600     napi_status              status;
601     nxt_unit_field_t         *f;
602     nxt_unit_request_info_t  *req;
603     napi_value               argv[5];
604 
605     argc = 5;
606 
607     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
608     if (status != napi_ok) {
609         return nullptr;
610     }
611 
612     if (argc != 5) {
613         napi_throw_error(env, NULL, "Wrong args count. Need three: "
614                          "statusCode, headers, headers count, headers length");
615         return nullptr;
616     }
617 
618     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
619     if (status != napi_ok) {
620         napi_throw_error(env, NULL, "Failed to get request pointer");
621         return nullptr;
622     }
623 
624     status = napi_get_value_int64(env, req_num, &req_p);
625     if (status != napi_ok) {
626         napi_throw_error(env, NULL, "Failed to get request pointer");
627         return nullptr;
628     }
629 
630     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
631 
632     status = napi_get_value_uint32(env, argv[1], &status_code);
633     if (status != napi_ok) {
634         goto failed;
635     }
636 
637     status = napi_get_value_uint32(env, argv[3], &keys_count);
638     if (status != napi_ok) {
639         goto failed;
640     }
641 
642     status = napi_get_value_uint32(env, argv[4], &header_len);
643     if (status != napi_ok) {
644         goto failed;
645     }
646 
647     /* Need to reserve extra byte for C-string 0-termination. */
648     header_len++;
649 
650     headers = argv[2];
651 
652     ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
653     if (ret != NXT_UNIT_OK) {
654         goto failed;
655     }
656 
657     status = napi_get_property_names(env, headers, &keys);
658     if (status != napi_ok) {
659         goto failed;
660     }
661 
662     status = napi_get_array_length(env, keys, &keys_len);
663     if (status != napi_ok) {
664         goto failed;
665     }
666 
667     ptr = req->response_buf->free;
668 
669     for (i = 0; i < keys_len; i++) {
670         status = napi_get_element(env, keys, i, &name);
671         if (status != napi_ok) {
672             goto failed;
673         }
674 
675         status = napi_get_property(env, headers, name, &value);
676         if (status != napi_ok) {
677             goto failed;
678         }
679 
680         status = napi_get_value_string_latin1(env, name, ptr, header_len,
681                                               &name_len);
682         if (status != napi_ok) {
683             goto failed;
684         }
685 
686         name_ptr = ptr;
687 
688         ptr += name_len;
689         header_len -= name_len;
690 
691         hash = nxt_unit_field_hash(name_ptr, name_len);
692 
693         status = napi_is_array(env, value, &is_array);
694         if (status != napi_ok) {
695             goto failed;
696         }
697 
698         if (is_array) {
699             status = napi_get_array_length(env, value, &array_len);
700             if (status != napi_ok) {
701                 goto failed;
702             }
703 
704             for (j = 0; j < array_len; j++) {
705                 status = napi_get_element(env, value, j, &array_val);
706                 if (status != napi_ok) {
707                     goto failed;
708                 }
709 
710                 status = napi_get_value_string_latin1(env, array_val, ptr,
711                                                       header_len,
712                                                       &value_len);
713                 if (status != napi_ok) {
714                     goto failed;
715                 }
716 
717                 f = req->response->fields + req->response->fields_count;
718                 f->skip = 0;
719 
720                 nxt_unit_sptr_set(&f->name, name_ptr);
721 
722                 f->name_length = name_len;
723                 f->hash = hash;
724 
725                 nxt_unit_sptr_set(&f->value, ptr);
726                 f->value_length = (uint32_t) value_len;
727 
728                 ptr += value_len;
729                 header_len -= value_len;
730 
731                 req->response->fields_count++;
732             }
733 
734         } else {
735             status = napi_get_value_string_latin1(env, value, ptr, header_len,
736                                                   &value_len);
737             if (status != napi_ok) {
738                 goto failed;
739             }
740 
741             f = req->response->fields + req->response->fields_count;
742             f->skip = 0;
743 
744             nxt_unit_sptr_set(&f->name, name_ptr);
745 
746             f->name_length = name_len;
747             f->hash = hash;
748 
749             nxt_unit_sptr_set(&f->value, ptr);
750             f->value_length = (uint32_t) value_len;
751 
752             ptr += value_len;
753             header_len -= value_len;
754 
755             req->response->fields_count++;
756         }
757     }
758 
759     req->response_buf->free = ptr;
760 
761     ret = nxt_unit_response_send(req);
762     if (ret != NXT_UNIT_OK) {
763         goto failed;
764     }
765 
766     return this_arg;
767 
768 failed:
769 
770     req->response->fields_count = 0;
771 
772     napi_throw_error(env, NULL, "Failed to write headers");
773 
774     return nullptr;
775 }
776 
777 
778 napi_value
779 Unit::response_write(napi_env env, napi_callback_info info)
780 {
781     int                      ret;
782     char                     *ptr;
783     size_t                   argc, have_buf_len;
784     int64_t                  req_p;
785     uint32_t                 buf_len;
786     napi_value               this_arg, req_num;
787     napi_status              status;
788     nxt_unit_buf_t           *buf;
789     napi_valuetype           buf_type;
790     nxt_unit_request_info_t  *req;
791     napi_value               argv[3];
792 
793     argc = 3;
794 
795     status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
796     if (status != napi_ok) {
797         goto failed;
798     }
799 
800     if (argc != 3) {
801         napi_throw_error(env, NULL, "Wrong args count. Need two: "
802                          "chunk, chunk length");
803         return nullptr;
804     }
805 
806     status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
807     if (status != napi_ok) {
808         napi_throw_error(env, NULL, "Failed to get request pointer");
809         return nullptr;
810     }
811 
812     status = napi_get_value_int64(env, req_num, &req_p);
813     if (status != napi_ok) {
814         napi_throw_error(env, NULL, "Failed to get request pointer");
815         return nullptr;
816     }
817 
818     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
819 
820     status = napi_get_value_uint32(env, argv[2], &buf_len);
821     if (status != napi_ok) {
822         goto failed;
823     }
824 
825     status = napi_typeof(env, argv[1], &buf_type);
826     if (status != napi_ok) {
827         goto failed;
828     }
829 
830     buf_len++;
831 
832     buf = nxt_unit_response_buf_alloc(req, buf_len);
833     if (buf == NULL) {
834         goto failed;
835     }
836 
837     if (buf_type == napi_string) {
838         /* TODO: will work only for utf8 content-type */
839 
840         status = napi_get_value_string_utf8(env, argv[1], buf->free,
841                                             buf_len, &have_buf_len);
842 
843     } else {
844         status = napi_get_buffer_info(env, argv[1], (void **) &ptr,
845                                       &have_buf_len);
846 
847         memcpy(buf->free, ptr, have_buf_len);
848     }
849 
850     if (status != napi_ok) {
851         goto failed;
852     }
853 
854     buf->free += have_buf_len;
855 
856     ret = nxt_unit_buf_send(buf);
857     if (ret != NXT_UNIT_OK) {
858         goto failed;
859     }
860 
861     return this_arg;
862 
863 failed:
864 
865     napi_throw_error(env, NULL, "Failed to write body");
866 
867     return nullptr;
868 }
869 
870 
871 napi_value
872 Unit::response_end(napi_env env, napi_callback_info info)
873 {
874     size_t                   argc;
875     int64_t                  req_p;
876     napi_value               resp, this_arg, req_num;
877     napi_status              status;
878     nxt_unit_request_info_t  *req;
879 
880     argc = 1;
881 
882     status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL);
883     if (status != napi_ok) {
884         napi_throw_error(env, NULL, "Failed to finalize sending body");
885         return nullptr;
886     }
887 
888     status = napi_get_named_property(env, resp, "_req_point", &req_num);
889     if (status != napi_ok) {
890         napi_throw_error(env, NULL, "Failed to get request pointer");
891         return nullptr;
892     }
893 
894     status = napi_get_value_int64(env, req_num, &req_p);
895     if (status != napi_ok) {
896         napi_throw_error(env, NULL, "Failed to get request pointer");
897         return nullptr;
898     }
899 
900     req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
901 
902     nxt_unit_request_done(req, NXT_UNIT_OK);
903 
904     return this_arg;
905 }
906