Enhance GET /v3 to handle Accept header
Keystone wasn't handling the Accept header for GET /v3 according to the HTTP 1.1 spec[1]. This change enhances the Keystone server so that it supports using multiple values and qvalues in the Accept header for GET /v3. This allows requesting a JSON Home or JSON response with a preference for JSON Home, for example. [1] http://tools.ietf.org/html/rfc2616#section-14.1 bp json-home Change-Id: Ifb204b6860c61a874ecbf92388878685ac437987
This commit is contained in:
parent
9077fdfe11
commit
c2e40d3de7
@ -193,6 +193,7 @@ class Application(BaseApplication):
|
|||||||
# values by the container and processed by the pipeline. the complete
|
# values by the container and processed by the pipeline. the complete
|
||||||
# set is not yet know.
|
# set is not yet know.
|
||||||
context['environment'] = req.environ
|
context['environment'] = req.environ
|
||||||
|
context['accept_header'] = req.accept
|
||||||
req.environ = None
|
req.environ = None
|
||||||
|
|
||||||
params.update(arg_dict)
|
params.update(arg_dict)
|
||||||
|
@ -60,6 +60,23 @@ def register_version(version):
|
|||||||
_VERSIONS.append(version)
|
_VERSIONS.append(version)
|
||||||
|
|
||||||
|
|
||||||
|
class MimeTypes:
|
||||||
|
JSON = 'application/json'
|
||||||
|
JSON_HOME = 'application/json-home'
|
||||||
|
|
||||||
|
|
||||||
|
def v3_mime_type_best_match(context):
|
||||||
|
|
||||||
|
# accept_header is a WebOb MIMEAccept object so supports best_match.
|
||||||
|
accept_header = context['accept_header']
|
||||||
|
|
||||||
|
if not accept_header:
|
||||||
|
return MimeTypes.JSON
|
||||||
|
|
||||||
|
SUPPORTED_TYPES = [MimeTypes.JSON, MimeTypes.JSON_HOME]
|
||||||
|
return accept_header.best_match(SUPPORTED_TYPES)
|
||||||
|
|
||||||
|
|
||||||
class Version(wsgi.Application):
|
class Version(wsgi.Application):
|
||||||
|
|
||||||
def __init__(self, version_type, routers=None):
|
def __init__(self, version_type, routers=None):
|
||||||
@ -157,10 +174,12 @@ class Version(wsgi.Application):
|
|||||||
def get_version_v3(self, context):
|
def get_version_v3(self, context):
|
||||||
versions = self._get_versions_list(context)
|
versions = self._get_versions_list(context)
|
||||||
if 'v3' in _VERSIONS:
|
if 'v3' in _VERSIONS:
|
||||||
if context['headers'].get('Accept') == 'application/json-home':
|
req_mime_type = v3_mime_type_best_match(context)
|
||||||
|
|
||||||
|
if req_mime_type == MimeTypes.JSON_HOME:
|
||||||
return wsgi.render_response(
|
return wsgi.render_response(
|
||||||
body=self._get_json_home_v3(),
|
body=self._get_json_home_v3(),
|
||||||
headers=(('Content-Type', 'application/json-home'),))
|
headers=(('Content-Type', MimeTypes.JSON_HOME),))
|
||||||
|
|
||||||
return wsgi.render_response(body={
|
return wsgi.render_response(body={
|
||||||
'version': versions['v3']
|
'version': versions['v3']
|
||||||
|
@ -563,6 +563,48 @@ class VersionTestCase(tests.TestCase):
|
|||||||
self.assertThat(jsonutils.loads(resp.body),
|
self.assertThat(jsonutils.loads(resp.body),
|
||||||
tt_matchers.Equals(exp_json_home_data))
|
tt_matchers.Equals(exp_json_home_data))
|
||||||
|
|
||||||
|
def test_accept_type_handling(self):
|
||||||
|
# Accept headers with multiple types and qvalues are handled.
|
||||||
|
|
||||||
|
def make_request(accept_types=None):
|
||||||
|
client = self.client(self.public_app)
|
||||||
|
headers = None
|
||||||
|
if accept_types:
|
||||||
|
headers = {'Accept': accept_types}
|
||||||
|
resp = client.get('/v3', headers=headers)
|
||||||
|
self.assertThat(resp.status, tt_matchers.Equals('200 OK'))
|
||||||
|
return resp.headers['Content-Type']
|
||||||
|
|
||||||
|
JSON = controllers.MimeTypes.JSON
|
||||||
|
JSON_HOME = controllers.MimeTypes.JSON_HOME
|
||||||
|
|
||||||
|
JSON_MATCHER = tt_matchers.Equals(JSON)
|
||||||
|
JSON_HOME_MATCHER = tt_matchers.Equals(JSON_HOME)
|
||||||
|
|
||||||
|
# Default is JSON.
|
||||||
|
self.assertThat(make_request(), JSON_MATCHER)
|
||||||
|
|
||||||
|
# Can request JSON and get JSON.
|
||||||
|
self.assertThat(make_request(JSON), JSON_MATCHER)
|
||||||
|
|
||||||
|
# Can request JSONHome and get JSONHome.
|
||||||
|
self.assertThat(make_request(JSON_HOME), JSON_HOME_MATCHER)
|
||||||
|
|
||||||
|
# If request JSON, JSON Home get JSON.
|
||||||
|
accept_types = '%s, %s' % (JSON, JSON_HOME)
|
||||||
|
self.assertThat(make_request(accept_types), JSON_MATCHER)
|
||||||
|
|
||||||
|
# If request JSON Home, JSON get JSON.
|
||||||
|
accept_types = '%s, %s' % (JSON_HOME, JSON)
|
||||||
|
self.assertThat(make_request(accept_types), JSON_MATCHER)
|
||||||
|
|
||||||
|
# If request JSON Home, JSON;q=0.5 get JSON Home.
|
||||||
|
accept_types = '%s, %s;q=0.5' % (JSON_HOME, JSON)
|
||||||
|
self.assertThat(make_request(accept_types), JSON_HOME_MATCHER)
|
||||||
|
|
||||||
|
# If request some unknown mime-type, get JSON.
|
||||||
|
self.assertThat(make_request(self.getUniqueString()), JSON_MATCHER)
|
||||||
|
|
||||||
|
|
||||||
class VersionInheritEnabledTestCase(tests.TestCase):
|
class VersionInheritEnabledTestCase(tests.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user