mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
These were intended to help users transition when the default behaviour changed to no longer perform out-of-tree builds. The transition is now considered complete.
136 lines
4.6 KiB
Python
136 lines
4.6 KiB
Python
import os
|
|
import shutil
|
|
from shutil import rmtree
|
|
from tempfile import mkdtemp
|
|
from typing import Any, Dict
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
|
|
from pip._internal.exceptions import HashMismatch
|
|
from pip._internal.models.link import Link
|
|
from pip._internal.network.download import Downloader
|
|
from pip._internal.network.session import PipSession
|
|
from pip._internal.operations.prepare import unpack_url
|
|
from pip._internal.utils.hashes import Hashes
|
|
from pip._internal.utils.urls import path_to_url
|
|
from tests.lib import TestData
|
|
from tests.lib.path import Path
|
|
from tests.lib.requests_mocks import MockResponse
|
|
|
|
|
|
def test_unpack_url_with_urllib_response_without_content_type(data: TestData) -> None:
|
|
"""
|
|
It should download and unpack files even if no Content-Type header exists
|
|
"""
|
|
_real_session = PipSession()
|
|
|
|
def _fake_session_get(*args: Any, **kwargs: Any) -> Dict[str, str]:
|
|
resp = _real_session.get(*args, **kwargs)
|
|
del resp.headers["Content-Type"]
|
|
return resp
|
|
|
|
session = Mock()
|
|
session.get = _fake_session_get
|
|
download = Downloader(session, progress_bar="on")
|
|
|
|
uri = path_to_url(data.packages.joinpath("simple-1.0.tar.gz"))
|
|
link = Link(uri)
|
|
temp_dir = mkdtemp()
|
|
try:
|
|
unpack_url(
|
|
link,
|
|
temp_dir,
|
|
download=download,
|
|
download_dir=None,
|
|
verbosity=0,
|
|
)
|
|
assert set(os.listdir(temp_dir)) == {
|
|
"PKG-INFO",
|
|
"setup.cfg",
|
|
"setup.py",
|
|
"simple",
|
|
"simple.egg-info",
|
|
}
|
|
finally:
|
|
rmtree(temp_dir)
|
|
|
|
|
|
@patch("pip._internal.network.download.raise_for_status")
|
|
def test_download_http_url__no_directory_traversal(
|
|
mock_raise_for_status: Mock, tmpdir: Path
|
|
) -> None:
|
|
"""
|
|
Test that directory traversal doesn't happen on download when the
|
|
Content-Disposition header contains a filename with a ".." path part.
|
|
"""
|
|
mock_url = "http://www.example.com/whatever.tgz"
|
|
contents = b"downloaded"
|
|
link = Link(mock_url)
|
|
|
|
session = Mock()
|
|
resp = MockResponse(contents)
|
|
resp.url = mock_url
|
|
resp.headers = {
|
|
# Set the content-type to a random value to prevent
|
|
# mimetypes.guess_extension from guessing the extension.
|
|
"content-type": "random",
|
|
"content-disposition": 'attachment;filename="../out_dir_file"',
|
|
}
|
|
session.get.return_value = resp
|
|
download = Downloader(session, progress_bar="on")
|
|
|
|
download_dir = tmpdir.joinpath("download")
|
|
os.mkdir(download_dir)
|
|
file_path, content_type = download(link, download_dir)
|
|
# The file should be downloaded to download_dir.
|
|
actual = os.listdir(download_dir)
|
|
assert actual == ["out_dir_file"]
|
|
mock_raise_for_status.assert_called_once_with(resp)
|
|
|
|
|
|
@pytest.fixture
|
|
def clean_project(tmpdir_factory: pytest.TempdirFactory, data: TestData) -> Path:
|
|
tmpdir = Path(str(tmpdir_factory.mktemp("clean_project")))
|
|
new_project_dir = tmpdir.joinpath("FSPkg")
|
|
path = data.packages.joinpath("FSPkg")
|
|
shutil.copytree(path, new_project_dir)
|
|
return new_project_dir
|
|
|
|
|
|
class Test_unpack_url:
|
|
def prep(self, tmpdir: Path, data: TestData) -> None:
|
|
self.build_dir = tmpdir.joinpath("build")
|
|
self.download_dir = tmpdir.joinpath("download")
|
|
os.mkdir(self.build_dir)
|
|
os.mkdir(self.download_dir)
|
|
self.dist_file = "simple-1.0.tar.gz"
|
|
self.dist_file2 = "simple-2.0.tar.gz"
|
|
self.dist_path = data.packages.joinpath(self.dist_file)
|
|
self.dist_path2 = data.packages.joinpath(self.dist_file2)
|
|
self.dist_url = Link(path_to_url(self.dist_path))
|
|
self.dist_url2 = Link(path_to_url(self.dist_path2))
|
|
self.no_download = Mock(side_effect=AssertionError)
|
|
|
|
def test_unpack_url_no_download(self, tmpdir: Path, data: TestData) -> None:
|
|
self.prep(tmpdir, data)
|
|
unpack_url(self.dist_url, self.build_dir, self.no_download, verbosity=0)
|
|
assert os.path.isdir(os.path.join(self.build_dir, "simple"))
|
|
assert not os.path.isfile(os.path.join(self.download_dir, self.dist_file))
|
|
|
|
def test_unpack_url_bad_hash(self, tmpdir: Path, data: TestData) -> None:
|
|
"""
|
|
Test when the file url hash fragment is wrong
|
|
"""
|
|
self.prep(tmpdir, data)
|
|
url = f"{self.dist_url.url}#md5=bogus"
|
|
dist_url = Link(url)
|
|
with pytest.raises(HashMismatch):
|
|
unpack_url(
|
|
dist_url,
|
|
self.build_dir,
|
|
download=self.no_download,
|
|
hashes=Hashes({"md5": ["bogus"]}),
|
|
verbosity=0,
|
|
)
|