|
|
@ -25,15 +25,88 @@ def _get_data(req, cache): |
|
|
|
return req.data |
|
|
|
return req.data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _is_mimetype_json(mimetype): |
|
|
|
class JSONMixin(object): |
|
|
|
if mimetype == 'application/json': |
|
|
|
"""Mixin for both request and response classes to provide JSON parsing |
|
|
|
return True |
|
|
|
capabilities. |
|
|
|
if mimetype.startswith('application/') and mimetype.endswith('+json'): |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 0.12 |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def is_json(self): |
|
|
|
|
|
|
|
"""Indicates if this request/response is JSON or not. By default it |
|
|
|
|
|
|
|
is considered to include JSON data if the mimetype is |
|
|
|
|
|
|
|
:mimetype:`application/json` or :mimetype:`application/*+json`. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
mt = self.mimetype |
|
|
|
|
|
|
|
if mt == 'application/json': |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
if mt.startswith('application/') and mt.endswith('+json'): |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def json(self): |
|
|
|
|
|
|
|
"""If the mimetype is :mimetype:`application/json` this will contain the |
|
|
|
|
|
|
|
parsed JSON data. Otherwise this will be ``None``. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The :meth:`get_json` method should be used instead. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
from warnings import warn |
|
|
|
|
|
|
|
warn(DeprecationWarning('json is deprecated. ' |
|
|
|
|
|
|
|
'Use get_json() instead.'), stacklevel=2) |
|
|
|
|
|
|
|
return self.get_json() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_json(self, force=False, silent=False, cache=True): |
|
|
|
|
|
|
|
"""Parses the incoming JSON request data and returns it. By default |
|
|
|
|
|
|
|
this function will return ``None`` if the mimetype is not |
|
|
|
|
|
|
|
:mimetype:`application/json` but this can be overridden by the |
|
|
|
|
|
|
|
``force`` parameter. If parsing fails the |
|
|
|
|
|
|
|
:meth:`on_json_loading_failed` method on the request object will be |
|
|
|
|
|
|
|
invoked. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param force: if set to ``True`` the mimetype is ignored. |
|
|
|
|
|
|
|
:param silent: if set to ``True`` this method will fail silently |
|
|
|
|
|
|
|
and return ``None``. |
|
|
|
|
|
|
|
:param cache: if set to ``True`` the parsed JSON data is remembered |
|
|
|
|
|
|
|
on the request. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
rv = getattr(self, '_cached_json', _missing) |
|
|
|
|
|
|
|
if rv is not _missing: |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not (force or self.is_json): |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# We accept a request charset against the specification as certain |
|
|
|
|
|
|
|
# clients have been using this in the past. For responses, we assume |
|
|
|
|
|
|
|
# that if the response charset was set explicitly then the data had |
|
|
|
|
|
|
|
# been encoded correctly as well. |
|
|
|
|
|
|
|
charset = self.mimetype_params.get('charset') |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
data = _get_data(self, cache) |
|
|
|
|
|
|
|
if charset is not None: |
|
|
|
|
|
|
|
rv = json.loads(data, encoding=charset) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = json.loads(data) |
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
|
|
|
|
if silent: |
|
|
|
|
|
|
|
rv = None |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = self.on_json_loading_failed(e) |
|
|
|
|
|
|
|
if cache: |
|
|
|
|
|
|
|
self._cached_json = rv |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_json_loading_failed(self, e): |
|
|
|
|
|
|
|
"""Called if decoding of the JSON data failed. The return value of |
|
|
|
|
|
|
|
this method is used by :meth:`get_json` when an error occurred. The |
|
|
|
|
|
|
|
default implementation just raises a :class:`BadRequest` exception. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
raise BadRequest() |
|
|
|
|
|
|
|
|
|
|
|
class Request(RequestBase): |
|
|
|
|
|
|
|
|
|
|
|
class Request(RequestBase, JSONMixin): |
|
|
|
"""The request object used by default in Flask. Remembers the |
|
|
|
"""The request object used by default in Flask. Remembers the |
|
|
|
matched endpoint and view arguments. |
|
|
|
matched endpoint and view arguments. |
|
|
|
|
|
|
|
|
|
|
@ -103,69 +176,6 @@ class Request(RequestBase): |
|
|
|
if self.url_rule and '.' in self.url_rule.endpoint: |
|
|
|
if self.url_rule and '.' in self.url_rule.endpoint: |
|
|
|
return self.url_rule.endpoint.rsplit('.', 1)[0] |
|
|
|
return self.url_rule.endpoint.rsplit('.', 1)[0] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def json(self): |
|
|
|
|
|
|
|
"""If the mimetype is :mimetype:`application/json` this will contain the |
|
|
|
|
|
|
|
parsed JSON data. Otherwise this will be ``None``. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The :meth:`get_json` method should be used instead. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
from warnings import warn |
|
|
|
|
|
|
|
warn(DeprecationWarning('json is deprecated. ' |
|
|
|
|
|
|
|
'Use get_json() instead.'), stacklevel=2) |
|
|
|
|
|
|
|
return self.get_json() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def is_json(self): |
|
|
|
|
|
|
|
"""Indicates if this request is JSON or not. By default a request |
|
|
|
|
|
|
|
is considered to include JSON data if the mimetype is |
|
|
|
|
|
|
|
:mimetype:`application/json` or :mimetype:`application/*+json`. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 0.11 |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
return _is_mimetype_json(self.mimetype) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_json(self, force=False, silent=False, cache=True): |
|
|
|
|
|
|
|
"""Parses the incoming JSON request data and returns it. By default |
|
|
|
|
|
|
|
this function will return ``None`` if the mimetype is not |
|
|
|
|
|
|
|
:mimetype:`application/json` but this can be overridden by the |
|
|
|
|
|
|
|
``force`` parameter. If parsing fails the |
|
|
|
|
|
|
|
:meth:`on_json_loading_failed` method on the request object will be |
|
|
|
|
|
|
|
invoked. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param force: if set to ``True`` the mimetype is ignored. |
|
|
|
|
|
|
|
:param silent: if set to ``True`` this method will fail silently |
|
|
|
|
|
|
|
and return ``None``. |
|
|
|
|
|
|
|
:param cache: if set to ``True`` the parsed JSON data is remembered |
|
|
|
|
|
|
|
on the request. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
rv = getattr(self, '_cached_json', _missing) |
|
|
|
|
|
|
|
if rv is not _missing: |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not (force or self.is_json): |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# We accept a request charset against the specification as |
|
|
|
|
|
|
|
# certain clients have been using this in the past. This |
|
|
|
|
|
|
|
# fits our general approach of being nice in what we accept |
|
|
|
|
|
|
|
# and strict in what we send out. |
|
|
|
|
|
|
|
request_charset = self.mimetype_params.get('charset') |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
data = _get_data(self, cache) |
|
|
|
|
|
|
|
if request_charset is not None: |
|
|
|
|
|
|
|
rv = json.loads(data, encoding=request_charset) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = json.loads(data) |
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
|
|
|
|
if silent: |
|
|
|
|
|
|
|
rv = None |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = self.on_json_loading_failed(e) |
|
|
|
|
|
|
|
if cache: |
|
|
|
|
|
|
|
self._cached_json = rv |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_json_loading_failed(self, e): |
|
|
|
def on_json_loading_failed(self, e): |
|
|
|
"""Called if decoding of the JSON data failed. The return value of |
|
|
|
"""Called if decoding of the JSON data failed. The return value of |
|
|
|
this method is used by :meth:`get_json` when an error occurred. The |
|
|
|
this method is used by :meth:`get_json` when an error occurred. The |
|
|
@ -195,7 +205,7 @@ class Request(RequestBase): |
|
|
|
attach_enctype_error_multidict(self) |
|
|
|
attach_enctype_error_multidict(self) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Response(ResponseBase): |
|
|
|
class Response(ResponseBase, JSONMixin): |
|
|
|
"""The response object that is used by default in Flask. Works like the |
|
|
|
"""The response object that is used by default in Flask. Works like the |
|
|
|
response object from Werkzeug but is set to have an HTML mimetype by |
|
|
|
response object from Werkzeug but is set to have an HTML mimetype by |
|
|
|
default. Quite often you don't have to create this object yourself because |
|
|
|
default. Quite often you don't have to create this object yourself because |
|
|
@ -205,69 +215,3 @@ class Response(ResponseBase): |
|
|
|
set :attr:`~flask.Flask.response_class` to your subclass. |
|
|
|
set :attr:`~flask.Flask.response_class` to your subclass. |
|
|
|
""" |
|
|
|
""" |
|
|
|
default_mimetype = 'text/html' |
|
|
|
default_mimetype = 'text/html' |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def json(self): |
|
|
|
|
|
|
|
"""If the mimetype is :mimetype:`application/json` this will contain the |
|
|
|
|
|
|
|
parsed JSON data. Otherwise this will be ``None``. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The :meth:`get_json` method should be used instead. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 1.0 |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
from warnings import warn |
|
|
|
|
|
|
|
warn(DeprecationWarning('json is deprecated. ' |
|
|
|
|
|
|
|
'Use get_json() instead.'), stacklevel=2) |
|
|
|
|
|
|
|
return self.get_json() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def is_json(self): |
|
|
|
|
|
|
|
"""Indicates if this response is JSON or not. By default a response |
|
|
|
|
|
|
|
is considered to include JSON data if the mimetype is |
|
|
|
|
|
|
|
:mimetype:`application/json` or :mimetype:`application/*+json`. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 1.0 |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
return _is_mimetype_json(self.mimetype) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_json(self, force=False, silent=False, cache=True): |
|
|
|
|
|
|
|
"""Parses the incoming JSON request data and returns it. If |
|
|
|
|
|
|
|
parsing fails the :meth:`on_json_loading_failed` method on the |
|
|
|
|
|
|
|
request object will be invoked. By default this function will |
|
|
|
|
|
|
|
only load the json data if the mimetype is :mimetype:`application/json` |
|
|
|
|
|
|
|
but this can be overridden by the `force` parameter. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param force: if set to ``True`` the mimetype is ignored. |
|
|
|
|
|
|
|
:param silent: if set to ``True`` this method will fail silently |
|
|
|
|
|
|
|
and return ``None``. |
|
|
|
|
|
|
|
:param cache: if set to ``True`` the parsed JSON data is remembered |
|
|
|
|
|
|
|
on the request. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 1.0 |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
rv = getattr(self, '_cached_json', _missing) |
|
|
|
|
|
|
|
if rv is not _missing: |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not (force or self.is_json): |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# We accept a request charset against the specification as |
|
|
|
|
|
|
|
# certain clients have been using this in the past. This |
|
|
|
|
|
|
|
# fits our general approach of being nice in what we accept |
|
|
|
|
|
|
|
# and strict in what we send out. |
|
|
|
|
|
|
|
request_charset = self.mimetype_params.get('charset') |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
data = _get_data(self, cache) |
|
|
|
|
|
|
|
if request_charset is not None: |
|
|
|
|
|
|
|
rv = json.loads(data, encoding=request_charset) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = json.loads(data) |
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
|
|
|
|
if silent: |
|
|
|
|
|
|
|
rv = None |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rv = self.on_json_loading_failed(e) |
|
|
|
|
|
|
|
if cache: |
|
|
|
|
|
|
|
self._cached_json = rv |
|
|
|
|
|
|
|
return rv |
|
|
|
|
|
|
|