From 3a74866d57ec3d9fc6b6ccfbb170573530c701a5 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Sun, 28 Feb 2016 11:41:29 +0100 Subject: [PATCH] properly handle content_type callables returning a single internet media type as scalar, improves and resolves #343 --- CHANGES.txt | 1 + cornice/tests/test_validation.py | 19 ++++++++++++++++++- cornice/tests/validationapp.py | 17 ++++++----------- cornice/util.py | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 303648dc..05a923bf 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,6 +7,7 @@ CHANGELOG ================== - Nothing changed yet. +- Properly handle content_type callables returning a single internet media type as scalar (#343) 1.2.0 (2016-01-18) diff --git a/cornice/tests/test_validation.py b/cornice/tests/test_validation.py index ce76af57..91d1f00b 100644 --- a/cornice/tests/test_validation.py +++ b/cornice/tests/test_validation.py @@ -94,6 +94,16 @@ def test_accept(self): response = app.get('/service3', headers={'Accept': 'text/*'}) self.assertEqual(response.content_type, "text/json") + # test that using a callable to define what's accepted works as well + # now, the callable returns a scalar instead of a list + response = app.put('/service3', headers={'Accept': 'audio/*'}, + status=406) + error_description = response.json['errors'][0]['description'] + self.assertIn('text/json', error_description) + + response = app.put('/service3', headers={'Accept': 'text/*'}) + self.assertEqual(response.content_type, "text/json") + # if we are not asking for a particular content-type, # we should get one of the two types that the service supports. response = app.get('/service2') @@ -243,7 +253,14 @@ def test_content_type_with_callable(self): self.assertTrue('text/xml' in error_description) self.assertTrue('application/json' in error_description) - app.post('/service6', headers={'Content-Type': 'text/xml'}) + def test_content_type_with_callable_returning_scalar(self): + # test that using a callable for content_type works as well + # now, the callable returns a scalar instead of a list + app = TestApp(main({})) + response = app.put('/service6', headers={'Content-Type': 'audio/*'}, + status=415) + error_description = response.json['errors'][0]['description'] + self.assertIn('text/xml', error_description) def test_accept_and_content_type(self): # tests that giving both Accept and Content-Type diff --git a/cornice/tests/validationapp.py b/cornice/tests/validationapp.py index c1379040..11cc9db1 100644 --- a/cornice/tests/validationapp.py +++ b/cornice/tests/validationapp.py @@ -62,11 +62,8 @@ def get2(request): service3 = Service(name="service3", path="/service3") -def _accept(request): - return ('application/json', 'text/json') - - -@service3.get(accept=_accept) +@service3.get(accept=lambda request: ('application/json', 'text/json')) +@service3.put(accept=lambda request: 'text/json') def get3(request): return {"body": "yay!"} @@ -117,15 +114,13 @@ def get4(request): def post5(request): return "some response" -# test the "content_type" parameter (callable) -service6 = Service(name="service6", path="/service6") - -def _content_type(request): - return ('text/xml', 'application/json') +# service for testing the "content_type" parameter (callable) +service6 = Service(name="service6", path="/service6") -@service6.post(content_type=_content_type) +@service6.post(content_type=lambda request: ('text/xml', 'application/json')) +@service6.put(content_type=lambda request: 'text/xml') def post6(request): return {"body": "yay!"} diff --git a/cornice/util.py b/cornice/util.py index d10ca17c..8d66d25a 100644 --- a/cornice/util.py +++ b/cornice/util.py @@ -111,15 +111,15 @@ def match_accept_header(func, context, request): The callable returning the list of acceptable content-types, given a request. It should accept a "request" argument. """ - acceptable = func(request) # attach the accepted egress content types to the request + acceptable = to_list(func(request)) request.info['acceptable'] = acceptable return request.accept.best_match(acceptable) is not None def match_content_type_header(func, context, request): - supported_contenttypes = func(request) # attach the accepted ingress content types to the request + supported_contenttypes = to_list(func(request)) request.info['supported_contenttypes'] = supported_contenttypes return content_type_matches(request, supported_contenttypes)