diff --git a/docs/history.rst b/docs/history.rst index b310248..9d6fa2e 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -6,10 +6,11 @@ Version History - Repackage from a module into a package. Distributing raw modules inside of a namespace package is unreliable and questionably correct. - Add :func:`sprockets.mixins.mediatype.content.add_transcoder`. -- Add :class:`sprockets.mixins.mediatype.transcoders.JSONTranscoder` -- Add :class:`sprockets.mixins.mediatype.transcoders.MsgPackTranscoder` -- Add :class:`sprockets.mixins.mediatype.transcoders.BinaryWrapper` +- Add :class:`sprockets.mixins.mediatype.transcoders.JSONTranscoder`. +- Add :class:`sprockets.mixins.mediatype.transcoders.MsgPackTranscoder`. +- Add :class:`sprockets.mixins.mediatype.transcoders.BinaryWrapper`. - Normalize registered MIME types. +- Raise a 400 status when content body decoding fails. `1.0.4`_ (14 Sep 2015) ---------------------- diff --git a/sprockets/mixins/mediatype/content.py b/sprockets/mixins/mediatype/content.py index b0e69a2..73dc0ef 100644 --- a/sprockets/mixins/mediatype/content.py +++ b/sprockets/mixins/mediatype/content.py @@ -236,6 +236,7 @@ class ContentMixin(object): super(ContentMixin, self).initialize() self._request_body = None self._best_response_match = None + self._logger = getattr(self, 'logger', logger) def get_response_content_type(self): """Figure out what content type will be used in the response.""" @@ -260,8 +261,11 @@ class ContentMixin(object): """ Fetch (and cache) the request body as a dictionary. - :raise web.HTTPError: if the content type cannot be decoded. - The status code is set to 415 Unsupported Media Type + :raise web.HTTPError: + - if the content type cannot be matched, then the status code + is set to 415 Unsupported Media Type. + - if decoding the content body fails, then the status code is + set to 400 Bad Syntax. """ if self._request_body is None: @@ -273,12 +277,16 @@ class ContentMixin(object): content_type_header.content_subtype]) try: handler = settings[content_type] - self._request_body = handler.from_bytes(self.request.body) - except KeyError: raise web.HTTPError(415, 'cannot decode body of type %s', content_type) + try: + self._request_body = handler.from_bytes(self.request.body) + except Exception: + self._logger.exception('failed to decode request body') + raise web.HTTPError(400, 'failed to decode request') + return self._request_body def send_response(self, body, set_content_type=True): diff --git a/tests.py b/tests.py index 9464209..76cb2a4 100644 --- a/tests.py +++ b/tests.py @@ -121,6 +121,14 @@ class GetRequestBodyTests(testing.AsyncHTTPTestCase): self.assertEqual(response.code, 200) self.assertEqual(json.loads(response.body.decode('utf-8')), body) + def test_that_invalid_data_returns_400(self): + response = self.fetch( + '/', method='POST', headers={'Content-Type': 'application/json'}, + body=('echo' + 'Hi' + '').encode('utf-8')) + self.assertEqual(response.code, 400) + class JSONTranscoderTests(unittest.TestCase):