Sfoglia il codice sorgente

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

Regression in 441103a04d1d167dc870eaaf90e3fba974f67c93.
Jonas Lundberg 2 anni fa
parent
commit
f1e0fc645b
4 ha cambiato i file con 26 aggiunte e 6 eliminazioni
  1. 1 0
      AUTHORS
  2. 6 6
      django/core/handlers/asgi.py
  3. 12 0
      tests/asgi/tests.py
  4. 7 0
      tests/asgi/urls.py

+ 1 - 0
AUTHORS

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

+ 6 - 6
django/core/handlers/asgi.py

@@ -171,14 +171,14 @@ class ASGIHandler(base.BaseHandler):
             )
             # Get the request and check for basic issues.
             request, error_response = self.create_request(scope, body_file)
+            if request is None:
+                await self.send_response(error_response, send)
+                return
+            # Get the response, using the async mode of BaseHandler.
+            response = await self.get_response_async(request)
+            response._handler_class = self.__class__
         finally:
             body_file.close()
-        if request is None:
-            await self.send_response(error_response, send)
-            return
-        # Get the response, using 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):

+ 12 - 0
tests/asgi/tests.py

@@ -163,6 +163,18 @@ class ASGITest(SimpleTestCase):
         self.assertEqual(response_body["type"], "http.response.body")
         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):
         application = get_asgi_application()
         for query_string in (b"name=Andrew", "name=Andrew"):

+ 7 - 0
tests/asgi/urls.py

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