Fixed #31594 -- Added ASGIStaticFilesHandler.get_response_async().
This commit is contained in:
parent
4652f1f0aa
commit
92309e53d9
|
@ -1,6 +1,8 @@
|
|||
from urllib.parse import urlparse
|
||||
from urllib.request import url2pathname
|
||||
|
||||
from asgiref.sync import sync_to_async
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.staticfiles import utils
|
||||
from django.contrib.staticfiles.views import serve
|
||||
|
@ -52,6 +54,12 @@ class StaticFilesHandlerMixin:
|
|||
except Http404 as e:
|
||||
return response_for_exception(request, e)
|
||||
|
||||
async def get_response_async(self, request):
|
||||
try:
|
||||
return await sync_to_async(self.serve)(request)
|
||||
except Http404 as e:
|
||||
return await sync_to_async(response_for_exception)(request, e)
|
||||
|
||||
|
||||
class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -1,18 +1,25 @@
|
|||
import asyncio
|
||||
import sys
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from unittest import skipIf
|
||||
|
||||
from asgiref.sync import SyncToAsync
|
||||
from asgiref.testing import ApplicationCommunicator
|
||||
|
||||
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
|
||||
from django.core.asgi import get_asgi_application
|
||||
from django.core.signals import request_finished, request_started
|
||||
from django.db import close_old_connections
|
||||
from django.test import AsyncRequestFactory, SimpleTestCase, override_settings
|
||||
from django.test import (
|
||||
AsyncRequestFactory, SimpleTestCase, modify_settings, override_settings,
|
||||
)
|
||||
from django.utils.http import http_date
|
||||
|
||||
from .urls import test_filename
|
||||
|
||||
TEST_STATIC_ROOT = Path(__file__).parent / 'project' / 'static'
|
||||
|
||||
|
||||
@skipIf(sys.platform == 'win32' and (3, 8, 0) < sys.version_info < (3, 8, 1), 'https://bugs.python.org/issue38563')
|
||||
@override_settings(ROOT_URLCONF='asgi.urls')
|
||||
|
@ -79,6 +86,45 @@ class ASGITest(SimpleTestCase):
|
|||
# Allow response.close() to finish.
|
||||
await communicator.wait()
|
||||
|
||||
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.staticfiles'})
|
||||
@override_settings(
|
||||
STATIC_URL='/static/',
|
||||
STATIC_ROOT=TEST_STATIC_ROOT,
|
||||
STATICFILES_DIRS=[TEST_STATIC_ROOT],
|
||||
STATICFILES_FINDERS=[
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
],
|
||||
)
|
||||
async def test_static_file_response(self):
|
||||
application = ASGIStaticFilesHandler(get_asgi_application())
|
||||
# Construct HTTP request.
|
||||
scope = self.async_request_factory._base_scope(path='/static/file.txt')
|
||||
communicator = ApplicationCommunicator(application, scope)
|
||||
await communicator.send_input({'type': 'http.request'})
|
||||
# Get the file content.
|
||||
file_path = TEST_STATIC_ROOT / 'file.txt'
|
||||
with open(file_path, 'rb') as test_file:
|
||||
test_file_contents = test_file.read()
|
||||
# Read the response.
|
||||
stat = file_path.stat()
|
||||
response_start = await communicator.receive_output()
|
||||
self.assertEqual(response_start['type'], 'http.response.start')
|
||||
self.assertEqual(response_start['status'], 200)
|
||||
self.assertEqual(
|
||||
set(response_start['headers']),
|
||||
{
|
||||
(b'Content-Length', str(len(test_file_contents)).encode('ascii')),
|
||||
(b'Content-Type', b'text/plain'),
|
||||
(b'Content-Disposition', b'inline; filename="file.txt"'),
|
||||
(b'Last-Modified', http_date(stat.st_mtime).encode('ascii')),
|
||||
},
|
||||
)
|
||||
response_body = await communicator.receive_output()
|
||||
self.assertEqual(response_body['type'], 'http.response.body')
|
||||
self.assertEqual(response_body['body'], test_file_contents)
|
||||
# Allow response.close() to finish.
|
||||
await communicator.wait()
|
||||
|
||||
async def test_headers(self):
|
||||
application = get_asgi_application()
|
||||
communicator = ApplicationCommunicator(
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
|
||||
from django.core.handlers.asgi import ASGIHandler
|
||||
from django.test import AsyncRequestFactory
|
||||
|
||||
from .cases import StaticFilesTestCase
|
||||
|
||||
|
||||
class TestASGIStaticFilesHandler(StaticFilesTestCase):
|
||||
async_request_factory = AsyncRequestFactory()
|
||||
|
||||
async def test_get_async_response(self):
|
||||
request = self.async_request_factory.get('/static/test/file.txt')
|
||||
handler = ASGIStaticFilesHandler(ASGIHandler())
|
||||
response = await handler.get_response_async(request)
|
||||
response.close()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
async def test_get_async_response_not_found(self):
|
||||
request = self.async_request_factory.get('/static/test/not-found.txt')
|
||||
handler = ASGIStaticFilesHandler(ASGIHandler())
|
||||
response = await handler.get_response_async(request)
|
||||
self.assertEqual(response.status_code, 404)
|
Loading…
Reference in New Issue