25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

74 satır
2.7 KiB

  1. from __future__ import annotations
  2. from collections.abc import Mapping
  3. from typing import Any
  4. from starlette._exception_handler import (
  5. ExceptionHandlers,
  6. StatusHandlers,
  7. wrap_app_handling_exceptions,
  8. )
  9. from starlette.exceptions import HTTPException, WebSocketException
  10. from starlette.requests import Request
  11. from starlette.responses import PlainTextResponse, Response
  12. from starlette.types import ASGIApp, ExceptionHandler, Receive, Scope, Send
  13. from starlette.websockets import WebSocket
  14. class ExceptionMiddleware:
  15. def __init__(
  16. self,
  17. app: ASGIApp,
  18. handlers: Mapping[Any, ExceptionHandler] | None = None,
  19. debug: bool = False,
  20. ) -> None:
  21. self.app = app
  22. self.debug = debug # TODO: We ought to handle 404 cases if debug is set.
  23. self._status_handlers: StatusHandlers = {}
  24. self._exception_handlers: ExceptionHandlers = {
  25. HTTPException: self.http_exception,
  26. WebSocketException: self.websocket_exception,
  27. }
  28. if handlers is not None: # pragma: no branch
  29. for key, value in handlers.items():
  30. self.add_exception_handler(key, value)
  31. def add_exception_handler(
  32. self,
  33. exc_class_or_status_code: int | type[Exception],
  34. handler: ExceptionHandler,
  35. ) -> None:
  36. if isinstance(exc_class_or_status_code, int):
  37. self._status_handlers[exc_class_or_status_code] = handler
  38. else:
  39. assert issubclass(exc_class_or_status_code, Exception)
  40. self._exception_handlers[exc_class_or_status_code] = handler
  41. async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
  42. if scope["type"] not in ("http", "websocket"):
  43. await self.app(scope, receive, send)
  44. return
  45. scope["starlette.exception_handlers"] = (
  46. self._exception_handlers,
  47. self._status_handlers,
  48. )
  49. conn: Request | WebSocket
  50. if scope["type"] == "http":
  51. conn = Request(scope, receive, send)
  52. else:
  53. conn = WebSocket(scope, receive, send)
  54. await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  55. async def http_exception(self, request: Request, exc: Exception) -> Response:
  56. assert isinstance(exc, HTTPException)
  57. if exc.status_code in {204, 304}:
  58. return Response(status_code=exc.status_code, headers=exc.headers)
  59. return PlainTextResponse(exc.detail, status_code=exc.status_code, headers=exc.headers)
  60. async def websocket_exception(self, websocket: WebSocket, exc: Exception) -> None:
  61. assert isinstance(exc, WebSocketException)
  62. await websocket.close(code=exc.code, reason=exc.reason) # pragma: no cover