1use crate::*;
2
3impl CookieBuilder {
5 #[inline]
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: false,
29 http_only: false,
30 same_site: None,
31 }
32 }
33
34 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.expires = Some(value);
76 }
77 COOKIE_MAX_AGE_LOWERCASE => {
78 if let Ok(max_age_value) = value.parse::<i64>() {
79 cookie_builder.max_age = Some(max_age_value);
80 }
81 }
82 COOKIE_DOMAIN_LOWERCASE => {
83 cookie_builder.domain = Some(value);
84 }
85 COOKIE_PATH_LOWERCASE => {
86 cookie_builder.path = Some(value);
87 }
88 COOKIE_SAME_SITE_LOWERCASE => {
89 cookie_builder.same_site = Some(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 = true;
98 }
99 COOKIE_HTTP_ONLY_LOWERCASE => {
100 cookie_builder.http_only = true;
101 }
102 _ => {}
103 }
104 }
105 }
106 cookie_builder
107 }
108
109 #[inline]
119 pub fn 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 #[inline]
137 pub fn max_age(&mut self, max_age: i64) -> &mut Self {
138 self.max_age = Some(max_age);
139 self
140 }
141
142 #[inline]
152 pub fn domain<D>(&mut self, domain: D) -> &mut Self
153 where
154 D: AsRef<str>,
155 {
156 self.domain = Some(domain.as_ref().to_owned());
157 self
158 }
159
160 #[inline]
170 pub fn path<T>(&mut self, path: T) -> &mut Self
171 where
172 T: AsRef<str>,
173 {
174 self.path = Some(path.as_ref().to_owned());
175 self
176 }
177
178 #[inline]
186 pub fn secure(&mut self) -> &mut Self {
187 self.secure = true;
188 self
189 }
190
191 #[inline]
199 pub fn http_only(&mut self) -> &mut Self {
200 self.http_only = true;
201 self
202 }
203
204 #[inline]
214 pub fn same_site<T>(&mut self, same_site: T) -> &mut Self
215 where
216 T: AsRef<str>,
217 {
218 self.same_site = Some(same_site.as_ref().to_owned());
219 self
220 }
221
222 pub fn build(&self) -> String {
228 if self.name.is_empty() {
229 return String::new();
230 }
231 let mut cookie_string: String = format!("{}={}", self.name, self.value);
232 if let Some(ref expires_value) = self.expires {
233 cookie_string.push_str(COOKIE_EXPIRES_ATTRIBUTE_LOWERCASE);
234 cookie_string.push_str(expires_value);
235 }
236 if let Some(max_age_value) = self.max_age {
237 cookie_string.push_str(COOKIE_MAX_AGE_ATTRIBUTE_LOWERCASE);
238 cookie_string.push_str(&max_age_value.to_string());
239 }
240 if let Some(ref domain_value) = self.domain {
241 cookie_string.push_str(COOKIE_DOMAIN_ATTRIBUTE_LOWERCASE);
242 cookie_string.push_str(domain_value);
243 }
244 if let Some(ref path_value) = self.path {
245 cookie_string.push_str(COOKIE_PATH_ATTRIBUTE_LOWERCASE);
246 cookie_string.push_str(path_value);
247 }
248 if self.secure {
249 cookie_string.push_str(COOKIE_SECURE_ATTRIBUTE_LOWERCASE);
250 }
251 if self.http_only {
252 cookie_string.push_str(COOKIE_HTTP_ONLY_ATTRIBUTE_LOWERCASE);
253 }
254 if let Some(ref same_site_value) = self.same_site {
255 cookie_string.push_str(COOKIE_SAME_SITE_ATTRIBUTE_LOWERCASE);
256 cookie_string.push_str(same_site_value);
257 }
258 cookie_string
259 }
260}
261
262impl Cookie {
264 pub fn parse<C>(cookie: C) -> Cookies
277 where
278 C: AsRef<str>,
279 {
280 let cookie_ref: &str = cookie.as_ref();
281 let mut cookies: Cookies = hash_map_xx_hash3_64();
282 if cookie_ref.trim().is_empty() {
283 return cookies;
284 }
285 let parts: Vec<&str> = cookie_ref.split(SEMICOLON).collect();
286 for part in parts {
287 let part: &str = part.trim();
288 if part.is_empty() {
289 continue;
290 }
291 if let Some((name, value)) = part.split_once(EQUAL) {
292 let name: String = name.trim().to_string();
293 let value: String = value.trim().to_string();
294 if !name.is_empty() {
295 cookies.insert(name, value);
296 }
297 } else if !part.is_empty() {
298 cookies.insert(part.to_string(), String::new());
299 }
300 }
301 cookies
302 }
303}