xref: /unit/src/perl/nxt_perl_psgi.c (revision 2078)
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;
211689Smax.romanov@nginx.com     nxt_perl_psgi_io_arg_t   arg_input;
221689Smax.romanov@nginx.com     nxt_perl_psgi_io_arg_t   arg_error;
231689Smax.romanov@nginx.com     SV                       *app;
241689Smax.romanov@nginx.com     CV                       *cb;
25743Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
261689Smax.romanov@nginx.com     pthread_t                thread;
271689Smax.romanov@nginx.com     nxt_unit_ctx_t           *ctx;
281689Smax.romanov@nginx.com } nxt_perl_psgi_ctx_t;
29510Salexander.borisov@nginx.com 
30510Salexander.borisov@nginx.com 
312060Smax.romanov@nginx.com static SSize_t 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);
332060Smax.romanov@nginx.com static SSize_t 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 
362060Smax.romanov@nginx.com static SSize_t nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
37510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length);
382060Smax.romanov@nginx.com static SSize_t nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
39510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length);
40510Salexander.borisov@nginx.com 
41510Salexander.borisov@nginx.com /*
42510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
43510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr);
44510Salexander.borisov@nginx.com */
45510Salexander.borisov@nginx.com 
46510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_init(pTHX);
47510Salexander.borisov@nginx.com 
48510Salexander.borisov@nginx.com static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
49743Smax.romanov@nginx.com     SV *env, SV *app, nxt_unit_request_info_t *req);
50969Salexander.borisov@nginx.com static SV *nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj,
51969Salexander.borisov@nginx.com     const char *method, nxt_unit_request_info_t *req);
52510Salexander.borisov@nginx.com 
53510Salexander.borisov@nginx.com /* For currect load XS modules */
54510Salexander.borisov@nginx.com EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
55510Salexander.borisov@nginx.com 
562060Smax.romanov@nginx.com static int nxt_perl_psgi_io_init(PerlInterpreter *my_perl,
572060Smax.romanov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const char *mode, void *req);
58510Salexander.borisov@nginx.com 
591689Smax.romanov@nginx.com static int nxt_perl_psgi_ctx_init(const char *script,
601689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t *pctx);
61510Salexander.borisov@nginx.com 
62743Smax.romanov@nginx.com static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl,
631689Smax.romanov@nginx.com     nxt_unit_request_info_t *req);
64743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env,
65743Smax.romanov@nginx.com     const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len);
66743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env,
67967Svbart@nginx.com     const char *name, uint32_t name_len, const char *str, uint32_t len);
68743Smax.romanov@nginx.com nxt_inline int nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env,
69743Smax.romanov@nginx.com     const char *name, uint32_t name_len, void *value);
70510Salexander.borisov@nginx.com 
71510Salexander.borisov@nginx.com 
721689Smax.romanov@nginx.com static char *nxt_perl_psgi_module_create(const char *script);
73510Salexander.borisov@nginx.com 
74743Smax.romanov@nginx.com static nxt_int_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl,
75510Salexander.borisov@nginx.com     SV *result);
76743Smax.romanov@nginx.com static int nxt_perl_psgi_result_head(PerlInterpreter *my_perl,
77743Smax.romanov@nginx.com     SV *sv_head, nxt_unit_request_info_t *req, uint16_t status);
78743Smax.romanov@nginx.com static int nxt_perl_psgi_result_body(PerlInterpreter *my_perl,
79743Smax.romanov@nginx.com     SV *result, nxt_unit_request_info_t *req);
80743Smax.romanov@nginx.com static int nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl,
81743Smax.romanov@nginx.com     SV *sv_body, nxt_unit_request_info_t *req);
82969Salexander.borisov@nginx.com static int nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body,
83969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req);
84969Salexander.borisov@nginx.com static ssize_t nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst,
85969Salexander.borisov@nginx.com     size_t size);
86743Smax.romanov@nginx.com static int nxt_perl_psgi_result_array(PerlInterpreter *my_perl,
87743Smax.romanov@nginx.com     SV *result, nxt_unit_request_info_t *req);
88986Salexander.borisov@nginx.com static void nxt_perl_psgi_result_cb(PerlInterpreter *my_perl, SV *result,
89986Salexander.borisov@nginx.com     nxt_unit_request_info_t *req);
90510Salexander.borisov@nginx.com 
911488St.nateldemoura@f5.com static nxt_int_t nxt_perl_psgi_start(nxt_task_t *task,
921689Smax.romanov@nginx.com     nxt_process_data_t *data);
93743Smax.romanov@nginx.com static void nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req);
941689Smax.romanov@nginx.com static int nxt_perl_psgi_ready_handler(nxt_unit_ctx_t *ctx);
951689Smax.romanov@nginx.com static void *nxt_perl_psgi_thread_func(void *main_ctx);
961689Smax.romanov@nginx.com static int nxt_perl_psgi_init_threads(nxt_perl_app_conf_t *c);
971689Smax.romanov@nginx.com static void nxt_perl_psgi_join_threads(nxt_unit_ctx_t *ctx,
981689Smax.romanov@nginx.com     nxt_perl_app_conf_t *c);
991689Smax.romanov@nginx.com static void nxt_perl_psgi_ctx_free(nxt_perl_psgi_ctx_t *pctx);
100510Salexander.borisov@nginx.com 
1011689Smax.romanov@nginx.com static CV                   *nxt_perl_psgi_write;
1021689Smax.romanov@nginx.com static CV                   *nxt_perl_psgi_close;
1031689Smax.romanov@nginx.com static CV                   *nxt_perl_psgi_cb;
1041689Smax.romanov@nginx.com static pthread_attr_t       *nxt_perl_psgi_thread_attr;
1051689Smax.romanov@nginx.com static nxt_perl_psgi_ctx_t  *nxt_perl_psgi_ctxs;
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,
1161489St.nateldemoura@f5.com     NULL,
1171489St.nateldemoura@f5.com     0,
118977Smax.romanov@gmail.com     NULL,
1191488St.nateldemoura@f5.com     nxt_perl_psgi_start,
120510Salexander.borisov@nginx.com };
121510Salexander.borisov@nginx.com 
1222060Smax.romanov@nginx.com const nxt_perl_psgi_io_tab_t nxt_perl_psgi_io_tab_input = {
1232060Smax.romanov@nginx.com     .read = nxt_perl_psgi_io_input_read,
1242060Smax.romanov@nginx.com     .write = nxt_perl_psgi_io_input_write,
1252060Smax.romanov@nginx.com };
126510Salexander.borisov@nginx.com 
1272060Smax.romanov@nginx.com const nxt_perl_psgi_io_tab_t nxt_perl_psgi_io_tab_error = {
1282060Smax.romanov@nginx.com     .read = nxt_perl_psgi_io_error_read,
1292060Smax.romanov@nginx.com     .write = nxt_perl_psgi_io_error_write,
1302060Smax.romanov@nginx.com };
1312060Smax.romanov@nginx.com 
1322060Smax.romanov@nginx.com 
1332060Smax.romanov@nginx.com static SSize_t
134510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl,
135510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
136510Salexander.borisov@nginx.com {
1372060Smax.romanov@nginx.com     return nxt_unit_request_read(arg->req, vbuf, length);
138510Salexander.borisov@nginx.com }
139510Salexander.borisov@nginx.com 
140510Salexander.borisov@nginx.com 
1412060Smax.romanov@nginx.com static SSize_t
142510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl,
143510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
144510Salexander.borisov@nginx.com {
145510Salexander.borisov@nginx.com     return 0;
146510Salexander.borisov@nginx.com }
147510Salexander.borisov@nginx.com 
148510Salexander.borisov@nginx.com 
1492060Smax.romanov@nginx.com static SSize_t
150510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
151510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
152510Salexander.borisov@nginx.com {
153510Salexander.borisov@nginx.com     return 0;
154510Salexander.borisov@nginx.com }
155510Salexander.borisov@nginx.com 
156510Salexander.borisov@nginx.com 
1572060Smax.romanov@nginx.com static SSize_t
158510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
159510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
160510Salexander.borisov@nginx.com {
1612060Smax.romanov@nginx.com     nxt_unit_req_error(arg->req, "Perl: %s", (const char*) vbuf);
162510Salexander.borisov@nginx.com 
1632060Smax.romanov@nginx.com     return (SSize_t) length;
164510Salexander.borisov@nginx.com }
165510Salexander.borisov@nginx.com 
166510Salexander.borisov@nginx.com 
167510Salexander.borisov@nginx.com /* In the future it will be necessary to change some Perl functions. */
168510Salexander.borisov@nginx.com /*
169510Salexander.borisov@nginx.com static void
170510Salexander.borisov@nginx.com nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
171510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr)
172510Salexander.borisov@nginx.com {
173510Salexander.borisov@nginx.com     GV  *gv;
174510Salexander.borisov@nginx.com 
175510Salexander.borisov@nginx.com     gv = gv_fetchpv(core, TRUE, SVt_PVCV);
176510Salexander.borisov@nginx.com 
177510Salexander.borisov@nginx.com #ifdef MUTABLE_CV
178510Salexander.borisov@nginx.com     GvCV_set(gv, MUTABLE_CV(SvREFCNT_inc(get_cv(sub, TRUE))));
179510Salexander.borisov@nginx.com #else
180510Salexander.borisov@nginx.com     GvCV_set(gv, (CV *) (SvREFCNT_inc(get_cv(sub, TRUE))));
181510Salexander.borisov@nginx.com #endif
182510Salexander.borisov@nginx.com     GvIMPORTED_CV_on(gv);
183510Salexander.borisov@nginx.com 
184510Salexander.borisov@nginx.com     newXS(sub, sub_addr, __FILE__);
185510Salexander.borisov@nginx.com }
186510Salexander.borisov@nginx.com */
187510Salexander.borisov@nginx.com 
188510Salexander.borisov@nginx.com 
189510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit);
190510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit)
191510Salexander.borisov@nginx.com {
192510Salexander.borisov@nginx.com     I32 ax = POPMARK;
193510Salexander.borisov@nginx.com     Perl_croak(aTHX_ (char *) NULL);
194510Salexander.borisov@nginx.com     XSRETURN_EMPTY;
195510Salexander.borisov@nginx.com }
196510Salexander.borisov@nginx.com 
197510Salexander.borisov@nginx.com 
198986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_write);
199986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_write)
200986Salexander.borisov@nginx.com {
2011689Smax.romanov@nginx.com     int                  rc;
2021689Smax.romanov@nginx.com     char                 *body;
2031689Smax.romanov@nginx.com     size_t               len;
2041689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
205986Salexander.borisov@nginx.com 
206986Salexander.borisov@nginx.com     dXSARGS;
207986Salexander.borisov@nginx.com 
208986Salexander.borisov@nginx.com     if (nxt_slow_path(items != 2)) {
209986Salexander.borisov@nginx.com         Perl_croak(aTHX_ "Wrong number of arguments. Need one string");
210986Salexander.borisov@nginx.com 
211986Salexander.borisov@nginx.com         XSRETURN_EMPTY;
212986Salexander.borisov@nginx.com     }
213986Salexander.borisov@nginx.com 
214986Salexander.borisov@nginx.com     body = SvPV(ST(1), len);
215986Salexander.borisov@nginx.com 
2161689Smax.romanov@nginx.com     pctx = CvXSUBANY(cv).any_ptr;
2171689Smax.romanov@nginx.com 
2181689Smax.romanov@nginx.com     rc = nxt_unit_response_write(pctx->req, body, len);
219986Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
220986Salexander.borisov@nginx.com         Perl_croak(aTHX_ "Failed to write response body");
221986Salexander.borisov@nginx.com 
222986Salexander.borisov@nginx.com         XSRETURN_EMPTY;
223986Salexander.borisov@nginx.com     }
224986Salexander.borisov@nginx.com 
225986Salexander.borisov@nginx.com     XSRETURN_IV(len);
226986Salexander.borisov@nginx.com }
227986Salexander.borisov@nginx.com 
228986Salexander.borisov@nginx.com 
229986Salexander.borisov@nginx.com nxt_inline void
2301689Smax.romanov@nginx.com nxt_perl_psgi_cb_request_done(nxt_perl_psgi_ctx_t *pctx, int status)
231986Salexander.borisov@nginx.com {
2321689Smax.romanov@nginx.com     if (pctx->req != NULL) {
2331689Smax.romanov@nginx.com         nxt_unit_request_done(pctx->req, status);
2341689Smax.romanov@nginx.com         pctx->req = NULL;
235986Salexander.borisov@nginx.com     }
236986Salexander.borisov@nginx.com }
237986Salexander.borisov@nginx.com 
238986Salexander.borisov@nginx.com 
239986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_close);
240986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_close)
241986Salexander.borisov@nginx.com {
242986Salexander.borisov@nginx.com     I32  ax;
243986Salexander.borisov@nginx.com 
244986Salexander.borisov@nginx.com     ax = POPMARK;
245986Salexander.borisov@nginx.com 
2461689Smax.romanov@nginx.com     nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_OK);
247986Salexander.borisov@nginx.com 
248986Salexander.borisov@nginx.com     XSRETURN_NO;
249986Salexander.borisov@nginx.com }
250986Salexander.borisov@nginx.com 
251986Salexander.borisov@nginx.com 
252986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_cb);
253986Salexander.borisov@nginx.com XS(XS_NGINX__Unit__Sandbox_cb)
254986Salexander.borisov@nginx.com {
2551689Smax.romanov@nginx.com     SV                   *obj;
2561689Smax.romanov@nginx.com     int                  rc;
2571689Smax.romanov@nginx.com     long                 array_len;
2581689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
259986Salexander.borisov@nginx.com 
260986Salexander.borisov@nginx.com     dXSARGS;
261986Salexander.borisov@nginx.com 
262986Salexander.borisov@nginx.com     if (nxt_slow_path(items != 1)) {
2631689Smax.romanov@nginx.com         nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR);
264986Salexander.borisov@nginx.com 
265986Salexander.borisov@nginx.com         Perl_croak(aTHX_ "Wrong number of arguments");
266986Salexander.borisov@nginx.com 
267986Salexander.borisov@nginx.com         XSRETURN_EMPTY;
268986Salexander.borisov@nginx.com     }
269986Salexander.borisov@nginx.com 
270986Salexander.borisov@nginx.com     if (nxt_slow_path(SvOK(ST(0)) == 0 || SvROK(ST(0)) == 0
271986Salexander.borisov@nginx.com                       || SvTYPE(SvRV(ST(0))) != SVt_PVAV))
272986Salexander.borisov@nginx.com     {
2731689Smax.romanov@nginx.com         nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR);
274986Salexander.borisov@nginx.com 
275986Salexander.borisov@nginx.com         Perl_croak(aTHX_ "PSGI: An unexpected response was received "
276986Salexander.borisov@nginx.com                    "from Perl Application");
277986Salexander.borisov@nginx.com 
278986Salexander.borisov@nginx.com         XSRETURN_EMPTY;
279986Salexander.borisov@nginx.com     }
280986Salexander.borisov@nginx.com 
2811689Smax.romanov@nginx.com     pctx = CvXSUBANY(cv).any_ptr;
2821689Smax.romanov@nginx.com 
2831689Smax.romanov@nginx.com     rc = nxt_perl_psgi_result_array(PERL_GET_CONTEXT, ST(0), pctx->req);
284986Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
2851689Smax.romanov@nginx.com         nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_ERROR);
286986Salexander.borisov@nginx.com 
287986Salexander.borisov@nginx.com         Perl_croak(aTHX_ (char *) NULL);
288986Salexander.borisov@nginx.com 
289986Salexander.borisov@nginx.com         XSRETURN_EMPTY;
290986Salexander.borisov@nginx.com     }
291986Salexander.borisov@nginx.com 
292986Salexander.borisov@nginx.com     array_len = av_len((AV *) SvRV(ST(0)));
293986Salexander.borisov@nginx.com 
294986Salexander.borisov@nginx.com     if (array_len < 2) {
295986Salexander.borisov@nginx.com         obj = sv_bless(newRV_noinc((SV *) newHV()),
296986Salexander.borisov@nginx.com                        gv_stashpv("NGINX::Unit::Sandbox", GV_ADD));
297986Salexander.borisov@nginx.com         ST(0) = obj;
298986Salexander.borisov@nginx.com 
299986Salexander.borisov@nginx.com         XSRETURN(1);
300986Salexander.borisov@nginx.com     }
301986Salexander.borisov@nginx.com 
3021689Smax.romanov@nginx.com     nxt_perl_psgi_cb_request_done(CvXSUBANY(cv).any_ptr, NXT_UNIT_OK);
303986Salexander.borisov@nginx.com 
304986Salexander.borisov@nginx.com     XSRETURN_EMPTY;
305986Salexander.borisov@nginx.com }
306986Salexander.borisov@nginx.com 
307986Salexander.borisov@nginx.com 
308510Salexander.borisov@nginx.com static void
309510Salexander.borisov@nginx.com nxt_perl_psgi_xs_init(pTHX)
310510Salexander.borisov@nginx.com {
311510Salexander.borisov@nginx.com /*
312510Salexander.borisov@nginx.com     nxt_perl_psgi_xs_core_global_changes(my_perl, "CORE::GLOBAL::exit",
313510Salexander.borisov@nginx.com                                          "NGINX::Unit::PSGI::exit",
314510Salexander.borisov@nginx.com                                          XS_NGINX__Unit__PSGI_exit);
315510Salexander.borisov@nginx.com */
316510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_init(aTHX);
317510Salexander.borisov@nginx.com 
318510Salexander.borisov@nginx.com     /* DynaLoader for Perl modules who use XS */
319510Salexander.borisov@nginx.com     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
320986Salexander.borisov@nginx.com 
3211689Smax.romanov@nginx.com     nxt_perl_psgi_write = newXS("NGINX::Unit::Sandbox::write",
3221689Smax.romanov@nginx.com                                 XS_NGINX__Unit__Sandbox_write, __FILE__);
3231689Smax.romanov@nginx.com 
3241689Smax.romanov@nginx.com     nxt_perl_psgi_close = newXS("NGINX::Unit::Sandbox::close",
3251689Smax.romanov@nginx.com                                 XS_NGINX__Unit__Sandbox_close, __FILE__);
326986Salexander.borisov@nginx.com 
327986Salexander.borisov@nginx.com     nxt_perl_psgi_cb = newXS("NGINX::Unit::Sandbox::cb",
328986Salexander.borisov@nginx.com                              XS_NGINX__Unit__Sandbox_cb, __FILE__);
329510Salexander.borisov@nginx.com }
330510Salexander.borisov@nginx.com 
331510Salexander.borisov@nginx.com 
332510Salexander.borisov@nginx.com static SV *
333510Salexander.borisov@nginx.com nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
334743Smax.romanov@nginx.com     SV *env, SV *app, nxt_unit_request_info_t *req)
335510Salexander.borisov@nginx.com {
336510Salexander.borisov@nginx.com     SV  *result;
337510Salexander.borisov@nginx.com 
338510Salexander.borisov@nginx.com     dSP;
339510Salexander.borisov@nginx.com 
340510Salexander.borisov@nginx.com     ENTER;
341510Salexander.borisov@nginx.com     SAVETMPS;
342510Salexander.borisov@nginx.com 
343510Salexander.borisov@nginx.com     PUSHMARK(sp);
344510Salexander.borisov@nginx.com     XPUSHs(env);
345510Salexander.borisov@nginx.com     PUTBACK;
346510Salexander.borisov@nginx.com 
347743Smax.romanov@nginx.com     call_sv(app, G_EVAL|G_SCALAR);
348510Salexander.borisov@nginx.com 
349510Salexander.borisov@nginx.com     SPAGAIN;
350510Salexander.borisov@nginx.com 
351510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
352743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: Failed to run Perl Application: \n%s",
353743Smax.romanov@nginx.com                            SvPV_nolen(ERRSV));
354510Salexander.borisov@nginx.com     }
355510Salexander.borisov@nginx.com 
356510Salexander.borisov@nginx.com     result = POPs;
357510Salexander.borisov@nginx.com     SvREFCNT_inc(result);
358510Salexander.borisov@nginx.com 
359510Salexander.borisov@nginx.com     PUTBACK;
360510Salexander.borisov@nginx.com     FREETMPS;
361510Salexander.borisov@nginx.com     LEAVE;
362510Salexander.borisov@nginx.com 
363510Salexander.borisov@nginx.com     return result;
364510Salexander.borisov@nginx.com }
365510Salexander.borisov@nginx.com 
366510Salexander.borisov@nginx.com 
367969Salexander.borisov@nginx.com static SV *
368969Salexander.borisov@nginx.com nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, const char *method,
369969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req)
370969Salexander.borisov@nginx.com {
371969Salexander.borisov@nginx.com     SV  *result;
372969Salexander.borisov@nginx.com 
373969Salexander.borisov@nginx.com     dSP;
374969Salexander.borisov@nginx.com 
375969Salexander.borisov@nginx.com     ENTER;
376969Salexander.borisov@nginx.com     SAVETMPS;
377969Salexander.borisov@nginx.com 
378969Salexander.borisov@nginx.com     PUSHMARK(sp);
379969Salexander.borisov@nginx.com     XPUSHs(obj);
380969Salexander.borisov@nginx.com     PUTBACK;
381969Salexander.borisov@nginx.com 
382969Salexander.borisov@nginx.com     call_method(method, G_EVAL|G_SCALAR);
383969Salexander.borisov@nginx.com 
384969Salexander.borisov@nginx.com     SPAGAIN;
385969Salexander.borisov@nginx.com 
386969Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
387969Salexander.borisov@nginx.com         nxt_unit_req_error(req, "PSGI: Failed to call method '%s':\n%s",
388969Salexander.borisov@nginx.com                            method, SvPV_nolen(ERRSV));
389969Salexander.borisov@nginx.com         result = NULL;
390969Salexander.borisov@nginx.com 
391969Salexander.borisov@nginx.com     } else {
392969Salexander.borisov@nginx.com         result = SvREFCNT_inc(POPs);
393969Salexander.borisov@nginx.com     }
394969Salexander.borisov@nginx.com 
395969Salexander.borisov@nginx.com     PUTBACK;
396969Salexander.borisov@nginx.com     FREETMPS;
397969Salexander.borisov@nginx.com     LEAVE;
398969Salexander.borisov@nginx.com 
399969Salexander.borisov@nginx.com     return result;
400969Salexander.borisov@nginx.com }
401969Salexander.borisov@nginx.com 
402969Salexander.borisov@nginx.com 
4031689Smax.romanov@nginx.com static char *
4041689Smax.romanov@nginx.com nxt_perl_psgi_module_create(const char *script)
405510Salexander.borisov@nginx.com {
4061689Smax.romanov@nginx.com     char    *buf, *p;
407510Salexander.borisov@nginx.com     size_t  length;
408510Salexander.borisov@nginx.com 
409510Salexander.borisov@nginx.com     static nxt_str_t  prefix = nxt_string(
410510Salexander.borisov@nginx.com         "package NGINX::Unit::Sandbox;"
411986Salexander.borisov@nginx.com         "sub new {"
412986Salexander.borisov@nginx.com         "   return bless {}, $_[0];"
413986Salexander.borisov@nginx.com         "}"
414510Salexander.borisov@nginx.com         "{my $app = do \""
415510Salexander.borisov@nginx.com     );
416510Salexander.borisov@nginx.com 
417510Salexander.borisov@nginx.com     static nxt_str_t  suffix = nxt_string_zero(
418510Salexander.borisov@nginx.com         "\";"
419510Salexander.borisov@nginx.com         "unless ($app) {"
420510Salexander.borisov@nginx.com         "    if($@ || $1) {die $@ || $1}"
421510Salexander.borisov@nginx.com         "    else {die \"File not found or compilation error.\"}"
422510Salexander.borisov@nginx.com         "} "
423510Salexander.borisov@nginx.com         "return $app}"
424510Salexander.borisov@nginx.com     );
425510Salexander.borisov@nginx.com 
426510Salexander.borisov@nginx.com     length = strlen(script);
427510Salexander.borisov@nginx.com 
4281689Smax.romanov@nginx.com     buf = nxt_unit_malloc(NULL, prefix.length + length + suffix.length);
429510Salexander.borisov@nginx.com     if (nxt_slow_path(buf == NULL)) {
4301689Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to allocate memory "
4311689Smax.romanov@nginx.com                        "for Perl script file %s", script);
4321689Smax.romanov@nginx.com 
433510Salexander.borisov@nginx.com         return NULL;
434510Salexander.borisov@nginx.com     }
435510Salexander.borisov@nginx.com 
436510Salexander.borisov@nginx.com     p = nxt_cpymem(buf, prefix.start, prefix.length);
437510Salexander.borisov@nginx.com     p = nxt_cpymem(p, script, length);
438510Salexander.borisov@nginx.com     nxt_memcpy(p, suffix.start, suffix.length);
439510Salexander.borisov@nginx.com 
440510Salexander.borisov@nginx.com     return buf;
441510Salexander.borisov@nginx.com }
442510Salexander.borisov@nginx.com 
443510Salexander.borisov@nginx.com 
4442060Smax.romanov@nginx.com static int
4452060Smax.romanov@nginx.com nxt_perl_psgi_io_init(PerlInterpreter *my_perl,
4462060Smax.romanov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const char *mode, void *req)
447510Salexander.borisov@nginx.com {
448510Salexander.borisov@nginx.com     SV      *io;
449510Salexander.borisov@nginx.com     PerlIO  *fp;
450510Salexander.borisov@nginx.com 
4512060Smax.romanov@nginx.com     if (arg->io == NULL) {
4522060Smax.romanov@nginx.com         fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg->rv, mode);
4532060Smax.romanov@nginx.com         if (nxt_slow_path(fp == NULL)) {
4542060Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
4552060Smax.romanov@nginx.com         }
456510Salexander.borisov@nginx.com 
4572060Smax.romanov@nginx.com         io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp);
4582060Smax.romanov@nginx.com         if (nxt_slow_path(io == NULL)) {
4592060Smax.romanov@nginx.com             nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp);
4602060Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
4612060Smax.romanov@nginx.com         }
4622060Smax.romanov@nginx.com 
4632060Smax.romanov@nginx.com         arg->io = io;
4642060Smax.romanov@nginx.com         arg->fp = fp;
465510Salexander.borisov@nginx.com     }
466510Salexander.borisov@nginx.com 
4672060Smax.romanov@nginx.com     arg->req = req;
468510Salexander.borisov@nginx.com 
4692060Smax.romanov@nginx.com     return NXT_UNIT_OK;
470510Salexander.borisov@nginx.com }
471510Salexander.borisov@nginx.com 
472510Salexander.borisov@nginx.com 
4732060Smax.romanov@nginx.com static void
4742060Smax.romanov@nginx.com nxt_perl_psgi_io_release(PerlInterpreter *my_perl, nxt_perl_psgi_io_arg_t *arg)
475510Salexander.borisov@nginx.com {
4762060Smax.romanov@nginx.com     if (arg->io != NULL) {
4772060Smax.romanov@nginx.com         SvREFCNT_dec(arg->io);
4782060Smax.romanov@nginx.com         arg->io = NULL;
479510Salexander.borisov@nginx.com     }
480510Salexander.borisov@nginx.com }
481510Salexander.borisov@nginx.com 
482510Salexander.borisov@nginx.com 
4831689Smax.romanov@nginx.com static int
4841689Smax.romanov@nginx.com nxt_perl_psgi_ctx_init(const char *script, nxt_perl_psgi_ctx_t *pctx)
485510Salexander.borisov@nginx.com {
4862060Smax.romanov@nginx.com     int              status, res;
4871689Smax.romanov@nginx.com     char             *run_module;
488510Salexander.borisov@nginx.com     PerlInterpreter  *my_perl;
489510Salexander.borisov@nginx.com 
490510Salexander.borisov@nginx.com     static char  argv[] = "\0""-e\0""0";
491510Salexander.borisov@nginx.com     static char  *embedding[] = { &argv[0], &argv[1], &argv[4] };
492510Salexander.borisov@nginx.com 
493510Salexander.borisov@nginx.com     my_perl = perl_alloc();
494510Salexander.borisov@nginx.com 
495510Salexander.borisov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
4961689Smax.romanov@nginx.com         nxt_unit_alert(NULL,
4971689Smax.romanov@nginx.com                        "PSGI: Failed to allocate memory for Perl interpreter");
4981689Smax.romanov@nginx.com 
4991689Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
500510Salexander.borisov@nginx.com     }
501510Salexander.borisov@nginx.com 
5021689Smax.romanov@nginx.com     pctx->my_perl = my_perl;
5031689Smax.romanov@nginx.com 
504510Salexander.borisov@nginx.com     run_module = NULL;
505510Salexander.borisov@nginx.com 
506510Salexander.borisov@nginx.com     perl_construct(my_perl);
507510Salexander.borisov@nginx.com     PERL_SET_CONTEXT(my_perl);
508510Salexander.borisov@nginx.com 
509510Salexander.borisov@nginx.com     status = perl_parse(my_perl, nxt_perl_psgi_xs_init, 3, embedding, NULL);
510510Salexander.borisov@nginx.com 
511510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
5121689Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to parse Perl Script");
513510Salexander.borisov@nginx.com         goto fail;
514510Salexander.borisov@nginx.com     }
515510Salexander.borisov@nginx.com 
5161689Smax.romanov@nginx.com     CvXSUBANY(nxt_perl_psgi_write).any_ptr = pctx;
5171689Smax.romanov@nginx.com     CvXSUBANY(nxt_perl_psgi_close).any_ptr = pctx;
5181689Smax.romanov@nginx.com     CvXSUBANY(nxt_perl_psgi_cb).any_ptr = pctx;
5191689Smax.romanov@nginx.com 
5201689Smax.romanov@nginx.com     pctx->cb = nxt_perl_psgi_cb;
5211689Smax.romanov@nginx.com 
522510Salexander.borisov@nginx.com     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
523510Salexander.borisov@nginx.com     PL_origalen = 1;
524510Salexander.borisov@nginx.com 
525510Salexander.borisov@nginx.com     status = perl_run(my_perl);
526510Salexander.borisov@nginx.com 
527510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
5281689Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to run Perl");
529510Salexander.borisov@nginx.com         goto fail;
530510Salexander.borisov@nginx.com     }
531510Salexander.borisov@nginx.com 
532510Salexander.borisov@nginx.com     sv_setsv(get_sv("0", 0), newSVpv(script, 0));
533510Salexander.borisov@nginx.com 
5341689Smax.romanov@nginx.com     run_module = nxt_perl_psgi_module_create(script);
535510Salexander.borisov@nginx.com     if (nxt_slow_path(run_module == NULL)) {
536510Salexander.borisov@nginx.com         goto fail;
537510Salexander.borisov@nginx.com     }
538510Salexander.borisov@nginx.com 
5392060Smax.romanov@nginx.com     pctx->arg_input.rv = newSV_type(SVt_RV);
5402060Smax.romanov@nginx.com     sv_setptrref(pctx->arg_input.rv, &pctx->arg_input);
5412060Smax.romanov@nginx.com     SvSETMAGIC(pctx->arg_input.rv);
542510Salexander.borisov@nginx.com 
5432060Smax.romanov@nginx.com     pctx->arg_input.io_tab = &nxt_perl_psgi_io_tab_input;
5442060Smax.romanov@nginx.com 
5452060Smax.romanov@nginx.com     res = nxt_perl_psgi_io_init(my_perl, &pctx->arg_input, "r", NULL);
5462060Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_UNIT_OK)) {
5471689Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to init io.psgi.input");
548510Salexander.borisov@nginx.com         goto fail;
549510Salexander.borisov@nginx.com     }
550510Salexander.borisov@nginx.com 
5512060Smax.romanov@nginx.com     pctx->arg_error.rv = newSV_type(SVt_RV);
5522060Smax.romanov@nginx.com     sv_setptrref(pctx->arg_error.rv, &pctx->arg_error);
5532060Smax.romanov@nginx.com     SvSETMAGIC(pctx->arg_error.rv);
554510Salexander.borisov@nginx.com 
5552060Smax.romanov@nginx.com     pctx->arg_error.io_tab = &nxt_perl_psgi_io_tab_error;
5562060Smax.romanov@nginx.com 
5572060Smax.romanov@nginx.com     res = nxt_perl_psgi_io_init(my_perl, &pctx->arg_error, "w", NULL);
5582060Smax.romanov@nginx.com     if (nxt_slow_path(res != NXT_UNIT_OK)) {
5592060Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to init io.psgi.error");
560510Salexander.borisov@nginx.com         goto fail;
561510Salexander.borisov@nginx.com     }
562510Salexander.borisov@nginx.com 
5631689Smax.romanov@nginx.com     pctx->app = eval_pv(run_module, FALSE);
564510Salexander.borisov@nginx.com 
565510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
5661689Smax.romanov@nginx.com         nxt_unit_alert(NULL, "PSGI: Failed to parse script: %s\n%s",
5671689Smax.romanov@nginx.com                        script, SvPV_nolen(ERRSV));
568510Salexander.borisov@nginx.com         goto fail;
569510Salexander.borisov@nginx.com     }
570510Salexander.borisov@nginx.com 
5711689Smax.romanov@nginx.com     nxt_unit_free(NULL, run_module);
572510Salexander.borisov@nginx.com 
5731689Smax.romanov@nginx.com     return NXT_UNIT_OK;
574510Salexander.borisov@nginx.com 
575510Salexander.borisov@nginx.com fail:
576510Salexander.borisov@nginx.com 
5772060Smax.romanov@nginx.com     nxt_perl_psgi_io_release(my_perl, &pctx->arg_input);
5782060Smax.romanov@nginx.com     nxt_perl_psgi_io_release(my_perl, &pctx->arg_error);
5792060Smax.romanov@nginx.com 
580510Salexander.borisov@nginx.com     if (run_module != NULL) {
5811689Smax.romanov@nginx.com         nxt_unit_free(NULL, run_module);
582510Salexander.borisov@nginx.com     }
583510Salexander.borisov@nginx.com 
584510Salexander.borisov@nginx.com     perl_destruct(my_perl);
585510Salexander.borisov@nginx.com     perl_free(my_perl);
586510Salexander.borisov@nginx.com 
5872060Smax.romanov@nginx.com     pctx->my_perl = NULL;
5882060Smax.romanov@nginx.com 
5891689Smax.romanov@nginx.com     return NXT_UNIT_ERROR;
590510Salexander.borisov@nginx.com }
591510Salexander.borisov@nginx.com 
592510Salexander.borisov@nginx.com 
593743Smax.romanov@nginx.com static SV *
594743Smax.romanov@nginx.com nxt_perl_psgi_env_create(PerlInterpreter *my_perl,
5951689Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
596510Salexander.borisov@nginx.com {
5971689Smax.romanov@nginx.com     HV                   *hash_env;
5981689Smax.romanov@nginx.com     AV                   *array_version;
5991689Smax.romanov@nginx.com     uint32_t             i;
6001689Smax.romanov@nginx.com     nxt_unit_field_t     *f;
6011689Smax.romanov@nginx.com     nxt_unit_request_t   *r;
6021689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
6031689Smax.romanov@nginx.com 
6041689Smax.romanov@nginx.com     pctx = req->ctx->data;
605510Salexander.borisov@nginx.com 
606510Salexander.borisov@nginx.com     hash_env = newHV();
607510Salexander.borisov@nginx.com     if (nxt_slow_path(hash_env == NULL)) {
608510Salexander.borisov@nginx.com         return NULL;
609510Salexander.borisov@nginx.com     }
610510Salexander.borisov@nginx.com 
611743Smax.romanov@nginx.com #define RC(FNS)                                                               \
612743Smax.romanov@nginx.com     do {                                                                      \
613743Smax.romanov@nginx.com         if (nxt_slow_path((FNS) != NXT_UNIT_OK))                              \
614743Smax.romanov@nginx.com             goto fail;                                                        \
615*2078Salx.manpages@gmail.com     } while (0)
616510Salexander.borisov@nginx.com 
617743Smax.romanov@nginx.com #define NL(S) (S), sizeof(S)-1
618510Salexander.borisov@nginx.com 
619743Smax.romanov@nginx.com     r = req->request;
620673Svbart@nginx.com 
621743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_SOFTWARE"),
622743Smax.romanov@nginx.com                              (char *) nxt_server.start, nxt_server.length));
623510Salexander.borisov@nginx.com 
624743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_METHOD"),
625743Smax.romanov@nginx.com                               &r->method, r->method_length));
626743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_URI"),
627743Smax.romanov@nginx.com                               &r->target, r->target_length));
628743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("PATH_INFO"),
629743Smax.romanov@nginx.com                               &r->path, r->path_length));
630580Salexander.borisov@nginx.com 
631510Salexander.borisov@nginx.com     array_version = newAV();
632510Salexander.borisov@nginx.com 
633510Salexander.borisov@nginx.com     if (nxt_slow_path(array_version == NULL)) {
634510Salexander.borisov@nginx.com         goto fail;
635510Salexander.borisov@nginx.com     }
636510Salexander.borisov@nginx.com 
637510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
638510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
639510Salexander.borisov@nginx.com 
640743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"),
641580Salexander.borisov@nginx.com                                 newRV_noinc((SV *) array_version)));
6421011Smax.romanov@nginx.com 
643743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"),
6441011Smax.romanov@nginx.com                                r->tls ? newSVpv("https", 5)
6451011Smax.romanov@nginx.com                                     : newSVpv("http", 4)));
6461011Smax.romanov@nginx.com 
6472060Smax.romanov@nginx.com     RC(nxt_perl_psgi_io_init(my_perl, &pctx->arg_input, "r", req));
648743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"),
6492060Smax.romanov@nginx.com                                SvREFCNT_inc(pctx->arg_input.io)));
6502060Smax.romanov@nginx.com 
6512060Smax.romanov@nginx.com     RC(nxt_perl_psgi_io_init(my_perl, &pctx->arg_error, "w", req));
652743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"),
6532060Smax.romanov@nginx.com                                SvREFCNT_inc(pctx->arg_error.io)));
6542060Smax.romanov@nginx.com 
655743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multithread"),
6562060Smax.romanov@nginx.com                                nxt_perl_psgi_ctxs != NULL
6572060Smax.romanov@nginx.com                                    ? &PL_sv_yes : &PL_sv_no));
658743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multiprocess"),
6592060Smax.romanov@nginx.com                                &PL_sv_yes));
660743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.run_once"),
6612060Smax.romanov@nginx.com                                &PL_sv_no));
662743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.nonblocking"),
6632060Smax.romanov@nginx.com                                &PL_sv_no));
664743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.streaming"),
6652060Smax.romanov@nginx.com                                &PL_sv_yes));
666510Salexander.borisov@nginx.com 
667981Svbart@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("QUERY_STRING"),
668981Svbart@nginx.com                               &r->query, r->query_length));
669743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_PROTOCOL"),
670743Smax.romanov@nginx.com                               &r->version, r->version_length));
671743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REMOTE_ADDR"),
672743Smax.romanov@nginx.com                               &r->remote, r->remote_length));
673743Smax.romanov@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_ADDR"),
674743Smax.romanov@nginx.com                               &r->local, r->local_length));
675510Salexander.borisov@nginx.com 
676967Svbart@nginx.com     RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_NAME"),
677967Svbart@nginx.com                               &r->server_name, r->server_name_length));
678967Svbart@nginx.com     RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_PORT"), "80", 2));
679967Svbart@nginx.com 
680743Smax.romanov@nginx.com     for (i = 0; i < r->fields_count; i++) {
681743Smax.romanov@nginx.com         f = r->fields + i;
682510Salexander.borisov@nginx.com 
683743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env,
684743Smax.romanov@nginx.com                                   nxt_unit_sptr_get(&f->name), f->name_length,
685743Smax.romanov@nginx.com                                   &f->value, f->value_length));
686510Salexander.borisov@nginx.com     }
687510Salexander.borisov@nginx.com 
688743Smax.romanov@nginx.com     if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
689743Smax.romanov@nginx.com         f = r->fields + r->content_length_field;
690510Salexander.borisov@nginx.com 
691743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_LENGTH"),
692743Smax.romanov@nginx.com                                   &f->value, f->value_length));
693743Smax.romanov@nginx.com     }
694510Salexander.borisov@nginx.com 
695743Smax.romanov@nginx.com     if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
696743Smax.romanov@nginx.com         f = r->fields + r->content_type_field;
697743Smax.romanov@nginx.com 
698743Smax.romanov@nginx.com         RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_TYPE"),
699743Smax.romanov@nginx.com                                   &f->value, f->value_length));
700510Salexander.borisov@nginx.com     }
701510Salexander.borisov@nginx.com 
702743Smax.romanov@nginx.com #undef NL
703510Salexander.borisov@nginx.com #undef RC
704510Salexander.borisov@nginx.com 
705510Salexander.borisov@nginx.com     return newRV_noinc((SV *) hash_env);
706510Salexander.borisov@nginx.com 
707510Salexander.borisov@nginx.com fail:
708510Salexander.borisov@nginx.com 
709510Salexander.borisov@nginx.com     SvREFCNT_dec(hash_env);
710510Salexander.borisov@nginx.com 
711510Salexander.borisov@nginx.com     return NULL;
712510Salexander.borisov@nginx.com }
713510Salexander.borisov@nginx.com 
714510Salexander.borisov@nginx.com 
715743Smax.romanov@nginx.com nxt_inline int
716743Smax.romanov@nginx.com nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env,
717743Smax.romanov@nginx.com     const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len)
718743Smax.romanov@nginx.com {
719743Smax.romanov@nginx.com     return nxt_perl_psgi_add_str(my_perl, hash_env, name, name_len,
720743Smax.romanov@nginx.com                                  nxt_unit_sptr_get(sptr), len);
721743Smax.romanov@nginx.com }
722743Smax.romanov@nginx.com 
723743Smax.romanov@nginx.com 
724743Smax.romanov@nginx.com nxt_inline int
725743Smax.romanov@nginx.com nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env,
726967Svbart@nginx.com     const char *name, uint32_t name_len, const char *str, uint32_t len)
727743Smax.romanov@nginx.com {
728743Smax.romanov@nginx.com     SV  **ha;
729743Smax.romanov@nginx.com 
730743Smax.romanov@nginx.com     ha = hv_store(hash_env, name, (I32) name_len,
731743Smax.romanov@nginx.com                   newSVpv(str, (STRLEN) len), 0);
732743Smax.romanov@nginx.com     if (nxt_slow_path(ha == NULL)) {
733743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
734743Smax.romanov@nginx.com     }
735743Smax.romanov@nginx.com 
736743Smax.romanov@nginx.com     return NXT_UNIT_OK;
737743Smax.romanov@nginx.com }
738743Smax.romanov@nginx.com 
739743Smax.romanov@nginx.com 
740743Smax.romanov@nginx.com nxt_inline int
741743Smax.romanov@nginx.com nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env,
742743Smax.romanov@nginx.com     const char *name, uint32_t name_len, void *value)
743743Smax.romanov@nginx.com {
744743Smax.romanov@nginx.com     SV  **ha;
745743Smax.romanov@nginx.com 
746743Smax.romanov@nginx.com     ha = hv_store(hash_env, name, (I32) name_len, value, 0);
747743Smax.romanov@nginx.com     if (nxt_slow_path(ha == NULL)) {
748743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
749743Smax.romanov@nginx.com     }
750743Smax.romanov@nginx.com 
751743Smax.romanov@nginx.com     return NXT_UNIT_OK;
752743Smax.romanov@nginx.com }
753743Smax.romanov@nginx.com 
754743Smax.romanov@nginx.com 
755743Smax.romanov@nginx.com static nxt_int_t
756510Salexander.borisov@nginx.com nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result)
757510Salexander.borisov@nginx.com {
758510Salexander.borisov@nginx.com     SV         **sv_status;
759510Salexander.borisov@nginx.com     AV         *array;
760743Smax.romanov@nginx.com     u_char     *space;
761510Salexander.borisov@nginx.com     nxt_str_t  status;
762510Salexander.borisov@nginx.com 
763510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
764510Salexander.borisov@nginx.com     sv_status = av_fetch(array, 0, 0);
765510Salexander.borisov@nginx.com 
766510Salexander.borisov@nginx.com     status.start = (u_char *) SvPV(*sv_status, status.length);
767510Salexander.borisov@nginx.com 
768743Smax.romanov@nginx.com     space = nxt_memchr(status.start, ' ', status.length);
769743Smax.romanov@nginx.com     if (space != NULL) {
770743Smax.romanov@nginx.com         status.length = space - status.start;
771743Smax.romanov@nginx.com     }
772743Smax.romanov@nginx.com 
773743Smax.romanov@nginx.com     return nxt_int_parse(status.start, status.length);
774510Salexander.borisov@nginx.com }
775510Salexander.borisov@nginx.com 
776510Salexander.borisov@nginx.com 
777743Smax.romanov@nginx.com static int
778510Salexander.borisov@nginx.com nxt_perl_psgi_result_head(PerlInterpreter *my_perl, SV *sv_head,
779743Smax.romanov@nginx.com     nxt_unit_request_info_t *req, uint16_t status)
780510Salexander.borisov@nginx.com {
781510Salexander.borisov@nginx.com     AV         *array_head;
782510Salexander.borisov@nginx.com     SV         **entry;
783743Smax.romanov@nginx.com     int        rc;
784510Salexander.borisov@nginx.com     long       i, array_len;
785743Smax.romanov@nginx.com     char       *name, *value;
786743Smax.romanov@nginx.com     STRLEN     name_len, value_len;
787743Smax.romanov@nginx.com     uint32_t   fields, size;
788510Salexander.borisov@nginx.com 
789510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_head) == 0
790510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_head)) != SVt_PVAV))
791510Salexander.borisov@nginx.com     {
792743Smax.romanov@nginx.com         nxt_unit_req_error(req,
793743Smax.romanov@nginx.com                            "PSGI: An unsupported format was received from "
794743Smax.romanov@nginx.com                            "Perl Application for head part");
795510Salexander.borisov@nginx.com 
796743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
797510Salexander.borisov@nginx.com     }
798510Salexander.borisov@nginx.com 
799510Salexander.borisov@nginx.com     array_head = (AV *) SvRV(sv_head);
800510Salexander.borisov@nginx.com     array_len = av_len(array_head);
801510Salexander.borisov@nginx.com 
802510Salexander.borisov@nginx.com     if (array_len < 1) {
803743Smax.romanov@nginx.com         return nxt_unit_response_init(req, status, 0, 0);
804510Salexander.borisov@nginx.com     }
805510Salexander.borisov@nginx.com 
806510Salexander.borisov@nginx.com     if (nxt_slow_path((array_len % 2) == 0)) {
807743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: Bad format for head from "
808743Smax.romanov@nginx.com                            "Perl Application");
809510Salexander.borisov@nginx.com 
810743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
811510Salexander.borisov@nginx.com     }
812510Salexander.borisov@nginx.com 
813743Smax.romanov@nginx.com     fields = 0;
814743Smax.romanov@nginx.com     size = 0;
815743Smax.romanov@nginx.com 
816510Salexander.borisov@nginx.com     for (i = 0; i <= array_len; i++) {
817510Salexander.borisov@nginx.com         entry = av_fetch(array_head, i, 0);
818510Salexander.borisov@nginx.com 
819510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
820743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get head entry from "
821743Smax.romanov@nginx.com                                "Perl Application");
822510Salexander.borisov@nginx.com 
823743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
824510Salexander.borisov@nginx.com         }
825510Salexander.borisov@nginx.com 
826743Smax.romanov@nginx.com         value = SvPV(*entry, value_len);
827743Smax.romanov@nginx.com         size += value_len;
828510Salexander.borisov@nginx.com 
829510Salexander.borisov@nginx.com         if ((i % 2) == 0) {
830743Smax.romanov@nginx.com             fields++;
831510Salexander.borisov@nginx.com         }
832743Smax.romanov@nginx.com     }
833510Salexander.borisov@nginx.com 
834743Smax.romanov@nginx.com     rc = nxt_unit_response_init(req, status, fields, size);
835743Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
836743Smax.romanov@nginx.com         return rc;
837743Smax.romanov@nginx.com     }
838743Smax.romanov@nginx.com 
839743Smax.romanov@nginx.com     for (i = 0; i <= array_len; i += 2) {
840743Smax.romanov@nginx.com         entry = av_fetch(array_head, i, 0);
841743Smax.romanov@nginx.com         name = SvPV(*entry, name_len);
842743Smax.romanov@nginx.com 
843743Smax.romanov@nginx.com         entry = av_fetch(array_head, i + 1, 0);
844743Smax.romanov@nginx.com         value = SvPV(*entry, value_len);
845743Smax.romanov@nginx.com 
846743Smax.romanov@nginx.com         rc = nxt_unit_response_add_field(req, name, name_len, value, value_len);
847743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
848510Salexander.borisov@nginx.com             return rc;
849510Salexander.borisov@nginx.com         }
850510Salexander.borisov@nginx.com     }
851510Salexander.borisov@nginx.com 
852743Smax.romanov@nginx.com     return NXT_UNIT_OK;
853510Salexander.borisov@nginx.com }
854510Salexander.borisov@nginx.com 
855510Salexander.borisov@nginx.com 
856743Smax.romanov@nginx.com static int
857510Salexander.borisov@nginx.com nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body,
858743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
859510Salexander.borisov@nginx.com {
860510Salexander.borisov@nginx.com     SV         **entry;
861510Salexander.borisov@nginx.com     AV         *body_array;
862743Smax.romanov@nginx.com     int        rc;
863510Salexander.borisov@nginx.com     long       i;
864510Salexander.borisov@nginx.com     nxt_str_t  body;
865510Salexander.borisov@nginx.com 
866510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_body) == 0
867510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_body)) != SVt_PVAV))
868510Salexander.borisov@nginx.com     {
869743Smax.romanov@nginx.com         nxt_unit_req_error(req, "PSGI: An unsupported format was received from "
870743Smax.romanov@nginx.com                            "Perl Application for a body part");
871510Salexander.borisov@nginx.com 
872743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
873510Salexander.borisov@nginx.com     }
874510Salexander.borisov@nginx.com 
875510Salexander.borisov@nginx.com     body_array = (AV *) SvRV(sv_body);
876510Salexander.borisov@nginx.com 
877510Salexander.borisov@nginx.com     for (i = 0; i <= av_len(body_array); i++) {
878510Salexander.borisov@nginx.com 
879510Salexander.borisov@nginx.com         entry = av_fetch(body_array, i, 0);
880510Salexander.borisov@nginx.com 
881510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
882743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get body entry from "
883743Smax.romanov@nginx.com                                "Perl Application");
884743Smax.romanov@nginx.com 
885743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
886510Salexander.borisov@nginx.com         }
887510Salexander.borisov@nginx.com 
888510Salexander.borisov@nginx.com         body.start = (u_char *) SvPV(*entry, body.length);
889510Salexander.borisov@nginx.com 
890510Salexander.borisov@nginx.com         if (body.length == 0) {
891510Salexander.borisov@nginx.com             continue;
892510Salexander.borisov@nginx.com         }
893510Salexander.borisov@nginx.com 
894743Smax.romanov@nginx.com         rc = nxt_unit_response_write(req, body.start, body.length);
895510Salexander.borisov@nginx.com 
896743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
897743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to write content from "
898743Smax.romanov@nginx.com                                "Perl Application");
899510Salexander.borisov@nginx.com             return rc;
900510Salexander.borisov@nginx.com         }
901510Salexander.borisov@nginx.com     }
902510Salexander.borisov@nginx.com 
903743Smax.romanov@nginx.com     return NXT_UNIT_OK;
904510Salexander.borisov@nginx.com }
905510Salexander.borisov@nginx.com 
906510Salexander.borisov@nginx.com 
907969Salexander.borisov@nginx.com static int
908969Salexander.borisov@nginx.com nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body,
909969Salexander.borisov@nginx.com     nxt_unit_request_info_t *req)
910969Salexander.borisov@nginx.com {
911969Salexander.borisov@nginx.com     SV          *data, *old_rs, *old_perl_rs;
912969Salexander.borisov@nginx.com     int         rc;
913969Salexander.borisov@nginx.com     size_t      len;
914969Salexander.borisov@nginx.com     const char  *body;
915969Salexander.borisov@nginx.com 
916969Salexander.borisov@nginx.com     /*
917969Salexander.borisov@nginx.com      * Servers should set the $/ special variable to the buffer size
918969Salexander.borisov@nginx.com      * when reading content from $body using the getline method.
919969Salexander.borisov@nginx.com      * This is done by setting $/ with a reference to an integer ($/ = \8192).
920969Salexander.borisov@nginx.com      */
921969Salexander.borisov@nginx.com 
922969Salexander.borisov@nginx.com     old_rs = PL_rs;
923969Salexander.borisov@nginx.com     old_perl_rs = get_sv("/", GV_ADD);
924969Salexander.borisov@nginx.com 
925969Salexander.borisov@nginx.com     PL_rs = sv_2mortal(newRV_noinc(newSViv(nxt_unit_buf_min())));
926969Salexander.borisov@nginx.com 
927969Salexander.borisov@nginx.com     sv_setsv(old_perl_rs, PL_rs);
928969Salexander.borisov@nginx.com 
929969Salexander.borisov@nginx.com     rc = NXT_UNIT_OK;
930969Salexander.borisov@nginx.com 
931969Salexander.borisov@nginx.com     for ( ;; ) {
932969Salexander.borisov@nginx.com         data = nxt_perl_psgi_call_method(my_perl, sv_body, "getline", req);
933969Salexander.borisov@nginx.com         if (nxt_slow_path(data == NULL)) {
934969Salexander.borisov@nginx.com             rc = NXT_UNIT_ERROR;
935969Salexander.borisov@nginx.com             break;
936969Salexander.borisov@nginx.com         }
937969Salexander.borisov@nginx.com 
938969Salexander.borisov@nginx.com         body = SvPV(data, len);
939969Salexander.borisov@nginx.com 
940969Salexander.borisov@nginx.com         if (len == 0) {
941969Salexander.borisov@nginx.com             SvREFCNT_dec(data);
942969Salexander.borisov@nginx.com 
943969Salexander.borisov@nginx.com             data = nxt_perl_psgi_call_method(my_perl, sv_body, "close", req);
944969Salexander.borisov@nginx.com             if (nxt_fast_path(data != NULL)) {
945969Salexander.borisov@nginx.com                 SvREFCNT_dec(data);
946969Salexander.borisov@nginx.com             }
947969Salexander.borisov@nginx.com 
948969Salexander.borisov@nginx.com             break;
949969Salexander.borisov@nginx.com         }
950969Salexander.borisov@nginx.com 
951969Salexander.borisov@nginx.com         rc = nxt_unit_response_write(req, body, len);
952969Salexander.borisov@nginx.com 
953969Salexander.borisov@nginx.com         SvREFCNT_dec(data);
954969Salexander.borisov@nginx.com 
955969Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
956969Salexander.borisov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to write content from "
957969Salexander.borisov@nginx.com                                "Perl Application");
958969Salexander.borisov@nginx.com             break;
959969Salexander.borisov@nginx.com         }
960969Salexander.borisov@nginx.com     };
961969Salexander.borisov@nginx.com 
962969Salexander.borisov@nginx.com     PL_rs =  old_rs;
963969Salexander.borisov@nginx.com     sv_setsv(get_sv("/", GV_ADD), old_perl_rs);
964969Salexander.borisov@nginx.com 
965969Salexander.borisov@nginx.com     return rc;
966969Salexander.borisov@nginx.com }
967969Salexander.borisov@nginx.com 
968969Salexander.borisov@nginx.com 
969743Smax.romanov@nginx.com typedef struct {
970743Smax.romanov@nginx.com     PerlInterpreter  *my_perl;
971743Smax.romanov@nginx.com     PerlIO           *fp;
972743Smax.romanov@nginx.com } nxt_perl_psgi_io_ctx_t;
973743Smax.romanov@nginx.com 
974743Smax.romanov@nginx.com 
975743Smax.romanov@nginx.com static int
976969Salexander.borisov@nginx.com nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body,
977743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
978510Salexander.borisov@nginx.com {
979743Smax.romanov@nginx.com     IO                      *io;
980743Smax.romanov@nginx.com     nxt_unit_read_info_t    read_info;
981743Smax.romanov@nginx.com     nxt_perl_psgi_io_ctx_t  io_ctx;
982510Salexander.borisov@nginx.com 
983510Salexander.borisov@nginx.com     io = GvIO(SvRV(sv_body));
984519Salexander.borisov@nginx.com 
985519Salexander.borisov@nginx.com     if (io == NULL) {
986743Smax.romanov@nginx.com         return NXT_UNIT_OK;
987519Salexander.borisov@nginx.com     }
988519Salexander.borisov@nginx.com 
989743Smax.romanov@nginx.com     io_ctx.my_perl = my_perl;
990743Smax.romanov@nginx.com     io_ctx.fp = IoIFP(io);
991510Salexander.borisov@nginx.com 
992743Smax.romanov@nginx.com     read_info.read = nxt_perl_psgi_io_read;
993743Smax.romanov@nginx.com     read_info.eof = PerlIO_eof(io_ctx.fp);
994743Smax.romanov@nginx.com     read_info.buf_size = 8192;
995743Smax.romanov@nginx.com     read_info.data = &io_ctx;
996510Salexander.borisov@nginx.com 
997743Smax.romanov@nginx.com     return nxt_unit_response_write_cb(req, &read_info);
998510Salexander.borisov@nginx.com }
999510Salexander.borisov@nginx.com 
1000510Salexander.borisov@nginx.com 
1001743Smax.romanov@nginx.com static ssize_t
1002743Smax.romanov@nginx.com nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, size_t size)
1003743Smax.romanov@nginx.com {
1004743Smax.romanov@nginx.com     ssize_t                 res;
1005743Smax.romanov@nginx.com     nxt_perl_psgi_io_ctx_t  *ctx;
1006743Smax.romanov@nginx.com 
1007743Smax.romanov@nginx.com     ctx = read_info->data;
1008749Salexander.borisov@nginx.com 
1009749Salexander.borisov@nginx.com     dTHXa(ctx->my_perl);
1010743Smax.romanov@nginx.com 
1011743Smax.romanov@nginx.com     res = PerlIO_read(ctx->fp, dst, size);
1012743Smax.romanov@nginx.com 
1013743Smax.romanov@nginx.com     read_info->eof = PerlIO_eof(ctx->fp);
1014743Smax.romanov@nginx.com 
1015743Smax.romanov@nginx.com     return res;
1016743Smax.romanov@nginx.com }
1017743Smax.romanov@nginx.com 
1018743Smax.romanov@nginx.com 
1019743Smax.romanov@nginx.com static int
1020510Salexander.borisov@nginx.com nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result,
1021743Smax.romanov@nginx.com     nxt_unit_request_info_t *req)
1022510Salexander.borisov@nginx.com {
1023510Salexander.borisov@nginx.com     AV         *array;
1024510Salexander.borisov@nginx.com     SV         **sv_temp;
1025743Smax.romanov@nginx.com     int        rc;
1026510Salexander.borisov@nginx.com     long       array_len;
1027743Smax.romanov@nginx.com     nxt_int_t  status;
1028510Salexander.borisov@nginx.com 
1029510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
1030510Salexander.borisov@nginx.com     array_len = av_len(array);
1031510Salexander.borisov@nginx.com 
1032510Salexander.borisov@nginx.com     if (nxt_slow_path(array_len < 0)) {
1033743Smax.romanov@nginx.com         nxt_unit_req_error(req,
1034743Smax.romanov@nginx.com                            "PSGI: Invalid result format from Perl Application");
1035510Salexander.borisov@nginx.com 
1036743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
1037510Salexander.borisov@nginx.com     }
1038510Salexander.borisov@nginx.com 
1039743Smax.romanov@nginx.com     status = nxt_perl_psgi_result_status(my_perl, result);
1040510Salexander.borisov@nginx.com 
1041743Smax.romanov@nginx.com     if (nxt_slow_path(status < 0)) {
1042743Smax.romanov@nginx.com         nxt_unit_req_error(req,
1043743Smax.romanov@nginx.com                            "PSGI: An unexpected status was received "
1044743Smax.romanov@nginx.com                            "from Perl Application");
1045510Salexander.borisov@nginx.com 
1046743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
1047510Salexander.borisov@nginx.com     }
1048510Salexander.borisov@nginx.com 
1049743Smax.romanov@nginx.com     if (array_len >= 1) {
1050743Smax.romanov@nginx.com         sv_temp = av_fetch(array, 1, 0);
1051510Salexander.borisov@nginx.com 
1052743Smax.romanov@nginx.com         if (nxt_slow_path(sv_temp == NULL)) {
1053743Smax.romanov@nginx.com             nxt_unit_req_error(req, "PSGI: Failed to get head from "
1054743Smax.romanov@nginx.com                                "Perl ARRAY variable");
1055510Salexander.borisov@nginx.com 
1056743Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
1057743Smax.romanov@nginx.com         }
1058743Smax.romanov@nginx.com 
1059743Smax.romanov@nginx.com         rc = nxt_perl_psgi_result_head(my_perl, *sv_temp, req, status);
1060743Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1061510Salexander.borisov@nginx.com             return rc;
1062510Salexander.borisov@nginx.com         }
1063510Salexander.borisov@nginx.com 
1064743Smax.romanov@nginx.com     } else {
1065743Smax.romanov@nginx.com         return nxt_unit_response_init(req, status, 0, 0);
1066510Salexander.borisov@nginx.com     }
1067510Salexander.borisov@nginx.com 
1068510Salexander.borisov@nginx.com     if (nxt_fast_path(array_len < 2)) {
1069743Smax.romanov@nginx.com         return NXT_UNIT_OK;
1070510Salexander.borisov@nginx.com     }
1071510Salexander.borisov@nginx.com 
1072510Salexander.borisov@nginx.com     sv_temp = av_fetch(array, 2, 0);
1073510Salexander.borisov@nginx.com 
1074519Salexander.borisov@nginx.com     if (nxt_slow_path(sv_temp == NULL || SvROK(*sv_temp) == FALSE)) {
1075743Smax.romanov@nginx.com         nxt_unit_req_error(req,
1076743Smax.romanov@nginx.com                            "PSGI: Failed to get body from "
1077743Smax.romanov@nginx.com                            "Perl ARRAY variable");
1078510Salexander.borisov@nginx.com 
1079743Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
1080510Salexander.borisov@nginx.com     }
1081510Salexander.borisov@nginx.com 
1082510Salexander.borisov@nginx.com     if (SvTYPE(SvRV(*sv_temp)) == SVt_PVAV) {
1083743Smax.romanov@nginx.com         return nxt_perl_psgi_result_body(my_perl, *sv_temp, req);
1084510Salexander.borisov@nginx.com     }
1085510Salexander.borisov@nginx.com 
1086969Salexander.borisov@nginx.com     if (SvTYPE(SvRV(*sv_temp)) == SVt_PVGV) {
1087969Salexander.borisov@nginx.com         return nxt_perl_psgi_result_body_fh(my_perl, *sv_temp, req);
1088969Salexander.borisov@nginx.com     }
1089969Salexander.borisov@nginx.com 
1090743Smax.romanov@nginx.com     return nxt_perl_psgi_result_body_ref(my_perl, *sv_temp, req);
1091510Salexander.borisov@nginx.com }
1092510Salexander.borisov@nginx.com 
1093510Salexander.borisov@nginx.com 
1094986Salexander.borisov@nginx.com static void
1095986Salexander.borisov@nginx.com nxt_perl_psgi_result_cb(PerlInterpreter *my_perl, SV *result,
1096986Salexander.borisov@nginx.com     nxt_unit_request_info_t *req)
1097986Salexander.borisov@nginx.com {
10981689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
10991689Smax.romanov@nginx.com 
1100986Salexander.borisov@nginx.com     dSP;
1101986Salexander.borisov@nginx.com 
11021689Smax.romanov@nginx.com     pctx = req->ctx->data;
11031689Smax.romanov@nginx.com 
1104986Salexander.borisov@nginx.com     ENTER;
1105986Salexander.borisov@nginx.com     SAVETMPS;
1106986Salexander.borisov@nginx.com 
1107986Salexander.borisov@nginx.com     PUSHMARK(sp);
11081689Smax.romanov@nginx.com     XPUSHs(newRV_noinc((SV*) pctx->cb));
1109986Salexander.borisov@nginx.com     PUTBACK;
1110986Salexander.borisov@nginx.com 
1111986Salexander.borisov@nginx.com     call_sv(result, G_EVAL|G_SCALAR);
1112986Salexander.borisov@nginx.com 
1113986Salexander.borisov@nginx.com     SPAGAIN;
1114986Salexander.borisov@nginx.com 
1115986Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
1116986Salexander.borisov@nginx.com         nxt_unit_error(NULL, "PSGI: Failed to execute result callback: \n%s",
1117986Salexander.borisov@nginx.com                        SvPV_nolen(ERRSV));
1118986Salexander.borisov@nginx.com 
11191689Smax.romanov@nginx.com         nxt_perl_psgi_cb_request_done(pctx, NXT_UNIT_ERROR);
1120986Salexander.borisov@nginx.com     }
1121986Salexander.borisov@nginx.com 
1122986Salexander.borisov@nginx.com     PUTBACK;
1123986Salexander.borisov@nginx.com     FREETMPS;
1124986Salexander.borisov@nginx.com     LEAVE;
1125986Salexander.borisov@nginx.com }
1126986Salexander.borisov@nginx.com 
1127986Salexander.borisov@nginx.com 
1128510Salexander.borisov@nginx.com static nxt_int_t
11291488St.nateldemoura@f5.com nxt_perl_psgi_start(nxt_task_t *task, nxt_process_data_t *data)
1130510Salexander.borisov@nginx.com {
11311689Smax.romanov@nginx.com     int                    rc, pargc;
11321689Smax.romanov@nginx.com     char                   **pargv, **penv;
11331689Smax.romanov@nginx.com     nxt_unit_ctx_t         *unit_ctx;
11341689Smax.romanov@nginx.com     nxt_unit_init_t        perl_init;
11351689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t    pctx;
11361689Smax.romanov@nginx.com     nxt_perl_app_conf_t    *c;
11371689Smax.romanov@nginx.com     nxt_common_app_conf_t  *common_conf;
11381689Smax.romanov@nginx.com 
11391689Smax.romanov@nginx.com     common_conf = data->app;
11401689Smax.romanov@nginx.com     c = &common_conf->u.perl;
1141510Salexander.borisov@nginx.com 
11421689Smax.romanov@nginx.com     pargc = 0;
11431689Smax.romanov@nginx.com     pargv = NULL;
11441689Smax.romanov@nginx.com     penv = NULL;
11451689Smax.romanov@nginx.com 
11461689Smax.romanov@nginx.com     PERL_SYS_INIT3(&pargc, &pargv, &penv);
11471488St.nateldemoura@f5.com 
11481689Smax.romanov@nginx.com     memset(&pctx, 0, sizeof(nxt_perl_psgi_ctx_t));
1149510Salexander.borisov@nginx.com 
11501689Smax.romanov@nginx.com     rc = nxt_perl_psgi_ctx_init(c->script, &pctx);
11511689Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
11521689Smax.romanov@nginx.com         goto fail;
1153510Salexander.borisov@nginx.com     }
1154510Salexander.borisov@nginx.com 
11551689Smax.romanov@nginx.com     rc = nxt_perl_psgi_init_threads(c);
11561689Smax.romanov@nginx.com 
11571689Smax.romanov@nginx.com     PERL_SET_CONTEXT(pctx.my_perl);
11581689Smax.romanov@nginx.com 
11591689Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
11601689Smax.romanov@nginx.com         goto fail;
11611689Smax.romanov@nginx.com     }
1162510Salexander.borisov@nginx.com 
11631980Smax.romanov@nginx.com     nxt_unit_default_init(task, &perl_init, common_conf);
1164743Smax.romanov@nginx.com 
1165743Smax.romanov@nginx.com     perl_init.callbacks.request_handler = nxt_perl_psgi_request_handler;
11661689Smax.romanov@nginx.com     perl_init.callbacks.ready_handler = nxt_perl_psgi_ready_handler;
11671689Smax.romanov@nginx.com     perl_init.data = c;
11681689Smax.romanov@nginx.com     perl_init.ctx_data = &pctx;
1169743Smax.romanov@nginx.com 
1170743Smax.romanov@nginx.com     unit_ctx = nxt_unit_init(&perl_init);
1171743Smax.romanov@nginx.com     if (nxt_slow_path(unit_ctx == NULL)) {
11721689Smax.romanov@nginx.com         goto fail;
1173743Smax.romanov@nginx.com     }
1174743Smax.romanov@nginx.com 
1175743Smax.romanov@nginx.com     rc = nxt_unit_run(unit_ctx);
1176743Smax.romanov@nginx.com 
11771689Smax.romanov@nginx.com     nxt_perl_psgi_join_threads(unit_ctx, c);
11781689Smax.romanov@nginx.com 
1179743Smax.romanov@nginx.com     nxt_unit_done(unit_ctx);
1180743Smax.romanov@nginx.com 
11811689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_free(&pctx);
11821689Smax.romanov@nginx.com 
11831689Smax.romanov@nginx.com     PERL_SYS_TERM();
1184743Smax.romanov@nginx.com 
1185743Smax.romanov@nginx.com     exit(rc);
1186743Smax.romanov@nginx.com 
1187510Salexander.borisov@nginx.com     return NXT_OK;
11881689Smax.romanov@nginx.com 
11891689Smax.romanov@nginx.com fail:
11901689Smax.romanov@nginx.com 
11911689Smax.romanov@nginx.com     nxt_perl_psgi_join_threads(NULL, c);
11921689Smax.romanov@nginx.com 
11931689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_free(&pctx);
11941689Smax.romanov@nginx.com 
11951689Smax.romanov@nginx.com     PERL_SYS_TERM();
11961689Smax.romanov@nginx.com 
11971689Smax.romanov@nginx.com     return NXT_ERROR;
1198510Salexander.borisov@nginx.com }
1199510Salexander.borisov@nginx.com 
1200510Salexander.borisov@nginx.com 
1201743Smax.romanov@nginx.com static void
1202743Smax.romanov@nginx.com nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req)
1203510Salexander.borisov@nginx.com {
12041689Smax.romanov@nginx.com     SV                   *env, *result;
12051689Smax.romanov@nginx.com     nxt_int_t            rc;
12061689Smax.romanov@nginx.com     PerlInterpreter      *my_perl;
12071689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
1208510Salexander.borisov@nginx.com 
12091689Smax.romanov@nginx.com     pctx = req->ctx->data;
12101689Smax.romanov@nginx.com     my_perl = pctx->my_perl;
1211743Smax.romanov@nginx.com 
12121689Smax.romanov@nginx.com     pctx->req = req;
1213986Salexander.borisov@nginx.com 
1214510Salexander.borisov@nginx.com     /*
1215510Salexander.borisov@nginx.com      * Create environ variable for perl sub "application".
1216510Salexander.borisov@nginx.com      *  > sub application {
1217510Salexander.borisov@nginx.com      *  >     my ($environ) = @_;
1218510Salexander.borisov@nginx.com      */
12191689Smax.romanov@nginx.com     env = nxt_perl_psgi_env_create(my_perl, req);
1220510Salexander.borisov@nginx.com     if (nxt_slow_path(env == NULL)) {
1221743Smax.romanov@nginx.com         nxt_unit_req_error(req,
1222743Smax.romanov@nginx.com                            "PSGI: Failed to create 'env' for Perl Application");
1223743Smax.romanov@nginx.com         nxt_unit_request_done(req, NXT_UNIT_ERROR);
12241689Smax.romanov@nginx.com         pctx->req = NULL;
1225510Salexander.borisov@nginx.com 
1226743Smax.romanov@nginx.com         return;
1227510Salexander.borisov@nginx.com     }
1228510Salexander.borisov@nginx.com 
1229510Salexander.borisov@nginx.com     /* Call perl sub and get result as SV*. */
12301689Smax.romanov@nginx.com     result = nxt_perl_psgi_call_var_application(my_perl, env, pctx->app,
12311689Smax.romanov@nginx.com                                                 req);
1232510Salexander.borisov@nginx.com 
1233986Salexander.borisov@nginx.com     if (nxt_fast_path(SvOK(result) != 0 && SvROK(result) != 0)) {
1234743Smax.romanov@nginx.com 
1235986Salexander.borisov@nginx.com         if (SvTYPE(SvRV(result)) == SVt_PVAV) {
1236986Salexander.borisov@nginx.com             rc = nxt_perl_psgi_result_array(my_perl, result, req);
1237986Salexander.borisov@nginx.com             nxt_unit_request_done(req, rc);
12381689Smax.romanov@nginx.com             pctx->req = NULL;
12391689Smax.romanov@nginx.com 
1240986Salexander.borisov@nginx.com             goto release;
1241986Salexander.borisov@nginx.com         }
1242743Smax.romanov@nginx.com 
1243986Salexander.borisov@nginx.com         if (SvTYPE(SvRV(result)) == SVt_PVCV) {
1244986Salexander.borisov@nginx.com             nxt_perl_psgi_result_cb(my_perl, result, req);
1245986Salexander.borisov@nginx.com             goto release;
1246986Salexander.borisov@nginx.com         }
1247510Salexander.borisov@nginx.com     }
1248510Salexander.borisov@nginx.com 
1249986Salexander.borisov@nginx.com     nxt_unit_req_error(req, "PSGI: An unexpected response was received "
1250986Salexander.borisov@nginx.com                        "from Perl Application");
1251986Salexander.borisov@nginx.com 
1252986Salexander.borisov@nginx.com     nxt_unit_request_done(req, NXT_UNIT_ERROR);
12531689Smax.romanov@nginx.com     pctx->req = NULL;
1254986Salexander.borisov@nginx.com 
1255986Salexander.borisov@nginx.com release:
1256510Salexander.borisov@nginx.com 
1257510Salexander.borisov@nginx.com     SvREFCNT_dec(result);
1258510Salexander.borisov@nginx.com     SvREFCNT_dec(env);
1259510Salexander.borisov@nginx.com }
1260510Salexander.borisov@nginx.com 
1261510Salexander.borisov@nginx.com 
12621689Smax.romanov@nginx.com static int
12631689Smax.romanov@nginx.com nxt_perl_psgi_ready_handler(nxt_unit_ctx_t *ctx)
1264510Salexander.borisov@nginx.com {
12651689Smax.romanov@nginx.com     int                  res;
12661689Smax.romanov@nginx.com     uint32_t             i;
12671689Smax.romanov@nginx.com     nxt_perl_app_conf_t  *c;
12681689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
12691689Smax.romanov@nginx.com 
12701689Smax.romanov@nginx.com     c = ctx->unit->data;
12711689Smax.romanov@nginx.com 
12721689Smax.romanov@nginx.com     if (c->threads <= 1) {
12731689Smax.romanov@nginx.com         return NXT_UNIT_OK;
12741689Smax.romanov@nginx.com     }
12751689Smax.romanov@nginx.com 
12761689Smax.romanov@nginx.com     for (i = 0; i < c->threads - 1; i++) {
12771689Smax.romanov@nginx.com         pctx = &nxt_perl_psgi_ctxs[i];
12781689Smax.romanov@nginx.com 
12791689Smax.romanov@nginx.com         pctx->ctx = ctx;
12801689Smax.romanov@nginx.com 
12811689Smax.romanov@nginx.com         res = pthread_create(&pctx->thread, nxt_perl_psgi_thread_attr,
12821689Smax.romanov@nginx.com                              nxt_perl_psgi_thread_func, pctx);
12831689Smax.romanov@nginx.com 
12841689Smax.romanov@nginx.com         if (nxt_fast_path(res == 0)) {
12851689Smax.romanov@nginx.com             nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1));
12861689Smax.romanov@nginx.com 
12871689Smax.romanov@nginx.com         } else {
12881689Smax.romanov@nginx.com             nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)",
12891689Smax.romanov@nginx.com                            (int) (i + 1), strerror(res), res);
12901689Smax.romanov@nginx.com 
12911689Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
12921689Smax.romanov@nginx.com         }
12931689Smax.romanov@nginx.com     }
12941689Smax.romanov@nginx.com 
12951689Smax.romanov@nginx.com     return NXT_UNIT_OK;
12961689Smax.romanov@nginx.com }
12971689Smax.romanov@nginx.com 
1298510Salexander.borisov@nginx.com 
12991689Smax.romanov@nginx.com static void *
13001689Smax.romanov@nginx.com nxt_perl_psgi_thread_func(void *data)
13011689Smax.romanov@nginx.com {
13021689Smax.romanov@nginx.com     nxt_unit_ctx_t       *ctx;
13031689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
13041689Smax.romanov@nginx.com 
13051689Smax.romanov@nginx.com     pctx = data;
13061689Smax.romanov@nginx.com 
13071689Smax.romanov@nginx.com     nxt_unit_debug(pctx->ctx, "worker thread start");
13081689Smax.romanov@nginx.com 
13091689Smax.romanov@nginx.com     ctx = nxt_unit_ctx_alloc(pctx->ctx, pctx);
13101689Smax.romanov@nginx.com     if (nxt_slow_path(ctx == NULL)) {
13111689Smax.romanov@nginx.com         return NULL;
13121689Smax.romanov@nginx.com     }
13131689Smax.romanov@nginx.com 
13141689Smax.romanov@nginx.com     pctx->ctx = ctx;
13151689Smax.romanov@nginx.com 
13161689Smax.romanov@nginx.com     PERL_SET_CONTEXT(pctx->my_perl);
13171689Smax.romanov@nginx.com 
13181689Smax.romanov@nginx.com     (void) nxt_unit_run(ctx);
13191689Smax.romanov@nginx.com 
13201689Smax.romanov@nginx.com     nxt_unit_done(ctx);
13211689Smax.romanov@nginx.com 
13221689Smax.romanov@nginx.com     nxt_unit_debug(NULL, "worker thread end");
13231689Smax.romanov@nginx.com 
13241689Smax.romanov@nginx.com     return NULL;
13251689Smax.romanov@nginx.com }
13261689Smax.romanov@nginx.com 
13271689Smax.romanov@nginx.com 
13281689Smax.romanov@nginx.com static int
13291689Smax.romanov@nginx.com nxt_perl_psgi_init_threads(nxt_perl_app_conf_t *c)
13301689Smax.romanov@nginx.com {
13311689Smax.romanov@nginx.com     int                    rc;
13321689Smax.romanov@nginx.com     uint32_t               i;
13331689Smax.romanov@nginx.com     static pthread_attr_t  attr;
13341689Smax.romanov@nginx.com 
13351689Smax.romanov@nginx.com     if (c->threads <= 1) {
13361689Smax.romanov@nginx.com         return NXT_UNIT_OK;
13371689Smax.romanov@nginx.com     }
13381689Smax.romanov@nginx.com 
13391689Smax.romanov@nginx.com     if (c->thread_stack_size > 0) {
13401689Smax.romanov@nginx.com         rc = pthread_attr_init(&attr);
13411689Smax.romanov@nginx.com         if (nxt_slow_path(rc != 0)) {
13421689Smax.romanov@nginx.com             nxt_unit_alert(NULL, "thread attr init failed: %s (%d)",
13431689Smax.romanov@nginx.com                            strerror(rc), rc);
1344510Salexander.borisov@nginx.com 
13451689Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
13461689Smax.romanov@nginx.com         }
13471689Smax.romanov@nginx.com 
13481689Smax.romanov@nginx.com         rc = pthread_attr_setstacksize(&attr, c->thread_stack_size);
13491689Smax.romanov@nginx.com         if (nxt_slow_path(rc != 0)) {
13501689Smax.romanov@nginx.com             nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)",
13511689Smax.romanov@nginx.com                            strerror(rc), rc);
13521689Smax.romanov@nginx.com 
13531689Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
13541689Smax.romanov@nginx.com         }
13551689Smax.romanov@nginx.com 
13561689Smax.romanov@nginx.com         nxt_perl_psgi_thread_attr = &attr;
13571689Smax.romanov@nginx.com     }
13581689Smax.romanov@nginx.com 
13591689Smax.romanov@nginx.com     nxt_perl_psgi_ctxs = nxt_unit_malloc(NULL, sizeof(nxt_perl_psgi_ctx_t)
13601689Smax.romanov@nginx.com                                                * (c->threads - 1));
13611689Smax.romanov@nginx.com     if (nxt_slow_path(nxt_perl_psgi_ctxs == NULL)) {
13621689Smax.romanov@nginx.com         return NXT_UNIT_ERROR;
13631689Smax.romanov@nginx.com     }
13641689Smax.romanov@nginx.com 
13651689Smax.romanov@nginx.com     memset(nxt_perl_psgi_ctxs, 0, sizeof(nxt_perl_psgi_ctx_t)
13661689Smax.romanov@nginx.com                                   * (c->threads - 1));
13671689Smax.romanov@nginx.com 
13681689Smax.romanov@nginx.com     for (i = 0; i < c->threads - 1; i++) {
13691689Smax.romanov@nginx.com         rc = nxt_perl_psgi_ctx_init(c->script, &nxt_perl_psgi_ctxs[i]);
13701689Smax.romanov@nginx.com 
13711689Smax.romanov@nginx.com         if (nxt_slow_path(rc != NXT_UNIT_OK)) {
13721689Smax.romanov@nginx.com             return NXT_UNIT_ERROR;
13731689Smax.romanov@nginx.com         }
13741689Smax.romanov@nginx.com     }
13751689Smax.romanov@nginx.com 
13761689Smax.romanov@nginx.com     return NXT_UNIT_OK;
13771689Smax.romanov@nginx.com }
13781689Smax.romanov@nginx.com 
13791689Smax.romanov@nginx.com 
13801689Smax.romanov@nginx.com static void
13811689Smax.romanov@nginx.com nxt_perl_psgi_join_threads(nxt_unit_ctx_t *ctx, nxt_perl_app_conf_t *c)
13821689Smax.romanov@nginx.com {
13831689Smax.romanov@nginx.com     int                  res;
13841689Smax.romanov@nginx.com     uint32_t             i;
13851689Smax.romanov@nginx.com     nxt_perl_psgi_ctx_t  *pctx;
1386510Salexander.borisov@nginx.com 
13871689Smax.romanov@nginx.com     if (nxt_perl_psgi_ctxs == NULL) {
13881689Smax.romanov@nginx.com         return;
13891689Smax.romanov@nginx.com     }
13901689Smax.romanov@nginx.com 
13911689Smax.romanov@nginx.com     for (i = 0; i < c->threads - 1; i++) {
13921689Smax.romanov@nginx.com         pctx = &nxt_perl_psgi_ctxs[i];
13931689Smax.romanov@nginx.com 
13941689Smax.romanov@nginx.com         res = pthread_join(pctx->thread, NULL);
13951689Smax.romanov@nginx.com 
13961689Smax.romanov@nginx.com         if (nxt_fast_path(res == 0)) {
13971689Smax.romanov@nginx.com             nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1));
13981689Smax.romanov@nginx.com 
13991689Smax.romanov@nginx.com         } else {
14001689Smax.romanov@nginx.com             nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)",
14011689Smax.romanov@nginx.com                            (int) (i + 1), strerror(res), res);
14021689Smax.romanov@nginx.com         }
14031689Smax.romanov@nginx.com     }
14041689Smax.romanov@nginx.com 
14051689Smax.romanov@nginx.com     for (i = 0; i < c->threads - 1; i++) {
14061689Smax.romanov@nginx.com         nxt_perl_psgi_ctx_free(&nxt_perl_psgi_ctxs[i]);
14071689Smax.romanov@nginx.com     }
14081689Smax.romanov@nginx.com 
14091689Smax.romanov@nginx.com     nxt_unit_free(NULL, nxt_perl_psgi_ctxs);
1410510Salexander.borisov@nginx.com }
14111689Smax.romanov@nginx.com 
14121689Smax.romanov@nginx.com 
14131689Smax.romanov@nginx.com static void
14141689Smax.romanov@nginx.com nxt_perl_psgi_ctx_free(nxt_perl_psgi_ctx_t *pctx)
14151689Smax.romanov@nginx.com {
14161689Smax.romanov@nginx.com     PerlInterpreter  *my_perl;
14171689Smax.romanov@nginx.com 
14181689Smax.romanov@nginx.com     my_perl = pctx->my_perl;
14191689Smax.romanov@nginx.com 
14201689Smax.romanov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
14211689Smax.romanov@nginx.com         return;
14221689Smax.romanov@nginx.com     }
14231689Smax.romanov@nginx.com 
14241689Smax.romanov@nginx.com     PERL_SET_CONTEXT(my_perl);
14251689Smax.romanov@nginx.com 
14262060Smax.romanov@nginx.com     SvREFCNT_dec(pctx->arg_input.rv);
14272060Smax.romanov@nginx.com     SvREFCNT_dec(pctx->arg_error.rv);
14281689Smax.romanov@nginx.com 
14292060Smax.romanov@nginx.com     nxt_perl_psgi_io_release(my_perl, &pctx->arg_input);
14302060Smax.romanov@nginx.com     nxt_perl_psgi_io_release(my_perl, &pctx->arg_error);
14311689Smax.romanov@nginx.com 
14321689Smax.romanov@nginx.com     perl_destruct(my_perl);
14331689Smax.romanov@nginx.com     perl_free(my_perl);
14341689Smax.romanov@nginx.com }
1435