Skip to content

Commit c800cf8

Browse files
committed
Add missing overrides in protos' dynamic handlers
1 parent e4d0251 commit c800cf8

File tree

2 files changed

+99
-11
lines changed

2 files changed

+99
-11
lines changed

emmett/asgi/handlers.py

+49-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
from importlib import resources
1616
from typing import Awaitable, Callable
1717

18-
from emmett_core.http.response import HTTPBytesResponse, HTTPResponse
19-
from emmett_core.protocols.asgi.handlers import HTTPHandler as _HTTPHandler, WSHandler as _WSHandler
18+
from emmett_core.http.response import HTTPBytesResponse, HTTPResponse, HTTPStringResponse
19+
from emmett_core.protocols.asgi.handlers import HTTPHandler as _HTTPHandler, RequestCancelled, WSHandler as _WSHandler
2020
from emmett_core.protocols.asgi.typing import Receive, Scope, Send
2121
from emmett_core.utils import cachedprop
2222

23-
from ..ctx import current
23+
from ..ctx import RequestContext, WSContext, current
2424
from ..debug import debug_handler, smart_traceback
2525
from ..libs.contenttype import contenttype
2626
from ..wrappers.response import Response
@@ -70,7 +70,53 @@ async def _debug_handler(self) -> str:
7070
current.response.headers._data["content-type"] = "text/html; charset=utf-8"
7171
return debug_handler(smart_traceback(self.app))
7272

73+
async def dynamic_handler(self, scope: Scope, receive: Receive, send: Send) -> HTTPResponse:
74+
request = Request(
75+
scope,
76+
receive,
77+
send,
78+
max_content_length=self.app.config.request_max_content_length,
79+
max_multipart_size=self.app.config.request_multipart_max_size,
80+
body_timeout=self.app.config.request_body_timeout,
81+
)
82+
response = Response()
83+
ctx = RequestContext(self.app, request, response)
84+
ctx_token = current._init_(ctx)
85+
try:
86+
http = await self.router.dispatch(request, response)
87+
except HTTPResponse as http_exception:
88+
http = http_exception
89+
#: render error with handlers if in app
90+
error_handler = self.app.error_handlers.get(http.status_code)
91+
if error_handler:
92+
http = HTTPStringResponse(
93+
http.status_code, await error_handler(), headers=response.headers, cookies=response.cookies
94+
)
95+
except RequestCancelled:
96+
raise
97+
except Exception:
98+
self.app.log.exception("Application exception:")
99+
http = HTTPStringResponse(500, await self.error_handler(), headers=response.headers)
100+
finally:
101+
current._close_(ctx_token)
102+
return http
103+
104+
async def _exception_handler(self) -> str:
105+
current.response.headers._data["content-type"] = "text/plain"
106+
return "Internal error"
107+
73108

74109
class WSHandler(_WSHandler):
75110
__slots__ = []
76111
wrapper_cls = Websocket
112+
113+
async def dynamic_handler(self, scope: Scope, send: Send):
114+
ctx = WSContext(self.app, Websocket(scope, scope["emt.input"].get, send))
115+
ctx_token = current._init_(ctx)
116+
try:
117+
await self.router.dispatch(ctx.websocket)
118+
finally:
119+
if not scope.get("emt._flow_cancel", False) and ctx.websocket._accepted:
120+
await send({"type": "websocket.close", "code": 1000})
121+
scope["emt._ws_closed"] = True
122+
current._close_(ctx_token)

emmett/rsgi/handlers.py

+50-8
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,15 @@
1111

1212
from __future__ import annotations
1313

14+
import asyncio
1415
import os
1516
from 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
1920
from 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
2623
from ..debug import debug_handler, smart_traceback
2724
from ..wrappers.response import Response
2825
from .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

6187
class 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

Comments
 (0)