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 = os.fspath(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)
def test_download_http_url__no_directory_traversal(tmpdir): """ 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 downloader = Downloader(session, progress_bar="on") download_dir = tmpdir.joinpath('download') os.mkdir(download_dir) file_path, content_type = _download_http_url( link, downloader, download_dir, hashes=None, ) # The file should be downloaded to download_dir. actual = os.listdir(download_dir) assert actual == ['out_dir_file']
def test_raise_for_status_does_not_raises_exception() -> None: contents = b"downloaded" resp = MockResponse(contents) resp.status_code = 201 resp.url = "http://www.example.com/whatever.tgz" resp.reason = "No error" raise_for_status(resp)
def test_raise_for_status_does_not_raises_exception(): contents = b'downloaded' resp = MockResponse(contents) resp.status_code = 201 resp.url = "http://www.example.com/whatever.tgz" resp.reason = "No error" return_value = raise_for_status(resp) assert return_value is None
def test_raise_for_status_raises_exception(status_code, error_type): contents = b'downloaded' resp = MockResponse(contents) resp.status_code = status_code resp.url = "http://www.example.com/whatever.tgz" resp.reason = "Network Error" with pytest.raises(NetworkConnectionError) as exc: raise_for_status(resp) assert str(exc.info) == ( "{} {}: Network Error for url:" " http://www.example.com/whatever.tgz".format( status_code, error_type) )
def test_prepare_download__log(caplog, url, headers, from_cache, expected): caplog.set_level(logging.INFO) resp = MockResponse(b'') resp.url = url resp.headers = headers if from_cache: resp.from_cache = from_cache link = Link(url) _prepare_download(resp, link, progress_bar="on") assert len(caplog.records) == 1 record = caplog.records[0] assert record.levelname == 'INFO' assert expected in record.message
def test_prepare_download__log( caplog: pytest.LogCaptureFixture, url: str, headers: Dict[str, str], from_cache: bool, expected: str, ) -> None: caplog.set_level(logging.INFO) resp = MockResponse(b"") resp.url = url resp.headers = headers if from_cache: resp.from_cache = from_cache link = Link(url) _prepare_download(resp, link, progress_bar="on") assert len(caplog.records) == 1 record = caplog.records[0] assert record.levelname == "INFO" assert expected in record.message
def test_keyring_set_password( monkeypatch: pytest.MonkeyPatch, response_status: int, creds: Tuple[str, str, bool], expect_save: bool, ) -> None: keyring = KeyringModuleV1() monkeypatch.setattr("pip._internal.network.auth.keyring", keyring) auth = MultiDomainBasicAuth(prompting=True) monkeypatch.setattr(auth, "_get_url_and_credentials", lambda u: (u, None, None)) monkeypatch.setattr(auth, "_prompt_for_password", lambda *a: creds) if creds[2]: # when _prompt_for_password indicates to save, we should save def should_save_password_to_keyring(*a: Any) -> bool: return True else: # when _prompt_for_password indicates not to save, we should # never call this function def should_save_password_to_keyring(*a: Any) -> bool: assert False, "_should_save_password_to_keyring should not be called" monkeypatch.setattr(auth, "_should_save_password_to_keyring", should_save_password_to_keyring) req = MockRequest("https://example.com") resp = MockResponse(b"") resp.url = req.url connection = MockConnection() def _send(sent_req: MockRequest, **kwargs: Any) -> MockResponse: assert sent_req is req assert "Authorization" in sent_req.headers r = MockResponse(b"") r.status_code = response_status return r # https://github.com/python/mypy/issues/2427 connection._send = _send # type: ignore[assignment] resp.request = req resp.status_code = 401 resp.connection = connection auth.handle_401(resp) if expect_save: assert keyring.saved_passwords == [("example.com", creds[0], creds[1])] else: assert keyring.saved_passwords == []
def test_unpack_http_url_bad_downloaded_checksum(mock_unpack_file): """ If already-downloaded file has bad checksum, re-download. """ base_url = 'http://www.example.com/somepackage.tgz' contents = b'downloaded' download_hash = hashlib.new('sha1', contents) link = Link(base_url + '#sha1=' + download_hash.hexdigest()) session = Mock() session.get = Mock() response = session.get.return_value = MockResponse(contents) response.headers = {'content-type': 'application/x-tar'} response.url = base_url downloader = Downloader(session, progress_bar="on") download_dir = mkdtemp() try: downloaded_file = os.path.join(download_dir, 'somepackage.tgz') create_file(downloaded_file, 'some contents') unpack_http_url(link, 'location', downloader=downloader, download_dir=download_dir, hashes=Hashes({'sha1': [download_hash.hexdigest()]})) # despite existence of downloaded file with bad hash, downloaded again session.get.assert_called_once_with( 'http://www.example.com/somepackage.tgz', headers={"Accept-Encoding": "identity"}, stream=True, ) # cached file is replaced with newly downloaded file with open(downloaded_file) as fh: assert fh.read() == 'downloaded' finally: rmtree(download_dir)
def test_keyring_set_password(monkeypatch, response_status, creds, expect_save): keyring = KeyringModuleV1() monkeypatch.setattr('pip._internal.network.auth.keyring', keyring) auth = MultiDomainBasicAuth(prompting=True) monkeypatch.setattr(auth, '_get_url_and_credentials', lambda u: (u, None, None)) monkeypatch.setattr(auth, '_prompt_for_password', lambda *a: creds) if creds[2]: # when _prompt_for_password indicates to save, we should save def should_save_password_to_keyring(*a): return True else: # when _prompt_for_password indicates not to save, we should # never call this function def should_save_password_to_keyring(*a): assert False, ("_should_save_password_to_keyring should not be " + "called") monkeypatch.setattr(auth, '_should_save_password_to_keyring', should_save_password_to_keyring) req = MockRequest("https://example.com") resp = MockResponse(b"") resp.url = req.url connection = MockConnection() def _send(sent_req, **kwargs): assert sent_req is req assert "Authorization" in sent_req.headers r = MockResponse(b"") r.status_code = response_status return r connection._send = _send resp.request = req resp.status_code = 401 resp.connection = connection auth.handle_401(resp) if expect_save: assert keyring.saved_passwords == [("example.com", creds[0], creds[1])] else: assert keyring.saved_passwords == []
def _send(sent_req, **kwargs): assert sent_req is req assert "Authorization" in sent_req.headers r = MockResponse(b"") r.status_code = response_status return r
def test_dist_from_wheel_url_no_range(session, monkeypatch): """Test handling when HTTP range requests are not supported.""" monkeypatch.setattr(session, 'head', lambda *a, **kw: MockResponse(b'')) with raises(RuntimeError): dist_from_wheel_url('mypy', MYPY_0_782_WHL, session)