# HG changeset patch # User Julien Cristau # Date 1391588616 -3600 # Node ID 7310738fafe538820809aa5c1d63ce362951a6a9 # Parent e699fbcc9a61ad936df0cafb107aaa3c5bf20c81 [web/staticcontrollers] create a unique temporary file for concat handling Predictable names means different processes can race against each other. Let's avoid that and use mkstemp to get a real unique temporary file, and atomically rename it when we're done. Closes #3524182 diff -r e699fbcc9a61 -r 7310738fafe5 web/views/staticcontrollers.py --- a/web/views/staticcontrollers.py Wed Jan 29 15:50:19 2014 +0100 +++ b/web/views/staticcontrollers.py Wed Feb 05 09:23:36 2014 +0100 @@ -27,6 +27,7 @@ import hashlib import mimetypes import threading +import tempfile from time import mktime from datetime import datetime, timedelta from logging import getLogger @@ -145,32 +146,34 @@ def concat_cached_filepath(self, paths): filepath = self.build_filepath(paths) if not self._up_to_date(filepath, paths): - tmpfile = filepath + '.tmp' - try: - with self.lock: - if self._up_to_date(filepath, paths): - # first check could have raced with some other thread - # updating the file - return filepath - with open(tmpfile, 'wb') as f: - for path in paths: - dirpath, rid = self._resource(path) - if rid is None: - # In production mode log an error, do not return a 404 - # XXX the erroneous content is cached anyway - self.logger.error('concatenated data url error: %r file ' - 'does not exist', path) - if self.config.debugmode: - raise NotFound(path) - else: - with open(osp.join(dirpath, rid), 'rb') as source: - for line in source: - f.write(line) - f.write('\n') + with self.lock: + if self._up_to_date(filepath, paths): + # first check could have raced with some other thread + # updating the file + return filepath + fd, tmpfile = tempfile.mkstemp(dir=os.path.dirname(filepath)) + try: + f = os.fdopen(fd, 'wb') + for path in paths: + dirpath, rid = self._resource(path) + if rid is None: + # In production mode log an error, do not return a 404 + # XXX the erroneous content is cached anyway + self.logger.error('concatenated data url error: %r file ' + 'does not exist', path) + if self.config.debugmode: + raise NotFound(path) + else: + with open(osp.join(dirpath, rid), 'rb') as source: + for line in source: + f.write(line) + f.write('\n') + f.close() + except: + os.remove(tmpfile) + raise + else: os.rename(tmpfile, filepath) - except: - os.remove(tmpfile) - raise return filepath