diff --git a/plugins/psgi/psgi.h b/plugins/psgi/psgi.h index 1f56c5d0..696a1191 100644 --- a/plugins/psgi/psgi.h +++ b/plugins/psgi/psgi.h @@ -58,6 +58,8 @@ struct uwsgi_perl { time_t last_auto_reload; struct uwsgi_string_list *auto_reload_ignore; HV *auto_reload_hash; + + int enable_psgix_io; }; void init_perl_embedded_module(void); diff --git a/plugins/psgi/psgi_loader.c b/plugins/psgi/psgi_loader.c index 6bb8110c..ba1763fc 100644 --- a/plugins/psgi/psgi_loader.c +++ b/plugins/psgi/psgi_loader.c @@ -349,6 +349,7 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe perl_eval_pv("use IO::Handle;", 0); perl_eval_pv("use IO::File;", 0); + perl_eval_pv("use IO::Socket;", 0); perl_eval_pv("use Scalar::Util;", 0); if (!uperl.no_die_catch) { perl_eval_pv("use Devel::StackTrace;", 0); diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index 0ba27af1..4cd729d6 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -14,6 +14,7 @@ struct uwsgi_plugin psgi_plugin; struct uwsgi_option uwsgi_perl_options[] = { {"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0}, + {"psgi-enable-psgix-io", no_argument, 0, "enable psgix.io support", uwsgi_opt_true, &uperl.enable_psgix_io, 0}, {"perl-no-die-catch", no_argument, 0, "do not catch $SIG{__DIE__}", uwsgi_opt_true, &uperl.no_die_catch, 0}, {"perl-local-lib", required_argument, 0, "set perl locallib path", uwsgi_opt_set_str, &uperl.locallib, 0}, #ifdef PERL_VERSION_STRING @@ -102,6 +103,31 @@ SV *uwsgi_perl_obj_new(char *class, size_t class_len) { } +SV *uwsgi_perl_obj_new_from_fd(char *class, size_t class_len, int fd) { + SV *newobj; + + dSP; + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv( class, class_len))); + XPUSHs(sv_2mortal(newSViv( fd ))); + XPUSHs(sv_2mortal(newSVpv( "w", 1 ))); + PUTBACK; + + call_method( "new_from_fd", G_SCALAR); + + SPAGAIN; + + newobj = SvREFCNT_inc(POPs); + PUTBACK; + FREETMPS; + LEAVE; + + return newobj; +} + SV *uwsgi_perl_call_stream(SV *func) { SV *ret = NULL; @@ -245,7 +271,10 @@ AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); } else { - ret = (AV *) SvREFCNT_inc(SvRV(POPs)); + SV *r = POPs; + if (SvROK(r)) { + ret = (AV *) SvREFCNT_inc(SvRV(r)); + } } PUTBACK; @@ -360,7 +389,12 @@ SV *build_psgi_env(struct wsgi_request *wsgi_req) { // cleanup handlers array av = newAV(); if (!hv_store(env, "psgix.cleanup.handlers", 22, newRV_noinc((SV *)av ), 0)) goto clear; - + + // this call requires a bunch of syscalls, so it hurts performance + if (uperl.enable_psgix_io) { + SV *io = uwsgi_perl_obj_new_from_fd("IO::Socket", 10, wsgi_req->fd); + if (!hv_store(env, "psgix.io", 8, io, 0)) goto clear; + } SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12); if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear; diff --git a/plugins/psgi/uwsgi_plmodule.c b/plugins/psgi/uwsgi_plmodule.c index 8c60d8a4..1f6ceb2b 100644 --- a/plugins/psgi/uwsgi_plmodule.c +++ b/plugins/psgi/uwsgi_plmodule.c @@ -404,9 +404,20 @@ XS(XS_i_am_the_lord) { } XSRETURN_NO; } - #endif +XS(XS_connection_fd) { + dXSARGS; + + psgi_check_args(0); + + struct wsgi_request *wsgi_req = current_wsgi_req(); + + ST(0) = newSViv(wsgi_req->fd); + sv_2mortal(ST(0)); + XSRETURN(1); +} + XS(XS_websocket_handshake) { dXSARGS; @@ -646,6 +657,9 @@ void init_perl_embedded_module() { #ifdef UWSGI_SSL psgi_xs(i_am_the_lord); #endif + + psgi_xs(connection_fd); + psgi_xs(alarm); psgi_xs(websocket_handshake); psgi_xs(websocket_recv);