headers/common/
set_cookie.rs

1/// `Set-Cookie` header, defined [RFC6265](http://tools.ietf.org/html/rfc6265#section-4.1)
2///
3/// The Set-Cookie HTTP response header is used to send cookies from the
4/// server to the user agent.
5///
6/// Informally, the Set-Cookie response header contains the header name
7/// "Set-Cookie" followed by a ":" and a cookie.  Each cookie begins with
8/// a name-value-pair, followed by zero or more attribute-value pairs.
9///
10/// # ABNF
11///
12/// ```text
13/// set-cookie-header = "Set-Cookie:" SP set-cookie-string
14/// set-cookie-string = cookie-pair *( ";" SP cookie-av )
15/// cookie-pair       = cookie-name "=" cookie-value
16/// cookie-name       = token
17/// cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
18/// cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
19///                       ; US-ASCII characters excluding CTLs,
20///                       ; whitespace DQUOTE, comma, semicolon,
21///                       ; and backslash
22/// token             = <token, defined in [RFC2616], Section 2.2>
23///
24/// cookie-av         = expires-av / max-age-av / domain-av /
25///                    path-av / secure-av / httponly-av /
26///                     extension-av
27/// expires-av        = "Expires=" sane-cookie-date
28/// sane-cookie-date  = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
29/// max-age-av        = "Max-Age=" non-zero-digit *DIGIT
30///                       ; In practice, both expires-av and max-age-av
31///                       ; are limited to dates representable by the
32///                       ; user agent.
33/// non-zero-digit    = %x31-39
34///                       ; digits 1 through 9
35/// domain-av         = "Domain=" domain-value
36/// domain-value      = <subdomain>
37///                       ; defined in [RFC1034], Section 3.5, as
38///                       ; enhanced by [RFC1123], Section 2.1
39/// path-av           = "Path=" path-value
40/// path-value        = <any CHAR except CTLs or ";">
41/// secure-av         = "Secure"
42/// httponly-av       = "HttpOnly"
43/// extension-av      = <any CHAR except CTLs or ";">
44/// ```
45///
46/// # Example values
47///
48/// * `SID=31d4d96e407aad42`
49/// * `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT`
50/// * `lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT`
51/// * `lang=en-US; Path=/; Domain=example.com`
52///
53/// # Example
54#[derive(Clone, Debug)]
55pub struct SetCookie(Vec<::HeaderValue>);
56
57impl ::Header for SetCookie {
58    fn name() -> &'static ::HeaderName {
59        &::http::header::SET_COOKIE
60    }
61
62    fn decode<'i, I: Iterator<Item = &'i ::HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
63        let vec = values.cloned().collect::<Vec<_>>();
64
65        if !vec.is_empty() {
66            Ok(SetCookie(vec))
67        } else {
68            Err(::Error::invalid())
69        }
70    }
71
72    fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
73        values.extend(self.0.iter().cloned());
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::super::{test_decode, test_encode};
80    use super::*;
81
82    #[test]
83    fn decode() {
84        let set_cookie = test_decode::<SetCookie>(&["foo=bar", "baz=quux"]).unwrap();
85        assert_eq!(set_cookie.0.len(), 2);
86        assert_eq!(set_cookie.0[0], "foo=bar");
87        assert_eq!(set_cookie.0[1], "baz=quux");
88    }
89
90    #[test]
91    fn encode() {
92        let set_cookie = SetCookie(vec![
93            ::HeaderValue::from_static("foo=bar"),
94            ::HeaderValue::from_static("baz=quux"),
95        ]);
96
97        let headers = test_encode(set_cookie);
98        let mut vals = headers.get_all("set-cookie").into_iter();
99        assert_eq!(vals.next().unwrap(), "foo=bar");
100        assert_eq!(vals.next().unwrap(), "baz=quux");
101        assert_eq!(vals.next(), None);
102    }
103}