]> git.ipfire.org Git - thirdparty/starlette.git/commitdiff
Add content disposition type parameter to FileResponse (#1266)
authorqu1ck <anlutsenko@gmail.com>
Mon, 14 Feb 2022 16:08:28 +0000 (08:08 -0800)
committerGitHub <noreply@github.com>
Mon, 14 Feb 2022 16:08:28 +0000 (16:08 +0000)
disposition "attachment" causes browsers to download
the file. E.g. "inline" will will be attempted to be
displayed directly.

Co-authored-by: Tom Christie <tom@tomchristie.com>
docs/responses.md
starlette/responses.py
tests/test_responses.py

index 5284ac5044a8fae78a114ebc135e7fc29b725846..ce91f7ffabd031e75a1c0dc19d4ab0e41eff7eb8 100644 (file)
@@ -169,6 +169,7 @@ Takes a different set of arguments to instantiate than the other response types:
 * `headers` - Any custom headers to include, as a dictionary.
 * `media_type` - A string giving the media type. If unset, the filename or path will be used to infer a media type.
 * `filename` - If set, this will be included in the response `Content-Disposition`.
+* `content_disposition_type` - will be included in the response `Content-Disposition`. Can be set to "attachment" (default) or "inline".
 
 File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.
 
index 83e737a8200b3b28576a39c6497a2deed0f6d085..b33bdd7132114d27a645acdfeb5ff2fd25307305 100644 (file)
@@ -274,6 +274,7 @@ class FileResponse(Response):
         filename: str = None,
         stat_result: os.stat_result = None,
         method: str = None,
+        content_disposition_type: str = "attachment",
     ) -> None:
         self.path = path
         self.status_code = status_code
@@ -287,11 +288,13 @@ class FileResponse(Response):
         if self.filename is not None:
             content_disposition_filename = quote(self.filename)
             if content_disposition_filename != self.filename:
-                content_disposition = "attachment; filename*=utf-8''{}".format(
-                    content_disposition_filename
+                content_disposition = "{}; filename*=utf-8''{}".format(
+                    content_disposition_type, content_disposition_filename
                 )
             else:
-                content_disposition = f'attachment; filename="{self.filename}"'
+                content_disposition = '{}; filename="{}"'.format(
+                    content_disposition_type, self.filename
+                )
             self.headers.setdefault("content-disposition", content_disposition)
         self.stat_result = stat_result
         if stat_result is not None:
index 38aea57614ad2a14fec4bd4e22904cadec6842d1..a272559ebbccaa89215dd6b8790cafa46165c6a7 100644 (file)
@@ -273,6 +273,21 @@ def test_file_response_with_chinese_filename(tmpdir, test_client_factory):
     assert response.headers["content-disposition"] == expected_disposition
 
 
+def test_file_response_with_inline_disposition(tmpdir, test_client_factory):
+    content = b"file content"
+    filename = "hello.txt"
+    path = os.path.join(tmpdir, filename)
+    with open(path, "wb") as f:
+        f.write(content)
+    app = FileResponse(path=path, filename=filename, content_disposition_type="inline")
+    client = test_client_factory(app)
+    response = client.get("/")
+    expected_disposition = 'inline; filename="hello.txt"'
+    assert response.status_code == status.HTTP_200_OK
+    assert response.content == content
+    assert response.headers["content-disposition"] == expected_disposition
+
+
 def test_set_cookie(test_client_factory):
     async def app(scope, receive, send):
         response = Response("Hello, world!", media_type="text/plain")