diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/perl/nxt_perl_psgi.c | 112 |
1 files changed, 109 insertions, 3 deletions
diff --git a/src/perl/nxt_perl_psgi.c b/src/perl/nxt_perl_psgi.c index a86fd0de..275ed913 100644 --- a/src/perl/nxt_perl_psgi.c +++ b/src/perl/nxt_perl_psgi.c @@ -51,6 +51,8 @@ static void nxt_perl_psgi_xs_init(pTHX); static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, SV *env, SV *app, nxt_unit_request_info_t *req); +static SV *nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, + const char *method, nxt_unit_request_info_t *req); /* For currect load XS modules */ EXTERN_C void boot_DynaLoader(pTHX_ CV *cv); @@ -84,8 +86,10 @@ static int nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *result, nxt_unit_request_info_t *req); static int nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body, nxt_unit_request_info_t *req); -static ssize_t nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, - void *dst, size_t size); +static int nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body, + nxt_unit_request_info_t *req); +static ssize_t nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, + size_t size); static int nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result, nxt_unit_request_info_t *req); @@ -251,6 +255,42 @@ nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, } +static SV * +nxt_perl_psgi_call_method(PerlInterpreter *my_perl, SV *obj, const char *method, + nxt_unit_request_info_t *req) +{ + SV *result; + + dSP; + + ENTER; + SAVETMPS; + + PUSHMARK(sp); + XPUSHs(obj); + PUTBACK; + + call_method(method, G_EVAL|G_SCALAR); + + SPAGAIN; + + if (SvTRUE(ERRSV)) { + nxt_unit_req_error(req, "PSGI: Failed to call method '%s':\n%s", + method, SvPV_nolen(ERRSV)); + result = NULL; + + } else { + result = SvREFCNT_inc(POPs); + } + + PUTBACK; + FREETMPS; + LEAVE; + + return result; +} + + static u_char * nxt_perl_psgi_module_create(nxt_task_t *task, const char *script) { @@ -749,6 +789,68 @@ nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body, } +static int +nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body, + nxt_unit_request_info_t *req) +{ + SV *data, *old_rs, *old_perl_rs; + int rc; + size_t len; + const char *body; + + /* + * Servers should set the $/ special variable to the buffer size + * when reading content from $body using the getline method. + * This is done by setting $/ with a reference to an integer ($/ = \8192). + */ + + old_rs = PL_rs; + old_perl_rs = get_sv("/", GV_ADD); + + PL_rs = sv_2mortal(newRV_noinc(newSViv(nxt_unit_buf_min()))); + + sv_setsv(old_perl_rs, PL_rs); + + rc = NXT_UNIT_OK; + + for ( ;; ) { + data = nxt_perl_psgi_call_method(my_perl, sv_body, "getline", req); + if (nxt_slow_path(data == NULL)) { + rc = NXT_UNIT_ERROR; + break; + } + + body = SvPV(data, len); + + if (len == 0) { + SvREFCNT_dec(data); + + data = nxt_perl_psgi_call_method(my_perl, sv_body, "close", req); + if (nxt_fast_path(data != NULL)) { + SvREFCNT_dec(data); + } + + break; + } + + rc = nxt_unit_response_write(req, body, len); + + SvREFCNT_dec(data); + + if (nxt_slow_path(rc != NXT_UNIT_OK)) { + nxt_unit_req_error(req, "PSGI: Failed to write content from " + "Perl Application"); + break; + } + }; + + PL_rs = old_rs; + sv_setsv(get_sv("/", GV_ADD), old_perl_rs); + + return rc; +} + + typedef struct { PerlInterpreter *my_perl; PerlIO *fp; @@ -756,7 +858,7 @@ typedef struct { static int -nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body, +nxt_perl_psgi_result_body_fh(PerlInterpreter *my_perl, SV *sv_body, nxt_unit_request_info_t *req) { IO *io; @@ -866,6 +968,10 @@ nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result, return nxt_perl_psgi_result_body(my_perl, *sv_temp, req); } + if (SvTYPE(SvRV(*sv_temp)) == SVt_PVGV) { + return nxt_perl_psgi_result_body_fh(my_perl, *sv_temp, req); + } + return nxt_perl_psgi_result_body_ref(my_perl, *sv_temp, req); } |