[js/css concat] do not return 404 when resources of a concatenated data URL does not exist, unless in debugmode; closes #1745644
authorFlorent Cayré <florent.cayre@gmail.com>
Mon, 27 Jun 2011 18:48:30 +0200
changeset 7565 b355d9dd43df
parent 7563 8e129bb6b571
child 7569 02c338197322
[js/css concat] do not return 404 when resources of a concatenated data URL does not exist, unless in debugmode; closes #1745644
etwist/server.py
etwist/test/unittest_server.py
--- a/etwist/server.py	Mon Jun 27 18:38:08 2011 +0200
+++ b/etwist/server.py	Mon Jun 27 18:48:30 2011 +0200
@@ -173,22 +173,35 @@
 class ConcatFiles(LongTimeExpiringFile):
     def __init__(self, config, paths):
         _, ext = osp.splitext(paths[0])
+        self._resources = {}
         # create a unique / predictable filename
         fname = 'cache_concat_' + hashlib.md5(';'.join(paths)).hexdigest() + ext
         filepath = osp.join(config.appdatahome, 'uicache', fname)
         LongTimeExpiringFile.__init__(self, config, filepath)
         self._concat_cached_filepath(filepath, paths)
 
+    def _resource(self, path):
+        try:
+            return self._resources[path]
+        except KeyError:
+            self._resources[path] = self.config.locate_resource(path)
+            return self._resources[path]
+
     def _concat_cached_filepath(self, filepath, paths):
         if not self._up_to_date(filepath, paths):
             concat_data = []
             for path in paths:
-                # FIXME locate_resource is called twice() in debug-mode, but
-                # it's a @cached method
-                dirpath, rid = self.config.locate_resource(path)
+                dirpath, rid = self._resource(path)
                 if rid is None:
-                    raise ConcatFileNotFoundError(path)
-                concat_data.append(open(osp.join(dirpath, rid)).read())
+                    if self.config.debugmode:
+                        raise ConcatFileNotFoundError(path)
+                    else:
+                        # In production mode log an error, do not return a 404
+                        # XXX the erroneous content is cached anyway
+                        LOGGER.error('concatenated data url error: %r file '
+                                     'does not exist', path)
+                else:
+                    concat_data.append(open(osp.join(dirpath, rid)).read())
             with open(filepath, 'wb') as f:
                 f.write('\n'.join(concat_data))
 
@@ -203,7 +216,7 @@
         if self.config.debugmode:
             concat_lastmod = os.stat(filepath).st_mtime
             for path in paths:
-                dirpath, rid = self.config.locate_resource(path)
+                dirpath, rid = self._resource(path)
                 if rid is None:
                     raise ConcatFileNotFoundError(path)
                 path = osp.join(dirpath, rid)
--- a/etwist/test/unittest_server.py	Mon Jun 27 18:38:08 2011 +0200
+++ b/etwist/test/unittest_server.py	Mon Jun 27 18:48:30 2011 +0200
@@ -15,8 +15,12 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+
+import os, os.path as osp, glob
+
 from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.etwist.server import host_prefixed_baseurl
+from cubicweb.etwist.server import (host_prefixed_baseurl, ConcatFiles,
+                                    ConcatFileNotFoundError)
 
 
 class HostPrefixedBaseURLTC(CubicWebTC):
@@ -50,3 +54,30 @@
         self._check('http://localhost:8080/hg/', 'code.cubicweb.org',
                     'http://localhost:8080/hg/')
 
+
+class ConcatFilesTC(CubicWebTC):
+
+    def tearDown(self):
+        super(ConcatFilesTC, self).tearDown()
+        self._cleanup_concat_cache()
+        self.config.debugmode = False
+
+    def _cleanup_concat_cache(self):
+        uicachedir = osp.join(self.config.apphome, 'uicache')
+        for fname in glob.glob(osp.join(uicachedir, 'cache_concat_*')):
+            os.unlink(osp.join(uicachedir, fname))
+
+    def test_cache(self):
+        concat = ConcatFiles(self.config, ('cubicweb.ajax.js', 'jquery.js'))
+        self.failUnless(osp.isfile(concat.path))
+
+    def test_404(self):
+        # when not in debug mode, should not crash
+        ConcatFiles(self.config, ('cubicweb.ajax.js', 'dummy.js'))
+        # in debug mode, raise error
+        self.config.debugmode = True
+        try:
+            self.assertRaises(ConcatFileNotFoundError, ConcatFiles, self.config,
+                              ('cubicweb.ajax.js', 'dummy.js'))
+        finally:
+            self.config.debugmode = False