From b92b2e6c743c8b09744c9c9788046c719cc38eab Mon Sep 17 00:00:00 2001 From: Jimmy Jia Date: Thu, 1 Nov 2018 16:41:53 -0400 Subject: [PATCH 1/2] Do not handle RoutingExceptions with app error handlers --- flask/app.py | 9 ++++++++- tests/test_user_error_handler.py | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) 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/') From 662ce2151d0f17d592133eeecdc8d7e6676db811 Mon Sep 17 00:00:00 2001 From: David Lord Date: Mon, 7 Jan 2019 09:52:54 -0800 Subject: [PATCH 2/2] add changelog for GH-2986 --- CHANGES.rst | 5 +++++ flask/app.py | 16 +++++++++++++--- tests/test_user_error_handler.py | 9 ++++----- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index cb1e6239..bdf0c896 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -19,11 +19,16 @@ Unreleased Python version. (`#2825`_) - :func:`send_file` handles an ``attachment_filename`` that is a native Python 2 string (bytes) with UTF-8 coded bytes. (`#2933`_) +- A catch-all error handler registered for ``HTTPException`` will not + handle ``RoutingExcpetion``, which is used internally during + routing. This fixes the unexpected behavior that had been introduced + in 1.0. (`#2986`_) .. _#2766: https://github.com/pallets/flask/issues/2766 .. _#2765: https://github.com/pallets/flask/pull/2765 .. _#2825: https://github.com/pallets/flask/pull/2825 .. _#2933: https://github.com/pallets/flask/issues/2933 +.. _#2986: https://github.com/pallets/flask/pull/2986 Version 1.0.2 diff --git a/flask/app.py b/flask/app.py index 8d193656..c570a95b 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1632,6 +1632,16 @@ class Flask(_PackageBoundObject): registered error handlers and fall back to returning the exception as response. + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPExcpetion`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + .. versionadded:: 0.3 """ # Proxy exceptions don't have error codes. We want to always return @@ -1639,9 +1649,9 @@ 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. + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. if isinstance(e, RoutingException): return e diff --git a/tests/test_user_error_handler.py b/tests/test_user_error_handler.py index 4e52485c..f4a08f58 100644 --- a/tests/test_user_error_handler.py +++ b/tests/test_user_error_handler.py @@ -184,9 +184,9 @@ def test_default_error_handler(): def forbidden(): raise Forbidden() - @app.route('/slash/') + @app.route("/slash/") def slash(): - return '' + return "slash" app.register_blueprint(bp, url_prefix='/bp') @@ -195,6 +195,5 @@ 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/') - - + # Don't handle RequestRedirect raised when adding slash. + assert c.get("/slash", follow_redirects=True).data == b"slash"