#33738: ASGI http.disconnect not handled on requests with body.
------------------------------------------+------------------------
               Reporter:  Carlton Gibson  |          Owner:  nobody
                   Type:  New feature     |         Status:  new
              Component:  HTTP handling   |        Version:  4.0
               Severity:  Normal          |       Keywords:  ASGI
           Triage Stage:  Unreviewed      |      Has patch:  0
    Needs documentation:  0               |    Needs tests:  0
Patch needs improvement:  0               |  Easy pickings:  0
                  UI/UX:  0               |
------------------------------------------+------------------------
 Noticed whilst reviewing [https://github.com/django/django/pull/15704 PR
 15704] for #33699, we're not handling the ASGI `http.disconnect` message
 correctly. Since it's only dealt with whilst reading the request body,
 `http.disconnect` is not processed on a request that includes a body.

 
https://github.com/django/django/blob/241fe59b74bb6031fa644f3ad55e6ad6a9187510/django/core/handlers/asgi.py#L189

 {{{
     async def read_body(self, receive):
         """Reads an HTTP body from an ASGI connection."""
         # Use the tempfile that auto rolls-over to a disk file as it fills
 up.
         body_file = tempfile.SpooledTemporaryFile(
             max_size=settings.FILE_UPLOAD_MAX_MEMORY_SIZE, mode="w+b"
         )
         while True:
             message = await receive()
             if message["type"] == "http.disconnect":    # This is the only
 place `http.disconnect` is handled.
                 body_file.close()
                 # Early client disconnect.
                 raise RequestAborted()
             # Add a body chunk from the message, if provided.
             if "body" in message:
                 body_file.write(message["body"])
             # Quit out if that's the end.
             if not message.get("more_body", False):
                 break
         body_file.seek(0)
         return body_file
 }}}

 `http.disconnect` is designed for long-polling — so we imagine a client
 opening a request, with a request body, and then disconnecting before the
 response is generated.

 The protocol server (Daphne/uvicorn/...) will send the `http.diconnect`
 message, but it's not handled.

 This test fails on main (at 9f5548952906c6ea97200c016734b4f519520a64 — 4.2
 pre-alpha)

 {{{
 diff --git a/tests/asgi/tests.py b/tests/asgi/tests.py
 index ef7b55724e..a68ca8a473 100644
 --- a/tests/asgi/tests.py
 +++ b/tests/asgi/tests.py
 @@ -188,6 +188,18 @@ class ASGITest(SimpleTestCase):
          with self.assertRaises(asyncio.TimeoutError):
              await communicator.receive_output()

 +    async def test_disconnect_with_body(self):
 +        application = get_asgi_application()
 +        scope = self.async_request_factory._base_scope(path="/")
 +        communicator = ApplicationCommunicator(application, scope)
 +        await communicator.send_input({
 +            "type": "http.request",
 +            "body": b"some body",
 +        })
 +        await communicator.send_input({"type": "http.disconnect"})
 +        with self.assertRaises(asyncio.TimeoutError):
 +            await communicator.receive_output()
 +
      async def test_wrong_connection_type(self):
          application = get_asgi_application()
          scope = self.async_request_factory._base_scope(path="/",
 type="other")
 }}}


 To handle this correctly it looks like we'd need something like Channel's
 
[https://github.com/django/channels/blob/ae60a7d86f3655a1cc35cd9198e61fe5dcc5d1a1/channels/utils.py#L32
 `await_many_dispatch()`] to keep receiving from the input queue whilst
 dispatching the request. 🤔

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33738>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070180f50c3d9f-321e8423-08c6-4b6b-8a53-ea07aa1871e1-000000%40eu-central-1.amazonses.com.

Reply via email to