pub mod decoder;
pub mod encoder;
pub mod flags;
pub use decoder::FrameDecoder;
pub use encoder::FrameEncoder;
pub use flags::FrameFlags;
use crate::settings::Setting;
pub const FRAME_HEADER_SIZE: usize = 9;
pub type StreamId = u32;
pub const CONNECTION_STREAM_ID: StreamId = 0;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum FrameType {
Data = 0x00,
Headers = 0x01,
Priority = 0x02,
RstStream = 0x03,
Settings = 0x04,
PushPromise = 0x05,
Ping = 0x06,
Goaway = 0x07,
WindowUpdate = 0x08,
Continuation = 0x09,
PriorityUpdate = 0x10,
}
impl FrameType {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0x00 => Some(Self::Data),
0x01 => Some(Self::Headers),
0x02 => Some(Self::Priority),
0x03 => Some(Self::RstStream),
0x04 => Some(Self::Settings),
0x05 => Some(Self::PushPromise),
0x06 => Some(Self::Ping),
0x07 => Some(Self::Goaway),
0x08 => Some(Self::WindowUpdate),
0x09 => Some(Self::Continuation),
0x10 => Some(Self::PriorityUpdate),
_ => None,
}
}
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FrameHeader {
pub length: u32,
pub frame_type: u8,
pub flags: FrameFlags,
pub stream_id: StreamId,
}
impl FrameHeader {
#[must_use]
pub const fn new(frame_type: FrameType, flags: FrameFlags, stream_id: StreamId) -> Self {
Self {
length: 0,
frame_type: frame_type.as_u8(),
flags,
stream_id,
}
}
#[must_use]
pub const fn with_length(mut self, length: u32) -> Self {
self.length = length;
self
}
#[must_use]
pub const fn get_frame_type(&self) -> Option<FrameType> {
FrameType::from_u8(self.frame_type)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DataFrame {
pub stream_id: StreamId,
pub end_stream: bool,
pub data: Vec<u8>,
pub pad_length: Option<u8>,
}
impl DataFrame {
#[must_use]
pub fn new(stream_id: StreamId, data: Vec<u8>) -> Self {
Self {
stream_id,
end_stream: false,
data,
pad_length: None,
}
}
#[must_use]
pub const fn with_end_stream(mut self, end_stream: bool) -> Self {
self.end_stream = end_stream;
self
}
#[must_use]
pub const fn with_padding(mut self, pad_length: u8) -> Self {
self.pad_length = Some(pad_length);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HeadersFrame {
pub stream_id: StreamId,
pub end_stream: bool,
pub end_headers: bool,
pub priority_fields: Option<PriorityFields>,
pub header_block_fragment: Vec<u8>,
pub pad_length: Option<u8>,
}
impl HeadersFrame {
#[must_use]
pub fn new(stream_id: StreamId, header_block_fragment: Vec<u8>) -> Self {
Self {
stream_id,
end_stream: false,
end_headers: true,
priority_fields: None,
header_block_fragment,
pad_length: None,
}
}
#[must_use]
pub const fn with_end_stream(mut self, end_stream: bool) -> Self {
self.end_stream = end_stream;
self
}
#[must_use]
pub const fn with_end_headers(mut self, end_headers: bool) -> Self {
self.end_headers = end_headers;
self
}
#[must_use]
pub const fn with_padding(mut self, pad_length: u8) -> Self {
self.pad_length = Some(pad_length);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PriorityFields {
pub exclusive: bool,
pub stream_dependency: StreamId,
pub weight: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PriorityFrame {
pub stream_id: StreamId,
pub exclusive: bool,
pub stream_dependency: StreamId,
pub weight: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RstStreamFrame {
pub stream_id: StreamId,
pub error_code: u32,
}
impl RstStreamFrame {
#[must_use]
pub const fn new(stream_id: StreamId, error_code: u32) -> Self {
Self {
stream_id,
error_code,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SettingsFrame {
pub ack: bool,
pub settings: Vec<Setting>,
}
impl SettingsFrame {
#[must_use]
pub fn new() -> Self {
Self {
ack: false,
settings: Vec::new(),
}
}
#[must_use]
pub fn ack() -> Self {
Self {
ack: true,
settings: Vec::new(),
}
}
pub fn add_setting(&mut self, setting: Setting) {
self.settings.push(setting);
}
}
impl Default for SettingsFrame {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PingFrame {
pub ack: bool,
pub opaque_data: [u8; 8],
}
impl PingFrame {
#[must_use]
pub const fn new(opaque_data: [u8; 8]) -> Self {
Self {
ack: false,
opaque_data,
}
}
#[must_use]
pub const fn ack(opaque_data: [u8; 8]) -> Self {
Self {
ack: true,
opaque_data,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GoawayFrame {
pub last_stream_id: StreamId,
pub error_code: u32,
pub debug_data: Vec<u8>,
}
impl GoawayFrame {
#[must_use]
pub fn new(last_stream_id: StreamId, error_code: u32) -> Self {
Self {
last_stream_id,
error_code,
debug_data: Vec::new(),
}
}
#[must_use]
pub fn with_debug_data(mut self, debug_data: Vec<u8>) -> Self {
self.debug_data = debug_data;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowUpdateFrame {
pub stream_id: StreamId,
pub window_size_increment: u32,
}
impl WindowUpdateFrame {
#[must_use]
pub const fn new(stream_id: StreamId, window_size_increment: u32) -> Self {
Self {
stream_id,
window_size_increment,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContinuationFrame {
pub stream_id: StreamId,
pub end_headers: bool,
pub header_block_fragment: Vec<u8>,
}
impl ContinuationFrame {
#[must_use]
pub fn new(stream_id: StreamId, header_block_fragment: Vec<u8>) -> Self {
Self {
stream_id,
end_headers: false,
header_block_fragment,
}
}
#[must_use]
pub const fn with_end_headers(mut self, end_headers: bool) -> Self {
self.end_headers = end_headers;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PriorityUpdateFrame {
pub prioritized_element_id: StreamId,
pub priority_field_value: Vec<u8>,
}
impl PriorityUpdateFrame {
#[must_use]
pub fn new(prioritized_element_id: StreamId, priority_field_value: Vec<u8>) -> Self {
Self {
prioritized_element_id,
priority_field_value,
}
}
#[must_use]
pub fn default_priority(prioritized_element_id: StreamId) -> Self {
Self {
prioritized_element_id,
priority_field_value: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Frame {
Data(DataFrame),
Headers(HeadersFrame),
Priority(PriorityFrame),
RstStream(RstStreamFrame),
Settings(SettingsFrame),
PushPromise {
stream_id: StreamId,
},
Ping(PingFrame),
Goaway(GoawayFrame),
WindowUpdate(WindowUpdateFrame),
Continuation(ContinuationFrame),
PriorityUpdate(PriorityUpdateFrame),
Unknown {
header: FrameHeader,
payload: Vec<u8>,
},
}
impl Frame {
#[must_use]
pub const fn stream_id(&self) -> StreamId {
match self {
Self::Data(f) => f.stream_id,
Self::Headers(f) => f.stream_id,
Self::Priority(f) => f.stream_id,
Self::RstStream(f) => f.stream_id,
Self::Settings(_) => CONNECTION_STREAM_ID,
Self::PushPromise { stream_id } => *stream_id,
Self::Ping(_) => CONNECTION_STREAM_ID,
Self::Goaway(_) => CONNECTION_STREAM_ID,
Self::WindowUpdate(f) => f.stream_id,
Self::Continuation(f) => f.stream_id,
Self::PriorityUpdate(_) => CONNECTION_STREAM_ID,
Self::Unknown { header, .. } => header.stream_id,
}
}
#[must_use]
pub const fn frame_type(&self) -> Option<FrameType> {
match self {
Self::Data(_) => Some(FrameType::Data),
Self::Headers(_) => Some(FrameType::Headers),
Self::Priority(_) => Some(FrameType::Priority),
Self::RstStream(_) => Some(FrameType::RstStream),
Self::Settings(_) => Some(FrameType::Settings),
Self::PushPromise { .. } => Some(FrameType::PushPromise),
Self::Ping(_) => Some(FrameType::Ping),
Self::Goaway(_) => Some(FrameType::Goaway),
Self::WindowUpdate(_) => Some(FrameType::WindowUpdate),
Self::Continuation(_) => Some(FrameType::Continuation),
Self::PriorityUpdate(_) => Some(FrameType::PriorityUpdate),
Self::Unknown { .. } => None,
}
}
}