Skip to content

Commit b8bc0dd

Browse files
hhirtzdirkf
authored and
GitHub Actions
committed
[utils] Handle user:pass in URLs (#28801)
* Handle user:pass in URLs Fixes "nonnumeric port" errors when youtube-dl is given URLs with usernames and passwords such as: http://username:[email protected]/myvideo.mp4 Refs: - https://en.wikipedia.org/wiki/Basic_access_authentication - https://tools.ietf.org/html/rfc1738#section-3.1 - https://docs.python.org/3.8/library/urllib.parse.html#urllib.parse.urlsplit Fixes #18276 (point 4) Fixes #20258 Fixes #26211 (see comment) * Align code with yt-dlp --------- Co-authored-by: dirkf <[email protected]>
1 parent 0f4c1b0 commit b8bc0dd

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

test/test_utils.py

+13
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
sanitize_filename,
8282
sanitize_path,
8383
sanitize_url,
84+
sanitized_Request,
8485
shell_quote,
8586
smuggle_url,
8687
str_or_none,
@@ -255,6 +256,18 @@ def test_sanitize_url(self):
255256
self.assertEqual(sanitize_url('https://foo.bar'), 'https://foo.bar')
256257
self.assertEqual(sanitize_url('foo bar'), 'foo bar')
257258

259+
def test_sanitized_Request(self):
260+
self.assertFalse(sanitized_Request('http://foo.bar').has_header('Authorization'))
261+
self.assertFalse(sanitized_Request('http://:foo.bar').has_header('Authorization'))
262+
self.assertEqual(sanitized_Request('http://@foo.bar').get_header('Authorization'),
263+
'Basic Og==')
264+
self.assertEqual(sanitized_Request('http://:[email protected]').get_header('Authorization'),
265+
'Basic OnBhc3M=')
266+
self.assertEqual(sanitized_Request('http://user:@foo.bar').get_header('Authorization'),
267+
'Basic dXNlcjo=')
268+
self.assertEqual(sanitized_Request('http://user:[email protected]').get_header('Authorization'),
269+
'Basic dXNlcjpwYXNz')
270+
258271
def test_expand_path(self):
259272
def env(var):
260273
return '%{0}%'.format(var) if sys.platform == 'win32' else '${0}'.format(var)

youtube_dl/utils.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -2182,8 +2182,28 @@ def sanitize_url(url):
21822182
return url
21832183

21842184

2185+
def extract_basic_auth(url):
2186+
parts = compat_urllib_parse.urlsplit(url)
2187+
if parts.username is None:
2188+
return url, None
2189+
url = compat_urllib_parse.urlunsplit(parts._replace(netloc=(
2190+
parts.hostname if parts.port is None
2191+
else '%s:%d' % (parts.hostname, parts.port))))
2192+
auth_payload = base64.b64encode(
2193+
('%s:%s' % (parts.username, parts.password or '')).encode('utf-8'))
2194+
return url, 'Basic {0}'.format(auth_payload.decode('ascii'))
2195+
2196+
21852197
def sanitized_Request(url, *args, **kwargs):
2186-
return compat_urllib_request.Request(escape_url(sanitize_url(url)), *args, **kwargs)
2198+
url, auth_header = extract_basic_auth(escape_url(sanitize_url(url)))
2199+
if auth_header is not None:
2200+
headers = args[1] if len(args) > 1 else kwargs.get('headers')
2201+
headers = headers or {}
2202+
headers['Authorization'] = auth_header
2203+
if len(args) <= 1 and kwargs.get('headers') is None:
2204+
kwargs['headers'] = headers
2205+
kwargs = compat_kwargs(kwargs)
2206+
return compat_urllib_request.Request(url, *args, **kwargs)
21872207

21882208

21892209
def expand_path(s):

0 commit comments

Comments
 (0)