Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 53 additions & 11 deletions setuptools/package_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,21 +807,63 @@ def open_url(self, url, warning=None): # noqa: C901 # is too complex (12)
else:
raise DistutilsError(f"Download error for {url}: {v}") from v

def _download_url(self, url, tmpdir):
# Determine download filename
#
@staticmethod
def _sanitize(name):
r"""
Replace unsafe path directives with underscores.

>>> san = PackageIndex._sanitize
>>> san('/home/user/.ssh/authorized_keys')
'_home_user_.ssh_authorized_keys'
>>> san('..\\foo\\bing')
'__foo_bing'
>>> san('D:bar')
'D_bar'
>>> san('C:\\bar')
'C__bar'
>>> san('foo..bar')
'foo..bar'
>>> san('D:../foo')
'D___foo'
"""
pattern = '|'.join((
# drive letters
r':',
# path separators
r'[/\\]',
# parent dirs
r'(?:(?<=([/\\]|:))\.\.(?=[/\\]|$))|(?:^\.\.(?=[/\\]|$))',
))
return re.sub(pattern, r'_', name)

@classmethod
def _resolve_download_filename(cls, url, tmpdir):
"""
>>> import pathlib
>>> du = PackageIndex._resolve_download_filename
>>> root = getfixture('tmp_path')
>>> url = 'https://files.pythonhosted.org/packages/a9/5a/0db.../setuptools-78.1.0.tar.gz'
>>> str(pathlib.Path(du(url, root)).relative_to(root))
'setuptools-78.1.0.tar.gz'
"""
name, _fragment = egg_info_for_url(url)
if name:
while '..' in name:
name = name.replace('..', '.').replace('\\', '_')
else:
name = "__downloaded__" # default if URL has no path contents
name = cls._sanitize(
name
or
# default if URL has no path contents
'__downloaded__'
)

if name.endswith('.egg.zip'):
name = name[:-4] # strip the extra .zip before download
# strip any extra .zip before download
name = re.sub(r'\.egg\.zip$', '.egg', name)

filename = os.path.join(tmpdir, name)
return os.path.join(tmpdir, name)

def _download_url(self, url, tmpdir):
"""
Determine the download filename.
"""
filename = self._resolve_download_filename(url, tmpdir)
return self._download_vcs(url, filename) or self._download_other(url, filename)

@staticmethod
Expand Down