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