Fail gracefully when transcoder is missing.

If there is no transcoder for the default content type, sending a
response would fail with a "500 Internal Server Error" due to an
*unhandled* KeyError.  This commit catches the KeyError and produces
an explicit "500 Internal Server Error" with an appropriate error
message being logged.
This commit is contained in:
Dave Shawley 2021-10-02 11:44:57 -04:00
parent d605acb5b7
commit 9ff5ca3781
No known key found for this signature in database
GPG key ID: F41A8A99298F8EED
3 changed files with 24 additions and 6 deletions

View file

@ -7,6 +7,7 @@ Version History
- Return a "406 Not Acceptable" if the :http:header:`Accept` header values cannot be matched
and there is no default content type configured
- Deprecate not having a default content type configured
- Fail gracefully when a transcoder does not exist for the default content type
:compare:`3.0.4 <3.0.3...3.0.4>` (2 Nov 2020)
---------------------------------------------

View file

@ -414,9 +414,17 @@ class ContentMixin(web.RequestHandler):
self._logger.error('please set a default content type')
raise web.HTTPError(406)
handler = settings[response_type]
content_type, data_bytes = handler.to_bytes(body)
if set_content_type:
self.set_header('Content-Type', content_type)
self.add_header('Vary', 'Accept')
self.write(data_bytes)
try:
handler = settings[response_type]
except KeyError:
self._logger.error(
'no transcoder for the selected response content type %s, '
'is the default content type %r correct?', response_type,
settings.default_content_type)
raise web.HTTPError(500)
else:
content_type, data_bytes = handler.to_bytes(body)
if set_content_type:
self.set_header('Content-Type', content_type)
self.add_header('Vary', 'Accept')
self.write(data_bytes)

View file

@ -150,6 +150,15 @@ class SendResponseTests(testing.AsyncHTTPTestCase):
})
self.assertEqual(response.code, 406)
def test_misconfigured_default_content_type(self):
settings = content.get_settings(self.application, force_instance=True)
settings.default_content_type = 'application/xml'
response = self.fetch('/',
method='POST',
body='{}',
headers={'Content-Type': 'application/json'})
self.assertEqual(response.code, 500)
class GetRequestBodyTests(testing.AsyncHTTPTestCase):
def setUp(self):