Skip to content

Commit 4b9068e

Browse files
[3.13] GH-126766: url2pathname(): handle 'localhost' authority (GH-127129) (#127130)
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 ebf564a) Co-authored-by: Barney Gale <[email protected]>
1 parent 8cdd636 commit 4b9068e

File tree

4 files changed

+15
-5
lines changed

4 files changed

+15
-5
lines changed

Lib/nturl2path.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ def url2pathname(url):
1515
# become
1616
# C:\foo\bar\spam.foo
1717
import string, urllib.parse
18+
if url[:3] == '///':
19+
# URL has an empty authority section, so the path begins on the third
20+
# character.
21+
url = url[2:]
22+
elif url[:12] == '//localhost/':
23+
# Skip past 'localhost' authority.
24+
url = url[11:]
1825
# Windows itself uses ":" even in URLs.
1926
url = url.replace(':', '|')
2027
if not '|' in url:
2128
# No drive specifier, just convert slashes
22-
if url[:3] == '///':
23-
# URL has an empty authority section, so the path begins on the
24-
# third character.
25-
url = url[2:]
2629
# make sure not to convert quoted slashes :-)
2730
return urllib.parse.unquote(url.replace('/', '\\'))
2831
comp = url.split('|')

Lib/test/test_urllib.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,8 @@ def test_url2pathname_win(self):
15951595
# Localhost paths
15961596
self.assertEqual(fn('//localhost/C:/path/to/file'), 'C:\\path\\to\\file')
15971597
self.assertEqual(fn('//localhost/C|/path/to/file'), 'C:\\path\\to\\file')
1598+
self.assertEqual(fn('//localhost/path/to/file'), '\\path\\to\\file')
1599+
self.assertEqual(fn('//localhost//server/path/to/file'), '\\\\server\\path\\to\\file')
15981600
# Percent-encoded forward slashes are preserved for backwards compatibility
15991601
self.assertEqual(fn('C:/foo%2fbar'), 'C:\\foo/bar')
16001602
self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar')
@@ -1613,7 +1615,7 @@ def test_url2pathname_posix(self):
16131615
self.assertEqual(fn('//foo/bar'), '//foo/bar')
16141616
self.assertEqual(fn('///foo/bar'), '/foo/bar')
16151617
self.assertEqual(fn('////foo/bar'), '//foo/bar')
1616-
self.assertEqual(fn('//localhost/foo/bar'), '//localhost/foo/bar')
1618+
self.assertEqual(fn('//localhost/foo/bar'), '/foo/bar')
16171619

16181620
@unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII')
16191621
def test_url2pathname_nonascii(self):

Lib/urllib/request.py

+3
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,9 @@ def url2pathname(pathname):
16601660
# URL has an empty authority section, so the path begins on the
16611661
# third character.
16621662
pathname = pathname[2:]
1663+
elif pathname[:12] == '//localhost/':
1664+
# Skip past 'localhost' authority.
1665+
pathname = pathname[11:]
16631666
encoding = sys.getfilesystemencoding()
16641667
errors = sys.getfilesystemencodeerrors()
16651668
return unquote(pathname, encoding=encoding, errors=errors)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix issue where :func:`urllib.request.url2pathname` failed to discard any
2+
'localhost' authority present in the URL.

0 commit comments

Comments
 (0)