Skip to content

Commit

Permalink
Merge pull request #7885 from NoahGorny/cache-trusted-host
Browse files Browse the repository at this point in the history
Cache trusted host
  • Loading branch information
pradyunsg authored Apr 13, 2020
2 parents f458573 + 2050ecc commit 3c1cf3e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 23 deletions.
1 change: 1 addition & 0 deletions news/7847.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change default behaviour to always cache responses from trusted-host source.
40 changes: 28 additions & 12 deletions src/pip/_internal/network/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ def cert_verify(self, conn, url, verify, cert):
)


class InsecureCacheControlAdapter(CacheControlAdapter):

def cert_verify(self, conn, url, verify, cert):
super(InsecureCacheControlAdapter, self).cert_verify(
conn=conn, url=url, verify=False, cert=cert
)


class PipSession(requests.Session):

timeout = None # type: Optional[int]
Expand Down Expand Up @@ -263,25 +271,30 @@ def __init__(self, *args, **kwargs):
backoff_factor=0.25,
)

# We want to _only_ cache responses on securely fetched origins. We do
# this because we can't validate the response of an insecurely fetched
# Our Insecure HTTPAdapter disables HTTPS validation. It does not
# support caching so we'll use it for all http:// URLs.
# If caching is disabled, we will also use it for
# https:// hosts that we've marked as ignoring
# TLS errors for (trusted-hosts).
insecure_adapter = InsecureHTTPAdapter(max_retries=retries)

# We want to _only_ cache responses on securely fetched origins or when
# the host is specified as trusted. We do this because
# we can't validate the response of an insecurely/untrusted fetched
# origin, and we don't want someone to be able to poison the cache and
# require manual eviction from the cache to fix it.
if cache:
secure_adapter = CacheControlAdapter(
cache=SafeFileCache(cache),
max_retries=retries,
)
self._trusted_host_adapter = InsecureCacheControlAdapter(
cache=SafeFileCache(cache),
max_retries=retries,
)
else:
secure_adapter = HTTPAdapter(max_retries=retries)

# Our Insecure HTTPAdapter disables HTTPS validation. It does not
# support caching (see above) so we'll use it for all http:// URLs as
# well as any https:// host that we've marked as ignoring TLS errors
# for.
insecure_adapter = InsecureHTTPAdapter(max_retries=retries)
# Save this for later use in add_insecure_host().
self._insecure_adapter = insecure_adapter
self._trusted_host_adapter = insecure_adapter

self.mount("https://", secure_adapter)
self.mount("http://", insecure_adapter)
Expand Down Expand Up @@ -310,12 +323,15 @@ def add_trusted_host(self, host, source=None, suppress_logging=False):
if host_port not in self.pip_trusted_origins:
self.pip_trusted_origins.append(host_port)

self.mount(build_url_from_netloc(host) + '/', self._insecure_adapter)
self.mount(
build_url_from_netloc(host) + '/',
self._trusted_host_adapter
)
if not host_port[1]:
# Mount wildcard ports for the same host.
self.mount(
build_url_from_netloc(host) + ':',
self._insecure_adapter
self._trusted_host_adapter
)

def iter_secure_origins(self):
Expand Down
18 changes: 9 additions & 9 deletions tests/unit/test_network_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_http_cache_is_not_enabled(self, tmpdir):

assert not hasattr(session.adapters["http://"], "cache")

def test_insecure_host_adapter(self, tmpdir):
def test_trusted_hosts_adapter(self, tmpdir):
session = PipSession(
cache=tmpdir.joinpath("test-cache"),
trusted_hosts=["example.com"],
Expand All @@ -81,14 +81,14 @@ def test_insecure_host_adapter(self, tmpdir):
assert "https://example.com/" in session.adapters
# Check that the "port wildcard" is present.
assert "https://example.com:" in session.adapters
# Check that the cache isn't enabled.
assert not hasattr(session.adapters["https://example.com/"], "cache")
# Check that the cache is enabled.
assert hasattr(session.adapters["https://example.com/"], "cache")

def test_add_trusted_host(self):
# Leave a gap to test how the ordering is affected.
trusted_hosts = ['host1', 'host3']
session = PipSession(trusted_hosts=trusted_hosts)
insecure_adapter = session._insecure_adapter
trusted_host_adapter = session._trusted_host_adapter
prefix2 = 'https://host2/'
prefix3 = 'https://host3/'
prefix3_wildcard = 'https://host3:'
Expand All @@ -97,8 +97,8 @@ def test_add_trusted_host(self):
assert session.pip_trusted_origins == [
('host1', None), ('host3', None)
]
assert session.adapters[prefix3] is insecure_adapter
assert session.adapters[prefix3_wildcard] is insecure_adapter
assert session.adapters[prefix3] is trusted_host_adapter
assert session.adapters[prefix3_wildcard] is trusted_host_adapter

assert prefix2 not in session.adapters

Expand All @@ -108,8 +108,8 @@ def test_add_trusted_host(self):
('host1', None), ('host3', None), ('host2', None)
]
# Check that prefix3 is still present.
assert session.adapters[prefix3] is insecure_adapter
assert session.adapters[prefix2] is insecure_adapter
assert session.adapters[prefix3] is trusted_host_adapter
assert session.adapters[prefix2] is trusted_host_adapter

# Test that adding the same host doesn't create a duplicate.
session.add_trusted_host('host3')
Expand All @@ -123,7 +123,7 @@ def test_add_trusted_host(self):
('host1', None), ('host3', None),
('host2', None), ('host4', 8080)
]
assert session.adapters[prefix4] is insecure_adapter
assert session.adapters[prefix4] is trusted_host_adapter

def test_add_trusted_host__logging(self, caplog):
"""
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/test_req_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,13 @@ def test_set_finder_trusted_host(
)
assert list(finder.trusted_hosts) == ['host1', 'host2:8080']
session = finder._link_collector.session
assert session.adapters['https://host1/'] is session._insecure_adapter
assert (
session.adapters['https://host1/']
is session._trusted_host_adapter
)
assert (
session.adapters['https://host2:8080/']
is session._insecure_adapter
is session._trusted_host_adapter
)

# Test the log message.
Expand Down

0 comments on commit 3c1cf3e

Please sign in to comment.