use super::error::H2ParseError;
pub const DEFAULT_MAX_FRAME_SIZE: u32 = 16_384;
#[allow(dead_code)] pub const FRAME_TYPE_DATA: u8 = 0x0;
pub const FRAME_TYPE_HEADERS: u8 = 0x1;
pub const FRAME_TYPE_SETTINGS: u8 = 0x4;
pub const FRAME_TYPE_CONTINUATION: u8 = 0x9;
pub const FLAG_END_HEADERS: u8 = 0x4;
pub const FLAG_PADDED: u8 = 0x8;
pub const FLAG_PRIORITY: u8 = 0x20;
#[allow(dead_code)]
pub const FLAG_SETTINGS_ACK: u8 = 0x1;
pub struct FrameHeader {
pub length: u32,
pub frame_type: u8,
pub flags: u8,
pub stream_id: u32,
}
pub type ParsedFrame<'a> = (FrameHeader, &'a [u8], &'a [u8]);
pub fn parse_one_frame(buf: &[u8]) -> Result<Option<ParsedFrame<'_>>, H2ParseError> {
const FRAME_HEADER_LEN: usize = 9;
if buf.len() < FRAME_HEADER_LEN {
return Ok(None);
}
let length = u32::from_be_bytes([0, buf[0], buf[1], buf[2]]);
if length > DEFAULT_MAX_FRAME_SIZE {
return Err(H2ParseError::OversizedFrame {
declared: length,
max: DEFAULT_MAX_FRAME_SIZE,
});
}
let frame_type = buf[3];
let flags = buf[4];
let stream_id = u32::from_be_bytes([buf[5], buf[6], buf[7], buf[8]]) & 0x7FFF_FFFF;
let payload_start = FRAME_HEADER_LEN;
let payload_end = payload_start
.checked_add(length as usize)
.ok_or(H2ParseError::MalformedHeaders)?;
if buf.len() < payload_end {
return Ok(None);
}
let header = FrameHeader {
length,
frame_type,
flags,
stream_id,
};
let payload = &buf[payload_start..payload_end];
let rest = &buf[payload_end..];
Ok(Some((header, payload, rest)))
}
pub fn strip_headers_padding_and_priority(
payload: &[u8],
flags: u8,
) -> Result<&[u8], H2ParseError> {
let mut cursor = payload;
let mut pad_len: usize = 0;
if flags & FLAG_PADDED != 0 {
if cursor.is_empty() {
return Err(H2ParseError::MalformedHeaders);
}
pad_len = cursor[0] as usize;
cursor = &cursor[1..];
}
if flags & FLAG_PRIORITY != 0 {
if cursor.len() < 5 {
return Err(H2ParseError::MalformedHeaders);
}
cursor = &cursor[5..];
}
if pad_len > cursor.len() {
return Err(H2ParseError::PaddingOverflow);
}
let inner_len = cursor.len() - pad_len;
Ok(&cursor[..inner_len])
}