1 // Copyright (c) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 /// TLS Application-Layer Protocol Negotiation (ALPN) Protocol is defined in 15 /// [`RFC7301`]. `AlpnProtocol` contains some protocols used in HTTP, which 16 /// registered in [`IANA`]. 17 /// 18 /// [`RFC7301`]: https://www.rfc-editor.org/rfc/rfc7301.html#section-3 19 /// [`IANA`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 20 /// 21 /// # Examples 22 /// ``` 23 /// use ylong_http_client::util::AlpnProtocol; 24 /// 25 /// let alpn = AlpnProtocol::HTTP11; 26 /// assert_eq!(alpn.as_use_bytes(), b"\x08http/1.1"); 27 /// assert_eq!(alpn.id_sequence(), b"http/1.1"); 28 /// ``` 29 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 30 pub struct AlpnProtocol(Inner); 31 32 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 33 enum Inner { 34 HTTP09, 35 HTTP10, 36 HTTP11, 37 SPDY1, 38 SPDY2, 39 SPDY3, 40 H2, 41 H2C, 42 H3, 43 } 44 45 impl AlpnProtocol { 46 /// `HTTP/0.9` in [`IANA Registration`]. 47 /// 48 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 49 pub const HTTP09: Self = Self(Inner::HTTP09); 50 51 /// `HTTP/1.0` in [`IANA Registration`]. 52 /// 53 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 54 pub const HTTP10: Self = Self(Inner::HTTP10); 55 56 /// `HTTP/1.1` in [`IANA Registration`]. 57 /// 58 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 59 pub const HTTP11: Self = Self(Inner::HTTP11); 60 61 /// `SPDY/1` in [`IANA Registration`]. 62 /// 63 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 64 pub const SPDY1: Self = Self(Inner::SPDY1); 65 66 /// `SPDY/2` in [`IANA Registration`]. 67 /// 68 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 69 pub const SPDY2: Self = Self(Inner::SPDY2); 70 71 /// `SPDY/3` in [`IANA Registration`]. 72 /// 73 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 74 pub const SPDY3: Self = Self(Inner::SPDY3); 75 76 /// `HTTP/2 over TLS` in [`IANA Registration`]. 77 /// 78 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 79 pub const H2: Self = Self(Inner::H2); 80 81 /// `HTTP/2 over TCP` in [`IANA Registration`]. 82 /// 83 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 84 pub const H2C: Self = Self(Inner::H2C); 85 86 /// `HTTP/3` in [`IANA Registration`]. 87 /// 88 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 89 pub const H3: Self = Self(Inner::H3); 90 91 /// Gets ALPN “wire format”, which consists protocol name prefixed by its 92 /// byte length. as_use_bytes(&self) -> &[u8]93 pub fn as_use_bytes(&self) -> &[u8] { 94 match *self { 95 AlpnProtocol::HTTP09 => b"\x08http/0.9", 96 AlpnProtocol::HTTP10 => b"\x08http/1.0", 97 AlpnProtocol::HTTP11 => b"\x08http/1.1", 98 AlpnProtocol::SPDY1 => b"\x06spdy/1", 99 AlpnProtocol::SPDY2 => b"\x06spdy/2", 100 AlpnProtocol::SPDY3 => b"\x06spdy/3", 101 AlpnProtocol::H2 => b"\x02h2", 102 AlpnProtocol::H2C => b"\x03h2c", 103 AlpnProtocol::H3 => b"\x02h3", 104 } 105 } 106 107 /// Gets ALPN protocol name, which also called identification sequence. id_sequence(&self) -> &[u8]108 pub fn id_sequence(&self) -> &[u8] { 109 &self.as_use_bytes()[1..] 110 } 111 } 112 113 /// `AlpnProtocolList` consists of a sequence of supported protocol names 114 /// prefixed by their byte length. 115 /// 116 /// # Examples 117 /// ``` 118 /// use ylong_http_client::util::{AlpnProtocol, AlpnProtocolList}; 119 /// 120 /// let list = AlpnProtocolList::new() 121 /// .extend(AlpnProtocol::SPDY1) 122 /// .extend(AlpnProtocol::HTTP11); 123 /// assert_eq!(list.as_slice(), b"\x06spdy/1\x08http/1.1"); 124 /// ``` 125 #[derive(Debug, Default)] 126 pub struct AlpnProtocolList(Vec<u8>); 127 128 impl AlpnProtocolList { 129 /// Creates a new `AlpnProtocolList`. new() -> Self130 pub fn new() -> Self { 131 AlpnProtocolList(vec![]) 132 } 133 extend_from_slice(&mut self, other: &[u8])134 fn extend_from_slice(&mut self, other: &[u8]) { 135 self.0.extend_from_slice(other); 136 } 137 138 /// Adds an `AlpnProtocol`. extend(mut self, protocol: AlpnProtocol) -> Self139 pub fn extend(mut self, protocol: AlpnProtocol) -> Self { 140 self.extend_from_slice(protocol.as_use_bytes()); 141 self 142 } 143 144 /// Gets `Vec<u8>` of ALPN “wire format”, which consists of a sequence of 145 /// supported protocol names prefixed by their byte length. into_bytes(self) -> Vec<u8>146 pub fn into_bytes(self) -> Vec<u8> { 147 self.0 148 } 149 150 /// Gets `&[u8]` of ALPN “wire format”, which consists of a sequence of 151 /// supported protocol names prefixed by their byte length. as_slice(&self) -> &[u8]152 pub fn as_slice(&self) -> &[u8] { 153 self.0.as_slice() 154 } 155 } 156 157 #[cfg(test)] 158 mod ut_alpn { 159 use crate::util::{AlpnProtocol, AlpnProtocolList}; 160 161 /// UT test cases for `AlpnProtocol::as_use_bytes`. 162 /// 163 /// # Brief 164 /// 1. Creates a `AlpnProtocol`. 165 /// 2. Gets `&[u8]` by AlpnProtocol::as_use_bytes. 166 /// 3. Checks whether the result is correct. 167 #[test] ut_alpn_as_use_bytes()168 fn ut_alpn_as_use_bytes() { 169 assert_eq!(AlpnProtocol::HTTP09.as_use_bytes(), b"\x08http/0.9"); 170 } 171 172 /// UT test cases for `AlpnProtocol::id_sequence`. 173 /// 174 /// # Brief 175 /// 1. Creates a `AlpnProtocol`. 176 /// 2. Gets `&[u8]` by AlpnProtocol::id_sequence. 177 /// 3. Checks whether the result is correct. 178 #[test] ut_alpn_id_sequence()179 fn ut_alpn_id_sequence() { 180 assert_eq!(AlpnProtocol::HTTP09.id_sequence(), b"http/0.9"); 181 } 182 183 /// UT test cases for `AlpnProtocolList::new`. 184 /// 185 /// # Brief 186 /// 1. Creates a `AlpnProtocolList` by `AlpnProtocolList::new`. 187 /// 2. Checks whether the result is correct. 188 #[test] ut_alpn_list_new()189 fn ut_alpn_list_new() { 190 assert_eq!(AlpnProtocolList::new().as_slice(), b""); 191 } 192 193 /// UT test cases for `AlpnProtocolList::add`. 194 /// 195 /// # Brief 196 /// 1. Creates a `AlpnProtocolList` by `AlpnProtocolList::new`. 197 /// 2. Adds several `AlpnProtocol`s. 198 /// 3. Checks whether the result is correct. 199 #[test] ut_alpn_list_add()200 fn ut_alpn_list_add() { 201 assert_eq!( 202 AlpnProtocolList::new() 203 .extend(AlpnProtocol::SPDY1) 204 .extend(AlpnProtocol::HTTP11) 205 .as_slice(), 206 b"\x06spdy/1\x08http/1.1" 207 ); 208 } 209 210 /// UT test cases for `AlpnProtocolList::as_slice`. 211 /// 212 /// # Brief 213 /// 1. Creates a `AlpnProtocolList` and adds several `AlpnProtocol`s. 214 /// 2. Gets slice by `AlpnProtocolList::as_slice`. 215 /// 3. Checks whether the result is correct. 216 #[test] ut_alpn_list_as_slice()217 fn ut_alpn_list_as_slice() { 218 assert_eq!( 219 AlpnProtocolList::new() 220 .extend(AlpnProtocol::HTTP09) 221 .as_slice(), 222 b"\x08http/0.9" 223 ); 224 } 225 226 /// UT test cases for `AlpnProtocolList::to_bytes`. 227 /// 228 /// # Brief 229 /// 1. Creates a `AlpnProtocolList` and adds several `AlpnProtocol`s. 230 /// 2. Gets bytes by `AlpnProtocolList::to_bytes`. 231 /// 3. Checks whether the result is correct. 232 #[test] ut_alpn_list_to_bytes()233 fn ut_alpn_list_to_bytes() { 234 assert_eq!( 235 AlpnProtocolList::new() 236 .extend(AlpnProtocol::SPDY1) 237 .extend(AlpnProtocol::HTTP11) 238 .into_bytes(), 239 b"\x06spdy/1\x08http/1.1".to_vec() 240 ); 241 } 242 } 243