Skip to main content

modo/middleware/
catch_panic.rs

1use std::any::Any;
2
3use axum::response::{IntoResponse, Response};
4use http::StatusCode;
5use tower_http::catch_panic::CatchPanicLayer;
6
7/// Panic handler used internally by [`catch_panic`].
8///
9/// Converts a caught panic into a `500 Internal Server Error` response and
10/// stores a `modo::Error` in the response extensions so that
11/// [`error_handler`](super::error_handler) can rewrite it.
12#[derive(Clone)]
13pub struct ModoPanicHandler;
14
15impl tower_http::catch_panic::ResponseForPanic for ModoPanicHandler {
16    type ResponseBody = axum::body::Body;
17
18    fn response_for_panic(
19        &mut self,
20        _err: Box<dyn Any + Send + 'static>,
21    ) -> Response<Self::ResponseBody> {
22        let error = crate::error::Error::internal("internal server error");
23        let mut response = StatusCode::INTERNAL_SERVER_ERROR.into_response();
24        response.extensions_mut().insert(error);
25        response
26    }
27}
28
29/// Returns a layer that catches panics in handlers and returns a 500 response.
30///
31/// The response includes a `modo::Error` in its extensions for downstream
32/// middleware (such as [`error_handler`](super::error_handler)) to inspect.
33pub fn catch_panic() -> CatchPanicLayer<ModoPanicHandler> {
34    CatchPanicLayer::custom(ModoPanicHandler)
35}