mirror of
https://github.com/python/cpython.git
synced 2025-08-08 10:58:51 +00:00
[3.12] GH-126766: url2pathname()
: handle empty authority section. (GH-126767) (#126837)
GH-126766: `url2pathname()`: handle empty authority section. (GH-126767)
Discard two leading slashes from the beginning of a `file:` URI if they
introduce an empty authority section. As a result, file URIs like
`///etc/hosts` are correctly parsed as `/etc/hosts`.
(cherry picked from commit cae9d9d20f
)
Co-authored-by: Barney Gale <barney.gale@gmail.com>
This commit is contained in:
parent
306db142c2
commit
04f38bb775
4 changed files with 14 additions and 9 deletions
|
@ -19,10 +19,9 @@ def url2pathname(url):
|
||||||
url = url.replace(':', '|')
|
url = url.replace(':', '|')
|
||||||
if not '|' in url:
|
if not '|' in url:
|
||||||
# No drive specifier, just convert slashes
|
# No drive specifier, just convert slashes
|
||||||
if url[:4] == '////':
|
if url[:3] == '///':
|
||||||
# path is something like ////host/path/on/remote/host
|
# URL has an empty authority section, so the path begins on the
|
||||||
# convert this to \\host\path\on\remote\host
|
# third character.
|
||||||
# (notice halving of slashes at the start of the path)
|
|
||||||
url = url[2:]
|
url = url[2:]
|
||||||
# make sure not to convert quoted slashes :-)
|
# make sure not to convert quoted slashes :-)
|
||||||
return urllib.parse.unquote(url.replace('/', '\\'))
|
return urllib.parse.unquote(url.replace('/', '\\'))
|
||||||
|
|
|
@ -1558,7 +1558,7 @@ class Pathname_Tests(unittest.TestCase):
|
||||||
self.assertEqual(fn('//?/unc/server/share/dir'), '//server/share/dir')
|
self.assertEqual(fn('//?/unc/server/share/dir'), '//server/share/dir')
|
||||||
# Round-tripping
|
# Round-tripping
|
||||||
urls = ['///C:',
|
urls = ['///C:',
|
||||||
'///folder/test/',
|
'/folder/test/',
|
||||||
'///C:/foo/bar/spam.foo']
|
'///C:/foo/bar/spam.foo']
|
||||||
for url in urls:
|
for url in urls:
|
||||||
self.assertEqual(fn(urllib.request.url2pathname(url)), url)
|
self.assertEqual(fn(urllib.request.url2pathname(url)), url)
|
||||||
|
@ -1582,7 +1582,7 @@ class Pathname_Tests(unittest.TestCase):
|
||||||
self.assertEqual(fn('/C|//'), 'C:\\\\')
|
self.assertEqual(fn('/C|//'), 'C:\\\\')
|
||||||
self.assertEqual(fn('///C|/path'), 'C:\\path')
|
self.assertEqual(fn('///C|/path'), 'C:\\path')
|
||||||
# No DOS drive
|
# No DOS drive
|
||||||
self.assertEqual(fn("///C/test/"), '\\\\\\C\\test\\')
|
self.assertEqual(fn("///C/test/"), '\\C\\test\\')
|
||||||
self.assertEqual(fn("////C/test/"), '\\\\C\\test\\')
|
self.assertEqual(fn("////C/test/"), '\\\\C\\test\\')
|
||||||
# DOS drive paths
|
# DOS drive paths
|
||||||
self.assertEqual(fn('C:/path/to/file'), 'C:\\path\\to\\file')
|
self.assertEqual(fn('C:/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
@ -1606,7 +1606,7 @@ class Pathname_Tests(unittest.TestCase):
|
||||||
self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar')
|
self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar')
|
||||||
# Round-tripping
|
# Round-tripping
|
||||||
paths = ['C:',
|
paths = ['C:',
|
||||||
r'\\\C\test\\',
|
r'\C\test\\',
|
||||||
r'C:\foo\bar\spam.foo']
|
r'C:\foo\bar\spam.foo']
|
||||||
for path in paths:
|
for path in paths:
|
||||||
self.assertEqual(fn(urllib.request.pathname2url(path)), path)
|
self.assertEqual(fn(urllib.request.pathname2url(path)), path)
|
||||||
|
@ -1617,8 +1617,8 @@ class Pathname_Tests(unittest.TestCase):
|
||||||
fn = urllib.request.url2pathname
|
fn = urllib.request.url2pathname
|
||||||
self.assertEqual(fn('/foo/bar'), '/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('///foo/bar'), '///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'), '//localhost/foo/bar')
|
||||||
|
|
||||||
class Utility_Tests(unittest.TestCase):
|
class Utility_Tests(unittest.TestCase):
|
||||||
|
|
|
@ -1681,6 +1681,10 @@ else:
|
||||||
def url2pathname(pathname):
|
def url2pathname(pathname):
|
||||||
"""OS-specific conversion from a relative URL of the 'file' scheme
|
"""OS-specific conversion from a relative URL of the 'file' scheme
|
||||||
to a file system path; not recommended for general use."""
|
to a file system path; not recommended for general use."""
|
||||||
|
if pathname[:3] == '///':
|
||||||
|
# URL has an empty authority section, so the path begins on the
|
||||||
|
# third character.
|
||||||
|
pathname = pathname[2:]
|
||||||
return unquote(pathname)
|
return unquote(pathname)
|
||||||
|
|
||||||
def pathname2url(pathname):
|
def pathname2url(pathname):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix issue where :func:`urllib.request.url2pathname` failed to discard two
|
||||||
|
leading slashes introducing an empty authority section.
|
Loading…
Add table
Add a link
Reference in a new issue