~tribaal/vmbuilder/jenkins_kvm-add-zesty-template

« back to all changes in this revision

Viewing changes to pylib/requests/packages/urllib3/util/url.py

  • Committer: Ben Howard
  • Date: 2014-08-19 20:30:00 UTC
  • Revision ID: ben.howard@ubuntu.com-20140819203000-9gfgaryo1w41orxu
12.04 does not ship with a version of python3-requests, so we need
to provided it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from collections import namedtuple
 
2
 
 
3
from ..exceptions import LocationParseError
 
4
 
 
5
 
 
6
class Url(namedtuple('Url', ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'])):
 
7
    """
 
8
    Datastructure for representing an HTTP URL. Used as a return value for
 
9
    :func:`parse_url`.
 
10
    """
 
11
    slots = ()
 
12
 
 
13
    def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, query=None, fragment=None):
 
14
        return super(Url, cls).__new__(cls, scheme, auth, host, port, path, query, fragment)
 
15
 
 
16
    @property
 
17
    def hostname(self):
 
18
        """For backwards-compatibility with urlparse. We're nice like that."""
 
19
        return self.host
 
20
 
 
21
    @property
 
22
    def request_uri(self):
 
23
        """Absolute path including the query string."""
 
24
        uri = self.path or '/'
 
25
 
 
26
        if self.query is not None:
 
27
            uri += '?' + self.query
 
28
 
 
29
        return uri
 
30
 
 
31
    @property
 
32
    def netloc(self):
 
33
        """Network location including host and port"""
 
34
        if self.port:
 
35
            return '%s:%d' % (self.host, self.port)
 
36
        return self.host
 
37
 
 
38
 
 
39
def split_first(s, delims):
 
40
    """
 
41
    Given a string and an iterable of delimiters, split on the first found
 
42
    delimiter. Return two split parts and the matched delimiter.
 
43
 
 
44
    If not found, then the first part is the full input string.
 
45
 
 
46
    Example: ::
 
47
 
 
48
        >>> split_first('foo/bar?baz', '?/=')
 
49
        ('foo', 'bar?baz', '/')
 
50
        >>> split_first('foo/bar?baz', '123')
 
51
        ('foo/bar?baz', '', None)
 
52
 
 
53
    Scales linearly with number of delims. Not ideal for large number of delims.
 
54
    """
 
55
    min_idx = None
 
56
    min_delim = None
 
57
    for d in delims:
 
58
        idx = s.find(d)
 
59
        if idx < 0:
 
60
            continue
 
61
 
 
62
        if min_idx is None or idx < min_idx:
 
63
            min_idx = idx
 
64
            min_delim = d
 
65
 
 
66
    if min_idx is None or min_idx < 0:
 
67
        return s, '', None
 
68
 
 
69
    return s[:min_idx], s[min_idx+1:], min_delim
 
70
 
 
71
 
 
72
def parse_url(url):
 
73
    """
 
74
    Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
 
75
    performed to parse incomplete urls. Fields not provided will be None.
 
76
 
 
77
    Partly backwards-compatible with :mod:`urlparse`.
 
78
 
 
79
    Example: ::
 
80
 
 
81
        >>> parse_url('http://google.com/mail/')
 
82
        Url(scheme='http', host='google.com', port=None, path='/', ...)
 
83
        >>> parse_url('google.com:80')
 
84
        Url(scheme=None, host='google.com', port=80, path=None, ...)
 
85
        >>> parse_url('/foo?bar')
 
86
        Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
 
87
    """
 
88
 
 
89
    # While this code has overlap with stdlib's urlparse, it is much
 
90
    # simplified for our needs and less annoying.
 
91
    # Additionally, this implementations does silly things to be optimal
 
92
    # on CPython.
 
93
 
 
94
    scheme = None
 
95
    auth = None
 
96
    host = None
 
97
    port = None
 
98
    path = None
 
99
    fragment = None
 
100
    query = None
 
101
 
 
102
    # Scheme
 
103
    if '://' in url:
 
104
        scheme, url = url.split('://', 1)
 
105
 
 
106
    # Find the earliest Authority Terminator
 
107
    # (http://tools.ietf.org/html/rfc3986#section-3.2)
 
108
    url, path_, delim = split_first(url, ['/', '?', '#'])
 
109
 
 
110
    if delim:
 
111
        # Reassemble the path
 
112
        path = delim + path_
 
113
 
 
114
    # Auth
 
115
    if '@' in url:
 
116
        # Last '@' denotes end of auth part
 
117
        auth, url = url.rsplit('@', 1)
 
118
 
 
119
    # IPv6
 
120
    if url and url[0] == '[':
 
121
        host, url = url.split(']', 1)
 
122
        host += ']'
 
123
 
 
124
    # Port
 
125
    if ':' in url:
 
126
        _host, port = url.split(':', 1)
 
127
 
 
128
        if not host:
 
129
            host = _host
 
130
 
 
131
        if port:
 
132
            # If given, ports must be integers.
 
133
            if not port.isdigit():
 
134
                raise LocationParseError(url)
 
135
            port = int(port)
 
136
        else:
 
137
            # Blank ports are cool, too. (rfc3986#section-3.2.3)
 
138
            port = None
 
139
 
 
140
    elif not host and url:
 
141
        host = url
 
142
 
 
143
    if not path:
 
144
        return Url(scheme, auth, host, port, path, query, fragment)
 
145
 
 
146
    # Fragment
 
147
    if '#' in path:
 
148
        path, fragment = path.split('#', 1)
 
149
 
 
150
    # Query
 
151
    if '?' in path:
 
152
        path, query = path.split('?', 1)
 
153
 
 
154
    return Url(scheme, auth, host, port, path, query, fragment)
 
155
 
 
156
 
 
157
def get_host(url):
 
158
    """
 
159
    Deprecated. Use :func:`.parse_url` instead.
 
160
    """
 
161
    p = parse_url(url)
 
162
    return p.scheme or 'http', p.hostname, p.port