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