Skip to content

Commit 98cf02b

Browse files
committed
Add custom_download_handler to download_target()
Give client-side users the option to provide their own custom download function which should comply with the specification. By default tuf.download.safe_download is used. Signed-off-by: Teodora Sechkova <[email protected]>
1 parent 77ca0af commit 98cf02b

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

tuf/client/updater.py

+40-8
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,10 @@ class Updater(object):
609609
targets that have changed are returns in a list. From this list, they
610610
can request a download by calling 'download_target()'.
611611
612-
download_target(target, destination_directory):
612+
download_target(target, destination_directory, custom_download_handler):
613613
This method performs the actual download of the specified target. The
614-
file is saved to the 'destination_directory' argument.
614+
file is saved to the 'destination_directory' argument. A custom
615+
file download function can be used if provided by the user.
615616
616617
remove_obsolete_targets(destination_directory):
617618
Any files located in 'destination_directory' that were previously
@@ -1313,7 +1314,7 @@ def _soft_check_file_length(self, file_object, trusted_file_length):
13131314

13141315

13151316
def _get_target_file(self, target_filepath, file_length, file_hashes,
1316-
prefix_filename_with_hash):
1317+
prefix_filename_with_hash, custom_download_handler=None):
13171318
"""
13181319
<Purpose>
13191320
Non-public method that safely (i.e., the file length and hash are
@@ -1339,6 +1340,10 @@ def _get_target_file(self, target_filepath, file_length, file_hashes,
13391340
prefixed with hashes (in this case the server uses other means
13401341
to ensure snapshot consistency).
13411342
1343+
custom_download_handler:
1344+
A user provided function performing the actual target file download.
1345+
If None, tuf.download.safe_download is used.
1346+
13421347
<Exceptions>
13431348
tuf.exceptions.NoWorkingMirrorError:
13441349
The target could not be fetched. This is raised only when all known
@@ -1370,7 +1375,7 @@ def verify_target_file(target_file_object):
13701375
target_filepath = os.path.join(dirname, target_digest + '.' + basename)
13711376

13721377
return self._get_file(target_filepath, verify_target_file,
1373-
'target', file_length)
1378+
'target', file_length, custom_download_handler)
13741379

13751380

13761381

@@ -1654,7 +1659,8 @@ def _get_metadata_file(self, metadata_role, remote_filename,
16541659

16551660

16561661

1657-
def _get_file(self, filepath, verify_file_function, file_type, file_length):
1662+
def _get_file(self, filepath, verify_file_function, file_type, file_length,
1663+
custom_download_handler=None):
16581664
"""
16591665
<Purpose>
16601666
Non-public method that tries downloading, up to a certain length, a
@@ -1681,6 +1687,10 @@ def _get_file(self, filepath, verify_file_function, file_type, file_length):
16811687
The expected length, or upper bound, of the target or metadata file to
16821688
be downloaded.
16831689
1690+
custom_download_handler:
1691+
A user provided function performing the actual target file download.
1692+
If None, tuf.download.safe_download is used.
1693+
16841694
<Exceptions>
16851695
tuf.exceptions.NoWorkingMirrorError:
16861696
The metadata could not be fetched. This is raised only when all known
@@ -1702,11 +1712,17 @@ def _get_file(self, filepath, verify_file_function, file_type, file_length):
17021712
file_mirror_errors = {}
17031713
file_object = None
17041714

1715+
if custom_download_handler is not None:
1716+
safe_download = custom_download_handler
1717+
1718+
else:
1719+
safe_download = tuf.download.safe_download
1720+
17051721
for file_mirror in file_mirrors:
17061722
try:
17071723
# Eensure the length of the downloaded file matches 'file_length'
17081724
# exactly.
1709-
file_object = tuf.download.safe_download(file_mirror, file_length)
1725+
file_object = safe_download(file_mirror, file_length)
17101726

17111727
# Verify 'file_object' according to the callable function.
17121728
# 'file_object' is also verified if decompressed above (i.e., the
@@ -3212,7 +3228,7 @@ def updated_targets(self, targets, destination_directory):
32123228

32133229

32143230
def download_target(self, target, destination_directory,
3215-
prefix_filename_with_hash=True):
3231+
prefix_filename_with_hash=True, custom_download_handler=None):
32163232
"""
32173233
<Purpose>
32183234
Download 'target' and verify it is trusted.
@@ -3237,6 +3253,22 @@ def download_target(self, target, destination_directory,
32373253
to ensure snapshot consistency).
32383254
Default is True.
32393255
3256+
custom_download_handler:
3257+
A user provided function performing the actual target file download.
3258+
In order to comply with the TUF specification, the function signature
3259+
should have the form:
3260+
3261+
'def download_handler_func(url, required_length)'
3262+
3263+
The function implementation should provide the following functionality:
3264+
3265+
'Given the 'url' and 'required_length' of the desired file, open a
3266+
connection to 'url', download it, and return the contents of the file.
3267+
Also ensure the length of the downloaded file matches 'required_length'
3268+
exactly'
3269+
3270+
If None, tuf.download.safe_download is used.
3271+
32403272
<Exceptions>
32413273
securesystemslib.exceptions.FormatError:
32423274
If 'target' is not properly formatted.
@@ -3294,6 +3326,6 @@ def download_target(self, target, destination_directory,
32943326
# '_get_target_file()' checks every mirror and returns the first target
32953327
# that passes verification.
32963328
target_file_object = self._get_target_file(target_filepath, trusted_length,
3297-
trusted_hashes, prefix_filename_with_hash)
3329+
trusted_hashes, prefix_filename_with_hash, custom_download_handler)
32983330

32993331
securesystemslib.util.persist_temp_file(target_file_object, destination)

0 commit comments

Comments
 (0)