ruts/extract/
mod.rs

1use std::sync::Arc;
2
3use axum_core::extract::FromRequestParts;
4use http::{StatusCode, request::Parts};
5use tower_cookies::Cookies;
6
7use crate::session::Inner;
8use crate::store::SessionStore;
9use crate::{Id, Session};
10
11/// axum extractor for [`Session`].
12impl<S, T> FromRequestParts<S> for Session<T>
13where
14    S: Sync + Send,
15    T: SessionStore,
16{
17    type Rejection = (StatusCode, &'static str);
18
19    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
20        let session_inner = parts.extensions.get::<Arc<Inner<T>>>().ok_or_else(|| {
21            tracing::error!("session layer not found in the request extensions");
22            (
23                StatusCode::INTERNAL_SERVER_ERROR,
24                "Session not found in the request",
25            )
26        })?;
27
28        // Cookies are only used if the SessionLayer has a cookie_options set.
29        let cookie_name = session_inner
30            .cookie_name
31            .ok_or((StatusCode::INTERNAL_SERVER_ERROR, "Missing cookie options"))?;
32
33        let cookies_ext = parts.extensions.get::<Cookies>().ok_or_else(|| {
34            tracing::error!("cookies not found in the request extensions");
35            (
36                StatusCode::INTERNAL_SERVER_ERROR,
37                "Cookies not found in the request",
38            )
39        })?;
40
41        session_inner.set_cookies_if_empty(cookies_ext.to_owned());
42
43        if let Some(cookie) = cookies_ext.get(cookie_name) {
44            let session_id = cookie
45                .value()
46                .parse::<Id>()
47                .map_err(|err| {
48                    tracing::warn!(
49                        err = %err,
50                        "malformed session id"
51                    )
52                })
53                .ok();
54            session_inner.set_id(session_id);
55        }
56
57        Ok(Session::new(session_inner.clone()))
58    }
59}