Merge pull request #41 from nvllsvm/suffix

Add support for content-type suffixes
This commit is contained in:
joshehlinger 2022-03-07 17:12:36 -05:00 committed by GitHub
commit e0e67363a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 27 deletions

View file

@ -20,6 +20,8 @@ LOGGER = logging.getLogger(__name__)
CONTENT_TYPE_JSON = headers.parse_content_type('application/json')
CONTENT_TYPE_MSGPACK = headers.parse_content_type('application/msgpack')
CONTENT_TYPE_SUFFIX_JSON = 'json'
CONTENT_TYPE_SUFFIX_MSGPACK = 'msgpack'
AVAILABLE_CONTENT_TYPES = [CONTENT_TYPE_JSON, CONTENT_TYPE_MSGPACK]
DEFAULT_USER_AGENT = 'sprockets.mixins.http/{}'.format(__version__)
@ -206,24 +208,30 @@ class HTTPResponse:
:rtype: mixed
"""
if not self._responses or not self._responses[-1].body:
return None
if 'Content-Type' not in self._responses[-1].headers:
return self._responses[-1].body
try:
content_type = algorithms.select_content_type([
headers.parse_content_type(
self._responses[-1].headers['Content-Type'])
], AVAILABLE_CONTENT_TYPES)
except errors.NoMatch:
return self._responses[-1].body
if not self._responses:
return
response = self._responses[-1]
if not response.body:
return
if 'Content-Type' not in response.headers:
return response.body
if content_type[0] == CONTENT_TYPE_JSON:
return self._decode(
self._json.loads(self._decode(self._responses[-1].body)))
elif content_type[0] == CONTENT_TYPE_MSGPACK: # pragma: nocover
return self._decode(self._msgpack.unpackb(
self._responses[-1].body))
content_type = headers.parse_content_type(
response.headers['Content-Type'])
if content_type.content_suffix == CONTENT_TYPE_SUFFIX_JSON:
return self._decode(self._json.loads(self._decode(response.body)))
elif content_type.content_suffix == CONTENT_TYPE_SUFFIX_MSGPACK:
return self._decode(self._msgpack.unpackb(response.body))
try:
selected = algorithms.select_content_type(
[content_type], AVAILABLE_CONTENT_TYPES)
except errors.NoMatch:
return response.body
if selected[0] == CONTENT_TYPE_JSON:
return self._decode(self._json.loads(self._decode(response.body)))
elif selected[0] == CONTENT_TYPE_MSGPACK:
return self._decode(self._msgpack.unpackb(response.body))
def _error_message(self):
"""Try and extract the error message from a HTTP error response.
@ -466,9 +474,11 @@ class HTTPClientMixin:
if body is None or not isinstance(body, (dict, list)):
return body
content_type = headers.parse_content_type(content_type)
if content_type == CONTENT_TYPE_JSON:
if content_type == CONTENT_TYPE_JSON \
or content_type.content_suffix == CONTENT_TYPE_SUFFIX_JSON:
return self.__hcm_json.dumps(body)
elif content_type == CONTENT_TYPE_MSGPACK:
elif content_type == CONTENT_TYPE_MSGPACK \
or content_type.content_suffix == CONTENT_TYPE_SUFFIX_MSGPACK:
return self.__hcm_msgpack.packb(body)
raise ValueError('Unsupported Content Type')

View file

@ -61,10 +61,13 @@ class TestHandler(web.RequestHandler):
self.respond()
def get_request_body(self):
if 'Content-Type' in self.request.headers:
if self.request.headers['Content-Type'] == 'application/json':
content_type = self.request.headers.get('Content-Type')
if content_type is not None:
if content_type == 'application/json' \
or content_type.endswith('+json'):
return json.loads(self.request.body.decode('utf-8'))
elif self.request.headers['Content-Type'] == 'application/msgpack':
elif content_type == 'application/msgpack' \
or content_type.endswith('+msgpack'):
return umsgpack.unpackb(self.request.body)
if self.request.body_arguments:
return self.request.body_arguments
@ -97,11 +100,13 @@ class TestHandler(web.RequestHandler):
def send_response(self, payload):
if isinstance(payload, (dict, list)):
if self.request.headers.get('Accept') == 'application/json':
self.set_header('Content-Type', 'application/json')
return self.write(decode(payload))
elif self.request.headers.get('Accept') == 'application/msgpack':
self.set_header('Content-Type', 'application/msgpack')
accept = self.request.headers.get('Accept')
if accept == 'application/json' or accept.endswith('+json'):
self.set_header('Content-Type', accept)
return self.write(json.dumps(decode(payload)))
elif accept == 'application/msgpack' \
or accept.endswith('+msgpack'):
self.set_header('Content-Type', accept)
return self.write(umsgpack.packb(decode(payload)))
LOGGER.debug('Bypassed serialization')
content_type = self.get_argument('content_type', None)
@ -750,3 +755,41 @@ class MixinTestCase(testing.AsyncHTTPTestCase):
request_headers={'Content-Type': 'application/json'})
self.assertEqual(200, response.code)
self.assertEqual([], response.body['body'])
@testing.gen_test
def test_post_msgpack_suffix(self):
body = {
'foo': 'bar',
'status_code': 200
}
response = yield self.mixin.http_fetch(
self.get_url('/test'),
method='POST',
body=body,
request_headers={
'Accept': 'bar/foo+msgpack',
'Content-Type': 'foo/bar+msgpack'
})
self.assertEqual(response.code, 200)
self.assertEqual(response.headers['Content-Type'],
'bar/foo+msgpack')
self.assertEqual(response.body['body'], body)
@testing.gen_test
def test_post_json_suffix(self):
body = {
'foo': 'bar',
'status_code': 200
}
response = yield self.mixin.http_fetch(
self.get_url('/test'),
method='POST',
body=body,
request_headers={
'Accept': 'bar/foo+json',
'Content-Type': 'foo/bar+json'
})
self.assertEqual(response.code, 200)
self.assertEqual(response.headers['Content-Type'],
'bar/foo+json')
self.assertEqual(response.body['body'], body)