xref: /unit/src/perl/nxt_perl_psgi.c (revision 612)
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>
14510Salexander.borisov@nginx.com 
15510Salexander.borisov@nginx.com 
16510Salexander.borisov@nginx.com typedef struct {
17510Salexander.borisov@nginx.com     PerlInterpreter  *my_perl;
18510Salexander.borisov@nginx.com 
19510Salexander.borisov@nginx.com     nxt_task_t       *task;
20510Salexander.borisov@nginx.com     nxt_app_rmsg_t   *rmsg;
21510Salexander.borisov@nginx.com     nxt_app_wmsg_t   *wmsg;
22510Salexander.borisov@nginx.com 
23510Salexander.borisov@nginx.com     size_t           body_preread_size;
24510Salexander.borisov@nginx.com } nxt_perl_psgi_input_t;
25510Salexander.borisov@nginx.com 
26510Salexander.borisov@nginx.com 
27521Szelenkov@nginx.com nxt_inline nxt_int_t nxt_perl_psgi_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg,
28510Salexander.borisov@nginx.com     const u_char *data, size_t len,
29510Salexander.borisov@nginx.com     nxt_bool_t flush, nxt_bool_t last);
30510Salexander.borisov@nginx.com 
31510Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_perl_psgi_http_write_status_str(nxt_task_t *task,
32510Salexander.borisov@nginx.com     nxt_app_wmsg_t *wmsg, nxt_str_t *http_status);
33510Salexander.borisov@nginx.com 
34510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl,
35510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length);
36510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl,
37510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length);
38510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_input_flush(PerlInterpreter *my_perl,
39510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
40510Salexander.borisov@nginx.com 
41510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
42510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length);
43510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
44510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length);
45510Salexander.borisov@nginx.com static long nxt_perl_psgi_io_error_flush(PerlInterpreter *my_perl,
46510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
47510Salexander.borisov@nginx.com 
48510Salexander.borisov@nginx.com /*
49510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
50510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr);
51510Salexander.borisov@nginx.com */
52510Salexander.borisov@nginx.com 
53510Salexander.borisov@nginx.com static void nxt_perl_psgi_xs_init(pTHX);
54510Salexander.borisov@nginx.com 
55510Salexander.borisov@nginx.com static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
56510Salexander.borisov@nginx.com     SV *env, nxt_task_t *task);
57510Salexander.borisov@nginx.com 
58510Salexander.borisov@nginx.com /* For currect load XS modules */
59510Salexander.borisov@nginx.com EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
60510Salexander.borisov@nginx.com 
61510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_io_input_init(PerlInterpreter *my_perl,
62510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
63510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl,
64510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg);
65510Salexander.borisov@nginx.com 
66510Salexander.borisov@nginx.com static PerlInterpreter *nxt_perl_psgi_interpreter_init(nxt_task_t *task,
67510Salexander.borisov@nginx.com     char *script);
68510Salexander.borisov@nginx.com 
69510Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_perl_psgi_env_append_str(PerlInterpreter *my_perl,
70510Salexander.borisov@nginx.com     HV *hash_env, const char *name, nxt_str_t *str);
71510Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_perl_psgi_env_append(PerlInterpreter *my_perl,
72510Salexander.borisov@nginx.com     HV *hash_env, const char *name, void *value);
73510Salexander.borisov@nginx.com 
74510Salexander.borisov@nginx.com static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl, nxt_task_t *task,
75510Salexander.borisov@nginx.com     nxt_app_rmsg_t *rmsg, size_t *body_preread_size);
76510Salexander.borisov@nginx.com 
77510Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_perl_psgi_read_add_env(PerlInterpreter *my_perl,
78510Salexander.borisov@nginx.com     nxt_task_t *task, nxt_app_rmsg_t *rmsg, HV *hash_env,
79510Salexander.borisov@nginx.com     const char *name, nxt_str_t *str);
80510Salexander.borisov@nginx.com 
81510Salexander.borisov@nginx.com static u_char *nxt_perl_psgi_module_create(nxt_task_t *task,
82510Salexander.borisov@nginx.com     const char *script);
83510Salexander.borisov@nginx.com 
84510Salexander.borisov@nginx.com static nxt_str_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl,
85510Salexander.borisov@nginx.com     SV *result);
86510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_result_head(PerlInterpreter *my_perl,
87510Salexander.borisov@nginx.com     SV *sv_head, nxt_task_t *task, nxt_app_wmsg_t *wmsg);
88510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_result_body(PerlInterpreter *my_perl,
89510Salexander.borisov@nginx.com     SV *result, nxt_task_t *task, nxt_app_wmsg_t *wmsg);
90510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl,
91510Salexander.borisov@nginx.com     SV *sv_body, nxt_task_t *task, nxt_app_wmsg_t *wmsg);
92510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_result_array(PerlInterpreter *my_perl,
93510Salexander.borisov@nginx.com     SV *result, nxt_task_t *task, nxt_app_wmsg_t *wmsg);
94510Salexander.borisov@nginx.com 
95510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_init(nxt_task_t *task,
96510Salexander.borisov@nginx.com     nxt_common_app_conf_t *conf);
97510Salexander.borisov@nginx.com static nxt_int_t nxt_perl_psgi_run(nxt_task_t *task,
98510Salexander.borisov@nginx.com     nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg);
99510Salexander.borisov@nginx.com static void nxt_perl_psgi_atexit(nxt_task_t *task);
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 SV                      *nxt_perl_psgi_app;
105510Salexander.borisov@nginx.com static PerlInterpreter         *nxt_perl_psgi;
106510Salexander.borisov@nginx.com static nxt_perl_psgi_io_arg_t  nxt_perl_psgi_arg_input, nxt_perl_psgi_arg_error;
107510Salexander.borisov@nginx.com 
108510Salexander.borisov@nginx.com static uint32_t  nxt_perl_psgi_compat[] = {
109510Salexander.borisov@nginx.com     NXT_VERNUM, NXT_DEBUG,
110510Salexander.borisov@nginx.com };
111510Salexander.borisov@nginx.com 
112510Salexander.borisov@nginx.com NXT_EXPORT nxt_application_module_t  nxt_app_module = {
113510Salexander.borisov@nginx.com     sizeof(nxt_perl_psgi_compat),
114510Salexander.borisov@nginx.com     nxt_perl_psgi_compat,
115510Salexander.borisov@nginx.com     nxt_string("perl"),
116*612Salexander.borisov@nginx.com     PERL_VERSION_STRING,
117510Salexander.borisov@nginx.com     nxt_perl_psgi_init,
118510Salexander.borisov@nginx.com     nxt_perl_psgi_run,
119510Salexander.borisov@nginx.com     nxt_perl_psgi_atexit,
120510Salexander.borisov@nginx.com };
121510Salexander.borisov@nginx.com 
122510Salexander.borisov@nginx.com 
123510Salexander.borisov@nginx.com nxt_inline nxt_int_t
124510Salexander.borisov@nginx.com nxt_perl_psgi_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg,
125510Salexander.borisov@nginx.com     const u_char *data, size_t len,
126510Salexander.borisov@nginx.com     nxt_bool_t flush, nxt_bool_t last)
127510Salexander.borisov@nginx.com {
128510Salexander.borisov@nginx.com     nxt_int_t  rc;
129510Salexander.borisov@nginx.com 
130510Salexander.borisov@nginx.com     rc = nxt_app_msg_write_raw(task, wmsg, data, len);
131510Salexander.borisov@nginx.com 
132510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
133510Salexander.borisov@nginx.com         return rc;
134510Salexander.borisov@nginx.com     }
135510Salexander.borisov@nginx.com 
136510Salexander.borisov@nginx.com     if (flush || last) {
137510Salexander.borisov@nginx.com         rc = nxt_app_msg_flush(task, wmsg, last);
138510Salexander.borisov@nginx.com     }
139510Salexander.borisov@nginx.com 
140510Salexander.borisov@nginx.com     return rc;
141510Salexander.borisov@nginx.com }
142510Salexander.borisov@nginx.com 
143510Salexander.borisov@nginx.com 
144510Salexander.borisov@nginx.com nxt_inline nxt_int_t
145510Salexander.borisov@nginx.com nxt_perl_psgi_http_write_status_str(nxt_task_t *task, nxt_app_wmsg_t *wmsg,
146510Salexander.borisov@nginx.com     nxt_str_t *http_status)
147510Salexander.borisov@nginx.com {
148510Salexander.borisov@nginx.com     nxt_int_t  rc;
149510Salexander.borisov@nginx.com 
150510Salexander.borisov@nginx.com     rc = NXT_OK;
151510Salexander.borisov@nginx.com 
152510Salexander.borisov@nginx.com #define RC_WRT(DATA, DATALEN, FLUSH)                       \
153510Salexander.borisov@nginx.com     do {                                                   \
154510Salexander.borisov@nginx.com         rc = nxt_perl_psgi_write(task, wmsg, DATA,         \
155510Salexander.borisov@nginx.com                     DATALEN, FLUSH, 0);                    \
156510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK))                   \
157510Salexander.borisov@nginx.com             return rc;                                     \
158510Salexander.borisov@nginx.com                                                            \
159510Salexander.borisov@nginx.com     } while (0)
160510Salexander.borisov@nginx.com 
161510Salexander.borisov@nginx.com     RC_WRT((const u_char *) "Status: ", (sizeof("Status: ") - 1), 0);
162510Salexander.borisov@nginx.com     RC_WRT(http_status->start, http_status->length, 0);
163510Salexander.borisov@nginx.com     RC_WRT((u_char *) "\r\n", (sizeof("\r\n") - 1), 0);
164510Salexander.borisov@nginx.com 
165510Salexander.borisov@nginx.com #undef RC_WRT
166510Salexander.borisov@nginx.com 
167510Salexander.borisov@nginx.com     return rc;
168510Salexander.borisov@nginx.com }
169510Salexander.borisov@nginx.com 
170510Salexander.borisov@nginx.com 
171510Salexander.borisov@nginx.com static long
172510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl,
173510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
174510Salexander.borisov@nginx.com {
175510Salexander.borisov@nginx.com     size_t                 copy_size;
176510Salexander.borisov@nginx.com     nxt_perl_psgi_input_t  *input;
177510Salexander.borisov@nginx.com 
178510Salexander.borisov@nginx.com     input = (nxt_perl_psgi_input_t *) arg->ctx;
179510Salexander.borisov@nginx.com 
180510Salexander.borisov@nginx.com     if (input->body_preread_size == 0) {
181510Salexander.borisov@nginx.com         return 0;
182510Salexander.borisov@nginx.com     }
183510Salexander.borisov@nginx.com 
184510Salexander.borisov@nginx.com     copy_size = nxt_min(length, input->body_preread_size);
185510Salexander.borisov@nginx.com     copy_size = nxt_app_msg_read_raw(input->task, input->rmsg,
186510Salexander.borisov@nginx.com                                      vbuf, copy_size);
187510Salexander.borisov@nginx.com 
188510Salexander.borisov@nginx.com     input->body_preread_size -= copy_size;
189510Salexander.borisov@nginx.com 
190510Salexander.borisov@nginx.com     return copy_size;
191510Salexander.borisov@nginx.com }
192510Salexander.borisov@nginx.com 
193510Salexander.borisov@nginx.com 
194510Salexander.borisov@nginx.com static long
195510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_write(PerlInterpreter *my_perl,
196510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
197510Salexander.borisov@nginx.com {
198510Salexander.borisov@nginx.com     return 0;
199510Salexander.borisov@nginx.com }
200510Salexander.borisov@nginx.com 
201510Salexander.borisov@nginx.com 
202510Salexander.borisov@nginx.com static long
203510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_flush(PerlInterpreter *my_perl,
204510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
205510Salexander.borisov@nginx.com {
206510Salexander.borisov@nginx.com     return 0;
207510Salexander.borisov@nginx.com }
208510Salexander.borisov@nginx.com 
209510Salexander.borisov@nginx.com 
210510Salexander.borisov@nginx.com static long
211510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_read(PerlInterpreter *my_perl,
212510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length)
213510Salexander.borisov@nginx.com {
214510Salexander.borisov@nginx.com     return 0;
215510Salexander.borisov@nginx.com }
216510Salexander.borisov@nginx.com 
217510Salexander.borisov@nginx.com 
218510Salexander.borisov@nginx.com static long
219510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl,
220510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg, const void *vbuf, size_t length)
221510Salexander.borisov@nginx.com {
222510Salexander.borisov@nginx.com     nxt_perl_psgi_input_t *input;
223510Salexander.borisov@nginx.com 
224510Salexander.borisov@nginx.com     input = (nxt_perl_psgi_input_t *) arg->ctx;
225510Salexander.borisov@nginx.com     nxt_log_error(NXT_LOG_ERR, input->task->log, "Perl: %s", vbuf);
226510Salexander.borisov@nginx.com 
227510Salexander.borisov@nginx.com     return (long) length;
228510Salexander.borisov@nginx.com }
229510Salexander.borisov@nginx.com 
230510Salexander.borisov@nginx.com 
231510Salexander.borisov@nginx.com static long
232510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_flush(PerlInterpreter *my_perl,
233510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
234510Salexander.borisov@nginx.com {
235510Salexander.borisov@nginx.com     return 0;
236510Salexander.borisov@nginx.com }
237510Salexander.borisov@nginx.com 
238510Salexander.borisov@nginx.com 
239510Salexander.borisov@nginx.com /* In the future it will be necessary to change some Perl functions. */
240510Salexander.borisov@nginx.com /*
241510Salexander.borisov@nginx.com static void
242510Salexander.borisov@nginx.com nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl,
243510Salexander.borisov@nginx.com     const char *core, const char *sub, XSUBADDR_t sub_addr)
244510Salexander.borisov@nginx.com {
245510Salexander.borisov@nginx.com     GV  *gv;
246510Salexander.borisov@nginx.com 
247510Salexander.borisov@nginx.com     gv = gv_fetchpv(core, TRUE, SVt_PVCV);
248510Salexander.borisov@nginx.com 
249510Salexander.borisov@nginx.com #ifdef MUTABLE_CV
250510Salexander.borisov@nginx.com     GvCV_set(gv, MUTABLE_CV(SvREFCNT_inc(get_cv(sub, TRUE))));
251510Salexander.borisov@nginx.com #else
252510Salexander.borisov@nginx.com     GvCV_set(gv, (CV *) (SvREFCNT_inc(get_cv(sub, TRUE))));
253510Salexander.borisov@nginx.com #endif
254510Salexander.borisov@nginx.com     GvIMPORTED_CV_on(gv);
255510Salexander.borisov@nginx.com 
256510Salexander.borisov@nginx.com     newXS(sub, sub_addr, __FILE__);
257510Salexander.borisov@nginx.com }
258510Salexander.borisov@nginx.com */
259510Salexander.borisov@nginx.com 
260510Salexander.borisov@nginx.com 
261510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit);
262510Salexander.borisov@nginx.com XS(XS_NGINX__Unit__PSGI_exit)
263510Salexander.borisov@nginx.com {
264510Salexander.borisov@nginx.com     I32 ax = POPMARK;
265510Salexander.borisov@nginx.com     Perl_croak(aTHX_ (char *) NULL);
266510Salexander.borisov@nginx.com     XSRETURN_EMPTY;
267510Salexander.borisov@nginx.com }
268510Salexander.borisov@nginx.com 
269510Salexander.borisov@nginx.com 
270510Salexander.borisov@nginx.com static void
271510Salexander.borisov@nginx.com nxt_perl_psgi_xs_init(pTHX)
272510Salexander.borisov@nginx.com {
273510Salexander.borisov@nginx.com /*
274510Salexander.borisov@nginx.com     nxt_perl_psgi_xs_core_global_changes(my_perl, "CORE::GLOBAL::exit",
275510Salexander.borisov@nginx.com                                          "NGINX::Unit::PSGI::exit",
276510Salexander.borisov@nginx.com                                          XS_NGINX__Unit__PSGI_exit);
277510Salexander.borisov@nginx.com */
278510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_init(aTHX);
279510Salexander.borisov@nginx.com 
280510Salexander.borisov@nginx.com     /* DynaLoader for Perl modules who use XS */
281510Salexander.borisov@nginx.com     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
282510Salexander.borisov@nginx.com }
283510Salexander.borisov@nginx.com 
284510Salexander.borisov@nginx.com 
285510Salexander.borisov@nginx.com static SV *
286510Salexander.borisov@nginx.com nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl,
287510Salexander.borisov@nginx.com     SV *env, nxt_task_t *task)
288510Salexander.borisov@nginx.com {
289510Salexander.borisov@nginx.com     SV  *result;
290510Salexander.borisov@nginx.com 
291510Salexander.borisov@nginx.com     dSP;
292510Salexander.borisov@nginx.com 
293510Salexander.borisov@nginx.com     ENTER;
294510Salexander.borisov@nginx.com     SAVETMPS;
295510Salexander.borisov@nginx.com 
296510Salexander.borisov@nginx.com     PUSHMARK(sp);
297510Salexander.borisov@nginx.com     XPUSHs(env);
298510Salexander.borisov@nginx.com     PUTBACK;
299510Salexander.borisov@nginx.com 
300510Salexander.borisov@nginx.com     call_sv(nxt_perl_psgi_app, G_EVAL|G_SCALAR);
301510Salexander.borisov@nginx.com 
302510Salexander.borisov@nginx.com     SPAGAIN;
303510Salexander.borisov@nginx.com 
304510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
305510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
306510Salexander.borisov@nginx.com                       "PSGI: Failed to run Perl Application: \n%s",
307510Salexander.borisov@nginx.com                       SvPV_nolen(ERRSV));
308510Salexander.borisov@nginx.com     }
309510Salexander.borisov@nginx.com 
310510Salexander.borisov@nginx.com     result = POPs;
311510Salexander.borisov@nginx.com     SvREFCNT_inc(result);
312510Salexander.borisov@nginx.com 
313510Salexander.borisov@nginx.com     PUTBACK;
314510Salexander.borisov@nginx.com     FREETMPS;
315510Salexander.borisov@nginx.com     LEAVE;
316510Salexander.borisov@nginx.com 
317510Salexander.borisov@nginx.com     return result;
318510Salexander.borisov@nginx.com }
319510Salexander.borisov@nginx.com 
320510Salexander.borisov@nginx.com 
321510Salexander.borisov@nginx.com static u_char *
322510Salexander.borisov@nginx.com nxt_perl_psgi_module_create(nxt_task_t *task, const char *script)
323510Salexander.borisov@nginx.com {
324510Salexander.borisov@nginx.com     u_char  *buf, *p;
325510Salexander.borisov@nginx.com     size_t  length;
326510Salexander.borisov@nginx.com 
327510Salexander.borisov@nginx.com     static nxt_str_t  prefix = nxt_string(
328510Salexander.borisov@nginx.com         "package NGINX::Unit::Sandbox;"
329510Salexander.borisov@nginx.com         "{my $app = do \""
330510Salexander.borisov@nginx.com     );
331510Salexander.borisov@nginx.com 
332510Salexander.borisov@nginx.com     static nxt_str_t  suffix = nxt_string_zero(
333510Salexander.borisov@nginx.com         "\";"
334510Salexander.borisov@nginx.com         "unless ($app) {"
335510Salexander.borisov@nginx.com         "    if($@ || $1) {die $@ || $1}"
336510Salexander.borisov@nginx.com         "    else {die \"File not found or compilation error.\"}"
337510Salexander.borisov@nginx.com         "} "
338510Salexander.borisov@nginx.com         "return $app}"
339510Salexander.borisov@nginx.com     );
340510Salexander.borisov@nginx.com 
341510Salexander.borisov@nginx.com     length = strlen(script);
342510Salexander.borisov@nginx.com 
343510Salexander.borisov@nginx.com     buf = nxt_malloc(prefix.length + length + suffix.length);
344510Salexander.borisov@nginx.com 
345510Salexander.borisov@nginx.com     if (nxt_slow_path(buf == NULL)) {
346510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
347510Salexander.borisov@nginx.com                       "PSGI: Failed to allocate memory "
348510Salexander.borisov@nginx.com                       "for Perl script file %s", script);
349510Salexander.borisov@nginx.com         return NULL;
350510Salexander.borisov@nginx.com     }
351510Salexander.borisov@nginx.com 
352510Salexander.borisov@nginx.com     p = nxt_cpymem(buf, prefix.start, prefix.length);
353510Salexander.borisov@nginx.com     p = nxt_cpymem(p, script, length);
354510Salexander.borisov@nginx.com     nxt_memcpy(p, suffix.start, suffix.length);
355510Salexander.borisov@nginx.com 
356510Salexander.borisov@nginx.com     return buf;
357510Salexander.borisov@nginx.com }
358510Salexander.borisov@nginx.com 
359510Salexander.borisov@nginx.com 
360510Salexander.borisov@nginx.com static nxt_int_t
361510Salexander.borisov@nginx.com nxt_perl_psgi_io_input_init(PerlInterpreter *my_perl,
362510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
363510Salexander.borisov@nginx.com {
364510Salexander.borisov@nginx.com     SV      *io;
365510Salexander.borisov@nginx.com     PerlIO  *fp;
366510Salexander.borisov@nginx.com 
367510Salexander.borisov@nginx.com     fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg, "r");
368510Salexander.borisov@nginx.com 
369510Salexander.borisov@nginx.com     if (nxt_slow_path(fp == NULL)) {
370510Salexander.borisov@nginx.com         return NXT_ERROR;
371510Salexander.borisov@nginx.com     }
372510Salexander.borisov@nginx.com 
373510Salexander.borisov@nginx.com     io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp);
374510Salexander.borisov@nginx.com 
375510Salexander.borisov@nginx.com     if (nxt_slow_path(io == NULL)) {
376510Salexander.borisov@nginx.com         nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp);
377510Salexander.borisov@nginx.com         return NXT_ERROR;
378510Salexander.borisov@nginx.com     }
379510Salexander.borisov@nginx.com 
380510Salexander.borisov@nginx.com     arg->io = io;
381510Salexander.borisov@nginx.com     arg->fp = fp;
382510Salexander.borisov@nginx.com     arg->flush = nxt_perl_psgi_io_input_flush;
383510Salexander.borisov@nginx.com     arg->read = nxt_perl_psgi_io_input_read;
384510Salexander.borisov@nginx.com     arg->write = nxt_perl_psgi_io_input_write;
385510Salexander.borisov@nginx.com 
386510Salexander.borisov@nginx.com     return NXT_OK;
387510Salexander.borisov@nginx.com }
388510Salexander.borisov@nginx.com 
389510Salexander.borisov@nginx.com 
390510Salexander.borisov@nginx.com static nxt_int_t
391510Salexander.borisov@nginx.com nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl,
392510Salexander.borisov@nginx.com     nxt_perl_psgi_io_arg_t *arg)
393510Salexander.borisov@nginx.com {
394510Salexander.borisov@nginx.com     SV      *io;
395510Salexander.borisov@nginx.com     PerlIO  *fp;
396510Salexander.borisov@nginx.com 
397510Salexander.borisov@nginx.com     fp = nxt_perl_psgi_layer_stream_fp_create(aTHX_ arg, "w");
398510Salexander.borisov@nginx.com 
399510Salexander.borisov@nginx.com     if (nxt_slow_path(fp == NULL)) {
400510Salexander.borisov@nginx.com         return NXT_ERROR;
401510Salexander.borisov@nginx.com     }
402510Salexander.borisov@nginx.com 
403510Salexander.borisov@nginx.com     io = nxt_perl_psgi_layer_stream_io_create(aTHX_ fp);
404510Salexander.borisov@nginx.com 
405510Salexander.borisov@nginx.com     if (nxt_slow_path(io == NULL)) {
406510Salexander.borisov@nginx.com         nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ fp);
407510Salexander.borisov@nginx.com         return NXT_ERROR;
408510Salexander.borisov@nginx.com     }
409510Salexander.borisov@nginx.com 
410510Salexander.borisov@nginx.com     arg->io = io;
411510Salexander.borisov@nginx.com     arg->fp = fp;
412510Salexander.borisov@nginx.com     arg->flush = nxt_perl_psgi_io_error_flush;
413510Salexander.borisov@nginx.com     arg->read = nxt_perl_psgi_io_error_read;
414510Salexander.borisov@nginx.com     arg->write = nxt_perl_psgi_io_error_write;
415510Salexander.borisov@nginx.com 
416510Salexander.borisov@nginx.com     return NXT_OK;
417510Salexander.borisov@nginx.com }
418510Salexander.borisov@nginx.com 
419510Salexander.borisov@nginx.com 
420510Salexander.borisov@nginx.com static PerlInterpreter *
421510Salexander.borisov@nginx.com nxt_perl_psgi_interpreter_init(nxt_task_t *task, char *script)
422510Salexander.borisov@nginx.com {
423510Salexander.borisov@nginx.com     int              status, pargc;
424510Salexander.borisov@nginx.com     char             **pargv, **penv;
425510Salexander.borisov@nginx.com     u_char           *run_module;
426510Salexander.borisov@nginx.com     PerlInterpreter  *my_perl;
427510Salexander.borisov@nginx.com 
428510Salexander.borisov@nginx.com     static char  argv[] = "\0""-e\0""0";
429510Salexander.borisov@nginx.com     static char  *embedding[] = { &argv[0], &argv[1], &argv[4] };
430510Salexander.borisov@nginx.com 
431510Salexander.borisov@nginx.com     pargc = 0;
432510Salexander.borisov@nginx.com     pargv = NULL;
433510Salexander.borisov@nginx.com     penv = NULL;
434510Salexander.borisov@nginx.com 
435510Salexander.borisov@nginx.com     PERL_SYS_INIT3(&pargc, &pargv, &penv);
436510Salexander.borisov@nginx.com 
437510Salexander.borisov@nginx.com     my_perl = perl_alloc();
438510Salexander.borisov@nginx.com 
439510Salexander.borisov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
440564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to allocate memory for Perl interpreter");
441510Salexander.borisov@nginx.com         return NULL;
442510Salexander.borisov@nginx.com     }
443510Salexander.borisov@nginx.com 
444510Salexander.borisov@nginx.com     run_module = NULL;
445510Salexander.borisov@nginx.com 
446510Salexander.borisov@nginx.com     perl_construct(my_perl);
447510Salexander.borisov@nginx.com     PERL_SET_CONTEXT(my_perl);
448510Salexander.borisov@nginx.com 
449510Salexander.borisov@nginx.com     status = perl_parse(my_perl, nxt_perl_psgi_xs_init, 3, embedding, NULL);
450510Salexander.borisov@nginx.com 
451510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
452564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to parse Perl Script");
453510Salexander.borisov@nginx.com         goto fail;
454510Salexander.borisov@nginx.com     }
455510Salexander.borisov@nginx.com 
456510Salexander.borisov@nginx.com     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
457510Salexander.borisov@nginx.com     PL_origalen = 1;
458510Salexander.borisov@nginx.com 
459510Salexander.borisov@nginx.com     status = perl_run(my_perl);
460510Salexander.borisov@nginx.com 
461510Salexander.borisov@nginx.com     if (nxt_slow_path(status != 0)) {
462564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to run Perl");
463510Salexander.borisov@nginx.com         goto fail;
464510Salexander.borisov@nginx.com     }
465510Salexander.borisov@nginx.com 
466510Salexander.borisov@nginx.com     sv_setsv(get_sv("0", 0), newSVpv(script, 0));
467510Salexander.borisov@nginx.com 
468510Salexander.borisov@nginx.com     run_module = nxt_perl_psgi_module_create(task, script);
469510Salexander.borisov@nginx.com 
470510Salexander.borisov@nginx.com     if (nxt_slow_path(run_module == NULL)) {
471510Salexander.borisov@nginx.com         goto fail;
472510Salexander.borisov@nginx.com     }
473510Salexander.borisov@nginx.com 
474510Salexander.borisov@nginx.com     status = nxt_perl_psgi_io_input_init(my_perl, &nxt_perl_psgi_arg_input);
475510Salexander.borisov@nginx.com 
476510Salexander.borisov@nginx.com     if (nxt_slow_path(status != NXT_OK)) {
477564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to init io.psgi.input");
478510Salexander.borisov@nginx.com         goto fail;
479510Salexander.borisov@nginx.com     }
480510Salexander.borisov@nginx.com 
481510Salexander.borisov@nginx.com     status = nxt_perl_psgi_io_error_init(my_perl, &nxt_perl_psgi_arg_error);
482510Salexander.borisov@nginx.com 
483510Salexander.borisov@nginx.com     if (nxt_slow_path(status != NXT_OK)) {
484564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to init io.psgi.errors");
485510Salexander.borisov@nginx.com         goto fail;
486510Salexander.borisov@nginx.com     }
487510Salexander.borisov@nginx.com 
488510Salexander.borisov@nginx.com     nxt_perl_psgi_app = eval_pv((const char *) run_module, FALSE);
489510Salexander.borisov@nginx.com 
490510Salexander.borisov@nginx.com     if (SvTRUE(ERRSV)) {
491564Svbart@nginx.com         nxt_alert(task, "PSGI: Failed to parse script: %s\n%s",
492564Svbart@nginx.com                   script, SvPV_nolen(ERRSV));
493510Salexander.borisov@nginx.com         goto fail;
494510Salexander.borisov@nginx.com     }
495510Salexander.borisov@nginx.com 
496510Salexander.borisov@nginx.com     nxt_free(run_module);
497510Salexander.borisov@nginx.com 
498510Salexander.borisov@nginx.com     return my_perl;
499510Salexander.borisov@nginx.com 
500510Salexander.borisov@nginx.com fail:
501510Salexander.borisov@nginx.com 
502510Salexander.borisov@nginx.com     if (run_module != NULL) {
503510Salexander.borisov@nginx.com         nxt_free(run_module);
504510Salexander.borisov@nginx.com     }
505510Salexander.borisov@nginx.com 
506510Salexander.borisov@nginx.com     perl_destruct(my_perl);
507510Salexander.borisov@nginx.com     perl_free(my_perl);
508510Salexander.borisov@nginx.com     PERL_SYS_TERM();
509510Salexander.borisov@nginx.com 
510510Salexander.borisov@nginx.com     return NULL;
511510Salexander.borisov@nginx.com }
512510Salexander.borisov@nginx.com 
513510Salexander.borisov@nginx.com 
514510Salexander.borisov@nginx.com nxt_inline nxt_int_t
515510Salexander.borisov@nginx.com nxt_perl_psgi_env_append_str(PerlInterpreter *my_perl, HV *hash_env,
516510Salexander.borisov@nginx.com     const char *name, nxt_str_t *str)
517510Salexander.borisov@nginx.com {
518510Salexander.borisov@nginx.com     SV  **ha;
519510Salexander.borisov@nginx.com 
520510Salexander.borisov@nginx.com     ha = hv_store(hash_env, name, (I32) strlen(name),
521521Szelenkov@nginx.com                   newSVpv((const char *) str->start, (STRLEN) str->length), 0);
522510Salexander.borisov@nginx.com 
523510Salexander.borisov@nginx.com     if (nxt_slow_path(ha == NULL)) {
524510Salexander.borisov@nginx.com         return NXT_ERROR;
525510Salexander.borisov@nginx.com     }
526510Salexander.borisov@nginx.com 
527510Salexander.borisov@nginx.com     return NXT_OK;
528510Salexander.borisov@nginx.com }
529510Salexander.borisov@nginx.com 
530510Salexander.borisov@nginx.com 
531510Salexander.borisov@nginx.com nxt_inline nxt_int_t
532510Salexander.borisov@nginx.com nxt_perl_psgi_env_append(PerlInterpreter *my_perl, HV *hash_env,
533510Salexander.borisov@nginx.com     const char *name, void *value)
534510Salexander.borisov@nginx.com {
535510Salexander.borisov@nginx.com     SV  **ha;
536510Salexander.borisov@nginx.com 
537510Salexander.borisov@nginx.com     ha = hv_store(hash_env, name, (I32) strlen(name), value, 0);
538510Salexander.borisov@nginx.com 
539510Salexander.borisov@nginx.com     if (nxt_slow_path(ha == NULL)) {
540510Salexander.borisov@nginx.com         return NXT_ERROR;
541510Salexander.borisov@nginx.com     }
542510Salexander.borisov@nginx.com 
543510Salexander.borisov@nginx.com     return NXT_OK;
544510Salexander.borisov@nginx.com }
545510Salexander.borisov@nginx.com 
546510Salexander.borisov@nginx.com 
547510Salexander.borisov@nginx.com nxt_inline nxt_int_t
548510Salexander.borisov@nginx.com nxt_perl_psgi_read_add_env(PerlInterpreter *my_perl, nxt_task_t *task,
549510Salexander.borisov@nginx.com     nxt_app_rmsg_t *rmsg, HV *hash_env,
550510Salexander.borisov@nginx.com     const char *name, nxt_str_t *str)
551510Salexander.borisov@nginx.com {
552510Salexander.borisov@nginx.com     nxt_int_t  rc;
553510Salexander.borisov@nginx.com 
554510Salexander.borisov@nginx.com     rc = nxt_app_msg_read_str(task, rmsg, str);
555510Salexander.borisov@nginx.com 
556510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
557510Salexander.borisov@nginx.com         return rc;
558510Salexander.borisov@nginx.com     }
559510Salexander.borisov@nginx.com 
560510Salexander.borisov@nginx.com     if (str->start == NULL) {
561510Salexander.borisov@nginx.com         return NXT_OK;
562510Salexander.borisov@nginx.com     }
563510Salexander.borisov@nginx.com 
564510Salexander.borisov@nginx.com     return nxt_perl_psgi_env_append_str(my_perl, hash_env, name, str);
565510Salexander.borisov@nginx.com }
566510Salexander.borisov@nginx.com 
567510Salexander.borisov@nginx.com 
568510Salexander.borisov@nginx.com static SV *
569510Salexander.borisov@nginx.com nxt_perl_psgi_env_create(PerlInterpreter *my_perl, nxt_task_t *task,
570510Salexander.borisov@nginx.com     nxt_app_rmsg_t *rmsg, size_t *body_preread_size)
571510Salexander.borisov@nginx.com {
572510Salexander.borisov@nginx.com     HV         *hash_env;
573510Salexander.borisov@nginx.com     AV         *array_version;
574510Salexander.borisov@nginx.com     u_char     *colon;
575510Salexander.borisov@nginx.com     size_t     query_size;
576510Salexander.borisov@nginx.com     nxt_int_t  rc;
577510Salexander.borisov@nginx.com     nxt_str_t  str, value, path, target;
578510Salexander.borisov@nginx.com     nxt_str_t  host, server_name, server_port;
579510Salexander.borisov@nginx.com 
580510Salexander.borisov@nginx.com     static nxt_str_t  def_host = nxt_string("localhost");
581510Salexander.borisov@nginx.com     static nxt_str_t  def_port = nxt_string("80");
582510Salexander.borisov@nginx.com 
583510Salexander.borisov@nginx.com     hash_env = newHV();
584510Salexander.borisov@nginx.com 
585510Salexander.borisov@nginx.com     if (nxt_slow_path(hash_env == NULL)) {
586510Salexander.borisov@nginx.com         return NULL;
587510Salexander.borisov@nginx.com     }
588510Salexander.borisov@nginx.com 
589510Salexander.borisov@nginx.com #define RC(FNS)                                                  \
590510Salexander.borisov@nginx.com     do {                                                         \
591510Salexander.borisov@nginx.com         if (nxt_slow_path((FNS) != NXT_OK))                      \
592510Salexander.borisov@nginx.com             goto fail;                                           \
593510Salexander.borisov@nginx.com     } while (0)
594510Salexander.borisov@nginx.com 
595510Salexander.borisov@nginx.com #define GET_STR(ATTR)                                            \
596510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_read_add_env(my_perl, task, rmsg,           \
597510Salexander.borisov@nginx.com         hash_env, ATTR, &str))
598510Salexander.borisov@nginx.com 
599510Salexander.borisov@nginx.com     GET_STR("REQUEST_METHOD");
600510Salexander.borisov@nginx.com     GET_STR("REQUEST_URI");
601510Salexander.borisov@nginx.com 
602510Salexander.borisov@nginx.com     target = str;
603510Salexander.borisov@nginx.com 
604510Salexander.borisov@nginx.com     RC(nxt_app_msg_read_str(task, rmsg, &path));
605510Salexander.borisov@nginx.com     RC(nxt_app_msg_read_size(task, rmsg, &query_size));
606510Salexander.borisov@nginx.com 
607510Salexander.borisov@nginx.com     if (path.start == NULL || path.length == 0) {
608510Salexander.borisov@nginx.com         path = target;
609510Salexander.borisov@nginx.com     }
610510Salexander.borisov@nginx.com 
611580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, "PATH_INFO",
612580Salexander.borisov@nginx.com                                     &path));
613580Salexander.borisov@nginx.com 
614510Salexander.borisov@nginx.com     array_version = newAV();
615510Salexander.borisov@nginx.com 
616510Salexander.borisov@nginx.com     if (nxt_slow_path(array_version == NULL)) {
617510Salexander.borisov@nginx.com         goto fail;
618510Salexander.borisov@nginx.com     }
619510Salexander.borisov@nginx.com 
620510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
621510Salexander.borisov@nginx.com     av_push(array_version, newSViv(1));
622510Salexander.borisov@nginx.com 
623580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.version",
624580Salexander.borisov@nginx.com                                 newRV_noinc((SV *) array_version)));
625510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.url_scheme",
626510Salexander.borisov@nginx.com                                 newSVpv("http", 4)));
627510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.input",
628510Salexander.borisov@nginx.com                                 SvREFCNT_inc(nxt_perl_psgi_arg_input.io)));
629510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.errors",
630510Salexander.borisov@nginx.com                                 SvREFCNT_inc(nxt_perl_psgi_arg_error.io)));
631580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.multithread",
632580Salexander.borisov@nginx.com                                 &PL_sv_no));
633580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.multiprocess",
634580Salexander.borisov@nginx.com                                 &PL_sv_yes));
635580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.run_once",
636580Salexander.borisov@nginx.com                                 &PL_sv_no));
637580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.nonblocking",
638580Salexander.borisov@nginx.com                                 &PL_sv_no));
639580Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.streaming",
640580Salexander.borisov@nginx.com                                 &PL_sv_no));
641510Salexander.borisov@nginx.com 
642510Salexander.borisov@nginx.com     if (query_size > 0) {
643510Salexander.borisov@nginx.com         query_size--;
644510Salexander.borisov@nginx.com 
645510Salexander.borisov@nginx.com         if (nxt_slow_path(target.length < query_size)) {
646510Salexander.borisov@nginx.com             goto fail;
647510Salexander.borisov@nginx.com         }
648510Salexander.borisov@nginx.com 
649510Salexander.borisov@nginx.com         str.start = &target.start[query_size];
650510Salexander.borisov@nginx.com         str.length = target.length - query_size;
651510Salexander.borisov@nginx.com 
652510Salexander.borisov@nginx.com         RC(nxt_perl_psgi_env_append_str(my_perl, hash_env,
653510Salexander.borisov@nginx.com                                         "QUERY_STRING", &str));
654510Salexander.borisov@nginx.com     }
655510Salexander.borisov@nginx.com 
656510Salexander.borisov@nginx.com     GET_STR("SERVER_PROTOCOL");
657510Salexander.borisov@nginx.com     GET_STR("REMOTE_ADDR");
658510Salexander.borisov@nginx.com     GET_STR("SERVER_ADDR");
659510Salexander.borisov@nginx.com 
660510Salexander.borisov@nginx.com     RC(nxt_app_msg_read_str(task, rmsg, &host));
661510Salexander.borisov@nginx.com 
662510Salexander.borisov@nginx.com     if (host.length == 0) {
663510Salexander.borisov@nginx.com         host = def_host;
664510Salexander.borisov@nginx.com     }
665510Salexander.borisov@nginx.com 
666510Salexander.borisov@nginx.com     colon = nxt_memchr(host.start, ':', host.length);
667510Salexander.borisov@nginx.com     server_name = host;
668510Salexander.borisov@nginx.com 
669510Salexander.borisov@nginx.com     if (colon != NULL) {
670510Salexander.borisov@nginx.com         server_name.length = colon - host.start;
671510Salexander.borisov@nginx.com 
672510Salexander.borisov@nginx.com         server_port.start = colon + 1;
673510Salexander.borisov@nginx.com         server_port.length = host.length - server_name.length - 1;
674510Salexander.borisov@nginx.com 
675510Salexander.borisov@nginx.com     } else {
676510Salexander.borisov@nginx.com         server_port = def_port;
677510Salexander.borisov@nginx.com     }
678510Salexander.borisov@nginx.com 
679510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append_str(my_perl, hash_env,
680510Salexander.borisov@nginx.com                                     "SERVER_NAME", &server_name));
681510Salexander.borisov@nginx.com     RC(nxt_perl_psgi_env_append_str(my_perl, hash_env,
682510Salexander.borisov@nginx.com                                     "SERVER_PORT", &server_port));
683510Salexander.borisov@nginx.com 
684510Salexander.borisov@nginx.com     GET_STR("CONTENT_TYPE");
685510Salexander.borisov@nginx.com     GET_STR("CONTENT_LENGTH");
686510Salexander.borisov@nginx.com 
687510Salexander.borisov@nginx.com     for ( ;; ) {
688510Salexander.borisov@nginx.com         rc = nxt_app_msg_read_str(task, rmsg, &str);
689510Salexander.borisov@nginx.com 
690510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
691510Salexander.borisov@nginx.com             goto fail;
692510Salexander.borisov@nginx.com         }
693510Salexander.borisov@nginx.com 
694510Salexander.borisov@nginx.com         if (nxt_slow_path(str.length == 0)) {
695510Salexander.borisov@nginx.com             break;
696510Salexander.borisov@nginx.com         }
697510Salexander.borisov@nginx.com 
698510Salexander.borisov@nginx.com         rc = nxt_app_msg_read_str(task, rmsg, &value);
699510Salexander.borisov@nginx.com 
700510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
701510Salexander.borisov@nginx.com             break;
702510Salexander.borisov@nginx.com         }
703510Salexander.borisov@nginx.com 
704510Salexander.borisov@nginx.com         RC(nxt_perl_psgi_env_append_str(my_perl, hash_env,
705510Salexander.borisov@nginx.com                                         (char *) str.start, &value));
706510Salexander.borisov@nginx.com     }
707510Salexander.borisov@nginx.com 
708510Salexander.borisov@nginx.com     RC(nxt_app_msg_read_size(task, rmsg, body_preread_size));
709510Salexander.borisov@nginx.com 
710510Salexander.borisov@nginx.com #undef GET_STR
711510Salexander.borisov@nginx.com #undef RC
712510Salexander.borisov@nginx.com 
713510Salexander.borisov@nginx.com     return newRV_noinc((SV *) hash_env);
714510Salexander.borisov@nginx.com 
715510Salexander.borisov@nginx.com fail:
716510Salexander.borisov@nginx.com 
717510Salexander.borisov@nginx.com     SvREFCNT_dec(hash_env);
718510Salexander.borisov@nginx.com 
719510Salexander.borisov@nginx.com     return NULL;
720510Salexander.borisov@nginx.com }
721510Salexander.borisov@nginx.com 
722510Salexander.borisov@nginx.com 
723510Salexander.borisov@nginx.com static nxt_str_t
724510Salexander.borisov@nginx.com nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result)
725510Salexander.borisov@nginx.com {
726510Salexander.borisov@nginx.com     SV         **sv_status;
727510Salexander.borisov@nginx.com     AV         *array;
728510Salexander.borisov@nginx.com     nxt_str_t  status;
729510Salexander.borisov@nginx.com 
730510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
731510Salexander.borisov@nginx.com     sv_status = av_fetch(array, 0, 0);
732510Salexander.borisov@nginx.com 
733510Salexander.borisov@nginx.com     status.start = (u_char *) SvPV(*sv_status, status.length);
734510Salexander.borisov@nginx.com 
735510Salexander.borisov@nginx.com     return status;
736510Salexander.borisov@nginx.com }
737510Salexander.borisov@nginx.com 
738510Salexander.borisov@nginx.com 
739510Salexander.borisov@nginx.com static nxt_int_t
740510Salexander.borisov@nginx.com nxt_perl_psgi_result_head(PerlInterpreter *my_perl, SV *sv_head,
741510Salexander.borisov@nginx.com     nxt_task_t *task, nxt_app_wmsg_t *wmsg)
742510Salexander.borisov@nginx.com {
743510Salexander.borisov@nginx.com     AV         *array_head;
744510Salexander.borisov@nginx.com     SV         **entry;
745510Salexander.borisov@nginx.com     long       i, array_len;
746510Salexander.borisov@nginx.com     nxt_int_t  rc;
747510Salexander.borisov@nginx.com     nxt_str_t  body;
748510Salexander.borisov@nginx.com 
749510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_head) == 0
750510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_head)) != SVt_PVAV))
751510Salexander.borisov@nginx.com     {
752510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
753510Salexander.borisov@nginx.com                       "PSGI: An unsupported format was received from "
754510Salexander.borisov@nginx.com                       "Perl Application for head part");
755510Salexander.borisov@nginx.com 
756510Salexander.borisov@nginx.com         return NXT_ERROR;
757510Salexander.borisov@nginx.com     }
758510Salexander.borisov@nginx.com 
759510Salexander.borisov@nginx.com     array_head = (AV *) SvRV(sv_head);
760510Salexander.borisov@nginx.com     array_len = av_len(array_head);
761510Salexander.borisov@nginx.com 
762510Salexander.borisov@nginx.com     if (array_len < 1) {
763510Salexander.borisov@nginx.com         return NXT_OK;
764510Salexander.borisov@nginx.com     }
765510Salexander.borisov@nginx.com 
766510Salexander.borisov@nginx.com     if (nxt_slow_path((array_len % 2) == 0)) {
767510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
768510Salexander.borisov@nginx.com                       "PSGI: Bad format for head from "
769510Salexander.borisov@nginx.com                       "Perl Application");
770510Salexander.borisov@nginx.com 
771510Salexander.borisov@nginx.com         return NXT_ERROR;
772510Salexander.borisov@nginx.com     }
773510Salexander.borisov@nginx.com 
774510Salexander.borisov@nginx.com     for (i = 0; i <= array_len; i++) {
775510Salexander.borisov@nginx.com         entry = av_fetch(array_head, i, 0);
776510Salexander.borisov@nginx.com 
777510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
778510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
779510Salexander.borisov@nginx.com                           "PSGI: Failed to get head entry from "
780510Salexander.borisov@nginx.com                           "Perl Application");
781510Salexander.borisov@nginx.com 
782510Salexander.borisov@nginx.com             return NXT_ERROR;
783510Salexander.borisov@nginx.com         }
784510Salexander.borisov@nginx.com 
785510Salexander.borisov@nginx.com         body.start = (u_char *) SvPV(*entry, body.length);
786510Salexander.borisov@nginx.com 
787510Salexander.borisov@nginx.com         rc = nxt_app_msg_write_raw(task, wmsg,
788510Salexander.borisov@nginx.com                                    (u_char *) body.start, body.length);
789510Salexander.borisov@nginx.com 
790510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
791510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
792510Salexander.borisov@nginx.com                           "PSGI: Failed to write head "
793510Salexander.borisov@nginx.com                           "from Perl Application");
794510Salexander.borisov@nginx.com             return rc;
795510Salexander.borisov@nginx.com         }
796510Salexander.borisov@nginx.com 
797510Salexander.borisov@nginx.com         if ((i % 2) == 0) {
798510Salexander.borisov@nginx.com             rc = nxt_app_msg_write_raw(task, wmsg,
799510Salexander.borisov@nginx.com                                        (u_char *) ": ",
800510Salexander.borisov@nginx.com                                        (sizeof(": ") - 1));
801510Salexander.borisov@nginx.com         } else {
802510Salexander.borisov@nginx.com             rc = nxt_app_msg_write_raw(task, wmsg,
803510Salexander.borisov@nginx.com                                        (u_char *) "\r\n",
804510Salexander.borisov@nginx.com                                        (sizeof("\r\n") - 1));
805510Salexander.borisov@nginx.com         }
806510Salexander.borisov@nginx.com 
807510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
808510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
809510Salexander.borisov@nginx.com                           "PSGI: Failed to write head from "
810510Salexander.borisov@nginx.com                           "Perl Application");
811510Salexander.borisov@nginx.com             return rc;
812510Salexander.borisov@nginx.com         }
813510Salexander.borisov@nginx.com     }
814510Salexander.borisov@nginx.com 
815510Salexander.borisov@nginx.com     return NXT_OK;
816510Salexander.borisov@nginx.com }
817510Salexander.borisov@nginx.com 
818510Salexander.borisov@nginx.com 
819510Salexander.borisov@nginx.com static nxt_int_t
820510Salexander.borisov@nginx.com nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body,
821510Salexander.borisov@nginx.com     nxt_task_t *task, nxt_app_wmsg_t *wmsg)
822510Salexander.borisov@nginx.com {
823510Salexander.borisov@nginx.com     SV         **entry;
824510Salexander.borisov@nginx.com     AV         *body_array;
825510Salexander.borisov@nginx.com     long       i;
826510Salexander.borisov@nginx.com     nxt_int_t  rc;
827510Salexander.borisov@nginx.com     nxt_str_t  body;
828510Salexander.borisov@nginx.com 
829510Salexander.borisov@nginx.com     if (nxt_slow_path(SvROK(sv_body) == 0
830510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(sv_body)) != SVt_PVAV))
831510Salexander.borisov@nginx.com     {
832510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
833510Salexander.borisov@nginx.com                       "PSGI: An unsupported format was received from "
834510Salexander.borisov@nginx.com                       "Perl Application for a body part");
835510Salexander.borisov@nginx.com 
836510Salexander.borisov@nginx.com         return NXT_ERROR;
837510Salexander.borisov@nginx.com     }
838510Salexander.borisov@nginx.com 
839510Salexander.borisov@nginx.com     body_array = (AV *) SvRV(sv_body);
840510Salexander.borisov@nginx.com 
841510Salexander.borisov@nginx.com     for (i = 0; i <= av_len(body_array); i++) {
842510Salexander.borisov@nginx.com 
843510Salexander.borisov@nginx.com         entry = av_fetch(body_array, i, 0);
844510Salexander.borisov@nginx.com 
845510Salexander.borisov@nginx.com         if (nxt_fast_path(entry == NULL)) {
846510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
847510Salexander.borisov@nginx.com                           "PSGI: Failed to get body entry from "
848510Salexander.borisov@nginx.com                           "Perl Application");
849510Salexander.borisov@nginx.com             return NXT_ERROR;
850510Salexander.borisov@nginx.com         }
851510Salexander.borisov@nginx.com 
852510Salexander.borisov@nginx.com         body.start = (u_char *) SvPV(*entry, body.length);
853510Salexander.borisov@nginx.com 
854510Salexander.borisov@nginx.com         if (body.length == 0) {
855510Salexander.borisov@nginx.com             continue;
856510Salexander.borisov@nginx.com         }
857510Salexander.borisov@nginx.com 
858510Salexander.borisov@nginx.com         rc = nxt_app_msg_write_raw(task, wmsg,
859510Salexander.borisov@nginx.com                                    (u_char *) body.start, body.length);
860510Salexander.borisov@nginx.com 
861510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
862510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
863510Salexander.borisov@nginx.com                           "PSGI: Failed to write 'body' from "
864510Salexander.borisov@nginx.com                           "Perl Application");
865510Salexander.borisov@nginx.com             return rc;
866510Salexander.borisov@nginx.com         }
867510Salexander.borisov@nginx.com 
868510Salexander.borisov@nginx.com         rc = nxt_app_msg_flush(task, wmsg, 0);
869510Salexander.borisov@nginx.com 
870510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
871510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
872510Salexander.borisov@nginx.com                           "PSGI: Failed to flush data for a 'body' "
873510Salexander.borisov@nginx.com                           "part from Perl Application");
874510Salexander.borisov@nginx.com             return rc;
875510Salexander.borisov@nginx.com         }
876510Salexander.borisov@nginx.com     }
877510Salexander.borisov@nginx.com 
878510Salexander.borisov@nginx.com     return NXT_OK;
879510Salexander.borisov@nginx.com }
880510Salexander.borisov@nginx.com 
881510Salexander.borisov@nginx.com 
882510Salexander.borisov@nginx.com static nxt_int_t
883510Salexander.borisov@nginx.com nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body,
884510Salexander.borisov@nginx.com     nxt_task_t *task, nxt_app_wmsg_t *wmsg)
885510Salexander.borisov@nginx.com {
886510Salexander.borisov@nginx.com     IO         *io;
887510Salexander.borisov@nginx.com     PerlIO     *fp;
888510Salexander.borisov@nginx.com     SSize_t    n;
889510Salexander.borisov@nginx.com     nxt_int_t  rc;
890510Salexander.borisov@nginx.com     u_char     vbuf[8192];
891510Salexander.borisov@nginx.com 
892510Salexander.borisov@nginx.com     io = GvIO(SvRV(sv_body));
893519Salexander.borisov@nginx.com 
894519Salexander.borisov@nginx.com     if (io == NULL) {
895519Salexander.borisov@nginx.com         return NXT_OK;
896519Salexander.borisov@nginx.com     }
897519Salexander.borisov@nginx.com 
898510Salexander.borisov@nginx.com     fp = IoIFP(io);
899510Salexander.borisov@nginx.com 
900510Salexander.borisov@nginx.com     for ( ;; ) {
901510Salexander.borisov@nginx.com         n = PerlIO_read(fp, vbuf, 8192);
902510Salexander.borisov@nginx.com 
903510Salexander.borisov@nginx.com         if (n < 1) {
904510Salexander.borisov@nginx.com             break;
905510Salexander.borisov@nginx.com         }
906510Salexander.borisov@nginx.com 
907510Salexander.borisov@nginx.com         rc = nxt_app_msg_write_raw(task, wmsg,
908510Salexander.borisov@nginx.com                                    (u_char *) vbuf, (size_t) n);
909510Salexander.borisov@nginx.com 
910510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
911510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
912510Salexander.borisov@nginx.com                           "PSGI: Failed to write 'body' from "
913510Salexander.borisov@nginx.com                           "Perl Application");
914510Salexander.borisov@nginx.com 
915510Salexander.borisov@nginx.com             return rc;
916510Salexander.borisov@nginx.com         }
917510Salexander.borisov@nginx.com 
918510Salexander.borisov@nginx.com         rc = nxt_app_msg_flush(task, wmsg, 0);
919510Salexander.borisov@nginx.com 
920510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
921510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
922510Salexander.borisov@nginx.com                           "PSGI: Failed to flush data for a body "
923510Salexander.borisov@nginx.com                           "part from Perl Application");
924510Salexander.borisov@nginx.com 
925510Salexander.borisov@nginx.com             return rc;
926510Salexander.borisov@nginx.com         }
927510Salexander.borisov@nginx.com     }
928510Salexander.borisov@nginx.com 
929510Salexander.borisov@nginx.com     return NXT_OK;
930510Salexander.borisov@nginx.com }
931510Salexander.borisov@nginx.com 
932510Salexander.borisov@nginx.com 
933510Salexander.borisov@nginx.com static nxt_int_t
934510Salexander.borisov@nginx.com nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result,
935510Salexander.borisov@nginx.com     nxt_task_t *task, nxt_app_wmsg_t *wmsg)
936510Salexander.borisov@nginx.com {
937510Salexander.borisov@nginx.com     AV         *array;
938510Salexander.borisov@nginx.com     SV         **sv_temp;
939510Salexander.borisov@nginx.com     long       array_len;
940510Salexander.borisov@nginx.com     nxt_int_t  rc;
941510Salexander.borisov@nginx.com     nxt_str_t  http_status;
942510Salexander.borisov@nginx.com 
943510Salexander.borisov@nginx.com     array = (AV *) SvRV(result);
944510Salexander.borisov@nginx.com     array_len = av_len(array);
945510Salexander.borisov@nginx.com 
946510Salexander.borisov@nginx.com     if (nxt_slow_path(array_len < 0)) {
947510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
948510Salexander.borisov@nginx.com                       "PSGI: Invalid result format from Perl Application");
949510Salexander.borisov@nginx.com 
950510Salexander.borisov@nginx.com         return NXT_ERROR;
951510Salexander.borisov@nginx.com     }
952510Salexander.borisov@nginx.com 
953510Salexander.borisov@nginx.com     http_status = nxt_perl_psgi_result_status(nxt_perl_psgi, result);
954510Salexander.borisov@nginx.com 
955510Salexander.borisov@nginx.com     if (nxt_slow_path(http_status.start == NULL || http_status.length == 0)) {
956510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
957510Salexander.borisov@nginx.com                       "PSGI: An unexpected status was received "
958510Salexander.borisov@nginx.com                       "from Perl Application");
959510Salexander.borisov@nginx.com 
960510Salexander.borisov@nginx.com         return NXT_ERROR;
961510Salexander.borisov@nginx.com     }
962510Salexander.borisov@nginx.com 
963510Salexander.borisov@nginx.com     rc = nxt_perl_psgi_http_write_status_str(task, wmsg, &http_status);
964510Salexander.borisov@nginx.com 
965510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
966510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
967510Salexander.borisov@nginx.com                       "PSGI: Failed to write HTTP Status");
968510Salexander.borisov@nginx.com 
969510Salexander.borisov@nginx.com         return rc;
970510Salexander.borisov@nginx.com     }
971510Salexander.borisov@nginx.com 
972510Salexander.borisov@nginx.com     if (array_len < 1) {
973510Salexander.borisov@nginx.com         rc = nxt_app_msg_write_raw(task, wmsg, (u_char *) "\r\n",
974510Salexander.borisov@nginx.com                                    (sizeof("\r\n") - 1));
975510Salexander.borisov@nginx.com 
976510Salexander.borisov@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
977510Salexander.borisov@nginx.com             nxt_log_error(NXT_LOG_ERR, task->log,
978510Salexander.borisov@nginx.com                           "PSGI: Failed to write HTTP Headers");
979510Salexander.borisov@nginx.com 
980510Salexander.borisov@nginx.com             return rc;
981510Salexander.borisov@nginx.com         }
982510Salexander.borisov@nginx.com 
983510Salexander.borisov@nginx.com         return NXT_OK;
984510Salexander.borisov@nginx.com     }
985510Salexander.borisov@nginx.com 
986510Salexander.borisov@nginx.com     sv_temp = av_fetch(array, 1, 0);
987510Salexander.borisov@nginx.com 
988510Salexander.borisov@nginx.com     if (nxt_slow_path(sv_temp == NULL)) {
989510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
990510Salexander.borisov@nginx.com                       "PSGI: Failed to get head from Perl ARRAY variable");
991510Salexander.borisov@nginx.com 
992510Salexander.borisov@nginx.com         return NXT_ERROR;
993510Salexander.borisov@nginx.com     }
994510Salexander.borisov@nginx.com 
995510Salexander.borisov@nginx.com     rc = nxt_perl_psgi_result_head(nxt_perl_psgi, *sv_temp, task, wmsg);
996510Salexander.borisov@nginx.com 
997510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
998510Salexander.borisov@nginx.com         return rc;
999510Salexander.borisov@nginx.com     }
1000510Salexander.borisov@nginx.com 
1001510Salexander.borisov@nginx.com     rc = nxt_app_msg_write_raw(task, wmsg, (u_char *) "\r\n",
1002510Salexander.borisov@nginx.com                                (sizeof("\r\n") - 1));
1003510Salexander.borisov@nginx.com 
1004510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1005510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
1006510Salexander.borisov@nginx.com                       "PSGI: Failed to write HTTP Headers");
1007510Salexander.borisov@nginx.com 
1008510Salexander.borisov@nginx.com         return rc;
1009510Salexander.borisov@nginx.com     }
1010510Salexander.borisov@nginx.com 
1011510Salexander.borisov@nginx.com     if (nxt_fast_path(array_len < 2)) {
1012510Salexander.borisov@nginx.com         return NXT_OK;
1013510Salexander.borisov@nginx.com     }
1014510Salexander.borisov@nginx.com 
1015510Salexander.borisov@nginx.com     sv_temp = av_fetch(array, 2, 0);
1016510Salexander.borisov@nginx.com 
1017519Salexander.borisov@nginx.com     if (nxt_slow_path(sv_temp == NULL || SvROK(*sv_temp) == FALSE)) {
1018510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
1019510Salexander.borisov@nginx.com                       "PSGI: Failed to get body from Perl ARRAY variable");
1020510Salexander.borisov@nginx.com 
1021510Salexander.borisov@nginx.com         return NXT_ERROR;
1022510Salexander.borisov@nginx.com     }
1023510Salexander.borisov@nginx.com 
1024510Salexander.borisov@nginx.com     if (SvTYPE(SvRV(*sv_temp)) == SVt_PVAV) {
1025510Salexander.borisov@nginx.com         rc = nxt_perl_psgi_result_body(nxt_perl_psgi, *sv_temp, task, wmsg);
1026510Salexander.borisov@nginx.com 
1027510Salexander.borisov@nginx.com     } else {
1028510Salexander.borisov@nginx.com         rc = nxt_perl_psgi_result_body_ref(nxt_perl_psgi, *sv_temp,
1029510Salexander.borisov@nginx.com                                            task, wmsg);
1030510Salexander.borisov@nginx.com     }
1031510Salexander.borisov@nginx.com 
1032510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1033510Salexander.borisov@nginx.com         return rc;
1034510Salexander.borisov@nginx.com     }
1035510Salexander.borisov@nginx.com 
1036510Salexander.borisov@nginx.com     return NXT_OK;
1037510Salexander.borisov@nginx.com }
1038510Salexander.borisov@nginx.com 
1039510Salexander.borisov@nginx.com 
1040510Salexander.borisov@nginx.com static nxt_int_t
1041510Salexander.borisov@nginx.com nxt_perl_psgi_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
1042510Salexander.borisov@nginx.com {
1043510Salexander.borisov@nginx.com     PerlInterpreter  *my_perl;
1044510Salexander.borisov@nginx.com 
1045510Salexander.borisov@nginx.com     my_perl = nxt_perl_psgi_interpreter_init(task, conf->u.perl.script);
1046510Salexander.borisov@nginx.com 
1047510Salexander.borisov@nginx.com     if (nxt_slow_path(my_perl == NULL)) {
1048510Salexander.borisov@nginx.com         return NXT_ERROR;
1049510Salexander.borisov@nginx.com     }
1050510Salexander.borisov@nginx.com 
1051510Salexander.borisov@nginx.com     nxt_perl_psgi = my_perl;
1052510Salexander.borisov@nginx.com 
1053510Salexander.borisov@nginx.com     return NXT_OK;
1054510Salexander.borisov@nginx.com }
1055510Salexander.borisov@nginx.com 
1056510Salexander.borisov@nginx.com 
1057510Salexander.borisov@nginx.com static nxt_int_t
1058510Salexander.borisov@nginx.com nxt_perl_psgi_run(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg)
1059510Salexander.borisov@nginx.com {
1060510Salexander.borisov@nginx.com     SV                     *env, *result;
1061510Salexander.borisov@nginx.com     size_t                 body_preread_size;
1062510Salexander.borisov@nginx.com     nxt_int_t              rc;
1063510Salexander.borisov@nginx.com     nxt_perl_psgi_input_t  input;
1064510Salexander.borisov@nginx.com 
1065510Salexander.borisov@nginx.com     dTHXa(nxt_perl_psgi);
1066510Salexander.borisov@nginx.com 
1067510Salexander.borisov@nginx.com     /*
1068510Salexander.borisov@nginx.com      * Create environ variable for perl sub "application".
1069510Salexander.borisov@nginx.com      *  > sub application {
1070510Salexander.borisov@nginx.com      *  >     my ($environ) = @_;
1071510Salexander.borisov@nginx.com      */
1072510Salexander.borisov@nginx.com     env = nxt_perl_psgi_env_create(nxt_perl_psgi, task, rmsg,
1073510Salexander.borisov@nginx.com                                    &body_preread_size);
1074510Salexander.borisov@nginx.com 
1075510Salexander.borisov@nginx.com     if (nxt_slow_path(env == NULL)) {
1076510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
1077510Salexander.borisov@nginx.com                       "PSGI: Failed to create 'env' for Perl Application");
1078510Salexander.borisov@nginx.com 
1079510Salexander.borisov@nginx.com         return NXT_ERROR;
1080510Salexander.borisov@nginx.com     }
1081510Salexander.borisov@nginx.com 
1082510Salexander.borisov@nginx.com     input.my_perl = nxt_perl_psgi;
1083510Salexander.borisov@nginx.com     input.task = task;
1084510Salexander.borisov@nginx.com     input.rmsg = rmsg;
1085510Salexander.borisov@nginx.com     input.wmsg = wmsg;
1086510Salexander.borisov@nginx.com     input.body_preread_size = body_preread_size;
1087510Salexander.borisov@nginx.com 
1088510Salexander.borisov@nginx.com     nxt_perl_psgi_arg_input.ctx = &input;
1089510Salexander.borisov@nginx.com     nxt_perl_psgi_arg_error.ctx = &input;
1090510Salexander.borisov@nginx.com 
1091510Salexander.borisov@nginx.com     /* Call perl sub and get result as SV*. */
1092510Salexander.borisov@nginx.com     result = nxt_perl_psgi_call_var_application(nxt_perl_psgi, env, task);
1093510Salexander.borisov@nginx.com 
1094510Salexander.borisov@nginx.com     /*
1095510Salexander.borisov@nginx.com      * We expect ARRAY ref like a
1096510Salexander.borisov@nginx.com      * ['200', ['Content-Type' => "text/plain"], ["body"]]
1097510Salexander.borisov@nginx.com      */
1098510Salexander.borisov@nginx.com     if (nxt_slow_path(SvOK(result) == 0 || SvROK(result) == 0
1099510Salexander.borisov@nginx.com                       || SvTYPE(SvRV(result)) != SVt_PVAV))
1100510Salexander.borisov@nginx.com     {
1101510Salexander.borisov@nginx.com         nxt_log_error(NXT_LOG_ERR, task->log,
1102510Salexander.borisov@nginx.com                       "PSGI: An unexpected response was received from "
1103510Salexander.borisov@nginx.com                       "Perl Application");
1104510Salexander.borisov@nginx.com         goto fail;
1105510Salexander.borisov@nginx.com     }
1106510Salexander.borisov@nginx.com 
1107510Salexander.borisov@nginx.com     rc = nxt_perl_psgi_result_array(nxt_perl_psgi, result, task, wmsg);
1108510Salexander.borisov@nginx.com 
1109510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1110510Salexander.borisov@nginx.com         goto fail;
1111510Salexander.borisov@nginx.com     }
1112510Salexander.borisov@nginx.com 
1113510Salexander.borisov@nginx.com     rc = nxt_app_msg_flush(task, wmsg, 1);
1114510Salexander.borisov@nginx.com 
1115510Salexander.borisov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1116510Salexander.borisov@nginx.com         goto fail;
1117510Salexander.borisov@nginx.com     }
1118510Salexander.borisov@nginx.com 
1119510Salexander.borisov@nginx.com     SvREFCNT_dec(result);
1120510Salexander.borisov@nginx.com     SvREFCNT_dec(env);
1121510Salexander.borisov@nginx.com 
1122510Salexander.borisov@nginx.com     return NXT_OK;
1123510Salexander.borisov@nginx.com 
1124510Salexander.borisov@nginx.com fail:
1125510Salexander.borisov@nginx.com 
1126510Salexander.borisov@nginx.com     SvREFCNT_dec(result);
1127510Salexander.borisov@nginx.com     SvREFCNT_dec(env);
1128510Salexander.borisov@nginx.com 
1129510Salexander.borisov@nginx.com     return NXT_ERROR;
1130510Salexander.borisov@nginx.com }
1131510Salexander.borisov@nginx.com 
1132510Salexander.borisov@nginx.com 
1133510Salexander.borisov@nginx.com static void
1134510Salexander.borisov@nginx.com nxt_perl_psgi_atexit(nxt_task_t *task)
1135510Salexander.borisov@nginx.com {
1136510Salexander.borisov@nginx.com     dTHXa(nxt_perl_psgi);
1137510Salexander.borisov@nginx.com 
1138510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_io_destroy(aTHX_ nxt_perl_psgi_arg_input.io);
1139510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ nxt_perl_psgi_arg_input.fp);
1140510Salexander.borisov@nginx.com 
1141510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_io_destroy(aTHX_ nxt_perl_psgi_arg_error.io);
1142510Salexander.borisov@nginx.com     nxt_perl_psgi_layer_stream_fp_destroy(aTHX_ nxt_perl_psgi_arg_error.fp);
1143510Salexander.borisov@nginx.com 
1144510Salexander.borisov@nginx.com     perl_destruct(nxt_perl_psgi);
1145510Salexander.borisov@nginx.com     perl_free(nxt_perl_psgi);
1146510Salexander.borisov@nginx.com     PERL_SYS_TERM();
1147510Salexander.borisov@nginx.com }
1148