1- import inspect
2- from aikido_zen .context import get_current_context
3- from .functions .asgi_middleware import InternalASGIMiddleware
1+ from aikido_zen .context import Context , get_current_context
2+ from .functions .request_handler import request_handler
43from ..helpers .get_argument import get_argument
5- from ..sinks import on_import , patch_function , before_async , after
4+ from ..sinks import on_import , patch_function , before , before_async
65
76
8- async def _call_coroutine (func , instance , args , kwargs ):
7+ @before
8+ def _call (func , instance , args , kwargs ):
99 scope = get_argument (args , kwargs , 0 , "scope" )
10- receive = get_argument (args , kwargs , 1 , "receive" )
11- send = get_argument (args , kwargs , 2 , "send" )
12-
13- await InternalASGIMiddleware (func , "quart" )(scope , receive , send )
14-
15-
16- @after
17- def _call (func , instance , args , kwargs , return_value ):
18- """
19- Legacy ASGI v2.0
20- func: application(scope)
21- return_value: coroutine application_instance(receive, send)
22- """
23- scope = get_argument (args , kwargs , 0 , "scope" )
24-
25- async def application_instance (receive , send ):
26- await InternalASGIMiddleware (return_value , "quart" )(scope , receive , send )
10+ if not scope or scope .get ("type" ) != "http" :
11+ return
2712
28- # Modify return_value
29- return_value = application_instance
13+ new_context = Context (req = scope , source = "quart" )
14+ new_context .set_as_current_context ()
15+ request_handler (stage = "init" )
3016
3117
3218@before_async
@@ -51,22 +37,60 @@ async def _handle_request_before(func, instance, args, kwargs):
5137 context .set_as_current_context ()
5238
5339
40+ async def _handle_request_after (func , instance , args , kwargs ):
41+ # pylint:disable=import-outside-toplevel # We don't want to install this by default
42+ from werkzeug .exceptions import HTTPException
43+
44+ try :
45+ response = await func (* args , ** kwargs )
46+ if hasattr (response , "status_code" ):
47+ request_handler (stage = "post_response" , status_code = response .status_code )
48+ return response
49+ except HTTPException as e :
50+ request_handler (stage = "post_response" , status_code = e .code )
51+ raise e
52+
53+
54+ async def _asgi_app (func , instance , args , kwargs ):
55+ scope = get_argument (args , kwargs , 0 , "scope" )
56+ if not scope or scope .get ("type" ) != "http" :
57+ return await func (* args , ** kwargs )
58+ send = get_argument (args , kwargs , 2 , "send" )
59+ if not send :
60+ return await func (* args , ** kwargs )
61+
62+ pre_response = request_handler (stage = "pre_response" )
63+ if pre_response :
64+ return await send_status_code_and_text (send , pre_response )
65+ return await func (* args , ** kwargs )
66+
67+
68+ async def send_status_code_and_text (send , pre_response ):
69+ await send (
70+ {
71+ "type" : "http.response.start" ,
72+ "status" : pre_response [1 ],
73+ "headers" : [(b"content-type" , b"text/plain" )],
74+ }
75+ )
76+ await send (
77+ {
78+ "type" : "http.response.body" ,
79+ "body" : pre_response [0 ].encode ("utf-8" ),
80+ "more_body" : False ,
81+ }
82+ )
83+
84+
5485@on_import ("quart.app" , "quart" )
5586def patch (m ):
5687 """
57- We patch Quart.__call__ instead of asgi_app, because asgi_app itself can be wrapped multiple times
58- And we want to be the first middleware to run.
59- - patches Quart.__call__ (handles internal asgi middleware )
60- - patches Quart.handle_request (Stores body/cookies )
88+ patching module quart.app
89+ - patches Quart.__call__ (creates Context)
90+ - patches Quart.handle_request (Stores body/cookies, checks status code )
91+ - patches Quart.asgi_app (Pre-response: puts in messages when request is blocked )
6192 """
62-
63- if inspect .iscoroutine (m .Quart .__call__ ):
64- # coroutine application(scope, receive, send)
65- patch_function (m , "Quart.__call__" , _call_coroutine )
66- else :
67- # Legacy ASGI v2.0
68- # https://asgi.readthedocs.io/en/latest/specs/main.html#legacy-applications
69- # application(scope): coroutine application_instance(receive, send)
70- patch_function (m , "Quart.__call__" , _call )
71-
93+ patch_function (m , "Quart.__call__" , _call )
7294 patch_function (m , "Quart.handle_request" , _handle_request_before )
95+ patch_function (m , "Quart.handle_request" , _handle_request_after )
96+ patch_function (m , "Quart.asgi_app" , _asgi_app )
0 commit comments