diff --git a/plugins/example/example_plugin.c b/plugins/example/example_plugin.c
index b8a1ffe7..a3140e8d 100644
--- a/plugins/example/example_plugin.c
+++ b/plugins/example/example_plugin.c
@@ -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
Hello World
" ;
- 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\nHello World
" ;
+
+ wsgi_req->response_size += write(wsgi_req->poll.fd, http, strlen(http));
return 0;
}
diff --git a/plugins/lua/lua_plugin.c b/plugins/lua/lua_plugin.c
index 77029971..ca8305a9 100644
--- a/plugins/lua/lua_plugin.c
+++ b/plugins/lua/lua_plugin.c
@@ -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;
}
diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c
new file mode 100644
index 00000000..42e0c427
--- /dev/null
+++ b/plugins/psgi/psgi_plugin.c
@@ -0,0 +1,375 @@
+#include
+
+#include
+#include
+
+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;ivar_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);
+}
diff --git a/plugins/psgi/uwsgiplugin.py b/plugins/psgi/uwsgiplugin.py
new file mode 100644
index 00000000..40ed048c
--- /dev/null
+++ b/plugins/psgi/uwsgiplugin.py
@@ -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()
diff --git a/test.psgi b/test.psgi
new file mode 100644
index 00000000..9698f23d
--- /dev/null
+++ b/test.psgi
@@ -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'} ],
+ ];
+};
+