]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] GH-126766: `url2pathname()`: handle empty authority section. (GH-126767) ...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 14 Nov 2024 23:52:46 +0000 (00:52 +0100)
committerGitHub <noreply@github.com>
Thu, 14 Nov 2024 23:52:46 +0000 (23:52 +0000)
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 cae9d9d20f61cdbde0765efa340b6b596c31b67f)

Co-authored-by: Barney Gale <barney.gale@gmail.com>
Lib/nturl2path.py
Lib/test/test_urllib.py
Lib/urllib/request.py
Misc/NEWS.d/next/Library/2024-11-12-21-43-12.gh-issue-126766.oi2KJ7.rst [new file with mode: 0644]

index 9ecabff21c33e144e3634e717ef706cf382f5b6f..255eb2f547c2ce1b66c5d13d2d1e8bb239cc1c8d 100644 (file)
@@ -19,10 +19,9 @@ def url2pathname(url):
     url = url.replace(':', '|')
     if not '|' in url:
         # No drive specifier, just convert slashes
-        if url[:4] == '////':
-            # path is something like ////host/path/on/remote/host
-            # convert this to \\host\path\on\remote\host
-            # (notice halving of slashes at the start of the path)
+        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('/', '\\'))
index 5433072bcda74153c6407819bfd263d01276c5f6..15a698cc10f21734c2d85e322a4a009f00548105 100644 (file)
@@ -1558,7 +1558,7 @@ class Pathname_Tests(unittest.TestCase):
         self.assertEqual(fn('//?/unc/server/share/dir'), '//server/share/dir')
         # Round-tripping
         urls = ['///C:',
-                '///folder/test/',
+                '/folder/test/',
                 '///C:/foo/bar/spam.foo']
         for url in urls:
             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|/path'), 'C:\\path')
         # No DOS drive
-        self.assertEqual(fn("///C/test/"), '\\\\\\C\\test\\')
+        self.assertEqual(fn("///C/test/"), '\\C\\test\\')
         self.assertEqual(fn("////C/test/"), '\\\\C\\test\\')
         # DOS drive paths
         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')
         # Round-tripping
         paths = ['C:',
-                 r'\\\C\test\\',
+                 r'\C\test\\',
                  r'C:\foo\bar\spam.foo']
         for path in paths:
             self.assertEqual(fn(urllib.request.pathname2url(path)), path)
@@ -1617,8 +1617,8 @@ class Pathname_Tests(unittest.TestCase):
         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('//localhost/foo/bar'), '//localhost/foo/bar')
 
 class Utility_Tests(unittest.TestCase):
index 7228a35534b6381e0f77f46e4e917f0b3adc090c..178c9795e19c6e48cff8472d0afeb9af56506413 100644 (file)
@@ -1681,6 +1681,10 @@ else:
     def url2pathname(pathname):
         """OS-specific conversion from a relative URL of the 'file' scheme
         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)
 
     def pathname2url(pathname):
diff --git a/Misc/NEWS.d/next/Library/2024-11-12-21-43-12.gh-issue-126766.oi2KJ7.rst b/Misc/NEWS.d/next/Library/2024-11-12-21-43-12.gh-issue-126766.oi2KJ7.rst
new file mode 100644 (file)
index 0000000..e393630
--- /dev/null
@@ -0,0 +1,2 @@
+Fix issue where :func:`urllib.request.url2pathname` failed to discard two
+leading slashes introducing an empty authority section.