headers/common/connection.rs
1use std::iter::FromIterator;
2
3use http::{HeaderName, HeaderValue};
4
5use self::sealed::AsConnectionOption;
6use crate::util::FlatCsv;
7
8/// `Connection` header, defined in
9/// [RFC7230](https://datatracker.ietf.org/doc/html/rfc7230#section-6.1)
10///
11/// The `Connection` header field allows the sender to indicate desired
12/// control options for the current connection. In order to avoid
13/// confusing downstream recipients, a proxy or gateway MUST remove or
14/// replace any received connection options before forwarding the
15/// message.
16///
17/// # ABNF
18///
19/// ```text
20/// Connection = 1#connection-option
21/// connection-option = token
22///
23/// # Example values
24/// * `close`
25/// * `keep-alive`
26/// * `upgrade`
27/// ```
28///
29/// # Examples
30///
31/// ```
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 http;
76 ///
77 /// use http::header::UPGRADE;
78 /// use headers::Connection;
79 ///
80 /// let conn = Connection::keep_alive();
81 ///
82 /// assert!(!conn.contains("close"));
83 /// assert!(!conn.contains(UPGRADE));
84 /// assert!(conn.contains("keep-alive"));
85 /// assert!(conn.contains("Keep-Alive"));
86 /// ```
87 pub fn contains(&self, name: impl AsConnectionOption) -> bool {
88 let s = name.as_connection_option();
89 self.0.iter().any(|opt| opt.eq_ignore_ascii_case(s))
90 }
91}
92
93impl FromIterator<HeaderName> for Connection {
94 fn from_iter<I>(iter: I) -> Self
95 where
96 I: IntoIterator<Item = HeaderName>,
97 {
98 let flat = iter.into_iter().map(HeaderValue::from).collect();
99 Connection(flat)
100 }
101}
102
103mod sealed {
104 use http::HeaderName;
105
106 pub trait AsConnectionOption: Sealed {
107 fn as_connection_option(&self) -> &str;
108 }
109 pub trait Sealed {}
110
111 impl AsConnectionOption for &str {
112 fn as_connection_option(&self) -> &str {
113 self
114 }
115 }
116
117 impl Sealed for &str {}
118
119 impl AsConnectionOption for &HeaderName {
120 fn as_connection_option(&self) -> &str {
121 self.as_ref()
122 }
123 }
124
125 impl Sealed for &HeaderName {}
126
127 impl AsConnectionOption for HeaderName {
128 fn as_connection_option(&self) -> &str {
129 self.as_ref()
130 }
131 }
132
133 impl Sealed for HeaderName {}
134}