1use core::fmt;
4
5use super::{
6 QpackIndexedFieldLine, QpackIndexedPostBaseFieldLine, QpackLiteralNameFieldLine,
7 QpackLiteralNameReferenceFieldLine, QpackLiteralPostBaseNameReferenceFieldLine,
8};
9use crate::qpack::integer::{
10 QPACK_INTEGER_MAX, QpackIntegerBuildError, canonical_encoded_len, integer_from_prevalidated,
11 write_canonical_prevalidated,
12};
13use crate::qpack::string::{
14 QpackStringLiteralBuildError, QpackStringLiteralPlan, string_from_prevalidated, string_plan,
15 write_string_prevalidated,
16};
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum QpackFieldLineBuildError {
21 IndexedIndex(#[doc = "The nested integer failure."] QpackIntegerBuildError),
23 IndexedPostBaseIndex(#[doc = "The nested integer failure."] QpackIntegerBuildError),
25 LiteralNameReferenceNameIndex(#[doc = "The nested integer failure."] QpackIntegerBuildError),
27 LiteralNameReferenceValue(
29 #[doc = "The nested string-literal failure."] QpackStringLiteralBuildError,
30 ),
31 LiteralPostBaseNameReferenceNameIndex(
33 #[doc = "The nested integer failure."] QpackIntegerBuildError,
34 ),
35 LiteralPostBaseNameReferenceValue(
37 #[doc = "The nested string-literal failure."] QpackStringLiteralBuildError,
38 ),
39 LiteralNameName(#[doc = "The nested string-literal failure."] QpackStringLiteralBuildError),
41 LiteralNameValue(#[doc = "The nested string-literal failure."] QpackStringLiteralBuildError),
43 RequiredLengthOverflow,
45 BufferTooShort {
47 required: usize,
49 available: usize,
51 },
52}
53
54impl fmt::Display for QpackFieldLineBuildError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::IndexedIndex(error) => {
58 write!(f, "QPACK Indexed Field Line index cannot be built: {error}")
59 }
60 Self::IndexedPostBaseIndex(error) => write!(
61 f,
62 "QPACK Indexed Field Line With Post-Base Index cannot be built: {error}"
63 ),
64 Self::LiteralNameReferenceNameIndex(error) => write!(
65 f,
66 "QPACK Literal Field Line With Name Reference name index cannot be built: {error}"
67 ),
68 Self::LiteralNameReferenceValue(error) => write!(
69 f,
70 "QPACK Literal Field Line With Name Reference value cannot be built: {error}"
71 ),
72 Self::LiteralPostBaseNameReferenceNameIndex(error) => write!(
73 f,
74 "QPACK Literal Field Line With Post-Base Name Reference name index cannot be built: {error}"
75 ),
76 Self::LiteralPostBaseNameReferenceValue(error) => write!(
77 f,
78 "QPACK Literal Field Line With Post-Base Name Reference value cannot be built: {error}"
79 ),
80 Self::LiteralNameName(error) => write!(
81 f,
82 "QPACK Literal Field Line With Literal Name name cannot be built: {error}"
83 ),
84 Self::LiteralNameValue(error) => write!(
85 f,
86 "QPACK Literal Field Line With Literal Name value cannot be built: {error}"
87 ),
88 Self::RequiredLengthOverflow => {
89 f.write_str("QPACK field-line required length overflows usize")
90 }
91 Self::BufferTooShort {
92 required,
93 available,
94 } => write!(
95 f,
96 "QPACK field-line buffer is too short: need {required} bytes, have {available}"
97 ),
98 }
99 }
100}
101
102#[derive(Clone, Copy, Debug, Eq, PartialEq)]
108pub(crate) enum QpackFieldLinePlanInput<'a> {
109 IndexedStatic {
110 index: u64,
111 },
112 IndexedDynamicPreBase {
113 relative_index: u64,
114 },
115 IndexedDynamicPostBase {
116 post_base_index: u64,
117 },
118 LiteralStaticNameReference {
119 never_indexed: bool,
120 index: u64,
121 value_huffman: bool,
122 encoded_value: &'a [u8],
123 },
124 LiteralDynamicPreBaseNameReference {
125 never_indexed: bool,
126 relative_index: u64,
127 value_huffman: bool,
128 encoded_value: &'a [u8],
129 },
130 LiteralDynamicPostBaseNameReference {
131 never_indexed: bool,
132 post_base_index: u64,
133 value_huffman: bool,
134 encoded_value: &'a [u8],
135 },
136 LiteralName {
137 never_indexed: bool,
138 name_huffman: bool,
139 encoded_name: &'a [u8],
140 value_huffman: bool,
141 encoded_value: &'a [u8],
142 },
143}
144
145#[derive(Clone, Copy)]
147pub(crate) struct QpackFieldLinePlan<'a> {
148 kind: QpackFieldLinePlanKind<'a>,
149 encoded_len: usize,
150}
151
152#[derive(Clone, Copy)]
153enum QpackFieldLinePlanKind<'a> {
154 Integer {
155 prefix_bits: u8,
156 high_bits: u8,
157 value: u64,
158 },
159 NameReference {
160 prefix_bits: u8,
161 high_bits: u8,
162 index: u64,
163 index_len: usize,
164 value: QpackStringLiteralPlan<'a>,
165 },
166 LiteralName {
167 name: QpackStringLiteralPlan<'a>,
168 value: QpackStringLiteralPlan<'a>,
169 },
170}
171
172impl QpackFieldLinePlan<'_> {
173 pub(crate) const fn empty() -> Self {
175 Self {
176 kind: QpackFieldLinePlanKind::Integer {
177 prefix_bits: 6,
178 high_bits: 0xc0,
179 value: 0,
180 },
181 encoded_len: 1,
182 }
183 }
184
185 pub(crate) const fn encoded_len(self) -> usize {
187 self.encoded_len
188 }
189
190 pub(crate) fn write(self, destination: &mut [u8]) {
197 if destination.len() != self.encoded_len {
198 return;
199 }
200
201 match self.kind {
202 QpackFieldLinePlanKind::Integer {
203 prefix_bits,
204 high_bits,
205 value,
206 } => write_canonical_prevalidated(destination, prefix_bits, high_bits, value),
207 QpackFieldLinePlanKind::NameReference {
208 prefix_bits,
209 high_bits,
210 index,
211 index_len,
212 value,
213 } => {
214 let (index_destination, value_destination) = destination.split_at_mut(index_len);
215 write_canonical_prevalidated(index_destination, prefix_bits, high_bits, index);
216 write_string_prevalidated(value_destination, value);
217 }
218 QpackFieldLinePlanKind::LiteralName { name, value } => {
219 let (name_destination, value_destination) =
220 destination.split_at_mut(name.required());
221 write_string_prevalidated(name_destination, name);
222 write_string_prevalidated(value_destination, value);
223 }
224 }
225 }
226}
227
228pub(crate) fn plan_field_line(
230 input: QpackFieldLinePlanInput<'_>,
231) -> Result<QpackFieldLinePlan<'_>, QpackFieldLineBuildError> {
232 match input {
233 QpackFieldLinePlanInput::IndexedStatic { index } => {
234 plan_integer(index, 6, 0xc0, QpackFieldLineBuildError::IndexedIndex)
235 }
236 QpackFieldLinePlanInput::IndexedDynamicPreBase { relative_index } => plan_integer(
237 relative_index,
238 6,
239 0x80,
240 QpackFieldLineBuildError::IndexedIndex,
241 ),
242 QpackFieldLinePlanInput::IndexedDynamicPostBase { post_base_index } => plan_integer(
243 post_base_index,
244 4,
245 0x10,
246 QpackFieldLineBuildError::IndexedPostBaseIndex,
247 ),
248 QpackFieldLinePlanInput::LiteralStaticNameReference {
249 never_indexed,
250 index,
251 value_huffman,
252 encoded_value,
253 } => plan_name_reference(
254 index,
255 4,
256 0x50 | if never_indexed { 0x20 } else { 0 },
257 value_huffman,
258 encoded_value,
259 QpackFieldLineBuildError::LiteralNameReferenceNameIndex,
260 QpackFieldLineBuildError::LiteralNameReferenceValue,
261 ),
262 QpackFieldLinePlanInput::LiteralDynamicPreBaseNameReference {
263 never_indexed,
264 relative_index,
265 value_huffman,
266 encoded_value,
267 } => plan_name_reference(
268 relative_index,
269 4,
270 0x40 | if never_indexed { 0x20 } else { 0 },
271 value_huffman,
272 encoded_value,
273 QpackFieldLineBuildError::LiteralNameReferenceNameIndex,
274 QpackFieldLineBuildError::LiteralNameReferenceValue,
275 ),
276 QpackFieldLinePlanInput::LiteralDynamicPostBaseNameReference {
277 never_indexed,
278 post_base_index,
279 value_huffman,
280 encoded_value,
281 } => plan_name_reference(
282 post_base_index,
283 3,
284 if never_indexed { 0x08 } else { 0 },
285 value_huffman,
286 encoded_value,
287 QpackFieldLineBuildError::LiteralPostBaseNameReferenceNameIndex,
288 QpackFieldLineBuildError::LiteralPostBaseNameReferenceValue,
289 ),
290 QpackFieldLinePlanInput::LiteralName {
291 never_indexed,
292 name_huffman,
293 encoded_name,
294 value_huffman,
295 encoded_value,
296 } => {
297 let name = string_plan(
298 4,
299 0x20 | if never_indexed { 0x10 } else { 0 },
300 name_huffman,
301 encoded_name,
302 )
303 .map_err(QpackFieldLineBuildError::LiteralNameName)?;
304 let value = string_plan(8, 0, value_huffman, encoded_value)
305 .map_err(QpackFieldLineBuildError::LiteralNameValue)?;
306 let encoded_len = checked_sum(name.required(), value.required())?;
307 Ok(QpackFieldLinePlan {
308 kind: QpackFieldLinePlanKind::LiteralName { name, value },
309 encoded_len,
310 })
311 }
312 }
313}
314
315fn plan_integer(
316 value: u64,
317 prefix_bits: u8,
318 high_bits: u8,
319 error: fn(QpackIntegerBuildError) -> QpackFieldLineBuildError,
320) -> Result<QpackFieldLinePlan<'static>, QpackFieldLineBuildError> {
321 let encoded_len = integer_length(value, prefix_bits).map_err(error)?;
322 Ok(QpackFieldLinePlan {
323 kind: QpackFieldLinePlanKind::Integer {
324 prefix_bits,
325 high_bits,
326 value,
327 },
328 encoded_len,
329 })
330}
331
332fn plan_name_reference<'a>(
333 index: u64,
334 prefix_bits: u8,
335 high_bits: u8,
336 value_huffman: bool,
337 encoded_value: &'a [u8],
338 index_error: fn(QpackIntegerBuildError) -> QpackFieldLineBuildError,
339 value_error: fn(QpackStringLiteralBuildError) -> QpackFieldLineBuildError,
340) -> Result<QpackFieldLinePlan<'a>, QpackFieldLineBuildError> {
341 let index_len = integer_length(index, prefix_bits).map_err(index_error)?;
342 let value = string_plan(8, 0, value_huffman, encoded_value).map_err(value_error)?;
343 let encoded_len = checked_sum(index_len, value.required())?;
344 Ok(QpackFieldLinePlan {
345 kind: QpackFieldLinePlanKind::NameReference {
346 prefix_bits,
347 high_bits,
348 index,
349 index_len,
350 value,
351 },
352 encoded_len,
353 })
354}
355
356pub struct QpackIndexedFieldLineBuilder<'buffer> {
358 destination: &'buffer mut [u8],
359 is_static: bool,
360 index: u64,
361}
362
363impl<'buffer> QpackIndexedFieldLineBuilder<'buffer> {
364 pub fn new(destination: &'buffer mut [u8], is_static: bool, index: u64) -> Self {
366 Self {
367 destination,
368 is_static,
369 index,
370 }
371 }
372
373 pub fn build(self) -> Result<QpackIndexedFieldLine<'buffer>, QpackFieldLineBuildError> {
375 let length =
376 integer_length(self.index, 6).map_err(QpackFieldLineBuildError::IndexedIndex)?;
377 ensure_capacity(self.destination, length)?;
378 let high_bits = 0x80 | if self.is_static { 0x40 } else { 0 };
379 write_canonical_prevalidated(&mut self.destination[..length], 6, high_bits, self.index);
380 let bytes = &self.destination[..length];
381 Ok(QpackIndexedFieldLine {
382 bytes,
383 index: integer_from_prevalidated(bytes, 6, high_bits, self.index),
384 })
385 }
386}
387
388pub struct QpackIndexedPostBaseFieldLineBuilder<'buffer> {
390 destination: &'buffer mut [u8],
391 index: u64,
392}
393
394impl<'buffer> QpackIndexedPostBaseFieldLineBuilder<'buffer> {
395 pub fn new(destination: &'buffer mut [u8], index: u64) -> Self {
397 Self { destination, index }
398 }
399
400 pub fn build(self) -> Result<QpackIndexedPostBaseFieldLine<'buffer>, QpackFieldLineBuildError> {
402 let length = integer_length(self.index, 4)
403 .map_err(QpackFieldLineBuildError::IndexedPostBaseIndex)?;
404 ensure_capacity(self.destination, length)?;
405 write_canonical_prevalidated(&mut self.destination[..length], 4, 0x10, self.index);
406 let bytes = &self.destination[..length];
407 Ok(QpackIndexedPostBaseFieldLine {
408 bytes,
409 index: integer_from_prevalidated(bytes, 4, 0x10, self.index),
410 })
411 }
412}
413
414pub struct QpackLiteralNameReferenceFieldLineBuilder<'buffer, 'value> {
416 destination: &'buffer mut [u8],
417 never_indexed: bool,
418 is_static: bool,
419 name_index: u64,
420 value_huffman: bool,
421 encoded_value: &'value [u8],
422}
423
424impl<'buffer, 'value> QpackLiteralNameReferenceFieldLineBuilder<'buffer, 'value> {
425 pub fn new(
429 destination: &'buffer mut [u8],
430 never_indexed: bool,
431 is_static: bool,
432 name_index: u64,
433 value_huffman: bool,
434 encoded_value: &'value [u8],
435 ) -> Self {
436 Self {
437 destination,
438 never_indexed,
439 is_static,
440 name_index,
441 value_huffman,
442 encoded_value,
443 }
444 }
445
446 pub fn build(
448 self,
449 ) -> Result<QpackLiteralNameReferenceFieldLine<'buffer>, QpackFieldLineBuildError> {
450 let name_length = integer_length(self.name_index, 4)
451 .map_err(QpackFieldLineBuildError::LiteralNameReferenceNameIndex)?;
452 let value_plan = string_plan(8, 0, self.value_huffman, self.encoded_value)
453 .map_err(QpackFieldLineBuildError::LiteralNameReferenceValue)?;
454 let required = checked_sum(name_length, value_plan.required())?;
455 ensure_capacity(self.destination, required)?;
456 let high_bits = 0x40
457 | if self.never_indexed { 0x20 } else { 0 }
458 | if self.is_static { 0x10 } else { 0 };
459 let (name_destination, value_destination) =
460 self.destination[..required].split_at_mut(name_length);
461 write_canonical_prevalidated(name_destination, 4, high_bits, self.name_index);
462 write_string_prevalidated(value_destination, value_plan);
463 let bytes = &self.destination[..required];
464 Ok(QpackLiteralNameReferenceFieldLine {
465 bytes,
466 name_index: integer_from_prevalidated(
467 &bytes[..name_length],
468 4,
469 high_bits,
470 self.name_index,
471 ),
472 value: string_from_prevalidated(&bytes[name_length..], value_plan),
473 })
474 }
475}
476
477pub struct QpackLiteralPostBaseNameReferenceFieldLineBuilder<'buffer, 'value> {
479 destination: &'buffer mut [u8],
480 never_indexed: bool,
481 name_index: u64,
482 value_huffman: bool,
483 encoded_value: &'value [u8],
484}
485
486impl<'buffer, 'value> QpackLiteralPostBaseNameReferenceFieldLineBuilder<'buffer, 'value> {
487 pub fn new(
491 destination: &'buffer mut [u8],
492 never_indexed: bool,
493 name_index: u64,
494 value_huffman: bool,
495 encoded_value: &'value [u8],
496 ) -> Self {
497 Self {
498 destination,
499 never_indexed,
500 name_index,
501 value_huffman,
502 encoded_value,
503 }
504 }
505
506 pub fn build(
508 self,
509 ) -> Result<QpackLiteralPostBaseNameReferenceFieldLine<'buffer>, QpackFieldLineBuildError> {
510 let name_length = integer_length(self.name_index, 3)
511 .map_err(QpackFieldLineBuildError::LiteralPostBaseNameReferenceNameIndex)?;
512 let value_plan = string_plan(8, 0, self.value_huffman, self.encoded_value)
513 .map_err(QpackFieldLineBuildError::LiteralPostBaseNameReferenceValue)?;
514 let required = checked_sum(name_length, value_plan.required())?;
515 ensure_capacity(self.destination, required)?;
516 let high_bits = if self.never_indexed { 0x08 } else { 0 };
517 let (name_destination, value_destination) =
518 self.destination[..required].split_at_mut(name_length);
519 write_canonical_prevalidated(name_destination, 3, high_bits, self.name_index);
520 write_string_prevalidated(value_destination, value_plan);
521 let bytes = &self.destination[..required];
522 Ok(QpackLiteralPostBaseNameReferenceFieldLine {
523 bytes,
524 name_index: integer_from_prevalidated(
525 &bytes[..name_length],
526 3,
527 high_bits,
528 self.name_index,
529 ),
530 value: string_from_prevalidated(&bytes[name_length..], value_plan),
531 })
532 }
533}
534
535pub struct QpackLiteralNameFieldLineBuilder<'buffer, 'name, 'value> {
537 destination: &'buffer mut [u8],
538 never_indexed: bool,
539 name_huffman: bool,
540 encoded_name: &'name [u8],
541 value_huffman: bool,
542 encoded_value: &'value [u8],
543}
544
545impl<'buffer, 'name, 'value> QpackLiteralNameFieldLineBuilder<'buffer, 'name, 'value> {
546 pub fn new(
550 destination: &'buffer mut [u8],
551 never_indexed: bool,
552 name_huffman: bool,
553 encoded_name: &'name [u8],
554 value_huffman: bool,
555 encoded_value: &'value [u8],
556 ) -> Self {
557 Self {
558 destination,
559 never_indexed,
560 name_huffman,
561 encoded_name,
562 value_huffman,
563 encoded_value,
564 }
565 }
566
567 pub fn build(self) -> Result<QpackLiteralNameFieldLine<'buffer>, QpackFieldLineBuildError> {
569 let name_high_bits = 0x20 | if self.never_indexed { 0x10 } else { 0 };
570 let name_plan = string_plan(4, name_high_bits, self.name_huffman, self.encoded_name)
571 .map_err(QpackFieldLineBuildError::LiteralNameName)?;
572 let value_plan = string_plan(8, 0, self.value_huffman, self.encoded_value)
573 .map_err(QpackFieldLineBuildError::LiteralNameValue)?;
574 let required = checked_sum(name_plan.required(), value_plan.required())?;
575 ensure_capacity(self.destination, required)?;
576 let (name_destination, value_destination) =
577 self.destination[..required].split_at_mut(name_plan.required());
578 write_string_prevalidated(name_destination, name_plan);
579 write_string_prevalidated(value_destination, value_plan);
580 let bytes = &self.destination[..required];
581 Ok(QpackLiteralNameFieldLine {
582 bytes,
583 name: string_from_prevalidated(&bytes[..name_plan.required()], name_plan),
584 value: string_from_prevalidated(&bytes[name_plan.required()..], value_plan),
585 })
586 }
587}
588
589fn integer_length(value: u64, prefix_bits: u8) -> Result<usize, QpackIntegerBuildError> {
590 if value > QPACK_INTEGER_MAX {
591 return Err(QpackIntegerBuildError::ValueTooLarge { value });
592 }
593 Ok(canonical_encoded_len(value, prefix_bits))
594}
595
596fn checked_sum(left: usize, right: usize) -> Result<usize, QpackFieldLineBuildError> {
597 left.checked_add(right)
598 .ok_or(QpackFieldLineBuildError::RequiredLengthOverflow)
599}
600
601fn ensure_capacity(destination: &[u8], required: usize) -> Result<(), QpackFieldLineBuildError> {
602 if destination.len() < required {
603 return Err(QpackFieldLineBuildError::BufferTooShort {
604 required,
605 available: destination.len(),
606 });
607 }
608 Ok(())
609}