http_type/cookie/impl.rs
1use crate::*;
2
3/// Implementation for `CookieBuilder`.
4impl CookieBuilder {
5 /// Creates a new cookie builder instance.
6 ///
7 /// # Arguments
8 ///
9 /// - `AsRef<str>` - The cookie name type.
10 /// - `AsRef<str>` - The cookie value type.
11 ///
12 /// # Returns
13 ///
14 /// - `CookieBuilder` - A new builder instance.
15 #[inline(always)]
16 pub fn new<N, V>(name: N, value: V) -> Self
17 where
18 N: AsRef<str>,
19 V: AsRef<str>,
20 {
21 Self {
22 name: name.as_ref().to_owned(),
23 value: value.as_ref().to_owned(),
24 expires: None,
25 max_age: None,
26 domain: None,
27 path: None,
28 secure: None,
29 http_only: None,
30 same_site: None,
31 }
32 }
33
34 /// Parses a `Set-Cookie` header string into a `CookieBuilder`.
35 ///
36 /// This method takes a `Set-Cookie` header string and extracts the various
37 /// attributes of a cookie, populating a `CookieBuilder` instance.
38 ///
39 /// # Arguments
40 ///
41 /// - `AsRef<str>` - The `Set-Cookie` header string to parse.
42 ///
43 /// # Returns
44 ///
45 /// A `CookieBuilder` instance populated with the parsed cookie attributes.
46 pub fn parse<C>(cookie: C) -> Self
47 where
48 C: AsRef<str>,
49 {
50 let mut cookie_builder: Self = Self::default();
51 let parts: Vec<&str> = cookie.as_ref().split(SEMICOLON).collect();
52 if parts.is_empty() {
53 return cookie_builder;
54 }
55 if let Some(name_value_pair) = parts.first() {
56 let name_value_pair: &str = name_value_pair.trim();
57 if let Some((name, value)) = name_value_pair.split_once(EQUAL) {
58 cookie_builder.name = name.trim().to_string();
59 cookie_builder.value = value.trim().to_string();
60 } else if !name_value_pair.is_empty() {
61 cookie_builder.name = name_value_pair.to_string();
62 cookie_builder.value = String::new();
63 }
64 }
65 for part in parts.iter().skip(1) {
66 let part: &str = part.trim();
67 if part.is_empty() {
68 continue;
69 }
70 if let Some((key, value)) = part.split_once(EQUAL) {
71 let key_lowercase: String = key.trim().to_lowercase();
72 let value: String = value.trim().to_string();
73 match key_lowercase.as_str() {
74 COOKIE_EXPIRES_LOWERCASE => {
75 cookie_builder.set_expires(value);
76 }
77 COOKIE_MAX_AGE_LOWERCASE => {
78 if let Ok(max_age_value) = value.parse::<i64>() {
79 cookie_builder.set_max_age(max_age_value);
80 }
81 }
82 COOKIE_DOMAIN_LOWERCASE => {
83 cookie_builder.set_domain(value);
84 }
85 COOKIE_PATH_LOWERCASE => {
86 cookie_builder.set_path(value);
87 }
88 COOKIE_SAME_SITE_LOWERCASE => {
89 cookie_builder.set_same_site(value);
90 }
91 _ => {}
92 }
93 } else {
94 let attribute_lowercase: String = part.to_lowercase();
95 match attribute_lowercase.as_str() {
96 COOKIE_SECURE_LOWERCASE => {
97 cookie_builder.secure = Some(true);
98 }
99 COOKIE_HTTP_ONLY_LOWERCASE => {
100 cookie_builder.http_only = Some(true);
101 }
102 _ => {}
103 }
104 }
105 }
106 cookie_builder
107 }
108
109 /// Sets the expiration date for the cookie.
110 ///
111 /// # Arguments
112 ///
113 /// - `AsRef<str>` - The expiration date string.
114 ///
115 /// # Returns
116 ///
117 /// The `CookieBuilder` instance for method chaining.
118 #[inline(always)]
119 pub fn set_expires<E>(&mut self, expires: E) -> &mut Self
120 where
121 E: AsRef<str>,
122 {
123 self.expires = Some(expires.as_ref().to_owned());
124 self
125 }
126
127 /// Sets the maximum age for the cookie in seconds.
128 ///
129 /// # Arguments
130 ///
131 /// - `Into<i64>` - The maximum age in seconds.
132 ///
133 /// # Returns
134 ///
135 /// The `CookieBuilder` instance for method chaining.
136 #[inline(always)]
137 pub fn set_max_age<M>(&mut self, max_age: M) -> &mut Self
138 where
139 M: Into<i64>,
140 {
141 self.max_age = Some(max_age.into());
142 self
143 }
144
145 /// Sets the domain for the cookie.
146 ///
147 /// # Arguments
148 ///
149 /// - `AsRef<str>` - The domain for the cookie.
150 ///
151 /// # Returns
152 ///
153 /// The `CookieBuilder` instance for method chaining.
154 #[inline(always)]
155 pub fn set_domain<D>(&mut self, domain: D) -> &mut Self
156 where
157 D: AsRef<str>,
158 {
159 self.domain = Some(domain.as_ref().to_owned());
160 self
161 }
162
163 /// Sets the path for the cookie.
164 ///
165 /// # Arguments
166 ///
167 /// - `AsRef<str>` - The path for the cookie.
168 ///
169 /// # Returns
170 ///
171 /// The `CookieBuilder` instance for method chaining.
172 #[inline(always)]
173 pub fn set_path<T>(&mut self, path: T) -> &mut Self
174 where
175 T: AsRef<str>,
176 {
177 self.path = Some(path.as_ref().to_owned());
178 self
179 }
180
181 /// Sets the `Secure` flag for the cookie.
182 ///
183 /// This flag indicates that the cookie should only be transmitted over secure (HTTPS) connections.
184 ///
185 /// # Returns
186 ///
187 /// The `CookieBuilder` instance for method chaining.
188 #[inline(always)]
189 pub fn secure(&mut self) -> &mut Self {
190 self.secure = Some(true);
191 self
192 }
193
194 /// Sets the `HttpOnly` flag for the cookie.
195 ///
196 /// This flag prevents client-side JavaScript from accessing the cookie.
197 ///
198 /// # Returns
199 ///
200 /// The `CookieBuilder` instance for method chaining.
201 #[inline(always)]
202 pub fn http_only(&mut self) -> &mut Self {
203 self.http_only = Some(true);
204 self
205 }
206
207 /// Explicitly disables the `Secure` flag for the cookie.
208 ///
209 /// This method explicitly sets the `Secure` flag to `false`, which may be useful
210 /// for overriding default secure settings or for testing purposes.
211 ///
212 /// # Returns
213 ///
214 /// The `CookieBuilder` instance for method chaining.
215 #[inline(always)]
216 pub fn disable_secure(&mut self) -> &mut Self {
217 self.secure = Some(false);
218 self
219 }
220
221 /// Explicitly disables the `HttpOnly` flag for the cookie.
222 ///
223 /// This method explicitly sets the `HttpOnly` flag to `false`, which may be useful
224 /// for overriding default HttpOnly settings or for testing purposes.
225 ///
226 /// # Returns
227 ///
228 /// The `CookieBuilder` instance for method chaining.
229 #[inline(always)]
230 pub fn disable_http_only(&mut self) -> &mut Self {
231 self.http_only = Some(false);
232 self
233 }
234
235 /// Sets the `SameSite` policy for the cookie.
236 ///
237 /// # Arguments
238 ///
239 /// - `AsRef<str>` - The `SameSite` policy.
240 ///
241 /// # Returns
242 ///
243 /// The `CookieBuilder` instance for method chaining.
244 #[inline(always)]
245 pub fn set_same_site<T>(&mut self, same_site: T) -> &mut Self
246 where
247 T: AsRef<str>,
248 {
249 self.same_site = Some(same_site.as_ref().to_owned());
250 self
251 }
252
253 /// Builds the cookie string according to the `Set-Cookie` header format.
254 ///
255 /// # Returns
256 ///
257 /// - `String` - A formatted cookie string ready to be sent in a `Set-Cookie` header.
258 pub fn build(&self) -> String {
259 if self.get_name().is_empty() {
260 return String::new();
261 }
262 let mut cookie_string: String = format!("{}={}", self.get_name(), self.get_value());
263 if let Some(expires_value) = self.get_expires() {
264 cookie_string.push_str(COOKIE_EXPIRES_ATTRIBUTE_LOWERCASE);
265 cookie_string.push_str(expires_value);
266 }
267 if let Some(max_age_value) = self.get_max_age() {
268 cookie_string.push_str(COOKIE_MAX_AGE_ATTRIBUTE_LOWERCASE);
269 cookie_string.push_str(&max_age_value.to_string());
270 }
271 if let Some(domain_value) = self.get_domain() {
272 cookie_string.push_str(COOKIE_DOMAIN_ATTRIBUTE_LOWERCASE);
273 cookie_string.push_str(domain_value);
274 }
275 if let Some(path_value) = self.get_path() {
276 cookie_string.push_str(COOKIE_PATH_ATTRIBUTE_LOWERCASE);
277 cookie_string.push_str(path_value);
278 }
279 if let Some(true) = self.get_secure() {
280 cookie_string.push_str(COOKIE_SECURE_ATTRIBUTE_LOWERCASE);
281 }
282 if let Some(true) = self.get_http_only() {
283 cookie_string.push_str(COOKIE_HTTP_ONLY_ATTRIBUTE_LOWERCASE);
284 }
285 if let Some(same_site_value) = self.get_same_site() {
286 cookie_string.push_str(COOKIE_SAME_SITE_ATTRIBUTE_LOWERCASE);
287 cookie_string.push_str(same_site_value);
288 }
289 cookie_string
290 }
291}
292
293/// Implementation for `Cookie`.
294impl Cookie {
295 /// Parses a `Cookie` header string into a collection of key-value pairs.
296 ///
297 /// This method takes a `Cookie` header string (typically from a `Cookie` request header)
298 /// and parses it into a map of cookie names to their values.
299 ///
300 /// # Arguments
301 ///
302 /// - `AsRef<str>` - The `Cookie` header string to parse.
303 ///
304 /// # Returns
305 ///
306 /// A `Cookies` collection (a hash map) containing all parsed cookie key-value pairs.
307 pub fn parse<C>(cookie: C) -> Cookies
308 where
309 C: AsRef<str>,
310 {
311 let cookie_ref: &str = cookie.as_ref();
312 let mut cookies: Cookies = hash_map_xx_hash3_64();
313 if cookie_ref.trim().is_empty() {
314 return cookies;
315 }
316 let parts: Vec<&str> = cookie_ref.split(SEMICOLON).collect();
317 for part in parts {
318 let part: &str = part.trim();
319 if part.is_empty() {
320 continue;
321 }
322 if let Some((name, value)) = part.split_once(EQUAL) {
323 let name: String = name.trim().to_string();
324 let value: String = value.trim().to_string();
325 if !name.is_empty() {
326 cookies.insert(name, value);
327 }
328 } else if !part.is_empty() {
329 cookies.insert(part.to_string(), String::new());
330 }
331 }
332 cookies
333 }
334}