1use core::fmt;
4
5use super::integer::{
6 HpackInteger, HpackIntegerParseError, canonical_encoded_len, canonical_integer,
7 write_canonical_for_valid_prefix,
8};
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub struct HpackStringLiteral<'a> {
13 bytes: &'a [u8],
14 length: HpackInteger<'a>,
15}
16
17impl<'a> HpackStringLiteral<'a> {
18 pub fn parse(bytes: &'a [u8]) -> Result<Self, HpackStringLiteralParseError> {
20 let length =
21 HpackInteger::parse(bytes, 7).map_err(HpackStringLiteralParseError::InvalidLength)?;
22 let encoded_length = usize::try_from(length.value()).map_err(|_| {
23 HpackStringLiteralParseError::EncodedLengthNotRepresentable {
24 encoded_length: length.value(),
25 }
26 })?;
27 let length_length = length.as_bytes().len();
28 let total = length_length.checked_add(encoded_length).ok_or(
29 HpackStringLiteralParseError::TotalLengthOverflow {
30 length_length,
31 encoded_length,
32 },
33 )?;
34 if bytes.len() < total {
35 return Err(HpackStringLiteralParseError::IncompleteEncodedPayload {
36 required: encoded_length,
37 available: bytes.len() - length_length,
38 });
39 }
40
41 Ok(Self {
42 bytes: &bytes[..total],
43 length,
44 })
45 }
46
47 pub const fn as_bytes(self) -> &'a [u8] {
49 self.bytes
50 }
51
52 pub const fn is_huffman(self) -> bool {
54 self.length.high_bits() != 0
55 }
56
57 pub fn encoded_bytes(self) -> &'a [u8] {
59 &self.bytes[self.length.as_bytes().len()..]
60 }
61
62 pub const fn length(self) -> HpackInteger<'a> {
64 self.length
65 }
66}
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub enum HpackStringLiteralParseError {
71 InvalidLength(HpackIntegerParseError),
73 EncodedLengthNotRepresentable {
75 encoded_length: u64,
77 },
78 TotalLengthOverflow {
80 length_length: usize,
82 encoded_length: usize,
84 },
85 IncompleteEncodedPayload {
87 required: usize,
89 available: usize,
91 },
92}
93
94impl fmt::Display for HpackStringLiteralParseError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 Self::InvalidLength(error) => write!(f, "invalid HPACK string length: {error}"),
98 Self::EncodedLengthNotRepresentable { encoded_length } => write!(
99 f,
100 "HPACK string encoded length {encoded_length} cannot be represented as usize"
101 ),
102 Self::TotalLengthOverflow {
103 length_length,
104 encoded_length,
105 } => write!(
106 f,
107 "HPACK string total length overflows usize: length uses {length_length} bytes and payload is {encoded_length} bytes"
108 ),
109 Self::IncompleteEncodedPayload {
110 required,
111 available,
112 } => write!(
113 f,
114 "HPACK string encoded payload is incomplete: need {required} bytes, have {available}"
115 ),
116 }
117 }
118}
119
120pub struct HpackStringLiteralBuilder<'a, 'b> {
122 destination: &'a mut [u8],
123 huffman: bool,
124 encoded_bytes: &'b [u8],
125}
126
127impl<'a, 'b> HpackStringLiteralBuilder<'a, 'b> {
128 pub fn new_encoded(destination: &'a mut [u8], huffman: bool, encoded_bytes: &'b [u8]) -> Self {
132 Self {
133 destination,
134 huffman,
135 encoded_bytes,
136 }
137 }
138
139 pub fn build(self) -> Result<HpackStringLiteral<'a>, HpackStringLiteralBuildError> {
141 let encoded_length = u64::try_from(self.encoded_bytes.len()).map_err(|_| {
142 HpackStringLiteralBuildError::EncodedLengthNotRepresentable {
143 encoded_length: self.encoded_bytes.len(),
144 }
145 })?;
146 let length_length = canonical_encoded_len(encoded_length, 0x7f);
147 let total = length_length.checked_add(self.encoded_bytes.len()).ok_or(
148 HpackStringLiteralBuildError::TotalLengthOverflow {
149 length_length,
150 encoded_length: self.encoded_bytes.len(),
151 },
152 )?;
153 if self.destination.len() < total {
154 return Err(HpackStringLiteralBuildError::BufferTooShort {
155 required: total,
156 available: self.destination.len(),
157 });
158 }
159
160 let literal = &mut self.destination[..total];
161 let (length_destination, payload_destination) = literal.split_at_mut(length_length);
162 write_canonical_for_valid_prefix(
163 length_destination,
164 7,
165 0x7f,
166 if self.huffman { 0x80 } else { 0 },
167 encoded_length,
168 );
169 payload_destination.copy_from_slice(self.encoded_bytes);
170
171 let bytes = &*literal;
172 Ok(HpackStringLiteral {
173 bytes,
174 length: canonical_integer(
175 &bytes[..length_length],
176 7,
177 if self.huffman { 0x80 } else { 0 },
178 encoded_length,
179 ),
180 })
181 }
182}
183
184#[derive(Clone, Copy, Debug, Eq, PartialEq)]
186pub enum HpackStringLiteralBuildError {
187 EncodedLengthNotRepresentable {
189 encoded_length: usize,
191 },
192 TotalLengthOverflow {
194 length_length: usize,
196 encoded_length: usize,
198 },
199 BufferTooShort {
201 required: usize,
203 available: usize,
205 },
206}
207
208impl fmt::Display for HpackStringLiteralBuildError {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 Self::EncodedLengthNotRepresentable { encoded_length } => write!(
212 f,
213 "HPACK string encoded length {encoded_length} cannot be represented as u64"
214 ),
215 Self::TotalLengthOverflow {
216 length_length,
217 encoded_length,
218 } => write!(
219 f,
220 "HPACK string total length overflows usize: length uses {length_length} bytes and payload is {encoded_length} bytes"
221 ),
222 Self::BufferTooShort {
223 required,
224 available,
225 } => write!(
226 f,
227 "HPACK string buffer is too short: need {required} bytes, have {available}"
228 ),
229 }
230 }
231}