File: //tmp/wsgi-lsapi-2.1/wsgi.c
/*-
* Copyright (c) 2006 Allan Saddi <allan@saddi.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#include <Python.h>
#include <locale.h>
#include <wchar.h>
#include <assert.h>
#include <ctype.h>
#include "wsgi-int.h"
#include "lsapilib.h"
#include "interp.h"
const char *wsgiPyVersion = PY_VERSION;
PyObject *wsgiStderr;
const char *wsgiScriptName = "";
int wsgiScriptNameLen = 0;
static PyThreadState *_main;
#define LOG_FLAG (LSAPI_LOG_TIMESTAMP_FULL|LSAPI_LOG_FLAG_ERROR|LSAPI_LOG_PID)
#define LOG_ERR(...) LSAPI_Log(LOG_FLAG, __VA_ARGS__)
/* Assumes c is a valid hex digit */
static inline int toxdigit(int c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}
/* Unquote an escaped path */
const char *wsgiUnquote(const char *s)
{
int len = strlen(s);
char *result, *t;
if ((result = PyMem_Malloc(len + 1)) == NULL)
return NULL;
t = result;
while (*s)
{
if (*s == '%')
{
if (s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]))
{
* (t++) = (toxdigit(s[1]) << 4) | toxdigit(s[2]);
s += 3;
}
else
* (t++) = * (s++);
}
else
* (t++) = * (s++);
}
*t = '\0';
return result;
}
int wsgiPutEnv(Request *self, const char *key, const char *value)
{
PyObject *val;
int ret;
#if PY_MAJOR_VERSION < 3
if ((val = PyBytes_FromString(value)) == NULL)
#else
if ((val = PyUnicode_DecodeLatin1(value, strlen(value), NULL)) == NULL)
#endif
return -1;
ret = PyDict_SetItemString(self->environ, key, val);
Py_DECREF(val);
if (ret)
return -1;
return 0;
}
static void sendResponse500(void *ctxt)
{
static const char *headers[] =
{
"Content-Type", "text/html; charset=iso-8859-1",
};
static const char *body =
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
"<html><head>\n"
"<title>500 Internal Error</title>\n"
"</head><body>\n"
"<h1>Internal Error</h1>\n"
"<p>The server encountered an unexpected condition which\n"
"prevented it from fulfilling the request.</p>\n"
"</body></html>\n";
if (!wsgiSendHeaders(ctxt, 500, 1, headers))
wsgiSendBody(ctxt, (uint8_t *) body, strlen(body));
}
static void Request_clear(Request *self)
{
PyObject *tmp;
tmp = self->result;
self->result = NULL;
Py_XDECREF(tmp);
tmp = self->headers;
self->headers = NULL;
Py_XDECREF(tmp);
tmp = self->input;
self->input = NULL;
Py_XDECREF(tmp);
tmp = self->environ;
self->environ = NULL;
Py_XDECREF(tmp);
}
static void Request_dealloc(Request *self)
{
Request_clear(self);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *Request_new(PyTypeObject *type, PyObject *args,
PyObject *kwds)
{
Request *self;
self = (Request *) type->tp_alloc(type, 0);
if (self != NULL)
{
self->environ = PyDict_New();
if (self->environ == NULL)
{
Py_DECREF(self);
return NULL;
}
self->input = NULL;
self->statusCode = 200;
self->headers = NULL;
self->result = NULL;
self->headers_sent = 0;
}
return (PyObject *) self;
}
/* Constructor. Accepts the context CObject as its sole argument. */
static int Request_init(Request *self, PyObject *args, PyObject *kwds)
{
PyObject *context_obj, *args2;
if (!PyArg_ParseTuple(args, "O!", &PyCapsule_Type, &context_obj))
return -1;
self->context = PyCapsule_GetPointer(context_obj, "Request");
if ((args2 = Py_BuildValue("(Oi)", self,
wsgiGetContentLength(self->context))) == NULL)
return -1;
self->input = PyObject_CallObject((PyObject *) &InputStream_Type, args2);
Py_DECREF(args2);
if (self->input == NULL)
return -1;
return wsgiPopulateEnviron(self);
}
/* start_response() callable implementation */
static PyObject *Request_start_response(Request *self, PyObject *args)
{
char *psStatus;
PyObject *headers, *exc_info = NULL;
PyObject *tmp;
if (!PyArg_ParseTuple(args, "sO!|O:start_response", &psStatus,
&PyList_Type, &headers, &exc_info))
{
LOG_ERR(
"Request_start_response() ParseTuple 'sO!|O:start_response' failed.\n");
return NULL;
}
if (exc_info != NULL && exc_info != Py_None)
{
/* If the headers have already been sent, just propagate the
exception. */
if (self->headers_sent)
{
PyObject *type, *value, *tb;
if (!PyArg_ParseTuple(exc_info, "OOO", &type, &value, &tb))
{
LOG_ERR("Request_start_response() ParseTuple 'OOO' failed.\n");
return NULL;
}
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyErr_Restore(type, value, tb);
return NULL;
}
}
else if (self->headers != NULL)
{
LOG_ERR("Request_start_response headers already set.\n");
PyErr_SetString(PyExc_AssertionError, "headers already set");
return NULL;
}
/* TODO validation of status and headers */
self->statusCode = strtol(psStatus, NULL, 10);
tmp = self->headers;
Py_INCREF(headers);
self->headers = headers;
Py_XDECREF(tmp);
return PyObject_GetAttrString((PyObject *) self, "write");
}
/* Sends headers. Assumes self->status and self->headers are valid. */
static int _wsgiSendHeaders(Request *self)
{
int headerCount;
const char **headers;
int i, j;
headerCount = PyList_Size(self->headers);
if (PyErr_Occurred())
return -1;
/* NB: 1 extra header for Content-Length */
if ((headers = PyMem_Malloc(sizeof(*headers) *
(headerCount * 2 + 2))) == NULL)
return -1;
for (i = 0, j = 0; i < headerCount; i++)
{
PyObject *item;
const char *header, *value;
if ((item = PyList_GetItem(self->headers, i)) == NULL)
goto bad;
if (!PyArg_ParseTuple(item, "ss", &header, &value))
goto bad;
headers[j++] = header;
headers[j++] = value;
}
if (wsgiSendHeaders(self->context, self->statusCode,
headerCount, headers))
goto bad;
PyMem_Free(headers);
return 0;
bad:
PyMem_Free(headers);
return -1;
}
/* Send a chunk of data */
static inline int wsgiWrite(Request *self, const char *data, int len)
{
if (len)
{
if (wsgiSendBody(self->context, (uint8_t *) data, len))
return -1;
}
return 0;
}
/* write() callable implementation */
static PyObject *Request_write(Request *self, PyObject *args)
{
const char *data;
int dataLen;
if (self->headers == NULL)
{
PyErr_SetString(PyExc_AssertionError, "write() before start_response()");
return NULL;
}
if (!PyArg_ParseTuple(args, "s#:write", &data, &dataLen))
return NULL;
/* Send headers if necessary */
if (!self->headers_sent)
{
if (_wsgiSendHeaders(self))
return NULL;
self->headers_sent = 1;
}
if (wsgiWrite(self, data, dataLen))
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
/* Send a wrapped file using wsgiSendFile */
static int
wsgiSendFileWrapper(Request *self, FileWrapper *wrapper)
{
PyObject *pFileno, *args, *pFD;
int fd;
/* file-like must have fileno */
if (!PyObject_HasAttrString((PyObject *) wrapper->filelike, "fileno"))
return 1;
if ((pFileno = PyObject_GetAttrString((PyObject *) wrapper->filelike,
"fileno")) == NULL)
return -1;
if ((args = PyTuple_New(0)) == NULL)
{
Py_DECREF(pFileno);
return -1;
}
pFD = PyObject_CallObject(pFileno, args);
Py_DECREF(args);
Py_DECREF(pFileno);
if (pFD == NULL)
return -1;
#if PY_MAJOR_VERSION >= 3
fd = PyLong_AsLong(pFD);
#else
fd = PyInt_AsLong(pFD);
#endif
Py_DECREF(pFD);
if (PyErr_Occurred())
return -1;
/* Send headers if necessary */
if (!self->headers_sent)
{
if (_wsgiSendHeaders(self))
return -1;
self->headers_sent = 1;
}
if (wsgiSendFile(self->context, fd))
return -1;
return 0;
}
/* Send the application's response */
static int wsgiSendResponse(Request *self, PyObject *result)
{
PyObject *iter;
PyObject *item;
int ret;
/* Check if it's a FileWrapper */
if (result->ob_type == &FileWrapper_Type)
{
ret = wsgiSendFileWrapper(self, (FileWrapper *) result);
if (ret < 0)
return -1;
if (!ret)
return 0;
/* Fallthrough */
}
iter = PyObject_GetIter(result);
if (iter == NULL)
return -1;
while ((item = PyIter_Next(iter)))
{
int dataLen;
const char *data;
if (PyUnicode_Check(item))
{
PyObject *pBytes = PyUnicode_AsASCIIString(item);
Py_DECREF(item);
item = pBytes;
}
dataLen = PyBytes_Size(item);
if (PyErr_Occurred())
{
Py_DECREF(item);
break;
}
if (dataLen)
{
if ((data = PyBytes_AsString(item)) == NULL)
{
Py_DECREF(item);
break;
}
/* Send headers if necessary */
if (!self->headers_sent)
{
if (_wsgiSendHeaders(self))
{
Py_DECREF(item);
break;
}
self->headers_sent = 1;
}
if (wsgiWrite(self, data, dataLen))
{
Py_DECREF(item);
break;
}
}
Py_DECREF(item);
}
Py_DECREF(iter);
if (PyErr_Occurred())
return -1;
/* Send headers if they haven't been sent at this point */
if (!self->headers_sent)
{
if (_wsgiSendHeaders(self))
return -1;
self->headers_sent = 1;
}
return 0;
}
/* Ensure application's iterator's close() method is called */
static void wsgiCallClose(PyObject *result)
{
PyObject *type, *value, *traceback;
PyObject *pClose, *args, *ret;
/* Save exception state */
PyErr_Fetch(&type, &value, &traceback);
if (PyObject_HasAttrString(result, "close"))
{
pClose = PyObject_GetAttrString(result, "close");
if (pClose != NULL)
{
args = PyTuple_New(0);
if (args != NULL)
{
ret = PyObject_CallObject(pClose, args);
Py_DECREF(args);
Py_XDECREF(ret);
}
Py_DECREF(pClose);
}
}
/* Restore exception state */
PyErr_Restore(type, value, traceback);
}
static PyMethodDef Request_methods[] =
{
{
"start_response", (PyCFunction) Request_start_response, METH_VARARGS,
"WSGI start_response callable"
},
{
"write", (PyCFunction) Request_write, METH_VARARGS,
"WSGI write callable"
},
{ NULL }
};
PyTypeObject Request_Type =
{
PyVarObject_HEAD_INIT(NULL, 0)
"lsapi_wsgi.Request", /*tp_name*/
sizeof(Request), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) Request_dealloc, /*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_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"WSGI Request class", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Request_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc) Request_init, /* tp_init */
0, /* tp_alloc */
Request_new, /* tp_new */
};
static PyMethodDef wsgisup_methods[] =
{
{ NULL }
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef wsgisup_moduledef =
{
PyModuleDef_HEAD_INIT,
"lsapi_wsgi",
NULL,
0,
wsgisup_methods,
NULL,
NULL,
NULL,
NULL
};
#define INITERROR return NULL
#else
#define INITERROR return
#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif
#endif
PyMODINIT_FUNC init_wsgisup(void)
{
PyObject *m = NULL;
if (PyType_Ready(&Request_Type) < 0)
INITERROR;
if (PyType_Ready(&InputStream_Type) < 0)
INITERROR;
if (PyType_Ready(&FileWrapper_Type) < 0)
INITERROR;
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&wsgisup_moduledef);
#else
m = Py_InitModule3("lsapi_wsgi", wsgisup_methods,
"WSGI C support module");
#endif
if (m == NULL)
INITERROR;
Py_INCREF(&Request_Type);
PyModule_AddObject(m, "Request", (PyObject *) &Request_Type);
Py_INCREF(&InputStream_Type);
PyModule_AddObject(m, "InputStream", (PyObject *) &InputStream_Type);
Py_INCREF(&FileWrapper_Type);
PyModule_AddObject(m, "FileWrapper", (PyObject *) &FileWrapper_Type);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
void wsgiCleanup(void)
{
PyEval_RestoreThread(_main);
Py_XDECREF(wsgiStderr);
Py_Finalize();
}
static PyObject *importModule(const char *name, const char *filename)
{
PyObject *module = NULL;
PyObject *code = NULL;
PyObject *res = NULL;
PyObject *io_module = NULL;
PyObject *file_object = NULL;
PyObject *source_object = NULL;
const char *source_buf = NULL;
io_module = PyImport_ImportModule("io");
if (!io_module)
goto end;
file_object = PyObject_CallMethod(io_module, "open", "ss", filename, "rb");
if (!file_object)
goto end;
source_object = PyObject_CallMethod(file_object, "read", "");
if (!source_object)
goto end;
res = PyObject_CallMethod(file_object, "close", "");
if (!res)
goto end;
source_buf = PyBytes_AsString(source_object);
if (!source_buf)
goto end;
code = Py_CompileString(source_buf, filename, Py_file_input);
if (code)
module = PyImport_ExecCodeModuleEx((char *)name, code, (char *)filename);
end:
if (PyErr_Occurred())
PyErr_Print();
Py_XDECREF(io_module);
Py_XDECREF(file_object);
Py_XDECREF(source_object);
Py_XDECREF(res);
Py_XDECREF(code);
if (module)
Py_XINCREF(module);
return module;
}
#if PY_MAJOR_VERSION >= 3
wchar_t *to_wchar(const char *str)
{
int len = strlen(str) + 1;
wchar_t *ret = malloc(sizeof(wchar_t) * len);
if (ret)
mbstowcs(ret, str, len);
return ret;
}
#else
#define to_wchar(str) ((char *)str)
#endif
void python_init()
{
#if PY_MAJOR_VERSION >= 3
setlocale(LC_CTYPE, "");
#endif
const char *python_home = getenv("PYTHONHOME");
if (python_home)
Py_SetPythonHome(to_wchar(python_home));
const char *python_bin = getenv("LS_PYTHONBIN");
if (python_bin)
Py_SetProgramName(to_wchar(python_bin));
Py_Initialize();
#if PY_VERSION_HEX < 0x03090000
PyEval_InitThreads();
#endif
const char *wsgi_root = getenv("WSGI_ROOT");
if (wsgi_root)
chdir(wsgi_root);
}
void wsgiInit()
{
python_init();
//init the Types, do it here???
init_wsgisup();
_main = PyEval_SaveThread();
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
wsgi_interpreters = PyDict_New();
PyGILState_Release(gstate);
}
PyObject *wsgiImport(const char *module_name, int deref)
{
PyObject *name, *module;
name = PyUnicode_FromString(module_name);
if (name == NULL)
return NULL;
module = PyImport_Import(name);
Py_XDECREF(name);
if (deref && module)
Py_XDECREF(module);
return module;
}
//Just for sub interpreter init
int wsgiSubInit (const char *progName )
{
PyObject *sys_module;
#if PY_MAJOR_VERSION >= 3
wchar_t *argv[1];
//setlocale(LC_CTYPE,"");
argv[0] = to_wchar(progName);
if (argv[0])
{
PySys_SetArgv( 1, argv ); /* make sure sys.argv gets set */
free(argv[0]);
}
#else
char *argv[1];
argv[0] = (char *)progName;
PySys_SetArgv(1, argv); /* make sure sys.argv gets set */
#endif
if (wsgiImport("threading", 1) != NULL
&& (sys_module = wsgiImport("sys", 0)) != NULL)
{
wsgiStderr = PyObject_GetAttrString(sys_module, "stderr");
Py_DECREF(sys_module);
if (wsgiStderr != NULL)
return 0;
}
PyErr_Print();
return -1;
}
PyObject *wsgiLoadModule(const char *moduleName)
{
PyObject *pModule;
char baseName[PATH_MAX] = {0};
int pos = -1;
const char *p = strrchr(moduleName, '/');
if (p)
strncpy(baseName, p + 1, sizeof(baseName));
else
strncpy(baseName, moduleName, sizeof(baseName));
p = strchr(baseName, '.');
if (p)
{
pos = p - baseName;
baseName[pos] = 0x00;
}
pModule = importModule(baseName, moduleName);
// fprintf(stdout, "wsgiLoadModule %s %s\n", baseName, moduleName);
return pModule;
}
int fixMainFile(const char *moduleName)
{
PyObject *m, *d;
m = PyImport_AddModule("__main__");
if (m == NULL)
return -1;
Py_INCREF(m);
d = PyModule_GetDict(m);
if (PyDict_GetItemString(d, "__file__") == NULL) {
PyObject *f;
#if PY_MAJOR_VERSION >= 3
f = PyUnicode_DecodeFSDefault(moduleName);
#else
f = PyString_FromString(moduleName);
#endif
if (f != NULL)
PyDict_SetItemString(d, "__file__", f);
Py_DECREF(f);
}
Py_DECREF(m);
return 0;
}
PyObject *wsgiInitModule(PyObject *modict, const char *moduleName,
const char *appName, int reload)
{
PyObject *module, *app = NULL;
char * p = (char *)strrchr(moduleName, '/');
if (p)
{
*p = 0;
chdir(moduleName);
*p = '/';
}
module = PyDict_GetItemString(modict, moduleName);
if (module != NULL)
{
if (reload)
{
Py_DECREF(module);
module = NULL;
PyDict_DelItemString(modict, moduleName);
}
else
{
Py_INCREF(module);
}
}
if (!module)
module = wsgiLoadModule(moduleName);
if (module != NULL)
{
PyDict_SetItemString(modict, moduleName, module);
if ( appName == NULL )
appName = "application";
app = PyObject_GetAttrString(module, (char *) appName);
Py_XDECREF(module);
if (app == NULL || !PyCallable_Check(app))
{
LOG_ERR("wsgiHandler getApp [%s] failed, pApp=%p.\n", appName,
app);
if (app)
{
Py_XDECREF(app);
app = NULL;
}
}
}
return app;
}
//The global modict
static PyObject *modict = NULL;
PyObject *preload_module(const char *moduleName, const char *appName, const char *progName)
{
PyObject *app = NULL;
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
if (wsgiSubInit(progName) != 0)
{
LOG_ERR("wsgiHandler wsgiSubInit ERROR.\n");
}
else
{
fixMainFile(moduleName);
modict = PyDict_New();
app = wsgiInitModule(modict, moduleName, appName, 0);
}
PyGILState_Release(gstate);
return app;
}
int wsgiHandler(void *ctxt, char *moduleName, char *appName,
const char *progName)
{
PyGILState_STATE gstate;
PyObject *ctxt_c_obj, *args, *start_resp;
Request *req_obj = NULL;
PyObject *result;
int renew = 0;
InterpreterObject *interp = NULL;
const char *app_group_name = NULL;
char *reloading = NULL;
int reload = 0;
PyObject *pApp;
//a pointer to global or sub
PyObject **pmodict = NULL;
app_group_name = LSAPI_GetEnv_r((LSAPI_Request *)ctxt, "WSGIApplicationGroup");
#ifdef __DEBUG__
//LOG_ERR("lsapi_wsgi: interpreter '%s'.\n", app_group_name);
#endif
if (!app_group_name || strcasecmp(app_group_name, "global") == 0)
{
pmodict = &modict;
gstate = PyGILState_Ensure();
}
else
{
interp = wsgi_acquire_interpreter(app_group_name, &renew);
if (!interp)
{
LOG_ERR("wsgi_acquire_interpreter ERROR for name %s. \n", app_group_name);
goto out;
}
pmodict = &interp->modict;
}
if (*pmodict == NULL)
{
if (wsgiSubInit(progName) != 0)
{
LOG_ERR("wsgiHandler wsgiSubInit ERROR.\n");
goto out;
}
*pmodict = PyDict_New();
}
if (moduleName == NULL)
{
moduleName = LSAPI_GetScriptFileName_r((LSAPI_Request *) ctxt );
appName = LSAPI_GetEnv_r((LSAPI_Request*)ctxt, "WSGICallableObject");
if (moduleName == NULL )
{
LOG_ERR("wsgiLoadModule Error, moduleName is NULL.");
goto out;
}
}
if (renew == 0)
{
//setting "WSGIScriptReloading"
reloading = LSAPI_GetEnv_r((LSAPI_Request*)ctxt, "WSGIScriptReloading");
if (reloading != NULL && strcmp(reloading, "ON") == 0)
reload = 1;
}
pApp = wsgiInitModule(*pmodict, moduleName, appName, reload);
if (pApp == NULL)
goto out;
/* Create Request object, passing it the context as a CObject */
ctxt_c_obj = PyCapsule_New(ctxt, "Request", NULL);
if (ctxt_c_obj == NULL)
{
LOG_ERR("wsgiHandler failed to create Request object.\n");
goto out;
}
args = Py_BuildValue("(O)", ctxt_c_obj);
Py_DECREF(ctxt_c_obj);
if (args == NULL)
{
LOG_ERR("wsgiHandler failed to build args.\n");
goto out;
}
req_obj = (Request *) PyObject_CallObject((PyObject *) &Request_Type,
args);
Py_DECREF(args);
if (req_obj == NULL)
{
LOG_ERR("wsgiHandler failed to create req_obj.\n");
goto out;
}
wsgiSetRequestData(ctxt, req_obj);
/* Get start_response callable */
start_resp = PyObject_GetAttrString((PyObject *) req_obj,
"start_response");
if (start_resp == NULL)
{
LOG_ERR("wsgiHandler missing start_response.\n");
goto out;
}
/* Build arguments and call application object */
args = Py_BuildValue("(OO)", req_obj->environ, start_resp);
Py_DECREF(start_resp);
if (args == NULL)
{
LOG_ERR("wsgiHandler failed to build start_resp args.\n");
goto out;
}
result = PyObject_CallObject(pApp, args);
Py_DECREF(args);
Py_XDECREF(pApp);
if (result != NULL)
{
/* Handle the application response */
req_obj->result = result;
/* result now owned by req_obj */
wsgiSendResponse(req_obj, result); /* ignore return */
wsgiCallClose(result);
}
else
LOG_ERR("wsgiHandler pApp->start_response() return NULL.\n");
out:
if (PyErr_Occurred())
{
PyErr_Print();
/* Display HTTP 500 error, if possible */
if (req_obj == NULL || !req_obj->headers_sent)
sendResponse500(ctxt);
}
if (req_obj != NULL)
{
wsgiSetRequestData(ctxt, NULL);
/* Don't rely on cyclic GC. Clear circular references NOW. */
Request_clear(req_obj);
Py_DECREF(req_obj);
}
if (interp)
wsgi_release_interpreter(interp);
else
PyGILState_Release(gstate);
/* Always return success. */
return 0;
}
int wsgiAppHandler(void *ctxt, PyObject *app)
{
PyObject *ctxt_c_obj, *args, *start_resp;
Request *req_obj = NULL;
PyObject *result;
//LOG_ERR("wsgiAppHandler(%p)\n", app);
if (app == NULL)
goto out;
/* Create Request object, passing it the context as a CObject */
ctxt_c_obj = PyCapsule_New(ctxt, "Request", NULL);
if (ctxt_c_obj == NULL)
{
LOG_ERR("wsgiAppHandler failed to create Request object.\n");
goto out;
}
args = Py_BuildValue("(O)", ctxt_c_obj);
Py_DECREF(ctxt_c_obj);
if (args == NULL)
{
LOG_ERR("wsgiAppHandler failed to build args.\n");
goto out;
}
//LOG_ERR("wsgiAppHandler args created.\n");
req_obj = (Request *) PyObject_CallObject((PyObject *) &Request_Type,
args);
Py_DECREF(args);
if (req_obj == NULL)
{
LOG_ERR("wsgiAppHandler failed to create req_obj.\n");
goto out;
}
wsgiSetRequestData(ctxt, req_obj);
//LOG_ERR("wsgiAppHandler create start_response.\n");
/* Get start_response callable */
start_resp = PyObject_GetAttrString((PyObject *) req_obj,
"start_response");
if (start_resp == NULL)
{
LOG_ERR("wsgiHandler missing start_response.\n");
goto out;
}
/* Build arguments and call application object */
args = Py_BuildValue("(OO)", req_obj->environ, start_resp);
Py_DECREF(start_resp);
if (args == NULL)
{
LOG_ERR("wsgiAppHandler failed to build start_resp args.\n");
goto out;
}
//LOG_ERR("wsgiAppHandler call app->start_response.\n");
result = PyObject_CallObject(app, args);
Py_DECREF(args);
if (result != NULL)
{
/* Handle the application response */
req_obj->result = result;
/* result now owned by req_obj */
wsgiSendResponse(req_obj, result); /* ignore return */
wsgiCallClose(result);
}
else
LOG_ERR("wsgiAppHandler pApp->start_response() return NULL.\n");
out:
if (PyErr_Occurred())
{
PyErr_Print();
/* Display HTTP 500 error, if possible */
if (req_obj == NULL || !req_obj->headers_sent)
sendResponse500(ctxt);
}
if (req_obj != NULL)
{
wsgiSetRequestData(ctxt, NULL);
/* Don't rely on cyclic GC. Clear circular references NOW. */
Request_clear(req_obj);
Py_DECREF(req_obj);
}
/* Always return success. */
return 0;
}