1use core::fmt;
4
5use super::integer::{canonical_encoded_len, write_canonical_for_valid_prefix};
6use super::representation::HpackLiteralMode;
7use super::string::HpackStringLiteralBuildError;
8
9pub struct HpackIndexedFieldBuilder<'a> {
11 destination: &'a mut [u8],
12 index: u64,
13}
14
15impl<'a> HpackIndexedFieldBuilder<'a> {
16 pub fn new(destination: &'a mut [u8], index: u64) -> Self {
18 Self { destination, index }
19 }
20
21 pub fn build(self) -> Result<&'a [u8], HpackRepresentationBuildError> {
23 if self.index == 0 {
24 return Err(HpackRepresentationBuildError::IndexedFieldZero);
25 }
26 let required = canonical_encoded_len(self.index, 0x7f);
27 check_capacity(self.destination.len(), required)?;
28 let representation = &mut self.destination[..required];
29 write_integer(representation, 7, 0x7f, 0x80, self.index);
30 Ok(&*representation)
31 }
32}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum HpackLiteralName<'a> {
37 Indexed(u64),
39 Literal {
43 encoded_bytes: &'a [u8],
45 huffman: bool,
47 },
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub struct HpackLiteralValue<'a> {
53 encoded_bytes: &'a [u8],
54 huffman: bool,
55}
56
57impl<'a> HpackLiteralValue<'a> {
58 pub const fn new_encoded(encoded_bytes: &'a [u8], huffman: bool) -> Self {
63 Self {
64 encoded_bytes,
65 huffman,
66 }
67 }
68
69 pub const fn encoded_bytes(self) -> &'a [u8] {
71 self.encoded_bytes
72 }
73
74 pub const fn is_huffman(self) -> bool {
76 self.huffman
77 }
78}
79
80pub struct HpackLiteralFieldBuilder<'a, 'b> {
82 destination: &'a mut [u8],
83 mode: HpackLiteralMode,
84 name: HpackLiteralName<'b>,
85 value: HpackLiteralValue<'b>,
86}
87
88impl<'a, 'b> HpackLiteralFieldBuilder<'a, 'b> {
89 pub fn new(
91 destination: &'a mut [u8],
92 mode: HpackLiteralMode,
93 name: HpackLiteralName<'b>,
94 value: HpackLiteralValue<'b>,
95 ) -> Self {
96 Self {
97 destination,
98 mode,
99 name,
100 value,
101 }
102 }
103
104 pub fn build(self) -> Result<&'a [u8], HpackRepresentationBuildError> {
106 let (prefix_bits, high_bits) = match self.mode {
107 HpackLiteralMode::IncrementalIndexing => (6, 0x40),
108 HpackLiteralMode::WithoutIndexing => (4, 0),
109 HpackLiteralMode::NeverIndexed => (4, 0x10),
110 };
111 let name_index = self.name_index();
112 if matches!(self.name, HpackLiteralName::Indexed(0)) {
113 return Err(HpackRepresentationBuildError::LiteralNameIndexZero);
114 }
115 let literal_name = self
116 .literal_name()
117 .map(|name| {
118 string_info(name)
119 .map(|info| (name, info))
120 .map_err(HpackRepresentationBuildError::LiteralName)
121 })
122 .transpose()?;
123 let name_index_len = canonical_encoded_len(name_index, prefix_mask(prefix_bits));
124 let literal_name_len = literal_name.map_or(0, |(_, (length, _))| length);
125 let (value_len, value_encoded_length) =
126 string_info(self.value).map_err(HpackRepresentationBuildError::LiteralValue)?;
127 let required = name_index_len
128 .checked_add(literal_name_len)
129 .and_then(|length| length.checked_add(value_len))
130 .ok_or(HpackRepresentationBuildError::TotalLengthOverflow)?;
131 check_capacity(self.destination.len(), required)?;
132
133 let representation = &mut self.destination[..required];
134 let (name_index_destination, after_name_index) =
135 representation.split_at_mut(name_index_len);
136 write_integer(
137 name_index_destination,
138 prefix_bits,
139 prefix_mask(prefix_bits),
140 high_bits,
141 name_index,
142 );
143 let after_name = match literal_name {
144 Some((name, (_, encoded_length))) => {
145 let (name_destination, remainder) = after_name_index.split_at_mut(literal_name_len);
146 write_string(name_destination, name, encoded_length);
147 remainder
148 }
149 None => after_name_index,
150 };
151 write_string(after_name, self.value, value_encoded_length);
152 Ok(&*representation)
153 }
154
155 fn name_index(&self) -> u64 {
156 match self.name {
157 HpackLiteralName::Indexed(index) => index,
158 HpackLiteralName::Literal { .. } => 0,
159 }
160 }
161
162 fn literal_name(&self) -> Option<HpackLiteralValue<'b>> {
163 match self.name {
164 HpackLiteralName::Indexed(_) => None,
165 HpackLiteralName::Literal {
166 encoded_bytes,
167 huffman,
168 } => Some(HpackLiteralValue::new_encoded(encoded_bytes, huffman)),
169 }
170 }
171}
172
173pub struct HpackDynamicTableSizeUpdateBuilder<'a> {
175 destination: &'a mut [u8],
176 size: u64,
177}
178
179impl<'a> HpackDynamicTableSizeUpdateBuilder<'a> {
180 pub fn new(destination: &'a mut [u8], size: u64) -> Self {
182 Self { destination, size }
183 }
184
185 pub fn build(self) -> Result<&'a [u8], HpackRepresentationBuildError> {
187 let required = canonical_encoded_len(self.size, 0x1f);
188 check_capacity(self.destination.len(), required)?;
189 let representation = &mut self.destination[..required];
190 write_integer(representation, 5, 0x1f, 0x20, self.size);
191 Ok(&*representation)
192 }
193}
194
195#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197pub enum HpackRepresentationBuildError {
198 IndexedFieldZero,
200
201 LiteralNameIndexZero,
203
204 LiteralName(HpackStringLiteralBuildError),
206 LiteralValue(HpackStringLiteralBuildError),
208 TotalLengthOverflow,
210 BufferTooShort {
212 required: usize,
214 available: usize,
216 },
217}
218
219impl fmt::Display for HpackRepresentationBuildError {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 match self {
222 Self::IndexedFieldZero => f.write_str("HPACK indexed field index must not be zero"),
223 Self::LiteralNameIndexZero => {
224 f.write_str("HPACK literal indexed name must not use index zero")
225 }
226
227 Self::LiteralName(error) => write!(f, "could not build HPACK literal name: {error}"),
228 Self::LiteralValue(error) => write!(f, "could not build HPACK literal value: {error}"),
229 Self::TotalLengthOverflow => f.write_str("HPACK representation length overflows usize"),
230 Self::BufferTooShort {
231 required,
232 available,
233 } => write!(
234 f,
235 "HPACK representation buffer is too short: need {required} bytes, have {available}"
236 ),
237 }
238 }
239}
240
241fn check_capacity(available: usize, required: usize) -> Result<(), HpackRepresentationBuildError> {
242 if available < required {
243 return Err(HpackRepresentationBuildError::BufferTooShort {
244 required,
245 available,
246 });
247 }
248 Ok(())
249}
250
251fn string_info(value: HpackLiteralValue<'_>) -> Result<(usize, u64), HpackStringLiteralBuildError> {
252 let encoded_length = u64::try_from(value.encoded_bytes.len()).map_err(|_| {
253 HpackStringLiteralBuildError::EncodedLengthNotRepresentable {
254 encoded_length: value.encoded_bytes.len(),
255 }
256 })?;
257 let length_length = canonical_encoded_len(encoded_length, 0x7f);
258 let total = length_length.checked_add(value.encoded_bytes.len()).ok_or(
259 HpackStringLiteralBuildError::TotalLengthOverflow {
260 length_length,
261 encoded_length: value.encoded_bytes.len(),
262 },
263 )?;
264 Ok((total, encoded_length))
265}
266
267fn write_string(destination: &mut [u8], value: HpackLiteralValue<'_>, encoded_length: u64) {
268 let length_length = canonical_encoded_len(encoded_length, 0x7f);
269 let (length_destination, payload_destination) = destination.split_at_mut(length_length);
270 write_integer(
271 length_destination,
272 7,
273 0x7f,
274 if value.huffman { 0x80 } else { 0 },
275 encoded_length,
276 );
277 payload_destination.copy_from_slice(value.encoded_bytes);
278}
279
280fn write_integer(
281 destination: &mut [u8],
282 prefix_bits: u8,
283 prefix_mask: u8,
284 high_bits: u8,
285 value: u64,
286) {
287 write_canonical_for_valid_prefix(destination, prefix_bits, prefix_mask, high_bits, value);
288}
289
290const fn prefix_mask(prefix_bits: u8) -> u8 {
291 (1 << prefix_bits) - 1
292}