summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bangert <ben@groovie.org>2016-02-28 08:48:54 -0800
committerBen Bangert <ben@groovie.org>2016-02-28 08:48:54 -0800
commit9adf7e567d77105752028bd2fc6715d7a09ef8c2 (patch)
treeefce3731deb1e76f89e47dc23d9cbc782120a6bd
parentefdf2984516688a3c9ada7981ca4f64d7791682c (diff)
parentf4b2cb0297f4f07d27f142e9112bd5fbf6a0a2c6 (diff)
downloadroutes-9adf7e567d77105752028bd2fc6715d7a09ef8c2.tar.gz
Merge pull request #60 from webknjaz/29-support-protocol-relative-url
Fix #29. Add support for protocol-relative URLs
-rw-r--r--CHANGELOG.rst2
-rw-r--r--routes/util.py36
-rw-r--r--tests/test_functional/test_utils.py2
3 files changed, 28 insertions, 12 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 2a8a322..3b08d25 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,6 +3,8 @@ Routes Changelog
Release 2.3 (**dev**)
=====================
+* Add support for protocol-relative URLs generation (i.e. starting with double
+ slash ``//``). PR #60. Patch by Sviatoslav Sydorenko.
* Add support for the ``middleware`` extra requirement, making possible to
depend on ``webob`` optionally. PR #59. Patch by Sviatoslav Sydorenko.
* Fix matching of an empty string route, which led to exception in earlier
diff --git a/routes/util.py b/routes/util.py
index baeeac7..f3d2dc4 100644
--- a/routes/util.py
+++ b/routes/util.py
@@ -180,15 +180,19 @@ def url_for(*args, **kargs):
"""
anchor = kargs.get('anchor')
host = kargs.get('host')
- protocol = kargs.get('protocol')
+ protocol = kargs.pop('protocol', None)
qualified = kargs.pop('qualified', None)
# Remove special words from kargs, convert placeholders
- for key in ['anchor', 'host', 'protocol']:
+ for key in ['anchor', 'host']:
if kargs.get(key):
del kargs[key]
if key+'_' in kargs:
kargs[key] = kargs.pop(key+'_')
+
+ if 'protocol_' in kargs:
+ kargs['protocol_'] = protocol
+
config = request_config()
route = None
static = False
@@ -250,21 +254,23 @@ def url_for(*args, **kargs):
newargs = _screenargs(kargs, config.mapper, environ)
anchor = newargs.pop('_anchor', None) or anchor
host = newargs.pop('_host', None) or host
- protocol = newargs.pop('_protocol', None) or protocol
+ protocol = newargs.pop('_protocol', protocol)
url = config.mapper.generate(*route_args, **newargs)
if anchor is not None:
url += '#' + _url_quote(anchor, encoding)
- if host or protocol or qualified:
+ if host or (protocol is not None) or qualified:
if not host and not qualified:
# Ensure we don't use a specific port, as changing the protocol
# means that we most likely need a new port
host = config.host.split(':')[0]
elif not host:
host = config.host
- if not protocol:
+ if protocol is None:
protocol = config.protocol
+ if protocol != '':
+ protocol += ':'
if url is not None:
- url = protocol + '://' + host + url
+ url = protocol + '//' + host + url
if not ascii_characters(url) and url is not None:
raise GenerationException("url_for can only return a string, got "
@@ -324,16 +330,19 @@ class URLGenerator(object):
"""
anchor = kargs.get('anchor')
host = kargs.get('host')
- protocol = kargs.get('protocol')
+ protocol = kargs.pop('protocol', None)
qualified = kargs.pop('qualified', None)
# Remove special words from kargs, convert placeholders
- for key in ['anchor', 'host', 'protocol']:
+ for key in ['anchor', 'host']:
if kargs.get(key):
del kargs[key]
if key+'_' in kargs:
kargs[key] = kargs.pop(key+'_')
+ if 'protocol_' in kargs:
+ kargs['protocol_'] = protocol
+
route = None
use_current = '_use_current' in kargs and kargs.pop('_use_current')
@@ -396,12 +405,13 @@ class URLGenerator(object):
anchor = anchor or newargs.pop('_anchor', None)
host = host or newargs.pop('_host', None)
- protocol = protocol or newargs.pop('_protocol', None)
+ if protocol is None:
+ protocol = newargs.pop('_protocol', None)
newargs['_environ'] = self.environ
url = self.mapper.generate(*route_args, **newargs)
if anchor is not None:
url += '#' + _url_quote(anchor, encoding)
- if host or protocol or qualified:
+ if host or (protocol is not None) or qualified:
if 'routes.cached_hostinfo' not in self.environ:
cache_hostinfo(self.environ)
hostinfo = self.environ['routes.cached_hostinfo']
@@ -412,12 +422,14 @@ class URLGenerator(object):
host = hostinfo['host'].split(':')[0]
elif not host:
host = hostinfo['host']
- if not protocol:
+ if protocol is None:
protocol = hostinfo['protocol']
+ if protocol != '':
+ protocol += ':'
if url is not None:
if host[-1] != '/':
host += '/'
- url = protocol + '://' + host + url.lstrip('/')
+ url = protocol + '//' + host + url.lstrip('/')
if not ascii_characters(url) and url is not None:
raise GenerationException("Can only return a string, got "
diff --git a/tests/test_functional/test_utils.py b/tests/test_functional/test_utils.py
index 3f4dd47..e2a6a04 100644
--- a/tests/test_functional/test_utils.py
+++ b/tests/test_functional/test_utils.py
@@ -62,6 +62,8 @@ class TestUtils(unittest.TestCase):
eq_('/content', urlobj())
eq_('https://www.test.com/viewpost', urlobj(controller='post', action='view', protocol='https'))
eq_('http://www.test.org/content', urlobj(host='www.test.org'))
+ eq_('//www.test.com/viewpost', urlobj(controller='post', action='view', protocol=''))
+ eq_('//www.test.org/content', urlobj(host='www.test.org', protocol=''))
def test_url_raises(self):
con = self.con