Skip to content

Commit

Permalink
Python: bytearray body support for ASGI module.
Browse files Browse the repository at this point in the history
@filiphanes requested support for bytearray
and memoryview in the request body here:
nginx#648

This patch implements bytearray body support only.
Memoryview body still need to be implemented.
  • Loading branch information
andrey-zelenkov committed Jan 30, 2024
1 parent 990fbe7 commit 69107e6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 12 deletions.
6 changes: 6 additions & 0 deletions docs/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ can be used as a unique request identifier.
</para>
</change>

<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
Expand Down
31 changes: 19 additions & 12 deletions src/python/nxt_python_asgi_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -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' "
Expand All @@ -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) );
Expand Down
20 changes: 20 additions & 0 deletions test/python/body_bytearray/asgi.py
Original file line number Diff line number Diff line change
@@ -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})
8 changes: 8 additions & 0 deletions test/test_asgi_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down

0 comments on commit 69107e6

Please sign in to comment.