Browse Source

Fixed #25905 -- Prevented leading slashes in urljoin() calls

Leading slashes in the second urljoin argument will return exactly that

argument, breaking FileSystemStorage.url behavior if called with a

parameter with leading slashes.

Also added test cases for null bytes and None. Thanks to Markus for

help and review.
rixx 9 years ago
parent
commit
fdf5cd3429
2 changed files with 17 additions and 1 deletions
  1. 4 1
      django/core/files/storage.py
  2. 13 0
      tests/file_storage/tests.py

+ 4 - 1
django/core/files/storage.py

@@ -405,7 +405,10 @@ class FileSystemStorage(Storage):
     def url(self, name):
         if self.base_url is None:
             raise ValueError("This file is not accessible via a URL.")
-        return urljoin(self.base_url, filepath_to_uri(name))
+        url = filepath_to_uri(name)
+        if url is not None:
+            url = url.lstrip('/')
+        return urljoin(self.base_url, url)
 
     def accessed_time(self, name):
         warnings.warn(

+ 13 - 0
tests/file_storage/tests.py

@@ -399,11 +399,24 @@ class FileStorageTests(TestCase):
         # like encodeURIComponent() JavaScript function do
         self.assertEqual(self.storage.url(r"""~!*()'@#$%^&*abc`+ =.file"""),
             """/test_media_url/~!*()'%40%23%24%25%5E%26*abc%60%2B%20%3D.file""")
+        self.assertEqual(self.storage.url("""ab\0c"""), """/test_media_url/ab%00c""")
 
         # should translate os path separator(s) to the url path separator
         self.assertEqual(self.storage.url("""a/b\\c.file"""),
             """/test_media_url/a/b/c.file""")
 
+        # #25905: remove leading slashes from file names to prevent unsafe url output
+        self.assertEqual(self.storage.url("/evil.com"), "/test_media_url/evil.com")
+        self.assertEqual(self.storage.url(r"\evil.com"), "/test_media_url/evil.com")
+        self.assertEqual(self.storage.url("///evil.com"), "/test_media_url/evil.com")
+        self.assertEqual(self.storage.url(r"\\\evil.com"), "/test_media_url/evil.com")
+
+        self.assertEqual(self.storage.url(None), "/test_media_url/")
+
+    def test_base_url(self):
+        """
+        File storage returns a url even when its base_url is unset or modified.
+        """
         self.storage.base_url = None
         with self.assertRaises(ValueError):
             self.storage.url('test.file')