http_type/cookie/
impl.rs

1use crate::*;
2
3impl CookieBuilder {
4    /// Creates a new CookieBuilder with the specified name and value.
5    ///
6    /// # Parameters
7    /// - `name`: The name of the cookie.
8    /// - `value`: The value of the cookie.
9    ///
10    /// # Returns
11    /// - A new CookieBuilder instance.
12    pub fn new<N, V>(name: N, value: V) -> Self
13    where
14        N: Into<CookieKey>,
15        V: Into<CookieValue>,
16    {
17        Self {
18            name: name.into(),
19            value: value.into(),
20            expires: None,
21            max_age: None,
22            domain: None,
23            path: None,
24            secure: false,
25            http_only: false,
26            same_site: None,
27        }
28    }
29
30    /// Parses a Set-Cookie header string and returns a CookieBuilder instance.
31    ///
32    /// # Parameters
33    /// - `cookie_string`: The Set-Cookie header string to parse.
34    ///
35    /// # Returns
36    /// - A CookieBuilder instance with parsed attributes.
37    pub fn parse(cookie_string: &str) -> Self {
38        let mut cookie_builder: Self = Self::default();
39        let parts: Vec<&str> = cookie_string.split(SEMICOLON).collect();
40        if parts.is_empty() {
41            return cookie_builder;
42        }
43        if let Some(name_value_pair) = parts.first() {
44            let name_value_pair: &str = name_value_pair.trim();
45            if let Some((name, value)) = name_value_pair.split_once(EQUAL) {
46                cookie_builder.name = name.trim().to_string();
47                cookie_builder.value = value.trim().to_string();
48            } else if !name_value_pair.is_empty() {
49                cookie_builder.name = name_value_pair.to_string();
50                cookie_builder.value = String::new();
51            }
52        }
53        for part in parts.iter().skip(1) {
54            let part: &str = part.trim();
55            if part.is_empty() {
56                continue;
57            }
58            if let Some((key, value)) = part.split_once(EQUAL) {
59                let key_lowercase: String = key.trim().to_lowercase();
60                let value: String = value.trim().to_string();
61                match key_lowercase.as_str() {
62                    COOKIE_EXPIRES_LOWERCASE => {
63                        cookie_builder.expires = Some(value);
64                    }
65                    COOKIE_MAX_AGE_LOWERCASE => {
66                        if let Ok(max_age_value) = value.parse::<i64>() {
67                            cookie_builder.max_age = Some(max_age_value);
68                        }
69                    }
70                    COOKIE_DOMAIN_LOWERCASE => {
71                        cookie_builder.domain = Some(value);
72                    }
73                    COOKIE_PATH_LOWERCASE => {
74                        cookie_builder.path = Some(value);
75                    }
76                    COOKIE_SAME_SITE_LOWERCASE => {
77                        cookie_builder.same_site = Some(value);
78                    }
79                    _ => {}
80                }
81            } else {
82                let attribute_lowercase: String = part.to_lowercase();
83                match attribute_lowercase.as_str() {
84                    COOKIE_SECURE_LOWERCASE => {
85                        cookie_builder.secure = true;
86                    }
87                    COOKIE_HTTP_ONLY_LOWERCASE => {
88                        cookie_builder.http_only = true;
89                    }
90                    _ => {}
91                }
92            }
93        }
94        cookie_builder
95    }
96
97    /// Sets the expiration date for the cookie.
98    ///
99    /// # Parameters
100    /// - `expires`: The expiration date string.
101    ///
102    /// # Returns
103    /// - The CookieBuilder instance for method chaining.
104    pub fn expires<T>(&mut self, expires: T) -> &mut Self
105    where
106        T: Into<String>,
107    {
108        self.expires = Some(expires.into());
109        self
110    }
111
112    /// Sets the maximum age for the cookie in seconds.
113    ///
114    /// # Parameters
115    /// - `max_age`: The maximum age in seconds.
116    ///
117    /// # Returns
118    /// - The CookieBuilder instance for method chaining.
119    pub fn max_age(&mut self, max_age: i64) -> &mut Self {
120        self.max_age = Some(max_age);
121        self
122    }
123
124    /// Sets the domain for the cookie.
125    ///
126    /// # Parameters
127    /// - `domain`: The domain for the cookie.
128    ///
129    /// # Returns
130    /// - The CookieBuilder instance for method chaining.
131    pub fn domain<T>(&mut self, domain: T) -> &mut Self
132    where
133        T: Into<String>,
134    {
135        self.domain = Some(domain.into());
136        self
137    }
138
139    /// Sets the path for the cookie.
140    ///
141    /// # Parameters
142    /// - `path`: The path for the cookie.
143    ///
144    /// # Returns
145    /// - The CookieBuilder instance for method chaining.
146    pub fn path<T>(&mut self, path: T) -> &mut Self
147    where
148        T: Into<String>,
149    {
150        self.path = Some(path.into());
151        self
152    }
153
154    /// Sets the secure flag for the cookie.
155    ///
156    /// When set to true, the cookie will only be sent over HTTPS connections.
157    ///
158    /// # Returns
159    /// - The CookieBuilder instance for method chaining.
160    pub fn secure(&mut self) -> &mut Self {
161        self.secure = true;
162        self
163    }
164
165    /// Sets the HttpOnly flag for the cookie.
166    ///
167    /// When set to true, the cookie will be inaccessible to JavaScript.
168    ///
169    /// # Returns
170    /// - The CookieBuilder instance for method chaining.
171    pub fn http_only(&mut self) -> &mut Self {
172        self.http_only = true;
173        self
174    }
175
176    /// Sets the SameSite policy for the cookie.
177    ///
178    /// # Parameters
179    /// - `same_site`: The SameSite policy ("Strict", "Lax", or "None").
180    ///
181    /// # Returns
182    /// - The CookieBuilder instance for method chaining.
183    pub fn same_site<T>(&mut self, same_site: T) -> &mut Self
184    where
185        T: Into<String>,
186    {
187        self.same_site = Some(same_site.into());
188        self
189    }
190
191    /// Builds the cookie string representation.
192    ///
193    /// # Returns
194    /// - A formatted cookie string ready to be used in Set-Cookie headers.
195    pub fn build(&self) -> String {
196        if self.name.is_empty() {
197            return String::new();
198        }
199        let mut cookie_string: String = format!("{}={}", self.name, self.value);
200        if let Some(ref expires_value) = self.expires {
201            cookie_string.push_str(COOKIE_EXPIRES_ATTRIBUTE_LOWERCASE);
202            cookie_string.push_str(expires_value);
203        }
204        if let Some(max_age_value) = self.max_age {
205            cookie_string.push_str(COOKIE_MAX_AGE_ATTRIBUTE_LOWERCASE);
206            cookie_string.push_str(&max_age_value.to_string());
207        }
208        if let Some(ref domain_value) = self.domain {
209            cookie_string.push_str(COOKIE_DOMAIN_ATTRIBUTE_LOWERCASE);
210            cookie_string.push_str(domain_value);
211        }
212        if let Some(ref path_value) = self.path {
213            cookie_string.push_str(COOKIE_PATH_ATTRIBUTE_LOWERCASE);
214            cookie_string.push_str(path_value);
215        }
216        if self.secure {
217            cookie_string.push_str(COOKIE_SECURE_ATTRIBUTE_LOWERCASE);
218        }
219        if self.http_only {
220            cookie_string.push_str(COOKIE_HTTP_ONLY_ATTRIBUTE_LOWERCASE);
221        }
222        if let Some(ref same_site_value) = self.same_site {
223            cookie_string.push_str(COOKIE_SAME_SITE_ATTRIBUTE_LOWERCASE);
224            cookie_string.push_str(same_site_value);
225        }
226        cookie_string
227    }
228}
229
230impl Cookie {
231    /// Parses a Cookie header string and returns a Cookies collection.
232    ///
233    /// # Parameters
234    /// - `cookie_string`: The Cookie header string to parse.
235    ///
236    /// # Returns
237    /// - A Cookies collection containing all parsed cookie key-value pairs.
238    pub fn parse(cookie_string: &str) -> Cookies {
239        let mut cookies: Cookies = hash_map_xx_hash3_64();
240        if cookie_string.trim().is_empty() {
241            return cookies;
242        }
243        let parts: Vec<&str> = cookie_string.split(SEMICOLON).collect();
244        for part in parts {
245            let part: &str = part.trim();
246            if part.is_empty() {
247                continue;
248            }
249            if let Some((name, value)) = part.split_once(EQUAL) {
250                let name: String = name.trim().to_string();
251                let value: String = value.trim().to_string();
252                if !name.is_empty() {
253                    cookies.insert(name, value);
254                }
255            } else if !part.is_empty() {
256                cookies.insert(part.to_string(), String::new());
257            }
258        }
259        cookies
260    }
261}