diff options
Diffstat (limited to 'src/perl')
-rw-r--r-- | src/perl/nxt_perl_psgi.c | 794 |
1 files changed, 324 insertions, 470 deletions
diff --git a/src/perl/nxt_perl_psgi.c b/src/perl/nxt_perl_psgi.c index 3619dcd0..b2a9c97f 100644 --- a/src/perl/nxt_perl_psgi.c +++ b/src/perl/nxt_perl_psgi.c @@ -11,25 +11,22 @@ #include <nxt_runtime.h> #include <nxt_application.h> #include <nxt_file.h> +#include <nxt_unit.h> +#include <nxt_unit_request.h> +#include <nxt_unit_response.h> typedef struct { - PerlInterpreter *my_perl; - - nxt_task_t *task; - nxt_app_rmsg_t *rmsg; - nxt_app_wmsg_t *wmsg; - - size_t body_preread_size; + PerlInterpreter *my_perl; + nxt_unit_request_info_t *req; } nxt_perl_psgi_input_t; -nxt_inline nxt_int_t nxt_perl_psgi_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg, - const u_char *data, size_t len, - nxt_bool_t flush, nxt_bool_t last); +typedef struct { + PerlInterpreter *my_perl; + SV *app; +} nxt_perl_psgi_module_t; -nxt_inline nxt_int_t nxt_perl_psgi_http_write_status_str(nxt_task_t *task, - nxt_app_wmsg_t *wmsg, nxt_str_t *http_status); static long nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl, nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length); @@ -53,7 +50,7 @@ static void nxt_perl_psgi_xs_core_global_changes(PerlInterpreter *my_perl, static void nxt_perl_psgi_xs_init(pTHX); static SV *nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, - SV *env, nxt_task_t *task); + SV *env, SV *app, nxt_unit_request_info_t *req); /* For currect load XS modules */ EXTERN_C void boot_DynaLoader(pTHX_ CV *cv); @@ -64,44 +61,42 @@ static nxt_int_t nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl, nxt_perl_psgi_io_arg_t *arg); static PerlInterpreter *nxt_perl_psgi_interpreter_init(nxt_task_t *task, - char *script); - -nxt_inline nxt_int_t nxt_perl_psgi_env_append_str(PerlInterpreter *my_perl, - HV *hash_env, const char *name, nxt_str_t *str); -nxt_inline nxt_int_t nxt_perl_psgi_env_append(PerlInterpreter *my_perl, - HV *hash_env, const char *name, void *value); + char *script, SV **app); -static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl, nxt_task_t *task, - nxt_app_rmsg_t *rmsg, size_t *body_preread_size); +static SV *nxt_perl_psgi_env_create(PerlInterpreter *my_perl, + nxt_unit_request_info_t *req, nxt_perl_psgi_input_t *input); +nxt_inline int nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len); +nxt_inline int nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, char *str, uint32_t len); +nxt_inline int nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, void *value); -nxt_inline nxt_int_t nxt_perl_psgi_read_add_env(PerlInterpreter *my_perl, - nxt_task_t *task, nxt_app_rmsg_t *rmsg, HV *hash_env, - const char *name, nxt_str_t *str); static u_char *nxt_perl_psgi_module_create(nxt_task_t *task, const char *script); -static nxt_str_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl, +static nxt_int_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result); -static nxt_int_t nxt_perl_psgi_result_head(PerlInterpreter *my_perl, - SV *sv_head, nxt_task_t *task, nxt_app_wmsg_t *wmsg); -static nxt_int_t nxt_perl_psgi_result_body(PerlInterpreter *my_perl, - SV *result, nxt_task_t *task, nxt_app_wmsg_t *wmsg); -static nxt_int_t nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, - SV *sv_body, nxt_task_t *task, nxt_app_wmsg_t *wmsg); -static nxt_int_t nxt_perl_psgi_result_array(PerlInterpreter *my_perl, - SV *result, nxt_task_t *task, nxt_app_wmsg_t *wmsg); +static int nxt_perl_psgi_result_head(PerlInterpreter *my_perl, + SV *sv_head, nxt_unit_request_info_t *req, uint16_t status); +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_array(PerlInterpreter *my_perl, + SV *result, nxt_unit_request_info_t *req); static nxt_int_t nxt_perl_psgi_init(nxt_task_t *task, nxt_common_app_conf_t *conf); -static nxt_int_t nxt_perl_psgi_run(nxt_task_t *task, - nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg); -static void nxt_perl_psgi_atexit(nxt_task_t *task); +static void nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req); +static void nxt_perl_psgi_atexit(void); typedef SV *(*nxt_perl_psgi_callback_f)(PerlInterpreter *my_perl, SV *env, nxt_task_t *task); -static SV *nxt_perl_psgi_app; static PerlInterpreter *nxt_perl_psgi; static nxt_perl_psgi_io_arg_t nxt_perl_psgi_arg_input, nxt_perl_psgi_arg_error; @@ -109,85 +104,24 @@ static uint32_t nxt_perl_psgi_compat[] = { NXT_VERNUM, NXT_DEBUG, }; -NXT_EXPORT nxt_application_module_t nxt_app_module = { +NXT_EXPORT nxt_app_module_t nxt_app_module = { sizeof(nxt_perl_psgi_compat), nxt_perl_psgi_compat, nxt_string("perl"), PERL_VERSION_STRING, nxt_perl_psgi_init, - nxt_perl_psgi_run, - nxt_perl_psgi_atexit, }; -nxt_inline nxt_int_t -nxt_perl_psgi_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg, - const u_char *data, size_t len, - nxt_bool_t flush, nxt_bool_t last) -{ - nxt_int_t rc; - - rc = nxt_app_msg_write_raw(task, wmsg, data, len); - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; - } - - if (flush || last) { - rc = nxt_app_msg_flush(task, wmsg, last); - } - - return rc; -} - - -nxt_inline nxt_int_t -nxt_perl_psgi_http_write_status_str(nxt_task_t *task, nxt_app_wmsg_t *wmsg, - nxt_str_t *http_status) -{ - nxt_int_t rc; - - rc = NXT_OK; - -#define RC_WRT(DATA, DATALEN, FLUSH) \ - do { \ - rc = nxt_perl_psgi_write(task, wmsg, DATA, \ - DATALEN, FLUSH, 0); \ - if (nxt_slow_path(rc != NXT_OK)) \ - return rc; \ - \ - } while (0) - - RC_WRT((const u_char *) "Status: ", nxt_length("Status: "), 0); - RC_WRT(http_status->start, http_status->length, 0); - RC_WRT((u_char *) "\r\n", nxt_length("\r\n"), 0); - -#undef RC_WRT - - return rc; -} - - static long nxt_perl_psgi_io_input_read(PerlInterpreter *my_perl, nxt_perl_psgi_io_arg_t *arg, void *vbuf, size_t length) { - size_t copy_size; nxt_perl_psgi_input_t *input; input = (nxt_perl_psgi_input_t *) arg->ctx; - if (input->body_preread_size == 0) { - return 0; - } - - copy_size = nxt_min(length, input->body_preread_size); - copy_size = nxt_app_msg_read_raw(input->task, input->rmsg, - vbuf, copy_size); - - input->body_preread_size -= copy_size; - - return copy_size; + return nxt_unit_request_read(input->req, vbuf, length); } @@ -222,7 +156,7 @@ nxt_perl_psgi_io_error_write(PerlInterpreter *my_perl, nxt_perl_psgi_input_t *input; input = (nxt_perl_psgi_input_t *) arg->ctx; - nxt_log_error(NXT_LOG_ERR, input->task->log, "Perl: %s", vbuf); + nxt_unit_req_error(input->req, "Perl: %s", vbuf); return (long) length; } @@ -284,7 +218,7 @@ nxt_perl_psgi_xs_init(pTHX) static SV * nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, - SV *env, nxt_task_t *task) + SV *env, SV *app, nxt_unit_request_info_t *req) { SV *result; @@ -297,14 +231,13 @@ nxt_perl_psgi_call_var_application(PerlInterpreter *my_perl, XPUSHs(env); PUTBACK; - call_sv(nxt_perl_psgi_app, G_EVAL|G_SCALAR); + call_sv(app, G_EVAL|G_SCALAR); SPAGAIN; if (SvTRUE(ERRSV)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to run Perl Application: \n%s", - SvPV_nolen(ERRSV)); + nxt_unit_req_error(req, "PSGI: Failed to run Perl Application: \n%s", + SvPV_nolen(ERRSV)); } result = POPs; @@ -418,7 +351,7 @@ nxt_perl_psgi_io_error_init(PerlInterpreter *my_perl, static PerlInterpreter * -nxt_perl_psgi_interpreter_init(nxt_task_t *task, char *script) +nxt_perl_psgi_interpreter_init(nxt_task_t *task, char *script, SV **app) { int status, pargc; char **pargv, **penv; @@ -485,7 +418,7 @@ nxt_perl_psgi_interpreter_init(nxt_task_t *task, char *script) goto fail; } - nxt_perl_psgi_app = eval_pv((const char *) run_module, FALSE); + *app = eval_pv((const char *) run_module, FALSE); if (SvTRUE(ERRSV)) { nxt_alert(task, "PSGI: Failed to parse script: %s\n%s", @@ -511,108 +444,41 @@ fail: } -nxt_inline nxt_int_t -nxt_perl_psgi_env_append_str(PerlInterpreter *my_perl, HV *hash_env, - const char *name, nxt_str_t *str) -{ - SV **ha; - - ha = hv_store(hash_env, name, (I32) strlen(name), - newSVpv((const char *) str->start, (STRLEN) str->length), 0); - - if (nxt_slow_path(ha == NULL)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_inline nxt_int_t -nxt_perl_psgi_env_append(PerlInterpreter *my_perl, HV *hash_env, - const char *name, void *value) -{ - SV **ha; - - ha = hv_store(hash_env, name, (I32) strlen(name), value, 0); - - if (nxt_slow_path(ha == NULL)) { - return NXT_ERROR; - } - - return NXT_OK; -} - - -nxt_inline nxt_int_t -nxt_perl_psgi_read_add_env(PerlInterpreter *my_perl, nxt_task_t *task, - nxt_app_rmsg_t *rmsg, HV *hash_env, - const char *name, nxt_str_t *str) -{ - nxt_int_t rc; - - rc = nxt_app_msg_read_str(task, rmsg, str); - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; - } - - if (str->start == NULL) { - return NXT_OK; - } - - return nxt_perl_psgi_env_append_str(my_perl, hash_env, name, str); -} - - static SV * -nxt_perl_psgi_env_create(PerlInterpreter *my_perl, nxt_task_t *task, - nxt_app_rmsg_t *rmsg, size_t *body_preread_size) +nxt_perl_psgi_env_create(PerlInterpreter *my_perl, + nxt_unit_request_info_t *req, nxt_perl_psgi_input_t *input) { - HV *hash_env; - AV *array_version; - u_char *colon; - size_t query_size; - nxt_int_t rc; - nxt_str_t str, value, path, target; - nxt_str_t host, server_name, server_port; - - static nxt_str_t def_host = nxt_string("localhost"); - static nxt_str_t def_port = nxt_string("80"); + HV *hash_env; + AV *array_version; + char *host_start, *port_start; + uint32_t i, host_length, port_length; + nxt_unit_field_t *f; + nxt_unit_request_t *r; hash_env = newHV(); - if (nxt_slow_path(hash_env == NULL)) { return NULL; } -#define RC(FNS) \ - do { \ - if (nxt_slow_path((FNS) != NXT_OK)) \ - goto fail; \ - } while (0) - -#define GET_STR(ATTR) \ - RC(nxt_perl_psgi_read_add_env(my_perl, task, rmsg, \ - hash_env, ATTR, &str)) - - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, - "SERVER_SOFTWARE", &nxt_server)); - - GET_STR("REQUEST_METHOD"); - GET_STR("REQUEST_URI"); +#define RC(FNS) \ + do { \ + if (nxt_slow_path((FNS) != NXT_UNIT_OK)) \ + goto fail; \ + } while (0) - target = str; +#define NL(S) (S), sizeof(S)-1 - RC(nxt_app_msg_read_str(task, rmsg, &path)); - RC(nxt_app_msg_read_size(task, rmsg, &query_size)); + r = req->request; - if (path.start == NULL || path.length == 0) { - path = target; - } + RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_SOFTWARE"), + (char *) nxt_server.start, nxt_server.length)); - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, "PATH_INFO", - &path)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_METHOD"), + &r->method, r->method_length)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REQUEST_URI"), + &r->target, r->target_length)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("PATH_INFO"), + &r->path, r->path_length)); array_version = newAV(); @@ -623,111 +489,136 @@ nxt_perl_psgi_env_create(PerlInterpreter *my_perl, nxt_task_t *task, av_push(array_version, newSViv(1)); av_push(array_version, newSViv(1)); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.version", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"), newRV_noinc((SV *) array_version))); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.url_scheme", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"), newSVpv("http", 4))); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.input", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"), SvREFCNT_inc(nxt_perl_psgi_arg_input.io))); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.errors", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"), SvREFCNT_inc(nxt_perl_psgi_arg_error.io))); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.multithread", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multithread"), &PL_sv_no)); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.multiprocess", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.multiprocess"), &PL_sv_yes)); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.run_once", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.run_once"), &PL_sv_no)); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.nonblocking", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.nonblocking"), &PL_sv_no)); - RC(nxt_perl_psgi_env_append(my_perl, hash_env, "psgi.streaming", + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.streaming"), &PL_sv_no)); - if (query_size > 0) { - query_size--; - - if (nxt_slow_path(target.length < query_size)) { - goto fail; - } + if (r->query.offset) { + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("QUERY_STRING"), + &r->query, r->query_length)); + } + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_PROTOCOL"), + &r->version, r->version_length)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("REMOTE_ADDR"), + &r->remote, r->remote_length)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("SERVER_ADDR"), + &r->local, r->local_length)); - str.start = &target.start[query_size]; - str.length = target.length - query_size; + for (i = 0; i < r->fields_count; i++) { + f = r->fields + i; - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, - "QUERY_STRING", &str)); + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, + nxt_unit_sptr_get(&f->name), f->name_length, + &f->value, f->value_length)); } - GET_STR("SERVER_PROTOCOL"); - GET_STR("REMOTE_ADDR"); - GET_STR("SERVER_ADDR"); + if (r->content_length_field != NXT_UNIT_NONE_FIELD) { + f = r->fields + r->content_length_field; - RC(nxt_app_msg_read_str(task, rmsg, &host)); - - if (host.length == 0) { - host = def_host; + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_LENGTH"), + &f->value, f->value_length)); } - colon = nxt_memchr(host.start, ':', host.length); - server_name = host; + if (r->content_type_field != NXT_UNIT_NONE_FIELD) { + f = r->fields + r->content_type_field; + + RC(nxt_perl_psgi_add_sptr(my_perl, hash_env, NL("CONTENT_TYPE"), + &f->value, f->value_length)); + } - if (colon != NULL) { - server_name.length = colon - host.start; + if (r->host_field != NXT_UNIT_NONE_FIELD) { + f = r->fields + r->host_field; - server_port.start = colon + 1; - server_port.length = host.length - server_name.length - 1; + host_start = nxt_unit_sptr_get(&f->value); + host_length = f->value_length; } else { - server_port = def_port; + host_start = NULL; + host_length = 0; } - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, - "SERVER_NAME", &server_name)); - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, - "SERVER_PORT", &server_port)); + nxt_unit_split_host(host_start, host_length, &host_start, &host_length, + &port_start, &port_length); - GET_STR("CONTENT_TYPE"); - GET_STR("CONTENT_LENGTH"); + RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_NAME"), + host_start, host_length)); + RC(nxt_perl_psgi_add_str(my_perl, hash_env, NL("SERVER_PORT"), + port_start, port_length)); - for ( ;; ) { - rc = nxt_app_msg_read_str(task, rmsg, &str); +#undef NL +#undef RC - if (nxt_slow_path(rc != NXT_OK)) { - goto fail; - } + return newRV_noinc((SV *) hash_env); - if (nxt_slow_path(str.length == 0)) { - break; - } +fail: - rc = nxt_app_msg_read_str(task, rmsg, &value); + SvREFCNT_dec(hash_env); - if (nxt_slow_path(rc != NXT_OK)) { - break; - } + return NULL; +} - RC(nxt_perl_psgi_env_append_str(my_perl, hash_env, - (char *) str.start, &value)); - } - RC(nxt_app_msg_read_size(task, rmsg, body_preread_size)); +nxt_inline int +nxt_perl_psgi_add_sptr(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, nxt_unit_sptr_t *sptr, uint32_t len) +{ + return nxt_perl_psgi_add_str(my_perl, hash_env, name, name_len, + nxt_unit_sptr_get(sptr), len); +} -#undef GET_STR -#undef RC - return newRV_noinc((SV *) hash_env); +nxt_inline int +nxt_perl_psgi_add_str(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, char *str, uint32_t len) +{ + SV **ha; -fail: + ha = hv_store(hash_env, name, (I32) name_len, + newSVpv(str, (STRLEN) len), 0); + if (nxt_slow_path(ha == NULL)) { + return NXT_UNIT_ERROR; + } - SvREFCNT_dec(hash_env); + return NXT_UNIT_OK; +} - return NULL; + +nxt_inline int +nxt_perl_psgi_add_value(PerlInterpreter *my_perl, HV *hash_env, + const char *name, uint32_t name_len, void *value) +{ + SV **ha; + + ha = hv_store(hash_env, name, (I32) name_len, value, 0); + if (nxt_slow_path(ha == NULL)) { + return NXT_UNIT_ERROR; + } + + return NXT_UNIT_OK; } -static nxt_str_t +static nxt_int_t nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result) { SV **sv_status; AV *array; + u_char *space; nxt_str_t status; array = (AV *) SvRV(result); @@ -735,106 +626,111 @@ nxt_perl_psgi_result_status(PerlInterpreter *my_perl, SV *result) status.start = (u_char *) SvPV(*sv_status, status.length); - return status; + space = nxt_memchr(status.start, ' ', status.length); + if (space != NULL) { + status.length = space - status.start; + } + + return nxt_int_parse(status.start, status.length); } -static nxt_int_t +static int nxt_perl_psgi_result_head(PerlInterpreter *my_perl, SV *sv_head, - nxt_task_t *task, nxt_app_wmsg_t *wmsg) + nxt_unit_request_info_t *req, uint16_t status) { AV *array_head; SV **entry; + int rc; long i, array_len; - nxt_int_t rc; - nxt_str_t body; + char *name, *value; + STRLEN name_len, value_len; + uint32_t fields, size; if (nxt_slow_path(SvROK(sv_head) == 0 || SvTYPE(SvRV(sv_head)) != SVt_PVAV)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: An unsupported format was received from " - "Perl Application for head part"); + nxt_unit_req_error(req, + "PSGI: An unsupported format was received from " + "Perl Application for head part"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } array_head = (AV *) SvRV(sv_head); array_len = av_len(array_head); if (array_len < 1) { - return NXT_OK; + return nxt_unit_response_init(req, status, 0, 0); } if (nxt_slow_path((array_len % 2) == 0)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Bad format for head from " - "Perl Application"); + nxt_unit_req_error(req, "PSGI: Bad format for head from " + "Perl Application"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } + fields = 0; + size = 0; + for (i = 0; i <= array_len; i++) { entry = av_fetch(array_head, i, 0); if (nxt_fast_path(entry == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to get head entry from " - "Perl Application"); + nxt_unit_req_error(req, "PSGI: Failed to get head entry from " + "Perl Application"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } - body.start = (u_char *) SvPV(*entry, body.length); - - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) body.start, body.length); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write head " - "from Perl Application"); - return rc; - } + value = SvPV(*entry, value_len); + size += value_len; if ((i % 2) == 0) { - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) ": ", nxt_length(": ")); - } else { - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) "\r\n", nxt_length("\r\n")); + fields++; } + } + + rc = nxt_unit_response_init(req, status, fields, size); + if (nxt_slow_path(rc != NXT_UNIT_OK)) { + return rc; + } + + for (i = 0; i <= array_len; i += 2) { + entry = av_fetch(array_head, i, 0); + name = SvPV(*entry, name_len); + + entry = av_fetch(array_head, i + 1, 0); + value = SvPV(*entry, value_len); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write head from " - "Perl Application"); + rc = nxt_unit_response_add_field(req, name, name_len, value, value_len); + if (nxt_slow_path(rc != NXT_UNIT_OK)) { return rc; } } - return NXT_OK; + return NXT_UNIT_OK; } -static nxt_int_t +static int nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body, - nxt_task_t *task, nxt_app_wmsg_t *wmsg) + nxt_unit_request_info_t *req) { SV **entry; AV *body_array; + int rc; long i; - nxt_int_t rc; nxt_str_t body; if (nxt_slow_path(SvROK(sv_body) == 0 || SvTYPE(SvRV(sv_body)) != SVt_PVAV)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: An unsupported format was received from " - "Perl Application for a body part"); + nxt_unit_req_error(req, "PSGI: An unsupported format was received from " + "Perl Application for a body part"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } body_array = (AV *) SvRV(sv_body); @@ -844,10 +740,10 @@ nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body, entry = av_fetch(body_array, i, 0); if (nxt_fast_path(entry == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to get body entry from " - "Perl Application"); - return NXT_ERROR; + nxt_unit_req_error(req, "PSGI: Failed to get body entry from " + "Perl Application"); + + return NXT_UNIT_ERROR; } body.start = (u_char *) SvPV(*entry, body.length); @@ -856,241 +752,215 @@ nxt_perl_psgi_result_body(PerlInterpreter *my_perl, SV *sv_body, continue; } - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) body.start, body.length); + rc = nxt_unit_response_write(req, body.start, body.length); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write 'body' from " - "Perl Application"); - return rc; - } - - rc = nxt_app_msg_flush(task, wmsg, 0); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to flush data for a 'body' " - "part from Perl Application"); + if (nxt_slow_path(rc != NXT_UNIT_OK)) { + nxt_unit_req_error(req, "PSGI: Failed to write content from " + "Perl Application"); return rc; } } - return NXT_OK; + return NXT_UNIT_OK; } -static nxt_int_t +typedef struct { + PerlInterpreter *my_perl; + PerlIO *fp; +} nxt_perl_psgi_io_ctx_t; + + +static int nxt_perl_psgi_result_body_ref(PerlInterpreter *my_perl, SV *sv_body, - nxt_task_t *task, nxt_app_wmsg_t *wmsg) + nxt_unit_request_info_t *req) { - IO *io; - PerlIO *fp; - SSize_t n; - nxt_int_t rc; - u_char vbuf[8192]; + IO *io; + nxt_unit_read_info_t read_info; + nxt_perl_psgi_io_ctx_t io_ctx; io = GvIO(SvRV(sv_body)); if (io == NULL) { - return NXT_OK; + return NXT_UNIT_OK; } - fp = IoIFP(io); + io_ctx.my_perl = my_perl; + io_ctx.fp = IoIFP(io); - for ( ;; ) { - n = PerlIO_read(fp, vbuf, 8192); + read_info.read = nxt_perl_psgi_io_read; + read_info.eof = PerlIO_eof(io_ctx.fp); + read_info.buf_size = 8192; + read_info.data = &io_ctx; - if (n < 1) { - break; - } - - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) vbuf, (size_t) n); + return nxt_unit_response_write_cb(req, &read_info); +} - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write 'body' from " - "Perl Application"); - return rc; - } +static ssize_t +nxt_perl_psgi_io_read(nxt_unit_read_info_t *read_info, void *dst, size_t size) +{ + ssize_t res; + PerlInterpreter *my_perl; + nxt_perl_psgi_io_ctx_t *ctx; - rc = nxt_app_msg_flush(task, wmsg, 0); + ctx = read_info->data; + my_perl = ctx->my_perl; - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to flush data for a body " - "part from Perl Application"); + res = PerlIO_read(ctx->fp, dst, size); - return rc; - } - } + read_info->eof = PerlIO_eof(ctx->fp); - return NXT_OK; + return res; } -static nxt_int_t +static int nxt_perl_psgi_result_array(PerlInterpreter *my_perl, SV *result, - nxt_task_t *task, nxt_app_wmsg_t *wmsg) + nxt_unit_request_info_t *req) { AV *array; SV **sv_temp; + int rc; long array_len; - nxt_int_t rc; - nxt_str_t http_status; + nxt_int_t status; array = (AV *) SvRV(result); array_len = av_len(array); if (nxt_slow_path(array_len < 0)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Invalid result format from Perl Application"); + nxt_unit_req_error(req, + "PSGI: Invalid result format from Perl Application"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } - http_status = nxt_perl_psgi_result_status(nxt_perl_psgi, result); + status = nxt_perl_psgi_result_status(my_perl, result); - if (nxt_slow_path(http_status.start == NULL || http_status.length == 0)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: An unexpected status was received " - "from Perl Application"); + if (nxt_slow_path(status < 0)) { + nxt_unit_req_error(req, + "PSGI: An unexpected status was received " + "from Perl Application"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } - rc = nxt_perl_psgi_http_write_status_str(task, wmsg, &http_status); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write HTTP Status"); - - return rc; - } + if (array_len >= 1) { + sv_temp = av_fetch(array, 1, 0); - if (array_len < 1) { - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) "\r\n", nxt_length("\r\n")); + if (nxt_slow_path(sv_temp == NULL)) { + nxt_unit_req_error(req, "PSGI: Failed to get head from " + "Perl ARRAY variable"); - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write HTTP Headers"); + return NXT_UNIT_ERROR; + } + rc = nxt_perl_psgi_result_head(my_perl, *sv_temp, req, status); + if (nxt_slow_path(rc != NXT_UNIT_OK)) { return rc; } - return NXT_OK; - } - - sv_temp = av_fetch(array, 1, 0); - - if (nxt_slow_path(sv_temp == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to get head from Perl ARRAY variable"); - - return NXT_ERROR; - } - - rc = nxt_perl_psgi_result_head(nxt_perl_psgi, *sv_temp, task, wmsg); - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; - } - - rc = nxt_app_msg_write_raw(task, wmsg, - (u_char *) "\r\n", nxt_length("\r\n")); - - if (nxt_slow_path(rc != NXT_OK)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to write HTTP Headers"); - - return rc; + } else { + return nxt_unit_response_init(req, status, 0, 0); } if (nxt_fast_path(array_len < 2)) { - return NXT_OK; + return NXT_UNIT_OK; } sv_temp = av_fetch(array, 2, 0); if (nxt_slow_path(sv_temp == NULL || SvROK(*sv_temp) == FALSE)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to get body from Perl ARRAY variable"); + nxt_unit_req_error(req, + "PSGI: Failed to get body from " + "Perl ARRAY variable"); - return NXT_ERROR; + return NXT_UNIT_ERROR; } if (SvTYPE(SvRV(*sv_temp)) == SVt_PVAV) { - rc = nxt_perl_psgi_result_body(nxt_perl_psgi, *sv_temp, task, wmsg); - - } else { - rc = nxt_perl_psgi_result_body_ref(nxt_perl_psgi, *sv_temp, - task, wmsg); - } - - if (nxt_slow_path(rc != NXT_OK)) { - return rc; + return nxt_perl_psgi_result_body(my_perl, *sv_temp, req); } - return NXT_OK; + return nxt_perl_psgi_result_body_ref(my_perl, *sv_temp, req); } static nxt_int_t nxt_perl_psgi_init(nxt_task_t *task, nxt_common_app_conf_t *conf) { - PerlInterpreter *my_perl; + int rc; + nxt_unit_ctx_t *unit_ctx; + nxt_unit_init_t perl_init; + PerlInterpreter *my_perl; + nxt_perl_psgi_module_t module; - my_perl = nxt_perl_psgi_interpreter_init(task, conf->u.perl.script); + my_perl = nxt_perl_psgi_interpreter_init(task, conf->u.perl.script, + &module.app); if (nxt_slow_path(my_perl == NULL)) { return NXT_ERROR; } + module.my_perl = my_perl; nxt_perl_psgi = my_perl; + nxt_unit_default_init(task, &perl_init); + + perl_init.callbacks.request_handler = nxt_perl_psgi_request_handler; + perl_init.data = &module; + + unit_ctx = nxt_unit_init(&perl_init); + if (nxt_slow_path(unit_ctx == NULL)) { + return NXT_ERROR; + } + + rc = nxt_unit_run(unit_ctx); + + nxt_unit_done(unit_ctx); + + nxt_perl_psgi_atexit(); + + exit(rc); + return NXT_OK; } -static nxt_int_t -nxt_perl_psgi_run(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg) +static void +nxt_perl_psgi_request_handler(nxt_unit_request_info_t *req) { - SV *env, *result; - size_t body_preread_size; - nxt_int_t rc; - nxt_perl_psgi_input_t input; + SV *env, *result; + nxt_int_t rc; + PerlInterpreter *my_perl; + nxt_perl_psgi_input_t input; + nxt_perl_psgi_module_t *module; - dTHXa(nxt_perl_psgi); + module = req->unit->data; + my_perl = module->my_perl; + + input.my_perl = my_perl; + input.req = req; /* * Create environ variable for perl sub "application". * > sub application { * > my ($environ) = @_; */ - env = nxt_perl_psgi_env_create(nxt_perl_psgi, task, rmsg, - &body_preread_size); - + env = nxt_perl_psgi_env_create(my_perl, req, &input); if (nxt_slow_path(env == NULL)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: Failed to create 'env' for Perl Application"); + nxt_unit_req_error(req, + "PSGI: Failed to create 'env' for Perl Application"); + nxt_unit_request_done(req, NXT_UNIT_ERROR); - return NXT_ERROR; + return; } - input.my_perl = nxt_perl_psgi; - input.task = task; - input.rmsg = rmsg; - input.wmsg = wmsg; - input.body_preread_size = body_preread_size; - nxt_perl_psgi_arg_input.ctx = &input; nxt_perl_psgi_arg_error.ctx = &input; /* Call perl sub and get result as SV*. */ - result = nxt_perl_psgi_call_var_application(nxt_perl_psgi, env, task); + result = nxt_perl_psgi_call_var_application(my_perl, env, module->app, req); /* * We expect ARRAY ref like a @@ -1099,40 +969,24 @@ nxt_perl_psgi_run(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg) if (nxt_slow_path(SvOK(result) == 0 || SvROK(result) == 0 || SvTYPE(SvRV(result)) != SVt_PVAV)) { - nxt_log_error(NXT_LOG_ERR, task->log, - "PSGI: An unexpected response was received from " - "Perl Application"); - goto fail; - } - - rc = nxt_perl_psgi_result_array(nxt_perl_psgi, result, task, wmsg); + nxt_unit_req_error(req, "PSGI: An unexpected response was received " + "from Perl Application"); - if (nxt_slow_path(rc != NXT_OK)) { - goto fail; - } + rc = NXT_UNIT_ERROR; - rc = nxt_app_msg_flush(task, wmsg, 1); - - if (nxt_slow_path(rc != NXT_OK)) { - goto fail; + } else { + rc = nxt_perl_psgi_result_array(my_perl, result, req); } - SvREFCNT_dec(result); - SvREFCNT_dec(env); - - return NXT_OK; - -fail: + nxt_unit_request_done(req, rc); SvREFCNT_dec(result); SvREFCNT_dec(env); - - return NXT_ERROR; } static void -nxt_perl_psgi_atexit(nxt_task_t *task) +nxt_perl_psgi_atexit(void) { dTHXa(nxt_perl_psgi); |