예제 #1
0
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)
예제 #2
0
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']
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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)
        )
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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 == []
예제 #9
0
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)
예제 #10
0
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 == []
예제 #11
0
 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
예제 #12
0
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)