xref: /unit/src/perl/nxt_perl_psgi.c (revision 969)
1510Salexander.borisov@nginx.com 
2510Salexander.borisov@nginx.com /*
3510Salexander.borisov@nginx.com  * Copyright (C) Alexander Borisov
4510Salexander.borisov@nginx.com  * Copyright (C) NGINX, Inc.
5510Salexander.borisov@nginx.com  */
6510Salexander.borisov@nginx.com 
7510Salexander.borisov@nginx.com #include <perl/nxt_perl_psgi_layer.h>
8510Salexander.borisov@nginx.com 
9510Salexander.borisov@nginx.com #include <nxt_main.h>
10510Salexander.borisov@nginx.com #include <nxt_router.h>
11510Salexander.borisov@nginx.com #include <nxt_runtime.h>
12510Salexander.borisov@nginx.com #include <nxt_application.h>
13510Salexander.borisov@nginx.com #include <nxt_file.h>
14743Smax.romanov@nginx.com #include <nxt_unit.h>
15743Smax.romanov@nginx.com #include <nxt_unit_request.h>
16743Smax.romanov@nginx.com #include <nxt_unit_response.h>
17510Salexander.borisov@nginx.com 
18510Salexander.borisov@nginx.com 
19510Salexander.borisov@nginx.com typedef struct {
20743Smax.romanov@nginx.com     PerlInterpreter          *my_perl;
21743Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
22510Salexander.borisov@nginx.com } nxt_perl_psgi_input_t;
23510Salexander.borisov@nginx.com 
24510Salexander.borisov@nginx.com 
25743Smax.romanov@nginx.com typedef struct {
26743Smax.romanov@nginx.com     PerlInterpreter          *my_perl;
27743Smax.romanov@nginx.com     SV                       *app;
28743Smax.romanov@nginx.com } nxt_perl_psgi_module_t;
29510Salexander.borisov@nginx.com 
30510Salexander.borisov@nginx.com 
31510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl,
32510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length);
33510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl,
34510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length);
35510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_flush(PerlInterpreter *my_perl,
36510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
37510Salexander.borisov@nginx.com 
38510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
39510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length);
40510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
41510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length);
42510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_flush(PerlInterpreter *my_perl,
43510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
44510Salexander.borisov@nginx.com 
45510Salexander.borisov@nginx.com /*
46510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
47510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr);
48510Salexander.borisov@nginx.com */
49510Salexander.borisov@nginx.com 
50510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_init(pTHX);
51510Salexander.borisov@nginx.com 
52510Salexander.borisov@nginx.com static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
53743Smax.romanov@nginx.com     SV *env, SV *app, nxt_unit_request_info_t *req);
54*969Salexander.borisov@nginx.com static SV *nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj,
55*969Salexander.borisov@nginx.com     const char *method, nxt_unit_request_info_t *req);
56510Salexander.borisov@nginx.com 
57510Salexander.borisov@nginx.com /* For currect load XS modules */
58510Salexander.borisov@nginx.com EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
59510Salexander.borisov@nginx.com 
60510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_io_input_init(PerlInterpreter *my_perl,
61510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
62510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl,
63510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
64510Salexander.borisov@nginx.com 
65510Salexander.borisov@nginx.com static PerlInterpreter *nxt_perl_psgi_interpreter_init(nxt_task_t *task,
66743Smax.romanov@nginx.com     char *script, SV **app);
67510Salexander.borisov@nginx.com 
68743Smax.romanov@nginx.com static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl,
69743Smax.romanov@nginx.com     nxt_unit_request_info_t *req, nxt_perl_psgi_input_t *input);
70743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env,
71743Smax.romanov@nginx.com     const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len);
72743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env,
73967Svbart@nginx.com     const char *name, uint32_t name_len, const char *str, uint32_t len);
74743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env,
75743Smax.romanov@nginx.com     const char *name, uint32_t name_len, void *value);
76510Salexander.borisov@nginx.com 
77510Salexander.borisov@nginx.com 
78510Salexander.borisov@nginx.com static u_char *nxt_perl_psgi_module_create(nxt_task_t *task,
79510Salexander.borisov@nginx.com     const char *script);
80510Salexander.borisov@nginx.com 
81743Smax.romanov@nginx.com static nxt_int_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl,
82510Salexander.borisov@nginx.com     SV *result);
83743Smax.romanov@nginx.com static int nxt_perl_psgi_result_head(PerlInterpreter *my_perl,
84743Smax.romanov@nginx.com     SV *sv_head, nxt_unit_request_info_t *req, uint16_t status);
85743Smax.romanov@nginx.com static int nxt_perl_psgi_result_body(PerlInterpreter *my_perl,
86743Smax.romanov@nginx.com     SV *result, nxt_unit_request_info_t *req);
87743Smax.romanov@nginx.com static int nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl,
88743Smax.romanov@nginx.com     SV *sv_body, nxt_unit_request_info_t *req);
89*969Salexander.borisov@nginx.com static int nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body,
90*969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req);
91*969Salexander.borisov@nginx.com static ssize_t nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst,
92*969Salexander.borisov@nginx.com     size_t size);
93743Smax.romanov@nginx.com static int nxt_perl_psgi_result_array(PerlInterpreter *my_perl,
94743Smax.romanov@nginx.com     SV *result, nxt_unit_request_info_t *req);
95510Salexander.borisov@nginx.com 
96510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_init(nxt_task_t *task,
97510Salexander.borisov@nginx.com     nxt_common_app_conf_t *conf);
98743Smax.romanov@nginx.com static void nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req);
99743Smax.romanov@nginx.com static void nxt_perl_psgi_atexit(void);
100510Salexander.borisov@nginx.com 
101510Salexander.borisov@nginx.com typedef SV *(*nxt_perl_psgi_callback_f)(PerlInterpreter *my_perl,
102510Salexander.borisov@nginx.com     SV *env, nxt_task_t *task);
103510Salexander.borisov@nginx.com 
104510Salexander.borisov@nginx.com static PerlInterpreter         *nxt_perl_psgi;
105510Salexander.borisov@nginx.com static nxt_perl_psgi_io_arg_t  nxt_perl_psgi_arg_input, nxt_perl_psgi_arg_error;
106510Salexander.borisov@nginx.com 
107510Salexander.borisov@nginx.com static uint32_t  nxt_perl_psgi_compat[] = {
108510Salexander.borisov@nginx.com     NXT_VERNUM, NXT_DEBUG,
109510Salexander.borisov@nginx.com };
110510Salexander.borisov@nginx.com 
111743Smax.romanov@nginx.com NXT_EXPORT nxt_app_module_t  nxt_app_module = {
112510Salexander.borisov@nginx.com     sizeof(nxt_perl_psgi_compat),
113510Salexander.borisov@nginx.com     nxt_perl_psgi_compat,
114510Salexander.borisov@nginx.com     nxt_string("perl"),
115612Salexander.borisov@nginx.com     PERL_VERSION_STRING,
116510Salexander.borisov@nginx.com     nxt_perl_psgi_init,
117510Salexander.borisov@nginx.com };
118510Salexander.borisov@nginx.com 
119510Salexander.borisov@nginx.com 
120510Salexander.borisov@nginx.com static long
121510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl,
122510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
123510Salexander.borisov@nginx.com {
124510Salexander.borisov@nginx.com     nxt_perl_psgi_input_t  *input;
125510Salexander.borisov@nginx.com 
126510Salexander.borisov@nginx.com     input = (nxt_perl_psgi_input_t *) arg->ctx;
127510Salexander.borisov@nginx.com 
128743Smax.romanov@nginx.com     return nxt_unit_request_read(input->req, vbuf, length);
129510Salexander.borisov@nginx.com }
130510Salexander.borisov@nginx.com 
131510Salexander.borisov@nginx.com 
132510Salexander.borisov@nginx.com static long
133510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl,
134510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
135510Salexander.borisov@nginx.com {
136510Salexander.borisov@nginx.com     return 0;
137510Salexander.borisov@nginx.com }
138510Salexander.borisov@nginx.com 
139510Salexander.borisov@nginx.com 
140510Salexander.borisov@nginx.com static long
141510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_flush(PerlInterpreter *my_perl,
142510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
143510Salexander.borisov@nginx.com {
144510Salexander.borisov@nginx.com     return 0;
145510Salexander.borisov@nginx.com }
146510Salexander.borisov@nginx.com 
147510Salexander.borisov@nginx.com 
148510Salexander.borisov@nginx.com static long
149510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
150510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
151510Salexander.borisov@nginx.com {
152510Salexander.borisov@nginx.com     return 0;
153510Salexander.borisov@nginx.com }
154510Salexander.borisov@nginx.com 
155510Salexander.borisov@nginx.com 
156510Salexander.borisov@nginx.com static long
157510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
158510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
159510Salexander.borisov@nginx.com {
160510Salexander.borisov@nginx.com     nxt_perl_psgi_input_t *input;
161510Salexander.borisov@nginx.com 
162510Salexander.borisov@nginx.com     input = (nxt_perl_psgi_input_t *) arg->ctx;
163743Smax.romanov@nginx.com     nxt_unit_req_error(input->req, "Perl: %s", vbuf);
164510Salexander.borisov@nginx.com 
165510Salexander.borisov@nginx.com     return (long) length;
166510Salexander.borisov@nginx.com }
167510Salexander.borisov@nginx.com 
168510Salexander.borisov@nginx.com 
169510Salexander.borisov@nginx.com static long
170510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_flush(PerlInterpreter *my_perl,
171510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
172510Salexander.borisov@nginx.com {
173510Salexander.borisov@nginx.com     return 0;
174510Salexander.borisov@nginx.com }
175510Salexander.borisov@nginx.com 
176510Salexander.borisov@nginx.com 
177510Salexander.borisov@nginx.com /* In the future it will be necessary to change some Perl functions. */
178510Salexander.borisov@nginx.com /*
179510Salexander.borisov@nginx.com static void
180510Salexander.borisov@nginx.com nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
181510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr)
182510Salexander.borisov@nginx.com {
183510Salexander.borisov@nginx.com     GV  *gv;
184510Salexander.borisov@nginx.com 
185510Salexander.borisov@nginx.com     gv = gv_fetchpv(core, TRUE, SVt_PVCV);
186510Salexander.borisov@nginx.com 
187510Salexander.borisov@nginx.com #ifdef MUTABLE_CV
188510Salexander.borisov@nginx.com     GvCV_set(gv, MUTABLE_CV(SvREFCNT_inc(get_cv(sub, TRUE))));
189510Salexander.borisov@nginx.com #else
190510Salexander.borisov@nginx.com     GvCV_set(gv, (CV *) (SvREFCNT_inc(get_cv(sub, TRUE))));
191510Salexander.borisov@nginx.com #endif
192510Salexander.borisov@nginx.com     GvIMPORTED_CV_on(gv);
193510Salexander.borisov@nginx.com 
194510Salexander.borisov@nginx.com     newXS(sub, sub_addr, __FILE__);
195510Salexander.borisov@nginx.com }
196510Salexander.borisov@nginx.com */
197510Salexander.borisov@nginx.com 
198510Salexander.borisov@nginx.com 
199510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit);
200510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit)
201510Salexander.borisov@nginx.com {
202510Salexander.borisov@nginx.com     I32 ax = POPMARK;
203510Salexander.borisov@nginx.com     Perl_croak(aTHX_ (char *) NULL);
204510Salexander.borisov@nginx.com     XSRETURN_EMPTY;
205510Salexander.borisov@nginx.com }
206510Salexander.borisov@nginx.com 
207510Salexander.borisov@nginx.com 
208510Salexander.borisov@nginx.com static void
209510Salexander.borisov@nginx.com nxt_perl_psgi_xs_init(pTHX)
210510Salexander.borisov@nginx.com {
211510Salexander.borisov@nginx.com /*
212510Salexander.borisov@nginx.com     nxt_perl_psgi_xs_core_global_changes(my_perl, "CORE::GLOBAL::exit",
213510Salexander.borisov@nginx.com                                          "NGINX::Unit::PSGI::exit",
214510Salexander.borisov@nginx.com                                          XS_NGINX__Unit__PSGI_exit);
215510Salexander.borisov@nginx.com */
216510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_init(aTHX);
217510Salexander.borisov@nginx.com 
218510Salexander.borisov@nginx.com     /* DynaLoader for Perl modules who use XS */
219510Salexander.borisov@nginx.com     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
220510Salexander.borisov@nginx.com }
221510Salexander.borisov@nginx.com 
222510Salexander.borisov@nginx.com 
223510Salexander.borisov@nginx.com static SV *
224510Salexander.borisov@nginx.com nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
225743Smax.romanov@nginx.com     SV *env, SV *app, nxt_unit_request_info_t *req)
226510Salexander.borisov@nginx.com {
227510Salexander.borisov@nginx.com     SV  *result;
228510Salexander.borisov@nginx.com 
229510Salexander.borisov@nginx.com     dSP;
230510Salexander.borisov@nginx.com 
231510Salexander.borisov@nginx.com     ENTER;
232510Salexander.borisov@nginx.com     SAVETMPS;
233510Salexander.borisov@nginx.com 
234510Salexander.borisov@nginx.com     PUSHMARK(sp);
235510Salexander.borisov@nginx.com     XPUSHs(env);
236510Salexander.borisov@nginx.com     PUTBACK;
237510Salexander.borisov@nginx.com 
238743Smax.romanov@nginx.com     call_sv(app, G_EVAL|G_SCALAR);
239510Salexander.borisov@nginx.com 
240510Salexander.borisov@nginx.com     SPAGAIN;
241510Salexander.borisov@nginx.com 
242510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
243743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: Failed to run Perl Application: \n%s",
244743Smax.romanov@nginx.com                            SvPV_nolen(ERRSV));
245510Salexander.borisov@nginx.com     }
246510Salexander.borisov@nginx.com 
247510Salexander.borisov@nginx.com     result = POPs;
248510Salexander.borisov@nginx.com     SvREFCNT_inc(result);
249510Salexander.borisov@nginx.com 
250510Salexander.borisov@nginx.com     PUTBACK;
251510Salexander.borisov@nginx.com     FREETMPS;
252510Salexander.borisov@nginx.com     LEAVE;
253510Salexander.borisov@nginx.com 
254510Salexander.borisov@nginx.com     return result;
255510Salexander.borisov@nginx.com }
256510Salexander.borisov@nginx.com 
257510Salexander.borisov@nginx.com 
258*969Salexander.borisov@nginx.com static SV *
259*969Salexander.borisov@nginx.com nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, const char *method,
260*969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req)
261*969Salexander.borisov@nginx.com {
262*969Salexander.borisov@nginx.com     SV  *result;
263*969Salexander.borisov@nginx.com 
264*969Salexander.borisov@nginx.com     dSP;
265*969Salexander.borisov@nginx.com 
266*969Salexander.borisov@nginx.com     ENTER;
267*969Salexander.borisov@nginx.com     SAVETMPS;
268*969Salexander.borisov@nginx.com 
269*969Salexander.borisov@nginx.com     PUSHMARK(sp);
270*969Salexander.borisov@nginx.com     XPUSHs(obj);
271*969Salexander.borisov@nginx.com     PUTBACK;
272*969Salexander.borisov@nginx.com 
273*969Salexander.borisov@nginx.com     call_method(method, G_EVAL|G_SCALAR);
274*969Salexander.borisov@nginx.com 
275*969Salexander.borisov@nginx.com     SPAGAIN;
276*969Salexander.borisov@nginx.com 
277*969Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
278*969Salexander.borisov@nginx.com         nxt_unit_req_error(req, "PSGI: Failed to call method '%s':\n%s",
279*969Salexander.borisov@nginx.com                            method, SvPV_nolen(ERRSV));
280*969Salexander.borisov@nginx.com         result = NULL;
281*969Salexander.borisov@nginx.com 
282*969Salexander.borisov@nginx.com     } else {
283*969Salexander.borisov@nginx.com         result = SvREFCNT_inc(POPs);
284*969Salexander.borisov@nginx.com     }
285*969Salexander.borisov@nginx.com 
286*969Salexander.borisov@nginx.com     PUTBACK;
287*969Salexander.borisov@nginx.com     FREETMPS;
288*969Salexander.borisov@nginx.com     LEAVE;
289*969Salexander.borisov@nginx.com 
290*969Salexander.borisov@nginx.com     return result;
291*969Salexander.borisov@nginx.com }
292*969Salexander.borisov@nginx.com 
293*969Salexander.borisov@nginx.com 
294510Salexander.borisov@nginx.com static u_char *
295510Salexander.borisov@nginx.com nxt_perl_psgi_module_create(nxt_task_t *task, const char *script)
296510Salexander.borisov@nginx.com {
297510Salexander.borisov@nginx.com     u_char  *buf, *p;
298510Salexander.borisov@nginx.com     size_t  length;
299510Salexander.borisov@nginx.com 
300510Salexander.borisov@nginx.com     static nxt_str_t  prefix = nxt_string(
301510Salexander.borisov@nginx.com         "package NGINX::Unit::Sandbox;"
302510Salexander.borisov@nginx.com         "{my $app = do \""
303510Salexander.borisov@nginx.com     );
304510Salexander.borisov@nginx.com 
305510Salexander.borisov@nginx.com     static nxt_str_t  suffix = nxt_string_zero(
306510Salexander.borisov@nginx.com         "\";"
307510Salexander.borisov@nginx.com         "unless ($app) {"
308510Salexander.borisov@nginx.com         "    if($@ || $1) {die $@ || $1}"
309510Salexander.borisov@nginx.com         "    else {die \"File not found or compilation error.\"}"
310510Salexander.borisov@nginx.com         "} "
311510Salexander.borisov@nginx.com         "return $app}"
312510Salexander.borisov@nginx.com     );
313510Salexander.borisov@nginx.com 
314510Salexander.borisov@nginx.com     length = strlen(script);
315510Salexander.borisov@nginx.com 
316510Salexander.borisov@nginx.com     buf = nxt_malloc(prefix.length + length + suffix.length);
317510Salexander.borisov@nginx.com 
318510Salexander.borisov@nginx.com     if (nxt_slow_path(buf == NULL)) {
319510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
320510Salexander.borisov@nginx.com                       "PSGI: Failed to allocate memory "
321510Salexander.borisov@nginx.com                       "for Perl script file %s", script);
322510Salexander.borisov@nginx.com         return NULL;
323510Salexander.borisov@nginx.com     }
324510Salexander.borisov@nginx.com 
325510Salexander.borisov@nginx.com     p = nxt_cpymem(buf, prefix.start, prefix.length);
326510Salexander.borisov@nginx.com     p = nxt_cpymem(p, script, length);
327510Salexander.borisov@nginx.com     nxt_memcpy(p, suffix.start, suffix.length);
328510Salexander.borisov@nginx.com 
329510Salexander.borisov@nginx.com     return buf;
330510Salexander.borisov@nginx.com }
331510Salexander.borisov@nginx.com 
332510Salexander.borisov@nginx.com 
333510Salexander.borisov@nginx.com static nxt_int_t
334510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_init(PerlInterpreter *my_perl,
335510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
336510Salexander.borisov@nginx.com {
337510Salexander.borisov@nginx.com     SV      *io;
338510Salexander.borisov@nginx.com     PerlIO  *fp;
339510Salexander.borisov@nginx.com 
340510Salexander.borisov@nginx.com     fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg, "r");
341510Salexander.borisov@nginx.com 
342510Salexander.borisov@nginx.com     if (nxt_slow_path(fp == NULL)) {
343510Salexander.borisov@nginx.com         return NXT_ERROR;
344510Salexander.borisov@nginx.com     }
345510Salexander.borisov@nginx.com 
346510Salexander.borisov@nginx.com     io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp);
347510Salexander.borisov@nginx.com 
348510Salexander.borisov@nginx.com     if (nxt_slow_path(io == NULL)) {
349510Salexander.borisov@nginx.com         nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp);
350510Salexander.borisov@nginx.com         return NXT_ERROR;
351510Salexander.borisov@nginx.com     }
352510Salexander.borisov@nginx.com 
353510Salexander.borisov@nginx.com     arg->io = io;
354510Salexander.borisov@nginx.com     arg->fp = fp;
355510Salexander.borisov@nginx.com     arg->flush = nxt_perl_psgi_io_input_flush;
356510Salexander.borisov@nginx.com     arg->read = nxt_perl_psgi_io_input_read;
357510Salexander.borisov@nginx.com     arg->write = nxt_perl_psgi_io_input_write;
358510Salexander.borisov@nginx.com 
359510Salexander.borisov@nginx.com     return NXT_OK;
360510Salexander.borisov@nginx.com }
361510Salexander.borisov@nginx.com 
362510Salexander.borisov@nginx.com 
363510Salexander.borisov@nginx.com static nxt_int_t
364510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl,
365510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
366510Salexander.borisov@nginx.com {
367510Salexander.borisov@nginx.com     SV      *io;
368510Salexander.borisov@nginx.com     PerlIO  *fp;
369510Salexander.borisov@nginx.com 
370510Salexander.borisov@nginx.com     fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg, "w");
371510Salexander.borisov@nginx.com 
372510Salexander.borisov@nginx.com     if (nxt_slow_path(fp == NULL)) {
373510Salexander.borisov@nginx.com         return NXT_ERROR;
374510Salexander.borisov@nginx.com     }
375510Salexander.borisov@nginx.com 
376510Salexander.borisov@nginx.com     io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp);
377510Salexander.borisov@nginx.com 
378510Salexander.borisov@nginx.com     if (nxt_slow_path(io == NULL)) {
379510Salexander.borisov@nginx.com         nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp);
380510Salexander.borisov@nginx.com         return NXT_ERROR;
381510Salexander.borisov@nginx.com     }
382510Salexander.borisov@nginx.com 
383510Salexander.borisov@nginx.com     arg->io = io;
384510Salexander.borisov@nginx.com     arg->fp = fp;
385510Salexander.borisov@nginx.com     arg->flush = nxt_perl_psgi_io_error_flush;
386510Salexander.borisov@nginx.com     arg->read = nxt_perl_psgi_io_error_read;
387510Salexander.borisov@nginx.com     arg->write = nxt_perl_psgi_io_error_write;
388510Salexander.borisov@nginx.com 
389510Salexander.borisov@nginx.com     return NXT_OK;
390510Salexander.borisov@nginx.com }
391510Salexander.borisov@nginx.com 
392510Salexander.borisov@nginx.com 
393510Salexander.borisov@nginx.com static PerlInterpreter *
394743Smax.romanov@nginx.com nxt_perl_psgi_interpreter_init(nxt_task_t *task, char *script, SV **app)
395510Salexander.borisov@nginx.com {
396510Salexander.borisov@nginx.com     int              status, pargc;
397510Salexander.borisov@nginx.com     char             **pargv, **penv;
398510Salexander.borisov@nginx.com     u_char           *run_module;
399510Salexander.borisov@nginx.com     PerlInterpreter  *my_perl;
400510Salexander.borisov@nginx.com 
401510Salexander.borisov@nginx.com     static char  argv[] = "\0""-e\0""0";
402510Salexander.borisov@nginx.com     static char  *embedding[] = { &argv[0], &argv[1], &argv[4] };
403510Salexander.borisov@nginx.com 
404510Salexander.borisov@nginx.com     pargc = 0;
405510Salexander.borisov@nginx.com     pargv = NULL;
406510Salexander.borisov@nginx.com     penv = NULL;
407510Salexander.borisov@nginx.com 
408510Salexander.borisov@nginx.com     PERL_SYS_INIT3(&pargc, &pargv, &penv);
409510Salexander.borisov@nginx.com 
410510Salexander.borisov@nginx.com     my_perl = perl_alloc();
411510Salexander.borisov@nginx.com 
412510Salexander.borisov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
413564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to allocate memory for Perl interpreter");
414510Salexander.borisov@nginx.com         return NULL;
415510Salexander.borisov@nginx.com     }
416510Salexander.borisov@nginx.com 
417510Salexander.borisov@nginx.com     run_module = NULL;
418510Salexander.borisov@nginx.com 
419510Salexander.borisov@nginx.com     perl_construct(my_perl);
420510Salexander.borisov@nginx.com     PERL_SET_CONTEXT(my_perl);
421510Salexander.borisov@nginx.com 
422510Salexander.borisov@nginx.com     status = perl_parse(my_perl, nxt_perl_psgi_xs_init, 3, embedding, NULL);
423510Salexander.borisov@nginx.com 
424510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
425564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to parse Perl Script");
426510Salexander.borisov@nginx.com         goto fail;
427510Salexander.borisov@nginx.com     }
428510Salexander.borisov@nginx.com 
429510Salexander.borisov@nginx.com     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
430510Salexander.borisov@nginx.com     PL_origalen = 1;
431510Salexander.borisov@nginx.com 
432510Salexander.borisov@nginx.com     status = perl_run(my_perl);
433510Salexander.borisov@nginx.com 
434510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
435564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to run Perl");
436510Salexander.borisov@nginx.com         goto fail;
437510Salexander.borisov@nginx.com     }
438510Salexander.borisov@nginx.com 
439510Salexander.borisov@nginx.com     sv_setsv(get_sv("0", 0), newSVpv(script, 0));
440510Salexander.borisov@nginx.com 
441510Salexander.borisov@nginx.com     run_module = nxt_perl_psgi_module_create(task, script);
442510Salexander.borisov@nginx.com 
443510Salexander.borisov@nginx.com     if (nxt_slow_path(run_module == NULL)) {
444510Salexander.borisov@nginx.com         goto fail;
445510Salexander.borisov@nginx.com     }
446510Salexander.borisov@nginx.com 
447510Salexander.borisov@nginx.com     status = nxt_perl_psgi_io_input_init(my_perl, &nxt_perl_psgi_arg_input);
448510Salexander.borisov@nginx.com 
449510Salexander.borisov@nginx.com     if (nxt_slow_path(status != NXT_OK)) {
450564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to init io.psgi.input");
451510Salexander.borisov@nginx.com         goto fail;
452510Salexander.borisov@nginx.com     }
453510Salexander.borisov@nginx.com 
454510Salexander.borisov@nginx.com     status = nxt_perl_psgi_io_error_init(my_perl, &nxt_perl_psgi_arg_error);
455510Salexander.borisov@nginx.com 
456510Salexander.borisov@nginx.com     if (nxt_slow_path(status != NXT_OK)) {
457564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to init io.psgi.errors");
458510Salexander.borisov@nginx.com         goto fail;
459510Salexander.borisov@nginx.com     }
460510Salexander.borisov@nginx.com 
461743Smax.romanov@nginx.com     *app = eval_pv((const char *) run_module, FALSE);
462510Salexander.borisov@nginx.com 
463510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
464564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to parse script: %s\n%s",
465564Svbart@nginx.com                   script, SvPV_nolen(ERRSV));
466510Salexander.borisov@nginx.com         goto fail;
467510Salexander.borisov@nginx.com     }
468510Salexander.borisov@nginx.com 
469510Salexander.borisov@nginx.com     nxt_free(run_module);
470510Salexander.borisov@nginx.com 
471510Salexander.borisov@nginx.com     return my_perl;
472510Salexander.borisov@nginx.com 
473510Salexander.borisov@nginx.com fail:
474510Salexander.borisov@nginx.com 
475510Salexander.borisov@nginx.com     if (run_module != NULL) {
476510Salexander.borisov@nginx.com         nxt_free(run_module);
477510Salexander.borisov@nginx.com     }
478510Salexander.borisov@nginx.com 
479510Salexander.borisov@nginx.com     perl_destruct(my_perl);
480510Salexander.borisov@nginx.com     perl_free(my_perl);
481510Salexander.borisov@nginx.com     PERL_SYS_TERM();
482510Salexander.borisov@nginx.com 
483510Salexander.borisov@nginx.com     return NULL;
484510Salexander.borisov@nginx.com }
485510Salexander.borisov@nginx.com 
486510Salexander.borisov@nginx.com 
487743Smax.romanov@nginx.com static SV *
488743Smax.romanov@nginx.com nxt_perl_psgi_env_create(PerlInterpreter *my_perl,
489743Smax.romanov@nginx.com     nxt_unit_request_info_t *req, nxt_perl_psgi_input_t *input)
490510Salexander.borisov@nginx.com {
491743Smax.romanov@nginx.com     HV                  *hash_env;
492743Smax.romanov@nginx.com     AV                  *array_version;
493967Svbart@nginx.com     uint32_t            i;
494743Smax.romanov@nginx.com     nxt_unit_field_t    *f;
495743Smax.romanov@nginx.com     nxt_unit_request_t  *r;
496510Salexander.borisov@nginx.com 
497510Salexander.borisov@nginx.com     hash_env = newHV();
498510Salexander.borisov@nginx.com     if (nxt_slow_path(hash_env == NULL)) {
499510Salexander.borisov@nginx.com         return NULL;
500510Salexander.borisov@nginx.com     }
501510Salexander.borisov@nginx.com 
502743Smax.romanov@nginx.com #define RC(FNS)                                                               \
503743Smax.romanov@nginx.com     do {                                                                      \
504743Smax.romanov@nginx.com         if (nxt_slow_path((FNS) != NXT_UNIT_OK))                              \
505743Smax.romanov@nginx.com             goto fail;                                                        \
506743Smax.romanov@nginx.com      } while (0)
507510Salexander.borisov@nginx.com 
508743Smax.romanov@nginx.com #define NL(S) (S), sizeof(S)-1
509510Salexander.borisov@nginx.com 
510743Smax.romanov@nginx.com     r = req->request;
511673Svbart@nginx.com 
512743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_SOFTWARE"),
513743Smax.romanov@nginx.com                              (char *) nxt_server.start, nxt_server.length));
514510Salexander.borisov@nginx.com 
515743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_METHOD"),
516743Smax.romanov@nginx.com                               &r->method, r->method_length));
517743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_URI"),
518743Smax.romanov@nginx.com                               &r->target, r->target_length));
519743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("PATH_INFO"),
520743Smax.romanov@nginx.com                               &r->path, r->path_length));
521580Salexander.borisov@nginx.com 
522510Salexander.borisov@nginx.com     array_version = newAV();
523510Salexander.borisov@nginx.com 
524510Salexander.borisov@nginx.com     if (nxt_slow_path(array_version == NULL)) {
525510Salexander.borisov@nginx.com         goto fail;
526510Salexander.borisov@nginx.com     }
527510Salexander.borisov@nginx.com 
528510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
529510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
530510Salexander.borisov@nginx.com 
531743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"),
532580Salexander.borisov@nginx.com                                 newRV_noinc((SV *) array_version)));
533743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"),
534510Salexander.borisov@nginx.com                                 newSVpv("http", 4)));
535743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"),
536510Salexander.borisov@nginx.com                                 SvREFCNT_inc(nxt_perl_psgi_arg_input.io)));
537743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"),
538510Salexander.borisov@nginx.com                                 SvREFCNT_inc(nxt_perl_psgi_arg_error.io)));
539743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multithread"),
540580Salexander.borisov@nginx.com                                 &PL_sv_no));
541743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multiprocess"),
542580Salexander.borisov@nginx.com                                 &PL_sv_yes));
543743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.run_once"),
544580Salexander.borisov@nginx.com                                 &PL_sv_no));
545743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.nonblocking"),
546580Salexander.borisov@nginx.com                                 &PL_sv_no));
547743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.streaming"),
548580Salexander.borisov@nginx.com                                 &PL_sv_no));
549510Salexander.borisov@nginx.com 
550743Smax.romanov@nginx.com     if (r->query.offset) {
551743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("QUERY_STRING"),
552743Smax.romanov@nginx.com                                   &r->query, r->query_length));
553743Smax.romanov@nginx.com     }
554743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_PROTOCOL"),
555743Smax.romanov@nginx.com                               &r->version, r->version_length));
556743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REMOTE_ADDR"),
557743Smax.romanov@nginx.com                               &r->remote, r->remote_length));
558743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_ADDR"),
559743Smax.romanov@nginx.com                               &r->local, r->local_length));
560510Salexander.borisov@nginx.com 
561967Svbart@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_NAME"),
562967Svbart@nginx.com                               &r->server_name, r->server_name_length));
563967Svbart@nginx.com     RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_PORT"), "80", 2));
564967Svbart@nginx.com 
565743Smax.romanov@nginx.com     for (i = 0; i < r->fields_count; i++) {
566743Smax.romanov@nginx.com         f = r->fields + i;
567510Salexander.borisov@nginx.com 
568743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env,
569743Smax.romanov@nginx.com                                   nxt_unit_sptr_get(&f->name), f->name_length,
570743Smax.romanov@nginx.com                                   &f->value, f->value_length));
571510Salexander.borisov@nginx.com     }
572510Salexander.borisov@nginx.com 
573743Smax.romanov@nginx.com     if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
574743Smax.romanov@nginx.com         f = r->fields + r->content_length_field;
575510Salexander.borisov@nginx.com 
576743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_LENGTH"),
577743Smax.romanov@nginx.com                                   &f->value, f->value_length));
578743Smax.romanov@nginx.com     }
579510Salexander.borisov@nginx.com 
580743Smax.romanov@nginx.com     if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
581743Smax.romanov@nginx.com         f = r->fields + r->content_type_field;
582743Smax.romanov@nginx.com 
583743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_TYPE"),
584743Smax.romanov@nginx.com                                   &f->value, f->value_length));
585510Salexander.borisov@nginx.com     }
586510Salexander.borisov@nginx.com 
587743Smax.romanov@nginx.com #undef NL
588510Salexander.borisov@nginx.com #undef RC
589510Salexander.borisov@nginx.com 
590510Salexander.borisov@nginx.com     return newRV_noinc((SV *) hash_env);
591510Salexander.borisov@nginx.com 
592510Salexander.borisov@nginx.com fail:
593510Salexander.borisov@nginx.com 
594510Salexander.borisov@nginx.com     SvREFCNT_dec(hash_env);
595510Salexander.borisov@nginx.com 
596510Salexander.borisov@nginx.com     return NULL;
597510Salexander.borisov@nginx.com }
598510Salexander.borisov@nginx.com 
599510Salexander.borisov@nginx.com 
600743Smax.romanov@nginx.com nxt_inline int
601743Smax.romanov@nginx.com nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env,
602743Smax.romanov@nginx.com     const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len)
603743Smax.romanov@nginx.com {
604743Smax.romanov@nginx.com     return nxt_perl_psgi_add_str(my_perl, hash_env, name, name_len,
605743Smax.romanov@nginx.com                                  nxt_unit_sptr_get(sptr), len);
606743Smax.romanov@nginx.com }
607743Smax.romanov@nginx.com 
608743Smax.romanov@nginx.com 
609743Smax.romanov@nginx.com nxt_inline int
610743Smax.romanov@nginx.com nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env,
611967Svbart@nginx.com     const char *name, uint32_t name_len, const char *str, uint32_t len)
612743Smax.romanov@nginx.com {
613743Smax.romanov@nginx.com     SV  **ha;
614743Smax.romanov@nginx.com 
615743Smax.romanov@nginx.com     ha = hv_store(hash_env, name, (I32) name_len,
616743Smax.romanov@nginx.com                   newSVpv(str, (STRLEN) len), 0);
617743Smax.romanov@nginx.com     if (nxt_slow_path(ha == NULL)) {
618743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
619743Smax.romanov@nginx.com     }
620743Smax.romanov@nginx.com 
621743Smax.romanov@nginx.com     return NXT_UNIT_OK;
622743Smax.romanov@nginx.com }
623743Smax.romanov@nginx.com 
624743Smax.romanov@nginx.com 
625743Smax.romanov@nginx.com nxt_inline int
626743Smax.romanov@nginx.com nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env,
627743Smax.romanov@nginx.com     const char *name, uint32_t name_len, void *value)
628743Smax.romanov@nginx.com {
629743Smax.romanov@nginx.com     SV  **ha;
630743Smax.romanov@nginx.com 
631743Smax.romanov@nginx.com     ha = hv_store(hash_env, name, (I32) name_len, value, 0);
632743Smax.romanov@nginx.com     if (nxt_slow_path(ha == NULL)) {
633743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
634743Smax.romanov@nginx.com     }
635743Smax.romanov@nginx.com 
636743Smax.romanov@nginx.com     return NXT_UNIT_OK;
637743Smax.romanov@nginx.com }
638743Smax.romanov@nginx.com 
639743Smax.romanov@nginx.com 
640743Smax.romanov@nginx.com static nxt_int_t
641510Salexander.borisov@nginx.com nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result)
642510Salexander.borisov@nginx.com {
643510Salexander.borisov@nginx.com     SV         **sv_status;
644510Salexander.borisov@nginx.com     AV         *array;
645743Smax.romanov@nginx.com     u_char     *space;
646510Salexander.borisov@nginx.com     nxt_str_t  status;
647510Salexander.borisov@nginx.com 
648510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
649510Salexander.borisov@nginx.com     sv_status = av_fetch(array, 0, 0);
650510Salexander.borisov@nginx.com 
651510Salexander.borisov@nginx.com     status.start = (u_char *) SvPV(*sv_status, status.length);
652510Salexander.borisov@nginx.com 
653743Smax.romanov@nginx.com     space = nxt_memchr(status.start, ' ', status.length);
654743Smax.romanov@nginx.com     if (space != NULL) {
655743Smax.romanov@nginx.com         status.length = space - status.start;
656743Smax.romanov@nginx.com     }
657743Smax.romanov@nginx.com 
658743Smax.romanov@nginx.com     return nxt_int_parse(status.start, status.length);
659510Salexander.borisov@nginx.com }
660510Salexander.borisov@nginx.com 
661510Salexander.borisov@nginx.com 
662743Smax.romanov@nginx.com static int
663510Salexander.borisov@nginx.com nxt_perl_psgi_result_head(PerlInterpreter *my_perl, SV *sv_head,
664743Smax.romanov@nginx.com     nxt_unit_request_info_t *req, uint16_t status)
665510Salexander.borisov@nginx.com {
666510Salexander.borisov@nginx.com     AV         *array_head;
667510Salexander.borisov@nginx.com     SV         **entry;
668743Smax.romanov@nginx.com     int        rc;
669510Salexander.borisov@nginx.com     long       i, array_len;
670743Smax.romanov@nginx.com     char       *name, *value;
671743Smax.romanov@nginx.com     STRLEN     name_len, value_len;
672743Smax.romanov@nginx.com     uint32_t   fields, size;
673510Salexander.borisov@nginx.com 
674510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_head) == 0
675510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_head)) != SVt_PVAV))
676510Salexander.borisov@nginx.com     {
677743Smax.romanov@nginx.com         nxt_unit_req_error(req,
678743Smax.romanov@nginx.com                            "PSGI: An unsupported format was received from "
679743Smax.romanov@nginx.com                            "Perl Application for head part");
680510Salexander.borisov@nginx.com 
681743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
682510Salexander.borisov@nginx.com     }
683510Salexander.borisov@nginx.com 
684510Salexander.borisov@nginx.com     array_head = (AV *) SvRV(sv_head);
685510Salexander.borisov@nginx.com     array_len = av_len(array_head);
686510Salexander.borisov@nginx.com 
687510Salexander.borisov@nginx.com     if (array_len < 1) {
688743Smax.romanov@nginx.com         return nxt_unit_response_init(req, status, 0, 0);
689510Salexander.borisov@nginx.com     }
690510Salexander.borisov@nginx.com 
691510Salexander.borisov@nginx.com     if (nxt_slow_path((array_len % 2) == 0)) {
692743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: Bad format for head from "
693743Smax.romanov@nginx.com                            "Perl Application");
694510Salexander.borisov@nginx.com 
695743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
696510Salexander.borisov@nginx.com     }
697510Salexander.borisov@nginx.com 
698743Smax.romanov@nginx.com     fields = 0;
699743Smax.romanov@nginx.com     size = 0;
700743Smax.romanov@nginx.com 
701510Salexander.borisov@nginx.com     for (i = 0; i <= array_len; i++) {
702510Salexander.borisov@nginx.com         entry = av_fetch(array_head, i, 0);
703510Salexander.borisov@nginx.com 
704510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
705743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get head entry from "
706743Smax.romanov@nginx.com                                "Perl Application");
707510Salexander.borisov@nginx.com 
708743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
709510Salexander.borisov@nginx.com         }
710510Salexander.borisov@nginx.com 
711743Smax.romanov@nginx.com         value = SvPV(*entry, value_len);
712743Smax.romanov@nginx.com         size += value_len;
713510Salexander.borisov@nginx.com 
714510Salexander.borisov@nginx.com         if ((i % 2) == 0) {
715743Smax.romanov@nginx.com             fields++;
716510Salexander.borisov@nginx.com         }
717743Smax.romanov@nginx.com     }
718510Salexander.borisov@nginx.com 
719743Smax.romanov@nginx.com     rc = nxt_unit_response_init(req, status, fields, size);
720743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
721743Smax.romanov@nginx.com         return rc;
722743Smax.romanov@nginx.com     }
723743Smax.romanov@nginx.com 
724743Smax.romanov@nginx.com     for (i = 0; i <= array_len; i += 2) {
725743Smax.romanov@nginx.com         entry = av_fetch(array_head, i, 0);
726743Smax.romanov@nginx.com         name = SvPV(*entry, name_len);
727743Smax.romanov@nginx.com 
728743Smax.romanov@nginx.com         entry = av_fetch(array_head, i + 1, 0);
729743Smax.romanov@nginx.com         value = SvPV(*entry, value_len);
730743Smax.romanov@nginx.com 
731743Smax.romanov@nginx.com         rc = nxt_unit_response_add_field(req, name, name_len, value, value_len);
732743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
733510Salexander.borisov@nginx.com             return rc;
734510Salexander.borisov@nginx.com         }
735510Salexander.borisov@nginx.com     }
736510Salexander.borisov@nginx.com 
737743Smax.romanov@nginx.com     return NXT_UNIT_OK;
738510Salexander.borisov@nginx.com }
739510Salexander.borisov@nginx.com 
740510Salexander.borisov@nginx.com 
741743Smax.romanov@nginx.com static int
742510Salexander.borisov@nginx.com nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body,
743743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
744510Salexander.borisov@nginx.com {
745510Salexander.borisov@nginx.com     SV         **entry;
746510Salexander.borisov@nginx.com     AV         *body_array;
747743Smax.romanov@nginx.com     int        rc;
748510Salexander.borisov@nginx.com     long       i;
749510Salexander.borisov@nginx.com     nxt_str_t  body;
750510Salexander.borisov@nginx.com 
751510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_body) == 0
752510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_body)) != SVt_PVAV))
753510Salexander.borisov@nginx.com     {
754743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: An unsupported format was received from "
755743Smax.romanov@nginx.com                            "Perl Application for a body part");
756510Salexander.borisov@nginx.com 
757743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
758510Salexander.borisov@nginx.com     }
759510Salexander.borisov@nginx.com 
760510Salexander.borisov@nginx.com     body_array = (AV *) SvRV(sv_body);
761510Salexander.borisov@nginx.com 
762510Salexander.borisov@nginx.com     for (i = 0; i <= av_len(body_array); i++) {
763510Salexander.borisov@nginx.com 
764510Salexander.borisov@nginx.com         entry = av_fetch(body_array, i, 0);
765510Salexander.borisov@nginx.com 
766510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
767743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get body entry from "
768743Smax.romanov@nginx.com                                "Perl Application");
769743Smax.romanov@nginx.com 
770743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
771510Salexander.borisov@nginx.com         }
772510Salexander.borisov@nginx.com 
773510Salexander.borisov@nginx.com         body.start = (u_char *) SvPV(*entry, body.length);
774510Salexander.borisov@nginx.com 
775510Salexander.borisov@nginx.com         if (body.length == 0) {
776510Salexander.borisov@nginx.com             continue;
777510Salexander.borisov@nginx.com         }
778510Salexander.borisov@nginx.com 
779743Smax.romanov@nginx.com         rc = nxt_unit_response_write(req, body.start, body.length);
780510Salexander.borisov@nginx.com 
781743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
782743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to write content from "
783743Smax.romanov@nginx.com                                "Perl Application");
784510Salexander.borisov@nginx.com             return rc;
785510Salexander.borisov@nginx.com         }
786510Salexander.borisov@nginx.com     }
787510Salexander.borisov@nginx.com 
788743Smax.romanov@nginx.com     return NXT_UNIT_OK;
789510Salexander.borisov@nginx.com }
790510Salexander.borisov@nginx.com 
791510Salexander.borisov@nginx.com 
792*969Salexander.borisov@nginx.com static int
793*969Salexander.borisov@nginx.com nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body,
794*969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req)
795*969Salexander.borisov@nginx.com {
796*969Salexander.borisov@nginx.com     SV          *data, *old_rs, *old_perl_rs;
797*969Salexander.borisov@nginx.com     int         rc;
798*969Salexander.borisov@nginx.com     size_t      len;
799*969Salexander.borisov@nginx.com     const char  *body;
800*969Salexander.borisov@nginx.com 
801*969Salexander.borisov@nginx.com     /*
802*969Salexander.borisov@nginx.com      * Servers should set the $/ special variable to the buffer size
803*969Salexander.borisov@nginx.com      * when reading content from $body using the getline method.
804*969Salexander.borisov@nginx.com      * This is done by setting $/ with a reference to an integer ($/ = \8192).
805*969Salexander.borisov@nginx.com      */
806*969Salexander.borisov@nginx.com 
807*969Salexander.borisov@nginx.com     old_rs = PL_rs;
808*969Salexander.borisov@nginx.com     old_perl_rs = get_sv("/", GV_ADD);
809*969Salexander.borisov@nginx.com 
810*969Salexander.borisov@nginx.com     PL_rs = sv_2mortal(newRV_noinc(newSViv(nxt_unit_buf_min())));
811*969Salexander.borisov@nginx.com 
812*969Salexander.borisov@nginx.com     sv_setsv(old_perl_rs, PL_rs);
813*969Salexander.borisov@nginx.com 
814*969Salexander.borisov@nginx.com     rc = NXT_UNIT_OK;
815*969Salexander.borisov@nginx.com 
816*969Salexander.borisov@nginx.com     for ( ;; ) {
817*969Salexander.borisov@nginx.com         data = nxt_perl_psgi_call_method(my_perl, sv_body, "getline", req);
818*969Salexander.borisov@nginx.com         if (nxt_slow_path(data == NULL)) {
819*969Salexander.borisov@nginx.com             rc = NXT_UNIT_ERROR;
820*969Salexander.borisov@nginx.com             break;
821*969Salexander.borisov@nginx.com         }
822*969Salexander.borisov@nginx.com 
823*969Salexander.borisov@nginx.com         body = SvPV(data, len);
824*969Salexander.borisov@nginx.com 
825*969Salexander.borisov@nginx.com         if (len == 0) {
826*969Salexander.borisov@nginx.com             SvREFCNT_dec(data);
827*969Salexander.borisov@nginx.com 
828*969Salexander.borisov@nginx.com             data = nxt_perl_psgi_call_method(my_perl, sv_body, "close", req);
829*969Salexander.borisov@nginx.com             if (nxt_fast_path(data != NULL)) {
830*969Salexander.borisov@nginx.com                 SvREFCNT_dec(data);
831*969Salexander.borisov@nginx.com             }
832*969Salexander.borisov@nginx.com 
833*969Salexander.borisov@nginx.com             break;
834*969Salexander.borisov@nginx.com         }
835*969Salexander.borisov@nginx.com 
836*969Salexander.borisov@nginx.com         rc = nxt_unit_response_write(req, body, len);
837*969Salexander.borisov@nginx.com 
838*969Salexander.borisov@nginx.com         SvREFCNT_dec(data);
839*969Salexander.borisov@nginx.com 
840*969Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
841*969Salexander.borisov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to write content from "
842*969Salexander.borisov@nginx.com                                "Perl Application");
843*969Salexander.borisov@nginx.com             break;
844*969Salexander.borisov@nginx.com         }
845*969Salexander.borisov@nginx.com     };
846*969Salexander.borisov@nginx.com 
847*969Salexander.borisov@nginx.com     PL_rs =  old_rs;
848*969Salexander.borisov@nginx.com     sv_setsv(get_sv("/", GV_ADD), old_perl_rs);
849*969Salexander.borisov@nginx.com 
850*969Salexander.borisov@nginx.com     return rc;
851*969Salexander.borisov@nginx.com }
852*969Salexander.borisov@nginx.com 
853*969Salexander.borisov@nginx.com 
854743Smax.romanov@nginx.com typedef struct {
855743Smax.romanov@nginx.com     PerlInterpreter  *my_perl;
856743Smax.romanov@nginx.com     PerlIO           *fp;
857743Smax.romanov@nginx.com } nxt_perl_psgi_io_ctx_t;
858743Smax.romanov@nginx.com 
859743Smax.romanov@nginx.com 
860743Smax.romanov@nginx.com static int
861*969Salexander.borisov@nginx.com nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body,
862743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
863510Salexander.borisov@nginx.com {
864743Smax.romanov@nginx.com     IO                      *io;
865743Smax.romanov@nginx.com     nxt_unit_read_info_t    read_info;
866743Smax.romanov@nginx.com     nxt_perl_psgi_io_ctx_t  io_ctx;
867510Salexander.borisov@nginx.com 
868510Salexander.borisov@nginx.com     io = GvIO(SvRV(sv_body));
869519Salexander.borisov@nginx.com 
870519Salexander.borisov@nginx.com     if (io == NULL) {
871743Smax.romanov@nginx.com         return NXT_UNIT_OK;
872519Salexander.borisov@nginx.com     }
873519Salexander.borisov@nginx.com 
874743Smax.romanov@nginx.com     io_ctx.my_perl = my_perl;
875743Smax.romanov@nginx.com     io_ctx.fp = IoIFP(io);
876510Salexander.borisov@nginx.com 
877743Smax.romanov@nginx.com     read_info.read = nxt_perl_psgi_io_read;
878743Smax.romanov@nginx.com     read_info.eof = PerlIO_eof(io_ctx.fp);
879743Smax.romanov@nginx.com     read_info.buf_size = 8192;
880743Smax.romanov@nginx.com     read_info.data = &io_ctx;
881510Salexander.borisov@nginx.com 
882743Smax.romanov@nginx.com     return nxt_unit_response_write_cb(req, &read_info);
883510Salexander.borisov@nginx.com }
884510Salexander.borisov@nginx.com 
885510Salexander.borisov@nginx.com 
886743Smax.romanov@nginx.com static ssize_t
887743Smax.romanov@nginx.com nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, size_t size)
888743Smax.romanov@nginx.com {
889743Smax.romanov@nginx.com     ssize_t                 res;
890743Smax.romanov@nginx.com     nxt_perl_psgi_io_ctx_t  *ctx;
891743Smax.romanov@nginx.com 
892743Smax.romanov@nginx.com     ctx = read_info->data;
893749Salexander.borisov@nginx.com 
894749Salexander.borisov@nginx.com     dTHXa(ctx->my_perl);
895743Smax.romanov@nginx.com 
896743Smax.romanov@nginx.com     res = PerlIO_read(ctx->fp, dst, size);
897743Smax.romanov@nginx.com 
898743Smax.romanov@nginx.com     read_info->eof = PerlIO_eof(ctx->fp);
899743Smax.romanov@nginx.com 
900743Smax.romanov@nginx.com     return res;
901743Smax.romanov@nginx.com }
902743Smax.romanov@nginx.com 
903743Smax.romanov@nginx.com 
904743Smax.romanov@nginx.com static int
905510Salexander.borisov@nginx.com nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result,
906743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
907510Salexander.borisov@nginx.com {
908510Salexander.borisov@nginx.com     AV         *array;
909510Salexander.borisov@nginx.com     SV         **sv_temp;
910743Smax.romanov@nginx.com     int        rc;
911510Salexander.borisov@nginx.com     long       array_len;
912743Smax.romanov@nginx.com     nxt_int_t  status;
913510Salexander.borisov@nginx.com 
914510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
915510Salexander.borisov@nginx.com     array_len = av_len(array);
916510Salexander.borisov@nginx.com 
917510Salexander.borisov@nginx.com     if (nxt_slow_path(array_len < 0)) {
918743Smax.romanov@nginx.com         nxt_unit_req_error(req,
919743Smax.romanov@nginx.com                            "PSGI: Invalid result format from Perl Application");
920510Salexander.borisov@nginx.com 
921743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
922510Salexander.borisov@nginx.com     }
923510Salexander.borisov@nginx.com 
924743Smax.romanov@nginx.com     status = nxt_perl_psgi_result_status(my_perl, result);
925510Salexander.borisov@nginx.com 
926743Smax.romanov@nginx.com     if (nxt_slow_path(status < 0)) {
927743Smax.romanov@nginx.com         nxt_unit_req_error(req,
928743Smax.romanov@nginx.com                            "PSGI: An unexpected status was received "
929743Smax.romanov@nginx.com                            "from Perl Application");
930510Salexander.borisov@nginx.com 
931743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
932510Salexander.borisov@nginx.com     }
933510Salexander.borisov@nginx.com 
934743Smax.romanov@nginx.com     if (array_len >= 1) {
935743Smax.romanov@nginx.com         sv_temp = av_fetch(array, 1, 0);
936510Salexander.borisov@nginx.com 
937743Smax.romanov@nginx.com         if (nxt_slow_path(sv_temp == NULL)) {
938743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get head from "
939743Smax.romanov@nginx.com                                "Perl ARRAY variable");
940510Salexander.borisov@nginx.com 
941743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
942743Smax.romanov@nginx.com         }
943743Smax.romanov@nginx.com 
944743Smax.romanov@nginx.com         rc = nxt_perl_psgi_result_head(my_perl, *sv_temp, req, status);
945743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
946510Salexander.borisov@nginx.com             return rc;
947510Salexander.borisov@nginx.com         }
948510Salexander.borisov@nginx.com 
949743Smax.romanov@nginx.com     } else {
950743Smax.romanov@nginx.com         return nxt_unit_response_init(req, status, 0, 0);
951510Salexander.borisov@nginx.com     }
952510Salexander.borisov@nginx.com 
953510Salexander.borisov@nginx.com     if (nxt_fast_path(array_len < 2)) {
954743Smax.romanov@nginx.com         return NXT_UNIT_OK;
955510Salexander.borisov@nginx.com     }
956510Salexander.borisov@nginx.com 
957510Salexander.borisov@nginx.com     sv_temp = av_fetch(array, 2, 0);
958510Salexander.borisov@nginx.com 
959519Salexander.borisov@nginx.com     if (nxt_slow_path(sv_temp == NULL || SvROK(*sv_temp) == FALSE)) {
960743Smax.romanov@nginx.com         nxt_unit_req_error(req,
961743Smax.romanov@nginx.com                            "PSGI: Failed to get body from "
962743Smax.romanov@nginx.com                            "Perl ARRAY variable");
963510Salexander.borisov@nginx.com 
964743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
965510Salexander.borisov@nginx.com     }
966510Salexander.borisov@nginx.com 
967510Salexander.borisov@nginx.com     if (SvTYPE(SvRV(*sv_temp)) == SVt_PVAV) {
968743Smax.romanov@nginx.com         return nxt_perl_psgi_result_body(my_perl, *sv_temp, req);
969510Salexander.borisov@nginx.com     }
970510Salexander.borisov@nginx.com 
971*969Salexander.borisov@nginx.com     if (SvTYPE(SvRV(*sv_temp)) == SVt_PVGV) {
972*969Salexander.borisov@nginx.com         return nxt_perl_psgi_result_body_fh(my_perl, *sv_temp, req);
973*969Salexander.borisov@nginx.com     }
974*969Salexander.borisov@nginx.com 
975743Smax.romanov@nginx.com     return nxt_perl_psgi_result_body_ref(my_perl, *sv_temp, req);
976510Salexander.borisov@nginx.com }
977510Salexander.borisov@nginx.com 
978510Salexander.borisov@nginx.com 
979510Salexander.borisov@nginx.com static nxt_int_t
980510Salexander.borisov@nginx.com nxt_perl_psgi_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
981510Salexander.borisov@nginx.com {
982743Smax.romanov@nginx.com     int                     rc;
983743Smax.romanov@nginx.com     nxt_unit_ctx_t          *unit_ctx;
984743Smax.romanov@nginx.com     nxt_unit_init_t         perl_init;
985743Smax.romanov@nginx.com     PerlInterpreter         *my_perl;
986743Smax.romanov@nginx.com     nxt_perl_psgi_module_t  module;
987510Salexander.borisov@nginx.com 
988743Smax.romanov@nginx.com     my_perl = nxt_perl_psgi_interpreter_init(task, conf->u.perl.script,
989743Smax.romanov@nginx.com                                              &module.app);
990510Salexander.borisov@nginx.com 
991510Salexander.borisov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
992510Salexander.borisov@nginx.com         return NXT_ERROR;
993510Salexander.borisov@nginx.com     }
994510Salexander.borisov@nginx.com 
995743Smax.romanov@nginx.com     module.my_perl = my_perl;
996510Salexander.borisov@nginx.com     nxt_perl_psgi = my_perl;
997510Salexander.borisov@nginx.com 
998743Smax.romanov@nginx.com     nxt_unit_default_init(task, &perl_init);
999743Smax.romanov@nginx.com 
1000743Smax.romanov@nginx.com     perl_init.callbacks.request_handler = nxt_perl_psgi_request_handler;
1001743Smax.romanov@nginx.com     perl_init.data = &module;
1002743Smax.romanov@nginx.com 
1003743Smax.romanov@nginx.com     unit_ctx = nxt_unit_init(&perl_init);
1004743Smax.romanov@nginx.com     if (nxt_slow_path(unit_ctx == NULL)) {
1005743Smax.romanov@nginx.com         return NXT_ERROR;
1006743Smax.romanov@nginx.com     }
1007743Smax.romanov@nginx.com 
1008743Smax.romanov@nginx.com     rc = nxt_unit_run(unit_ctx);
1009743Smax.romanov@nginx.com 
1010743Smax.romanov@nginx.com     nxt_unit_done(unit_ctx);
1011743Smax.romanov@nginx.com 
1012743Smax.romanov@nginx.com     nxt_perl_psgi_atexit();
1013743Smax.romanov@nginx.com 
1014743Smax.romanov@nginx.com     exit(rc);
1015743Smax.romanov@nginx.com 
1016510Salexander.borisov@nginx.com     return NXT_OK;
1017510Salexander.borisov@nginx.com }
1018510Salexander.borisov@nginx.com 
1019510Salexander.borisov@nginx.com 
1020743Smax.romanov@nginx.com static void
1021743Smax.romanov@nginx.com nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req)
1022510Salexander.borisov@nginx.com {
1023743Smax.romanov@nginx.com     SV                      *env, *result;
1024743Smax.romanov@nginx.com     nxt_int_t               rc;
1025743Smax.romanov@nginx.com     PerlInterpreter         *my_perl;
1026743Smax.romanov@nginx.com     nxt_perl_psgi_input_t   input;
1027743Smax.romanov@nginx.com     nxt_perl_psgi_module_t  *module;
1028510Salexander.borisov@nginx.com 
1029743Smax.romanov@nginx.com     module = req->unit->data;
1030743Smax.romanov@nginx.com     my_perl = module->my_perl;
1031743Smax.romanov@nginx.com 
1032743Smax.romanov@nginx.com     input.my_perl = my_perl;
1033743Smax.romanov@nginx.com     input.req = req;
1034510Salexander.borisov@nginx.com 
1035510Salexander.borisov@nginx.com     /*
1036510Salexander.borisov@nginx.com      * Create environ variable for perl sub "application".
1037510Salexander.borisov@nginx.com      *  > sub application {
1038510Salexander.borisov@nginx.com      *  >     my ($environ) = @_;
1039510Salexander.borisov@nginx.com      */
1040743Smax.romanov@nginx.com     env = nxt_perl_psgi_env_create(my_perl, req, &input);
1041510Salexander.borisov@nginx.com     if (nxt_slow_path(env == NULL)) {
1042743Smax.romanov@nginx.com         nxt_unit_req_error(req,
1043743Smax.romanov@nginx.com                            "PSGI: Failed to create 'env' for Perl Application");
1044743Smax.romanov@nginx.com         nxt_unit_request_done(req, NXT_UNIT_ERROR);
1045510Salexander.borisov@nginx.com 
1046743Smax.romanov@nginx.com         return;
1047510Salexander.borisov@nginx.com     }
1048510Salexander.borisov@nginx.com 
1049510Salexander.borisov@nginx.com     nxt_perl_psgi_arg_input.ctx = &input;
1050510Salexander.borisov@nginx.com     nxt_perl_psgi_arg_error.ctx = &input;
1051510Salexander.borisov@nginx.com 
1052510Salexander.borisov@nginx.com     /* Call perl sub and get result as SV*. */
1053743Smax.romanov@nginx.com     result = nxt_perl_psgi_call_var_application(my_perl, env, module->app, req);
1054510Salexander.borisov@nginx.com 
1055510Salexander.borisov@nginx.com     /*
1056510Salexander.borisov@nginx.com      * We expect ARRAY ref like a
1057510Salexander.borisov@nginx.com      * ['200', ['Content-Type' => "text/plain"], ["body"]]
1058510Salexander.borisov@nginx.com      */
1059510Salexander.borisov@nginx.com     if (nxt_slow_path(SvOK(result) == 0 || SvROK(result) == 0
1060510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(result)) != SVt_PVAV))
1061510Salexander.borisov@nginx.com     {
1062743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: An unexpected response was received "
1063743Smax.romanov@nginx.com                            "from Perl Application");
1064743Smax.romanov@nginx.com 
1065743Smax.romanov@nginx.com         rc = NXT_UNIT_ERROR;
1066743Smax.romanov@nginx.com 
1067743Smax.romanov@nginx.com     } else {
1068743Smax.romanov@nginx.com         rc = nxt_perl_psgi_result_array(my_perl, result, req);
1069510Salexander.borisov@nginx.com     }
1070510Salexander.borisov@nginx.com 
1071743Smax.romanov@nginx.com     nxt_unit_request_done(req, rc);
1072510Salexander.borisov@nginx.com 
1073510Salexander.borisov@nginx.com     SvREFCNT_dec(result);
1074510Salexander.borisov@nginx.com     SvREFCNT_dec(env);
1075510Salexander.borisov@nginx.com }
1076510Salexander.borisov@nginx.com 
1077510Salexander.borisov@nginx.com 
1078510Salexander.borisov@nginx.com static void
1079743Smax.romanov@nginx.com nxt_perl_psgi_atexit(void)
1080510Salexander.borisov@nginx.com {
1081510Salexander.borisov@nginx.com     dTHXa(nxt_perl_psgi);
1082510Salexander.borisov@nginx.com 
1083510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_io_destroy(aTHX_ nxt_perl_psgi_arg_input.io);
1084510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ nxt_perl_psgi_arg_input.fp);
1085510Salexander.borisov@nginx.com 
1086510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_io_destroy(aTHX_ nxt_perl_psgi_arg_error.io);
1087510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ nxt_perl_psgi_arg_error.fp);
1088510Salexander.borisov@nginx.com 
1089510Salexander.borisov@nginx.com     perl_destruct(nxt_perl_psgi);
1090510Salexander.borisov@nginx.com     perl_free(nxt_perl_psgi);
1091510Salexander.borisov@nginx.com     PERL_SYS_TERM();
1092510Salexander.borisov@nginx.com }
1093