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