Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17455 -- Extended `CachedStaticFilesStorage` slightly to handl…

…e some URLs better that are used to add support for webfonts to IE 6-8. Also ignore `data:` URLs and fragment-only URLs (e.g. `#default#VML`).

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17282 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 46c12d1293aa90209f3c640f214c4b5a3d6cb9e6 1 parent ae0ce43
Jannis Leidel authored December 27, 2011
17  django/contrib/staticfiles/storage.py
@@ -12,7 +12,7 @@
12 12
 from django.core.exceptions import ImproperlyConfigured
13 13
 from django.core.files.base import ContentFile
14 14
 from django.core.files.storage import FileSystemStorage, get_storage_class
15  
-from django.utils.encoding import force_unicode
  15
+from django.utils.encoding import force_unicode, smart_str
16 16
 from django.utils.functional import LazyObject
17 17
 from django.utils.importlib import import_module
18 18
 from django.utils.datastructures import SortedDict
@@ -84,9 +84,14 @@ def hashed_name(self, name, content=None):
84 84
         for chunk in content.chunks():
85 85
             md5.update(chunk)
86 86
         md5sum = md5.hexdigest()[:12]
87  
-        hashed_name = os.path.join(path, u"%s.%s%s" % (root, md5sum, ext))
  87
+        hashed_name = os.path.join(path, u"%s.%s%s" %
  88
+                                   (root, md5sum, ext))
88 89
         unparsed_name = list(parsed_name)
89 90
         unparsed_name[2] = hashed_name
  91
+        # Special casing for a @font-face hack, like url(myfont.eot?#iefix")
  92
+        # http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax
  93
+        if '?#' in name and not unparsed_name[3]:
  94
+            unparsed_name[2] += '?'
90 95
         return urlunsplit(unparsed_name)
91 96
 
92 97
     def cache_key(self, name):
@@ -103,7 +108,8 @@ def url(self, name, force=False):
103 108
             hashed_name = self.cache.get(cache_key)
104 109
             if hashed_name is None:
105 110
                 hashed_name = self.hashed_name(name).replace('\\', '/')
106  
-                # set the cache if there was a miss (e.g. if cache server goes down)
  111
+                # set the cache if there was a miss
  112
+                # (e.g. if cache server goes down)
107 113
                 self.cache.set(cache_key, hashed_name)
108 114
         return unquote(super(CachedFilesMixin, self).url(hashed_name))
109 115
 
@@ -119,7 +125,7 @@ def converter(matchobj):
119 125
             """
120 126
             matched, url = matchobj.groups()
121 127
             # Completely ignore http(s) prefixed URLs
122  
-            if url.startswith(('http', 'https')):
  128
+            if url.startswith(('#', 'http', 'https', 'data:')):
123 129
                 return matched
124 130
             name_parts = name.split(os.sep)
125 131
             # Using posix normpath here to remove duplicates
@@ -182,7 +188,8 @@ def post_process(self, paths, dry_run=False, **options):
182 188
                 if self.exists(hashed_name):
183 189
                     self.delete(hashed_name)
184 190
 
185  
-                saved_name = self._save(hashed_name, ContentFile(content))
  191
+                content_file = ContentFile(smart_str(content))
  192
+                saved_name = self._save(hashed_name, content_file)
186 193
                 hashed_name = force_unicode(saved_name.replace('\\', '/'))
187 194
                 processed_files.append(hashed_name)
188 195
 
1  tests/regressiontests/staticfiles_tests/project/documents/cached/css/fonts/font.eot
... ...
@@ -0,0 +1 @@
  1
+not really a EOT ;)
1  tests/regressiontests/staticfiles_tests/project/documents/cached/css/fonts/font.svg
... ...
@@ -0,0 +1 @@
  1
+not really a SVG ;)
8  tests/regressiontests/staticfiles_tests/project/documents/cached/css/fragments.css
... ...
@@ -0,0 +1,8 @@
  1
+@font-face {
  2
+    src: url('fonts/font.eot?#iefix') format('embedded-opentype'),
  3
+         url('fonts/font.svg#webfontIyfZbseF') format('svg');
  4
+         url('data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA');
  5
+}
  6
+div {
  7
+    behavior: url("#default#VML");
  8
+}
2  tests/regressiontests/staticfiles_tests/storage.py
@@ -4,7 +4,7 @@
4 4
 class DummyStorage(storage.Storage):
5 5
     """
6 6
     A storage class that does implement modified_time() but raises
7  
-    NotImplementedError when calling 
  7
+    NotImplementedError when calling
8 8
     """
9 9
     def _save(self, name, content):
10 10
         return 'dummy'
10  tests/regressiontests/staticfiles_tests/tests.py
@@ -331,6 +331,16 @@ def test_path_with_fragment(self):
331 331
             self.assertNotIn("cached/other.css", content)
332 332
             self.assertIn("/static/cached/other.d41d8cd98f00.css", content)
333 333
 
  334
+    def test_path_with_querystring_and_fragment(self):
  335
+        relpath = self.cached_file_path("cached/css/fragments.css")
  336
+        self.assertEqual(relpath, "cached/css/fragments.75433540b096.css")
  337
+        with storage.staticfiles_storage.open(relpath) as relfile:
  338
+            content = relfile.read()
  339
+            self.assertIn('/static/cached/css/fonts/font.a4b0478549d0.eot?#iefix', content)
  340
+            self.assertIn('/static/cached/css/fonts/font.b8d603e42714.svg#webfontIyfZbseF', content)
  341
+            self.assertIn('data:font/woff;charset=utf-8;base64,d09GRgABAAAAADJoAA0AAAAAR2QAAQAAAAAAAAAAAAA', content)
  342
+            self.assertIn('#default#VML', content)
  343
+
334 344
     def test_template_tag_absolute(self):
335 345
         relpath = self.cached_file_path("cached/absolute.css")
336 346
         self.assertEqual(relpath, "cached/absolute.cc80cb5e2eb1.css")

0 notes on commit 46c12d1

Please sign in to comment.
Something went wrong with that request. Please try again.