use axum::http;
use crate::http::{HttpContext, HttpContextInterface};
use crate::state::State;
#[derive(Debug)]
#[derive(thiserror::Error)]
#[error("\n\t{}: {0}", std::any::type_name::<Self>())]
pub enum HttpContextError {
Extension(#[from] axum::extract::rejection::ExtensionRejection),
Infaillible(#[from] std::convert::Infallible),
MissingExtension,
}
#[axum::async_trait]
impl<C, S> axum::extract::FromRequestParts<State<S>> for HttpContext<C>
where
C: 'static,
C: HttpContextInterface,
S: 'static,
S: Send + Sync,
<C as HttpContextInterface>::State: Send + Sync,
<C as HttpContextInterface>::State: axum::extract::FromRef<State<S>>,
{
type Rejection = HttpContextError;
async fn from_request_parts(
parts: &mut axum::http::request::Parts,
state: &State<S>,
) -> Result<Self, Self::Rejection> {
let axum::extract::State(extracts) = axum::extract::State::<
<C as HttpContextInterface>::State,
>::from_request_parts(parts, state)
.await?;
let context = C::new(&parts.extensions, extracts)
.await
.ok_or(HttpContextError::MissingExtension)?
.shared();
let axum::extract::ConnectInfo(ip) =
axum::extract::ConnectInfo::from_request_parts(parts, state)
.await?;
let method = parts.method.clone();
let axum::extract::OriginalUri(uri) =
axum::extract::OriginalUri::from_request_parts(parts, state)
.await?;
let axum::extract::RawQuery(raw_query) =
axum::extract::RawQuery::from_request_parts(parts, state).await?;
let referer =
axum::TypedHeader::<axum::headers::Referer>::from_request_parts(
parts, state,
)
.await
.map(|ext| ext.0)
.ok();
let request = crate::http::HttpRequest {
context: context.clone(),
ip,
method,
uri,
raw_query,
referer,
};
let response = crate::http::HttpResponse {
context: context.clone(),
};
#[cfg(feature = "cookies")]
{
let cookie_key = state.cookie_key.as_ref().unwrap().clone();
let cookies_manager =
tower_cookies::Cookies::from_request_parts(parts, state)
.await
.expect("Cookies Manager");
let cookies =
crate::http::cookies::Cookies::new(cookies_manager, cookie_key);
let session_handle = parts
.extensions
.get::<axum_sessions::SessionHandle>()
.cloned()
.expect("Impossible d'extraire la session");
Ok(Self {
context,
request,
response,
cookies,
session: crate::http::context::SessionContext {
handle: session_handle,
},
})
}
#[cfg(not(feature = "cookies"))]
{
Ok(Self {
context,
request,
response,
})
}
}
}
impl axum::response::IntoResponse for HttpContextError {
fn into_response(self) -> axum::response::Response {
let err_status = http::StatusCode::INTERNAL_SERVER_ERROR;
let err_body = self.to_string();
(err_status, err_body).into_response()
}
}