introduced open PSGI plugin for uWSGI

This commit is contained in:
roberto@sirius
2010-04-13 08:39:49 +02:00
parent 8caee1b15b
commit 299fd9cf8a
5 changed files with 396 additions and 6 deletions
+3 -5
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+375
View File
@@ -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);
}
+5
View File
@@ -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()
+12
View File
@@ -0,0 +1,12 @@
use strict;
use warnings;
my $app = sub {
my $env = shift;
return [
'200',
[ 'Content-Type' => 'text/plain' ],
[ "Hello World\r\n", $env->{'REQUEST_URI'} ],
];
};