diff --git a/flask/app.py b/flask/app.py index 49a025cd..8d193656 100644 --- a/flask/app.py +++ b/flask/app.py @@ -20,7 +20,8 @@ from threading import Lock from werkzeug.datastructures import Headers, ImmutableDict from werkzeug.exceptions import BadRequest, BadRequestKeyError, HTTPException, \ InternalServerError, MethodNotAllowed, default_exceptions -from werkzeug.routing import BuildError, Map, RequestRedirect, Rule +from werkzeug.routing import BuildError, Map, RequestRedirect, \ + RoutingException, Rule from . import cli, json from ._compat import integer_types, reraise, string_types, text_type @@ -1638,6 +1639,12 @@ class Flask(_PackageBoundObject): if e.code is None: return e + # RoutingExceptions such as RequestRedirects are special exceptions + # used to trigger routing actions such as redirects, and also behave + # like proxy exceptions. We return these unchanged as well. + if isinstance(e, RoutingException): + return e + handler = self._find_error_handler(e) if handler is None: return e diff --git a/tests/test_user_error_handler.py b/tests/test_user_error_handler.py index 18d5f277..4e52485c 100644 --- a/tests/test_user_error_handler.py +++ b/tests/test_user_error_handler.py @@ -184,6 +184,10 @@ def test_default_error_handler(): def forbidden(): raise Forbidden() + @app.route('/slash/') + def slash(): + return '' + app.register_blueprint(bp, url_prefix='/bp') c = app.test_client() @@ -191,5 +195,6 @@ def test_default_error_handler(): assert c.get('/bp/forbidden').data == b'bp-forbidden' assert c.get('/undefined').data == b'default' assert c.get('/forbidden').data == b'forbidden' + assert c.get('/slash').location.endswith('/slash/')