microversion-parse/microversion_parse/middleware.py

91 lines
3.6 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""WSGI middleware for getting microversion info."""
import webob
import webob.dec
import microversion_parse
class MicroversionMiddleware(object):
"""WSGI middleware for getting microversion info.
The application will get a WSGI environ with a
'SERVICE_TYPE.microversion' key that has a value of the microversion
found at an 'openstack-api-version' header that matches SERVICE_TYPE. If
no header is found, the minimum microversion will be set. If the
special keyword 'latest' is used, the maximum microversion will be
set.
If the requested microversion is not available a 406 response is
returned.
If there is an error parsing a provided header, a 400 response is
returned.
Otherwise the application is called.
"""
def __init__(self, application, service_type, versions,
json_error_formatter=None):
"""Create the WSGI middleware.
:param application: The application hosting the service.
:param service_type: The service type (entry in keystone catalog)
of the application.
:param versions: An ordered list of legitimate versions for the
application.
:param json_error_formatter: A Webob exception error formatter.
See Webob for details.
"""
self.application = application
self.service_type = service_type
self.microversion_environ = '%s.microversion' % service_type
self.versions = versions
self.json_error_formatter = json_error_formatter
@webob.dec.wsgify
def __call__(self, req):
try:
microversion = microversion_parse.extract_version(
req.headers, self.service_type, self.versions)
# TODO(cdent): These error response are not formatted according to
# api-sig guidelines, unless a json_error_formatter is provided
# that can do it. For an example, see the placement service.
except ValueError as exc:
raise webob.exc.HTTPNotAcceptable(
('Invalid microversion: %(error)s') % {'error': exc},
json_formatter=self.json_error_formatter)
except TypeError as exc:
raise webob.exc.HTTPBadRequest(
('Invalid microversion: %(error)s') % {'error': exc},
json_formatter=self.json_error_formatter)
req.environ[self.microversion_environ] = microversion
microversion_header = '%s %s' % (self.service_type, microversion)
standard_header = microversion_parse.STANDARD_HEADER
try:
response = req.get_response(self.application)
except webob.exc.HTTPError as exc:
# If there was an HTTPError in the application we still need
# to send the microversion header, so add the header and
# re-raise the exception.
exc.headers.add(standard_header, microversion_header)
raise exc
response.headers.add(standard_header, microversion_header)
response.headers.add('vary', standard_header)
return response