GH-126766: `url2pathname()`: handle 'localhost' authority (GH-127129)
Discard any 'localhost' authority from the beginning of a `file:` URI. As a
result, file URIs like `//localhost/etc/hosts` are correctly decoded as
`/etc/hosts`.
(cherry picked from commit
ebf564a1d3e2e81b9846535114e481d6096443d2)
Co-authored-by: Barney Gale <barney.gale@gmail.com>
# become
# C:\foo\bar\spam.foo
import string, urllib.parse
+ if url[:3] == '///':
+ # URL has an empty authority section, so the path begins on the third
+ # character.
+ url = url[2:]
+ elif url[:12] == '//localhost/':
+ # Skip past 'localhost' authority.
+ url = url[11:]
# Windows itself uses ":" even in URLs.
url = url.replace(':', '|')
if not '|' in url:
# No drive specifier, just convert slashes
- if url[:3] == '///':
- # URL has an empty authority section, so the path begins on the
- # third character.
- url = url[2:]
# make sure not to convert quoted slashes :-)
return urllib.parse.unquote(url.replace('/', '\\'))
comp = url.split('|')
# Localhost paths
self.assertEqual(fn('//localhost/C:/path/to/file'), 'C:\\path\\to\\file')
self.assertEqual(fn('//localhost/C|/path/to/file'), 'C:\\path\\to\\file')
+ self.assertEqual(fn('//localhost/path/to/file'), '\\path\\to\\file')
+ self.assertEqual(fn('//localhost//server/path/to/file'), '\\\\server\\path\\to\\file')
# Percent-encoded forward slashes are preserved for backwards compatibility
self.assertEqual(fn('C:/foo%2fbar'), 'C:\\foo/bar')
self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar')
self.assertEqual(fn('//foo/bar'), '//foo/bar')
self.assertEqual(fn('///foo/bar'), '/foo/bar')
self.assertEqual(fn('////foo/bar'), '//foo/bar')
- self.assertEqual(fn('//localhost/foo/bar'), '//localhost/foo/bar')
+ self.assertEqual(fn('//localhost/foo/bar'), '/foo/bar')
@unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII')
def test_url2pathname_nonascii(self):
# URL has an empty authority section, so the path begins on the
# third character.
pathname = pathname[2:]
+ elif pathname[:12] == '//localhost/':
+ # Skip past 'localhost' authority.
+ pathname = pathname[11:]
encoding = sys.getfilesystemencoding()
errors = sys.getfilesystemencodeerrors()
return unquote(pathname, encoding=encoding, errors=errors)
--- /dev/null
+Fix issue where :func:`urllib.request.url2pathname` failed to discard any
+'localhost' authority present in the URL.