1111
1212from __future__ import annotations
1313
14+ import asyncio
1415import os
1516from typing import Awaitable , Callable
1617
17- from emmett_core .http .response import HTTPResponse
18- from emmett_core .protocols .rsgi .handlers import HTTPHandler as _HTTPHandler , WSHandler as _WSHandler
18+ from emmett_core .http .response import HTTPResponse , HTTPStringResponse
19+ from emmett_core .protocols .rsgi .handlers import HTTPHandler as _HTTPHandler , WSHandler as _WSHandler , WSTransport
1920from emmett_core .utils import cachedprop
20- from granian .rsgi import (
21- HTTPProtocol ,
22- Scope ,
23- )
2421
25- from ..ctx import current
22+ from ..ctx import RequestContext , WSContext , current
2623from ..debug import debug_handler , smart_traceback
2724from ..wrappers .response import Response
2825from .wrappers import Request , Websocket
@@ -37,7 +34,7 @@ class HTTPHandler(_HTTPHandler):
3734 def error_handler (self ) -> Callable [[], Awaitable [str ]]:
3835 return self ._debug_handler if self .app .debug else self .exception_handler
3936
40- def _static_handler (self , scope : Scope , protocol : HTTPProtocol , path : str ) -> Awaitable [HTTPResponse ]:
37+ def _static_handler (self , scope , protocol , path : str ) -> Awaitable [HTTPResponse ]:
4138 #: handle internal assets
4239 if path .startswith ("/__emmett__" ):
4340 file_name = path [12 :]
@@ -57,6 +54,51 @@ async def _debug_handler(self) -> str:
5754 current .response .headers ._data ["content-type" ] = "text/html; charset=utf-8"
5855 return debug_handler (smart_traceback (self .app ))
5956
57+ async def dynamic_handler (self , scope , protocol , path : str ) -> HTTPResponse :
58+ request = Request (
59+ scope ,
60+ path ,
61+ protocol ,
62+ max_content_length = self .app .config .request_max_content_length ,
63+ max_multipart_size = self .app .config .request_multipart_max_size ,
64+ body_timeout = self .app .config .request_body_timeout ,
65+ )
66+ response = Response ()
67+ ctx = RequestContext (self .app , request , response )
68+ ctx_token = current ._init_ (ctx )
69+ try :
70+ http = await self .router .dispatch (request , response )
71+ except HTTPResponse as http_exception :
72+ http = http_exception
73+ #: render error with handlers if in app
74+ error_handler = self .app .error_handlers .get (http .status_code )
75+ if error_handler :
76+ http = HTTPStringResponse (
77+ http .status_code , await error_handler (), headers = response .headers , cookies = response .cookies
78+ )
79+ except Exception :
80+ self .app .log .exception ("Application exception:" )
81+ http = HTTPStringResponse (500 , await self .error_handler (), headers = response .headers )
82+ finally :
83+ current ._close_ (ctx_token )
84+ return http
85+
6086
6187class WSHandler (_WSHandler ):
6288 wrapper_cls = Websocket
89+
90+ async def dynamic_handler (self , scope , transport : WSTransport , path : str ):
91+ ctx = WSContext (self .app , Websocket (scope , path , transport ))
92+ ctx_token = current ._init_ (ctx )
93+ try :
94+ await self .router .dispatch (ctx .websocket )
95+ except HTTPResponse as http :
96+ transport .status = http .status_code
97+ except asyncio .CancelledError :
98+ if not transport .interrupted :
99+ self .app .log .exception ("Application exception:" )
100+ except Exception :
101+ transport .status = 500
102+ self .app .log .exception ("Application exception:" )
103+ finally :
104+ current ._close_ (ctx_token )
0 commit comments