Skip to content

Instantly share code, notes, and snippets.

@antoine-lizee
Last active December 22, 2016 20:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antoine-lizee/05e24078df1e3a0485bb8dafcfd0741a to your computer and use it in GitHub Desktop.
Save antoine-lizee/05e24078df1e3a0485bb8dafcfd0741a to your computer and use it in GitHub Desktop.
Implement exception-based catchall host routing with flask & tests
from werkzeug.routing import Rule as BaseRule
class Rule(BaseRule):
except_hosts = []
def match(self, path):
""" Monkey patched version of the default Werkzeug behavior to achieve host matching with catchall.
By default, if host matching is enabled, the match is only done if the host is always provided, which is
unpractical. This modified version matches normally if host matching is not enabled. If host matching is
enabled, if it fails, and if the host is not part of a blacklist, it will try matching again without host
matching ('catch all').
"""
host, route = path.split('|')
result = super().match(path)
if result is None and host and host not in self.except_hosts:
result = super().match('|' + route)
return result
def configure_app_host_routing(app, except_hosts):
app.url_rule_class = type('LocalRule', (Rule, ), {'except_hosts': except_hosts})
app.url_map.host_matching = True
### EXAMPLE
from flask import Flask
app = Flask('test_app')
configure_app_host_routing(app, ['specificdomain.com'])
# add host-specific endpoint
@app.route('/<argument>', host='specificdomain.com')
def specific_host_endpoint():
return
# add normal endpoint, could be a blueprint too.
@app.route('/test/<id>')
def test():
return
### TEST
import unittest
from werkzeug.exceptions import NotFound
class TestHostRouting(unittest.TestCase):
def main_test(self):
m = app.url_map
# host specific endpoint is routed correctly for specificdomain.com
self.assertEqual(
('specific_host_endpoint', {'argument': 'yo'}),
m.bind('specificdomain.com').match('/yo'),
)
with self.assertRaises(NotFound):
m.bind('specificdomain.com').match('/yo/')
# host specific endpoint does not work for other domains
with self.assertRaises(NotFound):
m.bind('domain.com').match('/yo')
with self.assertRaises(NotFound):
m.bind('anything.specificdomain.com').match('/yo')
# normal endpoint works as expected
self.assertEqual(('test', {'id': '1'}), m.bind('domain.com').match('/test/1'))
self.assertEqual(('test', {'id': '1'}), m.bind('anything.domain.com').match('/test/1'))
# normal endpoint doesn't work for specific host
with self.assertRaises(NotFound):
m.bind('specificdomain.com').match('/test/1')
TestHostRouting('main_test').main_test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment