mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-09-05 21:21:53 +00:00
better implementation of start_response()
This commit is contained in:
@@ -127,6 +127,8 @@ struct uwsgi_option uwsgi_python_options[] = {
|
||||
{"py-auto-reload-ignore", required_argument, 0, "ignore the specified module during auto-reload scan (can be specified multiple times)", uwsgi_opt_add_string_list, &up.auto_reload_ignore, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
|
||||
#endif
|
||||
|
||||
{"start_response-nodelay", no_argument, 0, "send WSGI http headers as soon as possible (PEP violation)", uwsgi_opt_true, &up.start_response_nodelay, 0},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
@@ -178,6 +178,7 @@ struct uwsgi_python {
|
||||
PyObject *after_req_hook_args;
|
||||
|
||||
char *pyrun;
|
||||
int start_response_nodelay;
|
||||
|
||||
};
|
||||
|
||||
@@ -266,6 +267,7 @@ char *uwsgi_pythonize(char *);
|
||||
void *uwsgi_python_autoreloader_thread(void *);
|
||||
|
||||
int uwsgi_python_manage_exceptions(void);
|
||||
int uwsgi_python_do_send_headers(struct wsgi_request *);
|
||||
|
||||
#ifdef UWSGI_PYPY
|
||||
#undef UWSGI_MINTERPRETERS
|
||||
|
||||
@@ -267,16 +267,21 @@ PyTypeObject uwsgi_InputType = {
|
||||
PyObject *py_uwsgi_write(PyObject * self, PyObject * args) {
|
||||
PyObject *data;
|
||||
char *content;
|
||||
int len;
|
||||
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);
|
||||
len = PyString_Size(data);
|
||||
content_len = PyString_Size(data);
|
||||
if (content_len > 0 && !wsgi_req->headers_sent) {
|
||||
if (uwsgi_python_do_send_headers(wsgi_req)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req, content, len);
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(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
|
||||
|
||||
@@ -19,6 +19,11 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
|
||||
int base = 0;
|
||||
|
||||
// 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);
|
||||
@@ -45,7 +50,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
|
||||
head = PyTuple_GetItem(args, 0);
|
||||
if (!head) {
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
|
||||
}
|
||||
|
||||
#ifdef PYTHREE
|
||||
@@ -53,8 +58,7 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
#else
|
||||
if (!PyString_Check(head)) {
|
||||
#endif
|
||||
uwsgi_log( "http status must be a string !\n");
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "http status must be a string");
|
||||
}
|
||||
|
||||
|
||||
@@ -101,12 +105,13 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
}
|
||||
|
||||
headers = PyTuple_GetItem(args, 1);
|
||||
if (!headers) goto clear;
|
||||
if (!headers) {
|
||||
return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
|
||||
}
|
||||
|
||||
|
||||
if (!PyList_Check(headers)) {
|
||||
uwsgi_log( "http headers must be in a python list\n");
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "http headers must be in a python list");
|
||||
}
|
||||
wsgi_req->header_cnt = PyList_Size(headers);
|
||||
|
||||
@@ -117,20 +122,36 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
j = (i * 4) + base;
|
||||
head = PyList_GetItem(headers, i);
|
||||
if (!head) {
|
||||
PyErr_Print();
|
||||
goto clear;
|
||||
}
|
||||
if (!PyTuple_Check(head)) {
|
||||
uwsgi_log( "http header must be defined in a tuple !\n");
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "http header must be defined in a tuple");
|
||||
}
|
||||
h_key = PyTuple_GetItem(head, 0);
|
||||
if (!h_key) {
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
|
||||
}
|
||||
#ifdef PYTHREE
|
||||
if (!PyUnicode_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) {
|
||||
goto clear;
|
||||
return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
|
||||
}
|
||||
#ifdef PYTHREE
|
||||
if (!PyUnicode_Check(h_value)) {
|
||||
#else
|
||||
if (!PyString_Check(h_value)) {
|
||||
#endif
|
||||
return PyErr_Format(PyExc_TypeError, "http header value must be a string");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef PYTHREE
|
||||
wsgi_req->hvec[j].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_key));
|
||||
@@ -181,30 +202,13 @@ PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
|
||||
wsgi_req->hvec[j].iov_base = nl;
|
||||
wsgi_req->hvec[j].iov_len = NL_SIZE;
|
||||
|
||||
#ifdef __sun__
|
||||
int remains = j + 1;
|
||||
int iov_size;
|
||||
struct iovec* iov_ptr = wsgi_req->hvec;
|
||||
ssize_t iov_ret;
|
||||
while(remains) {
|
||||
iov_size = UMIN(remains, IOV_MAX);
|
||||
UWSGI_RELEASE_GIL
|
||||
iov_ret = wsgi_req->socket->proto_writev_header(wsgi_req, iov_ptr, iov_size);
|
||||
UWSGI_GET_GIL
|
||||
wsgi_req->headers_size += iov_ret;
|
||||
iov_ptr += iov_size;
|
||||
remains -= iov_size;
|
||||
}
|
||||
#else
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, j + 1);
|
||||
UWSGI_GET_GIL
|
||||
#endif
|
||||
wsgi_req->headers_hvec = j;
|
||||
|
||||
if (wsgi_req->write_errors > uwsgi.write_errors_tolerance) {
|
||||
uwsgi_py_write_set_exception(wsgi_req);
|
||||
return NULL;
|
||||
}
|
||||
if (up.start_response_nodelay) {
|
||||
if (uwsgi_python_do_send_headers(wsgi_req)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//uwsgi_log("%d %p\n", wsgi_req->poll.fd, up.wsgi_writeout);
|
||||
Py_INCREF(up.wsgi_writeout);
|
||||
@@ -216,3 +220,36 @@ clear:
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
int uwsgi_python_do_send_headers(struct wsgi_request *wsgi_req) {
|
||||
|
||||
#ifdef __sun__
|
||||
int remains = wsgi_req->headers_hvec + 1;
|
||||
int iov_size;
|
||||
struct iovec* iov_ptr = wsgi_req->hvec;
|
||||
ssize_t iov_ret;
|
||||
while(remains) {
|
||||
iov_size = UMIN(remains, IOV_MAX);
|
||||
UWSGI_RELEASE_GIL
|
||||
iov_ret = wsgi_req->socket->proto_writev_header(wsgi_req, iov_ptr, iov_size);
|
||||
UWSGI_GET_GIL
|
||||
wsgi_req->headers_size += iov_ret;
|
||||
iov_ptr += iov_size;
|
||||
remains -= iov_size;
|
||||
}
|
||||
#else
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, wsgi_req->hvec, wsgi_req->headers_hvec + 1);
|
||||
UWSGI_GET_GIL
|
||||
#endif
|
||||
|
||||
wsgi_req->headers_sent = 1;
|
||||
|
||||
if (wsgi_req->write_errors > uwsgi.write_errors_tolerance) {
|
||||
uwsgi_py_write_set_exception(wsgi_req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -166,6 +166,11 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
|
||||
if (PyString_Check((PyObject *)wsgi_req->async_result)) {
|
||||
char *content = PyString_AsString(wsgi_req->async_result);
|
||||
size_t content_len = PyString_Size(wsgi_req->async_result);
|
||||
if (content_len > 0 && !wsgi_req->headers_sent) {
|
||||
if (uwsgi_python_do_send_headers(wsgi_req)) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len);
|
||||
UWSGI_GET_GIL
|
||||
@@ -252,6 +257,11 @@ int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) {
|
||||
if (PyString_Check(pychunk)) {
|
||||
char *content = PyString_AsString(pychunk);
|
||||
size_t content_len = PyString_Size(pychunk);
|
||||
if (content_len > 0 && !wsgi_req->headers_sent) {
|
||||
if (uwsgi_python_do_send_headers(wsgi_req)) {
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
UWSGI_RELEASE_GIL
|
||||
wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, content, content_len);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
Reference in New Issue
Block a user