mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-04-28 19:03:37 +00:00
547 lines
14 KiB
C
547 lines
14 KiB
C
#include "uwsgi_python.h"
|
|
|
|
extern struct uwsgi_server uwsgi;
|
|
extern struct uwsgi_python up;
|
|
extern struct uwsgi_plugin python_plugin;
|
|
|
|
|
|
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;
|
|
|
|
UWSGI_RELEASE_GIL
|
|
char *buf = uwsgi_request_body_readline(wsgi_req, hint, &rlen);
|
|
UWSGI_GET_GIL
|
|
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;
|
|
|
|
UWSGI_RELEASE_GIL
|
|
char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen);
|
|
UWSGI_GET_GIL
|
|
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_seek(uwsgi_Input *self, PyObject *args) {
|
|
long pos = 0;
|
|
int whence = 0;
|
|
|
|
if (!uwsgi.post_buffering) {
|
|
return PyErr_Format(PyExc_IOError, "seeking wsgi.input without post_buffering is IMPOSSIBLE !!!");
|
|
}
|
|
|
|
if (!PyArg_ParseTuple(args, "l|i:seek", &pos, &whence)) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
uwsgi_request_body_seek() uses SEEK_SET for positive value and SEEK_CUR for negative
|
|
yous hould always try to transform the "pos" value to an absolute position.
|
|
*/
|
|
|
|
// current
|
|
if (whence == 1) {
|
|
pos += self->wsgi_req->post_pos;
|
|
}
|
|
// end of stream
|
|
if (whence == 2) {
|
|
pos += self->wsgi_req->post_cl;
|
|
}
|
|
|
|
if (pos < 0 || pos > (off_t)self->wsgi_req->post_cl) {
|
|
return PyErr_Format(PyExc_IOError, "invalid seek position for wsgi.input");
|
|
}
|
|
|
|
uwsgi_request_body_seek(self->wsgi_req, pos);
|
|
|
|
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 PyObject *uwsgi_Input_tell(uwsgi_Input *self, PyObject *args) {
|
|
|
|
return PyLong_FromLong(self->wsgi_req->post_pos);
|
|
}
|
|
|
|
|
|
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 },
|
|
{ "seek", (PyCFunction)uwsgi_Input_seek, METH_VARARGS, 0 },
|
|
{ "tell", (PyCFunction)uwsgi_Input_tell, 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 = py_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 = py_current_wsgi_req();
|
|
|
|
if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (async_add_fd_read(wsgi_req, fd, timeout)) {
|
|
return PyErr_Format(PyExc_IOError, "unable to fd %d to the event queue", fd);
|
|
}
|
|
|
|
return PyString_FromString("");
|
|
}
|
|
|
|
|
|
PyObject *py_eventfd_write(PyObject * self, PyObject * args) {
|
|
int fd, timeout = 0;
|
|
|
|
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
|
|
|
if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (async_add_fd_write(wsgi_req, fd, timeout)) {
|
|
return PyErr_Format(PyExc_IOError, "unable to fd %d to the event queue", fd);
|
|
}
|
|
|
|
return PyString_FromString("");
|
|
}
|
|
|
|
int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
|
|
|
|
if (wsgi_req->is_raw) return uwsgi_request_python_raw(wsgi_req);
|
|
|
|
struct uwsgi_app *wi;
|
|
|
|
if (wsgi_req->async_force_again) {
|
|
wi = &uwsgi_apps[wsgi_req->app_id];
|
|
wsgi_req->async_force_again = 0;
|
|
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
|
|
if (ret == UWSGI_AGAIN) {
|
|
wsgi_req->async_force_again = 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Standard WSGI request */
|
|
if (!wsgi_req->len) {
|
|
uwsgi_log( "Empty python request. skip.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (uwsgi_parse_vars(wsgi_req)) {
|
|
return -1;
|
|
}
|
|
|
|
if (wsgi_req->dynamic) {
|
|
// this part must be heavy locked in threaded modes
|
|
if (uwsgi.threads > 1) {
|
|
pthread_mutex_lock(&up.lock_pyloaders);
|
|
up.is_dynamically_loading_an_app = 1;
|
|
}
|
|
}
|
|
|
|
if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, python_plugin.modifier1)) == -1) {
|
|
if (wsgi_req->dynamic) {
|
|
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 (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
|
|
if (uwsgi_apps[uwsgi.default_app].modifier1 == python_plugin.modifier1) {
|
|
wsgi_req->app_id = uwsgi.default_app;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wsgi_req->dynamic) {
|
|
if (uwsgi.threads > 1) {
|
|
up.is_dynamically_loading_an_app = 0;
|
|
pthread_mutex_unlock(&up.lock_pyloaders);
|
|
}
|
|
}
|
|
|
|
|
|
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 > 0) {
|
|
UWSGI_RELEASE_GIL
|
|
wsgi_req->async_force_again = 1;
|
|
return UWSGI_AGAIN;
|
|
}
|
|
else {
|
|
wsgi_req->switches++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// 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
|
|
|
|
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].cores[wsgi_req->async_id].harakiri > 0)
|
|
set_harakiri(wsgi_req, 0);
|
|
}
|
|
UWSGI_GET_GIL
|
|
PyObject *arh = python_call(up.after_req_hook, up.after_req_hook_args, 0, NULL);
|
|
if (!arh) {
|
|
uwsgi_manage_exception(wsgi_req, 0);
|
|
}
|
|
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 = py_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);
|
|
if (wsgi_req->sendfile_fd >= 0) {
|
|
Py_INCREF((PyObject *)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
|
|
}
|
|
}
|