Files
microversion-parse/microversion_parse/middleware.py
Stephen Finucane a3e4d6e9f2 Add ruff
Change-Id: I0a1bfae9996c1d866a200507b59f5c76753a1aca
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
2025-09-11 16:41:15 +01:00

95 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:
"""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 = f'{service_type}.microversion'
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(
(f'Invalid microversion: {exc}'),
json_formatter=self.json_error_formatter,
)
except TypeError as exc:
raise webob.exc.HTTPBadRequest(
(f'Invalid microversion: {exc}'),
json_formatter=self.json_error_formatter,
)
req.environ[self.microversion_environ] = microversion
microversion_header = f'{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