From e062eb8589583644760fa38a312dd5aad07882a7 Mon Sep 17 00:00:00 2001
From: Bastian Kleineidam <calvin@debian.org>
Date: Fri, 25 Jan 2008 17:17:59 +0100
Subject: Prevent file descriptor leaks
Wrap all opened files in try-finally blocks and close the
descriptors.
Signed-off-by: Bastian Kleineidam <calvin@debian.org>
diff --git a/django/bin/make-messages.py b/django/bin/make-messages.py
index 4404039..4cd0fc3 100755
|
a
|
b
|
def make_messages():
|
| 81 | 81 | for dirpath, file in all_files: |
| 82 | 82 | if domain == 'djangojs' and file.endswith('.js'): |
| 83 | 83 | if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) |
| 84 | | src = open(os.path.join(dirpath, file), "rb").read() |
| | 84 | f = open(os.path.join(dirpath, file), "rb") |
| | 85 | try: |
| | 86 | src = f.read() |
| | 87 | finally: |
| | 88 | f.close() |
| 85 | 89 | src = pythonize_re.sub('\n#', src) |
| 86 | | open(os.path.join(dirpath, '%s.py' % file), "wb").write(src) |
| | 90 | f = open(os.path.join(dirpath, '%s.py' % file), "wb") |
| | 91 | try: |
| | 92 | f.write(src) |
| | 93 | finally: |
| | 94 | f.close() |
| 87 | 95 | thefile = '%s.py' % file |
| 88 | 96 | cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( |
| 89 | 97 | os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) |
| … |
… |
def make_messages():
|
| 98 | 106 | new = '#: '+os.path.join(dirpath, file)[2:] |
| 99 | 107 | msgs = msgs.replace(old, new) |
| 100 | 108 | if msgs: |
| 101 | | open(potfile, 'ab').write(msgs) |
| | 109 | f = open(potfile, 'ab') |
| | 110 | try: |
| | 111 | f.write(msgs) |
| | 112 | finally: |
| | 113 | f.close() |
| 102 | 114 | os.unlink(os.path.join(dirpath, thefile)) |
| 103 | 115 | elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')): |
| 104 | 116 | thefile = file |
| 105 | 117 | if file.endswith('.html'): |
| 106 | | src = open(os.path.join(dirpath, file), "rb").read() |
| | 118 | f = open(os.path.join(dirpath, file), "rb") |
| | 119 | try: |
| | 120 | src = f.read() |
| | 121 | finally: |
| | 122 | f.close() |
| 107 | 123 | thefile = '%s.py' % file |
| 108 | | open(os.path.join(dirpath, thefile), "wb").write(templatize(src)) |
| | 124 | f = open(os.path.join(dirpath, thefile), "wb") |
| | 125 | try: |
| | 126 | f.write(templatize(src)) |
| | 127 | finally: |
| | 128 | f.close() |
| 109 | 129 | if verbose: |
| 110 | 130 | sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) |
| 111 | 131 | cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( |
| … |
… |
def make_messages():
|
| 127 | 147 | else: |
| 128 | 148 | msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8') |
| 129 | 149 | if msgs: |
| 130 | | open(potfile, 'ab').write(msgs) |
| | 150 | f = open(potfile, 'ab') |
| | 151 | try: |
| | 152 | f.write(msgs) |
| | 153 | finally: |
| | 154 | f.close() |
| 131 | 155 | if thefile != file: |
| 132 | 156 | os.unlink(os.path.join(dirpath, thefile)) |
| 133 | 157 | |
| … |
… |
def make_messages():
|
| 139 | 163 | print "errors happened while running msguniq" |
| 140 | 164 | print errors |
| 141 | 165 | sys.exit(8) |
| 142 | | open(potfile, 'w').write(msgs) |
| | 166 | f = open(potfile, 'w') |
| | 167 | try: |
| | 168 | f.write(msgs) |
| | 169 | finally: |
| | 170 | f.close() |
| 143 | 171 | if os.path.exists(pofile): |
| 144 | 172 | (stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b') |
| 145 | 173 | msgs = stdout.read() |
| … |
… |
def make_messages():
|
| 148 | 176 | print "errors happened while running msgmerge" |
| 149 | 177 | print errors |
| 150 | 178 | sys.exit(8) |
| 151 | | open(pofile, 'wb').write(msgs) |
| | 179 | f = open(pofile, 'wb') |
| | 180 | try: |
| | 181 | f.write(msgs) |
| | 182 | finally: |
| | 183 | f.close() |
| 152 | 184 | os.unlink(potfile) |
| 153 | 185 | |
| 154 | 186 | if __name__ == "__main__": |
diff --git a/django/bin/unique-messages.py b/django/bin/unique-messages.py
index c601a9e..d26635d 100755
|
a
|
b
|
def unique_messages():
|
| 22 | 22 | cmd = 'msguniq "%s.po"' % pf |
| 23 | 23 | stdout = os.popen(cmd) |
| 24 | 24 | msg = stdout.read() |
| 25 | | open('%s.po' % pf, 'w').write(msg) |
| | 25 | f = open('%s.po' % pf, 'w') |
| | 26 | try: |
| | 27 | f.write(msg) |
| | 28 | finally: |
| | 29 | f.close() |
| 26 | 30 | |
| 27 | 31 | if __name__ == "__main__": |
| 28 | 32 | unique_messages() |
diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py
index 44a27d6..955d06d 100644
|
a
|
b
|
def model_detail(request, app_label, model_name):
|
| 234 | 234 | }, context_instance=RequestContext(request)) |
| 235 | 235 | model_detail = staff_member_required(model_detail) |
| 236 | 236 | |
| | 237 | def get_template_contents (filename): |
| | 238 | if os.path.exists(filename): |
| | 239 | fd = open(filename) |
| | 240 | try: |
| | 241 | return fd.read() |
| | 242 | finally: |
| | 243 | fd.close() |
| | 244 | return '' |
| | 245 | |
| 237 | 246 | def template_detail(request, template): |
| 238 | 247 | templates = [] |
| 239 | 248 | for site_settings_module in settings.ADMIN_FOR: |
| … |
… |
def template_detail(request, template):
|
| 247 | 256 | templates.append({ |
| 248 | 257 | 'file': template_file, |
| 249 | 258 | 'exists': os.path.exists(template_file), |
| 250 | | 'contents': lambda: os.path.exists(template_file) and open(template_file).read() or '', |
| | 259 | 'contents': lambda: get_template_contents(template_file), |
| 251 | 260 | 'site_id': settings_mod.SITE_ID, |
| 252 | 261 | 'site': site_obj, |
| 253 | 262 | 'order': list(settings_mod.TEMPLATE_DIRS).index(dir), |
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index c1277bf..7483720 100644
|
a
|
b
|
class CacheClass(BaseCache):
|
| 38 | 38 | fname = self._key_to_file(key) |
| 39 | 39 | try: |
| 40 | 40 | f = open(fname, 'rb') |
| 41 | | exp = pickle.load(f) |
| 42 | | now = time.time() |
| 43 | | if exp < now: |
| | 41 | try: |
| | 42 | exp = pickle.load(f) |
| | 43 | now = time.time() |
| | 44 | if exp < now: |
| | 45 | f.close() |
| | 46 | self._delete(fname) |
| | 47 | else: |
| | 48 | return pickle.load(f) |
| | 49 | finally: |
| | 50 | # note: calling f.close() twice is ok |
| 44 | 51 | f.close() |
| 45 | | self._delete(fname) |
| 46 | | else: |
| 47 | | return pickle.load(f) |
| 48 | 52 | except (IOError, OSError, EOFError, pickle.PickleError): |
| 49 | 53 | pass |
| 50 | 54 | return default |
| … |
… |
class CacheClass(BaseCache):
|
| 63 | 67 | os.makedirs(dirname) |
| 64 | 68 | |
| 65 | 69 | f = open(fname, 'wb') |
| 66 | | now = time.time() |
| 67 | | pickle.dump(now + timeout, f, pickle.HIGHEST_PROTOCOL) |
| 68 | | pickle.dump(value, f, pickle.HIGHEST_PROTOCOL) |
| | 70 | try: |
| | 71 | now = time.time() |
| | 72 | pickle.dump(now + timeout, f, pickle.HIGHEST_PROTOCOL) |
| | 73 | pickle.dump(value, f, pickle.HIGHEST_PROTOCOL) |
| | 74 | finally: |
| | 75 | f.close() |
| 69 | 76 | except (IOError, OSError): |
| 70 | 77 | pass |
| 71 | 78 | |
| … |
… |
class CacheClass(BaseCache):
|
| 89 | 96 | fname = self._key_to_file(key) |
| 90 | 97 | try: |
| 91 | 98 | f = open(fname, 'rb') |
| 92 | | exp = pickle.load(f) |
| 93 | | now = time.time() |
| 94 | | if exp < now: |
| | 99 | try: |
| | 100 | exp = pickle.load(f) |
| | 101 | now = time.time() |
| | 102 | if exp < now: |
| | 103 | f.close() |
| | 104 | self._delete(fname) |
| | 105 | return False |
| | 106 | else: |
| | 107 | return True |
| | 108 | finally: |
| | 109 | # note: calling f.close() twice is ok |
| 95 | 110 | f.close() |
| 96 | | self._delete(fname) |
| 97 | | return False |
| 98 | | else: |
| 99 | | return True |
| 100 | 111 | except (IOError, OSError, EOFError, pickle.PickleError): |
| 101 | 112 | return False |
| 102 | 113 | |
diff --git a/django/core/mail.py b/django/core/mail.py
index 153dcb6..65b123b 100644
|
a
|
b
|
class EmailMessage(object):
|
| 273 | 273 | def attach_file(self, path, mimetype=None): |
| 274 | 274 | """Attaches a file from the filesystem.""" |
| 275 | 275 | filename = os.path.basename(path) |
| 276 | | content = open(path, 'rb').read() |
| | 276 | f = open(path, 'rb') |
| | 277 | try: |
| | 278 | content = f.read() |
| | 279 | finally: |
| | 280 | f.close() |
| 277 | 281 | self.attach(filename, content, mimetype) |
| 278 | 282 | |
| 279 | 283 | def _create_attachment(self, filename, content, mimetype=None): |
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 7b8a3e9..a192b87 100644
|
a
|
b
|
def copy_helper(style, app_or_project, name, directory, other_name=''):
|
| 210 | 210 | path_old = os.path.join(d, f) |
| 211 | 211 | path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name)) |
| 212 | 212 | fp_old = open(path_old, 'r') |
| | 213 | try: |
| | 214 | content = fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name) |
| | 215 | finally: |
| | 216 | fp_old.close() |
| 213 | 217 | fp_new = open(path_new, 'w') |
| 214 | | fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name)) |
| 215 | | fp_old.close() |
| 216 | | fp_new.close() |
| | 218 | try: |
| | 219 | fp_new.write(content) |
| | 220 | finally: |
| | 221 | fp_new.close() |
| 217 | 222 | try: |
| 218 | 223 | shutil.copymode(path_old, path_new) |
| 219 | 224 | _make_writeable(path_new) |
diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py
index ab4f409..560998e 100644
|
a
|
b
|
class Command(LabelCommand):
|
| 27 | 27 | |
| 28 | 28 | # Create a random SECRET_KEY hash, and put it in the main settings. |
| 29 | 29 | main_settings_file = os.path.join(directory, project_name, 'settings.py') |
| 30 | | settings_contents = open(main_settings_file, 'r').read() |
| 31 | | fp = open(main_settings_file, 'w') |
| | 30 | f = open(main_settings_file, 'r') |
| | 31 | try: |
| | 32 | settings_contents = f.read() |
| | 33 | finally: |
| | 34 | f.close() |
| 32 | 35 | secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)]) |
| 33 | 36 | settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents) |
| 34 | | fp.write(settings_contents) |
| 35 | | fp.close() |
| | 37 | fp = open(main_settings_file, 'w') |
| | 38 | try: |
| | 39 | fp.write(settings_contents) |
| | 40 | finally: |
| | 41 | fp.close() |
diff --git a/django/core/management/sql.py b/django/core/management/sql.py
index 15bffce..fd37d6d 100644
|
a
|
b
|
def custom_sql_for_model(model):
|
| 443 | 443 | for sql_file in sql_files: |
| 444 | 444 | if os.path.exists(sql_file): |
| 445 | 445 | fp = open(sql_file, 'U') |
| 446 | | for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)): |
| | 446 | try: |
| | 447 | content = fp.read().decode(settings.FILE_CHARSET) |
| | 448 | finally: |
| | 449 | fp.close() |
| | 450 | for statement in statements.split(content): |
| 447 | 451 | # Remove any comments from the file |
| 448 | 452 | statement = re.sub(ur"--.*[\n\Z]", "", statement) |
| 449 | 453 | if statement.strip(): |
| 450 | 454 | output.append(statement + u";") |
| 451 | | fp.close() |
| 452 | 455 | |
| 453 | 456 | return output |
| 454 | 457 | |
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index 05f8756..ac5cd86 100644
|
a
|
b
|
class AdminMediaHandler(object):
|
| 645 | 645 | headers = {'Content-type': 'text/plain'} |
| 646 | 646 | output = ['Permission denied: %s' % file_path] |
| 647 | 647 | else: |
| 648 | | status = '200 OK' |
| 649 | | headers = {} |
| 650 | | mime_type = mimetypes.guess_type(file_path)[0] |
| 651 | | if mime_type: |
| 652 | | headers['Content-Type'] = mime_type |
| 653 | | output = [fp.read()] |
| 654 | | fp.close() |
| | 648 | try: |
| | 649 | status = '200 OK' |
| | 650 | headers = {} |
| | 651 | mime_type = mimetypes.guess_type(file_path)[0] |
| | 652 | if mime_type: |
| | 653 | headers['Content-Type'] = mime_type |
| | 654 | output = [fp.read()] |
| | 655 | finally: |
| | 656 | fp.close() |
| 655 | 657 | start_response(status, headers.items()) |
| 656 | 658 | return output |
| 657 | 659 | |
diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py
index de04a5a..82c53c9 100644
|
a
|
b
|
def runfastcgi(argset=[], **kwargs):
|
| 155 | 155 | become_daemon(our_home_dir=options["workdir"]) |
| 156 | 156 | |
| 157 | 157 | if options["pidfile"]: |
| 158 | | fp = open(options["pidfile"], "w") |
| 159 | | fp.write("%d\n" % os.getpid()) |
| 160 | | fp.close() |
| | 158 | f = open(options["pidfile"], "w") |
| | 159 | try: |
| | 160 | f.write("%d\n" % os.getpid()) |
| | 161 | finally: |
| | 162 | f.close() |
| 161 | 163 | |
| 162 | 164 | WSGIServer(WSGIHandler(), **wsgi_opts).run() |
| 163 | 165 | |
diff --git a/django/core/validators.py b/django/core/validators.py
index 874edae..a051077 100644
|
a
|
b
|
class RelaxNGCompact(object):
|
| 553 | 553 | 'data': field_data |
| 554 | 554 | } |
| 555 | 555 | filename = tempfile.mktemp() # Insecure, but nothing else worked |
| 556 | | fp = open(filename, 'w') |
| 557 | | fp.write(field_data) |
| 558 | | fp.close() |
| | 556 | f = open(filename, 'w') |
| | 557 | try: |
| | 558 | f.write(field_data) |
| | 559 | finally: |
| | 560 | f.close() |
| 559 | 561 | if not os.path.exists(settings.JING_PATH): |
| 560 | 562 | raise Exception, "%s not found!" % settings.JING_PATH |
| 561 | 563 | p = os.popen('%s -c %s %s' % (settings.JING_PATH, self.schema_path, filename)) |
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 31bc907..b6c9948 100644
|
a
|
b
|
class Model(object):
|
| 403 | 403 | setattr(self, field.attname, filename) |
| 404 | 404 | |
| 405 | 405 | full_filename = self._get_FIELD_filename(field) |
| 406 | | fp = open(full_filename, 'wb') |
| 407 | | fp.write(raw_contents) |
| 408 | | fp.close() |
| | 406 | f = open(full_filename, 'wb') |
| | 407 | try: |
| | 408 | f.write(raw_contents) |
| | 409 | finally: |
| | 410 | f.close() |
| 409 | 411 | |
| 410 | 412 | # Save the width and/or height, if applicable. |
| 411 | 413 | if isinstance(field, ImageField) and (field.width_field or field.height_field): |
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index e5a8e66..27e8339 100644
|
a
|
b
|
class SsiNode(Node):
|
| 293 | 293 | else: |
| 294 | 294 | return '' # Fail silently for invalid includes. |
| 295 | 295 | try: |
| 296 | | fp = open(self.filepath, 'r') |
| 297 | | output = fp.read() |
| 298 | | fp.close() |
| | 296 | f = open(self.filepath, 'r') |
| | 297 | try: |
| | 298 | output = f.read() |
| | 299 | finally: |
| | 300 | f.close() |
| 299 | 301 | except IOError: |
| 300 | 302 | output = '' |
| 301 | 303 | if self.parsed: |
diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py
index f0f4b1a..6684acd 100644
|
a
|
b
|
def get_template_sources(template_name, template_dirs=None):
|
| 45 | 45 | def load_template_source(template_name, template_dirs=None): |
| 46 | 46 | for filepath in get_template_sources(template_name, template_dirs): |
| 47 | 47 | try: |
| 48 | | return (open(filepath).read().decode(settings.FILE_CHARSET), filepath) |
| | 48 | f = open(filepath) |
| | 49 | try: |
| | 50 | content = f.read().decode(settings.FILE_CHARSET) |
| | 51 | finally: |
| | 52 | f.close() |
| | 53 | return (content, filepath) |
| 49 | 54 | except IOError: |
| 50 | 55 | pass |
| 51 | 56 | raise TemplateDoesNotExist, template_name |
diff --git a/django/template/loaders/filesystem.py b/django/template/loaders/filesystem.py
index 9997eb9..37f9036 100644
|
a
|
b
|
def load_template_source(template_name, template_dirs=None):
|
| 20 | 20 | tried = [] |
| 21 | 21 | for filepath in get_template_sources(template_name, template_dirs): |
| 22 | 22 | try: |
| 23 | | return (open(filepath).read().decode(settings.FILE_CHARSET), filepath) |
| | 23 | f = open(filepath) |
| | 24 | try: |
| | 25 | content = f.read().decode(settings.FILE_CHARSET) |
| | 26 | finally: |
| | 27 | f.close() |
| | 28 | return (content, filepath) |
| 24 | 29 | except IOError: |
| 25 | 30 | tried.append(filepath) |
| 26 | 31 | if tried: |
diff --git a/django/test/_doctest.py b/django/test/_doctest.py
index a56483c..ae5c4ad 100644
|
a
|
b
|
def testfile(filename, module_relative=True, name=None, package=None,
|
| 1982 | 1982 | runner = DocTestRunner(verbose=verbose, optionflags=optionflags) |
| 1983 | 1983 | |
| 1984 | 1984 | # Read the file, convert it to a test, and run it. |
| 1985 | | s = open(filename).read() |
| | 1985 | f = open(filename) |
| | 1986 | try: |
| | 1987 | s = f.read() |
| | 1988 | finally: |
| | 1989 | f.close() |
| 1986 | 1990 | test = parser.get_doctest(s, globs, name, filename, 0) |
| 1987 | 1991 | runner.run(test) |
| 1988 | 1992 | |
| … |
… |
def DocFileTest(path, module_relative=True, package=None,
|
| 2368 | 2372 | |
| 2369 | 2373 | # Find the file and read it. |
| 2370 | 2374 | name = os.path.basename(path) |
| 2371 | | doc = open(path).read() |
| | 2375 | f = open(path) |
| | 2376 | try: |
| | 2377 | doc = f.read() |
| | 2378 | finally: |
| | 2379 | f.close() |
| 2372 | 2380 | |
| 2373 | 2381 | # Convert it to a test, and wrap it in a DocFileCase. |
| 2374 | 2382 | test = parser.get_doctest(doc, globs, name, path, 0) |
| … |
… |
def debug_script(src, pm=False, globs=None):
|
| 2554 | 2562 | # on modern Windows boxes, and execfile() needs to open it. |
| 2555 | 2563 | srcfilename = tempfile.mktemp(".py", "doctestdebug") |
| 2556 | 2564 | f = open(srcfilename, 'w') |
| 2557 | | f.write(src) |
| 2558 | | f.close() |
| | 2565 | try: |
| | 2566 | f.write(src) |
| | 2567 | finally: |
| | 2568 | f.close() |
| 2559 | 2569 | |
| 2560 | 2570 | try: |
| 2561 | 2571 | if globs: |
diff --git a/django/utils/images.py b/django/utils/images.py
index 122c6ae..35d51ed 100644
|
a
|
b
|
import ImageFile
|
| 9 | 9 | def get_image_dimensions(path): |
| 10 | 10 | """Returns the (width, height) of an image at a given path.""" |
| 11 | 11 | p = ImageFile.Parser() |
| 12 | | fp = open(path, 'rb') |
| 13 | | while 1: |
| 14 | | data = fp.read(1024) |
| 15 | | if not data: |
| 16 | | break |
| 17 | | p.feed(data) |
| 18 | | if p.image: |
| 19 | | return p.image.size |
| 20 | | break |
| 21 | | fp.close() |
| | 12 | f = open(path, 'rb') |
| | 13 | try: |
| | 14 | while 1: |
| | 15 | data = f.read(1024) |
| | 16 | if not data: |
| | 17 | break |
| | 18 | p.feed(data) |
| | 19 | if p.image: |
| | 20 | return p.image.size |
| | 21 | break |
| | 22 | finally: |
| | 23 | f.close() |
| 22 | 24 | return None |
diff --git a/django/utils/version.py b/django/utils/version.py
index cf80856..350da4a 100644
|
a
|
b
|
def get_svn_revision(path=None):
|
| 20 | 20 | entries_path = '%s/.svn/entries' % path |
| 21 | 21 | |
| 22 | 22 | if os.path.exists(entries_path): |
| 23 | | entries = open(entries_path, 'r').read() |
| | 23 | f = open(entries_path, 'r') |
| | 24 | try: |
| | 25 | entries = f.read() |
| | 26 | finally: |
| | 27 | f.close() |
| 24 | 28 | # Versions >= 7 of the entries file are flat text. The first line is |
| 25 | 29 | # the version number. The next set of digits after 'dir' is the revision. |
| 26 | 30 | if re.match('(\d+)', entries): |
diff --git a/django/views/static.py b/django/views/static.py
index 5a4d3ab..e010a18 100644
|
a
|
b
|
def serve(request, path, document_root=None, show_indexes=False):
|
| 60 | 60 | statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]): |
| 61 | 61 | return HttpResponseNotModified() |
| 62 | 62 | mimetype = mimetypes.guess_type(fullpath)[0] or 'application/octet-stream' |
| 63 | | contents = open(fullpath, 'rb').read() |
| | 63 | f = open(fullpath, 'rb') |
| | 64 | try: |
| | 65 | contents = f.read() |
| | 66 | finally: |
| | 67 | f.close() |
| 64 | 68 | response = HttpResponse(contents, mimetype=mimetype) |
| 65 | 69 | response["Last-Modified"] = http_date(statobj[stat.ST_MTIME]) |
| 66 | 70 | response["Content-Length"] = len(contents) |