1
0
mirror of https://github.com/django/django.git synced 2025-10-25 22:56:12 +00:00

Fixed #33738 -- Allowed handling ASGI http.disconnect in long-lived requests.

This commit is contained in:
th3nn3ss
2022-12-21 14:25:24 -05:00
committed by Mariusz Felisiak
parent 4e4eda6d6c
commit 1d1ddffc27
5 changed files with 157 additions and 3 deletions

View File

@@ -1,3 +1,4 @@
import asyncio
import logging
import sys
import tempfile
@@ -177,15 +178,49 @@ class ASGIHandler(base.BaseHandler):
body_file.close()
await self.send_response(error_response, send)
return
# Get the response, using the async mode of BaseHandler.
# Try to catch a disconnect while getting response.
tasks = [
asyncio.create_task(self.run_get_response(request)),
asyncio.create_task(self.listen_for_disconnect(receive)),
]
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
done, pending = done.pop(), pending.pop()
# Allow views to handle cancellation.
pending.cancel()
try:
await pending
except asyncio.CancelledError:
# Task re-raised the CancelledError as expected.
pass
try:
response = done.result()
except RequestAborted:
body_file.close()
return
except AssertionError:
body_file.close()
raise
# Send the response.
await self.send_response(response, send)
async def listen_for_disconnect(self, receive):
"""Listen for disconnect from the client."""
message = await receive()
if message["type"] == "http.disconnect":
raise RequestAborted()
# This should never happen.
assert False, "Invalid ASGI message after request body: %s" % message["type"]
async def run_get_response(self, request):
"""Get async response."""
# Use the async mode of BaseHandler.
response = await self.get_response_async(request)
response._handler_class = self.__class__
# Increase chunk size on file responses (ASGI servers handles low-level
# chunking).
if isinstance(response, FileResponse):
response.block_size = self.chunk_size
# Send the response.
await self.send_response(response, send)
return response
async def read_body(self, receive):
"""Reads an HTTP body from an ASGI connection."""