Add Content-Length, Last-Modified and ETag headers to FileResponse

This commit is contained in:
Tom Christie 2018-07-12 11:53:07 +01:00
parent 342a52f185
commit 14379e2240
2 changed files with 20 additions and 4 deletions

View File

@ -1,10 +1,13 @@
from aiofiles.os import stat as aio_stat
from email.utils import formatdate
from mimetypes import guess_type from mimetypes import guess_type
from starlette.datastructures import MutableHeaders from starlette.datastructures import MutableHeaders
from starlette.types import Receive, Send from starlette.types import Receive, Send
import aiofiles import aiofiles
import json import json
import hashlib
import stat
import typing import typing
import os
class Response: class Response:
@ -143,7 +146,18 @@ class FileResponse(Response):
content_disposition = 'attachment; filename="{}"'.format(self.filename) content_disposition = 'attachment; filename="{}"'.format(self.filename)
self.headers.setdefault("content-disposition", content_disposition) self.headers.setdefault("content-disposition", content_disposition)
def set_stat_headers(self, stat_result):
content_length = str(stat_result.st_size)
last_modified = formatdate(stat_result.st_mtime, usegmt=True)
etag_base = str(stat_result.st_mtime) + "-" + str(stat_result.st_size)
etag = hashlib.md5(etag_base.encode()).hexdigest()
self.headers.setdefault("content-length", content_length)
self.headers.setdefault("last-modified", last_modified)
self.headers.setdefault("etag", etag)
async def __call__(self, receive: Receive, send: Send) -> None: async def __call__(self, receive: Receive, send: Send) -> None:
stat_result = await aio_stat(self.path)
self.set_stat_headers(stat_result)
await send( await send(
{ {
"type": "http.response.start", "type": "http.response.start",

View File

@ -76,9 +76,11 @@ def test_file_response(tmpdir):
client = TestClient(app) client = TestClient(app)
response = client.get("/") response = client.get("/")
expected_disposition = 'attachment; filename="example.png"'
assert response.status_code == 200 assert response.status_code == 200
assert response.content == b"<file content>" assert response.content == b"<file content>"
assert response.headers["content-type"] == "image/png" assert response.headers["content-type"] == "image/png"
assert ( assert response.headers["content-disposition"] == expected_disposition
response.headers["content-disposition"] == 'attachment; filename="example.png"' assert "content-length" in response.headers
) assert "last-modified" in response.headers
assert "etag" in response.headers