1use std::fmt::Display;
2use crate::error::RlsResult;
3use crate::WriteExt;
4
5#[derive(Debug, PartialEq, Clone)]
6pub enum ALPN {
7 Http20,
8 Http11,
9 Http10,
10 Custom(Vec<u8>),
11}
12
13impl ALPN {
14 pub fn from_slice(opt: &[u8]) -> ALPN {
15 match opt {
16 b"http/1.0" => ALPN::Http10,
17 b"http/1.1" => ALPN::Http11,
18 b"h2" => ALPN::Http20,
19 _ => ALPN::Custom(opt.to_vec()),
20 }
21 }
22
23 pub fn value(&self) -> &str {
24 match self {
25 ALPN::Http10 => "http/1.0",
26 ALPN::Http11 => "http/1.1",
27 ALPN::Http20 => "h2",
28 ALPN::Custom(v) => unsafe { std::str::from_utf8_unchecked(v.as_slice()) }
29 }
30 }
31
32 pub fn from_bytes(bytes: &[u8]) -> RlsResult<Vec<ALPN>> {
33 let mut res = vec![];
34 let mut index = 0;
35 while index < bytes.len() {
36 let len = bytes[index] as usize;
37 res.push(ALPN::from_slice(&bytes[index + 1..len + index + 1]));
38 index = index + 1 + len;
39 }
40 Ok(res)
41 }
42
43 pub fn is_empty(&self) -> bool { self.len() == 0 }
44
45 pub fn len(&self) -> usize { 1 + self.value().len() }
46
47 pub fn write_to<W: WriteExt>(self, writer: &mut W) {
48 writer.write_u8(self.value().len() as u8);
49 writer.write_slice(self.value().as_bytes());
50 }
51}
52
53impl Display for ALPN {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match self {
56 ALPN::Http20 => write!(f, "HTTP/2.0"),
57 ALPN::Http11 => write!(f, "HTTP/1.1"),
58 ALPN::Http10 => write!(f, "HTTP/1.0"),
59 ALPN::Custom(v) => write!(f, "{}", String::from_utf8_lossy(v)),
60 }
61 }
62}