1use core::fmt;
4
5use crate::qpack::stream::decoder::{
6 QpackDecoderInstruction, QpackDecoderInstructions, QpackDecoderInstructionsParseError,
7};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub struct QpackEncoderOutstandingSection {
15 stream_id: u64,
16 required_insert_count: u64,
17 reference_start: usize,
18 reference_len: usize,
19}
20
21impl QpackEncoderOutstandingSection {
22 pub const EMPTY: Self = Self {
24 stream_id: 0,
25 required_insert_count: 0,
26 reference_start: 0,
27 reference_len: 0,
28 };
29
30 pub const fn stream_id(self) -> u64 {
32 self.stream_id
33 }
34
35 pub const fn required_insert_count(self) -> u64 {
37 self.required_insert_count
38 }
39
40 pub const fn reference_len(self) -> usize {
42 self.reference_len
43 }
44}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum QpackEncoderStateError {
49 RequiredInsertCountMismatch {
51 required_insert_count: u64,
53 expected_required_insert_count: u64,
55 },
56 RequiredInsertCountOverflow {
58 absolute_index: u64,
60 },
61 RequiredInsertCountExceedsInsertCount {
63 required_insert_count: u64,
65 encoder_insert_count: u64,
67 },
68 SectionStorageExhausted {
70 capacity: usize,
72 },
73 ReferenceStorageTooShort {
75 required: usize,
77 available: usize,
79 },
80 BlockedStreamsLimitExceeded {
82 maximum: u64,
84 },
85}
86
87impl QpackEncoderStateError {
88 pub const fn is_provisioning_error(self) -> bool {
90 matches!(
91 self,
92 Self::SectionStorageExhausted { .. } | Self::ReferenceStorageTooShort { .. }
93 )
94 }
95
96 pub const fn is_blocked_streams_limit_error(self) -> bool {
98 matches!(self, Self::BlockedStreamsLimitExceeded { .. })
99 }
100}
101
102impl fmt::Display for QpackEncoderStateError {
103 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Self::RequiredInsertCountMismatch {
106 required_insert_count,
107 expected_required_insert_count,
108 } => write!(
109 formatter,
110 "Required Insert Count {required_insert_count} does not match expected count {expected_required_insert_count}"
111 ),
112 Self::RequiredInsertCountOverflow { absolute_index } => write!(
113 formatter,
114 "Required Insert Count overflows u64 for absolute index {absolute_index}"
115 ),
116 Self::RequiredInsertCountExceedsInsertCount {
117 required_insert_count,
118 encoder_insert_count,
119 } => write!(
120 formatter,
121 "Required Insert Count {required_insert_count} exceeds encoder insert count {encoder_insert_count}"
122 ),
123 Self::SectionStorageExhausted { capacity } => {
124 write!(
125 formatter,
126 "section storage capacity {capacity} is exhausted"
127 )
128 }
129 Self::ReferenceStorageTooShort {
130 required,
131 available,
132 } => write!(
133 formatter,
134 "reference storage requires {required} slots but only {available} remain"
135 ),
136 Self::BlockedStreamsLimitExceeded { maximum } => {
137 write!(formatter, "blocked streams exceed maximum {maximum}")
138 }
139 }
140 }
141}
142
143impl core::error::Error for QpackEncoderStateError {}
144
145#[derive(Clone, Copy, Debug, Eq, PartialEq)]
147pub enum QpackDecoderInstructionApplyError {
148 SectionAcknowledgmentWithoutOutstandingReferences {
150 stream_id: u64,
152 },
153 InsertCountIncrementZero,
155 InsertCountIncrementExceedsInsertCount {
157 known_received_count: u64,
159 increment: u64,
161 encoder_insert_count: u64,
163 },
164}
165
166impl QpackDecoderInstructionApplyError {
167 pub const fn is_decoder_stream_error(self) -> bool {
169 true
170 }
171}
172
173impl fmt::Display for QpackDecoderInstructionApplyError {
174 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
175 match self {
176 Self::SectionAcknowledgmentWithoutOutstandingReferences { stream_id } => write!(
177 formatter,
178 "Section Acknowledgment stream {stream_id} has no outstanding dynamic references"
179 ),
180 Self::InsertCountIncrementZero => {
181 formatter.write_str("Insert Count Increment must be greater than zero")
182 }
183 Self::InsertCountIncrementExceedsInsertCount {
184 known_received_count,
185 increment,
186 encoder_insert_count,
187 } => write!(
188 formatter,
189 "Insert Count Increment {increment} from Known Received Count {known_received_count} exceeds encoder insert count {encoder_insert_count}"
190 ),
191 }
192 }
193}
194
195impl core::error::Error for QpackDecoderInstructionApplyError {}
196
197#[derive(Clone, Copy, Debug, Eq, PartialEq)]
199pub enum QpackDecoderInstructionsApplyError {
200 Parse(QpackDecoderInstructionsParseError),
202 Apply {
204 offset: usize,
206 error: QpackDecoderInstructionApplyError,
208 },
209}
210
211impl QpackDecoderInstructionsApplyError {
212 pub const fn is_decoder_stream_error(self) -> bool {
214 match self {
215 Self::Parse(_) => true,
216 Self::Apply { error, .. } => error.is_decoder_stream_error(),
217 }
218 }
219}
220
221impl fmt::Display for QpackDecoderInstructionsApplyError {
222 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
223 match self {
224 Self::Parse(error) => write!(
225 formatter,
226 "QPACK decoder instruction sequence is invalid: {error}"
227 ),
228 Self::Apply { offset, error } => write!(
229 formatter,
230 "QPACK decoder instruction application failed at byte {offset}: {error}"
231 ),
232 }
233 }
234}
235
236impl core::error::Error for QpackDecoderInstructionsApplyError {}
237
238pub struct QpackEncoderState<'sections, 'references> {
245 sections: &'sections mut [QpackEncoderOutstandingSection],
246 references: &'references mut [u64],
247 section_len: usize,
248 reference_len: usize,
249 known_received_count: u64,
250 maximum_blocked_streams: u64,
251}
252
253pub(in crate::qpack) struct QpackEncoderStateRegistration<'state, 'sections, 'references, 'input> {
258 state: &'state mut QpackEncoderState<'sections, 'references>,
259 stream_id: u64,
260 required_insert_count: u64,
261 absolute_references: &'input [u64],
262 reference_start: usize,
263}
264
265impl<'state, 'sections, 'references, 'input>
266 QpackEncoderStateRegistration<'state, 'sections, 'references, 'input>
267{
268 pub(in crate::qpack) fn commit(self) {
270 if self.absolute_references.is_empty() {
271 return;
272 }
273
274 let reference_end = self.reference_start + self.absolute_references.len();
275 self.state.references[self.reference_start..reference_end]
276 .copy_from_slice(self.absolute_references);
277 self.state.sections[self.state.section_len] = QpackEncoderOutstandingSection {
278 stream_id: self.stream_id,
279 required_insert_count: self.required_insert_count,
280 reference_start: self.reference_start,
281 reference_len: self.absolute_references.len(),
282 };
283 self.state.reference_len += self.absolute_references.len();
284 self.state.section_len += 1;
285 }
286}
287
288impl<'sections, 'references> QpackEncoderState<'sections, 'references> {
289 pub fn new(
291 sections: &'sections mut [QpackEncoderOutstandingSection],
292 references: &'references mut [u64],
293 maximum_blocked_streams: u64,
294 ) -> Self {
295 for section in sections.iter_mut() {
296 *section = QpackEncoderOutstandingSection::EMPTY;
297 }
298 for reference in references.iter_mut() {
299 *reference = 0;
300 }
301 Self {
302 sections,
303 references,
304 section_len: 0,
305 reference_len: 0,
306 known_received_count: 0,
307 maximum_blocked_streams,
308 }
309 }
310
311 pub const fn known_received_count(&self) -> u64 {
313 self.known_received_count
314 }
315
316 pub const fn maximum_blocked_streams(&self) -> u64 {
318 self.maximum_blocked_streams
319 }
320
321 pub const fn len(&self) -> usize {
323 self.section_len
324 }
325
326 pub const fn is_empty(&self) -> bool {
328 self.section_len == 0
329 }
330
331 pub const fn reference_len(&self) -> usize {
333 self.reference_len
334 }
335
336 pub const fn section_storage_capacity(&self) -> usize {
338 self.sections.len()
339 }
340
341 pub const fn reference_storage_capacity(&self) -> usize {
343 self.references.len()
344 }
345
346 pub fn blocked_stream_count(&self) -> usize {
348 let mut count = 0;
349 for (index, section) in self.sections[..self.section_len].iter().enumerate() {
350 if section.required_insert_count > self.known_received_count
351 && !self.sections[..index].iter().any(|previous| {
352 previous.required_insert_count > self.known_received_count
353 && previous.stream_id == section.stream_id
354 })
355 {
356 count += 1;
357 }
358 }
359 count
360 }
361
362 pub fn register(
368 &mut self,
369 stream_id: u64,
370 required_insert_count: u64,
371 absolute_references: &[u64],
372 encoder_insert_count: u64,
373 ) -> Result<(), QpackEncoderStateError> {
374 self.reserve_registration(
375 stream_id,
376 required_insert_count,
377 absolute_references,
378 encoder_insert_count,
379 )?
380 .commit();
381 Ok(())
382 }
383
384 pub(in crate::qpack) fn reserve_registration<'input>(
386 &mut self,
387 stream_id: u64,
388 required_insert_count: u64,
389 absolute_references: &'input [u64],
390 encoder_insert_count: u64,
391 ) -> Result<
392 QpackEncoderStateRegistration<'_, 'sections, 'references, 'input>,
393 QpackEncoderStateError,
394 > {
395 if absolute_references.is_empty() {
396 if required_insert_count == 0 {
397 let reference_start = self.reference_len;
398 return Ok(QpackEncoderStateRegistration {
399 state: self,
400 stream_id,
401 required_insert_count,
402 absolute_references,
403 reference_start,
404 });
405 }
406 return Err(QpackEncoderStateError::RequiredInsertCountMismatch {
407 required_insert_count,
408 expected_required_insert_count: 0,
409 });
410 }
411
412 let mut largest = absolute_references[0];
413 for &absolute_index in &absolute_references[1..] {
414 if absolute_index > largest {
415 largest = absolute_index;
416 }
417 }
418 let expected_required_insert_count =
419 largest
420 .checked_add(1)
421 .ok_or(QpackEncoderStateError::RequiredInsertCountOverflow {
422 absolute_index: largest,
423 })?;
424 if required_insert_count != expected_required_insert_count {
425 return Err(QpackEncoderStateError::RequiredInsertCountMismatch {
426 required_insert_count,
427 expected_required_insert_count,
428 });
429 }
430 if required_insert_count > encoder_insert_count {
431 return Err(
432 QpackEncoderStateError::RequiredInsertCountExceedsInsertCount {
433 required_insert_count,
434 encoder_insert_count,
435 },
436 );
437 }
438 if self.section_len == self.sections.len() {
439 return Err(QpackEncoderStateError::SectionStorageExhausted {
440 capacity: self.sections.len(),
441 });
442 }
443
444 let available_references = self.references.len() - self.reference_len;
445 if absolute_references.len() > available_references {
446 return Err(QpackEncoderStateError::ReferenceStorageTooShort {
447 required: absolute_references.len(),
448 available: available_references,
449 });
450 }
451
452 let could_block = required_insert_count > self.known_received_count;
453 let stream_already_risks_blocking = could_block
454 && self.sections[..self.section_len].iter().any(|section| {
455 section.stream_id == stream_id
456 && section.required_insert_count > self.known_received_count
457 });
458 if could_block && !stream_already_risks_blocking {
459 let blocked_stream_count = self.blocked_stream_count();
460 if u64::try_from(blocked_stream_count)
461 .map_or(true, |count| count >= self.maximum_blocked_streams)
462 {
463 return Err(QpackEncoderStateError::BlockedStreamsLimitExceeded {
464 maximum: self.maximum_blocked_streams,
465 });
466 }
467 }
468
469 let reference_start = self.reference_len;
470 Ok(QpackEncoderStateRegistration {
471 state: self,
472 stream_id,
473 required_insert_count,
474 absolute_references,
475 reference_start,
476 })
477 }
478
479 pub fn apply(
484 &mut self,
485 instruction: QpackDecoderInstruction<'_>,
486 encoder_insert_count: u64,
487 ) -> Result<(), QpackDecoderInstructionApplyError> {
488 match instruction {
489 QpackDecoderInstruction::SectionAcknowledgment(acknowledgment) => {
490 let stream_id = acknowledgment.stream_id().value();
491 let section_index = self.sections[..self.section_len]
492 .iter()
493 .position(|section| section.stream_id == stream_id)
494 .ok_or(
495 QpackDecoderInstructionApplyError::SectionAcknowledgmentWithoutOutstandingReferences {
496 stream_id,
497 },
498 )?;
499 self.known_received_count = self
500 .known_received_count
501 .max(self.sections[section_index].required_insert_count);
502 self.remove_section(section_index);
503 Ok(())
504 }
505 QpackDecoderInstruction::StreamCancellation(cancellation) => {
506 let stream_id = cancellation.stream_id().value();
507 let mut section_index = 0;
508 while section_index < self.section_len {
509 if self.sections[section_index].stream_id == stream_id {
510 self.remove_section(section_index);
511 } else {
512 section_index += 1;
513 }
514 }
515 Ok(())
516 }
517 QpackDecoderInstruction::InsertCountIncrement(increment) => {
518 let increment = increment.increment().value();
519 if increment == 0 {
520 return Err(QpackDecoderInstructionApplyError::InsertCountIncrementZero);
521 }
522
523 let known_received_count = self.known_received_count;
524 let Some(next_known_received_count) = known_received_count.checked_add(increment)
525 else {
526 return Err(
527 QpackDecoderInstructionApplyError::InsertCountIncrementExceedsInsertCount {
528 known_received_count,
529 increment,
530 encoder_insert_count,
531 },
532 );
533 };
534 if next_known_received_count > encoder_insert_count {
535 return Err(
536 QpackDecoderInstructionApplyError::InsertCountIncrementExceedsInsertCount {
537 known_received_count,
538 increment,
539 encoder_insert_count,
540 },
541 );
542 }
543 self.known_received_count = next_known_received_count;
544 Ok(())
545 }
546 }
547 }
548
549 pub fn apply_sequence(
556 &mut self,
557 bytes: &[u8],
558 encoder_insert_count: u64,
559 ) -> Result<(), QpackDecoderInstructionsApplyError> {
560 let instructions = QpackDecoderInstructions::parse(bytes)
561 .map_err(QpackDecoderInstructionsApplyError::Parse)?;
562 let mut offset = 0usize;
563
564 for instruction in instructions.iter() {
565 let instruction = instruction.map_err(QpackDecoderInstructionsApplyError::Parse)?;
566 self.apply(instruction, encoder_insert_count)
567 .map_err(|error| QpackDecoderInstructionsApplyError::Apply { offset, error })?;
568 offset += instruction.as_bytes().len();
569 }
570
571 Ok(())
572 }
573
574 fn remove_section(&mut self, section_index: usize) {
575 let removed = self.sections[section_index];
576 let reference_end = removed.reference_start + removed.reference_len;
577 self.references
578 .copy_within(reference_end..self.reference_len, removed.reference_start);
579 for section in &mut self.sections[section_index + 1..self.section_len] {
580 section.reference_start -= removed.reference_len;
581 }
582 self.sections
583 .copy_within(section_index + 1..self.section_len, section_index);
584
585 self.section_len -= 1;
586 self.reference_len -= removed.reference_len;
587 self.sections[self.section_len] = QpackEncoderOutstandingSection::EMPTY;
588 self.references[self.reference_len..self.reference_len + removed.reference_len].fill(0);
589 }
590
591 pub fn is_evictable(&self, absolute_index: u64) -> bool {
593 self.known_received_count > absolute_index
594 && !self.references[..self.reference_len].contains(&absolute_index)
595 }
596}