• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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