mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-06-16 02:15:48 +00:00
introduced open PSGI plugin for uWSGI
This commit is contained in:
@@ -1,17 +1,15 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
/* gcc `python-config --cflags` `python ../../uwsgiconfig.py --cflags` -o example_plugin.so -fPIC -shared example_plugin.c */
|
||||
|
||||
int uwsgi_init(struct uwsgi_server *uwsgi, char *args){
|
||||
fprintf(stderr,"i am the example plugin initialization function with arg: %s\n", args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n<h1>Hello World</h1>" ;
|
||||
wsgi_req->response_size += write(uwsgi->poll.fd, http, strlen(http));
|
||||
|
||||
fprintf(stderr,"UWSGI POLL: %p\n", &uwsgi->poll);
|
||||
char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n<h1>Hello World</h1>" ;
|
||||
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, http, strlen(http));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
char *ptrbuf;
|
||||
|
||||
/* Standard WSAPI request */
|
||||
if (!wsgi_req->size) {
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
fprintf (stderr, "Invalid WSAPI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
#include <uwsgi.h>
|
||||
|
||||
#include <EXTERN.h>
|
||||
#include <perl.h>
|
||||
|
||||
static PerlInterpreter *my_perl;
|
||||
static SV *psgi_func ;
|
||||
|
||||
/* statistically ordered */
|
||||
static struct http_status_codes hsc[] = {
|
||||
|
||||
{"200", "OK"},
|
||||
{"302", "Found"},
|
||||
{"404", "Not Found"},
|
||||
{"500", "Internal Server Error"},
|
||||
{"301", "Moved Permanently"},
|
||||
{"304", "Not Modified"},
|
||||
{"303", "See Other"},
|
||||
{"403", "Forbidden"},
|
||||
{"307", "Temporary Redirect"},
|
||||
{"401", "Unauthorized"},
|
||||
{"400", "Bad Request"},
|
||||
{"405", "Method Not Allowed"},
|
||||
{"408", "Request Timeout"},
|
||||
|
||||
{"100", "Continue"},
|
||||
{"101", "Switching Protocols"},
|
||||
{"201", "Created"},
|
||||
{"202", "Accepted"},
|
||||
{"203", "Non-Authoritative Information"},
|
||||
{"204", "No Content"},
|
||||
{"205", "Reset Content"},
|
||||
{"206", "Partial Content"},
|
||||
{"300", "Multiple Choices"},
|
||||
{"305", "Use Proxy"},
|
||||
{"402", "Payment Required"},
|
||||
{"406", "Not Acceptable"},
|
||||
{"407", "Proxy Authentication Required"},
|
||||
{"409", "Conflict"},
|
||||
{"410", "Gone"},
|
||||
{"411", "Length Required"},
|
||||
{"412", "Precondition Failed"},
|
||||
{"413", "Request Entity Too Large"},
|
||||
{"414", "Request-URI Too Long"},
|
||||
{"415", "Unsupported Media Type"},
|
||||
{"416", "Requested Range Not Satisfiable"},
|
||||
{"417", "Expectation Failed"},
|
||||
{"501", "Not Implemented"},
|
||||
{"502", "Bad Gateway"},
|
||||
{"503", "Service Unavailable"},
|
||||
{"504", "Gateway Timeout"},
|
||||
{"505", "HTTP Version Not Supported"},
|
||||
{ "", NULL },
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* end of automagically generated part */
|
||||
|
||||
|
||||
int uwsgi_init(struct uwsgi_server *uwsgi, char *args){
|
||||
|
||||
char *pargs[2] ;
|
||||
char *psgibuffer ;
|
||||
int fd ;
|
||||
|
||||
struct stat stat_psgi;
|
||||
|
||||
struct http_status_codes *http_sc ;
|
||||
|
||||
char *embedding[] = { "", "-e", "0" };
|
||||
|
||||
|
||||
fprintf(stderr,"initializing Perl environment: %s\n", args);
|
||||
|
||||
my_perl = perl_alloc();
|
||||
if (!my_perl) {
|
||||
fprintf(stderr,"unable to allocate perl interpreter\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pargs[0] = "" ;
|
||||
pargs[1] = args ;
|
||||
|
||||
perl_construct(my_perl);
|
||||
|
||||
// filling http status codes
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
http_sc->message_size = strlen(http_sc->message);
|
||||
}
|
||||
|
||||
|
||||
perl_parse(my_perl, xs_init, 3, embedding, NULL);
|
||||
|
||||
perl_eval_pv("use IO::Handle;", 0);
|
||||
|
||||
fd = open(args, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open()");
|
||||
goto clear ;
|
||||
}
|
||||
|
||||
if (fstat(fd, &stat_psgi)) {
|
||||
perror("fstat()");
|
||||
close(fd);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
psgibuffer = malloc(stat_psgi.st_size);
|
||||
if (!psgibuffer) {
|
||||
perror("malloc()");
|
||||
close(fd);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (read(fd, psgibuffer, stat_psgi.st_size) != stat_psgi.st_size) {
|
||||
perror("read()");
|
||||
close(fd);
|
||||
free(psgibuffer);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
psgibuffer[stat_psgi.st_size] = 0 ;
|
||||
|
||||
psgi_func = perl_eval_pv(psgibuffer, 0);
|
||||
if (!psgi_func) {
|
||||
fprintf(stderr,"unable to find PSGI function entry point.\n");
|
||||
close(fd);
|
||||
free(psgibuffer);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
free(psgibuffer);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
clear:
|
||||
perl_destruct(my_perl);
|
||||
perl_free(my_perl);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
HV *env ;
|
||||
SV **item ;
|
||||
|
||||
AV *response, *headers, *body ;
|
||||
|
||||
SV **status_code, **hitem, *io_new, *io_err, *io, *chunk;
|
||||
char *chitem ;
|
||||
STRLEN hlen ;
|
||||
|
||||
struct http_status_codes *http_sc;
|
||||
|
||||
int i,vi, base ;
|
||||
|
||||
/* Standard PSGI request */
|
||||
if (!wsgi_req->uh.pktsize) {
|
||||
fprintf (stderr, "Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (uwsgi_parse_vars(uwsgi, wsgi_req)) {
|
||||
fprintf(stderr,"Invalid PSGI request. skip.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
dSP;
|
||||
|
||||
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);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
item = hv_store(env, "psgi.url_scheme", 15, newSVpv("http", 4), 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal( newSVpv( "IO::Handle", 10 )));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_new = newSVsv(POPs);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(io_new) );
|
||||
XPUSHs( sv_2mortal( newSViv( wsgi_req->poll.fd)));
|
||||
XPUSHs( sv_2mortal( newSVpv( "r", 1)));
|
||||
PUTBACK;
|
||||
perl_call_method( "fdopen", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
|
||||
item = hv_store(env, "psgi.input", 10, newSVsv(POPs), 0);
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal( newSVpv( "IO::Handle", 10 )));
|
||||
PUTBACK;
|
||||
perl_call_method( "new", G_SCALAR);
|
||||
SPAGAIN;
|
||||
io_err = newSVsv(POPs);
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(io_err) );
|
||||
XPUSHs( sv_2mortal( newSViv( 2 )));
|
||||
XPUSHs( sv_2mortal( newSVpv( "w", 1)));
|
||||
PUTBACK;
|
||||
perl_call_method( "fdopen", G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
|
||||
item = hv_store(env, "psgi.errors", 11, newSVsv(POPs), 0);
|
||||
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs( sv_2mortal(newRV((SV *)env )) );
|
||||
PUTBACK;
|
||||
|
||||
|
||||
perl_call_sv(psgi_func, G_SCALAR);
|
||||
SPAGAIN;
|
||||
|
||||
// dereference output
|
||||
response = (AV *) SvRV( sv_2mortal(newSVsv(POPs)) ) ;
|
||||
|
||||
|
||||
status_code = av_fetch(response, 0, 0);
|
||||
|
||||
wsgi_req->hvec[0].iov_base = "HTTP/1.1 ";
|
||||
wsgi_req->hvec[0].iov_len = 9 ;
|
||||
|
||||
wsgi_req->hvec[1].iov_base = SvPV(*status_code, hlen);
|
||||
wsgi_req->hvec[1].iov_len = 3 ;
|
||||
|
||||
wsgi_req->hvec[2].iov_base = " ";
|
||||
wsgi_req->hvec[2].iov_len = 1 ;
|
||||
|
||||
wsgi_req->hvec[3].iov_len = 0 ;
|
||||
|
||||
// get the status code
|
||||
for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
|
||||
if (!strncmp(http_sc->key, wsgi_req->hvec[1].iov_base, 3)) {
|
||||
wsgi_req->hvec[3].iov_base = http_sc->message ;
|
||||
wsgi_req->hvec[3].iov_len = http_sc->message_size ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wsgi_req->hvec[3].iov_len == 0) {
|
||||
wsgi_req->hvec[3].iov_base = "Unknown" ;
|
||||
wsgi_req->hvec[3].iov_len = 7;
|
||||
}
|
||||
|
||||
wsgi_req->hvec[4].iov_base = "\r\n";
|
||||
wsgi_req->hvec[4].iov_len = 2 ;
|
||||
|
||||
hitem = av_fetch(response, 1, 0) ;
|
||||
|
||||
headers = (AV *) SvRV(*hitem);
|
||||
|
||||
base = 5 ;
|
||||
|
||||
// put them in hvec
|
||||
for(i=0; i<=av_len(headers); i++) {
|
||||
|
||||
vi = (i*2)+base ;
|
||||
hitem = av_fetch(headers,i,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi].iov_base = chitem ; wsgi_req->hvec[vi].iov_len = hlen ;
|
||||
|
||||
wsgi_req->hvec[vi+1].iov_base = ": " ; wsgi_req->hvec[vi+1].iov_len = 2 ;
|
||||
|
||||
hitem = av_fetch(headers,i+1,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->hvec[vi+2].iov_base = chitem ; wsgi_req->hvec[vi+2].iov_len = hlen ;
|
||||
|
||||
wsgi_req->hvec[vi+3].iov_base = "\r\n" ; wsgi_req->hvec[vi+3].iov_len = 2 ;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
vi = (i*2)+base ;
|
||||
wsgi_req->hvec[vi].iov_base = "\r\n" ; wsgi_req->hvec[vi].iov_len = 2 ;
|
||||
|
||||
|
||||
if ( (wsgi_req->response_size = writev(wsgi_req->poll.fd, wsgi_req->hvec, vi+1)) < 0) {
|
||||
perror("writev()");
|
||||
}
|
||||
|
||||
|
||||
hitem = av_fetch(response, 2, 0) ;
|
||||
|
||||
io = *hitem;
|
||||
|
||||
|
||||
if (SvTYPE(SvRV(io)) == SVt_PVGV) {
|
||||
|
||||
for(;;) {
|
||||
|
||||
PUSHMARK(SP);
|
||||
XPUSHs(io) ;
|
||||
PUTBACK;
|
||||
perl_call_method("getline", G_SCALAR);
|
||||
SPAGAIN;
|
||||
chunk = sv_2mortal(newSVsv(POPs));
|
||||
|
||||
chitem = SvPV(chunk, hlen);
|
||||
if (hlen <= 0) {
|
||||
break;
|
||||
}
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, chitem, hlen);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (SvTYPE(SvRV(io)) == SVt_PVAV) {
|
||||
|
||||
body = (AV *) SvRV(io);
|
||||
|
||||
for(i=0; i<=av_len(body); i++) {
|
||||
hitem = av_fetch(body,i,0);
|
||||
chitem = SvPV(*hitem, hlen);
|
||||
wsgi_req->response_size += write(wsgi_req->poll.fd, chitem, hlen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FREETMPS;
|
||||
LEAVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) {
|
||||
|
||||
if (uwsgi->shared->options[UWSGI_OPTION_LOGGING])
|
||||
log_request(wsgi_req);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import os,sys
|
||||
|
||||
NAME='psgi'
|
||||
CFLAGS = os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip()
|
||||
LDFLAGS = os.popen('perl -MExtUtils::Embed -e ldopts').read().rstrip()
|
||||
Reference in New Issue
Block a user