-
Notifications
You must be signed in to change notification settings - Fork 339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Django ASGI: Invalid ASGI message after request body: http.request #1561
Comments
I also asked Django forum regarding this issue and this is a probable cause proposed by carltongibson: This looks like Unit isn’t correctly handling the more_body key of the http.request event. |
Hi, thanks for the report. Managed to get your app (thanks for that!) running without docker, but it seems to be working fine. $ curl -X PUT localhost:8000 -d test
ok
$ curl -X POST localhost:8000 -d test
ok Using current Unit Python is 3.9.21 under RHEL 9. Django is 4.2.19 installed via pip |
Please try using Django version equal to or higher than 5.0 or with provided docker, I'm using I also updated demo project to require django>=5 I don't know what else I might be missing. I purposefully created this because I have the same exact problem in one production project which is now switched to different app server. :( |
Works under Fedora 41 with Python 3.13.2 and Django 4.2.16 (Unit master) I'll see if I can try Django 5.x |
OK, reproduced the issue with Django 5.1.6 |
I am also seeing this error (with both Django 4.x and 5.x)
Though it doesn't seem to prevent things from working (with Django 4.x anyway) Looking at the function call graph with Django 4.x we get
We call With Django 5.x we see
After calling This decision to call While we don't explicitly set This works with Django 4.x so something has obviously changed in 5.x. Looking at the commit log this looks a likely suspect, though I wonder if there more going on as if I comment out the |
If I hack diff --git ./django/core/handlers/asgi.py ./django/core/handlers/asgi.py
index bb6a6bfb3c..81e70567bd 100644
--- ./django/core/handlers/asgi.py
+++ ./django/core/handlers/asgi.py
@@ -198,7 +198,6 @@ class ASGIHandler(base.BaseHandler):
# because it should not raise unexpected errors that would prevent
# us from cancelling process_request().
- asyncio.create_task(self.listen_for_disconnect(receive)),
asyncio.create_task(process_request(request, send)),
]
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
# Now wait on both tasks (they may have both finished by now).
@@ -222,7 +221,7 @@ class ASGIHandler(base.BaseHandler):
pass
try:
- response = tasks[1].result()
+ response = tasks[0].result()
except asyncio.CancelledError:
await signals.request_finished.asend(sender=self.__class__)
else: Things work as expected $ curl -X POST -d test localhost:8000
ok
|
In my debugging (mostly printing results) I noticed that last message from I would assume that this doesn't get called: |
This is completely fine: ValueError: Django can only handle ASGI/HTTP connections, not lifespan. The main thing that is changed is now waiting for http.disconnect I guess. |
So it comes down to the fact that But of course there is no request data to read from the client, there is no message that needs to be sent to the application, we simply want to fall through to the end of index cdd6357e..e703c662 100644
--- ./src/python/nxt_python_asgi_http.c
+++ ./src/python/nxt_python_asgi_http.c
@@ -177,6 +192,8 @@ nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http)
}
if (size == 0) {
+ Py_RETURN_NONE;
+
if (http->empty_body_received) {
Py_RETURN_NONE;
} While that fixes the |
Whether or not this is the right way to fix it, things seem to work... (ASGI and Python pytrests pass) diff --git ./src/python/nxt_python_asgi_http.c ./src/python/nxt_python_asgi_http.c
index cdd6357e..79f387e3 100644
--- ./src/python/nxt_python_asgi_http.c
+++ ./src/python/nxt_python_asgi_http.c
@@ -28,6 +28,7 @@ typedef struct {
uint8_t complete;
uint8_t closed;
uint8_t empty_body_received;
+ uint8_t request_received;
} nxt_py_asgi_http_t;
@@ -103,6 +104,7 @@ nxt_py_asgi_http_create(nxt_unit_request_info_t *req)
http->complete = 0;
http->closed = 0;
http->empty_body_received = 0;
+ http->request_received = 0;
}
return (PyObject *) http;
@@ -177,7 +179,7 @@ nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http)
}
if (size == 0) {
- if (http->empty_body_received) {
+ if (http->request_received || http->empty_body_received) {
Py_RETURN_NONE;
}
@@ -234,6 +236,8 @@ nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http)
Py_XDECREF(body);
+ http->request_received = 1;
+
return msg;
}
|
Thank you for putting effort into this and quickly getting into the issue. Also I'm very happy with entire Unit project so far and want to thank the entire team. Best. |
That's the fix merged to Unit master. Thanks for your help in debugging this. |
Bug Overview
This is the regular django ASGI app with simple function based view.
If I try to send POST/PUT with body I will get this exception and 503 response:
This is the repo with example project:
https://github.com/codedoga/nginx_unit_asgi_django
Expected Behavior
The same code works perfectly well with uvicorn and granian so I would expect it to also work with Unit
Steps to Reproduce the Bug
Environment Details
Additional Context
Debug log:
The text was updated successfully, but these errors were encountered: