mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 06:46:15 +00:00
Use TLS settings in selecting connection pool
Previously, if someone made a request with `verify=False` then made a request where they expected verification to be enabled to the same host, they would potentially reuse a connection where TLS had not been verified. This fixes that issue.
This commit is contained in:
@@ -8,6 +8,7 @@ and maintain connections.
|
|||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import socket # noqa: F401
|
import socket # noqa: F401
|
||||||
|
import typing
|
||||||
|
|
||||||
from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
|
from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
|
||||||
from urllib3.exceptions import HTTPError as _HTTPError
|
from urllib3.exceptions import HTTPError as _HTTPError
|
||||||
@@ -61,12 +62,38 @@ except ImportError:
|
|||||||
raise InvalidSchema("Missing dependencies for SOCKS support.")
|
raise InvalidSchema("Missing dependencies for SOCKS support.")
|
||||||
|
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from .models import PreparedRequest
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_POOLBLOCK = False
|
DEFAULT_POOLBLOCK = False
|
||||||
DEFAULT_POOLSIZE = 10
|
DEFAULT_POOLSIZE = 10
|
||||||
DEFAULT_RETRIES = 0
|
DEFAULT_RETRIES = 0
|
||||||
DEFAULT_POOL_TIMEOUT = None
|
DEFAULT_POOL_TIMEOUT = None
|
||||||
|
|
||||||
|
|
||||||
|
def _urllib3_request_context(
|
||||||
|
request: "PreparedRequest", verify: "bool | str | None"
|
||||||
|
) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
|
||||||
|
host_params = {}
|
||||||
|
pool_kwargs = {}
|
||||||
|
parsed_request_url = urlparse(request.url)
|
||||||
|
scheme = parsed_request_url.scheme.lower()
|
||||||
|
port = parsed_request_url.port
|
||||||
|
cert_reqs = "CERT_REQUIRED"
|
||||||
|
if verify is False:
|
||||||
|
cert_reqs = "CERT_NONE"
|
||||||
|
if isinstance(verify, str):
|
||||||
|
pool_kwargs["ca_certs"] = verify
|
||||||
|
pool_kwargs["cert_reqs"] = cert_reqs
|
||||||
|
host_params = {
|
||||||
|
"scheme": scheme,
|
||||||
|
"host": parsed_request_url.hostname,
|
||||||
|
"port": port,
|
||||||
|
}
|
||||||
|
return host_params, pool_kwargs
|
||||||
|
|
||||||
|
|
||||||
class BaseAdapter:
|
class BaseAdapter:
|
||||||
"""The Base Transport Adapter"""
|
"""The Base Transport Adapter"""
|
||||||
|
|
||||||
@@ -327,6 +354,35 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def _get_connection(self, request, verify, proxies=None):
|
||||||
|
# Replace the existing get_connection without breaking things and
|
||||||
|
# ensure that TLS settings are considered when we interact with
|
||||||
|
# urllib3 HTTP Pools
|
||||||
|
proxy = select_proxy(request.url, proxies)
|
||||||
|
try:
|
||||||
|
host_params, pool_kwargs = _urllib3_request_context(request, verify)
|
||||||
|
except ValueError as e:
|
||||||
|
raise InvalidURL(e, request=request)
|
||||||
|
if proxy:
|
||||||
|
proxy = prepend_scheme_if_needed(proxy, "http")
|
||||||
|
proxy_url = parse_url(proxy)
|
||||||
|
if not proxy_url.host:
|
||||||
|
raise InvalidProxyURL(
|
||||||
|
"Please check proxy URL. It is malformed "
|
||||||
|
"and could be missing the host."
|
||||||
|
)
|
||||||
|
proxy_manager = self.proxy_manager_for(proxy)
|
||||||
|
conn = proxy_manager.connection_from_host(
|
||||||
|
**host_params, pool_kwargs=pool_kwargs
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Only scheme should be lower case
|
||||||
|
conn = self.poolmanager.connection_from_host(
|
||||||
|
**host_params, pool_kwargs=pool_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
return conn
|
||||||
|
|
||||||
def get_connection(self, url, proxies=None):
|
def get_connection(self, url, proxies=None):
|
||||||
"""Returns a urllib3 connection for the given URL. This should not be
|
"""Returns a urllib3 connection for the given URL. This should not be
|
||||||
called from user code, and is only exposed for use when subclassing the
|
called from user code, and is only exposed for use when subclassing the
|
||||||
@@ -453,7 +509,7 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.get_connection(request.url, proxies)
|
conn = self._get_connection(request, verify, proxies)
|
||||||
except LocationValueError as e:
|
except LocationValueError as e:
|
||||||
raise InvalidURL(e, request=request)
|
raise InvalidURL(e, request=request)
|
||||||
|
|
||||||
|
|||||||
@@ -2828,6 +2828,13 @@ class TestPreparingURLs:
|
|||||||
assert r5 == 425
|
assert r5 == 425
|
||||||
assert r6 == 425
|
assert r6 == 425
|
||||||
|
|
||||||
|
def test_different_connection_pool_for_tls_settings(self):
|
||||||
|
s = requests.Session()
|
||||||
|
r1 = s.get("https://invalid.badssl.com", verify=False)
|
||||||
|
assert r1.status_code == 421
|
||||||
|
with pytest.raises(requests.exceptions.SSLError):
|
||||||
|
s.get("https://invalid.badssl.com")
|
||||||
|
|
||||||
|
|
||||||
def test_json_decode_errors_are_serializable_deserializable():
|
def test_json_decode_errors_are_serializable_deserializable():
|
||||||
json_decode_error = requests.exceptions.JSONDecodeError(
|
json_decode_error = requests.exceptions.JSONDecodeError(
|
||||||
|
|||||||
Reference in New Issue
Block a user