summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/changes.xml6
-rw-r--r--src/python/nxt_python_asgi_http.c31
-rw-r--r--test/python/body_bytearray/asgi.py20
-rw-r--r--test/test_asgi_application.py8
4 files changed, 53 insertions, 12 deletions
diff --git a/docs/changes.xml b/docs/changes.xml
index 833ec20e..ba41f00d 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -80,6 +80,12 @@ can be used as a unique request identifier.
<change type="feature">
<para>
+bytearray in response body for ASGI applications.
+</para>
+</change>
+
+<change type="feature">
+<para>
ServerRequest.flushHeaders() implemented in Node.js module to make it compatible
with Next.js.
</para>
diff --git a/src/python/nxt_python_asgi_http.c b/src/python/nxt_python_asgi_http.c
index 05c0da4f..cdd6357e 100644
--- a/src/python/nxt_python_asgi_http.c
+++ b/src/python/nxt_python_asgi_http.c
@@ -362,16 +362,6 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
Py_ssize_t body_len, body_off;
nxt_py_asgi_ctx_data_t *ctx_data;
- body = PyDict_GetItem(dict, nxt_py_body_str);
- if (nxt_slow_path(body != NULL && !PyBytes_Check(body))) {
- return PyErr_Format(PyExc_TypeError, "'body' is not a byte string");
- }
-
- more_body = PyDict_GetItem(dict, nxt_py_more_body_str);
- if (nxt_slow_path(more_body != NULL && !PyBool_Check(more_body))) {
- return PyErr_Format(PyExc_TypeError, "'more_body' is not a bool");
- }
-
if (nxt_slow_path(http->complete)) {
return PyErr_Format(PyExc_RuntimeError,
"Unexpected ASGI message 'http.response.body' "
@@ -382,9 +372,26 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
return PyErr_Format(PyExc_RuntimeError, "Concurrent send");
}
+ more_body = PyDict_GetItem(dict, nxt_py_more_body_str);
+ if (nxt_slow_path(more_body != NULL && !PyBool_Check(more_body))) {
+ return PyErr_Format(PyExc_TypeError, "'more_body' is not a bool");
+ }
+
+ body = PyDict_GetItem(dict, nxt_py_body_str);
+
if (body != NULL) {
- body_str = PyBytes_AS_STRING(body);
- body_len = PyBytes_GET_SIZE(body);
+ if (PyBytes_Check(body)) {
+ body_str = PyBytes_AS_STRING(body);
+ body_len = PyBytes_GET_SIZE(body);
+
+ } else if (PyByteArray_Check(body)) {
+ body_str = PyByteArray_AS_STRING(body);
+ body_len = PyByteArray_GET_SIZE(body);
+
+ } else {
+ return PyErr_Format(PyExc_TypeError,
+ "'body' is not a byte string or bytearray");
+ }
nxt_unit_req_debug(http->req, "asgi_http_response_body: %d, %d",
(int) body_len, (more_body == Py_True) );
diff --git a/test/python/body_bytearray/asgi.py b/test/python/body_bytearray/asgi.py
new file mode 100644
index 00000000..6d2f402f
--- /dev/null
+++ b/test/python/body_bytearray/asgi.py
@@ -0,0 +1,20 @@
+async def application(scope, receive, send):
+ assert scope['type'] == 'http'
+
+ body = b''
+ while True:
+ m = await receive()
+ body += m.get('body', b'')
+ if not m.get('more_body', False):
+ body = bytearray(body)
+ break
+
+ await send(
+ {
+ 'type': 'http.response.start',
+ 'status': 200,
+ 'headers': [(b'content-length', str(len(body)).encode())],
+ }
+ )
+
+ await send({'type': 'http.response.body', 'body': body})
diff --git a/test/test_asgi_application.py b/test/test_asgi_application.py
index e6668b2f..226a1ed7 100644
--- a/test/test_asgi_application.py
+++ b/test/test_asgi_application.py
@@ -218,6 +218,14 @@ def test_asgi_application_shm_ack_handle():
assert resp['body'] == body, 'keep-alive 1'
+def test_asgi_application_body_bytearray():
+ client.load('body_bytearray')
+
+ body = '0123456789'
+
+ assert client.post(body=body)['body'] == body
+
+
def test_asgi_keepalive_body():
client.load('mirror')