sark-h2 0.29.5

Fiber-free HTTP/2 protocol primitives and manifold server for sark
use sark_core::manifold::stream::Boundary;
use sark_h2::{
    frame::{
        self,
        layout::{Data, Header, Headers},
        numbers::{ErrorCode, Flags, Length, ParseError, Type},
        payload::{Continuation, Payload, PushPromise},
    },
    stream::Id,
};
use sark_http::field::metadata::section::rules::Push;

use crate::common::protocol::rules::Build;

pub const OK_RESPONSE: &[u8] = &[0x88];

pub const SELF_DEPENDENT_HEADERS: &[u8] = &[
    0, 0, 11, 1, 0x24, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0x82, 0x86, 0x84, 1, 1, b'x',
];

#[derive(Clone, Copy)]
pub struct Authority;

impl Push for Authority {
    const SCHEMES: Option<&[&[u8]]> = Some(&[b"http"]);
    const AUTHORITIES: Option<&[&[u8]]> = Some(&[b"x", b"example.com"]);
}

pub struct Frame<'a> {
    id: u32,
    bytes: &'a [u8],
}

impl<'a> Frame<'a> {
    pub const fn new(id: u32, bytes: &'a [u8]) -> Self {
        Self { id, bytes }
    }
    pub fn try_headers(self, boundary: Boundary, chain: frame::Block) -> Result<Vec<u8>, Build> {
        let mut out = Vec::new();
        Headers::new(
            Id::new(self.id).ok_or(Build::Stream(self.id))?,
            boundary,
            chain,
            None,
            self.bytes,
        )
        .map_err(Build::Parse)?
        .encode(&mut out)
        .map_err(Build::Encode)?;
        Ok(out)
    }
    pub fn try_continue(self, chain: frame::Block) -> Result<Vec<u8>, Build> {
        let mut out = Vec::new();
        let stream = Id::new(self.id).ok_or(Build::Stream(self.id))?;
        Continuation::new(stream, chain, self.bytes)
            .ok_or(Build::Continuation {
                stream,
                bytes: self.bytes.len(),
            })?
            .encode(&mut out)
            .map_err(Build::Encode)?;
        Ok(out)
    }
    pub fn try_data(self, boundary: Boundary) -> Result<Vec<u8>, Build> {
        let mut out = Vec::new();
        let stream = Id::new(self.id).ok_or(Build::Stream(self.id))?;
        Data::new(stream, boundary, self.bytes)
            .ok_or(Build::Data {
                stream,
                bytes: self.bytes.len(),
            })?
            .encode(&mut out)
            .map_err(Build::Encode)?;
        Ok(out)
    }
    pub fn try_padded(self, boundary: Boundary, padding: u8) -> Result<Vec<u8>, Build> {
        let mut out = Vec::new();
        let flags = match boundary {
            Boundary::More => Flags::PADDED,
            Boundary::End => Flags::PADDED | Flags::END_STREAM,
        };
        let length = self
            .bytes
            .len()
            .checked_add(1)
            .and_then(|bytes| bytes.checked_add(padding as usize))
            .ok_or(Build::Length {
                bytes: self.bytes.len(),
                padding,
            })?;
        out.extend_from_slice(
            &Header {
                length: Length::from_usize(length).ok_or(Build::Length {
                    bytes: self.bytes.len(),
                    padding,
                })?,
                kind: Type::Data,
                flags: Flags(flags),
                stream_id: Id::new(self.id).ok_or(Build::Stream(self.id))?,
            }
            .wire_bytes(),
        );
        out.push(padding);
        out.extend_from_slice(self.bytes);
        out.resize(out.len() + padding as usize, 0);
        Ok(out)
    }
    pub fn try_push(self, promised: u32, chain: frame::Block) -> Result<Vec<u8>, Build> {
        let mut out = Vec::new();
        let stream = Id::new(self.id).ok_or(Build::Stream(self.id))?;
        let promised = Id::new(promised).ok_or(Build::Stream(promised))?;
        PushPromise::new(stream, promised, chain, self.bytes)
            .ok_or(Build::Push {
                stream,
                promised,
                bytes: self.bytes.len(),
            })?
            .encode(&mut out)
            .map_err(Build::Encode)?;
        Ok(out)
    }
}

pub struct Wire<'a> {
    bytes: &'a [u8],
}

impl<'a> Wire<'a> {
    pub const fn new(bytes: &'a [u8]) -> Self {
        Self { bytes }
    }
    pub fn try_reset(self) -> Result<Option<(Id, ErrorCode)>, ParseError> {
        let mut out = self.bytes;
        while !out.is_empty() {
            let (frame, consumed) = Payload::parse(out)?;
            if let Payload::RstStream(reset) = frame {
                return Ok(Some((reset.stream_id(), reset.error())));
            }
            out = &out[consumed..];
        }
        Ok(None)
    }
    pub fn try_window(self) -> Result<Option<u32>, ParseError> {
        let mut out = self.bytes;
        while !out.is_empty() {
            let (frame, consumed) = Payload::parse(out)?;
            if let Payload::WindowUpdate(update) = frame
                && update.stream_id == Id::CONNECTION
            {
                return Ok(Some(update.increment.get()));
            }
            out = &out[consumed..];
        }
        Ok(None)
    }
}