cogo_http/header/common/
connection.rs

1use std::fmt::{self, Display};
2use std::str::FromStr;
3use unicase::UniCase;
4
5pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
6
7const KEEP_ALIVE: UniCase<&'static str> = UniCase("keep-alive");
8const CLOSE: UniCase<&'static str> = UniCase("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(UniCase<String>),
26}
27
28impl FromStr for ConnectionOption {
29    type Err = ();
30    fn from_str(s: &str) -> Result<ConnectionOption, ()> {
31        if UniCase(s) == KEEP_ALIVE {
32            Ok(KeepAlive)
33        } else if UniCase(s) == CLOSE {
34            Ok(Close)
35        } else {
36            Ok(ConnectionHeader(UniCase(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(UniCase(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    /// ```plain
63    /// Connection        = 1#connection-option
64    /// connection-option = token
65    ///
66    /// # Example values
67    /// * `close`
68    /// * `keep-alive`
69    /// * `upgrade`
70    /// ```
71    ///
72    /// # Examples
73    /// ```
74    /// use cogo_http::header::{Headers, Connection};
75    ///
76    /// let mut headers = Headers::new();
77    /// headers.set(Connection::keep_alive());
78    /// ```
79    /// ```
80    /// # extern crate cogo_http;
81    /// # extern crate unicase;
82    /// # fn main() {
83    /// // extern crate unicase;
84    ///
85    /// use cogo_http::header::{Headers, Connection, ConnectionOption};
86    /// use unicase::UniCase;
87    ///
88    /// let mut headers = Headers::new();
89    /// headers.set(
90    ///     Connection(vec![
91    ///         ConnectionOption::ConnectionHeader(UniCase("upgrade".to_owned())),
92    ///     ])
93    /// );
94    /// # }
95    /// ```
96    (Connection, "Connection") => (ConnectionOption)+
97
98    test_connection {
99        test_header!(test1, vec![b"close"]);
100        test_header!(test2, vec![b"keep-alive"]);
101        test_header!(test3, vec![b"upgrade"]);
102    }
103}
104
105impl Connection {
106    /// A constructor to easily create a `Connection: close` header.
107    #[inline]
108    pub fn close() -> Connection {
109        Connection(vec![ConnectionOption::Close])
110    }
111
112    /// A constructor to easily create a `Connection: keep-alive` header.
113    #[inline]
114    pub fn keep_alive() -> Connection {
115        Connection(vec![ConnectionOption::KeepAlive])
116    }
117}
118
119bench_header!(close, Connection, { vec![b"close".to_vec()] });
120bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
121bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
122
123#[cfg(test)]
124mod tests {
125    use super::{Connection,ConnectionHeader};
126    use crate::header::Header;
127    use unicase::UniCase;
128
129    fn parse_option(header: Vec<u8>) -> Connection {
130        let val = vec![header];
131        let connection: Connection = Header::parse_header(&val[..]).unwrap();
132        connection
133    }
134
135    #[test]
136    fn test_parse() {
137        assert_eq!(Connection::close(),parse_option(b"close".to_vec()));
138        assert_eq!(Connection::keep_alive(),parse_option(b"keep-alive".to_vec()));
139        assert_eq!(Connection::keep_alive(),parse_option(b"Keep-Alive".to_vec()));
140        assert_eq!(Connection(vec![ConnectionHeader(UniCase("upgrade".to_owned()))]),
141            parse_option(b"upgrade".to_vec()));
142    }
143}