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.
This commit is contained in:
parent
ce4914eab4
commit
7624fdb9f8
|
@ -166,12 +166,15 @@ class HashedFilesMixin(object):
|
||||||
name_parts = name.split(os.sep)
|
name_parts = name.split(os.sep)
|
||||||
# Using posix normpath here to remove duplicates
|
# Using posix normpath here to remove duplicates
|
||||||
url = posixpath.normpath(url)
|
url = posixpath.normpath(url)
|
||||||
url_parts = url.split('/')
|
# Strip off the fragment so that a path-like fragment won't confuse
|
||||||
parent_level, sub_level = url.count('..'), url.count('/')
|
# the lookup.
|
||||||
if url.startswith('/'):
|
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
|
sub_level -= 1
|
||||||
url_parts = url_parts[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
|
start, end = parent_level + 1, parent_level
|
||||||
else:
|
else:
|
||||||
if sub_level:
|
if sub_level:
|
||||||
|
@ -183,7 +186,9 @@ class HashedFilesMixin(object):
|
||||||
joined_result = '/'.join(name_parts[:-start] + url_parts[end:])
|
joined_result = '/'.join(name_parts[:-start] + url_parts[end:])
|
||||||
hashed_url = self.url(unquote(joined_result), force=True)
|
hashed_url = self.url(unquote(joined_result), force=True)
|
||||||
file_name = hashed_url.split('/')[-1:]
|
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 the hashed version to the file
|
||||||
return template % unquote(relative_url)
|
return template % unquote(relative_url)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
src: url('fonts/font.eot?#iefix') format('embedded-opentype'),
|
src: url('fonts/font.eot?#iefix') format('embedded-opentype'),
|
||||||
url('fonts/font.svg#webfontIyfZbseF') format('svg');
|
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');
|
url('data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA');
|
||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
|
|
|
@ -85,11 +85,12 @@ class TestHashedFiles(object):
|
||||||
|
|
||||||
def test_path_with_querystring_and_fragment(self):
|
def test_path_with_querystring_and_fragment(self):
|
||||||
relpath = self.hashed_file_path("cached/css/fragments.css")
|
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:
|
with storage.staticfiles_storage.open(relpath) as relfile:
|
||||||
content = relfile.read()
|
content = relfile.read()
|
||||||
self.assertIn(b'fonts/font.a4b0478549d0.eot?#iefix', content)
|
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#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'data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA', content)
|
||||||
self.assertIn(b'#default#VML', content)
|
self.assertIn(b'#default#VML', content)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue