Skip to content

Commit 1596de2

Browse files
committed
Move download.py functions to FetcherInterface
Make download_file and download_bytes functions part of the FetcherInterface class. Remove download.py module. Signed-off-by: Teodora Sechkova <[email protected]>
1 parent 16f42fc commit 1596de2

File tree

3 files changed

+62
-79
lines changed

3 files changed

+62
-79
lines changed

tuf/ngclient/_internal/download.py

Lines changed: 0 additions & 69 deletions
This file was deleted.

tuf/ngclient/fetcher.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66

77
# Imports
88
import abc
9-
from typing import Iterator
9+
import logging
10+
import tempfile
11+
from contextlib import contextmanager
12+
from typing import IO, Iterator
13+
from urllib import parse
14+
15+
from tuf import exceptions
16+
17+
logger = logging.getLogger(__name__)
1018

1119

1220
# Classes
@@ -40,3 +48,51 @@ def fetch(self, url: str, required_length: int) -> Iterator[bytes]:
4048
A bytes iterator
4149
"""
4250
raise NotImplementedError # pragma: no cover
51+
52+
@contextmanager
53+
def download_file(self, url: str, required_length: int) -> Iterator[IO]:
54+
"""Opens a connection to 'url' and downloads the content
55+
up to 'required_length'.
56+
57+
Args:
58+
url: a URL string that represents the location of the file.
59+
required_length: an integer value representing the length of
60+
the file or an upper boundary.
61+
62+
Raises:
63+
DownloadLengthMismatchError: a mismatch of observed vs expected
64+
lengths while downloading the file.
65+
66+
Yields:
67+
A file object that points to the contents of 'url'.
68+
"""
69+
# 'url.replace('\\', '/')' is needed for compatibility with
70+
# Windows-based systems, because they might use back-slashes in place
71+
# of forward-slashes. This converts it to the common format.
72+
# unquote() replaces %xx escapes in a url with their single-character
73+
# equivalent. A back-slash may beencoded as %5c in the url, which
74+
# should also be replaced with a forward slash.
75+
url = parse.unquote(url).replace("\\", "/")
76+
logger.debug("Downloading: %s", url)
77+
78+
number_of_bytes_received = 0
79+
80+
with tempfile.TemporaryFile() as temp_file:
81+
chunks = self.fetch(url, required_length)
82+
for chunk in chunks:
83+
temp_file.write(chunk)
84+
number_of_bytes_received += len(chunk)
85+
if number_of_bytes_received > required_length:
86+
raise exceptions.DownloadLengthMismatchError(
87+
required_length, number_of_bytes_received
88+
)
89+
temp_file.seek(0)
90+
yield temp_file
91+
92+
def download_bytes(self, url: str, required_length: int) -> bytes:
93+
"""Download bytes from given url
94+
95+
Returns the downloaded bytes, otherwise like download_file()
96+
"""
97+
with self.download_file(url, required_length) as dl_file:
98+
return dl_file.read()

tuf/ngclient/updater.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
from securesystemslib import util as sslib_util
1515

1616
from tuf import exceptions
17-
from tuf.ngclient._internal import (
18-
download,
19-
requests_fetcher,
20-
trusted_metadata_set,
21-
)
17+
from tuf.ngclient._internal import requests_fetcher, trusted_metadata_set
2218
from tuf.ngclient.config import UpdaterConfig
2319
from tuf.ngclient.fetcher import FetcherInterface
2420

@@ -27,7 +23,7 @@
2723

2824
class Updater:
2925
"""
30-
An implemetation of the TUF client workflow.
26+
An implementation of the TUF client workflow.
3127
Provides a public API for integration in client applications.
3228
"""
3329

@@ -193,8 +189,8 @@ def download_target(
193189
target_fileinfo: "TargetFile" = targetinfo["fileinfo"]
194190
full_url = parse.urljoin(target_base_url, target_filepath)
195191

196-
with download.download_file(
197-
full_url, target_fileinfo.length, self._fetcher
192+
with self._fetcher.download_file(
193+
full_url, target_fileinfo.length
198194
) as target_file:
199195
try:
200196
target_fileinfo.verify_length_and_hashes(target_file)
@@ -215,7 +211,7 @@ def _download_metadata(
215211
else:
216212
filename = f"{version}.{rolename}.json"
217213
url = parse.urljoin(self._metadata_base_url, filename)
218-
return download.download_bytes(url, length, self._fetcher)
214+
return self._fetcher.download_bytes(url, length)
219215

220216
def _load_local_metadata(self, rolename: str) -> bytes:
221217
with open(os.path.join(self._dir, f"{rolename}.json"), "rb") as f:

0 commit comments

Comments
 (0)