1
from collections import namedtuple
3
from ..exceptions import LocationParseError
6
class Url(namedtuple('Url', ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'])):
8
Datastructure for representing an HTTP URL. Used as a return value for
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)
18
"""For backwards-compatibility with urlparse. We're nice like that."""
22
def request_uri(self):
23
"""Absolute path including the query string."""
24
uri = self.path or '/'
26
if self.query is not None:
27
uri += '?' + self.query
33
"""Network location including host and port"""
35
return '%s:%d' % (self.host, self.port)
39
def split_first(s, delims):
41
Given a string and an iterable of delimiters, split on the first found
42
delimiter. Return two split parts and the matched delimiter.
44
If not found, then the first part is the full input string.
48
>>> split_first('foo/bar?baz', '?/=')
49
('foo', 'bar?baz', '/')
50
>>> split_first('foo/bar?baz', '123')
51
('foo/bar?baz', '', None)
53
Scales linearly with number of delims. Not ideal for large number of delims.
62
if min_idx is None or idx < min_idx:
66
if min_idx is None or min_idx < 0:
69
return s[:min_idx], s[min_idx+1:], min_delim
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.
77
Partly backwards-compatible with :mod:`urlparse`.
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', ...)
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
104
scheme, url = url.split('://', 1)
106
# Find the earliest Authority Terminator
107
# (http://tools.ietf.org/html/rfc3986#section-3.2)
108
url, path_, delim = split_first(url, ['/', '?', '#'])
111
# Reassemble the path
116
# Last '@' denotes end of auth part
117
auth, url = url.rsplit('@', 1)
120
if url and url[0] == '[':
121
host, url = url.split(']', 1)
126
_host, port = url.split(':', 1)
132
# If given, ports must be integers.
133
if not port.isdigit():
134
raise LocationParseError(url)
137
# Blank ports are cool, too. (rfc3986#section-3.2.3)
140
elif not host and url:
144
return Url(scheme, auth, host, port, path, query, fragment)
148
path, fragment = path.split('#', 1)
152
path, query = path.split('?', 1)
154
return Url(scheme, auth, host, port, path, query, fragment)
159
Deprecated. Use :func:`.parse_url` instead.
162
return p.scheme or 'http', p.hostname, p.port