33
33
import re
34
34
import types
35
35
import warnings
36
+ import ipaddress
36
37
37
38
__all__ = ["urlparse" , "urlunparse" , "urljoin" , "urldefrag" ,
38
39
"urlsplit" , "urlunsplit" , "urlencode" , "parse_qs" ,
@@ -199,7 +200,7 @@ def _hostinfo(self):
199
200
_ , _ , hostinfo = netloc .rpartition ('@' )
200
201
_ , have_open_br , bracketed = hostinfo .partition ('[' )
201
202
if have_open_br :
202
- hostname , _ , port = bracketed .partition (']' )
203
+ hostname , _ , port = bracketed .rpartition (']' )
203
204
_ , _ , port = port .partition (':' )
204
205
else :
205
206
hostname , _ , port = hostinfo .partition (':' )
@@ -229,7 +230,7 @@ def _hostinfo(self):
229
230
_ , _ , hostinfo = netloc .rpartition (b'@' )
230
231
_ , have_open_br , bracketed = hostinfo .partition (b'[' )
231
232
if have_open_br :
232
- hostname , _ , port = bracketed .partition (b']' )
233
+ hostname , _ , port = bracketed .rpartition (b']' )
233
234
_ , _ , port = port .partition (b':' )
234
235
else :
235
236
hostname , _ , port = hostinfo .partition (b':' )
@@ -426,6 +427,15 @@ def _checknetloc(netloc):
426
427
if c in netloc2 :
427
428
raise ValueError ("netloc '" + netloc + "' contains invalid " +
428
429
"characters under NFKC normalization" )
430
+
431
+ def _check_bracketed_host (hostname ):
432
+ if hostname .startswith ('v' ):
433
+ if not re .match (r"\Av[a-fA-F0-9]+\..+\Z" , hostname ):
434
+ raise ValueError (f"IPvFuture address is invalid" )
435
+ else :
436
+ ip = ipaddress .ip_address (hostname ) # Throws Value Error if not IPv6 or IPv4
437
+ if isinstance (ip , ipaddress .IPv4Address ):
438
+ raise ValueError (f"An IPv4 address cannot be in brackets" )
429
439
430
440
# typed=True avoids BytesWarnings being emitted during cache key
431
441
# comparison since this API supports both bytes and str input.
@@ -466,12 +476,14 @@ def urlsplit(url, scheme='', allow_fragments=True):
466
476
break
467
477
else :
468
478
scheme , url = url [:i ].lower (), url [i + 1 :]
469
-
470
479
if url [:2 ] == '//' :
471
480
netloc , url = _splitnetloc (url , 2 )
472
481
if (('[' in netloc and ']' not in netloc ) or
473
482
(']' in netloc and '[' not in netloc )):
474
483
raise ValueError ("Invalid IPv6 URL" )
484
+ if '[' in netloc and ']' in netloc :
485
+ bracketed_host = netloc .partition ('[' )[2 ].rpartition (']' )[0 ]
486
+ _check_bracketed_host (bracketed_host )
475
487
if allow_fragments and '#' in url :
476
488
url , fragment = url .split ('#' , 1 )
477
489
if '?' in url :
0 commit comments