1#[cfg(test)]
2mod tests;
3
4#[cfg(feature = "crypto")]
5mod crypto_ext;
6#[cfg(feature = "crypto")]
7pub use crypto_ext::{decrypt_cookie, encrypted_cookie, signed_cookie, verify_signed_cookie};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Cookie {
12 pub name: String,
13 pub value: String,
14}
15
16pub struct CookieJar {
27 pub cookies: Vec<Cookie>,
28}
29
30impl CookieJar {
31 pub fn parse(header_value: &str) -> CookieJar {
33 let cookies = header_value
34 .split(';')
35 .filter_map(|pair| {
36 let pair = pair.trim();
37 let mut parts = pair.splitn(2, '=');
38 let name = parts.next()?.trim().to_string();
39 let value = parts.next().unwrap_or("").trim().to_string();
40 if name.is_empty() { None } else { Some(Cookie { name, value }) }
41 })
42 .collect();
43 CookieJar { cookies }
44 }
45
46 pub fn get(&self, name: &str) -> Option<&Cookie> {
48 self.cookies.iter().find(|c| c.name == name)
49 }
50}
51
52pub struct SetCookie {
70 pub name: String,
71 pub value: String,
72 pub path: Option<String>,
73 pub domain: Option<String>,
74 pub max_age: Option<i64>,
75 pub secure: bool,
76 pub http_only: bool,
77 pub same_site: Option<String>,
78}
79
80impl SetCookie {
81 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
82 SetCookie {
83 name: name.into(),
84 value: value.into(),
85 path: None,
86 domain: None,
87 max_age: None,
88 secure: false,
89 http_only: false,
90 same_site: None,
91 }
92 }
93
94 pub fn path(mut self, path: impl Into<String>) -> Self {
95 self.path = Some(path.into());
96 self
97 }
98
99 pub fn domain(mut self, domain: impl Into<String>) -> Self {
100 self.domain = Some(domain.into());
101 self
102 }
103
104 pub fn max_age(mut self, seconds: i64) -> Self {
105 self.max_age = Some(seconds);
106 self
107 }
108
109 pub fn secure(mut self) -> Self {
110 self.secure = true;
111 self
112 }
113
114 pub fn http_only(mut self) -> Self {
115 self.http_only = true;
116 self
117 }
118
119 pub fn same_site(mut self, policy: impl Into<String>) -> Self {
120 self.same_site = Some(policy.into());
121 self
122 }
123
124 pub fn build(&self) -> String {
126 let mut s = format!("{}={}", self.name, self.value);
127 if let Some(ref p) = self.path { s.push_str(&format!("; Path={}", p)); }
128 if let Some(ref d) = self.domain { s.push_str(&format!("; Domain={}", d)); }
129 if let Some(age) = self.max_age { s.push_str(&format!("; Max-Age={}", age)); }
130 if self.secure { s.push_str("; Secure"); }
131 if self.http_only { s.push_str("; HttpOnly"); }
132 if let Some(ref ss) = self.same_site { s.push_str(&format!("; SameSite={}", ss)); }
133 s
134 }
135}