from ..dependencies import brotli, requests, urllib3
from ..utils import bug_reports_message, int_or_none, variadic
+from ..utils.networking import normalize_url
if requests is None:
raise ImportError('requests module is not installed')
if urllib3_version < (1, 26, 17):
raise ImportError('Only urllib3 >= 1.26.17 is supported')
-if requests.__build__ < 0x023100:
- raise ImportError('Only requests >= 2.31.0 is supported')
+if requests.__build__ < 0x023200:
+ raise ImportError('Only requests >= 2.32.0 is supported')
import requests.adapters
import requests.utils
"""
if urllib3_version < (2, 0, 0):
- with contextlib.suppress():
+ with contextlib.suppress(Exception):
urllib3.util.IS_SECURETRANSPORT = urllib3.util.ssl_.IS_SECURETRANSPORT = True
return super().proxy_manager_for(proxy, **proxy_kwargs, **self._pm_args, **extra_kwargs)
def cert_verify(*args, **kwargs):
- # lean on SSLContext for cert verification
+ # Lean on our SSLContext for cert verification
pass
+ def _get_connection(self, request, *_, proxies=None, **__):
+ # Lean on our SSLContext for cert verification
+ return self.get_connection(request.url, proxies)
+
class RequestsSession(requests.sessions.Session):
"""
Ensure unified redirect method handling with our urllib redirect handler.
"""
+
def rebuild_method(self, prepared_request, response):
new_method = get_redirect_method(prepared_request.method, response.status_code)
prepared_request.method = new_method
+ # Requests fails to resolve dot segments on absolute redirect locations
+ # See: https://github.com/yt-dlp/yt-dlp/issues/9020
+ prepared_request.url = normalize_url(prepared_request.url)
+
def rebuild_auth(self, prepared_request, response):
# HACK: undo status code change from rebuild_method, if applicable.
# rebuild_auth runs after requests would remove headers/body based on status code
class Urllib3LoggingHandler(logging.Handler):
"""Redirect urllib3 logs to our logger"""
+
def __init__(self, logger, *args, **kwargs):
super().__init__(*args, **kwargs)
self._logger = logger
# Forward urllib3 debug messages to our logger
logger = logging.getLogger('urllib3')
- handler = Urllib3LoggingHandler(logger=self._logger)
- handler.setFormatter(logging.Formatter('requests: %(message)s'))
- handler.addFilter(Urllib3LoggingFilter())
- logger.addHandler(handler)
- logger.setLevel(logging.WARNING)
+ self.__logging_handler = Urllib3LoggingHandler(logger=self._logger)
+ self.__logging_handler.setFormatter(logging.Formatter('requests: %(message)s'))
+ self.__logging_handler.addFilter(Urllib3LoggingFilter())
+ logger.addHandler(self.__logging_handler)
+ # TODO: Use a logger filter to suppress pool reuse warning instead
+ logger.setLevel(logging.ERROR)
if self.verbose:
# Setting this globally is not ideal, but is easier than hacking with urllib3.
def close(self):
self._clear_instances()
+ # Remove the logging handler that contains a reference to our logger
+ # See: https://github.com/yt-dlp/yt-dlp/issues/8922
+ logging.getLogger('urllib3').removeHandler(self.__logging_handler)
def _check_extensions(self, extensions):
super()._check_extensions(extensions)
max_redirects_exceeded = False
- session = self._get_instance(
- cookiejar=request.extensions.get('cookiejar') or self.cookiejar)
+ session = self._get_instance(cookiejar=self._get_cookiejar(request))
try:
requests_res = session.request(
url=request.url,
data=request.data,
headers=headers,
- timeout=float(request.extensions.get('timeout') or self.timeout),
- proxies=request.proxies or self.proxies,
+ timeout=self._calculate_timeout(request),
+ proxies=self._get_proxies(request),
allow_redirects=True,
stream=True
)
self, f'Connection to {self.host} timed out. (connect timeout={self.timeout})') from e
except SocksProxyError as e:
raise urllib3.exceptions.ProxyError(str(e), e) from e
- except (OSError, socket.error) as e:
+ except OSError as e:
raise urllib3.exceptions.NewConnectionError(
self, f'Failed to establish a new connection: {e}') from e