diff --git a/django/contrib/staticfiles/views.py b/django/contrib/staticfiles/views.py index dfdbdac9e9..9987f49f73 100644 --- a/django/contrib/staticfiles/views.py +++ b/django/contrib/staticfiles/views.py @@ -5,7 +5,6 @@ development, and SHOULD NOT be used in a production setting. """ import os import posixpath -from urllib.parse import unquote from django.conf import settings from django.contrib.staticfiles import finders @@ -30,7 +29,7 @@ def serve(request, path, insecure=False, **kwargs): """ if not settings.DEBUG and not insecure: raise Http404 - normalized_path = posixpath.normpath(unquote(path)).lstrip('/') + normalized_path = posixpath.normpath(path).lstrip('/') absolute_path = finders.find(normalized_path) if not absolute_path: if path.endswith('/') or path == '': diff --git a/django/views/static.py b/django/views/static.py index 479c59cac6..03e8c34a1c 100644 --- a/django/views/static.py +++ b/django/views/static.py @@ -7,7 +7,6 @@ import os import posixpath import re import stat -from urllib.parse import unquote from django.http import ( FileResponse, Http404, HttpResponse, HttpResponseNotModified, @@ -34,7 +33,7 @@ def serve(request, path, document_root=None, show_indexes=False): but if you'd like to override it, you can create a template called ``static/directory_index.html``. """ - path = posixpath.normpath(unquote(path)) + path = posixpath.normpath(path) path = path.lstrip('/') newpath = '' for part in path.split('/'): diff --git a/tests/staticfiles_tests/apps/test/static/test/%2F.txt b/tests/staticfiles_tests/apps/test/static/test/%2F.txt new file mode 100644 index 0000000000..d98b646c7c --- /dev/null +++ b/tests/staticfiles_tests/apps/test/static/test/%2F.txt @@ -0,0 +1 @@ +%2F content diff --git a/tests/staticfiles_tests/cases.py b/tests/staticfiles_tests/cases.py index 81faf6d7d9..3adf5cf211 100644 --- a/tests/staticfiles_tests/cases.py +++ b/tests/staticfiles_tests/cases.py @@ -128,3 +128,6 @@ class TestDefaults: Can find a file with capital letters. """ self.assertFileContains('test/camelCase.txt', 'camelCase') + + def test_filename_with_percent_sign(self): + self.assertFileContains('test/%2F.txt', '%2F content') diff --git a/tests/staticfiles_tests/test_views.py b/tests/staticfiles_tests/test_views.py index fa817a6ef1..d16f4a2cec 100644 --- a/tests/staticfiles_tests/test_views.py +++ b/tests/staticfiles_tests/test_views.py @@ -1,4 +1,5 @@ import posixpath +from urllib.parse import quote from django.conf import settings from django.test import override_settings @@ -12,8 +13,7 @@ class TestServeStatic(StaticFilesTestCase): Test static asset serving view. """ def _response(self, filepath): - return self.client.get( - posixpath.join(settings.STATIC_URL, filepath)) + return self.client.get(quote(posixpath.join(settings.STATIC_URL, filepath))) def assertFileContains(self, filepath, text): self.assertContains(self._response(filepath), text) diff --git a/tests/view_tests/media/%2F.txt b/tests/view_tests/media/%2F.txt new file mode 100644 index 0000000000..d98b646c7c --- /dev/null +++ b/tests/view_tests/media/%2F.txt @@ -0,0 +1 @@ +%2F content diff --git a/tests/view_tests/tests/test_static.py b/tests/view_tests/tests/test_static.py index f7e5604d06..39ddc6b878 100644 --- a/tests/view_tests/tests/test_static.py +++ b/tests/view_tests/tests/test_static.py @@ -1,6 +1,7 @@ import mimetypes import unittest from os import path +from urllib.parse import quote from django.conf.urls.static import static from django.core.exceptions import ImproperlyConfigured @@ -21,9 +22,9 @@ class StaticTests(SimpleTestCase): def test_serve(self): "The static view can serve static media" - media_files = ['file.txt', 'file.txt.gz'] + media_files = ['file.txt', 'file.txt.gz', '%2F.txt'] for filename in media_files: - response = self.client.get('/%s/%s' % (self.prefix, filename)) + response = self.client.get('/%s/%s' % (self.prefix, quote(filename))) response_content = b''.join(response) file_path = path.join(media_dir, filename) with open(file_path, 'rb') as fp: