mirror of https://github.com/encode/starlette.git
Add Content-Length, Last-Modified and ETag headers to FileResponse
This commit is contained in:
parent
342a52f185
commit
14379e2240
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue