Fix SessionHttpContext to delegate attributes via __getattr__

The previous implementation eagerly copied ASGI-specific attributes
(pathsend, receive, send) from the wrapped context, which crashed under
RSGI because RsgiContext does not have those attributes. Now
SessionHttpContext delegates all non-overridden attributes to the wrapped
context via __getattr__, making it protocol-agnostic.
This commit is contained in:
2026-07-23 22:09:59 +08:00
parent 3ebf079533
commit 65f1b79ce8
@@ -15,6 +15,10 @@ class SessionHttpContext(HttpContext):
Works with any concrete ``HttpContext`` (ASGI or RSGI) because it only Works with any concrete ``HttpContext`` (ASGI or RSGI) because it only
relies on the abstract send methods, which all implementations share. relies on the abstract send methods, which all implementations share.
Attributes not explicitly overridden are delegated to the wrapped context
via ``__getattr__``, so protocol-specific fields (``pathsend``,
``receive``/``send`` for ASGI, ``protocol`` for RSGI, etc.) are passed
through transparently.
""" """
def __init__( def __init__(
@@ -23,20 +27,14 @@ class SessionHttpContext(HttpContext):
session: Session, session: Session,
cookie_injector: Callable[[], Optional[str]], cookie_injector: Callable[[], Optional[str]],
) -> None: ) -> None:
self._ctx = ctx object.__setattr__(self, '_ctx', ctx)
self.session = session object.__setattr__(self, 'session', session)
self._cookie_injector = cookie_injector object.__setattr__(self, '_cookie_injector', cookie_injector)
self.pathsend = ctx.pathsend
self.receive = ctx.receive def __getattr__(self, name: str) -> Any:
self.send = ctx.send if name == '_ctx':
self.scheme = ctx.scheme raise AttributeError(name)
self.method = ctx.method return getattr(self._ctx, name)
self.path = ctx.path
self.query_string = ctx.query_string
self.headers = ctx.headers
self.client = ctx.client
self.server = ctx.server
self.request_body = ctx.request_body
def _inject_cookie(self, headers: Optional[Mapping[str, StrOrStrings]]) -> Optional[Mapping[str, StrOrStrings]]: def _inject_cookie(self, headers: Optional[Mapping[str, StrOrStrings]]) -> Optional[Mapping[str, StrOrStrings]]:
cookie_value = self._cookie_injector() cookie_value = self._cookie_injector()