|
|
@ -882,7 +882,40 @@ def _create_http_connection(ydl_handler, http_class, is_https, *args, **kwargs):
|
|
|
|
kwargs['strict'] = True
|
|
|
|
kwargs['strict'] = True
|
|
|
|
hc = http_class(*args, **compat_kwargs(kwargs))
|
|
|
|
hc = http_class(*args, **compat_kwargs(kwargs))
|
|
|
|
source_address = ydl_handler._params.get('source_address')
|
|
|
|
source_address = ydl_handler._params.get('source_address')
|
|
|
|
|
|
|
|
|
|
|
|
if source_address is not None:
|
|
|
|
if source_address is not None:
|
|
|
|
|
|
|
|
filter_for = socket.AF_INET if '.' in source_address else socket.AF_INET6
|
|
|
|
|
|
|
|
# This is to workaround _create_connection() from socket where it will try all
|
|
|
|
|
|
|
|
# address data from getaddrinfo() including IPv6. This filters the result from
|
|
|
|
|
|
|
|
# getaddrinfo() based on the source_address value.
|
|
|
|
|
|
|
|
# This is based on the cpython socket.create_connection() function.
|
|
|
|
|
|
|
|
# https://github.com/python/cpython/blob/master/Lib/socket.py#L691
|
|
|
|
|
|
|
|
def _create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
|
|
|
|
|
|
|
|
host, port = address
|
|
|
|
|
|
|
|
err = None
|
|
|
|
|
|
|
|
addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)
|
|
|
|
|
|
|
|
ip_addrs = [addr for addr in addrs if addr[0] == filter_for]
|
|
|
|
|
|
|
|
for res in ip_addrs:
|
|
|
|
|
|
|
|
af, socktype, proto, canonname, sa = res
|
|
|
|
|
|
|
|
sock = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
sock = socket.socket(af, socktype, proto)
|
|
|
|
|
|
|
|
if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
|
|
|
|
|
|
|
|
sock.settimeout(timeout)
|
|
|
|
|
|
|
|
sock.bind(source_address)
|
|
|
|
|
|
|
|
sock.connect(sa)
|
|
|
|
|
|
|
|
err = None # Explicitly break reference cycle
|
|
|
|
|
|
|
|
return sock
|
|
|
|
|
|
|
|
except socket.error as _:
|
|
|
|
|
|
|
|
err = _
|
|
|
|
|
|
|
|
if sock is not None:
|
|
|
|
|
|
|
|
sock.close()
|
|
|
|
|
|
|
|
if err is not None:
|
|
|
|
|
|
|
|
raise err
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
raise socket.error('Unknown error occurred')
|
|
|
|
|
|
|
|
hc._create_connection = _create_connection
|
|
|
|
|
|
|
|
|
|
|
|
sa = (source_address, 0)
|
|
|
|
sa = (source_address, 0)
|
|
|
|
if hasattr(hc, 'source_address'): # Python 2.7+
|
|
|
|
if hasattr(hc, 'source_address'): # Python 2.7+
|
|
|
|
hc.source_address = sa
|
|
|
|
hc.source_address = sa
|
|
|
|