]> git.ipfire.org Git - thirdparty/starlette.git/commitdiff
Add Content-Length, Last-Modified and ETag headers to FileResponse 19/head
authorTom Christie <tom@tomchristie.com>
Thu, 12 Jul 2018 10:53:07 +0000 (11:53 +0100)
committerTom Christie <tom@tomchristie.com>
Thu, 12 Jul 2018 10:53:07 +0000 (11:53 +0100)
starlette/response.py
tests/test_response.py

index c3c98197b67445198b139e81c2e38f22d0248a06..d3294713d305e0953edff5b9f31f93577cb3eaa7 100644 (file)
@@ -1,10 +1,13 @@
+from aiofiles.os import stat as aio_stat
+from email.utils import formatdate
 from mimetypes import guess_type
 from starlette.datastructures import MutableHeaders
 from starlette.types import Receive, Send
 import aiofiles
 import json
+import hashlib
+import stat
 import typing
-import os
 
 
 class Response:
@@ -143,7 +146,18 @@ class FileResponse(Response):
             content_disposition = 'attachment; filename="{}"'.format(self.filename)
             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:
+        stat_result = await aio_stat(self.path)
+        self.set_stat_headers(stat_result)
         await send(
             {
                 "type": "http.response.start",
index d4850fc8b3b636f82378e3ec9987db71ec90a857..c22602b0aa1ecd1846fe9d034b0942b24c827d80 100644 (file)
@@ -76,9 +76,11 @@ def test_file_response(tmpdir):
 
     client = TestClient(app)
     response = client.get("/")
+    expected_disposition = 'attachment; filename="example.png"'
     assert response.status_code == 200
     assert response.content == b"<file content>"
     assert response.headers["content-type"] == "image/png"
-    assert (
-        response.headers["content-disposition"] == 'attachment; filename="example.png"'
-    )
+    assert response.headers["content-disposition"] == expected_disposition
+    assert "content-length" in response.headers
+    assert "last-modified" in response.headers
+    assert "etag" in response.headers