headers/common/connection.rs
1use std::iter::FromIterator;
2
3use self::sealed::AsConnectionOption;
4use util::FlatCsv;
5use {HeaderName, HeaderValue};
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;
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)]
38pub struct Connection(FlatCsv);
39
40derive_header! {
41 Connection(_),
42 name: CONNECTION
43}
44
45impl Connection {
46 /// A constructor to easily create a `Connection: close` header.
47 #[inline]
48 pub fn close() -> Connection {
49 Connection(HeaderValue::from_static("close").into())
50 }
51
52 /// A constructor to easily create a `Connection: keep-alive` header.
53 #[inline]
54 pub fn keep_alive() -> Connection {
55 Connection(HeaderValue::from_static("keep-alive").into())
56 }
57
58 /// A constructor to easily create a `Connection: Upgrade` header.
59 #[inline]
60 pub fn upgrade() -> Connection {
61 Connection(HeaderValue::from_static("upgrade").into())
62 }
63
64 /// Check if this header contains a given "connection option".
65 ///
66 /// This can be used with various argument types:
67 ///
68 /// - `&str`
69 /// - `&HeaderName`
70 /// - `HeaderName`
71 ///
72 /// # Example
73 ///
74 /// ```
75 /// # extern crate headers;
76 /// extern crate http;
77 ///
78 /// use http::header::UPGRADE;
79 /// use headers::Connection;
80 ///
81 /// let conn = Connection::keep_alive();
82 ///
83 /// assert!(!conn.contains("close"));
84 /// assert!(!conn.contains(UPGRADE));
85 /// assert!(conn.contains("keep-alive"));
86 /// assert!(conn.contains("Keep-Alive"));
87 /// ```
88 pub fn contains(&self, name: impl AsConnectionOption) -> bool {
89 let s = name.as_connection_option();
90 self.0
91 .iter()
92 .find(|&opt| opt.eq_ignore_ascii_case(s))
93 .is_some()
94 }
95}
96
97impl FromIterator<HeaderName> for Connection {
98 fn from_iter<I>(iter: I) -> Self
99 where
100 I: IntoIterator<Item = HeaderName>,
101 {
102 let flat = iter.into_iter().map(HeaderValue::from).collect();
103 Connection(flat)
104 }
105}
106
107mod sealed {
108 pub trait AsConnectionOption: Sealed {
109 fn as_connection_option(&self) -> &str;
110 }
111 pub trait Sealed {}
112
113 impl<'a> AsConnectionOption for &'a str {
114 fn as_connection_option(&self) -> &str {
115 *self
116 }
117 }
118
119 impl<'a> Sealed for &'a str {}
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}