|
101 | 101 | from urllib.parse import ( |
102 | 102 | urlparse, urlsplit, urljoin, unwrap, quote, unquote, |
103 | 103 | _splittype, _splithost, _splitport, _splituser, _splitpasswd, |
104 | | - _splitattr, _splitvalue, _splittag, |
| 104 | + _splitattr, _splitvalue, _splittag, _splitnetloc, |
| 105 | + _WHATWG_C0_CONTROL_OR_SPACE, _UNSAFE_URL_BYTES_TO_REMOVE, |
105 | 106 | unquote_to_bytes, urlunparse) |
106 | 107 | from urllib.response import addinfourl, addclosehook |
107 | 108 |
|
@@ -1681,7 +1682,22 @@ def url2pathname(url, *, require_scheme=False, resolve_host=False): |
1681 | 1682 | """ |
1682 | 1683 | if not require_scheme: |
1683 | 1684 | url = 'file:' + url |
1684 | | - scheme, authority, url = urlsplit(url)[:3] # Discard query and fragment. |
| 1685 | + # Match urlsplit()'s own control-character handling up front, so the |
| 1686 | + # except branch below can reuse this same cleaned-up string. |
| 1687 | + url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) |
| 1688 | + for b in _UNSAFE_URL_BYTES_TO_REMOVE: |
| 1689 | + url = url.replace(b, '') |
| 1690 | + try: |
| 1691 | + scheme, authority, url = urlsplit(url)[:3] # Discard query and fragment. |
| 1692 | + except ValueError: |
| 1693 | + # The authority here is not a real host[:port] pair -- it may |
| 1694 | + # hold a Windows drive letter (e.g. 'C:\\') -- so urlsplit()'s |
| 1695 | + # eager port check doesn't apply; split without it instead. |
| 1696 | + scheme, _, url = url.partition(':') |
| 1697 | + scheme = scheme.lower() |
| 1698 | + authority = '' |
| 1699 | + if url[:2] == '//': |
| 1700 | + authority, url = _splitnetloc(url, 2) |
1685 | 1701 | if scheme != 'file': |
1686 | 1702 | raise URLError("URL is missing a 'file:' scheme") |
1687 | 1703 | if os.name == 'nt': |
|
0 commit comments