Fixed #33754 -- Fixed crash with prematurely closed ASGI request body.

Regression in 441103a04d.
This commit is contained in:
Jonas Lundberg 2022-05-30 22:45:48 +02:00 committed by Mariusz Felisiak
parent 292f372768
commit f1e0fc645b
4 changed files with 26 additions and 6 deletions

View File

@ -490,6 +490,7 @@ answer newbie questions, and generally made Django that much better:
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com> Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
Jon Dufresne <jon.dufresne@gmail.com> Jon Dufresne <jon.dufresne@gmail.com>
Jonas Haag <jonas@lophus.org> Jonas Haag <jonas@lophus.org>
Jonas Lundberg <jonas.lundberg@gmail.com>
Jonathan Davis <jonathandavis47780@gmail.com> Jonathan Davis <jonathandavis47780@gmail.com>
Jonatas C. D. <jonatas.cd@gmail.com> Jonatas C. D. <jonatas.cd@gmail.com>
Jonathan Buchanan <jonathan.buchanan@gmail.com> Jonathan Buchanan <jonathan.buchanan@gmail.com>

View File

@ -171,14 +171,14 @@ class ASGIHandler(base.BaseHandler):
) )
# Get the request and check for basic issues. # Get the request and check for basic issues.
request, error_response = self.create_request(scope, body_file) request, error_response = self.create_request(scope, body_file)
finally:
body_file.close()
if request is None: if request is None:
await self.send_response(error_response, send) await self.send_response(error_response, send)
return return
# Get the response, using the async mode of BaseHandler. # Get the response, using the async mode of BaseHandler.
response = await self.get_response_async(request) response = await self.get_response_async(request)
response._handler_class = self.__class__ response._handler_class = self.__class__
finally:
body_file.close()
# Increase chunk size on file responses (ASGI servers handles low-level # Increase chunk size on file responses (ASGI servers handles low-level
# chunking). # chunking).
if isinstance(response, FileResponse): if isinstance(response, FileResponse):

View File

@ -163,6 +163,18 @@ class ASGITest(SimpleTestCase):
self.assertEqual(response_body["type"], "http.response.body") self.assertEqual(response_body["type"], "http.response.body")
self.assertEqual(response_body["body"], b"From Scotland,Wales") self.assertEqual(response_body["body"], b"From Scotland,Wales")
async def test_post_body(self):
application = get_asgi_application()
scope = self.async_request_factory._base_scope(method="POST", path="/post/")
communicator = ApplicationCommunicator(application, scope)
await communicator.send_input({"type": "http.request", "body": b"Echo!"})
response_start = await communicator.receive_output()
self.assertEqual(response_start["type"], "http.response.start")
self.assertEqual(response_start["status"], 200)
response_body = await communicator.receive_output()
self.assertEqual(response_body["type"], "http.response.body")
self.assertEqual(response_body["body"], b"Echo!")
async def test_get_query_string(self): async def test_get_query_string(self):
application = get_asgi_application() application = get_asgi_application()
for query_string in (b"name=Andrew", "name=Andrew"): for query_string in (b"name=Andrew", "name=Andrew"):

View File

@ -2,6 +2,7 @@ import threading
from django.http import FileResponse, HttpResponse from django.http import FileResponse, HttpResponse
from django.urls import path from django.urls import path
from django.views.decorators.csrf import csrf_exempt
def hello(request): def hello(request):
@ -23,6 +24,11 @@ def sync_waiter(request):
return hello(request) return hello(request)
@csrf_exempt
def post_echo(request):
return HttpResponse(request.body)
sync_waiter.active_threads = set() sync_waiter.active_threads = set()
sync_waiter.lock = threading.Lock() sync_waiter.lock = threading.Lock()
sync_waiter.barrier = threading.Barrier(2) sync_waiter.barrier = threading.Barrier(2)
@ -35,5 +41,6 @@ urlpatterns = [
path("", hello), path("", hello),
path("file/", lambda x: FileResponse(open(test_filename, "rb"))), path("file/", lambda x: FileResponse(open(test_filename, "rb"))),
path("meta/", hello_meta), path("meta/", hello_meta),
path("post/", post_echo),
path("wait/", sync_waiter), path("wait/", sync_waiter),
] ]