10000 [3.11] gh-103848: Adds checks to ensure that bracketed hosts found by… · gentoo/cpython@28bc8e7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 28bc8e7

Browse files
miss-islingtonJohnJamesUtleygpshead
authored andcommitted
[3.11] pythongh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (pythonGH-103849) (python#104349)
pythongh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (pythonGH-103849) * Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format --------- (cherry picked from commit 29f348e) Co-authored-by: JohnJamesUtley <81572567+JohnJamesUtley@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent 4979be0 commit 28bc8e7

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

Lib/test/test_urlparse.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,32 @@ def test_issue14072(self):
11621162
self.assertEqual(p2.scheme, 'tel')
11631163
self.assertEqual(p2.path, '+31641044153')
11641164

1165+
def test_invalid_bracketed_hosts(self):
1166+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[192.0.2.146]/Path?Query')
1167+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[important.com:8000]/Path?Query')
1168+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123r.IP]/Path?Query')
1169+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v12ae]/Path?Query')
1170+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v.IP]/Path?Query')
1171+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123.]/Path?Query')
1172+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v]/Path?Query')
1173+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query')
1174+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query')
1175+
self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path')
1176+
1177+
def test_splitting_bracketed_hosts(self):
1178+
p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query')
1179+
self.assertEqual(p1.hostname, 'v6a.ip')
1180+
self.assertEqual(p1.username, 'user')
1181+
self.assertEqual(p1.path, '/path')
1182+
p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query')
1183+
self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test')
1184+
self.assertEqual(p2.username, 'user')
1185+
self.assertEqual(p2.path, '/path')
1186+
p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query')
1187+
self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test')
1188+
self.assertEqual(p3.username, 'user')
1189+
self.assertEqual(p3.path, '/path')
1190+
11651191
def test_port_casting_failure_message(self):
11661192
message = "Port could not be cast to integer value as 'oracle'"
11671193
p1 = urllib.parse.urlparse('http://Server=sde; Service=sde:oracle')

Lib/urllib/parse.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import sys
3636
import collections
3737
import warnings
38+
import ipaddress
3839

3940
__all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag",
4041
"urlsplit", "urlunsplit", "urlencode", "parse_qs",
@@ -430,6 +431,18 @@ def _remove_unsafe_bytes_from_url(url):
430431
url = url.replace(b, "")
431432
return url
432433

434+
435+
# Valid bracketed hosts are defined in
436+
# https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/
437+
def _check_bracketed_host(hostname):
438+
if hostname.startswith('v'):
439+
if not re.match(r"\Av[a-fA-F0-9]+\..+\Z", hostname):
440+
raise ValueError(f"IPvFuture address is invalid")
441+
else:
442+
ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4
443+
if isinstance(ip, ipaddress.IPv4Address):
444+
raise ValueError(f"An IPv4 address cannot be in brackets")
445+
433446
def urlsplit(url, scheme='', allow_fragments=True):
434447
"""Parse a URL into 5 components:
435448
<scheme>://<netloc>/<path>?<query>#<fragment>
@@ -484,6 +497,9 @@ def urlsplit(url, scheme='', allow_fragments=True):
484497
if (('[' in netloc and ']' not in netloc) or
485498
(']' in netloc and '[' not in netloc)):
486499
raise ValueError("Invalid IPv6 URL")
500+
if '[' in netloc and ']' in netloc:
501+
bracketed_host = netloc.partition('[')[2].partition(']')[0]
502+
_check_bracketed_host(bracketed_host)
487503
if allow_fragments and '#' in url:
488504
url, fragment = url.split('#', 1)
489505
if '?' in url:

0 commit comments

Comments
 (0)
0