hyperx/header/common/
cookie.rs1use std::borrow::Cow;
2use std::fmt;
3use std::str::from_utf8;
4
5use header::{Header, RawLike};
6use header::internals::VecMap;
7
8#[derive(Clone)]
38pub struct Cookie(VecMap<Cow<'static, str>, Cow<'static, str>>);
39
40impl Cookie {
41 pub fn new() -> Cookie {
43 Cookie(VecMap::with_capacity(0))
44 }
45
46 pub fn set<K, V>(&mut self, key: K, value: V)
53 where K: Into<Cow<'static, str>>,
54 V: Into<Cow<'static, str>>
55 {
56 let key = key.into();
57 let value = value.into();
58 self.0.remove_all(&key);
59 self.0.append(key, value);
60 }
61
62 pub fn append<K, V>(&mut self, key: K, value: V)
76 where K: Into<Cow<'static, str>>,
77 V: Into<Cow<'static, str>>
78 {
79 self.0.append(key.into(), value.into());
80 }
81
82 pub fn get(&self, key: &str) -> Option<&str> {
90 self.0.get(key).map(AsRef::as_ref)
91 }
92
93 pub fn iter(&self) -> CookieIter {
113 CookieIter(self.0.iter())
114 }
115}
116
117impl Header for Cookie {
118 fn header_name() -> &'static str {
119 static NAME: &'static str = "Cookie";
120 NAME
121 }
122
123 fn parse_header<'a, T>(raw: &'a T) -> ::Result<Cookie>
124 where T: RawLike<'a>
125 {
126 let mut vec_map = VecMap::with_capacity(raw.len());
127 for cookies_raw in raw.iter() {
128 let cookies_str = from_utf8(&cookies_raw[..])?;
129 for cookie_str in cookies_str.split(';') {
130 let mut key_val = cookie_str.splitn(2, '=');
131 let key_val = (key_val.next(), key_val.next());
132 if let (Some(key), Some(val)) = key_val {
133 vec_map.insert(key.trim().to_owned().into(), val.trim().to_owned().into());
134 }
135 }
136 }
137
138 if vec_map.len() != 0 {
139 Ok(Cookie(vec_map))
140 } else {
141 Err(::Error::Header)
142 }
143 }
144
145 fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
146 f.fmt_line(self)
147 }
148}
149
150impl PartialEq for Cookie {
151 fn eq(&self, other: &Cookie) -> bool {
152 if self.0.len() == other.0.len() {
153 for &(ref k, ref v) in self.0.iter() {
154 if other.get(k) != Some(v) {
155 return false;
156 }
157 }
158 true
159 } else {
160 false
161 }
162 }
163}
164
165impl fmt::Debug for Cookie {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 f.debug_map()
168 .entries(self.0.iter().map(|&(ref k, ref v)| (k, v)))
169 .finish()
170 }
171}
172
173impl fmt::Display for Cookie {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 let mut iter = self.0.iter();
176 if let Some(&(ref key, ref val)) = iter.next() {
177 write!(f, "{}={}", key, val)?;
178 }
179 for &(ref key, ref val) in iter {
180 write!(f, "; {}={}", key, val)?;
181 }
182 Ok(())
183 }
184}
185
186#[derive(Debug)]
188pub struct CookieIter<'a>(::std::slice::Iter<'a, (Cow<'static, str>, Cow<'static, str>)>);
189
190impl<'a> Iterator for CookieIter<'a> {
191 type Item = (&'a str, &'a str);
192
193 fn next(&mut self) -> Option<Self::Item> {
194 self.0.next().map(|kv| (kv.0.as_ref(), kv.1.as_ref()))
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use header::{Header, Raw};
201 use super::Cookie;
202
203 #[test]
204 fn test_set_and_get() {
205 let mut cookie = Cookie::new();
206 cookie.append("foo", "bar");
207 cookie.append(String::from("dyn"), String::from("amic"));
208
209 assert_eq!(cookie.get("foo"), Some("bar"));
210 assert_eq!(cookie.get("dyn"), Some("amic"));
211 assert!(cookie.get("nope").is_none());
212
213 cookie.append("foo", "notbar");
214 assert_eq!(cookie.get("foo"), Some("bar"));
215
216 cookie.set("foo", "hi");
217 assert_eq!(cookie.get("foo"), Some("hi"));
218 assert_eq!(cookie.get("dyn"), Some("amic"));
219 }
220
221 #[test]
222 fn test_eq() {
223 let mut cookie = Cookie::new();
224 let mut cookie2 = Cookie::new();
225
226 assert_eq!(cookie, cookie2);
228
229 cookie.append("foo", "bar");
231 assert_ne!(cookie, cookie2);
232
233 cookie2.append("bar", "foo");
235 assert_ne!(cookie, cookie2);
236
237 cookie2.append("foo", "bar");
239 assert_ne!(cookie, cookie2);
240
241 cookie.append("bar", "foo");
243 assert_eq!(cookie, cookie2);
244 }
245
246 #[test]
247 fn test_parse() {
248 let mut cookie = Cookie::new();
249 let r: Raw = b"foo=bar".to_vec().into();
250 let parsed = Cookie::parse_header(&r).unwrap();
251 cookie.append("foo", "bar");
252 assert_eq!(cookie, parsed);
253
254 let parsed = Cookie::parse_header(&r).unwrap();
255 assert_eq!(cookie, parsed);
256
257 let r: Raw = b"foo=bar; baz=quux".to_vec().into();
258 let parsed = Cookie::parse_header(&r).unwrap();
259 cookie.append("baz", "quux");
260 assert_eq!(cookie, parsed);
261
262 let r: Raw = b"foo=bar;; baz=quux".to_vec().into();
263 let parsed = Cookie::parse_header(&r).unwrap();
264 assert_eq!(cookie, parsed);
265
266 let r: Raw = b"foo=bar; invalid ; bad; ;; baz=quux".to_vec().into();
267 let parsed = Cookie::parse_header(&r).unwrap();
268 assert_eq!(cookie, parsed);
269
270 let r: Raw = b" foo = bar;baz= quux ".to_vec().into();
271 let parsed = Cookie::parse_header(&r).unwrap();
272 assert_eq!(cookie, parsed);
273
274 let r: Raw = vec![b"foo = bar".to_vec(), b"baz= quux ".to_vec()].into();
275 let parsed = Cookie::parse_header(&r).unwrap();
276 assert_eq!(cookie, parsed);
277 let r: Raw = b"foo=bar; baz=quux ; empty=".to_vec().into();
278 let parsed = Cookie::parse_header(&r).unwrap();
279 cookie.append("empty", "");
280 assert_eq!(cookie, parsed);
281
282 let mut cookie = Cookie::new();
283 let r: Raw = b"middle=equals=in=the=middle".to_vec().into();
284 let parsed = Cookie::parse_header(&r).unwrap();
285 cookie.append("middle", "equals=in=the=middle");
286 assert_eq!(cookie, parsed);
287
288 let r: Raw = b"middle=equals=in=the=middle; double==2".to_vec().into();
289 let parsed = Cookie::parse_header(&r).unwrap();
290 cookie.append("double", "=2");
291 assert_eq!(cookie, parsed);
292 }
293}
294
295bench_header!(bench, Cookie, {
296 vec![b"foo=bar; baz=quux".to_vec()]
297});
298
299standard_header!(Cookie, COOKIE);