salvo_flash/
cookie_store.rs

1use salvo_core::http::cookie::time::Duration;
2use salvo_core::http::cookie::{Cookie, SameSite};
3use salvo_core::{Depot, Request, Response};
4
5use super::{Flash, FlashHandler, FlashStore};
6
7/// CookieStore is a `FlashStore` implementation that stores the flash messages in a cookie.
8#[derive(Debug)]
9#[non_exhaustive]
10pub struct CookieStore {
11    /// The cookie max age.
12    pub max_age: Duration,
13    /// The cookie same site.
14    pub same_site: SameSite,
15    /// The cookie http only.
16    pub http_only: bool,
17    /// The cookie path.
18    pub path: String,
19    /// The cookie name.
20    pub name: String,
21}
22impl Default for CookieStore {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl CookieStore {
29    /// Create a new `CookieStore`.
30    #[must_use]
31    pub fn new() -> Self {
32        Self {
33            max_age: Duration::seconds(60),
34            same_site: SameSite::Lax,
35            http_only: true,
36            path: "/".into(),
37            name: "salvo.flash".into(),
38        }
39    }
40
41    /// Sets cookie name.
42    #[must_use]
43    pub fn name(mut self, name: impl Into<String>) -> Self {
44        self.name = name.into();
45        self
46    }
47
48    /// Sets cookie max_age.
49    #[must_use]
50    pub fn max_age(mut self, max_age: Duration) -> Self {
51        self.max_age = max_age;
52        self
53    }
54
55    /// Sets cookie same site.
56    #[must_use]
57    pub fn same_site(mut self, same_site: SameSite) -> Self {
58        self.same_site = same_site;
59        self
60    }
61
62    /// Sets cookie http only.
63    #[must_use]
64    pub fn http_only(mut self, http_only: bool) -> Self {
65        self.http_only = http_only;
66        self
67    }
68
69    /// Sets cookie path.
70    #[must_use]
71    pub fn path(mut self, path: impl Into<String>) -> Self {
72        self.path = path.into();
73        self
74    }
75
76    /// Into `FlashHandler`.
77    #[must_use]
78    pub fn into_handler(self) -> FlashHandler<Self> {
79        FlashHandler::new(self)
80    }
81}
82impl FlashStore for CookieStore {
83    async fn load_flash(&self, req: &mut Request, _depot: &mut Depot) -> Option<Flash> {
84        match req.cookie(&self.name) {
85            None => None,
86            Some(cookie) => match serde_json::from_str(cookie.value()) {
87                Ok(flash) => Some(flash),
88                Err(e) => {
89                    tracing::error!(error = ?e, "deserialize flash cookie failed");
90                    None
91                }
92            },
93        }
94    }
95    async fn save_flash(
96        &self,
97        _req: &mut Request,
98        _depot: &mut Depot,
99        res: &mut Response,
100        flash: Flash,
101    ) {
102        res.add_cookie(
103            Cookie::build((
104                self.name.clone(),
105                serde_json::to_string(&flash).unwrap_or_default(),
106            ))
107            .max_age(self.max_age)
108            .path(self.path.clone())
109            .same_site(self.same_site)
110            .http_only(self.http_only)
111            .build(),
112        );
113    }
114    async fn clear_flash(&self, _depot: &mut Depot, res: &mut Response) {
115        res.add_cookie(
116            Cookie::build((self.name.clone(), ""))
117                .max_age(Duration::seconds(0))
118                .same_site(self.same_site)
119                .http_only(self.http_only)
120                .path(self.path.clone())
121                .build(),
122        );
123    }
124}