1from __future__ import annotations
2
3import errno
4import logging
5import queue
6import sys
7import typing
8import warnings
9import weakref
10from socket import timeout as SocketTimeout
11from types import TracebackType
12
13from ._base_connection import _TYPE_BODY
14from ._collections import HTTPHeaderDict
15from ._request_methods import RequestMethods
16from .connection import (
17 BaseSSLError,
18 BrokenPipeError,
19 DummyConnection,
20 HTTPConnection,
21 HTTPException,
22 HTTPSConnection,
23 ProxyConfig,
24 _wrap_proxy_error,
25)
26from .connection import port_by_scheme as port_by_scheme
27from .exceptions import (
28 ClosedPoolError,
29 EmptyPoolError,
30 FullPoolError,
31 HostChangedError,
32 InsecureRequestWarning,
33 LocationValueError,
34 MaxRetryError,
35 NewConnectionError,
36 ProtocolError,
37 ProxyError,
38 ReadTimeoutError,
39 SSLError,
40 TimeoutError,
41)
42from .response import BaseHTTPResponse
43from .util.connection import is_connection_dropped
44from .util.proxy import connection_requires_http_tunnel
45from .util.request import _TYPE_BODY_POSITION, set_file_position
46from .util.retry import Retry
47from .util.ssl_match_hostname import CertificateError
48from .util.timeout import _DEFAULT_TIMEOUT, _TYPE_DEFAULT, Timeout
49from .util.url import Url, _encode_target
50from .util.url import _normalize_host as normalize_host
51from .util.url import parse_url
52from .util.util import to_str
53
54if typing.TYPE_CHECKING:
55 import ssl
56
57 from typing_extensions import Self
58
59 from ._base_connection import BaseHTTPConnection, BaseHTTPSConnection
60
61log = logging.getLogger(__name__)
62
63_TYPE_TIMEOUT = typing.Union[Timeout, float, _TYPE_DEFAULT, None]
64_DEFAULT_QUEUE_CLASS = queue.LifoQueue
65
66
67# Pool objects
68class ConnectionPool:
69 """
70 Base class for all connection pools, such as
71 :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
72
73 .. note::
74 ConnectionPool.urlopen() does not normalize or percent-encode target URIs
75 which is useful if your target server doesn't support percent-encoded
76 target URIs.
77 """
78
79 scheme: str | None = None
80 QueueCls = _DEFAULT_QUEUE_CLASS
81
82 def __init__(self, host: str, port: int | None = None) -> None:
83 if not host:
84 raise LocationValueError("No host specified.")
85
86 self.host = _normalize_host(host, scheme=self.scheme)
87 self.port = port
88
89 # This property uses 'normalize_host()' (not '_normalize_host()')
90 # to avoid removing square braces around IPv6 addresses.
91 # This value is sent to `HTTPConnection.set_tunnel()` if called
92 # because square braces are required for HTTP CONNECT tunneling.
93 self._tunnel_host = normalize_host(host, scheme=self.scheme).lower()
94
95 def __str__(self) -> str:
96 return f"{type(self).__name__}(host={self.host!r}, port={self.port!r})"
97
98 def __enter__(self) -> Self:
99 return self
100
101 def __exit__(
102 self,
103 exc_type: type[BaseException] | None,
104 exc_val: BaseException | None,
105 exc_tb: TracebackType | None,
106 ) -> typing.Literal[False]:
107 self.close()
108 # Return False to re-raise any potential exceptions
109 return False
110
111 def close(self) -> None:
112 """
113 Close all pooled connections and disable the pool.
114 """
115
116 def _new_pool_queue(self, maxsize: int) -> queue.LifoQueue[typing.Any]:
117 if self.QueueCls is _DEFAULT_QUEUE_CLASS:
118 return queue.LifoQueue(maxsize)
119 return self.QueueCls(maxsize)
120
121
122# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252
123_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK}
124
125
126class HTTPConnectionPool(ConnectionPool, RequestMethods):
127 """
128 Thread-safe connection pool for one host.
129
130 :param host:
131 Host used for this HTTP Connection (e.g. "localhost"), passed into
132 :class:`http.client.HTTPConnection`.
133
134 :param port:
135 Port used for this HTTP Connection (None is equivalent to 80), passed
136 into :class:`http.client.HTTPConnection`.
137
138 :param timeout:
139 Socket timeout in seconds for each individual connection. This can
140 be a float or integer, which sets the timeout for the HTTP request,
141 or an instance of :class:`urllib3.util.Timeout` which gives you more
142 fine-grained control over request timeouts. After the constructor has
143 been parsed, this is always a `urllib3.util.Timeout` object.
144
145 :param maxsize:
146 Number of connections to save that can be reused. More than 1 is useful
147 in multithreaded situations. If ``block`` is set to False, more
148 connections will be created but they will not be saved once they've
149 been used.
150
151 :param block:
152 If set to True, no more than ``maxsize`` connections will be used at
153 a time. When no free connections are available, the call will block
154 until a connection has been released. This is a useful side effect for
155 particular multithreaded situations where one does not want to use more
156 than maxsize connections per host to prevent flooding.
157
158 :param headers:
159 Headers to include with all requests, unless other headers are given
160 explicitly.
161
162 :param retries:
163 Retry configuration to use by default with requests in this pool.
164
165 :param _proxy:
166 Parsed proxy URL, should not be used directly, instead, see
167 :class:`urllib3.ProxyManager`
168
169 :param _proxy_headers:
170 A dictionary with proxy headers, should not be used directly,
171 instead, see :class:`urllib3.ProxyManager`
172
173 :param \\**conn_kw:
174 Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`,
175 :class:`urllib3.connection.HTTPSConnection` instances.
176 """
177
178 scheme = "http"
179 ConnectionCls: type[BaseHTTPConnection] | type[BaseHTTPSConnection] = HTTPConnection
180
181 def __init__(
182 self,
183 host: str,
184 port: int | None = None,
185 timeout: _TYPE_TIMEOUT | None = _DEFAULT_TIMEOUT,
186 maxsize: int = 1,
187 block: bool = False,
188 headers: typing.Mapping[str, str] | None = None,
189 retries: Retry | bool | int | None = None,
190 _proxy: Url | None = None,
191 _proxy_headers: typing.Mapping[str, str] | None = None,
192 _proxy_config: ProxyConfig | None = None,
193 **conn_kw: typing.Any,
194 ):
195 ConnectionPool.__init__(self, host, port)
196 RequestMethods.__init__(self, headers)
197
198 if not isinstance(timeout, Timeout):
199 timeout = Timeout.from_float(timeout)
200
201 if retries is None:
202 retries = Retry.DEFAULT
203
204 self.timeout = timeout
205 self.retries = retries
206
207 self.pool: queue.LifoQueue[typing.Any] | None = self._new_pool_queue(maxsize)
208 self.block = block
209
210 self.proxy = _proxy
211 self.proxy_headers = _proxy_headers or {}
212 self.proxy_config = _proxy_config
213
214 # Fill the queue up so that doing get() on it will block properly
215 for _ in range(maxsize):
216 self.pool.put(None)
217
218 # These are mostly for testing and debugging purposes.
219 self.num_connections = 0
220 self.num_requests = 0
221 self.conn_kw = conn_kw
222
223 if self.proxy:
224 # Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
225 # Defaulting `socket_options` to an empty list avoids it defaulting to
226 # ``HTTPConnection.default_socket_options``.
227 self.conn_kw.setdefault("socket_options", [])
228
229 self.conn_kw["proxy"] = self.proxy
230 self.conn_kw["proxy_config"] = self.proxy_config
231
232 # Do not pass 'self' as callback to 'finalize'.
233 # Then the 'finalize' would keep an endless living (leak) to self.
234 # By just passing a reference to the pool allows the garbage collector
235 # to free self if nobody else has a reference to it.
236 pool = self.pool
237
238 # Close all the HTTPConnections in the pool before the
239 # HTTPConnectionPool object is garbage collected.
240 weakref.finalize(self, _close_pool_connections, pool)
241
242 def _new_conn(self) -> BaseHTTPConnection:
243 """
244 Return a fresh :class:`HTTPConnection`.
245 """
246 self.num_connections += 1
247 log.debug(
248 "Starting new HTTP connection (%d): %s:%s",
249 self.num_connections,
250 self.host,
251 self.port or "80",
252 )
253
254 conn = self.ConnectionCls(
255 host=self.host,
256 port=self.port,
257 timeout=self.timeout.connect_timeout,
258 **self.conn_kw,
259 )
260 return conn
261
262 def _get_conn(self, timeout: float | None = None) -> BaseHTTPConnection:
263 """
264 Get a connection. Will return a pooled connection if one is available.
265
266 If no connections are available and :prop:`.block` is ``False``, then a
267 fresh connection is returned.
268
269 :param timeout:
270 Seconds to wait before giving up and raising
271 :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
272 :prop:`.block` is ``True``.
273 """
274 conn = None
275
276 if self.pool is None:
277 raise ClosedPoolError(self, "Pool is closed.")
278
279 try:
280 conn = self.pool.get(block=self.block, timeout=timeout)
281
282 except AttributeError: # self.pool is None
283 raise ClosedPoolError(self, "Pool is closed.") from None # Defensive:
284
285 except queue.Empty:
286 if self.block:
287 raise EmptyPoolError(
288 self,
289 "Pool is empty and a new connection can't be opened due to blocking mode.",
290 ) from None
291 pass # Oh well, we'll create a new connection then
292
293 # If this is a persistent connection, check if it got disconnected
294 if conn and is_connection_dropped(conn):
295 log.debug("Resetting dropped connection: %s", self.host)
296 conn.close()
297
298 return conn or self._new_conn()
299
300 def _put_conn(self, conn: BaseHTTPConnection | None) -> None:
301 """
302 Put a connection back into the pool.
303
304 :param conn:
305 Connection object for the current host and port as returned by
306 :meth:`._new_conn` or :meth:`._get_conn`.
307
308 If the pool is already full, the connection is closed and discarded
309 because we exceeded maxsize. If connections are discarded frequently,
310 then maxsize should be increased.
311
312 If the pool is closed, then the connection will be closed and discarded.
313 """
314 if self.pool is not None:
315 try:
316 self.pool.put(conn, block=False)
317 return # Everything is dandy, done.
318 except AttributeError:
319 # self.pool is None.
320 pass
321 except queue.Full:
322 # Connection never got put back into the pool, close it.
323 if conn:
324 conn.close()
325
326 if self.block:
327 # This should never happen if you got the conn from self._get_conn
328 raise FullPoolError(
329 self,
330 "Pool reached maximum size and no more connections are allowed.",
331 ) from None
332
333 log.warning(
334 "Connection pool is full, discarding connection: %s. Connection pool size: %s",
335 self.host,
336 self.pool.qsize(),
337 )
338
339 # Connection never got put back into the pool, close it.
340 if conn:
341 conn.close()
342
343 def _validate_conn(self, conn: BaseHTTPConnection) -> None:
344 """
345 Called right before a request is made, after the socket is created.
346 """
347
348 def _prepare_proxy(self, conn: BaseHTTPConnection) -> None:
349 # Nothing to do for HTTP connections.
350 pass
351
352 def _get_timeout(self, timeout: _TYPE_TIMEOUT) -> Timeout:
353 """Helper that always returns a :class:`urllib3.util.Timeout`"""
354 if timeout is _DEFAULT_TIMEOUT:
355 return self.timeout.clone()
356
357 if isinstance(timeout, Timeout):
358 return timeout.clone()
359 else:
360 # User passed us an int/float. This is for backwards compatibility,
361 # can be removed later
362 return Timeout.from_float(timeout)
363
364 def _raise_timeout(
365 self,
366 err: BaseSSLError | OSError | SocketTimeout,
367 url: str,
368 timeout_value: _TYPE_TIMEOUT | None,
369 ) -> None:
370 """Is the error actually a timeout? Will raise a ReadTimeout or pass"""
371
372 if isinstance(err, SocketTimeout):
373 raise ReadTimeoutError(
374 self, url, f"Read timed out. (read timeout={timeout_value})"
375 ) from err
376
377 # See the above comment about EAGAIN in Python 3.
378 if hasattr(err, "errno") and err.errno in _blocking_errnos:
379 raise ReadTimeoutError(
380 self, url, f"Read timed out. (read timeout={timeout_value})"
381 ) from err
382
383 def _make_request(
384 self,
385 conn: BaseHTTPConnection,
386 method: str,
387 url: str,
388 body: _TYPE_BODY | None = None,
389 headers: typing.Mapping[str, str] | None = None,
390 retries: Retry | None = None,
391 timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
392 chunked: bool = False,
393 response_conn: BaseHTTPConnection | None = None,
394 preload_content: bool = True,
395 decode_content: bool = True,
396 enforce_content_length: bool = True,
397 ) -> BaseHTTPResponse:
398 """
399 Perform a request on a given urllib connection object taken from our
400 pool.
401
402 :param conn:
403 a connection from one of our connection pools
404
405 :param method:
406 HTTP request method (such as GET, POST, PUT, etc.)
407
408 :param url:
409 The URL to perform the request on.
410
411 :param body:
412 Data to send in the request body, either :class:`str`, :class:`bytes`,
413 an iterable of :class:`str`/:class:`bytes`, or a file-like object.
414
415 :param headers:
416 Dictionary of custom headers to send, such as User-Agent,
417 If-None-Match, etc. If None, pool headers are used. If provided,
418 these headers completely replace any pool-specific headers.
419
420 :param retries:
421 Configure the number of retries to allow before raising a
422 :class:`~urllib3.exceptions.MaxRetryError` exception.
423
424 Pass ``None`` to retry until you receive a response. Pass a
425 :class:`~urllib3.util.retry.Retry` object for fine-grained control
426 over different types of retries.
427 Pass an integer number to retry connection errors that many times,
428 but no other types of errors. Pass zero to never retry.
429
430 If ``False``, then retries are disabled and any exception is raised
431 immediately. Also, instead of raising a MaxRetryError on redirects,
432 the redirect response will be returned.
433
434 :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
435
436 :param timeout:
437 If specified, overrides the default timeout for this one
438 request. It may be a float (in seconds) or an instance of
439 :class:`urllib3.util.Timeout`.
440
441 :param chunked:
442 If True, urllib3 will send the body using chunked transfer
443 encoding. Otherwise, urllib3 will send the body using the standard
444 content-length form. Defaults to False.
445
446 :param response_conn:
447 Set this to ``None`` if you will handle releasing the connection or
448 set the connection to have the response release it.
449
450 :param preload_content:
451 If True, the response's body will be preloaded during construction.
452
453 :param decode_content:
454 If True, will attempt to decode the body based on the
455 'content-encoding' header.
456
457 :param enforce_content_length:
458 Enforce content length checking. Body returned by server must match
459 value of Content-Length header, if present. Otherwise, raise error.
460 """
461 self.num_requests += 1
462
463 timeout_obj = self._get_timeout(timeout)
464 timeout_obj.start_connect()
465 conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)
466
467 try:
468 # Trigger any extra validation we need to do.
469 try:
470 self._validate_conn(conn)
471 except (SocketTimeout, BaseSSLError) as e:
472 self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
473 raise
474
475 # _validate_conn() starts the connection to an HTTPS proxy
476 # so we need to wrap errors with 'ProxyError' here too.
477 except (
478 OSError,
479 NewConnectionError,
480 TimeoutError,
481 BaseSSLError,
482 CertificateError,
483 SSLError,
484 ) as e:
485 new_e: Exception = e
486 if isinstance(e, (BaseSSLError, CertificateError)):
487 new_e = SSLError(e)
488 # If the connection didn't successfully connect to it's proxy
489 # then there
490 if isinstance(
491 new_e, (OSError, NewConnectionError, TimeoutError, SSLError)
492 ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
493 new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
494 raise new_e
495
496 # conn.request() calls http.client.*.request, not the method in
497 # urllib3.request. It also calls makefile (recv) on the socket.
498 try:
499 conn.request(
500 method,
501 url,
502 body=body,
503 headers=headers,
504 chunked=chunked,
505 preload_content=preload_content,
506 decode_content=decode_content,
507 enforce_content_length=enforce_content_length,
508 )
509
510 # We are swallowing BrokenPipeError (errno.EPIPE) since the server is
511 # legitimately able to close the connection after sending a valid response.
512 # With this behaviour, the received response is still readable.
513 except BrokenPipeError:
514 pass
515 except OSError as e:
516 # MacOS/Linux
517 # EPROTOTYPE and ECONNRESET are needed on macOS
518 # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
519 # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.
520 if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:
521 raise
522
523 # Reset the timeout for the recv() on the socket
524 read_timeout = timeout_obj.read_timeout
525
526 if not conn.is_closed:
527 # In Python 3 socket.py will catch EAGAIN and return None when you
528 # try and read into the file pointer created by http.client, which
529 # instead raises a BadStatusLine exception. Instead of catching
530 # the exception and assuming all BadStatusLine exceptions are read
531 # timeouts, check for a zero timeout before making the request.
532 if read_timeout == 0:
533 raise ReadTimeoutError(
534 self, url, f"Read timed out. (read timeout={read_timeout})"
535 )
536 conn.timeout = read_timeout
537
538 # Receive the response from the server
539 try:
540 response = conn.getresponse()
541 except (BaseSSLError, OSError) as e:
542 self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
543 raise
544
545 # Set properties that are used by the pooling layer.
546 response.retries = retries
547 response._connection = response_conn # type: ignore[attr-defined]
548 response._pool = self # type: ignore[attr-defined]
549
550 log.debug(
551 '%s://%s:%s "%s %s %s" %s %s',
552 self.scheme,
553 self.host,
554 self.port,
555 method,
556 url,
557 response.version_string,
558 response.status,
559 response.length_remaining,
560 )
561
562 return response
563
564 def close(self) -> None:
565 """
566 Close all pooled connections and disable the pool.
567 """
568 if self.pool is None:
569 return
570 # Disable access to the pool
571 old_pool, self.pool = self.pool, None
572
573 # Close all the HTTPConnections in the pool.
574 _close_pool_connections(old_pool)
575
576 def is_same_host(self, url: str) -> bool:
577 """
578 Check if the given ``url`` is a member of the same host as this
579 connection pool.
580 """
581 if url.startswith("/"):
582 return True
583
584 # TODO: Add optional support for socket.gethostbyname checking.
585 scheme, _, host, port, *_ = parse_url(url)
586 scheme = scheme or "http"
587 if host is not None:
588 host = _normalize_host(host, scheme=scheme)
589
590 # Use explicit default port for comparison when none is given
591 if self.port is not None and port is None:
592 port = port_by_scheme.get(scheme)
593 elif self.port is None and port == port_by_scheme.get(scheme):
594 port = None
595
596 return (scheme, host, port) == (self.scheme, self.host, self.port)
597
598 def urlopen( # type: ignore[override]
599 self,
600 method: str,
601 url: str,
602 body: _TYPE_BODY | None = None,
603 headers: typing.Mapping[str, str] | None = None,
604 retries: Retry | bool | int | None = None,
605 redirect: bool = True,
606 assert_same_host: bool = True,
607 timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
608 pool_timeout: int | None = None,
609 release_conn: bool | None = None,
610 chunked: bool = False,
611 body_pos: _TYPE_BODY_POSITION | None = None,
612 preload_content: bool = True,
613 decode_content: bool = True,
614 **response_kw: typing.Any,
615 ) -> BaseHTTPResponse:
616 """
617 Get a connection from the pool and perform an HTTP request. This is the
618 lowest level call for making a request, so you'll need to specify all
619 the raw details.
620
621 .. note::
622
623 More commonly, it's appropriate to use a convenience method
624 such as :meth:`request`.
625
626 .. note::
627
628 `release_conn` will only behave as expected if
629 `preload_content=False` because we want to make
630 `preload_content=False` the default behaviour someday soon without
631 breaking backwards compatibility.
632
633 :param method:
634 HTTP request method (such as GET, POST, PUT, etc.)
635
636 :param url:
637 The URL to perform the request on.
638
639 :param body:
640 Data to send in the request body, either :class:`str`, :class:`bytes`,
641 an iterable of :class:`str`/:class:`bytes`, or a file-like object.
642
643 :param headers:
644 Dictionary of custom headers to send, such as User-Agent,
645 If-None-Match, etc. If None, pool headers are used. If provided,
646 these headers completely replace any pool-specific headers.
647
648 :param retries:
649 Configure the number of retries to allow before raising a
650 :class:`~urllib3.exceptions.MaxRetryError` exception.
651
652 If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a
653 :class:`~urllib3.util.retry.Retry` object for fine-grained control
654 over different types of retries.
655 Pass an integer number to retry connection errors that many times,
656 but no other types of errors. Pass zero to never retry.
657
658 If ``False``, then retries are disabled and any exception is raised
659 immediately. Also, instead of raising a MaxRetryError on redirects,
660 the redirect response will be returned.
661
662 :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
663
664 :param redirect:
665 If True, automatically handle redirects (status codes 301, 302,
666 303, 307, 308). Each redirect counts as a retry. Disabling retries
667 will disable redirect, too.
668
669 :param assert_same_host:
670 If ``True``, will make sure that the host of the pool requests is
671 consistent else will raise HostChangedError. When ``False``, you can
672 use the pool on an HTTP proxy and request foreign hosts.
673
674 :param timeout:
675 If specified, overrides the default timeout for this one
676 request. It may be a float (in seconds) or an instance of
677 :class:`urllib3.util.Timeout`.
678
679 :param pool_timeout:
680 If set and the pool is set to block=True, then this method will
681 block for ``pool_timeout`` seconds and raise EmptyPoolError if no
682 connection is available within the time period.
683
684 :param bool preload_content:
685 If True, the response's body will be preloaded into memory.
686
687 :param bool decode_content:
688 If True, will attempt to decode the body based on the
689 'content-encoding' header.
690
691 :param release_conn:
692 If False, then the urlopen call will not release the connection
693 back into the pool once a response is received (but will release if
694 you read the entire contents of the response such as when
695 `preload_content=True`). This is useful if you're not preloading
696 the response's content immediately. You will need to call
697 ``r.release_conn()`` on the response ``r`` to return the connection
698 back into the pool. If None, it takes the value of ``preload_content``
699 which defaults to ``True``.
700
701 :param bool chunked:
702 If True, urllib3 will send the body using chunked transfer
703 encoding. Otherwise, urllib3 will send the body using the standard
704 content-length form. Defaults to False.
705
706 :param int body_pos:
707 Position to seek to in file-like body in the event of a retry or
708 redirect. Typically this won't need to be set because urllib3 will
709 auto-populate the value when needed.
710 """
711 # Ensure that the URL we're connecting to is properly encoded
712 if url.startswith("/"):
713 # URLs starting with / are inherently schemeless.
714 url = to_str(_encode_target(url))
715 destination_scheme = None
716 else:
717 parsed_url = parse_url(url)
718 destination_scheme = parsed_url.scheme
719 url = to_str(parsed_url._replace(fragment=None).url)
720
721 if headers is None:
722 headers = self.headers
723
724 if not isinstance(retries, Retry):
725 retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
726
727 if release_conn is None:
728 release_conn = preload_content
729
730 # Check host
731 if assert_same_host and not self.is_same_host(url):
732 raise HostChangedError(self, url, retries)
733
734 conn = None
735
736 # Track whether `conn` needs to be released before
737 # returning/raising/recursing. Update this variable if necessary, and
738 # leave `release_conn` constant throughout the function. That way, if
739 # the function recurses, the original value of `release_conn` will be
740 # passed down into the recursive call, and its value will be respected.
741 #
742 # See issue #651 [1] for details.
743 #
744 # [1] <https://github.com/urllib3/urllib3/issues/651>
745 release_this_conn = release_conn
746
747 http_tunnel_required = connection_requires_http_tunnel(
748 self.proxy, self.proxy_config, destination_scheme
749 )
750
751 # Merge the proxy headers. Only done when not using HTTP CONNECT. We
752 # have to copy the headers dict so we can safely change it without those
753 # changes being reflected in anyone else's copy.
754 if not http_tunnel_required:
755 headers = headers.copy() # type: ignore[attr-defined]
756 headers.update(self.proxy_headers) # type: ignore[union-attr]
757
758 # Must keep the exception bound to a separate variable or else Python 3
759 # complains about UnboundLocalError.
760 err = None
761
762 # Keep track of whether we cleanly exited the except block. This
763 # ensures we do proper cleanup in finally.
764 clean_exit = False
765
766 # Rewind body position, if needed. Record current position
767 # for future rewinds in the event of a redirect/retry.
768 body_pos = set_file_position(body, body_pos)
769
770 timeout_obj = self._get_timeout(timeout)
771 try:
772 # Request a connection from the queue.
773 conn = self._get_conn(timeout=pool_timeout)
774 conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment]
775
776 # Is this a closed/new connection that requires CONNECT tunnelling?
777 if self.proxy is not None and http_tunnel_required and conn.is_closed:
778 try:
779 self._prepare_proxy(conn)
780 except (BaseSSLError, OSError, SocketTimeout) as e:
781 self._raise_timeout(
782 err=e, url=self.proxy.url, timeout_value=conn.timeout
783 )
784 raise
785
786 # If we're going to release the connection in ``finally:``, then
787 # the response doesn't need to know about the connection. Otherwise
788 # it will also try to release it and we'll have a double-release
789 # mess.
790 response_conn = conn if not release_conn else None
791
792 # Make the request on the HTTPConnection object
793 response = self._make_request(
794 conn,
795 method,
796 url,
797 timeout=timeout_obj,
798 body=body,
799 headers=headers,
800 chunked=chunked,
801 retries=retries,
802 response_conn=response_conn,
803 preload_content=preload_content,
804 decode_content=decode_content,
805 **response_kw,
806 )
807
808 # Everything went great!
809 clean_exit = True
810
811 except EmptyPoolError:
812 # Didn't get a connection from the pool, no need to clean up
813 clean_exit = True
814 release_this_conn = False
815 raise
816
817 except (
818 TimeoutError,
819 HTTPException,
820 OSError,
821 ProtocolError,
822 BaseSSLError,
823 SSLError,
824 CertificateError,
825 ProxyError,
826 ) as e:
827 # Discard the connection for these exceptions. It will be
828 # replaced during the next _get_conn() call.
829 clean_exit = False
830 new_e: Exception = e
831 if isinstance(e, (BaseSSLError, CertificateError)):
832 new_e = SSLError(e)
833 if isinstance(
834 new_e,
835 (
836 OSError,
837 NewConnectionError,
838 TimeoutError,
839 SSLError,
840 HTTPException,
841 ),
842 ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
843 new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
844 elif isinstance(new_e, (OSError, HTTPException)):
845 new_e = ProtocolError("Connection aborted.", new_e)
846
847 retries = retries.increment(
848 method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
849 )
850 retries.sleep()
851
852 # Keep track of the error for the retry warning.
853 err = e
854
855 finally:
856 if not clean_exit:
857 # We hit some kind of exception, handled or otherwise. We need
858 # to throw the connection away unless explicitly told not to.
859 # Close the connection, set the variable to None, and make sure
860 # we put the None back in the pool to avoid leaking it.
861 if conn:
862 conn.close()
863 conn = None
864 release_this_conn = True
865
866 if release_this_conn:
867 # Put the connection back to be reused. If the connection is
868 # expired then it will be None, which will get replaced with a
869 # fresh connection during _get_conn.
870 self._put_conn(conn)
871
872 if not conn:
873 # Try again
874 log.warning(
875 "Retrying (%r) after connection broken by '%r': %s",
876 retries,
877 err,
878 url,
879 # Provide an unique attribute with the host needed by pip to
880 # rewrite this warning. Ideally, we'd go with a better solution,
881 # but backwards compatibility and other constraints make those
882 # unfeasible, so this is the least bad option.
883 # See also: https://github.com/urllib3/urllib3/issues/2580.
884 extra={"__urllib3-retry-warning": {"host": self.host}},
885 )
886 return self.urlopen(
887 method,
888 url,
889 body,
890 headers,
891 retries,
892 redirect,
893 assert_same_host,
894 timeout=timeout,
895 pool_timeout=pool_timeout,
896 release_conn=release_conn,
897 chunked=chunked,
898 body_pos=body_pos,
899 preload_content=preload_content,
900 decode_content=decode_content,
901 **response_kw,
902 )
903
904 # Handle redirect?
905 redirect_location = redirect and response.get_redirect_location()
906 if redirect_location:
907 if response.status == 303:
908 # Change the method according to RFC 9110, Section 15.4.4.
909 method = "GET"
910 # And lose the body not to transfer anything sensitive.
911 body = None
912 # The body is gone, so the state that describes it has to go
913 # too: there is nothing left to frame with chunked transfer
914 # encoding, and nothing left to rewind.
915 chunked = False
916 body_pos = None
917 headers = HTTPHeaderDict(headers)._prepare_for_method_change()
918
919 # Strip headers marked as unsafe to forward to the redirected location.
920 # Check remove_headers_on_redirect to avoid a potential network call within
921 # self.is_same_host() which may use socket.gethostbyname() in the future.
922 if retries.remove_headers_on_redirect and not self.is_same_host(
923 redirect_location
924 ):
925 new_headers = headers.copy() # type: ignore[union-attr]
926 for header in headers:
927 if header.lower() in retries.remove_headers_on_redirect:
928 new_headers.pop(header, None)
929 headers = new_headers
930
931 try:
932 retries = retries.increment(method, url, response=response, _pool=self)
933 except MaxRetryError:
934 if retries.raise_on_redirect:
935 response.drain_conn()
936 raise
937 return response
938
939 response.drain_conn()
940 retries.sleep_for_retry(response)
941 log.debug("Redirecting %s -> %s", url, redirect_location)
942 return self.urlopen(
943 method,
944 redirect_location,
945 body,
946 headers,
947 retries=retries,
948 redirect=redirect,
949 assert_same_host=assert_same_host,
950 timeout=timeout,
951 pool_timeout=pool_timeout,
952 release_conn=release_conn,
953 chunked=chunked,
954 body_pos=body_pos,
955 preload_content=preload_content,
956 decode_content=decode_content,
957 **response_kw,
958 )
959
960 # Check if we should retry the HTTP response.
961 has_retry_after = bool(response.headers.get("Retry-After"))
962 if retries.is_retry(method, response.status, has_retry_after):
963 try:
964 retries = retries.increment(method, url, response=response, _pool=self)
965 except MaxRetryError:
966 if retries.raise_on_status:
967 response.drain_conn()
968 raise
969 return response
970
971 response.drain_conn()
972 retries.sleep(response)
973 log.debug("Retry: %s", url)
974 return self.urlopen(
975 method,
976 url,
977 body,
978 headers,
979 retries=retries,
980 redirect=redirect,
981 assert_same_host=assert_same_host,
982 timeout=timeout,
983 pool_timeout=pool_timeout,
984 release_conn=release_conn,
985 chunked=chunked,
986 body_pos=body_pos,
987 preload_content=preload_content,
988 decode_content=decode_content,
989 **response_kw,
990 )
991
992 return response
993
994
995class HTTPSConnectionPool(HTTPConnectionPool):
996 """
997 Same as :class:`.HTTPConnectionPool`, but HTTPS.
998
999 :class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
1000 ``assert_hostname`` and ``host`` in this order to verify connections.
1001 If ``assert_hostname`` is False, no verification is done.
1002
1003 The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
1004 ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
1005 is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
1006 the connection socket into an SSL socket.
1007 """
1008
1009 scheme = "https"
1010 ConnectionCls: type[BaseHTTPSConnection] = HTTPSConnection
1011
1012 def __init__(
1013 self,
1014 host: str,
1015 port: int | None = None,
1016 timeout: _TYPE_TIMEOUT | None = _DEFAULT_TIMEOUT,
1017 maxsize: int = 1,
1018 block: bool = False,
1019 headers: typing.Mapping[str, str] | None = None,
1020 retries: Retry | bool | int | None = None,
1021 _proxy: Url | None = None,
1022 _proxy_headers: typing.Mapping[str, str] | None = None,
1023 key_file: str | None = None,
1024 cert_file: str | None = None,
1025 cert_reqs: int | str | None = None,
1026 key_password: str | None = None,
1027 ca_certs: str | None = None,
1028 ssl_version: int | str | None = None,
1029 ssl_minimum_version: ssl.TLSVersion | None = None,
1030 ssl_maximum_version: ssl.TLSVersion | None = None,
1031 assert_hostname: str | typing.Literal[False] | None = None,
1032 assert_fingerprint: str | None = None,
1033 ca_cert_dir: str | None = None,
1034 **conn_kw: typing.Any,
1035 ) -> None:
1036 super().__init__(
1037 host,
1038 port,
1039 timeout,
1040 maxsize,
1041 block,
1042 headers,
1043 retries,
1044 _proxy,
1045 _proxy_headers,
1046 **conn_kw,
1047 )
1048
1049 self.key_file = key_file
1050 self.cert_file = cert_file
1051 self.cert_reqs = cert_reqs
1052 self.key_password = key_password
1053 self.ca_certs = ca_certs
1054 self.ca_cert_dir = ca_cert_dir
1055 self.ssl_version = ssl_version
1056 self.ssl_minimum_version = ssl_minimum_version
1057 self.ssl_maximum_version = ssl_maximum_version
1058 self.assert_hostname = assert_hostname
1059 self.assert_fingerprint = assert_fingerprint
1060
1061 def _prepare_proxy(self, conn: HTTPSConnection) -> None: # type: ignore[override]
1062 """Establishes a tunnel connection through HTTP CONNECT."""
1063 if self.proxy and self.proxy.scheme == "https":
1064 tunnel_scheme = "https"
1065 else:
1066 tunnel_scheme = "http"
1067
1068 conn.set_tunnel(
1069 scheme=tunnel_scheme,
1070 host=self._tunnel_host,
1071 port=self.port,
1072 headers=self.proxy_headers,
1073 )
1074 conn.connect()
1075
1076 def _new_conn(self) -> BaseHTTPSConnection:
1077 """
1078 Return a fresh :class:`urllib3.connection.HTTPConnection`.
1079 """
1080 self.num_connections += 1
1081 log.debug(
1082 "Starting new HTTPS connection (%d): %s:%s",
1083 self.num_connections,
1084 self.host,
1085 self.port or "443",
1086 )
1087
1088 if not self.ConnectionCls or self.ConnectionCls is DummyConnection: # type: ignore[comparison-overlap]
1089 raise ImportError(
1090 "Can't connect to HTTPS URL because the SSL module is not available."
1091 )
1092
1093 actual_host: str = self.host
1094 actual_port = self.port
1095 if self.proxy is not None and self.proxy.host is not None:
1096 actual_host = self.proxy.host
1097 actual_port = self.proxy.port
1098
1099 return self.ConnectionCls(
1100 host=actual_host,
1101 port=actual_port,
1102 timeout=self.timeout.connect_timeout,
1103 cert_file=self.cert_file,
1104 key_file=self.key_file,
1105 key_password=self.key_password,
1106 cert_reqs=self.cert_reqs,
1107 ca_certs=self.ca_certs,
1108 ca_cert_dir=self.ca_cert_dir,
1109 assert_hostname=self.assert_hostname,
1110 assert_fingerprint=self.assert_fingerprint,
1111 ssl_version=self.ssl_version,
1112 ssl_minimum_version=self.ssl_minimum_version,
1113 ssl_maximum_version=self.ssl_maximum_version,
1114 **self.conn_kw,
1115 )
1116
1117 def _validate_conn(self, conn: BaseHTTPConnection) -> None:
1118 """
1119 Called right before a request is made, after the socket is created.
1120 """
1121 super()._validate_conn(conn)
1122
1123 # Force connect early to allow us to validate the connection.
1124 if conn.is_closed:
1125 conn.connect()
1126
1127 # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791
1128 if not conn.is_verified and not conn.proxy_is_verified:
1129 warnings.warn(
1130 (
1131 f"Unverified HTTPS request is being made to host '{conn.host}'. "
1132 "Adding certificate verification is strongly advised. See: "
1133 "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
1134 "#tls-warnings"
1135 ),
1136 InsecureRequestWarning,
1137 )
1138
1139
1140def connection_from_url(url: str, **kw: typing.Any) -> HTTPConnectionPool:
1141 """
1142 Given a url, return an :class:`.ConnectionPool` instance of its host.
1143
1144 This is a shortcut for not having to parse out the scheme, host, and port
1145 of the url before creating an :class:`.ConnectionPool` instance.
1146
1147 :param url:
1148 Absolute URL string that must include the scheme. Port is optional.
1149
1150 :param \\**kw:
1151 Passes additional parameters to the constructor of the appropriate
1152 :class:`.ConnectionPool`. Useful for specifying things like
1153 timeout, maxsize, headers, etc.
1154
1155 Example::
1156
1157 >>> conn = connection_from_url('http://google.com/')
1158 >>> r = conn.request('GET', '/')
1159 """
1160 scheme, _, host, port, *_ = parse_url(url)
1161 scheme = scheme or "http"
1162 if port is None:
1163 port = port_by_scheme.get(scheme, 80)
1164 if scheme == "https":
1165 return HTTPSConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
1166 else:
1167 return HTTPConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
1168
1169
1170@typing.overload
1171def _normalize_host(host: None, scheme: str | None) -> None: ...
1172
1173
1174@typing.overload
1175def _normalize_host(host: str, scheme: str | None) -> str: ...
1176
1177
1178def _normalize_host(host: str | None, scheme: str | None) -> str | None:
1179 """
1180 Normalize hosts for comparisons and use with sockets.
1181 """
1182
1183 host = normalize_host(host, scheme)
1184
1185 # httplib doesn't like it when we include brackets in IPv6 addresses
1186 # Specifically, if we include brackets but also pass the port then
1187 # httplib crazily doubles up the square brackets on the Host header.
1188 # Instead, we need to make sure we never pass ``None`` as the port.
1189 # However, for backward compatibility reasons we can't actually
1190 # *assert* that. See http://bugs.python.org/issue28539
1191 if host and host.startswith("[") and host.endswith("]"):
1192 host = host[1:-1]
1193 return host
1194
1195
1196def _url_from_pool(
1197 pool: HTTPConnectionPool | HTTPSConnectionPool, path: str | None = None
1198) -> str:
1199 """Returns the URL from a given connection pool. This is mainly used for testing and logging."""
1200 return Url(scheme=pool.scheme, host=pool.host, port=pool.port, path=path).url
1201
1202
1203def _close_pool_connections(pool: queue.LifoQueue[typing.Any]) -> None:
1204 """Drains a queue of connections and closes each one."""
1205 try:
1206 while True:
1207 conn = pool.get(block=False)
1208 if conn:
1209 conn.close()
1210 except queue.Empty:
1211 pass # Done.