From 21c6cb73fef673b54e7008b794eaaefbe011b628 Mon Sep 17 00:00:00 2001 From: Dave Shawley Date: Thu, 29 Oct 2020 13:50:33 -0400 Subject: [PATCH] Invalid content-type --> 400 Bad Request. ietfparse raises a `ValueError` from `parse_content_type` which was uncaught and resulted in an internal server error. --- docs/history.rst | 5 +++++ sprockets/mixins/mediatype/content.py | 11 ++++++++--- tests.py | 13 ++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/history.rst b/docs/history.rst index aa87628..45c60af 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -1,6 +1,11 @@ Version History =============== +Next Release +------------ +- Return a "400 Bad Request" when an invalid Content-Type header is received + instead of failing with an internal server error + `3.0.3`_ (14 Sep 2020) ---------------------- - Import from collections.abc instead of collections (thanks @nullsvm) diff --git a/sprockets/mixins/mediatype/content.py b/sprockets/mixins/mediatype/content.py index a21fa2b..7552791 100644 --- a/sprockets/mixins/mediatype/content.py +++ b/sprockets/mixins/mediatype/content.py @@ -319,9 +319,14 @@ class ContentMixin: """ if self._request_body is None: settings = get_settings(self.application, force_instance=True) - content_type_header = headers.parse_content_type( - self.request.headers.get('Content-Type', - settings.default_content_type)) + content_type = self.request.headers.get( + 'Content-Type', settings.default_content_type) + + try: + content_type_header = headers.parse_content_type(content_type) + except ValueError: + raise web.HTTPError(400, 'failed to parse content type %s', + content_type) content_type = '/'.join([content_type_header.content_type, content_type_header.content_subtype]) if content_type_header.content_suffix is not None: diff --git a/tests.py b/tests.py index efa1dc2..5b735e5 100644 --- a/tests.py +++ b/tests.py @@ -114,9 +114,13 @@ class SendResponseTests(testing.AsyncHTTPTestCase): class GetRequestBodyTests(testing.AsyncHTTPTestCase): + def setUp(self): + self.app = None + super().setUp() def get_app(self): - return examples.make_application(debug=True) + self.app = examples.make_application(debug=True) + return self.app def test_that_request_with_unhandled_type_results_in_415(self): response = self.fetch( @@ -157,6 +161,13 @@ class GetRequestBodyTests(testing.AsyncHTTPTestCase): self.assertEqual(response.code, 200) self.assertEqual(json.loads(response.body.decode()), body) + def test_that_invalid_content_types_result_in_bad_request(self): + content.set_default_content_type(self.app, None, None) + response = self.fetch( + '/', method='POST', body='{"hi":"there"}', + headers={'Content-Type': 'application-json'}) + self.assertEqual(response.code, 400) + class JSONTranscoderTests(unittest.TestCase):