pub mod decoder;
pub mod encoder;
pub mod error;
pub mod flags;
pub use decoder::FrameDecoder;
pub use encoder::FrameEncoder;
pub use error::{FrameError, LastStreamId, Weight, WindowIncrement};
pub use flags::FrameFlags;
use crate::settings::Setting;
pub use crate::stream_id::{NonZeroStreamId, StreamId};
pub const FRAME_HEADER_SIZE: usize = 9;
#[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 name(self) -> &'static str {
match self {
Self::Data => "DATA",
Self::Headers => "HEADERS",
Self::Priority => "PRIORITY",
Self::RstStream => "RST_STREAM",
Self::Settings => "SETTINGS",
Self::PushPromise => "PUSH_PROMISE",
Self::Ping => "PING",
Self::Goaway => "GOAWAY",
Self::WindowUpdate => "WINDOW_UPDATE",
Self::Continuation => "CONTINUATION",
Self::PriorityUpdate => "PRIORITY_UPDATE",
}
}
#[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
}
}
impl std::fmt::Display for FrameType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FrameHeader {
pub length: u32,
pub frame_type: u8,
pub flags: FrameFlags,
pub stream_id: u32,
}
impl FrameHeader {
#[must_use]
pub const fn new(frame_type: FrameType, flags: FrameFlags, stream_id: u32) -> 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
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DataFrame {
pub stream_id: NonZeroStreamId,
pub end_stream: bool,
pub data: Vec<u8>,
pub pad_length: Option<u8>,
}
impl DataFrame {
#[must_use]
pub fn new(stream_id: NonZeroStreamId, 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: NonZeroStreamId,
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: NonZeroStreamId, 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: Weight,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PriorityFrame {
pub stream_id: NonZeroStreamId,
pub exclusive: bool,
pub stream_dependency: StreamId,
pub weight: Weight,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RstStreamFrame {
pub stream_id: NonZeroStreamId,
pub error_code: u32,
}
impl RstStreamFrame {
#[must_use]
pub const fn new(stream_id: NonZeroStreamId, error_code: u32) -> Self {
Self {
stream_id,
error_code,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SettingsFrame {
ack: bool,
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 from_settings(settings: impl IntoIterator<Item = Setting>) -> Self {
Self {
ack: false,
settings: settings.into_iter().collect(),
}
}
pub fn add(&mut self, setting: Setting) {
self.settings.push(setting);
}
#[must_use]
pub const fn is_ack(&self) -> bool {
self.ack
}
#[must_use]
pub fn settings(&self) -> &[Setting] {
&self.settings
}
}
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: LastStreamId,
pub error_code: u32,
pub debug_data: Vec<u8>,
}
impl GoawayFrame {
#[must_use]
pub fn new(last_stream_id: LastStreamId, 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: WindowIncrement,
}
impl WindowUpdateFrame {
#[must_use]
pub const fn for_connection(increment: WindowIncrement) -> Self {
Self {
stream_id: StreamId::Connection,
window_size_increment: increment,
}
}
#[must_use]
pub fn for_stream(stream_id: NonZeroStreamId, increment: WindowIncrement) -> Self {
Self {
stream_id: StreamId::from(stream_id),
window_size_increment: increment,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContinuationFrame {
pub stream_id: NonZeroStreamId,
pub end_headers: bool,
pub header_block_fragment: Vec<u8>,
}
impl ContinuationFrame {
#[must_use]
pub fn new(stream_id: NonZeroStreamId, 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: NonZeroStreamId,
pub priority_field_value: Vec<u8>,
}
impl PriorityUpdateFrame {
#[must_use]
pub fn new(prioritized_element_id: NonZeroStreamId, priority_field_value: Vec<u8>) -> Self {
Self {
prioritized_element_id,
priority_field_value,
}
}
}
#[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 fn stream_id(&self) -> StreamId {
match self {
Self::Data(f) => StreamId::from(f.stream_id),
Self::Headers(f) => StreamId::from(f.stream_id),
Self::Priority(f) => StreamId::from(f.stream_id),
Self::RstStream(f) => StreamId::from(f.stream_id),
Self::Settings(_) => StreamId::Connection,
Self::PushPromise { stream_id } => *stream_id,
Self::Ping(_) => StreamId::Connection,
Self::Goaway(_) => StreamId::Connection,
Self::WindowUpdate(f) => f.stream_id,
Self::Continuation(f) => StreamId::from(f.stream_id),
Self::PriorityUpdate(_) => StreamId::Connection,
Self::Unknown { header, .. } => StreamId::from_wire(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,
}
}
}