Skip to content

Commit b5a3c70

Browse files
author
Jussi Kukkonen
committed
Avoid leaving unclosed file objects
* move code to only create objects after potential raises * Use 'with' when possible * close manually if those did not help Signed-off-by: Jussi Kukkonen <[email protected]>
1 parent 87e92d5 commit b5a3c70

File tree

3 files changed

+46
-48
lines changed

3 files changed

+46
-48
lines changed

tests/test_download.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,11 @@ def tearDown(self):
105105
def test_download_url_to_tempfileobj(self):
106106

107107
download_file = download.safe_download
108-
109-
temp_fileobj = download_file(self.url, self.target_data_length)
110-
temp_fileobj.seek(0)
111-
temp_file_data = temp_fileobj.read().decode('utf-8')
112-
self.assertEqual(self.target_data, temp_file_data)
113-
self.assertEqual(self.target_data_length, len(temp_file_data))
114-
temp_fileobj.close()
108+
with download_file(self.url, self.target_data_length) as temp_fileobj:
109+
temp_fileobj.seek(0)
110+
temp_file_data = temp_fileobj.read().decode('utf-8')
111+
self.assertEqual(self.target_data, temp_file_data)
112+
self.assertEqual(self.target_data_length, len(temp_file_data))
115113

116114

117115

@@ -344,16 +342,16 @@ def test_https_connection(self):
344342
# TODO: Confirm necessity of this session clearing and lay out mechanics.
345343
tuf.download._sessions = {}
346344
logger.info('Trying HTTPS download of target file: ' + good_https_url)
347-
download.safe_download(good_https_url, target_data_length)
348-
download.unsafe_download(good_https_url, target_data_length)
345+
download.safe_download(good_https_url, target_data_length).close()
346+
download.unsafe_download(good_https_url, target_data_length).close()
349347

350348
os.environ['REQUESTS_CA_BUNDLE'] = good2_cert_fname
351349
# Clear sessions to ensure that the certificate we just specified is used.
352350
# TODO: Confirm necessity of this session clearing and lay out mechanics.
353351
tuf.download._sessions = {}
354352
logger.info('Trying HTTPS download of target file: ' + good2_https_url)
355-
download.safe_download(good2_https_url, target_data_length)
356-
download.unsafe_download(good2_https_url, target_data_length)
353+
download.safe_download(good2_https_url, target_data_length).close()
354+
download.unsafe_download(good2_https_url, target_data_length).close()
357355

358356
finally:
359357
for proc in [

tests/test_updater.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,32 +1627,32 @@ def test_9__get_target_hash(self):
16271627

16281628
def test_10__hard_check_file_length(self):
16291629
# Test for exception if file object is not equal to trusted file length.
1630-
temp_file_object = tempfile.TemporaryFile()
1631-
temp_file_object.write(b'X')
1632-
temp_file_object.seek(0)
1633-
self.assertRaises(tuf.exceptions.DownloadLengthMismatchError,
1634-
self.repository_updater._hard_check_file_length,
1635-
temp_file_object, 10)
1630+
with tempfile.TemporaryFile() as temp_file_object:
1631+
temp_file_object.write(b'X')
1632+
temp_file_object.seek(0)
1633+
self.assertRaises(tuf.exceptions.DownloadLengthMismatchError,
1634+
self.repository_updater._hard_check_file_length,
1635+
temp_file_object, 10)
16361636

16371637

16381638

16391639

16401640

16411641
def test_10__soft_check_file_length(self):
16421642
# Test for exception if file object is not equal to trusted file length.
1643-
temp_file_object = tempfile.TemporaryFile()
1644-
temp_file_object.write(b'XXX')
1645-
temp_file_object.seek(0)
1646-
self.assertRaises(tuf.exceptions.DownloadLengthMismatchError,
1647-
self.repository_updater._soft_check_file_length,
1648-
temp_file_object, 1)
1643+
with tempfile.TemporaryFile() as temp_file_object:
1644+
temp_file_object.write(b'XXX')
1645+
temp_file_object.seek(0)
1646+
self.assertRaises(tuf.exceptions.DownloadLengthMismatchError,
1647+
self.repository_updater._soft_check_file_length,
1648+
temp_file_object, 1)
16491649

1650-
# Verify that an exception is not raised if the file length <= the observed
1651-
# file length.
1652-
temp_file_object.seek(0)
1653-
self.repository_updater._soft_check_file_length(temp_file_object, 3)
1654-
temp_file_object.seek(0)
1655-
self.repository_updater._soft_check_file_length(temp_file_object, 4)
1650+
# Verify that an exception is not raised if the file length <= the observed
1651+
# file length.
1652+
temp_file_object.seek(0)
1653+
self.repository_updater._soft_check_file_length(temp_file_object, 3)
1654+
temp_file_object.seek(0)
1655+
self.repository_updater._soft_check_file_length(temp_file_object, 4)
16561656

16571657

16581658

@@ -1763,14 +1763,13 @@ def test_10__visit_child_role(self):
17631763

17641764
def test_11__verify_metadata_file(self):
17651765
# Test for invalid metadata content.
1766-
metadata_file_object = tempfile.TemporaryFile()
1767-
metadata_file_object.write(b'X')
1768-
metadata_file_object.seek(0)
1769-
1770-
self.assertRaises(tuf.exceptions.InvalidMetadataJSONError,
1771-
self.repository_updater._verify_metadata_file,
1772-
metadata_file_object, 'root')
1766+
with tempfile.TemporaryFile() as metadata_file_object:
1767+
metadata_file_object.write(b'X')
1768+
metadata_file_object.seek(0)
17731769

1770+
self.assertRaises(tuf.exceptions.InvalidMetadataJSONError,
1771+
self.repository_updater._verify_metadata_file,
1772+
metadata_file_object, 'root')
17741773

17751774

17761775
def test_12__get_file(self):
@@ -1788,10 +1787,10 @@ def verify_target_file(targets_path):
17881787
self.repository_updater._check_hashes(targets_path, file_hashes)
17891788

17901789
self.repository_updater._get_file('targets.json', verify_target_file,
1791-
file_type, file_size, download_safely=True)
1790+
file_type, file_size, download_safely=True).close()
17921791

17931792
self.repository_updater._get_file('targets.json', verify_target_file,
1794-
file_type, file_size, download_safely=False)
1793+
file_type, file_size, download_safely=False).close()
17951794

17961795
def test_13__targets_of_role(self):
17971796
# Test case where a list of targets is given. By default, the 'targets'

tuf/client/updater.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,9 @@ def _get_metadata_file(self, metadata_role, remote_filename,
16371637
# Remember the error from this mirror, and "reset" the target file.
16381638
logger.exception('Update failed from ' + file_mirror + '.')
16391639
file_mirror_errors[file_mirror] = exception
1640-
file_object = None
1640+
if file_object:
1641+
file_object.close()
1642+
file_object = None
16411643

16421644
else:
16431645
break
@@ -3281,15 +3283,9 @@ def download_target(self, target, destination_directory,
32813283
trusted_length = target['fileinfo']['length']
32823284
trusted_hashes = target['fileinfo']['hashes']
32833285

3284-
# '_get_target_file()' checks every mirror and returns the first target
3285-
# that passes verification.
3286-
target_file_object = self._get_target_file(target_filepath, trusted_length,
3287-
trusted_hashes, prefix_filename_with_hash)
3288-
3289-
# We acquired a target file object from a mirror. Move the file into place
3290-
# (i.e., locally to 'destination_directory'). Note: join() discards
3291-
# 'destination_directory' if 'target_path' contains a leading path
3292-
# separator (i.e., is treated as an absolute path).
3286+
# Build absolute 'destination' file path.
3287+
# Note: join() discards 'destination_directory' if 'target_path' contains
3288+
# a leading path separator (i.e., is treated as an absolute path).
32933289
destination = os.path.join(destination_directory,
32943290
target_filepath.lstrip(os.sep))
32953291
destination = os.path.abspath(destination)
@@ -3310,4 +3306,9 @@ def download_target(self, target, destination_directory,
33103306
else:
33113307
raise
33123308

3309+
# '_get_target_file()' checks every mirror and returns the first target
3310+
# that passes verification.
3311+
target_file_object = self._get_target_file(target_filepath, trusted_length,
3312+
trusted_hashes, prefix_filename_with_hash)
3313+
33133314
securesystemslib.util.persist_temp_file(target_file_object, destination)

0 commit comments

Comments
 (0)