#include "uwsgi_python.h"
extern struct uwsgi_server uwsgi;
extern struct uwsgi_python up;
// check here
PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
PyObject *headers, *head;
PyObject *h_key, *h_value;
PyObject *exc_info = NULL;
size_t i;
struct wsgi_request *wsgi_req = py_current_wsgi_req();
// avoid double sending of headers
if (wsgi_req->headers_sent) {
return PyErr_Format(PyExc_IOError, "headers already sent");
}
// this must be done before headers management
if (PyTuple_Size(args) > 2) {
exc_info = PyTuple_GetItem(args, 2);
if (exc_info && exc_info != Py_None) {
PyObject *exc_type = PyTuple_GetItem(exc_info, 0);
PyObject *exc_val = PyTuple_GetItem(exc_info, 1);
PyObject *exc_tb = PyTuple_GetItem(exc_info, 2);
if (!exc_type || !exc_val || !exc_tb) {
return NULL;
}
Py_INCREF(exc_type);
Py_INCREF(exc_val);
Py_INCREF(exc_tb);
// in this way, error will be reported to the log
PyErr_Restore(exc_type, exc_val, exc_tb);
// the error is reported, let's continue...
// return NULL
}
}
head = PyTuple_GetItem(args, 0);
if (!head) {
return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
}
#ifdef PYTHREE
// check for web3
if ((self != Py_None && !PyUnicode_Check(head)) || (self == Py_None && !PyBytes_Check(head))) {
#else
if (!PyString_Check(head)) {
#endif
return PyErr_Format(PyExc_TypeError, "http status must be a string");
}
char *status_line = NULL;
size_t status_line_len = 0;
#ifdef PYTHREE
PyObject *zero = NULL;
PyObject *zero2 = NULL;
if (self != Py_None) {
zero = PyUnicode_AsLatin1String(head);
if (!zero) {
return PyErr_Format(PyExc_TypeError, "http status string must be encodable in latin1");
}
status_line = PyBytes_AsString(zero);
status_line_len = PyBytes_Size(zero);
}
else {
status_line = PyBytes_AsString(head);
status_line_len = PyBytes_Size(head);
}
#else
status_line = PyString_AsString(head);
status_line_len = PyString_Size(head);
#endif
if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) {
#ifdef PYTHREE
Py_DECREF(zero);
#endif
goto end;
}
#ifdef PYTHREE
Py_DECREF(zero);
#endif
headers = PyTuple_GetItem(args, 1);
if (!headers) {
return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
}
if (!PyList_Check(headers)) {
return PyErr_Format(PyExc_TypeError, "http headers must be in a python list");
}
size_t h_count = PyList_Size(headers);
for (i = 0; i < h_count; i++) {
head = PyList_GetItem(headers, i);
if (!head) {
return NULL;
}
if (!PyTuple_Check(head)) {
return PyErr_Format(PyExc_TypeError, "http header must be defined in a tuple");
}
h_key = PyTuple_GetItem(head, 0);
if (!h_key) {
return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
}
#ifdef PYTHREE
if ((self != Py_None && !PyUnicode_Check(h_key)) || (self == Py_None && !PyBytes_Check(h_key))) {
#else
if (!PyString_Check(h_key)) {
#endif
return PyErr_Format(PyExc_TypeError, "http header key must be a string");
}
h_value = PyTuple_GetItem(head, 1);
if (!h_value) {
return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
}
#ifdef PYTHREE
if ((self != Py_None && !PyUnicode_Check(h_value)) || (self == Py_None && !PyBytes_Check(h_value))) {
#else
if (!PyString_Check(h_value)) {
#endif
return PyErr_Format(PyExc_TypeError, "http header value must be a string");
}
char *k = NULL; size_t kl = 0;
char *v = NULL; size_t vl = 0;
#ifdef PYTHREE
if (self != Py_None) {
zero = PyUnicode_AsLatin1String(h_key);
if (!zero) {
return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
}
k = PyBytes_AsString(zero);
kl = PyBytes_Size(zero);
}
else {
k = PyBytes_AsString(h_key);
kl = PyBytes_Size(h_key);
}
#else
k = PyString_AsString(h_key);
kl = PyString_Size(h_key);
#endif
#ifdef PYTHREE
if (self != Py_None) {
zero2 = PyUnicode_AsLatin1String(h_value);
if (!zero2) {
return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
}
v = PyBytes_AsString(zero2);
vl = PyBytes_Size(zero2);
}
else {
v = PyBytes_AsString(h_value);
vl = PyBytes_Size(h_value);
}
#else
v = PyString_AsString(h_value);
vl = PyString_Size(h_value);
#endif
if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) {
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
return PyErr_Format(PyExc_TypeError, "unable to add header to the response");
}
#ifdef PYTHREE
Py_DECREF(zero);
Py_DECREF(zero2);
#endif
}
if (up.start_response_nodelay) {
UWSGI_RELEASE_GIL
if (uwsgi_response_write_headers_do(wsgi_req)) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "unable to directly send headers");
}
UWSGI_GET_GIL
}
end:
Py_INCREF(up.wsgi_writeout);
return up.wsgi_writeout;
}