rama_http_headers/common/
connection.rs

1use std::iter::FromIterator;
2
3use rama_http_types::{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 rama_http_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    /// use rama_http_types::header::UPGRADE;
76    /// use rama_http_headers::Connection;
77    ///
78    /// let conn = Connection::keep_alive();
79    ///
80    /// assert!(!conn.contains("close"));
81    /// assert!(!conn.contains(UPGRADE));
82    /// assert!(conn.contains("keep-alive"));
83    /// assert!(conn.contains("Keep-Alive"));
84    /// ```
85    pub fn contains(&self, name: impl AsConnectionOption) -> bool {
86        let s = name.as_connection_option();
87        self.0.iter().any(|opt| opt.eq_ignore_ascii_case(s))
88    }
89}
90
91impl FromIterator<HeaderName> for Connection {
92    fn from_iter<I>(iter: I) -> Self
93    where
94        I: IntoIterator<Item = HeaderName>,
95    {
96        let flat = iter.into_iter().map(HeaderValue::from).collect();
97        Connection(flat)
98    }
99}
100
101mod sealed {
102    use rama_http_types::HeaderName;
103
104    pub trait AsConnectionOption: Sealed {
105        fn as_connection_option(&self) -> &str;
106    }
107    pub trait Sealed {}
108
109    impl AsConnectionOption for &str {
110        fn as_connection_option(&self) -> &str {
111            self
112        }
113    }
114
115    impl Sealed for &str {}
116
117    impl AsConnectionOption for &HeaderName {
118        fn as_connection_option(&self) -> &str {
119            self.as_ref()
120        }
121    }
122
123    impl Sealed for &HeaderName {}
124
125    impl AsConnectionOption for HeaderName {
126        fn as_connection_option(&self) -> &str {
127            self.as_ref()
128        }
129    }
130
131    impl Sealed for HeaderName {}
132}