|
8 | 8 |
|
9 | 9 | import os.path
|
10 | 10 | import socket # noqa: F401
|
| 11 | +import typing |
11 | 12 |
|
12 | 13 | from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
|
13 | 14 | from urllib3.exceptions import HTTPError as _HTTPError
|
@@ -61,12 +62,38 @@ def SOCKSProxyManager(*args, **kwargs):
|
61 | 62 | raise InvalidSchema("Missing dependencies for SOCKS support.")
|
62 | 63 |
|
63 | 64 |
|
| 65 | +if typing.TYPE_CHECKING: |
| 66 | + from .models import PreparedRequest |
| 67 | + |
| 68 | + |
64 | 69 | DEFAULT_POOLBLOCK = False
|
65 | 70 | DEFAULT_POOLSIZE = 10
|
66 | 71 | DEFAULT_RETRIES = 0
|
67 | 72 | DEFAULT_POOL_TIMEOUT = None
|
68 | 73 |
|
69 | 74 |
|
| 75 | +def _urllib3_request_context( |
| 76 | + request: "PreparedRequest", verify: "bool | str | None" |
| 77 | +) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])": |
| 78 | + host_params = {} |
| 79 | + pool_kwargs = {} |
| 80 | + parsed_request_url = urlparse(request.url) |
| 81 | + scheme = parsed_request_url.scheme.lower() |
| 82 | + port = parsed_request_url.port |
| 83 | + cert_reqs = "CERT_REQUIRED" |
| 84 | + if verify is False: |
| 85 | + cert_reqs = "CERT_NONE" |
| 86 | + if isinstance(verify, str): |
| 87 | + pool_kwargs["ca_certs"] = verify |
| 88 | + pool_kwargs["cert_reqs"] = cert_reqs |
| 89 | + host_params = { |
| 90 | + "scheme": scheme, |
| 91 | + "host": parsed_request_url.hostname, |
| 92 | + "port": port, |
| 93 | + } |
| 94 | + return host_params, pool_kwargs |
| 95 | + |
| 96 | + |
70 | 97 | class BaseAdapter:
|
71 | 98 | """The Base Transport Adapter"""
|
72 | 99 |
|
@@ -327,6 +354,35 @@ def build_response(self, req, resp):
|
327 | 354 |
|
328 | 355 | return response
|
329 | 356 |
|
| 357 | + def _get_connection(self, request, verify, proxies=None): |
| 358 | + # Replace the existing get_connection without breaking things and |
| 359 | + # ensure that TLS settings are considered when we interact with |
| 360 | + # urllib3 HTTP Pools |
| 361 | + proxy = select_proxy(request.url, proxies) |
| 362 | + try: |
| 363 | + host_params, pool_kwargs = _urllib3_request_context(request, verify) |
| 364 | + except ValueError as e: |
| 365 | + raise InvalidURL(e, request=request) |
| 366 | + if proxy: |
| 367 | + proxy = prepend_scheme_if_needed(proxy, "http") |
| 368 | + proxy_url = parse_url(proxy) |
| 369 | + if not proxy_url.host: |
| 370 | + raise InvalidProxyURL( |
| 371 | + "Please check proxy URL. It is malformed " |
| 372 | + "and could be missing the host." |
| 373 | + ) |
| 374 | + proxy_manager = self.proxy_manager_for(proxy) |
| 375 | + conn = proxy_manager.connection_from_host( |
| 376 | + **host_params, pool_kwargs=pool_kwargs |
| 377 | + ) |
| 378 | + else: |
| 379 | + # Only scheme should be lower case |
| 380 | + conn = self.poolmanager.connection_from_host( |
| 381 | + **host_params, pool_kwargs=pool_kwargs |
| 382 | + ) |
| 383 | + |
| 384 | + return conn |
| 385 | + |
330 | 386 | def get_connection(self, url, proxies=None):
|
331 | 387 | """Returns a urllib3 connection for the given URL. This should not be
|
332 | 388 | called from user code, and is only exposed for use when subclassing the
|
@@ -453,7 +509,7 @@ def send(
|
453 | 509 | """
|
454 | 510 |
|
455 | 511 | try:
|
456 |
| - conn = self.get_connection(request.url, proxies) |
| 512 | + conn = self._get_connection(request, verify, proxies) |
457 | 513 | except LocationValueError as e:
|
458 | 514 | raise InvalidURL(e, request=request)
|
459 | 515 |
|
|
0 commit comments