annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/requests/adapters.py @ 68:5028fdace37b

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