diff --git a/hello_world.py b/hello_world.py
index 9509c649..e5328f3e 100644
--- a/hello_world.py
+++ b/hello_world.py
@@ -1,5 +1,5 @@
import uwsgi
-uwsgi.cache_set('/', "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello World from cache")
+#uwsgi.cache_set('/', "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello World from cache")
def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return "
Hello World
"
diff --git a/plugins/python/pyloader.c b/plugins/python/pyloader.c
index e357c05d..2a9649b9 100644
--- a/plugins/python/pyloader.c
+++ b/plugins/python/pyloader.c
@@ -22,9 +22,8 @@ PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_re
PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}};
#endif
-int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter) {
+int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter, int app_type) {
- PyObject *zero;
PyObject *app_list = NULL, *applications = NULL;
int id = uwsgi.apps_cnt;
@@ -212,48 +211,23 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
}
#endif
- // check function args
- // by defaut it is a WSGI app
- wi->argc = 2;
- zero = PyObject_GetAttrString(wi->callable, "__code__");
- if (!zero) {
- zero = PyObject_GetAttrString(wi->callable, "__call__");
- if (zero) {
- zero = PyObject_GetAttrString(wi->callable, "__code__");
- }
- else {
- uwsgi_log("WARNING: unable to get the number of callable args. Fallback to WSGI\n");
- }
- }
+ wi->argc = 1;
- // avoid __code__ attr error propagation
- PyErr_Clear();
-
- if (zero) {
- zero = PyObject_GetAttrString(zero, "co_argcount");
- wi->argc = (int) PyInt_AsLong(zero);
- }
-
- if (wi->argc == 2) {
+ if (app_type == PYTHON_APP_TYPE_WSGI) {
#ifdef UWSGI_DEBUG
- uwsgi_log("-- WSGI callable detected --\n");
+ uwsgi_log("-- WSGI callable selected --\n");
#endif
wi->request_subhandler = uwsgi_request_subhandler_wsgi;
wi->response_subhandler = uwsgi_response_subhandler_wsgi;
+ wi->argc = 2;
}
-#ifdef UWSGI_WEB3
- else if (wi->argc == 1) {
+ else if (app_type == PYTHON_APP_TYPE_WEB3) {
#ifdef UWSGI_DEBUG
- uwsgi_log("-- Web3 callable detected --\n");
+ uwsgi_log("-- Web3 callable selected --\n");
#endif
wi->request_subhandler = uwsgi_request_subhandler_web3;
wi->response_subhandler = uwsgi_response_subhandler_web3;
}
-#endif
- else {
- uwsgi_log("-- INVALID callable detected --\n");
- goto doh;
- }
#ifdef UWSGI_ASYNC
wi->args = malloc(sizeof(PyObject*)*uwsgi.cores);
@@ -270,7 +244,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
}
// add start_response on WSGI app
- if (wi->argc == 2) {
+ if (app_type == PYTHON_APP_TYPE_WSGI) {
if (PyTuple_SetItem(wi->args[i], 1, up.wsgi_spitout)) {
uwsgi_log("unable to set start_response in args tuple\n");
exit(1);
@@ -280,7 +254,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
#else
wi->wsgi_args = PyTuple_New(wi->argc);
- if (wi->argc == 2) {
+ if (app_type == PYTHON_APP_TYPE_WSGI) {
if (PyTuple_SetItem(wi->wsgi_args, 1, up.wsgi_spitout)) {
uwsgi_log("unable to set start_response in args tuple\n");
exit(1);
@@ -288,7 +262,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
}
#endif
- if (wi->argc == 2) {
+ if (app_type == PYTHON_APP_TYPE_WSGI) {
#ifdef UWSGI_SENDFILE
// prepare sendfile() for WSGI app
wi->sendfile = PyCFunction_New(uwsgi_sendfile_method, NULL);
@@ -329,12 +303,12 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
PyThreadState_Swap(up.main_thread);
}
- if (wi->argc == 1) {
- uwsgi_log( "Web3 application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
- }
- else {
+ if (app_type == PYTHON_APP_TYPE_WSGI) {
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p pid: %d", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter, (int) getpid());
}
+ else if (app_type == PYTHON_APP_TYPE_WEB3) {
+ uwsgi_log( "Web3 application %d (SCRIPT_NAME=%.*s) ready on interpreter %p pid: %d", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter, (int) getpid());
+ }
if (!wsgi_req->script_name_len) {
uwsgi_rawlog(" (default app)");
@@ -355,7 +329,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThre
wsgi_req->script_name = PyString_AsString(app_mnt);
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
- init_uwsgi_app(LOADER_CALLABLE, PyDict_GetItem(applications, app_mnt), wsgi_req, wi->interpreter);
+ init_uwsgi_app(LOADER_CALLABLE, PyDict_GetItem(applications, app_mnt), wsgi_req, wi->interpreter, app_type);
}
}
diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c
index b0a567ac..fb52444e 100644
--- a/plugins/python/python_plugin.c
+++ b/plugins/python/python_plugin.c
@@ -31,6 +31,9 @@ struct option uwsgi_python_options[] = {
{"pyargv", required_argument, 0, LONG_ARGS_PYARGV},
{"optimize", required_argument, 0, 'O'},
{"paste", required_argument, 0, LONG_ARGS_PASTE},
+ {"web3", required_argument, 0, LONG_ARGS_WEB3},
+ {"pump", required_argument, 0, LONG_ARGS_PUMP},
+ {"wsgi-lite", required_argument, 0, LONG_ARGS_WSGI_LITE},
#ifdef UWSGI_INI
{"ini-paste", required_argument, 0, LONG_ARGS_INI_PASTE},
#endif
@@ -742,6 +745,15 @@ int uwsgi_python_manage_options(int i, char *optarg) {
}
return 1;
#endif
+ case LONG_ARGS_WEB3:
+ up.web3 = optarg;
+ return 1;
+ case LONG_ARGS_PUMP:
+ up.pump = optarg;
+ return 1;
+ case LONG_ARGS_WSGI_LITE:
+ up.wsgi_lite = optarg;
+ return 1;
case LONG_ARGS_PASTE:
up.paste = optarg;
return 1;
@@ -758,9 +770,9 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
uwsgi.wsgi_req->script_name = mountpoint;
uwsgi.wsgi_req->script_name_len = strlen(mountpoint);
if (uwsgi.single_interpreter) {
- return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread);
+ return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
- return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL);
+ return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
}
@@ -889,17 +901,26 @@ void uwsgi_python_init_apps() {
if (up.wsgi_config != NULL) {
- init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread);
+ init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
if (up.file_config != NULL) {
- init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread);
+ init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
if (up.paste != NULL) {
- init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread);
+ init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
if (up.eval != NULL) {
- init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread);
+ init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
+ }
+ if (up.web3 != NULL) {
+ init_uwsgi_app(LOADER_UWSGI, up.web3, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WEB3);
+ }
+ if (up.pump != NULL) {
+ init_uwsgi_app(LOADER_UWSGI, up.pump, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_PUMP);
+ }
+ if (up.wsgi_lite != NULL) {
+ init_uwsgi_app(LOADER_UWSGI, up.wsgi_lite, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI_LITE);
}
if (uwsgi.profiler) {
@@ -979,16 +1000,16 @@ int uwsgi_python_xml(char *node, char *content) {
}
if (!strcmp("script", node)) {
- return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
else if (!strcmp("file", node)) {
- return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
else if (!strcmp("eval", node)) {
- return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
else if (!strcmp("wsgi", node)) {
- return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
else if (!strcmp("module", node)) {
uwsgi.wsgi_req->module = content;
@@ -999,10 +1020,10 @@ int uwsgi_python_xml(char *node, char *content) {
uwsgi.wsgi_req->callable++;
uwsgi.wsgi_req->callable_len = strlen(uwsgi.wsgi_req->callable);
uwsgi.wsgi_req->module_len = strlen(uwsgi.wsgi_req->module);
- return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
else {
- return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
return 1;
}
@@ -1014,7 +1035,7 @@ int uwsgi_python_xml(char *node, char *content) {
else if (!strcmp("callable", node)) {
uwsgi.wsgi_req->callable = content;
uwsgi.wsgi_req->callable_len = strlen(content);
- return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
+ return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter, PYTHON_APP_TYPE_WSGI);
}
return 0;
diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h
index 37f4e243..4436fdd2 100644
--- a/plugins/python/uwsgi_python.h
+++ b/plugins/python/uwsgi_python.h
@@ -15,6 +15,15 @@
#define LONG_ARGS_RELOAD_OS_ENV LONG_ARGS_PYTHON_BASE + 5
#define LONG_ARGS_PYIMPORT LONG_ARGS_PYTHON_BASE + 6
#define LONG_ARGS_POST_PYMODULE_ALIAS LONG_ARGS_PYTHON_BASE + 7
+#define LONG_ARGS_WEB3 LONG_ARGS_PYTHON_BASE + 8
+#define LONG_ARGS_PUMP LONG_ARGS_PYTHON_BASE + 9
+#define LONG_ARGS_WSGI_LITE LONG_ARGS_PYTHON_BASE + 10
+
+#define PYTHON_APP_TYPE_WSGI 0
+#define PYTHON_APP_TYPE_WEB3 1
+#define PYTHON_APP_TYPE_WSGI2 2
+#define PYTHON_APP_TYPE_PUMP 3
+#define PYTHON_APP_TYPE_WSGI_LITE 4
#if PY_MINOR_VERSION == 4 && PY_MAJOR_VERSION == 2
#define Py_ssize_t ssize_t
@@ -83,6 +92,16 @@ PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t);
#define LOADER_MAX 8
+typedef struct uwsgi_Input {
+ PyObject_HEAD
+ char readline[1024];
+ size_t readline_size;
+ size_t readline_max_size;
+ size_t readline_pos;
+ size_t pos;
+ struct wsgi_request *wsgi_req;
+} uwsgi_Input;
+
struct uwsgi_python {
char *home;
@@ -116,6 +135,9 @@ struct uwsgi_python {
char *paste;
char *eval;
+ char *web3;
+ char *pump;
+ char *wsgi_lite;
char *callable;
@@ -166,7 +188,7 @@ void uwsgi_paste_config(char *);
void uwsgi_file_config(char *);
void uwsgi_eval_config(char *);
-int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, PyThreadState *);
+int init_uwsgi_app(int, void *, struct wsgi_request *, PyThreadState *, int);
PyObject *py_eventfd_read(PyObject *, PyObject *);
@@ -188,10 +210,8 @@ PyObject *py_uwsgi_spit(PyObject *, PyObject *);
void init_pyargv(void);
-#ifdef UWSGI_WEB3
void *uwsgi_request_subhandler_web3(struct wsgi_request *, struct uwsgi_app *);
int uwsgi_response_subhandler_web3(struct wsgi_request *);
-#endif
PyObject *uwsgi_uwsgi_loader(void *);
PyObject *uwsgi_dyn_loader(void *);
diff --git a/plugins/python/uwsgiplugin.py b/plugins/python/uwsgiplugin.py
index 4b58db8d..5f21c9e8 100644
--- a/plugins/python/uwsgiplugin.py
+++ b/plugins/python/uwsgiplugin.py
@@ -3,7 +3,7 @@ import os,sys
from distutils import sysconfig
NAME='python'
-GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter']
+GCC_LIST = ['python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter']
CFLAGS = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True) ]
LDFLAGS = []
diff --git a/plugins/python/web3_subhandler.c b/plugins/python/web3_subhandler.c
index d6a108cc..c1964f6e 100644
--- a/plugins/python/web3_subhandler.c
+++ b/plugins/python/web3_subhandler.c
@@ -1,20 +1,70 @@
-#include "uwsgi.h"
+#include "uwsgi_python.h"
extern struct uwsgi_server uwsgi;
+extern struct uwsgi_python up;
+extern PyTypeObject uwsgi_InputType;
void *uwsgi_request_subhandler_web3(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
- PyObject *zero, *wsgi_socket;
+ PyObject *zero;
- wsgi_socket = PyFile_FromFile(wsgi_req->async_post, "web3_input", "r", NULL);
- PyDict_SetItemString(wsgi_req->async_environ, "web3.input", wsgi_socket);
- Py_DECREF(wsgi_socket);
+ int i;
+ PyObject *pydictkey, *pydictvalue;
+ char *path_info;
- zero = PyTuple_New(2);
- PyTuple_SetItem(zero, 0, PyInt_FromLong(1));
- PyTuple_SetItem(zero, 1, PyInt_FromLong(0));
- PyDict_SetItemString(wsgi_req->async_environ, "web3.version", zero);
- Py_DECREF(zero);
+ for (i = 0; i < wsgi_req->var_cnt; i += 2) {
+#ifdef UWSGI_DEBUG
+ uwsgi_debug("%.*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);
+#endif
+#ifdef PYTHREE
+ pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, NULL);
+ pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL);
+#else
+ pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
+ pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len);
+#endif
+ PyDict_SetItem(wsgi_req->async_environ, pydictkey, pydictvalue);
+ Py_DECREF(pydictkey);
+ Py_DECREF(pydictvalue);
+ }
+
+ if (wsgi_req->uh.modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
+ wsgi_req->uh.modifier1 = 0;
+ pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME");
+ if (pydictkey) {
+ if (PyString_Check(pydictkey)) {
+ pydictvalue = PyDict_GetItemString(wsgi_req->async_environ, "PATH_INFO");
+ if (pydictvalue) {
+ if (PyString_Check(pydictvalue)) {
+ path_info = PyString_AsString(pydictvalue);
+ PyDict_SetItemString(wsgi_req->async_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey)));
+ }
+ }
+ }
+ }
+ }
+
+ // if async_post is mapped as a file, directly use it as wsgi.input
+ if (wsgi_req->async_post) {
+#ifdef PYTHREE
+ wsgi_req->async_input = PyFile_FromFd(fileno(wsgi_req->async_post), "web3_input", "rb", 0, NULL, NULL, NULL, 0);
+#else
+ wsgi_req->async_input = PyFile_FromFile(wsgi_req->async_post, "web3_input", "r", NULL);
+#endif
+ }
+ else {
+ // create wsgi.input custom object
+ wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
+ ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req;
+ ((uwsgi_Input*)wsgi_req->async_input)->pos = 0;
+ ((uwsgi_Input*)wsgi_req->async_input)->readline_pos = 0;
+ ((uwsgi_Input*)wsgi_req->async_input)->readline_max_size = 0;
+
+ }
+
+ PyDict_SetItemString(wsgi_req->async_environ, "web3.input", wsgi_req->async_input);
+
+ PyDict_SetItemString(wsgi_req->async_environ, "web3.version", wi->uwsgi_version);
zero = PyFile_FromFile(stderr, "web3_input", "w", NULL);
PyDict_SetItemString(wsgi_req->async_environ, "web3.errors", zero);
@@ -48,12 +98,30 @@ void *uwsgi_request_subhandler_web3(struct wsgi_request *wsgi_req, struct uwsgi_
Py_DECREF(zero);
- wsgi_req->async_app = wi->wsgi_callable;
+ wsgi_req->async_app = wi->callable;
- PyDict_SetItemString(uwsgi.embedded_dict, "env", wsgi_req->async_environ);
+ // export .env only in non-threaded mode
+ if (uwsgi.threads < 2) {
+ PyDict_SetItemString(up.embedded_dict, "env", wsgi_req->async_environ);
+ }
- // TODO: fix this
- //PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.version", uwsgi_version);
+ PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.version", wi->uwsgi_version);
+
+ if (uwsgi.cores > 1) {
+ PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.core", PyInt_FromLong(wsgi_req->async_id));
+ }
+
+ // cache this ?
+ if (uwsgi.cluster_fd >= 0) {
+ zero = PyString_FromString(uwsgi.cluster);
+ PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.cluster", zero);
+ Py_DECREF(zero);
+ zero = PyString_FromString(uwsgi.hostname);
+ PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.cluster_node", zero);
+ Py_DECREF(zero);
+ }
+
+ PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.node", wi->uwsgi_node);
// call
@@ -68,16 +136,7 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) {
PyObject *pychunk;
ssize_t wsize;
- // return or yield ? (PyString on python2 PyBytes on python3)
- if (PyString_Check((PyObject *)wsgi_req->async_result)) {
- if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(wsgi_req->async_result), PyString_Size(wsgi_req->async_result))) < 0) {
- uwsgi_error("write()");
- goto clear;
- }
- wsgi_req->response_size += wsize;
- goto clear;
- }
-
+ UWSGI_GET_GIL
// ok its a yield
if (!wsgi_req->async_placeholder) {
@@ -86,19 +145,36 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) {
uwsgi_log("invalid Web3 response.\n");
goto clear;
}
- if (py_uwsgi_spit(NULL, (PyObject *)wsgi_req->async_result) == Py_None) {
+ PyObject *spit_args = PyTuple_New(2);
+ PyTuple_SetItem(spit_args, 0, PyTuple_GetItem((PyObject *)wsgi_req->async_result, 1));
+ PyTuple_SetItem(spit_args, 1, PyTuple_GetItem((PyObject *)wsgi_req->async_result, 2));
+ Py_INCREF((PyObject *)wsgi_req->async_result);
+
+ if (py_uwsgi_spit(NULL, spit_args) == Py_None) {
+ Py_DECREF(spit_args);
goto clear;
}
+ Py_DECREF(spit_args);
- wsgi_req->async_result = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 0);
+ wsgi_req->async_placeholder = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 0);
- wsgi_req->async_placeholder = PyObject_GetIter( (PyObject *)wsgi_req->async_result );
+ if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) {
+ if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(wsgi_req->async_placeholder), PyString_Size(wsgi_req->async_placeholder))) < 0) {
+ uwsgi_error("write()");
+ goto clear;
+ }
+ wsgi_req->response_size += wsize;
+ goto clear;
+ }
+
+ wsgi_req->async_placeholder = PyObject_GetIter( (PyObject *)wsgi_req->async_placeholder );
if (!wsgi_req->async_placeholder) {
- goto clear2;
+ goto clear;
}
#ifdef UWSGI_ASYNC
if (uwsgi.async > 1) {
+ UWSGI_RELEASE_GIL
return UWSGI_AGAIN;
}
}
@@ -121,7 +197,7 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) {
if (PyString_Check(pychunk)) {
- if ((wsize = write(wsgi_req->poll.fd, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
+ if ((wsize = wsgi_req->socket->proto_write(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk))) < 0) {
uwsgi_error("write()");
Py_DECREF(pychunk);
goto clear;
@@ -131,34 +207,22 @@ int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) {
Py_DECREF(pychunk);
+ UWSGI_RELEASE_GIL
return UWSGI_AGAIN;
clear:
+ if (wsgi_req->async_input) {
+ Py_DECREF((PyObject *)wsgi_req->async_input);
+ }
if (wsgi_req->async_environ) {
PyDict_Clear(wsgi_req->async_environ);
}
- if (wsgi_req->async_post && !wsgi_req->fd_closed) {
- fclose(wsgi_req->async_post);
- if (!uwsgi.post_buffering || wsgi_req->post_cl <= (size_t) uwsgi.post_buffering) {
- wsgi_req->fd_closed = 1;
- }
- }
Py_XDECREF((PyObject *)wsgi_req->async_placeholder);
-clear2:
+
Py_DECREF((PyObject *)wsgi_req->async_result);
PyErr_Clear();
-#ifdef UWSGI_DEBUG
- if (wsgi_req->async_placeholder) {
- uwsgi_debug("wsgi_req->async_placeholder: %d\n", ((PyObject *)wsgi_req->async_placeholder)->ob_refcnt);
- }
- if (wsgi_req->async_result) {
- uwsgi_debug("wsgi_req->async_result: %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt);
- }
- if (wsgi_req->async_app) {
- uwsgi_debug("wsgi_req->async_app: %d\n", ((PyObject *)wsgi_req->async_app)->ob_refcnt);
- }
-#endif
+ UWSGI_RELEASE_GIL
return UWSGI_OK;
}
diff --git a/plugins/python/wsgi_handlers.c b/plugins/python/wsgi_handlers.c
index 5c4eb6d6..ce3fbbbf 100644
--- a/plugins/python/wsgi_handlers.c
+++ b/plugins/python/wsgi_handlers.c
@@ -4,16 +4,6 @@ extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
-typedef struct uwsgi_Input {
- PyObject_HEAD
- char readline[1024];
- size_t readline_size;
- size_t readline_max_size;
- size_t readline_pos;
- size_t pos;
- struct wsgi_request *wsgi_req;
-} uwsgi_Input;
-
PyObject *uwsgi_Input_iter(PyObject *self) {
Py_INCREF(self);
return self;
@@ -62,7 +52,7 @@ PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
else {
rlen = read(wsgi_req->poll.fd, self->readline, 1024);
}
- if (rlen < 0) {
+ if (rlen <= 0) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
}
@@ -166,7 +156,7 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
}
rlen = read(self->wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
- if (rlen < 0) {
+ if (rlen <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data");
@@ -327,11 +317,6 @@ PyObject *py_eventfd_write(PyObject * self, PyObject * args) {
int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
- int i;
-
- PyObject *pydictkey, *pydictvalue;
-
- char *path_info;
struct uwsgi_app *wi;
int tmp_stderr;
@@ -406,10 +391,10 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
UWSGI_GET_GIL
if (uwsgi.single_interpreter) {
- wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
+ wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI);
}
else {
- wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
+ wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL, PYTHON_APP_TYPE_WSGI);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
@@ -485,60 +470,6 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
Py_INCREF((PyObject *)wsgi_req->async_environ);
- for (i = 0; i < wsgi_req->var_cnt; i += 2) {
-#ifdef UWSGI_DEBUG
- uwsgi_debug("%.*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);
-#endif
-#ifdef PYTHREE
- pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, NULL);
- pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL);
-#else
- pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
- pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len);
-#endif
- PyDict_SetItem(wsgi_req->async_environ, pydictkey, pydictvalue);
- Py_DECREF(pydictkey);
- Py_DECREF(pydictvalue);
- }
-
- if (wsgi_req->uh.modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
- wsgi_req->uh.modifier1 = 0;
- pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME");
- if (pydictkey) {
- if (PyString_Check(pydictkey)) {
- pydictvalue = PyDict_GetItemString(wsgi_req->async_environ, "PATH_INFO");
- if (pydictvalue) {
- if (PyString_Check(pydictvalue)) {
- path_info = PyString_AsString(pydictvalue);
- PyDict_SetItemString(wsgi_req->async_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey)));
- }
- }
- }
- }
- }
-
-
-
- // if async_post is mapped as a file, directly use it as wsgi.input
- if (wsgi_req->async_post) {
-#ifdef PYTHREE
- wsgi_req->async_input = PyFile_FromFd(fileno(wsgi_req->async_post), "wsgi_input", "rb", 0, NULL, NULL, NULL, 0);
-#else
- wsgi_req->async_input = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
-#endif
- }
- else {
- // create wsgi.input custom object
- wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
- ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req;
- ((uwsgi_Input*)wsgi_req->async_input)->pos = 0;
- ((uwsgi_Input*)wsgi_req->async_input)->readline_pos = 0;
- ((uwsgi_Input*)wsgi_req->async_input)->readline_max_size = 0;
-
- }
-
- PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input);
-
wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi);
UWSGI_RELEASE_GIL
diff --git a/plugins/python/wsgi_subhandler.c b/plugins/python/wsgi_subhandler.c
index 1dd2a99a..ee7ab2b1 100644
--- a/plugins/python/wsgi_subhandler.c
+++ b/plugins/python/wsgi_subhandler.c
@@ -2,10 +2,66 @@
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
+extern PyTypeObject uwsgi_InputType;
void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
PyObject *zero;
+ int i;
+ PyObject *pydictkey, *pydictvalue;
+ char *path_info;
+
+ for (i = 0; i < wsgi_req->var_cnt; i += 2) {
+#ifdef UWSGI_DEBUG
+ uwsgi_debug("%.*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);
+#endif
+#ifdef PYTHREE
+ pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, NULL);
+ pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL);
+#else
+ pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len);
+ pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len);
+#endif
+ PyDict_SetItem(wsgi_req->async_environ, pydictkey, pydictvalue);
+ Py_DECREF(pydictkey);
+ Py_DECREF(pydictvalue);
+ }
+
+ if (wsgi_req->uh.modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
+ wsgi_req->uh.modifier1 = 0;
+ pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME");
+ if (pydictkey) {
+ if (PyString_Check(pydictkey)) {
+ pydictvalue = PyDict_GetItemString(wsgi_req->async_environ, "PATH_INFO");
+ if (pydictvalue) {
+ if (PyString_Check(pydictvalue)) {
+ path_info = PyString_AsString(pydictvalue);
+ PyDict_SetItemString(wsgi_req->async_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey)));
+ }
+ }
+ }
+ }
+ }
+
+ // if async_post is mapped as a file, directly use it as wsgi.input
+ if (wsgi_req->async_post) {
+#ifdef PYTHREE
+ wsgi_req->async_input = PyFile_FromFd(fileno(wsgi_req->async_post), "wsgi_input", "rb", 0, NULL, NULL, NULL, 0);
+#else
+ wsgi_req->async_input = PyFile_FromFile(wsgi_req->async_post, "wsgi_input", "r", NULL);
+#endif
+ }
+ else {
+ // create wsgi.input custom object
+ wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType);
+ ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req;
+ ((uwsgi_Input*)wsgi_req->async_input)->pos = 0;
+ ((uwsgi_Input*)wsgi_req->async_input)->readline_pos = 0;
+ ((uwsgi_Input*)wsgi_req->async_input)->readline_max_size = 0;
+
+ }
+
+ PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input);
#ifdef UWSGI_SENDFILE
PyDict_SetItemString(wsgi_req->async_environ, "wsgi.file_wrapper", wi->sendfile);
diff --git a/tests/web3.py b/tests/web3.py
new file mode 100644
index 00000000..2370e63c
--- /dev/null
+++ b/tests/web3.py
@@ -0,0 +1,9 @@
+class AppClass(object):
+
+ def __call__(self, environ):
+ status = b'200 OK'
+ headers = [(b'Content-type', b'text/plain')]
+ body = [b'Hello world!\n']
+ return body, status, headers
+
+application = AppClass()