annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/requests/adapters.py @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
rev   line source
jpayne@69 1 """
jpayne@69 2 requests.adapters
jpayne@69 3 ~~~~~~~~~~~~~~~~~
jpayne@69 4
jpayne@69 5 This module contains the transport adapters that Requests uses to define
jpayne@69 6 and maintain connections.
jpayne@69 7 """
jpayne@69 8
jpayne@69 9 import os.path
jpayne@69 10 import socket # noqa: F401
jpayne@69 11 import typing
jpayne@69 12 import warnings
jpayne@69 13
jpayne@69 14 from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
jpayne@69 15 from urllib3.exceptions import HTTPError as _HTTPError
jpayne@69 16 from urllib3.exceptions import InvalidHeader as _InvalidHeader
jpayne@69 17 from urllib3.exceptions import (
jpayne@69 18 LocationValueError,
jpayne@69 19 MaxRetryError,
jpayne@69 20 NewConnectionError,
jpayne@69 21 ProtocolError,
jpayne@69 22 )
jpayne@69 23 from urllib3.exceptions import ProxyError as _ProxyError
jpayne@69 24 from urllib3.exceptions import ReadTimeoutError, ResponseError
jpayne@69 25 from urllib3.exceptions import SSLError as _SSLError
jpayne@69 26 from urllib3.poolmanager import PoolManager, proxy_from_url
jpayne@69 27 from urllib3.util import Timeout as TimeoutSauce
jpayne@69 28 from urllib3.util import parse_url
jpayne@69 29 from urllib3.util.retry import Retry
jpayne@69 30 from urllib3.util.ssl_ import create_urllib3_context
jpayne@69 31
jpayne@69 32 from .auth import _basic_auth_str
jpayne@69 33 from .compat import basestring, urlparse
jpayne@69 34 from .cookies import extract_cookies_to_jar
jpayne@69 35 from .exceptions import (
jpayne@69 36 ConnectionError,
jpayne@69 37 ConnectTimeout,
jpayne@69 38 InvalidHeader,
jpayne@69 39 InvalidProxyURL,
jpayne@69 40 InvalidSchema,
jpayne@69 41 InvalidURL,
jpayne@69 42 ProxyError,
jpayne@69 43 ReadTimeout,
jpayne@69 44 RetryError,
jpayne@69 45 SSLError,
jpayne@69 46 )
jpayne@69 47 from .models import Response
jpayne@69 48 from .structures import CaseInsensitiveDict
jpayne@69 49 from .utils import (
jpayne@69 50 DEFAULT_CA_BUNDLE_PATH,
jpayne@69 51 extract_zipped_paths,
jpayne@69 52 get_auth_from_url,
jpayne@69 53 get_encoding_from_headers,
jpayne@69 54 prepend_scheme_if_needed,
jpayne@69 55 select_proxy,
jpayne@69 56 urldefragauth,
jpayne@69 57 )
jpayne@69 58
jpayne@69 59 try:
jpayne@69 60 from urllib3.contrib.socks import SOCKSProxyManager
jpayne@69 61 except ImportError:
jpayne@69 62
jpayne@69 63 def SOCKSProxyManager(*args, **kwargs):
jpayne@69 64 raise InvalidSchema("Missing dependencies for SOCKS support.")
jpayne@69 65
jpayne@69 66
jpayne@69 67 if typing.TYPE_CHECKING:
jpayne@69 68 from .models import PreparedRequest
jpayne@69 69
jpayne@69 70
jpayne@69 71 DEFAULT_POOLBLOCK = False
jpayne@69 72 DEFAULT_POOLSIZE = 10
jpayne@69 73 DEFAULT_RETRIES = 0
jpayne@69 74 DEFAULT_POOL_TIMEOUT = None
jpayne@69 75
jpayne@69 76
jpayne@69 77 try:
jpayne@69 78 import ssl # noqa: F401
jpayne@69 79
jpayne@69 80 _preloaded_ssl_context = create_urllib3_context()
jpayne@69 81 _preloaded_ssl_context.load_verify_locations(
jpayne@69 82 extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
jpayne@69 83 )
jpayne@69 84 except ImportError:
jpayne@69 85 # Bypass default SSLContext creation when Python
jpayne@69 86 # interpreter isn't built with the ssl module.
jpayne@69 87 _preloaded_ssl_context = None
jpayne@69 88
jpayne@69 89
jpayne@69 90 def _urllib3_request_context(
jpayne@69 91 request: "PreparedRequest",
jpayne@69 92 verify: "bool | str | None",
jpayne@69 93 client_cert: "typing.Tuple[str, str] | str | None",
jpayne@69 94 poolmanager: "PoolManager",
jpayne@69 95 ) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
jpayne@69 96 host_params = {}
jpayne@69 97 pool_kwargs = {}
jpayne@69 98 parsed_request_url = urlparse(request.url)
jpayne@69 99 scheme = parsed_request_url.scheme.lower()
jpayne@69 100 port = parsed_request_url.port
jpayne@69 101
jpayne@69 102 # Determine if we have and should use our default SSLContext
jpayne@69 103 # to optimize performance on standard requests.
jpayne@69 104 poolmanager_kwargs = getattr(poolmanager, "connection_pool_kw", {})
jpayne@69 105 has_poolmanager_ssl_context = poolmanager_kwargs.get("ssl_context")
jpayne@69 106 should_use_default_ssl_context = (
jpayne@69 107 _preloaded_ssl_context is not None and not has_poolmanager_ssl_context
jpayne@69 108 )
jpayne@69 109
jpayne@69 110 cert_reqs = "CERT_REQUIRED"
jpayne@69 111 if verify is False:
jpayne@69 112 cert_reqs = "CERT_NONE"
jpayne@69 113 elif verify is True and should_use_default_ssl_context:
jpayne@69 114 pool_kwargs["ssl_context"] = _preloaded_ssl_context
jpayne@69 115 elif isinstance(verify, str):
jpayne@69 116 if not os.path.isdir(verify):
jpayne@69 117 pool_kwargs["ca_certs"] = verify
jpayne@69 118 else:
jpayne@69 119 pool_kwargs["ca_cert_dir"] = verify
jpayne@69 120 pool_kwargs["cert_reqs"] = cert_reqs
jpayne@69 121 if client_cert is not None:
jpayne@69 122 if isinstance(client_cert, tuple) and len(client_cert) == 2:
jpayne@69 123 pool_kwargs["cert_file"] = client_cert[0]
jpayne@69 124 pool_kwargs["key_file"] = client_cert[1]
jpayne@69 125 else:
jpayne@69 126 # According to our docs, we allow users to specify just the client
jpayne@69 127 # cert path
jpayne@69 128 pool_kwargs["cert_file"] = client_cert
jpayne@69 129 host_params = {
jpayne@69 130 "scheme": scheme,
jpayne@69 131 "host": parsed_request_url.hostname,
jpayne@69 132 "port": port,
jpayne@69 133 }
jpayne@69 134 return host_params, pool_kwargs
jpayne@69 135
jpayne@69 136
jpayne@69 137 class BaseAdapter:
jpayne@69 138 """The Base Transport Adapter"""
jpayne@69 139
jpayne@69 140 def __init__(self):
jpayne@69 141 super().__init__()
jpayne@69 142
jpayne@69 143 def send(
jpayne@69 144 self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
jpayne@69 145 ):
jpayne@69 146 """Sends PreparedRequest object. Returns Response object.
jpayne@69 147
jpayne@69 148 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
jpayne@69 149 :param stream: (optional) Whether to stream the request content.
jpayne@69 150 :param timeout: (optional) How long to wait for the server to send
jpayne@69 151 data before giving up, as a float, or a :ref:`(connect timeout,
jpayne@69 152 read timeout) <timeouts>` tuple.
jpayne@69 153 :type timeout: float or tuple
jpayne@69 154 :param verify: (optional) Either a boolean, in which case it controls whether we verify
jpayne@69 155 the server's TLS certificate, or a string, in which case it must be a path
jpayne@69 156 to a CA bundle to use
jpayne@69 157 :param cert: (optional) Any user-provided SSL certificate to be trusted.
jpayne@69 158 :param proxies: (optional) The proxies dictionary to apply to the request.
jpayne@69 159 """
jpayne@69 160 raise NotImplementedError
jpayne@69 161
jpayne@69 162 def close(self):
jpayne@69 163 """Cleans up adapter specific items."""
jpayne@69 164 raise NotImplementedError
jpayne@69 165
jpayne@69 166
jpayne@69 167 class HTTPAdapter(BaseAdapter):
jpayne@69 168 """The built-in HTTP Adapter for urllib3.
jpayne@69 169
jpayne@69 170 Provides a general-case interface for Requests sessions to contact HTTP and
jpayne@69 171 HTTPS urls by implementing the Transport Adapter interface. This class will
jpayne@69 172 usually be created by the :class:`Session <Session>` class under the
jpayne@69 173 covers.
jpayne@69 174
jpayne@69 175 :param pool_connections: The number of urllib3 connection pools to cache.
jpayne@69 176 :param pool_maxsize: The maximum number of connections to save in the pool.
jpayne@69 177 :param max_retries: The maximum number of retries each connection
jpayne@69 178 should attempt. Note, this applies only to failed DNS lookups, socket
jpayne@69 179 connections and connection timeouts, never to requests where data has
jpayne@69 180 made it to the server. By default, Requests does not retry failed
jpayne@69 181 connections. If you need granular control over the conditions under
jpayne@69 182 which we retry a request, import urllib3's ``Retry`` class and pass
jpayne@69 183 that instead.
jpayne@69 184 :param pool_block: Whether the connection pool should block for connections.
jpayne@69 185
jpayne@69 186 Usage::
jpayne@69 187
jpayne@69 188 >>> import requests
jpayne@69 189 >>> s = requests.Session()
jpayne@69 190 >>> a = requests.adapters.HTTPAdapter(max_retries=3)
jpayne@69 191 >>> s.mount('http://', a)
jpayne@69 192 """
jpayne@69 193
jpayne@69 194 __attrs__ = [
jpayne@69 195 "max_retries",
jpayne@69 196 "config",
jpayne@69 197 "_pool_connections",
jpayne@69 198 "_pool_maxsize",
jpayne@69 199 "_pool_block",
jpayne@69 200 ]
jpayne@69 201
jpayne@69 202 def __init__(
jpayne@69 203 self,
jpayne@69 204 pool_connections=DEFAULT_POOLSIZE,
jpayne@69 205 pool_maxsize=DEFAULT_POOLSIZE,
jpayne@69 206 max_retries=DEFAULT_RETRIES,
jpayne@69 207 pool_block=DEFAULT_POOLBLOCK,
jpayne@69 208 ):
jpayne@69 209 if max_retries == DEFAULT_RETRIES:
jpayne@69 210 self.max_retries = Retry(0, read=False)
jpayne@69 211 else:
jpayne@69 212 self.max_retries = Retry.from_int(max_retries)
jpayne@69 213 self.config = {}
jpayne@69 214 self.proxy_manager = {}
jpayne@69 215
jpayne@69 216 super().__init__()
jpayne@69 217
jpayne@69 218 self._pool_connections = pool_connections
jpayne@69 219 self._pool_maxsize = pool_maxsize
jpayne@69 220 self._pool_block = pool_block
jpayne@69 221
jpayne@69 222 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
jpayne@69 223
jpayne@69 224 def __getstate__(self):
jpayne@69 225 return {attr: getattr(self, attr, None) for attr in self.__attrs__}
jpayne@69 226
jpayne@69 227 def __setstate__(self, state):
jpayne@69 228 # Can't handle by adding 'proxy_manager' to self.__attrs__ because
jpayne@69 229 # self.poolmanager uses a lambda function, which isn't pickleable.
jpayne@69 230 self.proxy_manager = {}
jpayne@69 231 self.config = {}
jpayne@69 232
jpayne@69 233 for attr, value in state.items():
jpayne@69 234 setattr(self, attr, value)
jpayne@69 235
jpayne@69 236 self.init_poolmanager(
jpayne@69 237 self._pool_connections, self._pool_maxsize, block=self._pool_block
jpayne@69 238 )
jpayne@69 239
jpayne@69 240 def init_poolmanager(
jpayne@69 241 self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs
jpayne@69 242 ):
jpayne@69 243 """Initializes a urllib3 PoolManager.
jpayne@69 244
jpayne@69 245 This method should not be called from user code, and is only
jpayne@69 246 exposed for use when subclassing the
jpayne@69 247 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 248
jpayne@69 249 :param connections: The number of urllib3 connection pools to cache.
jpayne@69 250 :param maxsize: The maximum number of connections to save in the pool.
jpayne@69 251 :param block: Block when no free connections are available.
jpayne@69 252 :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager.
jpayne@69 253 """
jpayne@69 254 # save these values for pickling
jpayne@69 255 self._pool_connections = connections
jpayne@69 256 self._pool_maxsize = maxsize
jpayne@69 257 self._pool_block = block
jpayne@69 258
jpayne@69 259 self.poolmanager = PoolManager(
jpayne@69 260 num_pools=connections,
jpayne@69 261 maxsize=maxsize,
jpayne@69 262 block=block,
jpayne@69 263 **pool_kwargs,
jpayne@69 264 )
jpayne@69 265
jpayne@69 266 def proxy_manager_for(self, proxy, **proxy_kwargs):
jpayne@69 267 """Return urllib3 ProxyManager for the given proxy.
jpayne@69 268
jpayne@69 269 This method should not be called from user code, and is only
jpayne@69 270 exposed for use when subclassing the
jpayne@69 271 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 272
jpayne@69 273 :param proxy: The proxy to return a urllib3 ProxyManager for.
jpayne@69 274 :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager.
jpayne@69 275 :returns: ProxyManager
jpayne@69 276 :rtype: urllib3.ProxyManager
jpayne@69 277 """
jpayne@69 278 if proxy in self.proxy_manager:
jpayne@69 279 manager = self.proxy_manager[proxy]
jpayne@69 280 elif proxy.lower().startswith("socks"):
jpayne@69 281 username, password = get_auth_from_url(proxy)
jpayne@69 282 manager = self.proxy_manager[proxy] = SOCKSProxyManager(
jpayne@69 283 proxy,
jpayne@69 284 username=username,
jpayne@69 285 password=password,
jpayne@69 286 num_pools=self._pool_connections,
jpayne@69 287 maxsize=self._pool_maxsize,
jpayne@69 288 block=self._pool_block,
jpayne@69 289 **proxy_kwargs,
jpayne@69 290 )
jpayne@69 291 else:
jpayne@69 292 proxy_headers = self.proxy_headers(proxy)
jpayne@69 293 manager = self.proxy_manager[proxy] = proxy_from_url(
jpayne@69 294 proxy,
jpayne@69 295 proxy_headers=proxy_headers,
jpayne@69 296 num_pools=self._pool_connections,
jpayne@69 297 maxsize=self._pool_maxsize,
jpayne@69 298 block=self._pool_block,
jpayne@69 299 **proxy_kwargs,
jpayne@69 300 )
jpayne@69 301
jpayne@69 302 return manager
jpayne@69 303
jpayne@69 304 def cert_verify(self, conn, url, verify, cert):
jpayne@69 305 """Verify a SSL certificate. This method should not be called from user
jpayne@69 306 code, and is only exposed for use when subclassing the
jpayne@69 307 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 308
jpayne@69 309 :param conn: The urllib3 connection object associated with the cert.
jpayne@69 310 :param url: The requested URL.
jpayne@69 311 :param verify: Either a boolean, in which case it controls whether we verify
jpayne@69 312 the server's TLS certificate, or a string, in which case it must be a path
jpayne@69 313 to a CA bundle to use
jpayne@69 314 :param cert: The SSL certificate to verify.
jpayne@69 315 """
jpayne@69 316 if url.lower().startswith("https") and verify:
jpayne@69 317 conn.cert_reqs = "CERT_REQUIRED"
jpayne@69 318
jpayne@69 319 # Only load the CA certificates if 'verify' is a string indicating the CA bundle to use.
jpayne@69 320 # Otherwise, if verify is a boolean, we don't load anything since
jpayne@69 321 # the connection will be using a context with the default certificates already loaded,
jpayne@69 322 # and this avoids a call to the slow load_verify_locations()
jpayne@69 323 if verify is not True:
jpayne@69 324 # `verify` must be a str with a path then
jpayne@69 325 cert_loc = verify
jpayne@69 326
jpayne@69 327 if not os.path.exists(cert_loc):
jpayne@69 328 raise OSError(
jpayne@69 329 f"Could not find a suitable TLS CA certificate bundle, "
jpayne@69 330 f"invalid path: {cert_loc}"
jpayne@69 331 )
jpayne@69 332
jpayne@69 333 if not os.path.isdir(cert_loc):
jpayne@69 334 conn.ca_certs = cert_loc
jpayne@69 335 else:
jpayne@69 336 conn.ca_cert_dir = cert_loc
jpayne@69 337 else:
jpayne@69 338 conn.cert_reqs = "CERT_NONE"
jpayne@69 339 conn.ca_certs = None
jpayne@69 340 conn.ca_cert_dir = None
jpayne@69 341
jpayne@69 342 if cert:
jpayne@69 343 if not isinstance(cert, basestring):
jpayne@69 344 conn.cert_file = cert[0]
jpayne@69 345 conn.key_file = cert[1]
jpayne@69 346 else:
jpayne@69 347 conn.cert_file = cert
jpayne@69 348 conn.key_file = None
jpayne@69 349 if conn.cert_file and not os.path.exists(conn.cert_file):
jpayne@69 350 raise OSError(
jpayne@69 351 f"Could not find the TLS certificate file, "
jpayne@69 352 f"invalid path: {conn.cert_file}"
jpayne@69 353 )
jpayne@69 354 if conn.key_file and not os.path.exists(conn.key_file):
jpayne@69 355 raise OSError(
jpayne@69 356 f"Could not find the TLS key file, invalid path: {conn.key_file}"
jpayne@69 357 )
jpayne@69 358
jpayne@69 359 def build_response(self, req, resp):
jpayne@69 360 """Builds a :class:`Response <requests.Response>` object from a urllib3
jpayne@69 361 response. This should not be called from user code, and is only exposed
jpayne@69 362 for use when subclassing the
jpayne@69 363 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`
jpayne@69 364
jpayne@69 365 :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response.
jpayne@69 366 :param resp: The urllib3 response object.
jpayne@69 367 :rtype: requests.Response
jpayne@69 368 """
jpayne@69 369 response = Response()
jpayne@69 370
jpayne@69 371 # Fallback to None if there's no status_code, for whatever reason.
jpayne@69 372 response.status_code = getattr(resp, "status", None)
jpayne@69 373
jpayne@69 374 # Make headers case-insensitive.
jpayne@69 375 response.headers = CaseInsensitiveDict(getattr(resp, "headers", {}))
jpayne@69 376
jpayne@69 377 # Set encoding.
jpayne@69 378 response.encoding = get_encoding_from_headers(response.headers)
jpayne@69 379 response.raw = resp
jpayne@69 380 response.reason = response.raw.reason
jpayne@69 381
jpayne@69 382 if isinstance(req.url, bytes):
jpayne@69 383 response.url = req.url.decode("utf-8")
jpayne@69 384 else:
jpayne@69 385 response.url = req.url
jpayne@69 386
jpayne@69 387 # Add new cookies from the server.
jpayne@69 388 extract_cookies_to_jar(response.cookies, req, resp)
jpayne@69 389
jpayne@69 390 # Give the Response some context.
jpayne@69 391 response.request = req
jpayne@69 392 response.connection = self
jpayne@69 393
jpayne@69 394 return response
jpayne@69 395
jpayne@69 396 def build_connection_pool_key_attributes(self, request, verify, cert=None):
jpayne@69 397 """Build the PoolKey attributes used by urllib3 to return a connection.
jpayne@69 398
jpayne@69 399 This looks at the PreparedRequest, the user-specified verify value,
jpayne@69 400 and the value of the cert parameter to determine what PoolKey values
jpayne@69 401 to use to select a connection from a given urllib3 Connection Pool.
jpayne@69 402
jpayne@69 403 The SSL related pool key arguments are not consistently set. As of
jpayne@69 404 this writing, use the following to determine what keys may be in that
jpayne@69 405 dictionary:
jpayne@69 406
jpayne@69 407 * If ``verify`` is ``True``, ``"ssl_context"`` will be set and will be the
jpayne@69 408 default Requests SSL Context
jpayne@69 409 * If ``verify`` is ``False``, ``"ssl_context"`` will not be set but
jpayne@69 410 ``"cert_reqs"`` will be set
jpayne@69 411 * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
jpayne@69 412 ``"ca_certs"`` will be set if the string is not a directory recognized
jpayne@69 413 by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
jpayne@69 414 set.
jpayne@69 415 * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
jpayne@69 416 ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
jpayne@69 417 be present
jpayne@69 418
jpayne@69 419 To override these settings, one may subclass this class, call this
jpayne@69 420 method and use the above logic to change parameters as desired. For
jpayne@69 421 example, if one wishes to use a custom :py:class:`ssl.SSLContext` one
jpayne@69 422 must both set ``"ssl_context"`` and based on what else they require,
jpayne@69 423 alter the other keys to ensure the desired behaviour.
jpayne@69 424
jpayne@69 425 :param request:
jpayne@69 426 The PreparedReqest being sent over the connection.
jpayne@69 427 :type request:
jpayne@69 428 :class:`~requests.models.PreparedRequest`
jpayne@69 429 :param verify:
jpayne@69 430 Either a boolean, in which case it controls whether
jpayne@69 431 we verify the server's TLS certificate, or a string, in which case it
jpayne@69 432 must be a path to a CA bundle to use.
jpayne@69 433 :param cert:
jpayne@69 434 (optional) Any user-provided SSL certificate for client
jpayne@69 435 authentication (a.k.a., mTLS). This may be a string (i.e., just
jpayne@69 436 the path to a file which holds both certificate and key) or a
jpayne@69 437 tuple of length 2 with the certificate file path and key file
jpayne@69 438 path.
jpayne@69 439 :returns:
jpayne@69 440 A tuple of two dictionaries. The first is the "host parameters"
jpayne@69 441 portion of the Pool Key including scheme, hostname, and port. The
jpayne@69 442 second is a dictionary of SSLContext related parameters.
jpayne@69 443 """
jpayne@69 444 return _urllib3_request_context(request, verify, cert, self.poolmanager)
jpayne@69 445
jpayne@69 446 def get_connection_with_tls_context(self, request, verify, proxies=None, cert=None):
jpayne@69 447 """Returns a urllib3 connection for the given request and TLS settings.
jpayne@69 448 This should not be called from user code, and is only exposed for use
jpayne@69 449 when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 450
jpayne@69 451 :param request:
jpayne@69 452 The :class:`PreparedRequest <PreparedRequest>` object to be sent
jpayne@69 453 over the connection.
jpayne@69 454 :param verify:
jpayne@69 455 Either a boolean, in which case it controls whether we verify the
jpayne@69 456 server's TLS certificate, or a string, in which case it must be a
jpayne@69 457 path to a CA bundle to use.
jpayne@69 458 :param proxies:
jpayne@69 459 (optional) The proxies dictionary to apply to the request.
jpayne@69 460 :param cert:
jpayne@69 461 (optional) Any user-provided SSL certificate to be used for client
jpayne@69 462 authentication (a.k.a., mTLS).
jpayne@69 463 :rtype:
jpayne@69 464 urllib3.ConnectionPool
jpayne@69 465 """
jpayne@69 466 proxy = select_proxy(request.url, proxies)
jpayne@69 467 try:
jpayne@69 468 host_params, pool_kwargs = self.build_connection_pool_key_attributes(
jpayne@69 469 request,
jpayne@69 470 verify,
jpayne@69 471 cert,
jpayne@69 472 )
jpayne@69 473 except ValueError as e:
jpayne@69 474 raise InvalidURL(e, request=request)
jpayne@69 475 if proxy:
jpayne@69 476 proxy = prepend_scheme_if_needed(proxy, "http")
jpayne@69 477 proxy_url = parse_url(proxy)
jpayne@69 478 if not proxy_url.host:
jpayne@69 479 raise InvalidProxyURL(
jpayne@69 480 "Please check proxy URL. It is malformed "
jpayne@69 481 "and could be missing the host."
jpayne@69 482 )
jpayne@69 483 proxy_manager = self.proxy_manager_for(proxy)
jpayne@69 484 conn = proxy_manager.connection_from_host(
jpayne@69 485 **host_params, pool_kwargs=pool_kwargs
jpayne@69 486 )
jpayne@69 487 else:
jpayne@69 488 # Only scheme should be lower case
jpayne@69 489 conn = self.poolmanager.connection_from_host(
jpayne@69 490 **host_params, pool_kwargs=pool_kwargs
jpayne@69 491 )
jpayne@69 492
jpayne@69 493 return conn
jpayne@69 494
jpayne@69 495 def get_connection(self, url, proxies=None):
jpayne@69 496 """DEPRECATED: Users should move to `get_connection_with_tls_context`
jpayne@69 497 for all subclasses of HTTPAdapter using Requests>=2.32.2.
jpayne@69 498
jpayne@69 499 Returns a urllib3 connection for the given URL. This should not be
jpayne@69 500 called from user code, and is only exposed for use when subclassing the
jpayne@69 501 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 502
jpayne@69 503 :param url: The URL to connect to.
jpayne@69 504 :param proxies: (optional) A Requests-style dictionary of proxies used on this request.
jpayne@69 505 :rtype: urllib3.ConnectionPool
jpayne@69 506 """
jpayne@69 507 warnings.warn(
jpayne@69 508 (
jpayne@69 509 "`get_connection` has been deprecated in favor of "
jpayne@69 510 "`get_connection_with_tls_context`. Custom HTTPAdapter subclasses "
jpayne@69 511 "will need to migrate for Requests>=2.32.2. Please see "
jpayne@69 512 "https://github.com/psf/requests/pull/6710 for more details."
jpayne@69 513 ),
jpayne@69 514 DeprecationWarning,
jpayne@69 515 )
jpayne@69 516 proxy = select_proxy(url, proxies)
jpayne@69 517
jpayne@69 518 if proxy:
jpayne@69 519 proxy = prepend_scheme_if_needed(proxy, "http")
jpayne@69 520 proxy_url = parse_url(proxy)
jpayne@69 521 if not proxy_url.host:
jpayne@69 522 raise InvalidProxyURL(
jpayne@69 523 "Please check proxy URL. It is malformed "
jpayne@69 524 "and could be missing the host."
jpayne@69 525 )
jpayne@69 526 proxy_manager = self.proxy_manager_for(proxy)
jpayne@69 527 conn = proxy_manager.connection_from_url(url)
jpayne@69 528 else:
jpayne@69 529 # Only scheme should be lower case
jpayne@69 530 parsed = urlparse(url)
jpayne@69 531 url = parsed.geturl()
jpayne@69 532 conn = self.poolmanager.connection_from_url(url)
jpayne@69 533
jpayne@69 534 return conn
jpayne@69 535
jpayne@69 536 def close(self):
jpayne@69 537 """Disposes of any internal state.
jpayne@69 538
jpayne@69 539 Currently, this closes the PoolManager and any active ProxyManager,
jpayne@69 540 which closes any pooled connections.
jpayne@69 541 """
jpayne@69 542 self.poolmanager.clear()
jpayne@69 543 for proxy in self.proxy_manager.values():
jpayne@69 544 proxy.clear()
jpayne@69 545
jpayne@69 546 def request_url(self, request, proxies):
jpayne@69 547 """Obtain the url to use when making the final request.
jpayne@69 548
jpayne@69 549 If the message is being sent through a HTTP proxy, the full URL has to
jpayne@69 550 be used. Otherwise, we should only use the path portion of the URL.
jpayne@69 551
jpayne@69 552 This should not be called from user code, and is only exposed for use
jpayne@69 553 when subclassing the
jpayne@69 554 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 555
jpayne@69 556 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
jpayne@69 557 :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs.
jpayne@69 558 :rtype: str
jpayne@69 559 """
jpayne@69 560 proxy = select_proxy(request.url, proxies)
jpayne@69 561 scheme = urlparse(request.url).scheme
jpayne@69 562
jpayne@69 563 is_proxied_http_request = proxy and scheme != "https"
jpayne@69 564 using_socks_proxy = False
jpayne@69 565 if proxy:
jpayne@69 566 proxy_scheme = urlparse(proxy).scheme.lower()
jpayne@69 567 using_socks_proxy = proxy_scheme.startswith("socks")
jpayne@69 568
jpayne@69 569 url = request.path_url
jpayne@69 570 if url.startswith("//"): # Don't confuse urllib3
jpayne@69 571 url = f"/{url.lstrip('/')}"
jpayne@69 572
jpayne@69 573 if is_proxied_http_request and not using_socks_proxy:
jpayne@69 574 url = urldefragauth(request.url)
jpayne@69 575
jpayne@69 576 return url
jpayne@69 577
jpayne@69 578 def add_headers(self, request, **kwargs):
jpayne@69 579 """Add any headers needed by the connection. As of v2.0 this does
jpayne@69 580 nothing by default, but is left for overriding by users that subclass
jpayne@69 581 the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 582
jpayne@69 583 This should not be called from user code, and is only exposed for use
jpayne@69 584 when subclassing the
jpayne@69 585 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 586
jpayne@69 587 :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to.
jpayne@69 588 :param kwargs: The keyword arguments from the call to send().
jpayne@69 589 """
jpayne@69 590 pass
jpayne@69 591
jpayne@69 592 def proxy_headers(self, proxy):
jpayne@69 593 """Returns a dictionary of the headers to add to any request sent
jpayne@69 594 through a proxy. This works with urllib3 magic to ensure that they are
jpayne@69 595 correctly sent to the proxy, rather than in a tunnelled request if
jpayne@69 596 CONNECT is being used.
jpayne@69 597
jpayne@69 598 This should not be called from user code, and is only exposed for use
jpayne@69 599 when subclassing the
jpayne@69 600 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
jpayne@69 601
jpayne@69 602 :param proxy: The url of the proxy being used for this request.
jpayne@69 603 :rtype: dict
jpayne@69 604 """
jpayne@69 605 headers = {}
jpayne@69 606 username, password = get_auth_from_url(proxy)
jpayne@69 607
jpayne@69 608 if username:
jpayne@69 609 headers["Proxy-Authorization"] = _basic_auth_str(username, password)
jpayne@69 610
jpayne@69 611 return headers
jpayne@69 612
jpayne@69 613 def send(
jpayne@69 614 self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
jpayne@69 615 ):
jpayne@69 616 """Sends PreparedRequest object. Returns Response object.
jpayne@69 617
jpayne@69 618 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
jpayne@69 619 :param stream: (optional) Whether to stream the request content.
jpayne@69 620 :param timeout: (optional) How long to wait for the server to send
jpayne@69 621 data before giving up, as a float, or a :ref:`(connect timeout,
jpayne@69 622 read timeout) <timeouts>` tuple.
jpayne@69 623 :type timeout: float or tuple or urllib3 Timeout object
jpayne@69 624 :param verify: (optional) Either a boolean, in which case it controls whether
jpayne@69 625 we verify the server's TLS certificate, or a string, in which case it
jpayne@69 626 must be a path to a CA bundle to use
jpayne@69 627 :param cert: (optional) Any user-provided SSL certificate to be trusted.
jpayne@69 628 :param proxies: (optional) The proxies dictionary to apply to the request.
jpayne@69 629 :rtype: requests.Response
jpayne@69 630 """
jpayne@69 631
jpayne@69 632 try:
jpayne@69 633 conn = self.get_connection_with_tls_context(
jpayne@69 634 request, verify, proxies=proxies, cert=cert
jpayne@69 635 )
jpayne@69 636 except LocationValueError as e:
jpayne@69 637 raise InvalidURL(e, request=request)
jpayne@69 638
jpayne@69 639 self.cert_verify(conn, request.url, verify, cert)
jpayne@69 640 url = self.request_url(request, proxies)
jpayne@69 641 self.add_headers(
jpayne@69 642 request,
jpayne@69 643 stream=stream,
jpayne@69 644 timeout=timeout,
jpayne@69 645 verify=verify,
jpayne@69 646 cert=cert,
jpayne@69 647 proxies=proxies,
jpayne@69 648 )
jpayne@69 649
jpayne@69 650 chunked = not (request.body is None or "Content-Length" in request.headers)
jpayne@69 651
jpayne@69 652 if isinstance(timeout, tuple):
jpayne@69 653 try:
jpayne@69 654 connect, read = timeout
jpayne@69 655 timeout = TimeoutSauce(connect=connect, read=read)
jpayne@69 656 except ValueError:
jpayne@69 657 raise ValueError(
jpayne@69 658 f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
jpayne@69 659 f"or a single float to set both timeouts to the same value."
jpayne@69 660 )
jpayne@69 661 elif isinstance(timeout, TimeoutSauce):
jpayne@69 662 pass
jpayne@69 663 else:
jpayne@69 664 timeout = TimeoutSauce(connect=timeout, read=timeout)
jpayne@69 665
jpayne@69 666 try:
jpayne@69 667 resp = conn.urlopen(
jpayne@69 668 method=request.method,
jpayne@69 669 url=url,
jpayne@69 670 body=request.body,
jpayne@69 671 headers=request.headers,
jpayne@69 672 redirect=False,
jpayne@69 673 assert_same_host=False,
jpayne@69 674 preload_content=False,
jpayne@69 675 decode_content=False,
jpayne@69 676 retries=self.max_retries,
jpayne@69 677 timeout=timeout,
jpayne@69 678 chunked=chunked,
jpayne@69 679 )
jpayne@69 680
jpayne@69 681 except (ProtocolError, OSError) as err:
jpayne@69 682 raise ConnectionError(err, request=request)
jpayne@69 683
jpayne@69 684 except MaxRetryError as e:
jpayne@69 685 if isinstance(e.reason, ConnectTimeoutError):
jpayne@69 686 # TODO: Remove this in 3.0.0: see #2811
jpayne@69 687 if not isinstance(e.reason, NewConnectionError):
jpayne@69 688 raise ConnectTimeout(e, request=request)
jpayne@69 689
jpayne@69 690 if isinstance(e.reason, ResponseError):
jpayne@69 691 raise RetryError(e, request=request)
jpayne@69 692
jpayne@69 693 if isinstance(e.reason, _ProxyError):
jpayne@69 694 raise ProxyError(e, request=request)
jpayne@69 695
jpayne@69 696 if isinstance(e.reason, _SSLError):
jpayne@69 697 # This branch is for urllib3 v1.22 and later.
jpayne@69 698 raise SSLError(e, request=request)
jpayne@69 699
jpayne@69 700 raise ConnectionError(e, request=request)
jpayne@69 701
jpayne@69 702 except ClosedPoolError as e:
jpayne@69 703 raise ConnectionError(e, request=request)
jpayne@69 704
jpayne@69 705 except _ProxyError as e:
jpayne@69 706 raise ProxyError(e)
jpayne@69 707
jpayne@69 708 except (_SSLError, _HTTPError) as e:
jpayne@69 709 if isinstance(e, _SSLError):
jpayne@69 710 # This branch is for urllib3 versions earlier than v1.22
jpayne@69 711 raise SSLError(e, request=request)
jpayne@69 712 elif isinstance(e, ReadTimeoutError):
jpayne@69 713 raise ReadTimeout(e, request=request)
jpayne@69 714 elif isinstance(e, _InvalidHeader):
jpayne@69 715 raise InvalidHeader(e, request=request)
jpayne@69 716 else:
jpayne@69 717 raise
jpayne@69 718
jpayne@69 719 return self.build_response(request, resp)