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 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 21 pub(crate) struct AlpnProtocol(Inner); 22 23 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 24 enum Inner { 25 HTTP09, 26 HTTP10, 27 HTTP11, 28 SPDY1, 29 SPDY2, 30 SPDY3, 31 H2, 32 H2C, 33 H3, 34 } 35 36 impl AlpnProtocol { 37 /// `HTTP/0.9` in [`IANA Registration`]. 38 /// 39 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 40 pub(crate) const HTTP09: Self = Self(Inner::HTTP09); 41 42 /// `HTTP/1.0` in [`IANA Registration`]. 43 /// 44 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 45 pub(crate) const HTTP10: Self = Self(Inner::HTTP10); 46 47 /// `HTTP/1.1` in [`IANA Registration`]. 48 /// 49 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 50 pub(crate) const HTTP11: Self = Self(Inner::HTTP11); 51 52 /// `SPDY/1` in [`IANA Registration`]. 53 /// 54 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 55 pub(crate) const SPDY1: Self = Self(Inner::SPDY1); 56 57 /// `SPDY/2` in [`IANA Registration`]. 58 /// 59 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 60 pub(crate) const SPDY2: Self = Self(Inner::SPDY2); 61 62 /// `SPDY/3` in [`IANA Registration`]. 63 /// 64 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 65 pub(crate) const SPDY3: Self = Self(Inner::SPDY3); 66 67 /// `HTTP/2 over TLS` in [`IANA Registration`]. 68 /// 69 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 70 pub(crate) const H2: Self = Self(Inner::H2); 71 72 /// `HTTP/2 over TCP` in [`IANA Registration`]. 73 /// 74 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 75 pub(crate) const H2C: Self = Self(Inner::H2C); 76 77 /// `HTTP/3` in [`IANA Registration`]. 78 /// 79 /// [`IANA Registration`]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids 80 pub(crate) const H3: Self = Self(Inner::H3); 81 82 /// Gets ALPN “wire format”, which consists protocol name prefixed by its 83 /// byte length. wire_format_bytes(&self) -> &[u8]84 pub(crate) fn wire_format_bytes(&self) -> &[u8] { 85 match *self { 86 AlpnProtocol::HTTP09 => b"\x08http/0.9", 87 AlpnProtocol::HTTP10 => b"\x08http/1.0", 88 AlpnProtocol::HTTP11 => b"\x08http/1.1", 89 AlpnProtocol::SPDY1 => b"\x06spdy/1", 90 AlpnProtocol::SPDY2 => b"\x06spdy/2", 91 AlpnProtocol::SPDY3 => b"\x06spdy/3", 92 AlpnProtocol::H2 => b"\x02h2", 93 AlpnProtocol::H2C => b"\x03h2c", 94 AlpnProtocol::H3 => b"\x02h3", 95 } 96 } 97 } 98 99 /// `AlpnProtocolList` consists of a sequence of supported protocol names 100 /// prefixed by their byte length. 101 #[derive(Debug, Default)] 102 pub(crate) struct AlpnProtocolList(Vec<u8>); 103 104 impl AlpnProtocolList { 105 /// Creates a new `AlpnProtocolList`. new() -> Self106 pub(crate) fn new() -> Self { 107 AlpnProtocolList(vec![]) 108 } 109 extend_from_slice(&mut self, other: &[u8])110 fn extend_from_slice(&mut self, other: &[u8]) { 111 self.0.extend_from_slice(other); 112 } 113 114 /// Adds an `AlpnProtocol`. extend(mut self, protocol: AlpnProtocol) -> Self115 pub(crate) fn extend(mut self, protocol: AlpnProtocol) -> Self { 116 self.extend_from_slice(protocol.wire_format_bytes()); 117 self 118 } 119 120 /// Gets `&[u8]` of ALPN “wire format”, which consists of a sequence of 121 /// supported protocol names prefixed by their byte length. as_slice(&self) -> &[u8]122 pub(crate) fn as_slice(&self) -> &[u8] { 123 self.0.as_slice() 124 } 125 } 126 127 #[cfg(test)] 128 mod ut_alpn { 129 use crate::util::{AlpnProtocol, AlpnProtocolList}; 130 131 /// UT test cases for `AlpnProtocol::wire_format_bytes`. 132 /// 133 /// # Brief 134 /// 1. Creates a `AlpnProtocol`. 135 /// 2. Gets `&[u8]` by AlpnProtocol::wire_format_bytes. 136 /// 3. Checks whether the result is correct. 137 #[test] ut_alpn_as_use_bytes()138 fn ut_alpn_as_use_bytes() { 139 assert_eq!(AlpnProtocol::HTTP09.wire_format_bytes(), b"\x08http/0.9"); 140 assert_eq!(AlpnProtocol::HTTP10.wire_format_bytes(), b"\x08http/1.0"); 141 assert_eq!(AlpnProtocol::HTTP11.wire_format_bytes(), b"\x08http/1.1"); 142 assert_eq!(AlpnProtocol::SPDY1.wire_format_bytes(), b"\x06spdy/1"); 143 assert_eq!(AlpnProtocol::SPDY2.wire_format_bytes(), b"\x06spdy/2"); 144 assert_eq!(AlpnProtocol::SPDY3.wire_format_bytes(), b"\x06spdy/3"); 145 assert_eq!(AlpnProtocol::H2.wire_format_bytes(), b"\x02h2"); 146 assert_eq!(AlpnProtocol::H2C.wire_format_bytes(), b"\x03h2c"); 147 assert_eq!(AlpnProtocol::H3.wire_format_bytes(), b"\x02h3"); 148 } 149 150 /// UT test cases for `AlpnProtocol::clone`. 151 /// 152 /// # Brief 153 /// 1. Creates a `AlpnProtocol`. 154 /// 2. Compares the cloned values. 155 /// 3. Checks whether the result is correct. 156 #[test] ut_alpn_clone()157 fn ut_alpn_clone() { 158 assert_eq!(AlpnProtocol::HTTP09, AlpnProtocol::HTTP09.clone()); 159 } 160 161 /// UT test cases for `AlpnProtocolList::new`. 162 /// 163 /// # Brief 164 /// 1. Creates a `AlpnProtocolList` by `AlpnProtocolList::new`. 165 /// 2. Checks whether the result is correct. 166 #[test] ut_alpn_list_new()167 fn ut_alpn_list_new() { 168 assert_eq!(AlpnProtocolList::new().as_slice(), b""); 169 } 170 171 /// UT test cases for `AlpnProtocolList::default`. 172 /// 173 /// # Brief 174 /// 1. Creates a `AlpnProtocolList` by `AlpnProtocolList::default`. 175 /// 2. Checks whether the result is correct. 176 #[test] ut_alpn_list_default()177 fn ut_alpn_list_default() { 178 assert_eq!(AlpnProtocolList::default().as_slice(), b""); 179 } 180 181 /// UT test cases for `AlpnProtocolList::add`. 182 /// 183 /// # Brief 184 /// 1. Creates a `AlpnProtocolList` by `AlpnProtocolList::new`. 185 /// 2. Adds several `AlpnProtocol`s. 186 /// 3. Checks whether the result is correct. 187 #[test] ut_alpn_list_add()188 fn ut_alpn_list_add() { 189 assert_eq!( 190 AlpnProtocolList::new() 191 .extend(AlpnProtocol::SPDY1) 192 .extend(AlpnProtocol::HTTP11) 193 .as_slice(), 194 b"\x06spdy/1\x08http/1.1" 195 ); 196 } 197 198 /// UT test cases for `AlpnProtocolList::as_slice`. 199 /// 200 /// # Brief 201 /// 1. Creates a `AlpnProtocolList` and adds several `AlpnProtocol`s. 202 /// 2. Gets slice by `AlpnProtocolList::as_slice`. 203 /// 3. Checks whether the result is correct. 204 #[test] ut_alpn_list_as_slice()205 fn ut_alpn_list_as_slice() { 206 assert_eq!( 207 AlpnProtocolList::new() 208 .extend(AlpnProtocol::HTTP09) 209 .as_slice(), 210 b"\x08http/0.9" 211 ); 212 } 213 } 214