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