Files
uwsgi/plugins/python/wsgi_handlers.c
T
Unbit d4130dbc4b first round of protocol parsers optimizations
preliminary api for language-independent body read

another step

completed body read language independent implementation

ported gevent to the new read/write api

ported websockets to the new read/write api

removed channels subsystem

removed channels subsystem

ported lua to the new read/write api

fixed post-buffering

readline is still broken

improved request body readline

very difficult test for readline()/read() combo passed

other improvements in postbuffering/read/readline

ported --http-socket to the new api

added X-Forwarded-SSL management

removed old api

more refactoring

ported the RACK plugin to the new api

ported psgi plugin to the new api

defintely removed clustering

simpified ifdel hell

simpified ifdef hell

removed useless configuration options
2013-02-03 10:38:13 +01:00

538 lines
13 KiB
C

#include "uwsgi_python.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
PyObject *uwsgi_Input_iter(PyObject *self) {
Py_INCREF(self);
return self;
}
PyObject *uwsgi_Input_getline(uwsgi_Input *self, long hint) {
struct wsgi_request *wsgi_req = self->wsgi_req;
ssize_t rlen = 0;
char *buf = uwsgi_request_body_readline(wsgi_req, hint, &rlen);
if (buf == uwsgi.empty) {
return PyString_FromString("");
}
if (buf) {
return PyString_FromStringAndSize(buf, rlen);
}
if (rlen < 0) {
return PyErr_Format(PyExc_IOError, "error during readline(%ld) on wsgi.input", hint);
}
return PyErr_Format(PyExc_IOError, "timeout during readline(%ld) on wsgi.input", hint);
}
PyObject *uwsgi_Input_next(PyObject* self) {
PyObject *line = uwsgi_Input_getline((uwsgi_Input *)self, 0);
if (!line) return NULL;
if (PyString_Size(line) == 0) {
Py_DECREF(line);
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
return line;
}
static void uwsgi_Input_free(uwsgi_Input *self) {
PyObject_Del(self);
}
static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
long arg_len = 0;
if (!PyArg_ParseTuple(args, "|l:read", &arg_len)) {
return NULL;
}
struct wsgi_request *wsgi_req = self->wsgi_req;
ssize_t rlen = 0;
char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen);
if (buf == uwsgi.empty) {
return PyString_FromString("");
}
if (buf) {
return PyString_FromStringAndSize(buf, rlen);
}
// error ?
if (rlen < 0) {
return PyErr_Format(PyExc_IOError, "error during read(%ld) on wsgi.input", arg_len);
}
// timeout ?
return PyErr_Format(PyExc_IOError, "timeout during read(%ld) on wsgi.input", arg_len);
}
static PyObject *uwsgi_Input_readline(uwsgi_Input *self, PyObject *args) {
long hint = 0;
if (!PyArg_ParseTuple(args, "|l:readline", &hint)) {
return NULL;
}
PyObject *line = uwsgi_Input_getline(self, hint);
if (!line) return NULL;
if (PyString_Size(line) == 0) {
Py_DECREF(line);
return PyString_FromString("");
}
return line;
}
static PyObject *uwsgi_Input_readlines(uwsgi_Input *self, PyObject *args) {
long hint = 0;
if (!PyArg_ParseTuple(args, "|l:readline", &hint)) {
return NULL;
}
PyObject *res = PyList_New(0);
for(;;) {
PyObject *line = uwsgi_Input_getline(self, hint);
if (!line) {
Py_DECREF(res);
return NULL;
}
if (PyString_Size(line) == 0) {
Py_DECREF(line);
return res;
}
PyList_Append(res, line);
Py_DECREF(line);
}
return res;
}
static PyObject *uwsgi_Input_close(uwsgi_Input *self, PyObject *args) {
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *uwsgi_Input_fileno(uwsgi_Input *self, PyObject *args) {
return PyInt_FromLong(self->wsgi_req->fd);
}
static PyMethodDef uwsgi_Input_methods[] = {
{ "read", (PyCFunction)uwsgi_Input_read, METH_VARARGS, 0 },
{ "readline", (PyCFunction)uwsgi_Input_readline, METH_VARARGS, 0 },
{ "readlines", (PyCFunction)uwsgi_Input_readlines, METH_VARARGS, 0 },
// add close to allow mod_wsgi compatibility
{ "close", (PyCFunction)uwsgi_Input_close, METH_VARARGS, 0 },
{ "fileno", (PyCFunction)uwsgi_Input_fileno, METH_VARARGS, 0 },
{ NULL, NULL}
};
PyTypeObject uwsgi_InputType = {
PyVarObject_HEAD_INIT(NULL, 0)
"uwsgi._Input", /*tp_name */
sizeof(uwsgi_Input), /*tp_basicsize */
0, /*tp_itemsize */
(destructor) uwsgi_Input_free, /*tp_dealloc */
0, /*tp_print */
0, /*tp_getattr */
0, /*tp_setattr */
0, /*tp_compare */
0, /*tp_repr */
0, /*tp_as_number */
0, /*tp_as_sequence */
0, /*tp_as_mapping */
0, /*tp_hash */
0, /*tp_call */
0, /*tp_str */
0, /*tp_getattr */
0, /*tp_setattr */
0, /*tp_as_buffer */
#if defined(Py_TPFLAGS_HAVE_ITER)
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,
#else
Py_TPFLAGS_DEFAULT,
#endif
"uwsgi input object.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
uwsgi_Input_iter, /* tp_iter: __iter__() method */
uwsgi_Input_next, /* tp_iternext: next() method */
uwsgi_Input_methods,
0,0,0,0,0,0,0,0,0,0,0,0
};
PyObject *py_uwsgi_write(PyObject * self, PyObject * args) {
PyObject *data;
char *content;
size_t content_len;
struct wsgi_request *wsgi_req = current_wsgi_req();
data = PyTuple_GetItem(args, 0);
if (PyString_Check(data)) {
content = PyString_AsString(data);
content_len = PyString_Size(data);
UWSGI_RELEASE_GIL
uwsgi_response_write_body_do(wsgi_req, content, content_len);
UWSGI_GET_GIL
// this is a special case for the write callable
// no need to honout write-errors-exception-only
if (wsgi_req->write_errors > uwsgi.write_errors_tolerance && !uwsgi.disable_write_exception) {
uwsgi_py_write_set_exception(wsgi_req);
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *py_eventfd_read(PyObject * self, PyObject * args) {
int fd, timeout = 0;
struct wsgi_request *wsgi_req = current_wsgi_req();
if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) {
return NULL;
}
if (fd >= 0) {
async_add_fd_read(wsgi_req, fd, timeout);
}
return PyString_FromString("");
}
PyObject *py_eventfd_write(PyObject * self, PyObject * args) {
int fd, timeout = 0;
struct wsgi_request *wsgi_req = current_wsgi_req();
if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) {
return NULL;
}
if (fd >= 0) {
async_add_fd_write(wsgi_req, fd, timeout);
}
return PyString_FromString("");
}
int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
struct uwsgi_app *wi;
int tmp_stderr;
int free_appid = 0;
if (wsgi_req->async_status == UWSGI_AGAIN) {
wi = &uwsgi_apps[wsgi_req->app_id];
UWSGI_GET_GIL
// get rid of timeout
if (wsgi_req->async_timed_out) {
PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_True);
wsgi_req->async_timed_out = 0;
}
else {
PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None);
}
if (wsgi_req->async_ready_fd) {
PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", PyInt_FromLong(wsgi_req->async_last_ready_fd));
wsgi_req->async_ready_fd = 0;
}
else {
PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", Py_None);
}
int ret = manage_python_response(wsgi_req);
if (ret == UWSGI_OK) goto end;
UWSGI_RELEASE_GIL
return ret;
}
/* Standard WSGI request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty python request. skip.\n");
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (wsgi_req->appid_len == 0) {
if (!uwsgi.ignore_script_name) {
wsgi_req->appid = wsgi_req->script_name;
wsgi_req->appid_len = wsgi_req->script_name_len;
}
if (uwsgi.vhost) {
wsgi_req->appid = uwsgi_concat3n(wsgi_req->host, wsgi_req->host_len, "|",1, wsgi_req->script_name, wsgi_req->script_name_len);
wsgi_req->appid_len = wsgi_req->host_len + 1 + wsgi_req->script_name_len;
#ifdef UWSGI_DEBUG
uwsgi_debug("VirtualHost KEY=%.*s\n", wsgi_req->appid_len, wsgi_req->appid);
#endif
free_appid = 1;
}
}
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req->appid, wsgi_req->appid_len, 0)) == -1) {
wsgi_req->app_id = uwsgi.default_app;
if (uwsgi.no_default_app) {
wsgi_req->app_id = -1;
}
if (wsgi_req->dynamic) {
// this part must be heavy locked in threaded modes
if (uwsgi.threads > 1) {
pthread_mutex_lock(&up.lock_pyloaders);
}
UWSGI_GET_GIL
if (uwsgi.single_interpreter) {
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, PYTHON_APP_TYPE_WSGI);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
}
}
}
if (free_appid) {
free(wsgi_req->appid);
}
if (wsgi_req->app_id == -1) {
uwsgi_500(wsgi_req);
uwsgi_log("--- no python application found, check your startup logs for errors ---\n");
goto clear2;
}
wi = &uwsgi_apps[wsgi_req->app_id];
up.swap_ts(wsgi_req, wi);
if (wi->chdir[0] != 0) {
#ifdef UWSGI_DEBUG
uwsgi_debug("chdir to %s\n", wi->chdir);
#endif
if (chdir(wi->chdir)) {
uwsgi_error("chdir()");
}
}
UWSGI_GET_GIL
// no fear of race conditions for this counter as it is already protected by the GIL
wi->requests++;
// create WSGI environ
wsgi_req->async_environ = up.wsgi_env_create(wsgi_req, wi);
wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi);
if (wsgi_req->async_result) {
while (wi->response_subhandler(wsgi_req) != UWSGI_OK) {
if (uwsgi.async > 1) {
UWSGI_RELEASE_GIL
return UWSGI_AGAIN;
}
else {
wsgi_req->switches++;
}
}
}
else if (uwsgi.catch_exceptions) {
// LOCK THIS PART
uwsgi_500(wsgi_req);
if (uwsgi_response_write_headers_do(wsgi_req)) goto clear;
/*
sorry that is a hack to avoid the rewrite of PyErr_Print
temporarily map (using dup2) stderr to wsgi_req->fd
*/
tmp_stderr = dup(2);
if (tmp_stderr < 0) {
uwsgi_error("dup()");
goto clear;
}
// map 2 to wsgi_req
if (dup2(wsgi_req->fd, 2) < 0) {
close(tmp_stderr);
uwsgi_error("dup2()");
goto clear;
}
// print the error
UWSGI_GET_GIL
PyErr_Print();
UWSGI_RELEASE_GIL
// ...resume the original stderr, in case of error we are damaged forever !!!
if (dup2(tmp_stderr, 2) < 0) {
uwsgi_error("dup2()");
}
close(tmp_stderr);
}
// this object must be freed/cleared always
end:
if (wsgi_req->async_input) {
Py_DECREF((PyObject *)wsgi_req->async_input);
}
if (wsgi_req->async_environ) {
up.wsgi_env_destroy(wsgi_req);
}
UWSGI_RELEASE_GIL
clear:
up.reset_ts(wsgi_req, wi);
clear2:
return UWSGI_OK;
}
void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) {
if (up.after_req_hook) {
if (uwsgi.harakiri_no_arh) {
// leave harakiri mode
if (uwsgi.workers[uwsgi.mywid].harakiri > 0)
set_harakiri(0);
}
UWSGI_GET_GIL
PyObject *arh = python_call(up.after_req_hook, up.after_req_hook_args, 0, NULL);
if (!arh) {
PyErr_Print();
}
else {
Py_DECREF(arh);
}
PyErr_Clear();
UWSGI_RELEASE_GIL
}
log_request(wsgi_req);
}
PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) {
struct wsgi_request *wsgi_req = current_wsgi_req();
if (!PyArg_ParseTuple(args, "O|i:uwsgi_sendfile", &wsgi_req->async_sendfile, &wsgi_req->sendfile_fd_chunk)) {
return NULL;
}
#ifdef PYTHREE
wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(wsgi_req->async_sendfile);
#else
if (PyFile_Check((PyObject *)wsgi_req->async_sendfile)) {
Py_INCREF((PyObject *)wsgi_req->async_sendfile);
wsgi_req->sendfile_fd = PyObject_AsFileDescriptor(wsgi_req->async_sendfile);
}
#endif
// PEP 333 hack
wsgi_req->sendfile_obj = wsgi_req->async_sendfile;
//wsgi_req->sendfile_obj = (void *) PyTuple_New(0);
Py_INCREF((PyObject *) wsgi_req->sendfile_obj);
return (PyObject *) wsgi_req->sendfile_obj;
}
void threaded_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
UWSGI_GET_GIL
PyThreadState_Swap(uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].ts[wsgi_req->app_id]);
UWSGI_RELEASE_GIL
}
}
void threaded_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
UWSGI_GET_GIL
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key));
UWSGI_RELEASE_GIL
}
}
void simple_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
// restoring main interpreter
PyThreadState_Swap(up.main_thread);
}
}
void simple_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
// set the interpreter
PyThreadState_Swap(wi->interpreter);
}
}
void simple_threaded_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
// restoring main interpreter
UWSGI_GET_GIL
PyThreadState_Swap(up.main_thread);
UWSGI_RELEASE_GIL
}
}
void simple_threaded_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
// set the interpreter
UWSGI_GET_GIL
PyThreadState_Swap(wi->interpreter);
UWSGI_RELEASE_GIL
}
}