sark-h2 0.13.0

HTTP/2 protocol primitives + client/server bootstrap for sark stack
Documentation
use core::convert::Infallible;

use sark_core::http::{HpackHuffmanEncoded, HpackHuffmanSource, PrefixedInt};

use super::DecoderError;

pub(super) const MAX_LITERAL_LEN: usize = 1 << 24;

pub(super) struct Literal<'a>(&'a [u8]);

pub(super) struct DecodedLiteral {
    pub(super) consumed: usize,
    pub(super) len: usize,
    pub(super) retained: bool,
}

impl<'a> Literal<'a> {
    pub(super) const fn new(bytes: &'a [u8]) -> Self {
        Self(bytes)
    }

    pub(super) fn encode(self, huffman: bool, out: &mut Vec<u8>) {
        if huffman {
            let source = HpackHuffmanSource::new(self.0);
            let len = source.encoded_len();
            PrefixedInt::<7>::new(len as u64).encode(0x80, out);
            source.encode(out);
        } else {
            PrefixedInt::<7>::new(self.0.len() as u64).encode(0x00, out);
            out.extend_from_slice(self.0);
        }
    }

    pub(super) fn decode_into(
        buf: &[u8],
        scratch: &mut Vec<u8>,
        retain_limit: Option<usize>,
    ) -> Result<DecodedLiteral, DecoderError> {
        if buf.is_empty() {
            return Err(DecoderError::NeedMore);
        }
        let huffman = (buf[0] & 0x80) != 0;
        let (len, n) = PrefixedInt::<7>::decode(buf)?;
        let len = len.get();
        if len > MAX_LITERAL_LEN as u64 {
            return Err(DecoderError::BadString);
        }
        let len = len as usize;
        if n > buf.len() || len > buf.len() - n {
            return Err(DecoderError::NeedMore);
        }
        let end = n.checked_add(len).ok_or(DecoderError::BadString)?;
        let payload = &buf[n..end];
        scratch.clear();
        if huffman {
            let mut decoded_len = 0usize;
            HpackHuffmanEncoded::new(payload)
                .decode_with(|byte| {
                    decoded_len += 1;
                    if retain_limit.is_none_or(|limit| decoded_len <= limit) {
                        scratch.push(byte);
                    }
                    Ok::<_, Infallible>(())
                })
                .map_err(|_| DecoderError::BadString)?;
            let retained = retain_limit.is_none_or(|limit| decoded_len <= limit);
            if !retained {
                scratch.clear();
            }
            Ok(DecodedLiteral {
                consumed: end,
                len: decoded_len,
                retained,
            })
        } else {
            if retain_limit.is_none_or(|limit| payload.len() <= limit) {
                scratch.extend_from_slice(payload);
            }
            Ok(DecodedLiteral {
                consumed: end,
                len: payload.len(),
                retained: scratch.len() == payload.len(),
            })
        }
    }
}