mirror of
https://github.com/django/django.git
synced 2025-11-19 19:24:46 +00:00
Refs #36315 -- Used contextlib.closing() in ASGIHandler.handle().
This commit is contained in:
parent
5ef870fbc5
commit
796cf3d325
1 changed files with 53 additions and 53 deletions
|
|
@ -3,7 +3,7 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
from contextlib import aclosing
|
from contextlib import aclosing, closing
|
||||||
|
|
||||||
from asgiref.sync import ThreadSensitiveContext, sync_to_async
|
from asgiref.sync import ThreadSensitiveContext, sync_to_async
|
||||||
|
|
||||||
|
|
@ -174,65 +174,65 @@ class ASGIHandler(base.BaseHandler):
|
||||||
body_file = await self.read_body(receive)
|
body_file = await self.read_body(receive)
|
||||||
except RequestAborted:
|
except RequestAborted:
|
||||||
return
|
return
|
||||||
# Request is complete and can be served.
|
|
||||||
set_script_prefix(get_script_prefix(scope))
|
|
||||||
await signals.request_started.asend(sender=self.__class__, scope=scope)
|
|
||||||
# Get the request and check for basic issues.
|
|
||||||
request, error_response = self.create_request(scope, body_file)
|
|
||||||
if request is None:
|
|
||||||
body_file.close()
|
|
||||||
await self.send_response(error_response, send)
|
|
||||||
await sync_to_async(error_response.close)()
|
|
||||||
return
|
|
||||||
|
|
||||||
async def process_request(request, send):
|
with closing(body_file):
|
||||||
response = await self.run_get_response(request)
|
# Request is complete and can be served.
|
||||||
try:
|
set_script_prefix(get_script_prefix(scope))
|
||||||
await self.send_response(response, send)
|
await signals.request_started.asend(sender=self.__class__, scope=scope)
|
||||||
except asyncio.CancelledError:
|
# Get the request and check for basic issues.
|
||||||
# Client disconnected during send_response (ignore exception).
|
request, error_response = self.create_request(scope, body_file)
|
||||||
pass
|
if request is None:
|
||||||
|
body_file.close()
|
||||||
|
await self.send_response(error_response, send)
|
||||||
|
await sync_to_async(error_response.close)()
|
||||||
|
return
|
||||||
|
|
||||||
return response
|
async def process_request(request, send):
|
||||||
|
response = await self.run_get_response(request)
|
||||||
# Try to catch a disconnect while getting response.
|
|
||||||
tasks = [
|
|
||||||
# Check the status of these tasks and (optionally) terminate them
|
|
||||||
# in this order. The listen_for_disconnect() task goes first
|
|
||||||
# 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).
|
|
||||||
for task in tasks:
|
|
||||||
if task.done():
|
|
||||||
try:
|
try:
|
||||||
task.result()
|
await self.send_response(response, send)
|
||||||
except RequestAborted:
|
|
||||||
# Ignore client disconnects.
|
|
||||||
pass
|
|
||||||
except AssertionError:
|
|
||||||
body_file.close()
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
# Allow views to handle cancellation.
|
|
||||||
task.cancel()
|
|
||||||
try:
|
|
||||||
await task
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
# Task re-raised the CancelledError as expected.
|
# Client disconnected during send_response (ignore exception).
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
return response
|
||||||
response = tasks[1].result()
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
await signals.request_finished.asend(sender=self.__class__)
|
|
||||||
else:
|
|
||||||
await sync_to_async(response.close)()
|
|
||||||
|
|
||||||
body_file.close()
|
# Try to catch a disconnect while getting response.
|
||||||
|
tasks = [
|
||||||
|
# Check the status of these tasks and (optionally) terminate them
|
||||||
|
# in this order. The listen_for_disconnect() task goes first
|
||||||
|
# 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).
|
||||||
|
for task in tasks:
|
||||||
|
if task.done():
|
||||||
|
try:
|
||||||
|
task.result()
|
||||||
|
except RequestAborted:
|
||||||
|
# Ignore client disconnects.
|
||||||
|
pass
|
||||||
|
except AssertionError:
|
||||||
|
body_file.close()
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# Allow views to handle cancellation.
|
||||||
|
task.cancel()
|
||||||
|
try:
|
||||||
|
await task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
# Task re-raised the CancelledError as expected.
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = tasks[1].result()
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
await signals.request_finished.asend(sender=self.__class__)
|
||||||
|
else:
|
||||||
|
await sync_to_async(response.close)()
|
||||||
|
|
||||||
async def listen_for_disconnect(self, receive):
|
async def listen_for_disconnect(self, receive):
|
||||||
"""Listen for disconnect from the client."""
|
"""Listen for disconnect from the client."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue