From c422ff3f3da1b73c498f1c0a934b327874ceacc6 Mon Sep 17 00:00:00 2001 From: Ben Timby Date: Fri, 27 Sep 2019 14:55:50 -0400 Subject: [PATCH] Allow caller to control HTTP status when using FileResponse (#4107) --- CHANGES/4106.bugfix | 1 + CONTRIBUTORS.txt | 1 + aiohttp/web_fileresponse.py | 5 ++--- tests/test_web_sendfile.py | 20 ++++++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 CHANGES/4106.bugfix diff --git a/CHANGES/4106.bugfix b/CHANGES/4106.bugfix new file mode 100644 index 00000000000..26bf89bba28 --- /dev/null +++ b/CHANGES/4106.bugfix @@ -0,0 +1 @@ +Don't clobber HTTP status when using FileResponse. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 8b8594bd774..d126b74eb47 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -42,6 +42,7 @@ Anton Zhdan-Pushkin Artem Yushkovskiy Arthur Darcet Ben Bader +Ben Timby Benedikt Reinartz Boris Feld Boyi Chen diff --git a/aiohttp/web_fileresponse.py b/aiohttp/web_fileresponse.py index d7012d425f9..c6968ccab72 100644 --- a/aiohttp/web_fileresponse.py +++ b/aiohttp/web_fileresponse.py @@ -24,7 +24,6 @@ from .typedefs import LooseHeaders from .web_exceptions import ( HTTPNotModified, - HTTPOk, HTTPPartialContent, HTTPPreconditionFailed, HTTPRequestRangeNotSatisfiable, @@ -245,7 +244,7 @@ async def prepare( encoding = 'gzip' if gzip else None should_set_ct = False - status = HTTPOk.status_code + status = self._status file_size = st.st_size count = file_size @@ -318,8 +317,8 @@ async def prepare( status = HTTPPartialContent.status_code # Even though you are sending the whole file, you should still # return a HTTP 206 for a Range request. + self.set_status(status) - self.set_status(status) if should_set_ct: self.content_type = ct # type: ignore if encoding: diff --git a/tests/test_web_sendfile.py b/tests/test_web_sendfile.py index f0849f15c8a..115a9007028 100644 --- a/tests/test_web_sendfile.py +++ b/tests/test_web_sendfile.py @@ -109,3 +109,23 @@ def test_gzip_if_header_present_and_file_not_available(loop) -> None: assert filepath.open.called assert not gz_filepath.open.called + + +def test_status_controlled_by_user(loop) -> None: + request = make_mocked_request( + 'GET', 'http://python.org/logo.png', headers={ + } + ) + + filepath = mock.Mock() + filepath.name = 'logo.png' + filepath.open = mock.mock_open() + filepath.stat.return_value = mock.MagicMock() + filepath.stat.st_size = 1024 + + file_sender = FileResponse(filepath, status=203) + file_sender._sendfile = make_mocked_coro(None) + + loop.run_until_complete(file_sender.prepare(request)) + + assert file_sender._status == 203