diff options
| author | Florian Apolloner <florian@apolloner.eu> | 2020-02-07 12:55:59 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2020-02-11 20:40:24 +0100 |
| commit | 4e8d6a1bafbbebc0720c5d1ed751521356364fe9 (patch) | |
| tree | a50a7b4db7277bda878d1668ede1e133cd3114db /tests/builtin_server | |
| parent | 22c25bea54dcad23c76d26bb0bfb8d56eeedeef2 (diff) | |
[3.0.x] Fixed #31240 -- Properly closed FileResponse when wsgi.file_wrapper is used.
Thanks to Oskar Persson for the report.
Backport of 41a3b3d18647b258331104520e76f977406c590d from master
Diffstat (limited to 'tests/builtin_server')
| -rw-r--r-- | tests/builtin_server/tests.py | 26 | ||||
| -rw-r--r-- | tests/builtin_server/urls.py | 7 | ||||
| -rw-r--r-- | tests/builtin_server/views.py | 15 |
3 files changed, 48 insertions, 0 deletions
diff --git a/tests/builtin_server/tests.py b/tests/builtin_server/tests.py index 879a93bc08..71e261ddcc 100644 --- a/tests/builtin_server/tests.py +++ b/tests/builtin_server/tests.py @@ -4,6 +4,11 @@ from io import BytesIO from unittest import TestCase from wsgiref import simple_server +from django.core.servers.basehttp import get_internal_wsgi_application +from django.test import RequestFactory, override_settings + +from .views import FILE_RESPONSE_HOLDER + # If data is too large, socket will choke, so write chunks no larger than 32MB # at a time. The rationale behind the 32MB can be found in #5596#comment:4. MAX_SOCKET_CHUNK_SIZE = 32 * 1024 * 1024 # 32 MB @@ -89,6 +94,27 @@ class WSGIFileWrapperTests(TestCase): self.assertEqual(handler.stdout.getvalue().splitlines()[-1], b'Hello World!') self.assertEqual(handler.stderr.getvalue(), b'') + @override_settings(ROOT_URLCONF='builtin_server.urls') + def test_file_response_closing(self): + """ + View returning a FileResponse properly closes the file and http + response when file_wrapper is used. + """ + env = RequestFactory().get('/fileresponse/').environ + handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env) + handler.run(get_internal_wsgi_application()) + # Sendfile is used only when file_wrapper has been used. + self.assertTrue(handler._used_sendfile) + # Fetch the original response object. + self.assertIn('response', FILE_RESPONSE_HOLDER) + response = FILE_RESPONSE_HOLDER['response'] + # The response and file buffers are closed. + self.assertIs(response.closed, True) + buf1, buf2 = FILE_RESPONSE_HOLDER['buffers'] + self.assertIs(buf1.closed, True) + self.assertIs(buf2.closed, True) + FILE_RESPONSE_HOLDER.clear() + class WriteChunkCounterHandler(ServerHandler): """ diff --git a/tests/builtin_server/urls.py b/tests/builtin_server/urls.py new file mode 100644 index 0000000000..c26366f1e6 --- /dev/null +++ b/tests/builtin_server/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path('fileresponse/', views.file_response), +] diff --git a/tests/builtin_server/views.py b/tests/builtin_server/views.py new file mode 100644 index 0000000000..be7c7e94ab --- /dev/null +++ b/tests/builtin_server/views.py @@ -0,0 +1,15 @@ +from io import BytesIO + +from django.http import FileResponse + +FILE_RESPONSE_HOLDER = {} + + +def file_response(request): + f1 = BytesIO(b"test1") + f2 = BytesIO(b"test2") + response = FileResponse(f1) + response._resource_closers.append(f2.close) + FILE_RESPONSE_HOLDER['response'] = response + FILE_RESPONSE_HOLDER['buffers'] = (f1, f2) + return response |
