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