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)
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 return _is_same_host(url, self.scheme, self.host, self.port)
582
583 def urlopen( # type: ignore[override]
584 self,
585 method: str,
586 url: str,
587 body: _TYPE_BODY | None = None,
588 headers: typing.Mapping[str, str] | None = None,
589 retries: Retry | bool | int | None = None,
590 redirect: bool = True,
591 assert_same_host: bool = True,
592 timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
593 pool_timeout: int | None = None,
594 release_conn: bool | None = None,
595 chunked: bool = False,
596 body_pos: _TYPE_BODY_POSITION | None = None,
597 preload_content: bool = True,
598 decode_content: bool = True,
599 **response_kw: typing.Any,
600 ) -> BaseHTTPResponse:
601 """
602 Get a connection from the pool and perform an HTTP request. This is the
603 lowest level call for making a request, so you'll need to specify all
604 the raw details.
605
606 .. note::
607
608 More commonly, it's appropriate to use a convenience method
609 such as :meth:`request`.
610
611 .. note::
612
613 `release_conn` will only behave as expected if
614 `preload_content=False` because we want to make
615 `preload_content=False` the default behaviour someday soon without
616 breaking backwards compatibility.
617
618 :param method:
619 HTTP request method (such as GET, POST, PUT, etc.)
620
621 :param url:
622 The URL to perform the request on.
623
624 :param body:
625 Data to send in the request body, either :class:`str`, :class:`bytes`,
626 an iterable of :class:`str`/:class:`bytes`, or a file-like object.
627
628 :param headers:
629 Dictionary of custom headers to send, such as User-Agent,
630 If-None-Match, etc. If None, pool headers are used. If provided,
631 these headers completely replace any pool-specific headers.
632
633 :param retries:
634 Configure the number of retries to allow before raising a
635 :class:`~urllib3.exceptions.MaxRetryError` exception.
636
637 If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a
638 :class:`~urllib3.util.retry.Retry` object for fine-grained control
639 over different types of retries.
640 Pass an integer number to retry connection errors that many times,
641 but no other types of errors. Pass zero to never retry.
642
643 If ``False``, then retries are disabled and any exception is raised
644 immediately. Also, instead of raising a MaxRetryError on redirects,
645 the redirect response will be returned.
646
647 :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
648
649 :param redirect:
650 If True, automatically handle redirects (status codes 301, 302,
651 303, 307, 308). Each redirect counts as a retry. Disabling retries
652 will disable redirect, too.
653
654 :param assert_same_host:
655 If ``True``, will make sure that the host of the pool requests is
656 consistent else will raise HostChangedError. When ``False``, you can
657 use the pool on an HTTP proxy and request foreign hosts.
658
659 :param timeout:
660 If specified, overrides the default timeout for this one
661 request. It may be a float (in seconds) or an instance of
662 :class:`urllib3.util.Timeout`.
663
664 :param pool_timeout:
665 If set and the pool is set to block=True, then this method will
666 block for ``pool_timeout`` seconds and raise EmptyPoolError if no
667 connection is available within the time period.
668
669 :param bool preload_content:
670 If True, the response's body will be preloaded into memory.
671
672 :param bool decode_content:
673 If True, will attempt to decode the body based on the
674 'content-encoding' header.
675
676 :param release_conn:
677 If False, then the urlopen call will not release the connection
678 back into the pool once a response is received (but will release if
679 you read the entire contents of the response such as when
680 `preload_content=True`). This is useful if you're not preloading
681 the response's content immediately. You will need to call
682 ``r.release_conn()`` on the response ``r`` to return the connection
683 back into the pool. If None, it takes the value of ``preload_content``
684 which defaults to ``True``.
685
686 :param bool chunked:
687 If True, urllib3 will send the body using chunked transfer
688 encoding. Otherwise, urllib3 will send the body using the standard
689 content-length form. Defaults to False.
690
691 :param int body_pos:
692 Position to seek to in file-like body in the event of a retry or
693 redirect. Typically this won't need to be set because urllib3 will
694 auto-populate the value when needed.
695 """
696 # Preserve the input for retries so that IPv6 zone identifiers aren't
697 # decoded again when urlopen() normalizes the URL on the next attempt.
698 original_url = url
699
700 # Ensure that the URL we're connecting to is properly encoded
701 if url.startswith("/"):
702 # URLs starting with / are inherently schemeless.
703 url = to_str(_encode_target(url))
704 destination_scheme = None
705 else:
706 parsed_url = parse_url(url)
707 destination_scheme = parsed_url.scheme
708 url = to_str(parsed_url._replace(fragment=None).url)
709
710 if headers is None:
711 headers = self.headers
712
713 if not isinstance(retries, Retry):
714 retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
715
716 if release_conn is None:
717 release_conn = preload_content
718
719 # Check host
720 if assert_same_host and not self.is_same_host(url):
721 raise HostChangedError(self, url, retries)
722
723 conn = None
724
725 # Track whether `conn` needs to be released before
726 # returning/raising/recursing. Update this variable if necessary, and
727 # leave `release_conn` constant throughout the function. That way, if
728 # the function recurses, the original value of `release_conn` will be
729 # passed down into the recursive call, and its value will be respected.
730 #
731 # See issue #651 [1] for details.
732 #
733 # [1] <https://github.com/urllib3/urllib3/issues/651>
734 release_this_conn = release_conn
735
736 http_tunnel_required = connection_requires_http_tunnel(
737 self.proxy, self.proxy_config, destination_scheme
738 )
739
740 # Merge the proxy headers. Only done when not using HTTP CONNECT. We
741 # have to copy the headers dict so we can safely change it without those
742 # changes being reflected in anyone else's copy.
743 if not http_tunnel_required:
744 headers = headers.copy() # type: ignore[attr-defined]
745 headers.update(self.proxy_headers) # type: ignore[union-attr]
746
747 # Must keep the exception bound to a separate variable or else Python 3
748 # complains about UnboundLocalError.
749 err = None
750
751 # Keep track of whether we cleanly exited the except block. This
752 # ensures we do proper cleanup in finally.
753 clean_exit = False
754
755 # Rewind body position, if needed. Record current position
756 # for future rewinds in the event of a redirect/retry.
757 body_pos = set_file_position(body, body_pos)
758
759 timeout_obj = self._get_timeout(timeout)
760 try:
761 # Request a connection from the queue.
762 conn = self._get_conn(timeout=pool_timeout)
763 conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment]
764
765 # Is this a closed/new connection that requires CONNECT tunnelling?
766 if self.proxy is not None and http_tunnel_required and conn.is_closed:
767 try:
768 self._prepare_proxy(conn)
769 except (BaseSSLError, OSError, SocketTimeout) as e:
770 self._raise_timeout(
771 err=e, url=self.proxy.url, timeout_value=conn.timeout
772 )
773 raise
774
775 # If we're going to release the connection in ``finally:``, then
776 # the response doesn't need to know about the connection. Otherwise
777 # it will also try to release it and we'll have a double-release
778 # mess.
779 response_conn = conn if not release_conn else None
780
781 # Make the request on the HTTPConnection object
782 response = self._make_request(
783 conn,
784 method,
785 url,
786 timeout=timeout_obj,
787 body=body,
788 headers=headers,
789 chunked=chunked,
790 retries=retries,
791 response_conn=response_conn,
792 preload_content=preload_content,
793 decode_content=decode_content,
794 **response_kw,
795 )
796
797 # Everything went great!
798 clean_exit = True
799
800 except EmptyPoolError:
801 # Didn't get a connection from the pool, no need to clean up
802 clean_exit = True
803 release_this_conn = False
804 raise
805
806 except (
807 TimeoutError,
808 HTTPException,
809 OSError,
810 ProtocolError,
811 BaseSSLError,
812 SSLError,
813 CertificateError,
814 ProxyError,
815 ) as e:
816 # Discard the connection for these exceptions. It will be
817 # replaced during the next _get_conn() call.
818 clean_exit = False
819 new_e: Exception = e
820 if isinstance(e, (BaseSSLError, CertificateError)):
821 new_e = SSLError(e)
822 if isinstance(
823 new_e,
824 (
825 OSError,
826 NewConnectionError,
827 TimeoutError,
828 SSLError,
829 HTTPException,
830 ),
831 ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
832 new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
833 elif isinstance(new_e, (OSError, HTTPException)):
834 new_e = ProtocolError("Connection aborted.", new_e)
835
836 retries = retries.increment(
837 method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
838 )
839 retries.sleep()
840
841 # Keep track of the error for the retry warning.
842 err = e
843
844 finally:
845 if not clean_exit:
846 # We hit some kind of exception, handled or otherwise. We need
847 # to throw the connection away unless explicitly told not to.
848 # Close the connection, set the variable to None, and make sure
849 # we put the None back in the pool to avoid leaking it.
850 if conn:
851 conn.close()
852 conn = None
853 release_this_conn = True
854
855 if release_this_conn:
856 # Put the connection back to be reused. If the connection is
857 # expired then it will be None, which will get replaced with a
858 # fresh connection during _get_conn.
859 self._put_conn(conn)
860
861 if not conn:
862 # Try again
863 log.warning(
864 "Retrying (%r) after connection broken by '%r': %s",
865 retries,
866 err,
867 url,
868 # Provide an unique attribute with the host needed by pip to
869 # rewrite this warning. Ideally, we'd go with a better solution,
870 # but backwards compatibility and other constraints make those
871 # unfeasible, so this is the least bad option.
872 # See also: https://github.com/urllib3/urllib3/issues/2580.
873 extra={"__urllib3-retry-warning": {"host": self.host}},
874 )
875 return self.urlopen(
876 method,
877 original_url,
878 body,
879 headers,
880 retries,
881 redirect,
882 assert_same_host,
883 timeout=timeout,
884 pool_timeout=pool_timeout,
885 release_conn=release_conn,
886 chunked=chunked,
887 body_pos=body_pos,
888 preload_content=preload_content,
889 decode_content=decode_content,
890 **response_kw,
891 )
892
893 # Handle redirect?
894 redirect_location = redirect and response.get_redirect_location()
895 if redirect_location:
896 if response.status == 303:
897 # Change the method according to RFC 9110, Section 15.4.4.
898 method = "GET"
899 # And lose the body not to transfer anything sensitive.
900 body = None
901 # The body is gone, so the state that describes it has to go
902 # too: there is nothing left to frame with chunked transfer
903 # encoding, and nothing left to rewind.
904 chunked = False
905 body_pos = None
906 headers = HTTPHeaderDict(headers)._prepare_for_method_change()
907
908 # Strip headers marked as unsafe to forward to the redirected location.
909 # Check remove_headers_on_redirect to avoid a potential network call within
910 # self.is_same_host() which may use socket.gethostbyname() in the future.
911 if retries.remove_headers_on_redirect and not self.is_same_host(
912 redirect_location
913 ):
914 new_headers = headers.copy() # type: ignore[union-attr]
915 for header in headers:
916 if header.lower() in retries.remove_headers_on_redirect:
917 new_headers.pop(header, None)
918 headers = new_headers
919
920 try:
921 retries = retries.increment(method, url, response=response, _pool=self)
922 except MaxRetryError:
923 if retries.raise_on_redirect:
924 response.drain_conn()
925 raise
926 return response
927
928 response.drain_conn()
929 retries.sleep_for_retry(response)
930 log.debug("Redirecting %s -> %s", url, redirect_location)
931 return self.urlopen(
932 method,
933 redirect_location,
934 body,
935 headers,
936 retries=retries,
937 redirect=redirect,
938 assert_same_host=assert_same_host,
939 timeout=timeout,
940 pool_timeout=pool_timeout,
941 release_conn=release_conn,
942 chunked=chunked,
943 body_pos=body_pos,
944 preload_content=preload_content,
945 decode_content=decode_content,
946 **response_kw,
947 )
948
949 # Check if we should retry the HTTP response.
950 has_retry_after = bool(response.headers.get("Retry-After"))
951 if retries.is_retry(method, response.status, has_retry_after):
952 try:
953 retries = retries.increment(method, url, response=response, _pool=self)
954 except MaxRetryError:
955 if retries.raise_on_status:
956 response.drain_conn()
957 raise
958 return response
959
960 response.drain_conn()
961 retries.sleep(response)
962 log.debug("Retry: %s", url)
963 return self.urlopen(
964 method,
965 original_url,
966 body,
967 headers,
968 retries=retries,
969 redirect=redirect,
970 assert_same_host=assert_same_host,
971 timeout=timeout,
972 pool_timeout=pool_timeout,
973 release_conn=release_conn,
974 chunked=chunked,
975 body_pos=body_pos,
976 preload_content=preload_content,
977 decode_content=decode_content,
978 **response_kw,
979 )
980
981 return response
982
983
984class HTTPSConnectionPool(HTTPConnectionPool):
985 """
986 Same as :class:`.HTTPConnectionPool`, but HTTPS.
987
988 :class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
989 ``assert_hostname`` and ``host`` in this order to verify connections.
990 If ``assert_hostname`` is False, no verification is done.
991
992 The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
993 ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
994 is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
995 the connection socket into an SSL socket.
996 """
997
998 scheme = "https"
999 ConnectionCls: type[BaseHTTPSConnection] = HTTPSConnection
1000
1001 def __init__(
1002 self,
1003 host: str,
1004 port: int | None = None,
1005 timeout: _TYPE_TIMEOUT | None = _DEFAULT_TIMEOUT,
1006 maxsize: int = 1,
1007 block: bool = False,
1008 headers: typing.Mapping[str, str] | None = None,
1009 retries: Retry | bool | int | None = None,
1010 _proxy: Url | None = None,
1011 _proxy_headers: typing.Mapping[str, str] | None = None,
1012 key_file: str | None = None,
1013 cert_file: str | None = None,
1014 cert_reqs: int | str | None = None,
1015 key_password: str | None = None,
1016 ca_certs: str | None = None,
1017 ssl_version: int | str | None = None,
1018 ssl_minimum_version: ssl.TLSVersion | None = None,
1019 ssl_maximum_version: ssl.TLSVersion | None = None,
1020 assert_hostname: str | typing.Literal[False] | None = None,
1021 assert_fingerprint: str | None = None,
1022 ca_cert_dir: str | None = None,
1023 **conn_kw: typing.Any,
1024 ) -> None:
1025 super().__init__(
1026 host,
1027 port,
1028 timeout,
1029 maxsize,
1030 block,
1031 headers,
1032 retries,
1033 _proxy,
1034 _proxy_headers,
1035 **conn_kw,
1036 )
1037
1038 self.key_file = key_file
1039 self.cert_file = cert_file
1040 self.cert_reqs = cert_reqs
1041 self.key_password = key_password
1042 self.ca_certs = ca_certs
1043 self.ca_cert_dir = ca_cert_dir
1044 self.ssl_version = ssl_version
1045 self.ssl_minimum_version = ssl_minimum_version
1046 self.ssl_maximum_version = ssl_maximum_version
1047 self.assert_hostname = assert_hostname
1048 self.assert_fingerprint = assert_fingerprint
1049
1050 def _prepare_proxy(self, conn: HTTPSConnection) -> None: # type: ignore[override]
1051 """Establishes a tunnel connection through HTTP CONNECT."""
1052 if self.proxy and self.proxy.scheme == "https":
1053 tunnel_scheme = "https"
1054 else:
1055 tunnel_scheme = "http"
1056
1057 conn.set_tunnel(
1058 scheme=tunnel_scheme,
1059 host=self._tunnel_host,
1060 port=self.port,
1061 headers=self.proxy_headers,
1062 )
1063 conn.connect()
1064
1065 def _new_conn(self) -> BaseHTTPSConnection:
1066 """
1067 Return a fresh :class:`urllib3.connection.HTTPConnection`.
1068 """
1069 self.num_connections += 1
1070 log.debug(
1071 "Starting new HTTPS connection (%d): %s:%s",
1072 self.num_connections,
1073 self.host,
1074 self.port or "443",
1075 )
1076
1077 if not self.ConnectionCls or self.ConnectionCls is DummyConnection: # type: ignore[comparison-overlap]
1078 raise ImportError(
1079 "Can't connect to HTTPS URL because the SSL module is not available."
1080 )
1081
1082 actual_host: str = self.host
1083 actual_port = self.port
1084 if self.proxy is not None and self.proxy.host is not None:
1085 actual_host = self.proxy.host
1086 actual_port = self.proxy.port
1087
1088 return self.ConnectionCls(
1089 host=actual_host,
1090 port=actual_port,
1091 timeout=self.timeout.connect_timeout,
1092 cert_file=self.cert_file,
1093 key_file=self.key_file,
1094 key_password=self.key_password,
1095 cert_reqs=self.cert_reqs,
1096 ca_certs=self.ca_certs,
1097 ca_cert_dir=self.ca_cert_dir,
1098 assert_hostname=self.assert_hostname,
1099 assert_fingerprint=self.assert_fingerprint,
1100 ssl_version=self.ssl_version,
1101 ssl_minimum_version=self.ssl_minimum_version,
1102 ssl_maximum_version=self.ssl_maximum_version,
1103 **self.conn_kw,
1104 )
1105
1106 def _validate_conn(self, conn: BaseHTTPConnection) -> None:
1107 """
1108 Called right before a request is made, after the socket is created.
1109 """
1110 super()._validate_conn(conn)
1111
1112 # Force connect early to allow us to validate the connection.
1113 if conn.is_closed:
1114 conn.connect()
1115
1116 # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791
1117 if not conn.is_verified and not conn.proxy_is_verified:
1118 warnings.warn(
1119 (
1120 f"Unverified HTTPS request is being made to host '{conn.host}'. "
1121 "Adding certificate verification is strongly advised. See: "
1122 "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
1123 "#tls-warnings"
1124 ),
1125 InsecureRequestWarning,
1126 )
1127
1128
1129def connection_from_url(url: str, **kw: typing.Any) -> HTTPConnectionPool:
1130 """
1131 Given a url, return an :class:`.ConnectionPool` instance of its host.
1132
1133 This is a shortcut for not having to parse out the scheme, host, and port
1134 of the url before creating an :class:`.ConnectionPool` instance.
1135
1136 :param url:
1137 Absolute URL string that must include the scheme. Port is optional.
1138
1139 :param \\**kw:
1140 Passes additional parameters to the constructor of the appropriate
1141 :class:`.ConnectionPool`. Useful for specifying things like
1142 timeout, maxsize, headers, etc.
1143
1144 Example::
1145
1146 >>> conn = connection_from_url('http://google.com/')
1147 >>> r = conn.request('GET', '/')
1148 """
1149 scheme, _, host, port, *_ = parse_url(url)
1150 scheme = scheme or "http"
1151 if port is None:
1152 port = port_by_scheme.get(scheme, 80)
1153 if scheme == "https":
1154 return HTTPSConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
1155 else:
1156 return HTTPConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
1157
1158
1159@typing.overload
1160def _normalize_host(host: None, scheme: str | None) -> None: ...
1161
1162
1163@typing.overload
1164def _normalize_host(host: str, scheme: str | None) -> str: ...
1165
1166
1167def _normalize_host(host: str | None, scheme: str | None) -> str | None:
1168 """
1169 Normalize hosts for comparisons and use with sockets.
1170 """
1171
1172 host = normalize_host(host, scheme)
1173
1174 # httplib doesn't like it when we include brackets in IPv6 addresses
1175 # Specifically, if we include brackets but also pass the port then
1176 # httplib crazily doubles up the square brackets on the Host header.
1177 # Instead, we need to make sure we never pass ``None`` as the port.
1178 # However, for backward compatibility reasons we can't actually
1179 # *assert* that. See http://bugs.python.org/issue28539
1180 if host and host.startswith("[") and host.endswith("]"):
1181 host = host[1:-1]
1182 return host
1183
1184
1185def _is_same_host(
1186 url: str, scheme: str | None, host: str | None, port: int | None
1187) -> bool:
1188 """
1189 Check if the given ``url`` is a member of the same host as the given
1190 ``scheme``, ``host`` and ``port``. ``host`` is expected to be
1191 normalized with :func:`_normalize_host` already.
1192 """
1193 if url.startswith("/"):
1194 return True
1195
1196 # TODO: Add optional support for socket.gethostbyname checking.
1197 url_scheme, _, url_host, url_port, *_ = parse_url(url)
1198 url_scheme = url_scheme or "http"
1199 if url_host is not None:
1200 url_host = _normalize_host(url_host, scheme=url_scheme)
1201
1202 # Use explicit default port for comparison when none is given
1203 if port is not None and url_port is None:
1204 url_port = port_by_scheme.get(url_scheme)
1205 elif port is None and url_port == port_by_scheme.get(url_scheme):
1206 url_port = None
1207
1208 return (url_scheme, url_host, url_port) == (scheme, host, port)
1209
1210
1211def _url_from_pool(
1212 pool: HTTPConnectionPool | HTTPSConnectionPool, path: str | None = None
1213) -> str:
1214 """Returns the URL from a given connection pool. This is mainly used for testing and logging."""
1215 return Url(scheme=pool.scheme, host=pool.host, port=pool.port, path=path).url
1216
1217
1218def _close_pool_connections(pool: queue.LifoQueue[typing.Any]) -> None:
1219 """Drains a queue of connections and closes each one."""
1220 try:
1221 while True:
1222 conn = pool.get(block=False)
1223 if conn:
1224 conn.close()
1225 except queue.Empty:
1226 pass # Done.