1use core::fmt;
4
5use super::integer::{HpackInteger, HpackIntegerParseError};
6use super::string::{HpackStringLiteral, HpackStringLiteralParseError};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum HpackRepresentation<'a> {
11 Indexed(HpackIndexedField<'a>),
13 Literal(HpackLiteralField<'a>),
15 DynamicTableSizeUpdate(HpackDynamicTableSizeUpdate<'a>),
17}
18
19impl<'a> HpackRepresentation<'a> {
20 pub fn parse(bytes: &'a [u8]) -> Result<Self, HpackRepresentationParseError> {
22 let first = *bytes
23 .first()
24 .ok_or(HpackRepresentationParseError::IndexedIndex(
25 HpackIntegerParseError::Incomplete {
26 required: 1,
27 available: 0,
28 },
29 ))?;
30
31 if first & 0x80 != 0 {
32 HpackIndexedField::parse(bytes).map(Self::Indexed)
33 } else if first & 0x40 != 0 {
34 HpackLiteralField::parse(bytes, HpackLiteralMode::IncrementalIndexing)
35 .map(Self::Literal)
36 } else if first & 0x20 != 0 {
37 HpackDynamicTableSizeUpdate::parse(bytes).map(Self::DynamicTableSizeUpdate)
38 } else if first & 0x10 != 0 {
39 HpackLiteralField::parse(bytes, HpackLiteralMode::NeverIndexed).map(Self::Literal)
40 } else {
41 HpackLiteralField::parse(bytes, HpackLiteralMode::WithoutIndexing).map(Self::Literal)
42 }
43 }
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub struct HpackIndexedField<'a> {
49 bytes: &'a [u8],
50 index: HpackInteger<'a>,
51}
52
53impl<'a> HpackIndexedField<'a> {
54 fn parse(bytes: &'a [u8]) -> Result<Self, HpackRepresentationParseError> {
55 let index =
56 HpackInteger::parse(bytes, 7).map_err(HpackRepresentationParseError::IndexedIndex)?;
57 if index.value() == 0 {
58 return Err(HpackRepresentationParseError::IndexedFieldZero);
59 }
60 Ok(Self {
61 bytes: index.as_bytes(),
62 index,
63 })
64 }
65
66 pub const fn as_bytes(self) -> &'a [u8] {
68 self.bytes
69 }
70
71 pub const fn index(self) -> HpackInteger<'a> {
73 self.index
74 }
75
76 pub const fn index_value(self) -> u64 {
78 self.index.value()
79 }
80}
81
82#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub enum HpackLiteralMode {
85 IncrementalIndexing,
87 WithoutIndexing,
89 NeverIndexed,
91}
92
93#[derive(Clone, Copy, Debug, Eq, PartialEq)]
95pub struct HpackLiteralField<'a> {
96 bytes: &'a [u8],
97 mode: HpackLiteralMode,
98 name_index: HpackInteger<'a>,
99 name: Option<HpackStringLiteral<'a>>,
100 value: HpackStringLiteral<'a>,
101}
102
103impl<'a> HpackLiteralField<'a> {
104 fn parse(
105 bytes: &'a [u8],
106 mode: HpackLiteralMode,
107 ) -> Result<Self, HpackRepresentationParseError> {
108 let prefix_bits = match mode {
109 HpackLiteralMode::IncrementalIndexing => 6,
110 HpackLiteralMode::WithoutIndexing | HpackLiteralMode::NeverIndexed => 4,
111 };
112 let name_index = HpackInteger::parse(bytes, prefix_bits)
113 .map_err(HpackRepresentationParseError::LiteralNameIndex)?;
114 let after_name_index = bytes
115 .get(name_index.as_bytes().len()..)
116 .ok_or(HpackRepresentationParseError::LengthOverflow)?;
117 let name = if name_index.value() == 0 {
118 let name = HpackStringLiteral::parse(after_name_index)
119 .map_err(HpackRepresentationParseError::LiteralName)?;
120 Some(name)
121 } else {
122 None
123 };
124 let after_name = match name {
125 Some(name) => after_name_index
126 .get(name.as_bytes().len()..)
127 .ok_or(HpackRepresentationParseError::LengthOverflow)?,
128 None => after_name_index,
129 };
130 let value = HpackStringLiteral::parse(after_name)
131 .map_err(HpackRepresentationParseError::LiteralValue)?;
132 let total = name_index
133 .as_bytes()
134 .len()
135 .checked_add(name.map_or(0, |literal| literal.as_bytes().len()))
136 .and_then(|length| length.checked_add(value.as_bytes().len()))
137 .ok_or(HpackRepresentationParseError::LengthOverflow)?;
138 let representation = bytes
139 .get(..total)
140 .ok_or(HpackRepresentationParseError::LengthOverflow)?;
141
142 Ok(Self {
143 bytes: representation,
144 mode,
145 name_index,
146 name,
147 value,
148 })
149 }
150
151 pub const fn as_bytes(self) -> &'a [u8] {
153 self.bytes
154 }
155
156 pub const fn mode(self) -> HpackLiteralMode {
158 self.mode
159 }
160
161 pub const fn name_index(self) -> HpackInteger<'a> {
163 self.name_index
164 }
165
166 pub const fn name_index_value(self) -> u64 {
168 self.name_index.value()
169 }
170
171 pub const fn name(self) -> Option<HpackStringLiteral<'a>> {
173 self.name
174 }
175
176 pub const fn value(self) -> HpackStringLiteral<'a> {
178 self.value
179 }
180}
181
182#[derive(Clone, Copy, Debug, Eq, PartialEq)]
184pub struct HpackDynamicTableSizeUpdate<'a> {
185 bytes: &'a [u8],
186 size: HpackInteger<'a>,
187}
188
189impl<'a> HpackDynamicTableSizeUpdate<'a> {
190 fn parse(bytes: &'a [u8]) -> Result<Self, HpackRepresentationParseError> {
191 let size = HpackInteger::parse(bytes, 5)
192 .map_err(HpackRepresentationParseError::DynamicTableSize)?;
193 Ok(Self {
194 bytes: size.as_bytes(),
195 size,
196 })
197 }
198
199 pub const fn as_bytes(self) -> &'a [u8] {
201 self.bytes
202 }
203
204 pub const fn size(self) -> HpackInteger<'a> {
206 self.size
207 }
208
209 pub const fn size_value(self) -> u64 {
211 self.size.value()
212 }
213}
214
215#[derive(Clone, Copy, Debug, Eq, PartialEq)]
217pub enum HpackRepresentationParseError {
218 IndexedIndex(HpackIntegerParseError),
220 IndexedFieldZero,
222 LiteralNameIndex(HpackIntegerParseError),
224 LiteralName(HpackStringLiteralParseError),
226 LiteralValue(HpackStringLiteralParseError),
228 DynamicTableSize(HpackIntegerParseError),
230 LengthOverflow,
232}
233
234impl fmt::Display for HpackRepresentationParseError {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 match self {
237 Self::IndexedIndex(error) => write!(f, "invalid HPACK indexed field index: {error}"),
238 Self::IndexedFieldZero => f.write_str("HPACK indexed field index must not be zero"),
239 Self::LiteralNameIndex(error) => {
240 write!(f, "invalid HPACK literal field name index: {error}")
241 }
242 Self::LiteralName(error) => write!(f, "invalid HPACK literal field name: {error}"),
243 Self::LiteralValue(error) => write!(f, "invalid HPACK literal field value: {error}"),
244 Self::DynamicTableSize(error) => write!(f, "invalid HPACK dynamic table size: {error}"),
245 Self::LengthOverflow => f.write_str("HPACK representation length overflows usize"),
246 }
247 }
248}