use bytes::Buf;
use bytes::Bytes;
use crate::solicit::frame::builder::FrameBuilder;
use crate::solicit::frame::parse_padded_payload;
use crate::solicit::frame::Frame;
use crate::solicit::frame::FrameHeader;
use crate::solicit::frame::FrameIR;
use crate::solicit::frame::ParseFrameError;
use crate::solicit::frame::ParseFrameResult;
use crate::solicit::frame::RawFrame;
use super::flags::Flag;
use super::flags::Flags;
use crate::codec::write_buffer::WriteBuffer;
use crate::solicit::stream_id::StreamId;
pub const PUSH_PROMISE_FRAME_TYPE: u8 = 0x5;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PushPromiseFrame {
pub flags: Flags<PushPromiseFlag>,
pub stream_id: StreamId,
pub promised_stream_id: StreamId,
pub header_fragment: Bytes,
pub padding_len: u8,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum PushPromiseFlag {
EndHeaders = 0x4,
Padded = 0x8,
}
impl Flag for PushPromiseFlag {
fn bitmask(&self) -> u8 {
*self as u8
}
fn flags() -> &'static [PushPromiseFlag] {
static FLAGS: &'static [PushPromiseFlag] =
&[PushPromiseFlag::EndHeaders, PushPromiseFlag::Padded];
FLAGS
}
}
impl PushPromiseFrame {
fn payload_len(&self) -> u32 {
let padding = if self.flags.is_set(PushPromiseFlag::Padded) {
1 + self.padding_len as u32
} else {
0
};
let stream_id_len = 4;
self.header_fragment.len() as u32 + stream_id_len + padding
}
}
impl Frame for PushPromiseFrame {
type FlagType = PushPromiseFlag;
fn from_raw(raw_frame: &RawFrame) -> ParseFrameResult<PushPromiseFrame> {
let FrameHeader {
payload_len,
frame_type,
flags,
stream_id,
} = raw_frame.header();
if frame_type != PUSH_PROMISE_FRAME_TYPE {
return Err(ParseFrameError::InternalError);
}
if (payload_len as usize) != raw_frame.payload().len() {
return Err(ParseFrameError::InternalError);
}
let flags = Flags::new(flags);
let padded = flags.is_set(PushPromiseFlag::Padded);
let (payload, padding_len) = parse_padded_payload(raw_frame.payload(), padded)?;
let mut buf = &payload[..];
let promised_stream_id = buf.get_u32();
let header_fragment =
payload.slice((payload_len as usize) - buf.remaining()..payload.len());
Ok(PushPromiseFrame {
header_fragment,
stream_id,
padding_len,
flags,
promised_stream_id,
})
}
fn flags(&self) -> Flags<PushPromiseFlag> {
self.flags
}
fn get_stream_id(&self) -> StreamId {
self.stream_id
}
fn get_header(&self) -> FrameHeader {
FrameHeader {
payload_len: self.payload_len(),
frame_type: PUSH_PROMISE_FRAME_TYPE,
flags: self.flags.0,
stream_id: self.stream_id,
}
}
}
impl FrameIR for PushPromiseFrame {
fn serialize_into(self, b: &mut WriteBuffer) {
b.write_header(self.get_header());
let padded = self.flags.is_set(PushPromiseFlag::Padded);
if padded {
b.extend_from_slice(&[self.padding_len]);
}
b.extend_from_bytes(self.header_fragment);
if padded {
b.write_padding(self.padding_len);
}
}
}