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);