1 use std::iter::FromIterator;
2 
3 use util::FlatCsv;
4 use ::{HeaderName, HeaderValue};
5 use self::sealed::AsConnectionOption;
6 
7 /// `Connection` header, defined in
8 /// [RFC7230](http://tools.ietf.org/html/rfc7230#section-6.1)
9 ///
10 /// The `Connection` header field allows the sender to indicate desired
11 /// control options for the current connection.  In order to avoid
12 /// confusing downstream recipients, a proxy or gateway MUST remove or
13 /// replace any received connection options before forwarding the
14 /// message.
15 ///
16 /// # ABNF
17 ///
18 /// ```text
19 /// Connection        = 1#connection-option
20 /// connection-option = token
21 ///
22 /// # Example values
23 /// * `close`
24 /// * `keep-alive`
25 /// * `upgrade`
26 /// ```
27 ///
28 /// # Examples
29 ///
30 /// ```
31 /// # extern crate headers;
32 /// use headers::Connection;
33 ///
34 /// let keep_alive = Connection::keep_alive();
35 /// ```
36 // This is frequently just 1 or 2 values, so optimize for that case.
37 #[derive(Clone, Debug, Header)]
38 pub struct Connection(FlatCsv);
39 
40 impl Connection {
41     /// A constructor to easily create a `Connection: close` header.
42     #[inline]
close() -> Connection43     pub fn close() -> Connection {
44         Connection(HeaderValue::from_static("close").into())
45     }
46 
47     /// A constructor to easily create a `Connection: keep-alive` header.
48     #[inline]
keep_alive() -> Connection49     pub fn keep_alive() -> Connection {
50         Connection(HeaderValue::from_static("keep-alive").into())
51     }
52 
53     /// A constructor to easily create a `Connection: Upgrade` header.
54     #[inline]
upgrade() -> Connection55     pub fn upgrade() -> Connection {
56         Connection(HeaderValue::from_static("upgrade").into())
57     }
58 
59     /// Check if this header contains a given "connection option".
60     ///
61     /// This can be used with various argument types:
62     ///
63     /// - `&str`
64     /// - `&HeaderName`
65     /// - `HeaderName`
66     ///
67     /// # Example
68     ///
69     /// ```
70     /// # extern crate headers;
71     /// extern crate http;
72     ///
73     /// use http::header::UPGRADE;
74     /// use headers::Connection;
75     ///
76     /// let conn = Connection::keep_alive();
77     ///
78     /// assert!(!conn.contains("close"));
79     /// assert!(!conn.contains(UPGRADE));
80     /// assert!(conn.contains("keep-alive"));
81     /// assert!(conn.contains("Keep-Alive"));
82     /// ```
contains(&self, name: impl AsConnectionOption) -> bool83     pub fn contains(&self, name: impl AsConnectionOption) -> bool {
84         let s = name.as_connection_option();
85         self
86             .0
87             .iter()
88             .find(|&opt| opt.eq_ignore_ascii_case(s))
89             .is_some()
90     }
91 }
92 
93 impl FromIterator<HeaderName> for Connection {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = HeaderName>,94     fn from_iter<I>(iter: I) -> Self
95     where
96         I: IntoIterator<Item = HeaderName>,
97     {
98         let flat = iter
99             .into_iter()
100             .map(HeaderValue::from)
101             .collect();
102         Connection(flat)
103     }
104 }
105 
106 mod sealed {
107     pub trait AsConnectionOption: Sealed {
as_connection_option(&self) -> &str108         fn as_connection_option(&self) -> &str;
109     }
110     pub trait Sealed {}
111 
112     impl<'a> AsConnectionOption for &'a str {
as_connection_option(&self) -> &str113         fn as_connection_option(&self) -> &str {
114             *self
115         }
116     }
117 
118     impl<'a> Sealed for &'a str {}
119 
120 
121     impl<'a> AsConnectionOption for &'a ::HeaderName {
as_connection_option(&self) -> &str122         fn as_connection_option(&self) -> &str {
123             self.as_ref()
124         }
125     }
126 
127     impl<'a> Sealed for &'a ::HeaderName {}
128 
129     impl AsConnectionOption for ::HeaderName {
as_connection_option(&self) -> &str130         fn as_connection_option(&self) -> &str {
131             self.as_ref()
132         }
133     }
134 
135     impl Sealed for ::HeaderName {}
136 }
137