cja/server/cookies/
cookie_jar.rs

1use axum::{
2    extract::FromRequestParts,
3    http::request::Parts,
4    response::{IntoResponse as _, Response},
5};
6use http::StatusCode;
7use tracing::error;
8
9use crate::app_state::AppState;
10
11pub struct CookieJar<AS> {
12    cookies: tower_cookies::Cookies,
13    state: AS,
14}
15
16impl<A> FromRequestParts<A> for CookieJar<A>
17where
18    A: Send + Sync,
19    A: AppState,
20{
21    type Rejection = Response;
22
23    async fn from_request_parts(parts: &mut Parts, state: &A) -> Result<Self, Self::Rejection> {
24        let Ok(cookies) = tower_cookies::Cookies::from_request_parts(parts, state).await else {
25            error!("Failed to extract cookies from request");
26            return Err(StatusCode::INTERNAL_SERVER_ERROR.into_response());
27        };
28
29        Ok(CookieJar {
30            cookies,
31            state: state.clone(),
32        })
33    }
34}
35
36impl<AS> CookieJar<AS>
37where
38    AS: AppState,
39{
40    /// Add a new private cookie
41    pub fn add(&self, cookie: tower_cookies::Cookie<'static>) {
42        let private = self.cookies.private(self.state.cookie_key());
43        private.add(cookie);
44    }
45
46    /// Get a private cookie by name
47    pub fn get(&self, name: &str) -> Option<tower_cookies::Cookie<'static>> {
48        let private = self.cookies.private(self.state.cookie_key());
49        private.get(name)
50    }
51
52    /// Removes the `cookie` from the jar.
53    pub fn remove(&self, cookie: tower_cookies::Cookie<'static>) {
54        let private = self.cookies.private(self.state.cookie_key());
55        private.remove(cookie);
56    }
57}