1use crate::*;
2
3impl CookieBuilder {
4 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 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 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 pub fn max_age(&mut self, max_age: i64) -> &mut Self {
120 self.max_age = Some(max_age);
121 self
122 }
123
124 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 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 pub fn secure(&mut self) -> &mut Self {
161 self.secure = true;
162 self
163 }
164
165 pub fn http_only(&mut self) -> &mut Self {
172 self.http_only = true;
173 self
174 }
175
176 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 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 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}