def prepare_middleware(middleware=None): """Check middleware interface and prepare it to iterate. Args: middleware: list (or object) of input middleware Returns: A middleware list """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. prepared_middleware = [] if middleware is None: middleware = [] else: if not isinstance(middleware, list): middleware = [middleware] for component in middleware: process_request = util.get_bound_method(component, "process_request") process_resource = util.get_bound_method(component, "process_resource") process_response = util.get_bound_method(component, "process_response") if not (process_request or process_resource or process_response): msg = "{0} does not implement the middleware interface" raise TypeError(msg.format(component)) prepared_middleware.append((process_request, process_resource, process_response)) return prepared_middleware
def prepare_middleware(middleware=None): """Check middleware interface and prepare it to iterate. Args: middleware: list (or object) of input middleware Returns: A middleware list """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. prepared_middleware = [] if middleware is None: middleware = [] else: if not isinstance(middleware, list): middleware = [middleware] for component in middleware: process_request = util.get_bound_method(component, 'process_request') process_resource = util.get_bound_method(component, 'process_resource') process_response = util.get_bound_method(component, 'process_response') if not (process_request or process_resource or process_response): msg = '{0} does not implement the middleware interface' raise TypeError(msg.format(component)) prepared_middleware.append( (process_request, process_resource, process_response)) return prepared_middleware
def prepare_middleware(middleware=None, independent_middleware=False): """Check middleware interface and prepare it to iterate. Args: middleware: list (or object) of input middleware independent_middleware: bool whether should prepare request and response middleware independently Returns: list: A tuple of prepared middleware tuples """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. request_mw = [] resource_mw = [] response_mw = [] if middleware is None: middleware = [] else: if not isinstance(middleware, list): middleware = [middleware] for component in middleware: process_request = util.get_bound_method(component, 'process_request') process_resource = util.get_bound_method(component, 'process_resource') process_response = util.get_bound_method(component, 'process_response') if not (process_request or process_resource or process_response): msg = '{0} does not implement the middleware interface' raise TypeError(msg.format(component)) # NOTE: depending on whether we want to execute middleware # independently, we group response and request middleware either # together or separately. if independent_middleware: if process_request: request_mw.append(process_request) if process_response: response_mw.insert(0, process_response) else: if process_request or process_response: request_mw.append((process_request, process_response)) if process_resource: resource_mw.append(process_resource) return (tuple(request_mw), tuple(resource_mw), tuple(response_mw))
def add_middleware(self, mw): process_request = util.get_bound_method(mw, 'process_request') process_resource = util.get_bound_method(mw, 'process_resource') process_response = util.get_bound_method(mw, 'process_response') if process_request: self.req_mw.append(process_request) if process_resource: self.resc_mw.append(process_resource) if process_response: self.resp_mw.append(process_response)
def prepare_middleware(middleware=None): """Check middleware interface and prepare it to iterate. Args: middleware: list (or object) of input middleware Returns: list: A list of prepared middleware tuples """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. prepared_middleware = [] if middleware is None: middleware = [] else: if not isinstance(middleware, list): middleware = [middleware] for component in middleware: process_request = util.get_bound_method(component, 'process_request') process_resource = util.get_bound_method(component, 'process_resource') process_response = util.get_bound_method(component, 'process_response') if not (process_request or process_resource or process_response): msg = '{0} does not implement the middleware interface' raise TypeError(msg.format(component)) if process_response: # NOTE(kgriffs): Shim older implementations to ensure # backwards-compatibility. args = util.get_argnames(process_response) if len(args) == 3: # (req, resp, resource) def let(process_response=process_response): @wraps(process_response) def shim(req, resp, resource, req_succeeded): process_response(req, resp, resource) return shim process_response = let() prepared_middleware.append((process_request, process_resource, process_response)) return prepared_middleware
def prepare_middleware_ws(middleware): """Check middleware interfaces and prepare WebSocket methods for request handling. Note: This method is only applicable to ASGI apps. Arguments: middleware (iterable): An iterable of middleware objects. Returns: tuple: A two-item ``(request_mw, resource_mw)`` tuple, where *request_mw* is an ordered list of ``process_request_ws()`` methods, and *resource_mw* is an ordered list of ``process_resource_ws()`` methods. """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. request_mw = [] resource_mw = [] for component in middleware: process_request_ws = util.get_bound_method(component, 'process_request_ws') process_resource_ws = util.get_bound_method(component, 'process_resource_ws') for m in (process_request_ws, process_resource_ws): if not m: continue # NOTE(kgriffs): iscoroutinefunction() always returns False # for cythonized functions. # # https://github.com/cython/cython/issues/2273 # https://bugs.python.org/issue38225 # if not iscoroutinefunction(m) and util.is_python_func(m): msg = '{} must be implemented as an awaitable coroutine.' raise CompatibilityError(msg.format(m)) if process_request_ws: request_mw.append(process_request_ws) if process_resource_ws: resource_mw.append(process_resource_ws) return request_mw, resource_mw
def prepare_middleware(middleware, independent_middleware=False, asgi=False): """Check middleware interfaces and prepare the methods for request handling. Arguments: middleware (iterable): An iterable of middleware objects. Keyword Args: independent_middleware (bool): ``True`` if the request and response middleware methods should be treated independently (default ``False``) asgi (bool): ``True`` if an ASGI app, ``False`` otherwise (default ``False``) Returns: tuple: A tuple of prepared middleware method tuples """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. request_mw = [] resource_mw = [] response_mw = [] for component in middleware: # NOTE(kgriffs): Middleware that uses parts of the Request and Response # interfaces that are the same between ASGI and WSGI (most of it is, # and we should probably define this via ABC) can just implement # the method names without the *_async postfix. If a middleware # component wants to provide an alternative implementation that # does some work that requires async def, or something specific about # the ASGI Request/Response classes, the component can implement the # *_async method in that case. # # Middleware that is WSGI-only or ASGI-only can simply implement all # methods without the *_async postfix. Regardless, components should # clearly document their compatibility with WSGI vs. ASGI. if asgi: process_request = ( util.get_bound_method(component, 'process_request_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_request') ) ) process_resource = ( util.get_bound_method(component, 'process_resource_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_resource') ) ) process_response = ( util.get_bound_method(component, 'process_response_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_response') ) ) for m in (process_request, process_resource, process_response): if m and not iscoroutinefunction(m): msg = ( '{} must be implemented as an awaitable coroutine. If ' 'you would like to retain compatibility ' 'with WSGI apps, the coroutine versions of the ' 'middleware methods may be implemented side-by-side ' 'by applying an *_async postfix to the method names. ' ) raise CompatibilityError(msg.format(m)) else: process_request = util.get_bound_method(component, 'process_request') process_resource = util.get_bound_method(component, 'process_resource') process_response = util.get_bound_method(component, 'process_response') for m in (process_request, process_resource, process_response): if m and iscoroutinefunction(m): msg = ( '{} may not implement coroutine methods and ' 'remain compatible with WSGI apps without ' 'using the *_async postfix to explicitly identify ' 'the coroutine version of a given middleware ' 'method.' ) raise CompatibilityError(msg.format(component)) if not (process_request or process_resource or process_response): if asgi and ( hasattr(component, 'process_startup') or hasattr(component, 'process_shutdown') ): # NOTE(kgriffs): This middleware only has ASGI lifespan # event handlers continue msg = '{0} must implement at least one middleware method' raise TypeError(msg.format(component)) # NOTE: depending on whether we want to execute middleware # independently, we group response and request middleware either # together or separately. if independent_middleware: if process_request: request_mw.append(process_request) if process_response: response_mw.insert(0, process_response) else: if process_request or process_response: request_mw.append((process_request, process_response)) if process_resource: resource_mw.append(process_resource) return (tuple(request_mw), tuple(resource_mw), tuple(response_mw))
def prepare_middleware(middleware, independent_middleware=False, asgi=False): """Check middleware interfaces and prepare the methods for request handling. Arguments: middleware (iterable): An iterable of middleware objects. Keyword Args: independent_middleware (bool): ``True`` if the request and response middleware methods should be treated independently (default ``False``) asgi (bool): ``True`` if an ASGI app, ``False`` otherwise (default ``False``) Returns: tuple: A tuple of prepared middleware method tuples """ # PERF(kgriffs): do getattr calls once, in advance, so we don't # have to do them every time in the request path. request_mw = [] resource_mw = [] response_mw = [] for component in middleware: # NOTE(kgriffs): Middleware that supports both WSGI and ASGI can # append an *_async postfix to the ASGI version of the method # to distinguish the two. Otherwise, the prefix is unnecessary. if asgi: process_request = ( util.get_bound_method(component, 'process_request_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_request'))) process_resource = ( util.get_bound_method(component, 'process_resource_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_resource'))) process_response = ( util.get_bound_method(component, 'process_response_async') or _wrap_non_coroutine_unsafe( util.get_bound_method(component, 'process_response'))) for m in (process_request, process_resource, process_response): # NOTE(kgriffs): iscoroutinefunction() always returns False # for cythonized functions. # # https://github.com/cython/cython/issues/2273 # https://bugs.python.org/issue38225 # if m and not iscoroutinefunction(m) and util.is_python_func(m): msg = ( '{} must be implemented as an awaitable coroutine. If ' 'you would like to retain compatibility ' 'with WSGI apps, the coroutine versions of the ' 'middleware methods may be implemented side-by-side ' 'by applying an *_async postfix to the method names. ') raise CompatibilityError(msg.format(m)) else: process_request = util.get_bound_method(component, 'process_request') process_resource = util.get_bound_method(component, 'process_resource') process_response = util.get_bound_method(component, 'process_response') for m in (process_request, process_resource, process_response): if m and iscoroutinefunction(m): msg = ('{} may not implement coroutine methods and ' 'remain compatible with WSGI apps without ' 'using the *_async postfix to explicitly identify ' 'the coroutine version of a given middleware ' 'method.') raise CompatibilityError(msg.format(component)) if not (process_request or process_resource or process_response): if asgi and (hasattr(component, 'process_startup') or hasattr(component, 'process_shutdown')): # NOTE(kgriffs): This middleware only has ASGI lifespan # event handlers continue msg = '{0} must implement at least one middleware method' raise TypeError(msg.format(component)) # NOTE: depending on whether we want to execute middleware # independently, we group response and request middleware either # together or separately. if independent_middleware: if process_request: request_mw.append(process_request) if process_response: response_mw.insert(0, process_response) else: if process_request or process_response: request_mw.append((process_request, process_response)) if process_resource: resource_mw.append(process_resource) return (tuple(request_mw), tuple(resource_mw), tuple(response_mw))