• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Convert a NT pathname to a file URL and vice versa.
2
3This module only exists to provide OS-specific code
4for urllib.requests, thus do not use directly.
5"""
6# Testing is done through test_urllib.
7
8def url2pathname(url):
9    """OS-specific conversion from a relative URL of the 'file' scheme
10    to a file system path; not recommended for general use."""
11    # e.g.
12    #   ///C|/foo/bar/spam.foo
13    # and
14    #   ///C:/foo/bar/spam.foo
15    # become
16    #   C:\foo\bar\spam.foo
17    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:]
25    if url[:3] == '///':
26        # Skip past extra slash before UNC drive in URL path.
27        url = url[1:]
28    # Windows itself uses ":" even in URLs.
29    url = url.replace(':', '|')
30    if not '|' in url:
31        # No drive specifier, just convert slashes
32        # make sure not to convert quoted slashes :-)
33        return urllib.parse.unquote(url.replace('/', '\\'))
34    comp = url.split('|')
35    if len(comp) != 2 or comp[0][-1] not in string.ascii_letters:
36        error = 'Bad URL: ' + url
37        raise OSError(error)
38    drive = comp[0][-1].upper()
39    tail = urllib.parse.unquote(comp[1].replace('/', '\\'))
40    return drive + ':' + tail
41
42def pathname2url(p):
43    """OS-specific conversion from a file system path to a relative URL
44    of the 'file' scheme; not recommended for general use."""
45    # e.g.
46    #   C:\foo\bar\spam.foo
47    # becomes
48    #   ///C:/foo/bar/spam.foo
49    import urllib.parse
50    # First, clean up some special forms. We are going to sacrifice
51    # the additional information anyway
52    p = p.replace('\\', '/')
53    if p[:4] == '//?/':
54        p = p[4:]
55        if p[:4].upper() == 'UNC/':
56            p = '//' + p[4:]
57        elif p[1:2] != ':':
58            raise OSError('Bad path: ' + p)
59    if not ':' in p:
60        # No DOS drive specified, just quote the pathname
61        return urllib.parse.quote(p)
62    comp = p.split(':', maxsplit=2)
63    if len(comp) != 2 or len(comp[0]) > 1:
64        error = 'Bad path: ' + p
65        raise OSError(error)
66
67    drive = urllib.parse.quote(comp[0].upper())
68    tail = urllib.parse.quote(comp[1])
69    return '///' + drive + ':' + tail
70