diff --git a/docs/responses.md b/docs/responses.md index 5284ac504..ce91f7ffa 100644 --- a/docs/responses.md +++ b/docs/responses.md @@ -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. diff --git a/starlette/responses.py b/starlette/responses.py index 83e737a82..b33bdd713 100644 --- a/starlette/responses.py +++ b/starlette/responses.py @@ -274,6 +274,7 @@ def __init__( 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 @@ def __init__( 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: diff --git a/tests/test_responses.py b/tests/test_responses.py index 38aea5761..a272559eb 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -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")