forked from orbit-oss/flask
make debugging bad key errors easier
* TRAP_BAD_REQUEST_ERRORS is enabled by default in debug mode * BadRequestKeyError has the key in the description in debug mode closes #382
This commit is contained in:
parent
fb90c310b9
commit
045dccaefb
4 changed files with 37 additions and 7 deletions
6
CHANGES
6
CHANGES
|
|
@ -49,7 +49,7 @@ Major release, unreleased
|
||||||
work with the ``flask`` command. If they take a single parameter or a
|
work with the ``flask`` command. If they take a single parameter or a
|
||||||
parameter named ``script_info``, the ``ScriptInfo`` object will be passed.
|
parameter named ``script_info``, the ``ScriptInfo`` object will be passed.
|
||||||
(`#2319`_)
|
(`#2319`_)
|
||||||
- FLASK_APP=myproject.app:create_app('dev') support.
|
- FLASK_APP=myproject.app:create_app('dev') support.
|
||||||
- ``FLASK_APP`` can be set to an app factory, with arguments if needed, for
|
- ``FLASK_APP`` can be set to an app factory, with arguments if needed, for
|
||||||
example ``FLASK_APP=myproject.app:create_app('dev')``. (`#2326`_)
|
example ``FLASK_APP=myproject.app:create_app('dev')``. (`#2326`_)
|
||||||
- ``View.provide_automatic_options = True`` is set on the view function from
|
- ``View.provide_automatic_options = True`` is set on the view function from
|
||||||
|
|
@ -62,6 +62,9 @@ Major release, unreleased
|
||||||
parameters for use when building base URL. (`#1621`_)
|
parameters for use when building base URL. (`#1621`_)
|
||||||
- Set ``APPLICATION_ROOT = '/'`` by default. This was already the implicit
|
- Set ``APPLICATION_ROOT = '/'`` by default. This was already the implicit
|
||||||
default when it was set to ``None``.
|
default when it was set to ``None``.
|
||||||
|
- ``TRAP_BAD_REQUEST_ERRORS`` is enabled by default in debug mode.
|
||||||
|
``BadRequestKeyError`` has a message with the bad key in debug mode instead
|
||||||
|
of the generic bad request message. (`#2348`_)
|
||||||
|
|
||||||
.. _#1489: https://github.com/pallets/flask/pull/1489
|
.. _#1489: https://github.com/pallets/flask/pull/1489
|
||||||
.. _#1621: https://github.com/pallets/flask/pull/1621
|
.. _#1621: https://github.com/pallets/flask/pull/1621
|
||||||
|
|
@ -80,6 +83,7 @@ Major release, unreleased
|
||||||
.. _#2316: https://github.com/pallets/flask/pull/2316
|
.. _#2316: https://github.com/pallets/flask/pull/2316
|
||||||
.. _#2319: https://github.com/pallets/flask/pull/2319
|
.. _#2319: https://github.com/pallets/flask/pull/2319
|
||||||
.. _#2326: https://github.com/pallets/flask/pull/2326
|
.. _#2326: https://github.com/pallets/flask/pull/2326
|
||||||
|
.. _#2348: https://github.com/pallets/flask/pull/2348
|
||||||
|
|
||||||
Version 0.12.2
|
Version 0.12.2
|
||||||
--------------
|
--------------
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,10 @@ The following configuration values are used internally by Flask:
|
||||||
Trying to access a key that doesn't exist from request dicts like ``args``
|
Trying to access a key that doesn't exist from request dicts like ``args``
|
||||||
and ``form`` will return a 400 Bad Request error page. Enable this to treat
|
and ``form`` will return a 400 Bad Request error page. Enable this to treat
|
||||||
the error as an unhandled exception instead so that you get the interactive
|
the error as an unhandled exception instead so that you get the interactive
|
||||||
debugger. This is a more specific version of ``TRAP_HTTP_EXCEPTIONS``.
|
debugger. This is a more specific version of ``TRAP_HTTP_EXCEPTIONS``. If
|
||||||
|
unset, it is enabled in debug mode.
|
||||||
|
|
||||||
Default: ``False``
|
Default: ``None``
|
||||||
|
|
||||||
.. py:data:: SECRET_KEY
|
.. py:data:: SECRET_KEY
|
||||||
|
|
||||||
|
|
|
||||||
31
flask/app.py
31
flask/app.py
|
|
@ -18,7 +18,8 @@ from threading import Lock
|
||||||
|
|
||||||
from werkzeug.datastructures import ImmutableDict, Headers
|
from werkzeug.datastructures import ImmutableDict, Headers
|
||||||
from werkzeug.exceptions import BadRequest, HTTPException, \
|
from werkzeug.exceptions import BadRequest, HTTPException, \
|
||||||
InternalServerError, MethodNotAllowed, default_exceptions
|
InternalServerError, MethodNotAllowed, default_exceptions, \
|
||||||
|
BadRequestKeyError
|
||||||
from werkzeug.routing import BuildError, Map, RequestRedirect, Rule
|
from werkzeug.routing import BuildError, Map, RequestRedirect, Rule
|
||||||
|
|
||||||
from . import cli, json
|
from . import cli, json
|
||||||
|
|
@ -317,7 +318,7 @@ class Flask(_PackageBoundObject):
|
||||||
'SESSION_REFRESH_EACH_REQUEST': True,
|
'SESSION_REFRESH_EACH_REQUEST': True,
|
||||||
'MAX_CONTENT_LENGTH': None,
|
'MAX_CONTENT_LENGTH': None,
|
||||||
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
|
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
|
||||||
'TRAP_BAD_REQUEST_ERRORS': False,
|
'TRAP_BAD_REQUEST_ERRORS': None,
|
||||||
'TRAP_HTTP_EXCEPTIONS': False,
|
'TRAP_HTTP_EXCEPTIONS': False,
|
||||||
'EXPLAIN_TEMPLATE_LOADING': False,
|
'EXPLAIN_TEMPLATE_LOADING': False,
|
||||||
'PREFERRED_URL_SCHEME': 'http',
|
'PREFERRED_URL_SCHEME': 'http',
|
||||||
|
|
@ -1542,13 +1543,21 @@ class Flask(_PackageBoundObject):
|
||||||
exception is not called and it shows up as regular exception in the
|
exception is not called and it shows up as regular exception in the
|
||||||
traceback. This is helpful for debugging implicitly raised HTTP
|
traceback. This is helpful for debugging implicitly raised HTTP
|
||||||
exceptions.
|
exceptions.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.0
|
||||||
|
Bad request errors are not trapped by default in debug mode.
|
||||||
|
|
||||||
.. versionadded:: 0.8
|
.. versionadded:: 0.8
|
||||||
"""
|
"""
|
||||||
if self.config['TRAP_HTTP_EXCEPTIONS']:
|
if self.config['TRAP_HTTP_EXCEPTIONS']:
|
||||||
return True
|
return True
|
||||||
if self.config['TRAP_BAD_REQUEST_ERRORS']:
|
|
||||||
|
trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS']
|
||||||
|
|
||||||
|
# if unset, trap based on debug mode
|
||||||
|
if (trap_bad_request is None and self.debug) or trap_bad_request:
|
||||||
return isinstance(e, BadRequest)
|
return isinstance(e, BadRequest)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_user_exception(self, e):
|
def handle_user_exception(self, e):
|
||||||
|
|
@ -1559,16 +1568,30 @@ class Flask(_PackageBoundObject):
|
||||||
function will either return a response value or reraise the
|
function will either return a response value or reraise the
|
||||||
exception with the same traceback.
|
exception with the same traceback.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.0
|
||||||
|
Key errors raised from request data like ``form`` show the the bad
|
||||||
|
key in debug mode rather than a generic bad request message.
|
||||||
|
|
||||||
.. versionadded:: 0.7
|
.. versionadded:: 0.7
|
||||||
"""
|
"""
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
exc_type, exc_value, tb = sys.exc_info()
|
||||||
assert exc_value is e
|
assert exc_value is e
|
||||||
|
|
||||||
# ensure not to trash sys.exc_info() at that point in case someone
|
# ensure not to trash sys.exc_info() at that point in case someone
|
||||||
# wants the traceback preserved in handle_http_exception. Of course
|
# wants the traceback preserved in handle_http_exception. Of course
|
||||||
# we cannot prevent users from trashing it themselves in a custom
|
# we cannot prevent users from trashing it themselves in a custom
|
||||||
# trap_http_exception method so that's their fault then.
|
# trap_http_exception method so that's their fault then.
|
||||||
|
|
||||||
|
# MultiDict passes the key to the exception, but that's ignored
|
||||||
|
# when generating the response message. Set an informative
|
||||||
|
# description for key errors in debug mode.
|
||||||
|
if (
|
||||||
|
self.debug
|
||||||
|
and isinstance(e, BadRequestKeyError)
|
||||||
|
# only set it if it's still the default description
|
||||||
|
and e.description is BadRequestKeyError.description
|
||||||
|
):
|
||||||
|
e.description = "KeyError: '{0}'".format(*e.args)
|
||||||
|
|
||||||
if isinstance(e, HTTPException) and not self.trap_http_exception(e):
|
if isinstance(e, HTTPException) and not self.trap_http_exception(e):
|
||||||
return self.handle_http_exception(e)
|
return self.handle_http_exception(e)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class TestJSON(object):
|
||||||
|
|
||||||
def test_post_empty_json_adds_exception_to_response_content_in_debug(self, app, client):
|
def test_post_empty_json_adds_exception_to_response_content_in_debug(self, app, client):
|
||||||
app.config['DEBUG'] = True
|
app.config['DEBUG'] = True
|
||||||
|
app.config['TRAP_BAD_REQUEST_ERRORS'] = False
|
||||||
|
|
||||||
@app.route('/json', methods=['POST'])
|
@app.route('/json', methods=['POST'])
|
||||||
def post_json():
|
def post_json():
|
||||||
|
|
@ -56,6 +57,7 @@ class TestJSON(object):
|
||||||
|
|
||||||
def test_post_empty_json_wont_add_exception_to_response_if_no_debug(self, app, client):
|
def test_post_empty_json_wont_add_exception_to_response_if_no_debug(self, app, client):
|
||||||
app.config['DEBUG'] = False
|
app.config['DEBUG'] = False
|
||||||
|
app.config['TRAP_BAD_REQUEST_ERRORS'] = False
|
||||||
|
|
||||||
@app.route('/json', methods=['POST'])
|
@app.route('/json', methods=['POST'])
|
||||||
def post_json():
|
def post_json():
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue