headers_ext/common/cookie.rs
1
2use util::{FlatCsv, SemiColon};
3
4/// `Cookie` header, defined in [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.4)
5///
6/// If the user agent does attach a Cookie header field to an HTTP
7/// request, the user agent must send the cookie-string
8/// as the value of the header field.
9///
10/// When the user agent generates an HTTP request, the user agent MUST NOT
11/// attach more than one Cookie header field.
12///
13/// # Example values
14/// * `SID=31d4d96e407aad42`
15/// * `SID=31d4d96e407aad42; lang=en-US`
16///
17#[derive(Clone, Debug, Header)]
18pub struct Cookie(FlatCsv<SemiColon>);
19
20impl Cookie {
21 /// Lookup a value for a cookie name.
22 ///
23 /// # Example
24 ///
25 /// ```
26 /// # extern crate headers_ext as headers;
27 /// use headers::{Cookie, HeaderMap, HeaderMapExt, HeaderValue};
28 ///
29 /// // Setup the header map with strings...
30 /// let mut headers = HeaderMap::new();
31 /// headers.insert("cookie", HeaderValue::from_static("lang=en-US"));
32 ///
33 /// // Parse a `Cookie` so we can play with it...
34 /// let cookie = headers
35 /// .typed_get::<Cookie>()
36 /// .expect("we just inserted a valid Cookie");
37 ///
38 /// assert_eq!(cookie.get("lang"), Some("en-US"));
39 /// assert_eq!(cookie.get("SID"), None);
40 /// ```
41 pub fn get(&self, name: &str) -> Option<&str> {
42 self.iter()
43 .find(|&(key, _)| key == name)
44 .map(|(_, val)| val)
45 }
46
47 /// Get the number of key-value pairs this `Cookie` contains.
48 pub fn len(&self) -> usize {
49 self.iter().count()
50 }
51
52 /// Iterator the key-value pairs of this `Cookie` header.
53 pub fn iter(&self) -> impl Iterator<Item=(&str, &str)> {
54 self.0.iter()
55 .filter_map(|kv| {
56 let mut iter = kv.splitn(2, '=');
57 let key = iter.next()?.trim();
58 let val = iter.next()?.trim();
59 Some((key, val))
60 })
61 }
62}
63
64
65/*
66impl PartialEq for Cookie {
67 fn eq(&self, other: &Cookie) -> bool {
68 if self.0.len() == other.0.len() {
69 for &(ref k, ref v) in self.0.iter() {
70 if other.get(k) != Some(v) {
71 return false;
72 }
73 }
74 true
75 } else {
76 false
77 }
78 }
79}
80*/
81
82#[cfg(test)]
83mod tests {
84 use super::Cookie;
85 use super::super::test_decode;
86
87 #[test]
88 fn test_parse() {
89 let cookie = test_decode::<Cookie>(&["foo=bar"]).unwrap();
90
91 assert_eq!(cookie.get("foo"), Some("bar"));
92 assert_eq!(cookie.get("bar"), None);
93 }
94
95 #[test]
96 fn test_multipe_same_name() {
97 let cookie = test_decode::<Cookie>(&["foo=bar; foo=baz"]).unwrap();
98
99 assert_eq!(cookie.get("foo"), Some("bar"));
100 }
101
102 #[test]
103 fn test_multipe_lines() {
104 let cookie = test_decode::<Cookie>(&["foo=bar", "lol = cat"]).unwrap();
105
106 assert_eq!(cookie.get("foo"), Some("bar"));
107 assert_eq!(cookie.get("lol"), Some("cat"));
108 }
109
110 /*
111 #[test]
112 fn test_set_and_get() {
113 let mut cookie = Cookie::new();
114 cookie.append("foo", "bar");
115 cookie.append(String::from("dyn"), String::from("amic"));
116
117 assert_eq!(cookie.get("foo"), Some("bar"));
118 assert_eq!(cookie.get("dyn"), Some("amic"));
119 assert!(cookie.get("nope").is_none());
120
121 cookie.append("foo", "notbar");
122 assert_eq!(cookie.get("foo"), Some("bar"));
123
124 cookie.set("foo", "hi");
125 assert_eq!(cookie.get("foo"), Some("hi"));
126 assert_eq!(cookie.get("dyn"), Some("amic"));
127 }
128
129 #[test]
130 fn test_eq() {
131 let mut cookie = Cookie::new();
132 let mut cookie2 = Cookie::new();
133
134 // empty is equal
135 assert_eq!(cookie, cookie2);
136
137 // left has more params
138 cookie.append("foo", "bar");
139 assert_ne!(cookie, cookie2);
140
141 // same len, different params
142 cookie2.append("bar", "foo");
143 assert_ne!(cookie, cookie2);
144
145
146 // right has more params, and matching KV
147 cookie2.append("foo", "bar");
148 assert_ne!(cookie, cookie2);
149
150 // same params, different order
151 cookie.append("bar", "foo");
152 assert_eq!(cookie, cookie2);
153 }
154
155 #[test]
156 fn test_parse() {
157 let mut cookie = Cookie::new();
158
159 let parsed = Cookie::parse_header(&b"foo=bar".to_vec().into()).unwrap();
160 cookie.append("foo", "bar");
161 assert_eq!(cookie, parsed);
162
163 let parsed = Cookie::parse_header(&b"foo=bar;".to_vec().into()).unwrap();
164 assert_eq!(cookie, parsed);
165
166 let parsed = Cookie::parse_header(&b"foo=bar; baz=quux".to_vec().into()).unwrap();
167 cookie.append("baz", "quux");
168 assert_eq!(cookie, parsed);
169
170 let parsed = Cookie::parse_header(&b"foo=bar;; baz=quux".to_vec().into()).unwrap();
171 assert_eq!(cookie, parsed);
172
173 let parsed = Cookie::parse_header(&b"foo=bar; invalid ; bad; ;; baz=quux".to_vec().into())
174 .unwrap();
175 assert_eq!(cookie, parsed);
176
177 let parsed = Cookie::parse_header(&b" foo = bar;baz= quux ".to_vec().into()).unwrap();
178 assert_eq!(cookie, parsed);
179
180 let parsed =
181 Cookie::parse_header(&vec![b"foo = bar".to_vec(), b"baz= quux ".to_vec()].into())
182 .unwrap();
183 assert_eq!(cookie, parsed);
184
185 let parsed = Cookie::parse_header(&b"foo=bar; baz=quux ; empty=".to_vec().into()).unwrap();
186 cookie.append("empty", "");
187 assert_eq!(cookie, parsed);
188
189
190 let mut cookie = Cookie::new();
191
192 let parsed = Cookie::parse_header(&b"middle=equals=in=the=middle".to_vec().into()).unwrap();
193 cookie.append("middle", "equals=in=the=middle");
194 assert_eq!(cookie, parsed);
195
196 let parsed =
197 Cookie::parse_header(&b"middle=equals=in=the=middle; double==2".to_vec().into())
198 .unwrap();
199 cookie.append("double", "=2");
200 assert_eq!(cookie, parsed);
201 }
202 */
203}
204