|
91 | 91 | # Unsafe bytes to be removed per WHATWG spec |
92 | 92 | _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] |
93 | 93 |
|
| 94 | +# Zone ID regex as defined in RFC 6874 |
| 95 | +zone_id_regex = re.compile(r"(%[a-fA-F0-9]{2}|[\w\.~-])+") |
| 96 | + |
94 | 97 | def clear_cache(): |
95 | 98 | """Clear internal performance caches. Undocumented; some tests want it.""" |
96 | 99 | urlsplit.cache_clear() |
@@ -461,13 +464,13 @@ def _check_bracketed_netloc(netloc): |
461 | 464 | def _check_bracketed_host(hostname): |
462 | 465 | if hostname.startswith('v'): |
463 | 466 | if not re.match(r"\Av[a-fA-F0-9]+\..+\z", hostname): |
464 | | - raise ValueError(f"IPvFuture address is invalid") |
| 467 | + raise ValueError("IPvFuture address is invalid") |
465 | 468 | else: |
466 | 469 | ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 |
467 | 470 | if isinstance(ip, ipaddress.IPv4Address): |
468 | | - raise ValueError(f"An IPv4 address cannot be in brackets") |
469 | | - if "%" in hostname and not re.match(r"\A(%[a-fA-F0-9]{2}|[\w\.~-])+\z", hostname.split("%", 1)[1], flags=re.ASCII): |
470 | | - raise ValueError(f"IPv6 ZoneID is invalid") |
| 471 | + raise ValueError("An IPv4 address cannot be in brackets") |
| 472 | + if "%" in hostname and not zone_id_regex.fullmatch(hostname.split("%", 1)[1], flags=re.ASCII): |
| 473 | + raise ValueError("IPv6 ZoneID is invalid") |
471 | 474 |
|
472 | 475 | # typed=True avoids BytesWarnings being emitted during cache key |
473 | 476 | # comparison since this API supports both bytes and str input. |
|
0 commit comments