@@ -83,16 +83,20 @@ def _urllib3_request_context(
8383 request : "PreparedRequest" ,
8484 verify : "bool | str | None" ,
8585 client_cert : "typing.Tuple[str, str] | str | None" ,
86+ poolmanager : "PoolManager" ,
8687) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])" :
8788 host_params = {}
8889 pool_kwargs = {}
8990 parsed_request_url = urlparse (request .url )
9091 scheme = parsed_request_url .scheme .lower ()
9192 port = parsed_request_url .port
93+ poolmanager_kwargs = getattr (poolmanager , "connection_pool_kw" , {})
94+ has_poolmanager_ssl_context = poolmanager_kwargs .get ("ssl_context" )
95+
9296 cert_reqs = "CERT_REQUIRED"
9397 if verify is False :
9498 cert_reqs = "CERT_NONE"
95- elif verify is True :
99+ elif verify is True and not has_poolmanager_ssl_context :
96100 pool_kwargs ["ssl_context" ] = _preloaded_ssl_context
97101 elif isinstance (verify , str ):
98102 if not os .path .isdir (verify ):
@@ -375,23 +379,83 @@ def build_response(self, req, resp):
375379
376380 return response
377381
382+ def build_connection_pool_key_attributes (self , request , verify , cert = None ):
383+ """Build the PoolKey attributes used by urllib3 to return a connection.
384+
385+ This looks at the PreparedRequest, the user-specified verify value,
386+ and the value of the cert parameter to determine what PoolKey values
387+ to use to select a connection from a given urllib3 Connection Pool.
388+
389+ The SSL related pool key arguments are not consistently set. As of
390+ this writing, use the following to determine what keys may be in that
391+ dictionary:
392+
393+ * If ``verify`` is ``True``, ``"ssl_context"`` will be set and will be the
394+ default Requests SSL Context
395+ * If ``verify`` is ``False``, ``"ssl_context"`` will not be set but
396+ ``"cert_reqs"`` will be set
397+ * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
398+ ``"ca_certs"`` will be set if the string is not a directory recognized
399+ by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
400+ set.
401+ * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
402+ ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
403+ be present
404+
405+ To override these settings, one may subclass this class, call this
406+ method and use the above logic to change parameters as desired. For
407+ example, if one wishes to use a custom :py:class:`ssl.SSLContext` one
408+ must both set ``"ssl_context"`` and based on what else they require,
409+ alter the other keys to ensure the desired behaviour.
410+
411+ :param request:
412+ The PreparedReqest being sent over the connection.
413+ :type request:
414+ :class:`~requests.models.PreparedRequest`
415+ :param verify:
416+ Either a boolean, in which case it controls whether
417+ we verify the server's TLS certificate, or a string, in which case it
418+ must be a path to a CA bundle to use.
419+ :param cert:
420+ (optional) Any user-provided SSL certificate for client
421+ authentication (a.k.a., mTLS). This may be a string (i.e., just
422+ the path to a file which holds both certificate and key) or a
423+ tuple of length 2 with the certificate file path and key file
424+ path.
425+ :returns:
426+ A tuple of two dictionaries. The first is the "host parameters"
427+ portion of the Pool Key including scheme, hostname, and port. The
428+ second is a dictionary of SSLContext related parameters.
429+ """
430+ return _urllib3_request_context (request , verify , cert , self .poolmanager )
431+
378432 def get_connection_with_tls_context (self , request , verify , proxies = None , cert = None ):
379433 """Returns a urllib3 connection for the given request and TLS settings.
380434 This should not be called from user code, and is only exposed for use
381435 when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
382436
383- :param request: The :class:`PreparedRequest <PreparedRequest>` object
384- to be sent over the connection.
385- :param verify: Either a boolean, in which case it controls whether
386- we verify the server's TLS certificate, or a string, in which case it
387- must be a path to a CA bundle to use.
388- :param proxies: (optional) The proxies dictionary to apply to the request.
389- :param cert: (optional) Any user-provided SSL certificate to be trusted.
390- :rtype: urllib3.ConnectionPool
437+ :param request:
438+ The :class:`PreparedRequest <PreparedRequest>` object to be sent
439+ over the connection.
440+ :param verify:
441+ Either a boolean, in which case it controls whether we verify the
442+ server's TLS certificate, or a string, in which case it must be a
443+ path to a CA bundle to use.
444+ :param proxies:
445+ (optional) The proxies dictionary to apply to the request.
446+ :param cert:
447+ (optional) Any user-provided SSL certificate to be used for client
448+ authentication (a.k.a., mTLS).
449+ :rtype:
450+ urllib3.ConnectionPool
391451 """
392452 proxy = select_proxy (request .url , proxies )
393453 try :
394- host_params , pool_kwargs = _urllib3_request_context (request , verify , cert )
454+ host_params , pool_kwargs = self .build_connection_pool_key_attributes (
455+ request ,
456+ verify ,
457+ cert ,
458+ )
395459 except ValueError as e :
396460 raise InvalidURL (e , request = request )
397461 if proxy :
0 commit comments