#![allow(clippy::unused_async, reason = "Middleware functions need to be async")]
use axum::{
body::Body,
http::{Request, StatusCode},
middleware::Next,
response::{Html, IntoResponse, Response},
};
use rubedo::http::UnpackedResponseBody;
use tracing::error;
#[cfg(feature = "tera")]
use crate::app::{
errors::AppError,
state::StateProvider as AppStateProvider,
};
#[cfg(feature = "tera")]
use ::{
axum::{
extract::State,
http::HeaderValue,
},
std::sync::Arc,
tera::Context as Template,
};
pub async fn no_route() -> impl IntoResponse {
(
StatusCode::NOT_FOUND,
[
("protected", "protected"),
],
).into_response()
}
#[cfg(feature = "tera")]
pub async fn graceful_error_layer<SP>(
State(state): State<Arc<SP>>,
request: Request<Body>,
next: Next,
) -> Result<Response, AppError>
where
SP: AppStateProvider,
{
let response = next.run(request).await;
let (mut parts, body) = response.into_parts();
Ok(match parts.status {
StatusCode::NOT_FOUND => {
drop(parts.headers.remove("content-length"));
drop(parts.headers.remove("content-type"));
let mut template = Template::new();
template.insert("Title", &state.title());
(
parts,
Html(state.render("404-notfound", &template).await?),
).into_response()
},
StatusCode::INTERNAL_SERVER_ERROR => {
error!("Internal server error: {}", UnpackedResponseBody::from(body));
let mut template = Template::new();
template.insert("Title", &state.title());
drop(parts.headers.remove("content-length"));
drop(parts.headers.remove("content-type"));
drop(parts.headers.insert("error-handled", HeaderValue::from_static("gracefully")));
(
parts,
Html(state.render("500-error", &template).await?),
).into_response()
},
_ => {
(
parts,
body,
).into_response()
},
})
}
pub async fn final_error_layer(
request: Request<Body>,
next: Next,
) -> Response {
let response = next.run(request).await;
match response.status() {
StatusCode::INTERNAL_SERVER_ERROR => {
let (mut parts, body) = response.into_parts();
if parts.headers.contains_key("error-handled") {
drop(parts.headers.remove("error-handled"));
return (parts, body).into_response();
}
error!("Internal server error: {}", UnpackedResponseBody::from(body));
drop(parts.headers.remove("content-length"));
drop(parts.headers.remove("content-type"));
(
parts,
Html(r"<h1>Internal server error</h1>"),
).into_response()
},
_ => response,
}
}