diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c index 78cd0249..90cd2301 100644 --- a/plugins/python/python_plugin.c +++ b/plugins/python/python_plugin.c @@ -156,7 +156,8 @@ struct uwsgi_option uwsgi_python_options[] = { {"wsgi-env-behavior", required_argument, 0, "set the strategy for allocating/deallocating the WSGI env", uwsgi_opt_set_str, &up.wsgi_env_behaviour, 0}, {"start_response-nodelay", no_argument, 0, "send WSGI http headers as soon as possible (PEP violation)", uwsgi_opt_true, &up.start_response_nodelay, 0}, - {"wsgi-strict", no_argument, 0, "expect the WSGI callable to return ONLY strings (python 2.x) or bytes (python 3.x), and disable non-iterable optimizations", uwsgi_opt_true, &up.wsgi_strict, 0}, + {"wsgi-strict", no_argument, 0, "try to be fully PEP compliant disabling optimizations", uwsgi_opt_true, &up.wsgi_strict, 0}, + {"wsgi-accept-buffer", no_argument, 0, "accept CPython buffer-compliant objects as WSGI response in addition to string/bytes", uwsgi_opt_true, &up.wsgi_accept_buffer, 0}, {"python-version", no_argument, 0, "report python version", uwsgi_opt_pyver, NULL, UWSGI_OPT_IMMEDIATE}, diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h index c2bc24a6..fdf8e97e 100644 --- a/plugins/python/uwsgi_python.h +++ b/plugins/python/uwsgi_python.h @@ -181,6 +181,7 @@ struct uwsgi_python { char *programname; int wsgi_strict; + int wsgi_accept_buffer; char *raw; PyObject *raw_callable; diff --git a/plugins/python/wsgi_subhandler.c b/plugins/python/wsgi_subhandler.c index 5264d671..e1486994 100644 --- a/plugins/python/wsgi_subhandler.c +++ b/plugins/python/wsgi_subhandler.c @@ -8,39 +8,42 @@ extern PyTypeObject uwsgi_InputType; /* Albeit PEP 333/3333 is clear about what kind of return object we must - expect from a WSGI callable, we use the buffer api to optimize for lower-level + expect from a WSGI callable, we CAN use the buffer api to optimize for lower-level returns type: bytes, bytearray, array.array - the "strict" behaviour can be forced with --wsgi-strict + to enable this optimization add --wsgi-accept-buffer + + NOTE: this is a violation of the standards !!! use only if you know the implications !!! */ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) { + if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) Py_buffer pbuf; int has_buffer = 0; #endif char *content = NULL; size_t content_len = 0; - if (!up.wsgi_strict) { #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) - if (PyObject_CheckBuffer(chunk)) { - if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) { - content = (char *) pbuf.buf; - content_len = (size_t) pbuf.len; - has_buffer = 1; - goto found; - } + if (PyObject_CheckBuffer(chunk)) { + if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) { + content = (char *) pbuf.buf; + content_len = (size_t) pbuf.len; + has_buffer = 1; + goto found; } -#else - if (PyObject_CheckReadBuffer(chunk)) { - if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) { - PyErr_Clear(); - goto found; - } - } -#endif } +#else + if (PyObject_CheckReadBuffer(chunk)) { + if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) { + PyErr_Clear(); + goto found; + } + } +#endif + +strict: // fallback if (PyString_Check(chunk)) { content = PyString_AsString(chunk);