1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
#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;
}
|