summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsaelices <msaelices@gmail.com>2015-08-17 17:59:31 +0200
committerTim Graham <timograham@gmail.com>2015-11-12 19:30:48 -0500
commit7624fdb9f8ea4cbff407436606998f572898038b (patch)
tree341293a573918afc1e4e2fa96e45b7901b5033c8
parentce4914eab4688ace4b97d14a8c271887235ebb3f (diff)
Fixed #25283 -- Fixed collectstatic crash if a URL contains a fragment with a path.
A @font-face declaration may contain a fragment that looks like a relative path, e.g. @font-face { src: url('../fonts/font.svg#../path/like/fragment'); } In this case, an incorrect path was passed to the storage backend, which raised an error that caused collectstatic to crash.
-rw-r--r--django/contrib/staticfiles/storage.py15
-rw-r--r--tests/staticfiles_tests/project/documents/cached/css/fragments.css1
-rw-r--r--tests/staticfiles_tests/test_storage.py3
3 files changed, 13 insertions, 6 deletions
diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py
index b3c53b7232..d6911c9fd7 100644
--- a/django/contrib/staticfiles/storage.py
+++ b/django/contrib/staticfiles/storage.py
@@ -166,12 +166,15 @@ class HashedFilesMixin(object):
name_parts = name.split(os.sep)
# Using posix normpath here to remove duplicates
url = posixpath.normpath(url)
- url_parts = url.split('/')
- parent_level, sub_level = url.count('..'), url.count('/')
- if url.startswith('/'):
+ # Strip off the fragment so that a path-like fragment won't confuse
+ # the lookup.
+ url_path, fragment = urldefrag(url)
+ url_parts = url_path.split('/')
+ parent_level, sub_level = url_path.count('..'), url_path.count('/')
+ if url_path.startswith('/'):
sub_level -= 1
url_parts = url_parts[1:]
- if parent_level or not url.startswith('/'):
+ if parent_level or not url_path.startswith('/'):
start, end = parent_level + 1, parent_level
else:
if sub_level:
@@ -183,7 +186,9 @@ class HashedFilesMixin(object):
joined_result = '/'.join(name_parts[:-start] + url_parts[end:])
hashed_url = self.url(unquote(joined_result), force=True)
file_name = hashed_url.split('/')[-1:]
- relative_url = '/'.join(url.split('/')[:-1] + file_name)
+ relative_url = '/'.join(url_path.split('/')[:-1] + file_name)
+ if fragment:
+ relative_url += '?#%s' % fragment if '?#' in url else '#%s' % fragment
# Return the hashed version to the file
return template % unquote(relative_url)
diff --git a/tests/staticfiles_tests/project/documents/cached/css/fragments.css b/tests/staticfiles_tests/project/documents/cached/css/fragments.css
index 540d54b88d..e6e7049465 100644
--- a/tests/staticfiles_tests/project/documents/cached/css/fragments.css
+++ b/tests/staticfiles_tests/project/documents/cached/css/fragments.css
@@ -1,6 +1,7 @@
@font-face {
src: url('fonts/font.eot?#iefix') format('embedded-opentype'),
url('fonts/font.svg#webfontIyfZbseF') format('svg');
+ url('fonts/font.svg#../path/to/fonts/font.svg') format('svg');
url('data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA');
}
div {
diff --git a/tests/staticfiles_tests/test_storage.py b/tests/staticfiles_tests/test_storage.py
index b96d9d0f12..f0c69cebe6 100644
--- a/tests/staticfiles_tests/test_storage.py
+++ b/tests/staticfiles_tests/test_storage.py
@@ -85,11 +85,12 @@ class TestHashedFiles(object):
def test_path_with_querystring_and_fragment(self):
relpath = self.hashed_file_path("cached/css/fragments.css")
- self.assertEqual(relpath, "cached/css/fragments.75433540b096.css")
+ self.assertEqual(relpath, "cached/css/fragments.ef92012a8c16.css")
with storage.staticfiles_storage.open(relpath) as relfile:
content = relfile.read()
self.assertIn(b'fonts/font.a4b0478549d0.eot?#iefix', content)
self.assertIn(b'fonts/font.b8d603e42714.svg#webfontIyfZbseF', content)
+ self.assertIn(b'fonts/font.b8d603e42714.svg#../path/to/fonts/font.svg', content)
self.assertIn(b'data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA', content)
self.assertIn(b'#default#VML', content)