Skip to content

Commit

Permalink
customizable block_size
Browse files Browse the repository at this point in the history
  • Loading branch information
Archmonger committed Jul 21, 2023
1 parent 68f19c2 commit 00f064d
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/whitenoise/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async def __call__(self, scope, receive, send):


class AsgiFileServer:
"""Simple ASGI application that streams a single static file over HTTP."""
"""Simple ASGI application that streams a StaticFile over HTTP."""

def __init__(self, static_file: StaticFile, block_size: int = DEFAULT_BLOCK_SIZE):
self.block_size = block_size
Expand Down
26 changes: 19 additions & 7 deletions src/whitenoise/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ class WhiteNoiseFileResponse(FileResponse):
"""
Wrapper for Django's FileResponse that has a few differences:
- Prevents Django response headers since they are already generated by WhiteNoise.
- Only generates responses for async file handles.
- Only generates responses for async file handles.
- Provides Django an asynchronous iterator for more efficient file streaming.
- Requires a block_size argument to determine the size of iterator chunks.
"""

def __init__(self, *args, block_size: int = DEFAULT_BLOCK_SIZE, **kwargs):
self.block_size = block_size
super().__init__(*args, **kwargs)

def _set_streaming_content(self, value):
# Make sure the value is an async file handle
if not hasattr(value, "read") and not asyncio.iscoroutinefunction(value.read):
Expand All @@ -38,7 +43,7 @@ def _set_streaming_content(self, value):
self.file_to_stream = value
if hasattr(value, "close"):
self._resource_closers.append(value.close)
super()._set_streaming_content(AsyncFileIterator(value))
super()._set_streaming_content(AsyncFileIterator(value, self.block_size))


class WhiteNoiseMiddleware(WhiteNoise):
Expand Down Expand Up @@ -132,6 +137,11 @@ def __init__(self, get_response=None, settings=settings):
if self.use_finders and not self.autorefresh:
self.add_files_from_finders()

try:
self.block_size: int = settings.WHITENOISE_BLOCK_SIZE
except AttributeError:
self.block_size = DEFAULT_BLOCK_SIZE

async def __call__(self, request):
if self.autorefresh:
static_file = await asyncio.to_thread(self.find_file, request.path_info)
Expand All @@ -141,11 +151,12 @@ async def __call__(self, request):
return await self.serve(static_file, request)
return await self.get_response(request)

@staticmethod
async def serve(static_file: StaticFile, request):
async def serve(self, static_file: StaticFile, request):
response = await static_file.aget_response(request.method, request.META)
status = int(response.status)
http_response = WhiteNoiseFileResponse(response.file or (), status=status)
http_response = WhiteNoiseFileResponse(
response.file or (), block_size=self.block_size, status=status
)
# Remove default content-type
del http_response["content-type"]
for key, value in response.headers:
Expand Down Expand Up @@ -224,12 +235,13 @@ class AsyncFileIterator:
"""Async iterator compatible with Django Middleware.
Yields chunks of data from the provided aiofile object."""

def __init__(self, aiofile):
def __init__(self, aiofile, block_size: int = DEFAULT_BLOCK_SIZE):
self.aiofile = aiofile
self.block_size = block_size

async def __aiter__(self):
while True:
chunk = await self.aiofile.read(DEFAULT_BLOCK_SIZE)
chunk = await self.aiofile.read(self.block_size)
if not chunk:
break
yield chunk

0 comments on commit 00f064d

Please sign in to comment.