hyperx/header/common/
connection.rs

1use std::fmt::{self, Display};
2use std::str::FromStr;
3use unicase::Ascii;
4
5pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
6
7static KEEP_ALIVE: &'static str = "keep-alive";
8static CLOSE: &'static str = "close";
9
10/// Values that can be in the `Connection` header.
11#[derive(Clone, PartialEq, Debug)]
12pub enum ConnectionOption {
13    /// The `keep-alive` connection value.
14    KeepAlive,
15    /// The `close` connection value.
16    Close,
17    /// Values in the Connection header that are supposed to be names of other Headers.
18    ///
19    /// > When a header field aside from Connection is used to supply control
20    /// > information for or about the current connection, the sender MUST list
21    /// > the corresponding field-name within the Connection header field.
22    // TODO: it would be nice if these "Strings" could be stronger types, since
23    // they are supposed to relate to other Header fields (which we have strong
24    // types for).
25    ConnectionHeader(Ascii<String>),
26}
27
28impl FromStr for ConnectionOption {
29    type Err = ();
30    fn from_str(s: &str) -> Result<ConnectionOption, ()> {
31        if Ascii::new(s) == KEEP_ALIVE {
32            Ok(KeepAlive)
33        } else if Ascii::new(s) == CLOSE {
34            Ok(Close)
35        } else {
36            Ok(ConnectionHeader(Ascii::new(s.to_owned())))
37        }
38    }
39}
40
41impl Display for ConnectionOption {
42    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43        f.write_str(match *self {
44            KeepAlive => "keep-alive",
45            Close => "close",
46            ConnectionHeader(ref s) => s.as_ref()
47        })
48    }
49}
50
51header! {
52    /// `Connection` header, defined in
53    /// [RFC7230](http://tools.ietf.org/html/rfc7230#section-6.1)
54    ///
55    /// The `Connection` header field allows the sender to indicate desired
56    /// control options for the current connection.  In order to avoid
57    /// confusing downstream recipients, a proxy or gateway MUST remove or
58    /// replace any received connection options before forwarding the
59    /// message.
60    ///
61    /// # ABNF
62    ///
63    /// ```text
64    /// Connection        = 1#connection-option
65    /// connection-option = token
66    ///
67    /// # Example values
68    /// * `close`
69    /// * `keep-alive`
70    /// * `upgrade`
71    /// ```
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// # extern crate http;
77    /// use hyperx::header::{Connection, TypedHeaders};
78    ///
79    /// let mut headers = http::HeaderMap::new();
80    /// headers.encode(&Connection::keep_alive());
81    /// ```
82    ///
83    /// ```
84    /// # extern crate http;
85    /// # extern crate hyperx;
86    /// # extern crate unicase;
87    /// # fn main() {
88    /// // extern crate unicase;
89    ///
90    /// use hyperx::header::{Connection, ConnectionOption, TypedHeaders};
91    /// use unicase::Ascii;
92    ///
93    /// let mut headers = http::HeaderMap::new();
94    /// headers.encode(
95    ///     &Connection(vec![
96    ///         ConnectionOption::ConnectionHeader(Ascii::new("upgrade".to_owned())),
97    ///     ])
98    /// );
99    /// # }
100    /// ```
101    (Connection, "Connection") => (ConnectionOption)+
102
103    test_connection {
104        test_header!(test1, vec![b"close"]);
105        test_header!(test2, vec![b"keep-alive"]);
106        test_header!(test3, vec![b"upgrade"]);
107    }
108}
109
110impl Connection {
111    /// A constructor to easily create a `Connection: close` header.
112    #[inline]
113    pub fn close() -> Connection {
114        Connection(vec![ConnectionOption::Close])
115    }
116
117    /// A constructor to easily create a `Connection: keep-alive` header.
118    #[inline]
119    pub fn keep_alive() -> Connection {
120        Connection(vec![ConnectionOption::KeepAlive])
121    }
122}
123
124bench_header!(close, Connection, { vec![b"close".to_vec()] });
125bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
126bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
127
128#[cfg(test)]
129mod tests {
130    use super::{Connection,ConnectionHeader};
131    use header::{Header, Raw};
132    use unicase::Ascii;
133
134    fn parse_option(header: Vec<u8>) -> Connection {
135        let val: Raw = header.into();
136        let connection: Connection = Header::parse_header(&val).unwrap();
137        connection
138    }
139
140    #[test]
141    fn test_parse() {
142        assert_eq!(Connection::close(),parse_option(b"close".to_vec()));
143        assert_eq!(Connection::keep_alive(),parse_option(b"keep-alive".to_vec()));
144        assert_eq!(Connection::keep_alive(),parse_option(b"Keep-Alive".to_vec()));
145        assert_eq!(Connection(vec![ConnectionHeader(Ascii::new("upgrade".to_owned()))]),
146            parse_option(b"upgrade".to_vec()));
147    }
148}
149
150standard_header!(Connection, CONNECTION);