2015-01-06 12:04:31 -05:00
|
|
|
# Copyright 2011 OpenStack Foundation.
|
|
|
|
# All Rights Reserved.
|
|
|
|
#
|
|
|
|
# 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.
|
|
|
|
|
|
|
|
"""Base class(es) for WSGI Middleware."""
|
|
|
|
|
2020-05-05 13:00:00 -05:00
|
|
|
from inspect import getfullargspec
|
2019-03-06 22:31:48 +08:00
|
|
|
from oslo_config import cfg
|
2015-01-06 12:04:31 -05:00
|
|
|
import webob.dec
|
2016-05-10 17:05:24 +02:00
|
|
|
import webob.request
|
|
|
|
import webob.response
|
2015-01-06 12:04:31 -05:00
|
|
|
|
|
|
|
|
2016-05-10 17:05:24 +02:00
|
|
|
class NoContentTypeResponse(webob.response.Response):
|
|
|
|
|
|
|
|
default_content_type = None # prevents webob assigning content type
|
|
|
|
|
|
|
|
|
|
|
|
class NoContentTypeRequest(webob.request.Request):
|
|
|
|
|
|
|
|
ResponseClass = NoContentTypeResponse
|
|
|
|
|
|
|
|
|
2015-08-20 07:52:59 +02:00
|
|
|
class ConfigurableMiddleware(object):
|
2015-01-06 12:04:31 -05:00
|
|
|
"""Base WSGI middleware wrapper.
|
|
|
|
|
|
|
|
These classes require an application to be initialized that will be called
|
|
|
|
next. By default the middleware will simply call its wrapped app, or you
|
|
|
|
can override __call__ to customize its behavior.
|
|
|
|
"""
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def factory(cls, global_conf, **local_conf):
|
2015-08-20 11:02:44 +02:00
|
|
|
"""Factory method for paste.deploy.
|
|
|
|
|
|
|
|
:param global_conf: dict of options for all middlewares
|
|
|
|
(usually the [DEFAULT] section of the paste deploy
|
|
|
|
configuration file)
|
|
|
|
:param local_conf: options dedicated to this middleware
|
|
|
|
(usually the option defined in the middleware
|
|
|
|
section of the paste deploy configuration file)
|
|
|
|
"""
|
2015-08-06 09:15:57 +02:00
|
|
|
conf = global_conf.copy() if global_conf else {}
|
|
|
|
conf.update(local_conf)
|
|
|
|
|
|
|
|
def middleware_filter(app):
|
|
|
|
return cls(app, conf)
|
2015-01-06 12:04:31 -05:00
|
|
|
|
2015-08-06 09:15:57 +02:00
|
|
|
return middleware_filter
|
|
|
|
|
|
|
|
def __init__(self, application, conf=None):
|
2015-08-20 07:52:59 +02:00
|
|
|
"""Base middleware constructor
|
|
|
|
|
|
|
|
:param conf: a dict of options or a cfg.ConfigOpts object
|
|
|
|
"""
|
2015-01-06 12:04:31 -05:00
|
|
|
self.application = application
|
2015-08-20 07:52:59 +02:00
|
|
|
|
2015-08-06 09:15:57 +02:00
|
|
|
# NOTE(sileht): If the configuration come from oslo.config
|
|
|
|
# just use it.
|
|
|
|
if isinstance(conf, cfg.ConfigOpts):
|
2015-08-20 07:52:59 +02:00
|
|
|
self.conf = {}
|
2015-08-06 09:15:57 +02:00
|
|
|
self.oslo_conf = conf
|
|
|
|
else:
|
2015-08-20 07:52:59 +02:00
|
|
|
self.conf = conf or {}
|
2015-08-06 09:15:57 +02:00
|
|
|
if "oslo_config_project" in self.conf:
|
|
|
|
if 'oslo_config_file' in self.conf:
|
|
|
|
default_config_files = [self.conf['oslo_config_file']]
|
|
|
|
else:
|
|
|
|
default_config_files = None
|
2015-11-13 15:00:48 -08:00
|
|
|
|
|
|
|
if 'oslo_config_program' in self.conf:
|
|
|
|
program = self.conf['oslo_config_program']
|
|
|
|
else:
|
|
|
|
program = None
|
|
|
|
|
2015-08-06 09:15:57 +02:00
|
|
|
self.oslo_conf = cfg.ConfigOpts()
|
2015-11-13 15:00:48 -08:00
|
|
|
self.oslo_conf([],
|
|
|
|
project=self.conf['oslo_config_project'],
|
|
|
|
prog=program,
|
2015-08-06 09:15:57 +02:00
|
|
|
default_config_files=default_config_files,
|
|
|
|
validate_default_values=True)
|
|
|
|
|
|
|
|
else:
|
|
|
|
# Fallback to global object
|
|
|
|
self.oslo_conf = cfg.CONF
|
2015-01-06 12:04:31 -05:00
|
|
|
|
2015-08-06 10:53:48 +02:00
|
|
|
def _conf_get(self, key, group="oslo_middleware"):
|
|
|
|
if key in self.conf:
|
|
|
|
# Validate value type
|
2017-05-31 14:50:20 +08:00
|
|
|
self.oslo_conf.set_override(key, self.conf[key], group=group)
|
2015-08-06 10:53:48 +02:00
|
|
|
return getattr(getattr(self.oslo_conf, group), key)
|
|
|
|
|
2015-08-07 11:01:59 +02:00
|
|
|
@staticmethod
|
|
|
|
def process_request(req):
|
2015-01-06 12:04:31 -05:00
|
|
|
"""Called on each request.
|
|
|
|
|
|
|
|
If this returns None, the next application down the stack will be
|
|
|
|
executed. If it returns a response then that response will be returned
|
|
|
|
and execution will stop here.
|
|
|
|
"""
|
|
|
|
return None
|
|
|
|
|
2015-08-07 11:01:59 +02:00
|
|
|
@staticmethod
|
|
|
|
def process_response(response, request=None):
|
2015-01-06 12:04:31 -05:00
|
|
|
"""Do whatever you'd like to the response."""
|
|
|
|
return response
|
|
|
|
|
2016-05-10 17:05:24 +02:00
|
|
|
@webob.dec.wsgify(RequestClass=NoContentTypeRequest)
|
2015-01-06 12:04:31 -05:00
|
|
|
def __call__(self, req):
|
|
|
|
response = self.process_request(req)
|
|
|
|
if response:
|
|
|
|
return response
|
|
|
|
response = req.get_response(self.application)
|
2015-06-11 11:35:19 -07:00
|
|
|
|
2017-06-19 14:46:15 -04:00
|
|
|
args = getfullargspec(self.process_response)[0]
|
2015-06-11 11:35:19 -07:00
|
|
|
if 'request' in args:
|
|
|
|
return self.process_response(response, request=req)
|
2015-01-06 12:04:31 -05:00
|
|
|
return self.process_response(response)
|
2015-08-20 07:52:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Middleware(ConfigurableMiddleware):
|
|
|
|
"""Legacy base WSGI middleware wrapper.
|
|
|
|
|
|
|
|
Legacy interface that doesn't pass configuration options
|
|
|
|
to the middleware when it's loaded via paste.deploy.
|
|
|
|
"""
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def factory(cls, global_conf, **local_conf):
|
|
|
|
"""Factory method for paste.deploy."""
|
|
|
|
return cls
|