Handle urllib3 not being available

pull/9625/head
coletdjnz 2024-04-06 15:40:29 +13:00
rodzic 3999a510f7
commit 01fe8e8fa6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 91984263BB39894A
4 zmienionych plików z 57 dodań i 25 usunięć

Wyświetl plik

@ -156,7 +156,10 @@ class WebSocketSecureProxyHandler(WebSocketProxyHandler):
certfn = os.path.join(TEST_DIR, 'testcert.pem') certfn = os.path.join(TEST_DIR, 'testcert.pem')
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.load_cert_chain(certfn, None) sslctx.load_cert_chain(certfn, None)
request = SSLTransport(request, ssl_context=sslctx, server_side=True) if SSLTransport:
request = SSLTransport(request, ssl_context=sslctx, server_side=True)
else:
request = sslctx.wrap_socket(request, server_side=True)
super().__init__(request, *args, **kwargs) super().__init__(request, *args, **kwargs)

Wyświetl plik

@ -4137,15 +4137,15 @@ class YoutubeDL:
'Use --enable-file-urls to enable at your own risk.', cause=ue) from ue 'Use --enable-file-urls to enable at your own risk.', cause=ue) from ue
if ( if (
'unsupported proxy type: "https"' in ue.msg.lower() 'unsupported proxy type: "https"' in ue.msg.lower()
and 'requests' not in self._request_director.handlers and 'Requests' not in self._request_director.handlers
and 'curl_cffi' not in self._request_director.handlers and 'CurlCFFI' not in self._request_director.handlers
): ):
raise RequestError( raise RequestError(
'To use an HTTPS proxy for this request, one of the following dependencies needs to be installed: requests, curl_cffi') 'To use an HTTPS proxy for this request, one of the following dependencies needs to be installed: requests, curl_cffi')
elif ( elif (
re.match(r'unsupported url scheme: "wss?"', ue.msg.lower()) re.match(r'unsupported url scheme: "wss?"', ue.msg.lower())
and 'websockets' not in self._request_director.handlers and 'Websockets' not in self._request_director.handlers
): ):
raise RequestError( raise RequestError(
'This request requires WebSocket support. ' 'This request requires WebSocket support. '

Wyświetl plik

@ -19,20 +19,18 @@ from .exceptions import (
ProxyError, ProxyError,
RequestError, RequestError,
SSLError, SSLError,
TransportError, TransportError, UnsupportedRequest,
) )
from .websocket import WebSocketRequestHandler, WebSocketResponse from .websocket import WebSocketRequestHandler, WebSocketResponse
from ..compat import functools from ..compat import functools
from ..dependencies import websockets from ..dependencies import websockets, urllib3
from ..socks import ProxyError as SocksProxyError from ..socks import ProxyError as SocksProxyError
from ..utils import int_or_none, extract_basic_auth from ..utils import int_or_none
import io import io
import urllib.parse import urllib.parse
import base64 import base64
from http.client import HTTPResponse, HTTPConnection, HTTPSConnection from http.client import HTTPResponse, HTTPConnection
from urllib3.util.ssltransport import SSLTransport
from ..utils.networking import HTTPHeaderDict from ..utils.networking import HTTPHeaderDict
@ -45,6 +43,11 @@ websockets_version = tuple(map(int_or_none, websockets.version.version.split('.'
if websockets_version < (12, 0): if websockets_version < (12, 0):
raise ImportError('Only websockets>=12.0 is supported') raise ImportError('Only websockets>=12.0 is supported')
urllib3_supported = False
urllib3_version = tuple(int_or_none(x, default=0) for x in urllib3.__version__.split('.')) if urllib3 else None
if urllib3_version and urllib3_version >= (1, 26, 17):
urllib3_supported = True
import websockets.sync.client import websockets.sync.client
from websockets.uri import parse_uri from websockets.uri import parse_uri
@ -124,6 +127,17 @@ class WebsocketsRH(WebSocketRequestHandler):
if self.verbose: if self.verbose:
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
def _validate(self, request):
super()._validate(request)
proxy = select_proxy(request.url, self._get_proxies(request))
if (
proxy
and urllib.parse.urlparse(proxy).scheme.lower() == 'https'
and urllib.parse.urlparse(request.url).scheme.lower() == 'wss'
and not urllib3_supported
):
raise UnsupportedRequest('WSS over HTTPS proxies requires a supported version of urllib3')
def _check_extensions(self, extensions): def _check_extensions(self, extensions):
super()._check_extensions(extensions) super()._check_extensions(extensions)
extensions.pop('timeout', None) extensions.pop('timeout', None)
@ -178,6 +192,12 @@ class WebsocketsRH(WebSocketRequestHandler):
proxy = select_proxy(request.url, self._get_proxies(request)) proxy = select_proxy(request.url, self._get_proxies(request))
ssl_context = None
if parse_uri(request.url).secure:
if WebsocketsSSLContext is not None:
ssl_context = WebsocketsSSLContext(self._make_sslcontext())
else:
ssl_context = self._make_sslcontext()
try: try:
conn = websockets.sync.client.connect( conn = websockets.sync.client.connect(
sock=self._make_sock(proxy, request.url, timeout), sock=self._make_sock(proxy, request.url, timeout),
@ -185,10 +205,7 @@ class WebsocketsRH(WebSocketRequestHandler):
additional_headers=headers, additional_headers=headers,
open_timeout=timeout, open_timeout=timeout,
user_agent_header=None, user_agent_header=None,
ssl_context=( ssl_context=ssl_context,
WebsocketsSSLContext(self._make_sslcontext())
if parse_uri(request.url).secure else None
),
close_timeout=0, # not ideal, but prevents yt-dlp hanging close_timeout=0, # not ideal, but prevents yt-dlp hanging
) )
return WebsocketsResponseAdapter(conn, url=request.url) return WebsocketsResponseAdapter(conn, url=request.url)
@ -223,17 +240,21 @@ class NoCloseHTTPResponse(HTTPResponse):
self.will_close = False self.will_close = False
# todo: only define if urllib3 is available if urllib3_supported:
class WebsocketsSSLTransport(SSLTransport): from urllib3.util.ssltransport import SSLTransport
"""
Modified version of urllib3 SSLTransport to support additional operations used by websockets
"""
def setsockopt(self, *args, **kwargs):
self.socket.setsockopt(*args, **kwargs)
def shutdown(self, *args, **kwargs): class WebsocketsSSLTransport(SSLTransport):
self.unwrap() """
self.socket.shutdown(*args, **kwargs) Modified version of urllib3 SSLTransport to support additional operations used by websockets
"""
def setsockopt(self, *args, **kwargs):
self.socket.setsockopt(*args, **kwargs)
def shutdown(self, *args, **kwargs):
self.unwrap()
self.socket.shutdown(*args, **kwargs)
else:
WebsocketsSSLTransport = None
class WebsocketsSSLContext: class WebsocketsSSLContext:

Wyświetl plik

@ -1,8 +1,9 @@
from __future__ import annotations from __future__ import annotations
import abc import abc
import urllib.parse
from .common import RequestHandler, Response from .common import RequestHandler, Response, register_preference
class WebSocketResponse(Response): class WebSocketResponse(Response):
@ -21,3 +22,10 @@ class WebSocketResponse(Response):
class WebSocketRequestHandler(RequestHandler, abc.ABC): class WebSocketRequestHandler(RequestHandler, abc.ABC):
pass pass
@register_preference(WebSocketRequestHandler)
def websocket_preference(_, request):
if urllib.parse.urlparse(request.url).scheme in ('ws', 'wss'):
return 200
return 0