mirror of
https://github.com/sprockets/sprockets.mixins.mediatype.git
synced 2024-11-22 03:00:25 +00:00
Add request body negotiation.
This commit is contained in:
parent
123793cd86
commit
f766a24e26
2 changed files with 59 additions and 8 deletions
|
@ -6,6 +6,7 @@ sprockets.mixins.media_type
|
|||
import logging
|
||||
|
||||
from ietfparse import algorithms, errors, headers
|
||||
from tornado import web
|
||||
|
||||
|
||||
version_info = (0, 0, 0)
|
||||
|
@ -74,6 +75,9 @@ class ContentSettings(object):
|
|||
self._available_types.append(headers.parse_content_type(content_type))
|
||||
self._handlers[content_type] = handler
|
||||
|
||||
def get(self, content_type, default=None):
|
||||
return self._handlers.get(content_type, default)
|
||||
|
||||
@classmethod
|
||||
def from_application(cls, application):
|
||||
"""Retrieve the content settings from an application."""
|
||||
|
@ -186,11 +190,28 @@ class ContentMixin(object):
|
|||
return self._best_response_match
|
||||
|
||||
def get_request_body(self):
|
||||
"""Fetch (and cache) the request body as a dictionary."""
|
||||
"""
|
||||
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
|
||||
|
||||
"""
|
||||
if self._request_body is None:
|
||||
settings = ContentSettings.from_application(self.application)
|
||||
handler = settings[settings.default_content_type]
|
||||
self._request_body = handler.from_bytes(self.request.body)
|
||||
content_type_header = headers.parse_content_type(
|
||||
self.request.headers.get('Content-Type',
|
||||
settings.default_content_type))
|
||||
content_type = '/'.join([content_type_header.content_type,
|
||||
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)
|
||||
|
||||
return self._request_body
|
||||
|
||||
def send_response(self, body, set_content_type=True):
|
||||
|
|
40
tests.py
40
tests.py
|
@ -1,16 +1,18 @@
|
|||
import json
|
||||
|
||||
from tornado import testing
|
||||
import msgpack
|
||||
|
||||
import examples
|
||||
|
||||
|
||||
class ContentTypeTests(testing.AsyncHTTPTestCase):
|
||||
class SendResponseTests(testing.AsyncHTTPTestCase):
|
||||
|
||||
def get_app(self):
|
||||
return examples.make_application(debug=True)
|
||||
|
||||
def test_that_content_type_default_works(self):
|
||||
response = self.fetch('/', method='POST',
|
||||
body='{"attribute": "value"}',
|
||||
response = self.fetch('/', method='POST', body='{}',
|
||||
headers={'Content-Type': 'application/json'})
|
||||
self.assertEqual(response.code, 200)
|
||||
self.assertEqual(response.headers['Content-Type'],
|
||||
|
@ -18,14 +20,42 @@ class ContentTypeTests(testing.AsyncHTTPTestCase):
|
|||
|
||||
def test_that_missing_content_type_uses_default(self):
|
||||
response = self.fetch('/', method='POST', body='{}',
|
||||
headers={'Accept': 'application/xml'})
|
||||
headers={'Accept': 'application/xml',
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(response.code, 200)
|
||||
self.assertEqual(response.headers['Content-Type'],
|
||||
'application/json; charset="utf-8"')
|
||||
|
||||
def test_that_accept_header_is_obeyed(self):
|
||||
response = self.fetch('/', method='POST', body='{}',
|
||||
headers={'Accept': 'application/msgpack'})
|
||||
headers={'Accept': 'application/msgpack',
|
||||
'Content-Type': 'application/json'})
|
||||
self.assertEqual(response.code, 200)
|
||||
self.assertEqual(response.headers['Content-Type'],
|
||||
'application/msgpack')
|
||||
|
||||
|
||||
class GetRequestBodyTests(testing.AsyncHTTPTestCase):
|
||||
|
||||
def get_app(self):
|
||||
return examples.make_application(debug=True)
|
||||
|
||||
def test_that_request_with_unhandled_type_results_in_415(self):
|
||||
response = self.fetch(
|
||||
'/', method='POST', headers={'Content-Type': 'application/xml'},
|
||||
body=(u'<request><name>value</name>'
|
||||
u'<embedded><utf8>\u2731</utf8></embedded>'
|
||||
u'</request>').encode('utf-8'))
|
||||
self.assertEqual(response.code, 415)
|
||||
|
||||
def test_that_msgpack_request_returns_default_type(self):
|
||||
body = {
|
||||
'name': 'value',
|
||||
'embedded': {
|
||||
'utf8': u'\u2731'
|
||||
}
|
||||
}
|
||||
response = self.fetch('/', method='POST', body=msgpack.packb(body),
|
||||
headers={'Content-Type': 'application/msgpack'})
|
||||
self.assertEqual(response.code, 200)
|
||||
self.assertEqual(json.loads(response.body.decode('utf-8')), body)
|
||||
|
|
Loading…
Reference in a new issue