GIT-37: fix blueprint middleware application (#1690)

* GIT-37: fix blueprint middleware application

1. If you register a middleware via `@blueprint.middleware` then it will apply only to the routes defined by the blueprint.
2. If you register a middleware via `@blueprint_group.middleware` then it will apply to all blueprint based routes that are part of the group.
3. If you define a middleware via `@app.middleware` then it will be applied on all available routes

Fixes #37

Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>

* GIT-37: add changelog

Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
This commit is contained in:
Harsha Narayana
2019-12-20 21:31:05 +05:30
committed by Stephen Sadowski
parent 179a07942e
commit a6077a1790
7 changed files with 91 additions and 34 deletions

View File

@@ -85,7 +85,8 @@ class Sanic:
self.is_request_stream = False
self.websocket_enabled = False
self.websocket_tasks = set()
self.named_request_middleware = {}
self.named_response_middleware = {}
# Register alternative method names
self.go_fast = self.run
@@ -178,7 +179,7 @@ class Sanic:
:param stream:
:param version:
:param name: user defined route name for url_for
:return: decorated function
:return: tuple of routes, decorated function
"""
# Fix case where the user did not prefix the URL with a /
@@ -204,7 +205,7 @@ class Sanic:
if stream:
handler.is_stream = stream
self.router.add(
routes = self.router.add(
uri=uri,
methods=methods,
handler=handler,
@@ -213,7 +214,7 @@ class Sanic:
version=version,
name=name,
)
return handler
return routes, handler
return response
@@ -462,7 +463,7 @@ class Sanic:
:param subprotocols: optional list of str with supported subprotocols
:param name: A unique name assigned to the URL so that it can
be used with :func:`url_for`
:return: decorated function
:return: tuple of routes, decorated function
"""
self.enable_websocket()
@@ -515,7 +516,7 @@ class Sanic:
self.websocket_tasks.remove(fut)
await ws.close()
self.router.add(
routes = self.router.add(
uri=uri,
handler=websocket_handler,
methods=frozenset({"GET"}),
@@ -523,7 +524,7 @@ class Sanic:
strict_slashes=strict_slashes,
name=name,
)
return handler
return routes, handler
return response
@@ -544,6 +545,7 @@ class Sanic:
:param host: Host IP or FQDN details
:param uri: URL path that will be mapped to the websocket
handler
handler
:param strict_slashes: If the API endpoint needs to terminate
with a "/" or not
:param subprotocols: Subprotocols to be used with websocket
@@ -645,6 +647,22 @@ class Sanic:
self.response_middleware.appendleft(middleware)
return middleware
def register_named_middleware(
self, middleware, route_names, attach_to="request"
):
if attach_to == "request":
for _rn in route_names:
if _rn not in self.named_request_middleware:
self.named_request_middleware[_rn] = deque()
if middleware not in self.named_request_middleware[_rn]:
self.named_request_middleware[_rn].append(middleware)
if attach_to == "response":
for _rn in route_names:
if _rn not in self.named_response_middleware:
self.named_response_middleware[_rn] = deque()
if middleware not in self.named_response_middleware[_rn]:
self.named_response_middleware[_rn].append(middleware)
# Decorator
def middleware(self, middleware_or_request):
"""
@@ -916,20 +934,23 @@ class Sanic:
# allocation before assignment below.
response = None
cancelled = False
name = None
try:
# Fetch handler from router
handler, args, kwargs, uri, name = self.router.get(request)
# -------------------------------------------- #
# Request Middleware
# -------------------------------------------- #
response = await self._run_request_middleware(request)
response = await self._run_request_middleware(
request, request_name=name
)
# No middleware results
if not response:
# -------------------------------------------- #
# Execute Handler
# -------------------------------------------- #
# Fetch handler from router
handler, args, kwargs, uri = self.router.get(request)
request.uri_template = uri
if handler is None:
raise ServerError(
@@ -993,7 +1014,7 @@ class Sanic:
if response is not None:
try:
response = await self._run_response_middleware(
request, response
request, response, request_name=name
)
except CancelledError:
# Response middleware can timeout too, as above.
@@ -1265,10 +1286,14 @@ class Sanic:
if isawaitable(result):
await result
async def _run_request_middleware(self, request):
async def _run_request_middleware(self, request, request_name=None):
# The if improves speed. I don't know why
if self.request_middleware:
for middleware in self.request_middleware:
named_middleware = self.named_request_middleware.get(
request_name, deque()
)
applicable_middleware = self.request_middleware + named_middleware
if applicable_middleware:
for middleware in applicable_middleware:
response = middleware(request)
if isawaitable(response):
response = await response
@@ -1276,9 +1301,15 @@ class Sanic:
return response
return None
async def _run_response_middleware(self, request, response):
if self.response_middleware:
for middleware in self.response_middleware:
async def _run_response_middleware(
self, request, response, request_name=None
):
named_middleware = self.named_response_middleware.get(
request_name, deque()
)
applicable_middleware = self.response_middleware + named_middleware
if applicable_middleware:
for middleware in applicable_middleware:
_response = middleware(request, response)
if isawaitable(_response):
_response = await _response