hyper_sync/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    /// use hyper_sync::header::{Headers, Connection};
77    ///
78    /// let mut headers = Headers::new();
79    /// headers.set(Connection::keep_alive());
80    /// ```
81    ///
82    /// ```
83    /// # extern crate hyper_sync;
84    /// # extern crate unicase;
85    /// # fn main() {
86    /// // extern crate unicase;
87    ///
88    /// use hyper_sync::header::{Headers, Connection, ConnectionOption};
89    /// use unicase::Ascii;
90    ///
91    /// let mut headers = Headers::new();
92    /// headers.set(
93    ///     Connection(vec![
94    ///         ConnectionOption::ConnectionHeader(Ascii::new("upgrade".to_owned())),
95    ///     ])
96    /// );
97    /// # }
98    /// ```
99    (Connection, "Connection") => (ConnectionOption)+
100
101    test_connection {
102        test_header!(test1, vec![b"close"]);
103        test_header!(test2, vec![b"keep-alive"]);
104        test_header!(test3, vec![b"upgrade"]);
105    }
106}
107
108impl Connection {
109    /// A constructor to easily create a `Connection: close` header.
110    #[inline]
111    pub fn close() -> Connection {
112        Connection(vec![ConnectionOption::Close])
113    }
114
115    /// A constructor to easily create a `Connection: keep-alive` header.
116    #[inline]
117    pub fn keep_alive() -> Connection {
118        Connection(vec![ConnectionOption::KeepAlive])
119    }
120}
121
122bench_header!(close, Connection, { vec![b"close".to_vec()] });
123bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
124bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
125
126#[cfg(test)]
127mod tests {
128    use super::{Connection,ConnectionHeader};
129    use header::Header;
130    use unicase::Ascii;
131
132    fn parse_option(header: Vec<u8>) -> Connection {
133        let val = header.into();
134        let connection: Connection = Header::parse_header(&val).unwrap();
135        connection
136    }
137
138    #[test]
139    fn test_parse() {
140        assert_eq!(Connection::close(),parse_option(b"close".to_vec()));
141        assert_eq!(Connection::keep_alive(),parse_option(b"keep-alive".to_vec()));
142        assert_eq!(Connection::keep_alive(),parse_option(b"Keep-Alive".to_vec()));
143        assert_eq!(Connection(vec![ConnectionHeader(Ascii::new("upgrade".to_owned()))]),
144            parse_option(b"upgrade".to_vec()));
145    }
146}