http_type/cookie/
impl.rs

1use crate::*;
2
3/// Implementation for `CookieBuilder`.
4impl CookieBuilder {
5    /// Parses a `Set-Cookie` header string into a `CookieBuilder`.
6    ///
7    /// This method takes a `Set-Cookie` header string and extracts the various
8    /// attributes of a cookie, populating a `CookieBuilder` instance.
9    ///
10    /// # Arguments
11    ///
12    /// - `AsRef<str>` - The `Set-Cookie` header string to parse.
13    ///
14    /// # Returns
15    ///
16    /// A `CookieBuilder` instance populated with the parsed cookie attributes.
17    pub fn parse<C>(cookie: C) -> Self
18    where
19        C: AsRef<str>,
20    {
21        let mut cookie_builder: Self = Self::default();
22        let parts: Vec<&str> = cookie.as_ref().split(SEMICOLON).collect();
23        if parts.is_empty() {
24            return cookie_builder;
25        }
26        if let Some(name_value_pair) = parts.first() {
27            let name_value_pair: &str = name_value_pair.trim();
28            if let Some((name, value)) = name_value_pair.split_once(EQUAL) {
29                cookie_builder.name = name.trim().to_string();
30                cookie_builder.value = value.trim().to_string();
31            } else if !name_value_pair.is_empty() {
32                cookie_builder.name = name_value_pair.to_string();
33                cookie_builder.value = String::new();
34            }
35        }
36        for part in parts.iter().skip(1) {
37            let part: &str = part.trim();
38            if part.is_empty() {
39                continue;
40            }
41            if let Some((key, value)) = part.split_once(EQUAL) {
42                let key_lowercase: String = key.trim().to_lowercase();
43                let value: String = value.trim().to_string();
44                match key_lowercase.as_str() {
45                    COOKIE_EXPIRES_LOWERCASE => {
46                        cookie_builder.expires = Some(value);
47                    }
48                    COOKIE_MAX_AGE_LOWERCASE => {
49                        if let Ok(max_age_value) = value.parse::<i64>() {
50                            cookie_builder.max_age = Some(max_age_value);
51                        }
52                    }
53                    COOKIE_DOMAIN_LOWERCASE => {
54                        cookie_builder.domain = Some(value);
55                    }
56                    COOKIE_PATH_LOWERCASE => {
57                        cookie_builder.path = Some(value);
58                    }
59                    COOKIE_SAME_SITE_LOWERCASE => {
60                        cookie_builder.same_site = Some(value);
61                    }
62                    _ => {}
63                }
64            } else {
65                let attribute_lowercase: String = part.to_lowercase();
66                match attribute_lowercase.as_str() {
67                    COOKIE_SECURE_LOWERCASE => {
68                        cookie_builder.secure = true;
69                    }
70                    COOKIE_HTTP_ONLY_LOWERCASE => {
71                        cookie_builder.http_only = true;
72                    }
73                    _ => {}
74                }
75            }
76        }
77        cookie_builder
78    }
79
80    /// Builds the cookie string according to the `Set-Cookie` header format.
81    ///
82    /// # Returns
83    ///
84    /// - `String` - A formatted cookie string ready to be sent in a `Set-Cookie` header.
85    pub fn build(&self) -> String {
86        if self.name.is_empty() {
87            return String::new();
88        }
89        let mut cookie_string: String = format!("{}={}", self.name, self.value);
90        if let Some(ref expires_value) = self.expires {
91            cookie_string.push_str(COOKIE_EXPIRES_ATTRIBUTE_LOWERCASE);
92            cookie_string.push_str(expires_value);
93        }
94        if let Some(max_age_value) = self.max_age {
95            cookie_string.push_str(COOKIE_MAX_AGE_ATTRIBUTE_LOWERCASE);
96            cookie_string.push_str(&max_age_value.to_string());
97        }
98        if let Some(ref domain_value) = self.domain {
99            cookie_string.push_str(COOKIE_DOMAIN_ATTRIBUTE_LOWERCASE);
100            cookie_string.push_str(domain_value);
101        }
102        if let Some(ref path_value) = self.path {
103            cookie_string.push_str(COOKIE_PATH_ATTRIBUTE_LOWERCASE);
104            cookie_string.push_str(path_value);
105        }
106        if self.secure {
107            cookie_string.push_str(COOKIE_SECURE_ATTRIBUTE_LOWERCASE);
108        }
109        if self.http_only {
110            cookie_string.push_str(COOKIE_HTTP_ONLY_ATTRIBUTE_LOWERCASE);
111        }
112        if let Some(ref same_site_value) = self.same_site {
113            cookie_string.push_str(COOKIE_SAME_SITE_ATTRIBUTE_LOWERCASE);
114            cookie_string.push_str(same_site_value);
115        }
116        cookie_string
117    }
118}
119
120/// Implementation for `Cookie`.
121impl Cookie {
122    /// Parses a `Cookie` header string into a collection of key-value pairs.
123    ///
124    /// This method takes a `Cookie` header string (typically from a `Cookie` request header)
125    /// and parses it into a map of cookie names to their values.
126    ///
127    /// # Arguments
128    ///
129    /// - `AsRef<str>` - The `Cookie` header string to parse.
130    ///
131    /// # Returns
132    ///
133    /// A `Cookies` collection (a hash map) containing all parsed cookie key-value pairs.
134    pub fn parse<C>(cookie: C) -> Cookies
135    where
136        C: AsRef<str>,
137    {
138        let cookie_ref: &str = cookie.as_ref();
139        let mut cookies: Cookies = hash_map_xx_hash3_64();
140        if cookie_ref.trim().is_empty() {
141            return cookies;
142        }
143        let parts: Vec<&str> = cookie_ref.split(SEMICOLON).collect();
144        for part in parts {
145            let part: &str = part.trim();
146            if part.is_empty() {
147                continue;
148            }
149            if let Some((name, value)) = part.split_once(EQUAL) {
150                let name: String = name.trim().to_string();
151                let value: String = value.trim().to_string();
152                if !name.is_empty() {
153                    cookies.insert(name, value);
154                }
155            } else if !part.is_empty() {
156                cookies.insert(part.to_string(), String::new());
157            }
158        }
159        cookies
160    }
161}