~matsubara/ubuntu/trusty/python-urllib3/bug-1412545

« back to all changes in this revision

Viewing changes to urllib3/util.py

  • Committer: Package Import Robot
  • Author(s): Barry Warsaw
  • Date: 2012-11-01 15:31:36 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20121101153136-w2fm02askveqxxkx
Tags: 1.5-0ubuntu1
* New upstream release.  Remaining changes:
  - 01_do-not-use-embedded-python-six.patch: refreshed
  - 02_require-cert-verification.patch: refreshed
  - 03-fix-appenginge.patch: removed

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
 
7
7
 
8
8
from base64 import b64encode
 
9
from collections import namedtuple
 
10
from socket import error as SocketError
9
11
 
10
12
try:
11
13
    from select import poll, POLLIN
20
22
from .exceptions import LocationParseError
21
23
 
22
24
 
 
25
class Url(namedtuple('Url', ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'])):
 
26
    """
 
27
    Datastructure for representing an HTTP URL. Used as a return value for
 
28
    :func:`parse_url`.
 
29
    """
 
30
    slots = ()
 
31
 
 
32
    def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, query=None, fragment=None):
 
33
        return super(Url, cls).__new__(cls, scheme, auth, host, port, path, query, fragment)
 
34
 
 
35
    @property
 
36
    def hostname(self):
 
37
        """For backwards-compatibility with urlparse. We're nice like that."""
 
38
        return self.host
 
39
 
 
40
    @property
 
41
    def request_uri(self):
 
42
        """Absolute path including the query string."""
 
43
        uri = self.path or '/'
 
44
 
 
45
        if self.query is not None:
 
46
            uri += '?' + self.query
 
47
 
 
48
        return uri
 
49
 
 
50
 
 
51
def split_first(s, delims):
 
52
    """
 
53
    Given a string and an iterable of delimiters, split on the first found
 
54
    delimiter. Return two split parts and the matched delimiter.
 
55
 
 
56
    If not found, then the first part is the full input string.
 
57
 
 
58
    Example: ::
 
59
 
 
60
        >>> split_first('foo/bar?baz', '?/=')
 
61
        ('foo', 'bar?baz', '/')
 
62
        >>> split_first('foo/bar?baz', '123')
 
63
        ('foo/bar?baz', '', None)
 
64
 
 
65
    Scales linearly with number of delims. Not ideal for large number of delims.
 
66
    """
 
67
    min_idx = None
 
68
    min_delim = None
 
69
    for d in delims:
 
70
        idx = s.find(d)
 
71
        if idx < 0:
 
72
            continue
 
73
 
 
74
        if min_idx is None or idx < min_idx:
 
75
            min_idx = idx
 
76
            min_delim = d
 
77
 
 
78
    if min_idx is None or min_idx < 0:
 
79
        return s, '', None
 
80
 
 
81
    return s[:min_idx], s[min_idx+1:], min_delim
 
82
 
 
83
 
 
84
def parse_url(url):
 
85
    """
 
86
    Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
 
87
    performed to parse incomplete urls. Fields not provided will be None.
 
88
 
 
89
    Partly backwards-compatible with :mod:`urlparse`.
 
90
 
 
91
    Example: ::
 
92
 
 
93
        >>> parse_url('http://google.com/mail/')
 
94
        Url(scheme='http', host='google.com', port=None, path='/', ...)
 
95
        >>> prase_url('google.com:80')
 
96
        Url(scheme=None, host='google.com', port=80, path=None, ...)
 
97
        >>> prase_url('/foo?bar')
 
98
        Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
 
99
    """
 
100
 
 
101
    # While this code has overlap with stdlib's urlparse, it is much
 
102
    # simplified for our needs and less annoying.
 
103
    # Additionally, this imeplementations does silly things to be optimal
 
104
    # on CPython.
 
105
 
 
106
    scheme = None
 
107
    auth = None
 
108
    host = None
 
109
    port = None
 
110
    path = None
 
111
    fragment = None
 
112
    query = None
 
113
 
 
114
    # Scheme
 
115
    if '://' in url:
 
116
        scheme, url = url.split('://', 1)
 
117
 
 
118
    # Find the earliest Authority Terminator
 
119
    # (http://tools.ietf.org/html/rfc3986#section-3.2)
 
120
    url, path_, delim = split_first(url, ['/', '?', '#'])
 
121
 
 
122
    if delim:
 
123
        # Reassemble the path
 
124
        path = delim + path_
 
125
 
 
126
    # Auth
 
127
    if '@' in url:
 
128
        auth, url = url.split('@', 1)
 
129
 
 
130
    # IPv6
 
131
    if url and url[0] == '[':
 
132
        host, url = url[1:].split(']', 1)
 
133
 
 
134
    # Port
 
135
    if ':' in url:
 
136
        _host, port = url.split(':', 1)
 
137
 
 
138
        if not host:
 
139
            host = _host
 
140
 
 
141
        if not port.isdigit():
 
142
            raise LocationParseError("Failed to parse: %s" % url)
 
143
 
 
144
        port = int(port)
 
145
 
 
146
    elif not host and url:
 
147
        host = url
 
148
 
 
149
    if not path:
 
150
        return Url(scheme, auth, host, port, path, query, fragment)
 
151
 
 
152
    # Fragment
 
153
    if '#' in path:
 
154
        path, fragment = path.split('#', 1)
 
155
 
 
156
    # Query
 
157
    if '?' in path:
 
158
        path, query = path.split('?', 1)
 
159
 
 
160
    return Url(scheme, auth, host, port, path, query, fragment)
 
161
 
 
162
 
 
163
def get_host(url):
 
164
    """
 
165
    Deprecated. Use :func:`.parse_url` instead.
 
166
    """
 
167
    p = parse_url(url)
 
168
    return p.scheme or 'http', p.hostname, p.port
 
169
 
 
170
 
23
171
def make_headers(keep_alive=None, accept_encoding=None, user_agent=None,
24
172
                 basic_auth=None):
25
173
    """
72
220
    return headers
73
221
 
74
222
 
75
 
def get_host(url):
76
 
    """
77
 
    Given a url, return its scheme, host and port (None if it's not there).
78
 
 
79
 
    For example: ::
80
 
 
81
 
        >>> get_host('http://google.com/mail/')
82
 
        ('http', 'google.com', None)
83
 
        >>> get_host('google.com:80')
84
 
        ('http', 'google.com', 80)
85
 
    """
86
 
 
87
 
    # This code is actually similar to urlparse.urlsplit, but much
88
 
    # simplified for our needs.
89
 
    port = None
90
 
    scheme = 'http'
91
 
 
92
 
    if '://' in url:
93
 
        scheme, url = url.split('://', 1)
94
 
    if '/' in url:
95
 
        url, _path = url.split('/', 1)
96
 
    if '@' in url:
97
 
        _auth, url = url.split('@', 1)
98
 
    if ':' in url:
99
 
        url, port = url.split(':', 1)
100
 
 
101
 
        if not port.isdigit():
102
 
            raise LocationParseError("Failed to parse: %s" % url)
103
 
 
104
 
        port = int(port)
105
 
 
106
 
    return scheme, url, port
107
 
 
108
 
 
109
 
 
110
223
def is_connection_dropped(conn):
111
224
    """
112
225
    Returns True if the connection is dropped and should be closed.
113
226
 
114
227
    :param conn:
115
 
        ``HTTPConnection`` object.
 
228
        :class:`httplib.HTTPConnection` object.
116
229
 
117
230
    Note: For platforms like AppEngine, this will always return ``False`` to
118
231
    let the platform handle connection recycling transparently for us.
119
232
    """
120
233
    sock = getattr(conn, 'sock', False)
121
 
    if not sock: #Platform-specific: AppEngine
 
234
    if not sock: # Platform-specific: AppEngine
122
235
        return False
123
236
 
124
237
    if not poll: # Platform-specific
125
 
        if not select: #Platform-specific: AppEngine
 
238
        if not select: # Platform-specific: AppEngine
126
239
            return False
127
240
 
128
 
        return select([sock], [], [], 0.0)[0]
 
241
        try:
 
242
            return select([sock], [], [], 0.0)[0]
 
243
        except SocketError:
 
244
            return True
129
245
 
130
246
    # This version is better on platforms that support it.
131
247
    p = poll()