headers_ext/common/
connection.rs

1use std::iter::FromIterator;
2
3use util::FlatCsv;
4use ::{HeaderName, HeaderValue};
5use 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_ext as 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)]
38pub struct Connection(FlatCsv);
39
40impl Connection {
41    /// A constructor to easily create a `Connection: close` header.
42    #[inline]
43    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]
49    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]
55    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_ext as 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    /// ```
83    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
93impl FromIterator<HeaderName> for Connection {
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
106mod sealed {
107    pub trait AsConnectionOption: Sealed {
108        fn as_connection_option(&self) -> &str;
109    }
110    pub trait Sealed {}
111
112    impl<'a> AsConnectionOption for &'a str {
113        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 {
122        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 {
130        fn as_connection_option(&self) -> &str {
131            self.as_ref()
132        }
133    }
134
135    impl Sealed for ::HeaderName {}
136}