mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-08 14:41:55 +00:00
423 lines
8.0 KiB
C
423 lines
8.0 KiB
C
#include "psgi.h"
|
|
|
|
extern char **environ;
|
|
extern struct uwsgi_server uwsgi;
|
|
|
|
struct uwsgi_perl uperl;
|
|
|
|
struct option uwsgi_perl_options[] = {
|
|
|
|
{"psgi", required_argument, 0, LONG_ARGS_PSGI},
|
|
{0, 0, 0, 0},
|
|
|
|
};
|
|
|
|
extern struct http_status_codes hsc[];
|
|
|
|
XS(XS_stream)
|
|
{
|
|
dXSARGS;
|
|
struct wsgi_request *wsgi_req = current_wsgi_req();
|
|
SV *stack;
|
|
AV *response;
|
|
|
|
uwsgi_log("args: %d %p\n", items, wsgi_req);
|
|
stack = ST(0);
|
|
uwsgi_log("type %d\n", SvTYPE(stack));
|
|
response = (AV* ) SvRV(stack) ;
|
|
|
|
|
|
psgi_response(wsgi_req, my_perl, response);
|
|
|
|
//mXPUSHp("x", 1);
|
|
XSRETURN(0);
|
|
|
|
}
|
|
|
|
/* automatically generated */
|
|
|
|
EXTERN_C void xs_init (pTHX);
|
|
|
|
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
|
|
|
|
EXTERN_C void
|
|
xs_init(pTHX)
|
|
{
|
|
char *file = __FILE__;
|
|
dXSUB_SYS;
|
|
|
|
/* DynaLoader is a special case */
|
|
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
|
|
|
uperl.stream_responder = newXS("uwsgi::stream", XS_stream, "uwsgi");
|
|
|
|
#ifdef UWSGI_EMBEDDED
|
|
init_perl_embedded_module();
|
|
#endif
|
|
}
|
|
|
|
/* end of automagically generated part */
|
|
|
|
|
|
int uwsgi_perl_init(){
|
|
|
|
|
|
struct http_status_codes *http_sc;
|
|
|
|
int argc = 4;
|
|
char *embedding[] = { "", "-e", "-e", "0" };
|
|
|
|
uwsgi_log("initializing Perl environment\n");
|
|
PERL_SYS_INIT3(&argc, (char ***) &embedding, &environ);
|
|
uperl.main = perl_alloc();
|
|
if (!uperl.main) {
|
|
uwsgi_log("unable to allocate perl interpreter\n");
|
|
return -1;
|
|
}
|
|
|
|
dTHXa(uperl.main);
|
|
PERL_SET_CONTEXT(uperl.main);
|
|
|
|
PL_perl_destruct_level = 2;
|
|
perl_construct(uperl.main);
|
|
|
|
// filling http status codes
|
|
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
|
http_sc->message_size = strlen(http_sc->message);
|
|
}
|
|
|
|
PL_origalen = 1;
|
|
perl_parse(uperl.main, xs_init, 4, embedding, NULL);
|
|
|
|
perl_eval_pv("use IO::Handle;", 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
void uwsgi_psgi_app() {
|
|
|
|
struct stat stat_psgi;
|
|
|
|
if (uperl.psgi) {
|
|
uperl.fd = open(uperl.psgi, O_RDONLY);
|
|
if (uperl.fd < 0) {
|
|
uwsgi_error("open()");
|
|
exit(1);
|
|
}
|
|
|
|
if (fstat(uperl.fd, &stat_psgi)) {
|
|
uwsgi_error("fstat()");
|
|
exit(1);
|
|
}
|
|
|
|
uperl.psgibuffer = malloc(stat_psgi.st_size + 1);
|
|
if (!uperl.psgibuffer) {
|
|
uwsgi_error("malloc()");
|
|
exit(1);
|
|
}
|
|
|
|
if (read(uperl.fd, uperl.psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
|
|
uwsgi_error("read()");
|
|
exit(1);
|
|
}
|
|
|
|
uperl.psgibuffer[stat_psgi.st_size] = 0;
|
|
|
|
if (uwsgi.threads < 2) {
|
|
uperl.psgi_main = perl_eval_pv(uperl.psgibuffer, 0);
|
|
if (!uperl.psgi_main) {
|
|
uwsgi_log("unable to find PSGI function entry point.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(SvTRUE(ERRSV)) {
|
|
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
|
exit(1);
|
|
}
|
|
|
|
free(uperl.psgibuffer);
|
|
close(uperl.fd);
|
|
}
|
|
|
|
uwsgi_log("PSGI app (%s) loaded at %p\n", uperl.psgi, uperl.psgi_main);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void uwsgi_perl_enable_threads() {
|
|
|
|
int i;
|
|
|
|
if (pthread_key_create(&uperl.u_interpreter, NULL)) {
|
|
uwsgi_error("pthread_key_create()");
|
|
exit(1);
|
|
}
|
|
|
|
uperl.interp = malloc( sizeof(PerlInterpreter*) * uwsgi.threads );
|
|
if (!uperl.interp) {
|
|
uwsgi_error("malloc()");
|
|
exit(1);
|
|
}
|
|
|
|
for(i=1;i<uwsgi.threads;i++) {
|
|
uperl.interp[i] = perl_clone(uperl.main, CLONEf_KEEP_PTR_TABLE);
|
|
if (!uperl.interp[i]) {
|
|
uwsgi_log("unable to create new perl interpreter\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
uperl.psgi_func = malloc( sizeof(SV*) * uwsgi.threads );
|
|
if (!uperl.psgi_func) {
|
|
uwsgi_error("malloc()");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
dTHXa(uperl.main);
|
|
PERL_SET_CONTEXT(uperl.main);
|
|
|
|
uperl.psgi_main = perl_eval_pv(uperl.psgibuffer, 0);
|
|
if (!uperl.psgi_main) {
|
|
uwsgi_log("unable to find PSGI function entry point.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(SvTRUE(ERRSV)) {
|
|
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
|
exit(1);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int uwsgi_perl_request(struct wsgi_request *wsgi_req) {
|
|
|
|
HV *env;
|
|
SV **item;
|
|
|
|
AV *response;
|
|
|
|
SV *io_new, *io_err;
|
|
int i;
|
|
|
|
SV *psgi_func = uperl.psgi_main;
|
|
// ugly hack
|
|
register PerlInterpreter *my_perl = uperl.main;
|
|
dSP;
|
|
|
|
|
|
/* Standard PSGI request */
|
|
if (!wsgi_req->uh.pktsize) {
|
|
uwsgi_log("Invalid PSGI request. skip.\n");
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (uwsgi_parse_vars(wsgi_req)) {
|
|
uwsgi_log("Invalid PSGI request. skip.\n");
|
|
return -1;
|
|
}
|
|
|
|
|
|
#ifdef UWSGI_THREADING
|
|
if (uwsgi.threads > 1 && wsgi_req->async_id > 0) {
|
|
psgi_func = uperl.psgi_func[wsgi_req->async_id];
|
|
my_perl = pthread_getspecific(uperl.u_interpreter);
|
|
}
|
|
#endif
|
|
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
|
|
|
|
env = (HV*) sv_2mortal((SV*)newHV());
|
|
|
|
|
|
// fill perl hash
|
|
for(i=0;i<wsgi_req->var_cnt;i++) {
|
|
if (wsgi_req->hvec[i+1].iov_len > 0) {
|
|
|
|
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len,
|
|
newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0);
|
|
}
|
|
else {
|
|
item = hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0);
|
|
}
|
|
//uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base);
|
|
i++;
|
|
}
|
|
|
|
|
|
SV *us = newSVpv("http", 4);
|
|
item = hv_store(env, "psgi.url_scheme", 15, us, 0);
|
|
|
|
|
|
SV* iohandle = newSVpv( "IO::Handle", 10 );
|
|
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( sv_2mortal(iohandle));
|
|
PUTBACK;
|
|
perl_call_method( "new", G_SCALAR);
|
|
SPAGAIN;
|
|
io_new = POPs;
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( io_new );
|
|
XPUSHs( sv_2mortal(newSViv( wsgi_req->poll.fd)));
|
|
XPUSHs( sv_2mortal(newSVpv( "r", 1)));
|
|
PUTBACK;
|
|
perl_call_method( "fdopen", G_SCALAR);
|
|
SPAGAIN;
|
|
|
|
|
|
|
|
|
|
SV *pi = SvREFCNT_inc(POPs);
|
|
item = hv_store(env, "psgi.input", 10, pi, 0);
|
|
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( newSVpv( "IO::Handle", 10 ));
|
|
PUTBACK;
|
|
perl_call_method( "new", G_SCALAR);
|
|
SPAGAIN;
|
|
io_err = POPs;
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( io_err );
|
|
XPUSHs( sv_2mortal( newSViv( 2 )));
|
|
XPUSHs( sv_2mortal( newSVpv( "w", 1)));
|
|
PUTBACK;
|
|
perl_call_method( "fdopen", G_SCALAR);
|
|
SPAGAIN;
|
|
|
|
SV *pe = SvREFCNT_inc(POPs);
|
|
item = hv_store(env, "psgi.errors", 11, pe, 0);
|
|
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( sv_2mortal(newRV((SV *)env )) );
|
|
PUTBACK;
|
|
|
|
|
|
perl_call_sv(psgi_func, G_SCALAR);
|
|
|
|
|
|
if(SvTRUE(ERRSV)) {
|
|
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
|
goto clear;
|
|
}
|
|
SPAGAIN;
|
|
// no leaks to here
|
|
|
|
// dereference output
|
|
response = (AV *) SvRV( POPs );
|
|
|
|
//uwsgi_log("response: %p %d\n", response, SvTYPE(response));
|
|
|
|
if (SvTYPE(response) == SVt_PVCV) {
|
|
uwsgi_log("streaming response\n");
|
|
|
|
PUSHMARK(SP);
|
|
XPUSHs( newRV((SV*) uperl.stream_responder));
|
|
PUTBACK;
|
|
|
|
perl_call_sv( (SV*)response, G_SCALAR);
|
|
|
|
if(SvTRUE(ERRSV)) {
|
|
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
|
}
|
|
|
|
goto clear;
|
|
}
|
|
|
|
psgi_response(wsgi_req, my_perl, response);
|
|
|
|
clear:
|
|
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) {
|
|
|
|
if (uwsgi.shared->options[UWSGI_OPTION_LOGGING])
|
|
log_request(wsgi_req);
|
|
}
|
|
|
|
void uwsgi_perl_init_thread(int core_id) {
|
|
|
|
|
|
pthread_setspecific(uperl.u_interpreter, uperl.interp[core_id]);
|
|
dTHXa(uperl.interp[core_id]);
|
|
PERL_SET_CONTEXT(uperl.interp[core_id]);
|
|
|
|
uperl.psgi_func[core_id] = perl_eval_pv(uperl.psgibuffer, 0);
|
|
if (!uperl.psgi_func[core_id]) {
|
|
uwsgi_log("unable to find PSGI function entry point.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(SvTRUE(ERRSV)) {
|
|
uwsgi_log("%s\n", SvPV_nolen(ERRSV));
|
|
exit(1);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
int uwsgi_perl_manage_options(int i, char *optarg) {
|
|
|
|
switch(i) {
|
|
case LONG_ARGS_PSGI:
|
|
uperl.psgi = optarg;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uwsgi_perl_magic(char *mountpoint, char *lazy) {
|
|
|
|
if (!strcmp(lazy+strlen(lazy)-5, ".psgi")) {
|
|
uperl.psgi = lazy;
|
|
return 1;
|
|
}
|
|
else if (!strcmp(lazy+strlen(lazy)-3, ".pl")) {
|
|
uperl.psgi = lazy;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
struct uwsgi_plugin psgi_plugin = {
|
|
|
|
.name = "psgi",
|
|
.modifier1 = 5,
|
|
.init = uwsgi_perl_init,
|
|
.options = uwsgi_perl_options,
|
|
.init_apps = uwsgi_psgi_app,
|
|
//.magic = uwsgi_perl_magic,
|
|
//.help = uwsgi_perl_help,
|
|
.enable_threads = uwsgi_perl_enable_threads,
|
|
.manage_opt = uwsgi_perl_manage_options,
|
|
.init_thread = uwsgi_perl_init_thread,
|
|
.request = uwsgi_perl_request,
|
|
.after_request = uwsgi_perl_after_request,
|
|
|
|
.magic = uwsgi_perl_magic,
|
|
};
|