# HG changeset patch # User Florent Cayré # Date 1309193310 -7200 # Node ID b355d9dd43df13497ad109a8674d7e20142e9797 # Parent 8e129bb6b5714d81cb95c1cf0e32382670f5fb2e [js/css concat] do not return 404 when resources of a concatenated data URL does not exist, unless in debugmode; closes #1745644 diff -r 8e129bb6b571 -r b355d9dd43df etwist/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) diff -r 8e129bb6b571 -r b355d9dd43df etwist/test/unittest_server.py --- 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 . + +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