use std::mem;
use bytes::Bytes;
use crate::solicit::frame::flags::*;
macro_rules! unpack_octets_4 {
($buf:expr, $offset:expr, $tip:ty) => {
(($buf[$offset + 0] as $tip) << 24)
| (($buf[$offset + 1] as $tip) << 16)
| (($buf[$offset + 2] as $tip) << 8)
| (($buf[$offset + 3] as $tip) << 0)
};
}
#[inline]
fn parse_stream_id(buf: &[u8]) -> u32 {
let unpacked = unpack_octets_4!(buf, 0, u32);
unpacked & !0x80000000
}
pub mod builder;
mod continuation;
mod data;
mod flags;
mod frame_type;
mod goaway;
mod headers;
mod ping;
mod priority;
mod push_promise;
mod rst_stream;
mod settings;
mod window_update;
pub(crate) use self::builder::FrameBuilder;
pub use self::continuation::ContinuationFlag;
pub use self::continuation::ContinuationFrame;
pub use self::data::DataFlag;
pub use self::data::DataFrame;
pub use self::flags::Flags;
pub use self::frame_type::HttpFrameType;
pub use self::frame_type::RawHttpFrameType;
pub use self::goaway::GoawayFrame;
pub use self::headers::HeadersDecodedFrame;
pub use self::headers::HeadersFlag;
pub use self::headers::HeadersFrame;
pub use self::headers::HeadersMultiFrame;
pub use self::ping::PingFrame;
pub use self::priority::PriorityFrame;
pub use self::push_promise::PushPromiseFlag;
pub use self::push_promise::PushPromiseFrame;
pub use self::rst_stream::RstStreamFrame;
pub use self::settings::HttpSetting;
pub use self::settings::HttpSettings;
pub use self::settings::SettingsFlag;
pub use self::settings::SettingsFrame;
pub use self::window_update::WindowUpdateFrame;
use crate::codec::write_buffer::WriteBuffer;
use crate::solicit::frame;
use crate::solicit::stream_id::StreamId;
use std::fmt;
pub const FRAME_HEADER_LEN: usize = 9;
pub type FrameHeaderBuffer = [u8; FRAME_HEADER_LEN];
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct FrameHeader {
pub payload_len: u32,
pub frame_type: u8,
pub flags: u8,
pub stream_id: u32,
}
impl FrameHeader {
pub fn new(payload_len: u32, frame_type: u8, flags: u8, stream_id: u32) -> FrameHeader {
FrameHeader {
payload_len,
frame_type,
flags,
stream_id,
}
}
}
#[inline]
pub fn unpack_header_from_slice(header: &[u8]) -> FrameHeader {
assert_eq!(FRAME_HEADER_LEN, header.len());
let payload_len: u32 =
((header[0] as u32) << 16) | ((header[1] as u32) << 8) | (header[2] as u32);
let frame_type = header[3];
let flags = header[4];
let stream_id = parse_stream_id(&header[5..]);
FrameHeader {
payload_len,
frame_type,
flags,
stream_id,
}
}
#[cfg(test)]
pub fn unpack_frames_for_test(mut raw: &[u8]) -> Vec<HttpFrame> {
let mut r = Vec::new();
while !raw.is_empty() {
let raw_frame = RawFrame::parse(Bytes::copy_from_slice(raw)).unwrap();
raw = &raw[raw_frame.len()..];
r.push(HttpFrame::from_raw(&raw_frame).unwrap());
}
r
}
pub fn unpack_header(header: &FrameHeaderBuffer) -> FrameHeader {
unpack_header_from_slice(header)
}
pub fn pack_header(header: &FrameHeader) -> FrameHeaderBuffer {
let &FrameHeader {
payload_len,
frame_type,
flags,
stream_id,
} = header;
[
(((payload_len >> 16) & 0x000000FF) as u8),
(((payload_len >> 8) & 0x000000FF) as u8),
(((payload_len) & 0x000000FF) as u8),
frame_type,
flags,
(((stream_id >> 24) & 0x000000FF) as u8),
(((stream_id >> 16) & 0x000000FF) as u8),
(((stream_id >> 8) & 0x000000FF) as u8),
(((stream_id) & 0x000000FF) as u8),
]
}
fn parse_padded_payload(payload: Bytes, flag: bool) -> ParseFrameResult<(Bytes, u8)> {
if !flag {
return Ok((payload, 0));
}
if payload.len() == 0 {
return Err(ParseFrameError::ProtocolError);
}
let pad_len = payload[0] as usize;
if pad_len >= payload.len() {
return Err(ParseFrameError::ProtocolError);
}
Ok((payload.slice(1..payload.len() - pad_len), pad_len as u8))
}
pub trait FrameIR: fmt::Debug {
fn serialize_into(self, builder: &mut WriteBuffer);
fn serialize_into_vec(self) -> Vec<u8>
where
Self: Sized,
{
let mut builder = WriteBuffer::new();
self.serialize_into(&mut builder);
builder.into()
}
}
#[derive(Debug)]
pub enum ParseFrameError {
InternalError,
BufMustBeAtLeast9Bytes(usize),
IncorrectPayloadLen,
StreamIdMustBeNonZero,
StreamIdMustBeZero(u32),
StreamDependencyOnItself(u32),
IncorrectFrameLength(u32),
IncorrectFlags(u8),
IncorrectSettingsPushValue(u32),
IncorrectSettingsMaxFrameSize(u32),
WindowSizeTooLarge(u32),
WindowUpdateIncrementInvalid(u32),
ProtocolError,
}
pub type ParseFrameResult<T> = Result<T, ParseFrameError>;
pub trait Frame: Sized {
type FlagType: Flag;
fn from_raw(raw_frame: &RawFrame) -> ParseFrameResult<Self>;
fn flags(&self) -> Flags<Self::FlagType>;
fn get_stream_id(&self) -> StreamId;
fn get_header(&self) -> FrameHeader;
}
#[derive(PartialEq, Debug, Clone)]
pub struct RawFrame {
pub raw_content: Bytes,
}
pub struct RawFrameRef<'a> {
pub raw_content: &'a [u8],
}
impl RawFrame {
pub fn parse<B: Into<Bytes>>(into_buf: B) -> ParseFrameResult<RawFrame> {
let buf = into_buf.into();
if buf.len() < 9 {
return Err(ParseFrameError::BufMustBeAtLeast9Bytes(buf.len()));
}
let header = unpack_header(unsafe {
assert!(buf.len() >= 9);
mem::transmute(buf.as_ptr())
});
let payload_len = header.payload_len as usize;
if buf[9..].len() < payload_len {
return Err(ParseFrameError::IncorrectPayloadLen);
}
let raw = &buf[..9 + payload_len];
Ok(raw.into())
}
pub fn as_frame_ref(&self) -> RawFrameRef {
RawFrameRef {
raw_content: &self.raw_content,
}
}
pub fn frame_type(&self) -> u8 {
self.as_frame_ref().frame_type()
}
#[inline]
pub fn len(&self) -> usize {
self.raw_content.len()
}
pub fn serialize(&self) -> &Bytes {
&self.raw_content
}
pub fn header(&self) -> FrameHeader {
unpack_header(unsafe {
assert!(self.raw_content.len() >= 9);
mem::transmute(self.raw_content.as_ptr())
})
}
pub fn get_stream_id(&self) -> StreamId {
self.header().stream_id
}
pub fn payload(&self) -> Bytes {
self.raw_content.slice(9..)
}
}
impl<'a> RawFrameRef<'a> {
pub fn frame_type(&self) -> u8 {
self.raw_content[3]
}
}
impl AsRef<[u8]> for RawFrame {
fn as_ref(&self) -> &[u8] {
self.raw_content.as_ref()
}
}
impl From<Vec<u8>> for RawFrame {
fn from(raw: Vec<u8>) -> RawFrame {
RawFrame {
raw_content: Bytes::from(raw),
}
}
}
impl<'a> From<&'a [u8]> for RawFrame {
fn from(raw: &'a [u8]) -> RawFrame {
RawFrame {
raw_content: Bytes::copy_from_slice(raw),
}
}
}
impl FrameIR for RawFrame {
fn serialize_into(self, b: &mut WriteBuffer) {
b.write_header(self.header());
b.extend_from_bytes(self.payload());
}
}
#[cfg(test)]
mod tests {
use super::{pack_header, unpack_header, FrameHeader, RawFrame};
#[test]
fn test_unpack_header() {
{
let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
assert_eq!(
FrameHeader {
payload_len: 1,
frame_type: 2,
flags: 3,
stream_id: 4
},
unpack_header(&header)
);
}
{
let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(
FrameHeader {
payload_len: 256,
frame_type: 0,
flags: 0,
stream_id: 0
},
unpack_header(&header)
);
}
{
let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(
FrameHeader {
payload_len: 256 * 256,
frame_type: 0,
flags: 0,
stream_id: 0
},
unpack_header(&header)
);
}
{
let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
assert_eq!(
FrameHeader {
payload_len: (1 << 24) - 1,
frame_type: 0,
flags: 0,
stream_id: 1
},
unpack_header(&header)
);
}
{
let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
assert_eq!(
FrameHeader {
payload_len: (1 << 24) - 1,
frame_type: 0,
flags: 0,
stream_id: 1 + (1 << 8) + (1 << 16) + (1 << 24)
},
unpack_header(&header)
);
}
{
let header = [0, 0, 1, 0, 0, 0x80, 0, 0, 1];
assert_eq!(
FrameHeader {
payload_len: 1,
frame_type: 0,
flags: 0,
stream_id: 1
},
unpack_header(&header)
);
}
}
#[test]
fn test_pack_header() {
{
let header = [0; 9];
assert_eq!(pack_header(&FrameHeader::new(0, 0, 0, 0)), header);
}
{
let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
assert_eq!(pack_header(&FrameHeader::new(1, 2, 3, 4)), header);
}
{
let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
assert_eq!(pack_header(&FrameHeader::new(1, 200, 100, 4)), header);
}
{
let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
assert_eq!(pack_header(&FrameHeader::new(1, 0, 0, 0)), header);
}
{
let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(pack_header(&FrameHeader::new(256, 0, 0, 0)), header);
}
{
let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
assert_eq!(pack_header(&FrameHeader::new(256 * 256, 0, 0, 0)), header);
}
{
let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
assert_eq!(pack_header(&FrameHeader::new(0, 0, 0, 1)), header);
}
{
let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
assert_eq!(
pack_header(&FrameHeader::new((1 << 24) - 1, 0, 0, 1)),
header
);
}
{
let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
let header_components =
FrameHeader::new((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24));
assert_eq!(pack_header(&header_components), header);
}
}
pub fn build_padded_frame_payload(data: &[u8], pad_len: u8) -> Vec<u8> {
let sz = 1 + data.len() + pad_len as usize;
let mut payload: Vec<u8> = Vec::with_capacity(sz);
payload.push(pad_len);
payload.extend(data.to_vec().into_iter());
for _ in 0..pad_len {
payload.push(0);
}
payload
}
#[test]
fn test_from_slice() {
let buf = &b""[..];
let frame = RawFrame::from(buf);
assert_eq!(frame.as_ref(), buf);
}
#[test]
fn test_raw_frame_serialize() {
let data = b"123";
let header = FrameHeader {
payload_len: data.len() as u32,
frame_type: 0x1,
flags: 0,
stream_id: 1,
};
let buf = {
let mut buf = Vec::new();
buf.extend(pack_header(&header).to_vec().into_iter());
buf.extend(data.to_vec().into_iter());
buf
};
let raw: RawFrame = buf.clone().into();
assert_eq!(raw.serialize().as_ref(), &buf[..]);
}
#[test]
fn test_raw_frame_len() {
{
let buf = b"123";
let frame = RawFrame::from(&buf[..]);
assert_eq!(buf.len(), frame.len());
}
{
let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0];
let frame = RawFrame::from(&buf[..]);
assert_eq!(buf.len(), frame.len());
}
{
let buf = vec![0, 0, 1, 0, 0, 0, 0, 0, 0, 1];
let frame = RawFrame::from(&buf[..]);
assert_eq!(buf.len(), frame.len());
}
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum HttpFrame {
Data(DataFrame),
Headers(HeadersFrame),
Priority(PriorityFrame),
RstStream(RstStreamFrame),
Settings(SettingsFrame),
PushPromise(PushPromiseFrame),
Ping(PingFrame),
Goaway(GoawayFrame),
WindowUpdate(WindowUpdateFrame),
Continuation(ContinuationFrame),
Unknown(RawFrame),
}
impl HttpFrame {
pub fn from_raw(raw_frame: &RawFrame) -> ParseFrameResult<HttpFrame> {
let frame = match raw_frame.header().frame_type {
frame::data::DATA_FRAME_TYPE => HttpFrame::Data(HttpFrame::parse_frame(&raw_frame)?),
frame::headers::HEADERS_FRAME_TYPE => {
HttpFrame::Headers(HttpFrame::parse_frame(&raw_frame)?)
}
frame::priority::PRIORITY_FRAME_TYPE => {
HttpFrame::Priority(HttpFrame::parse_frame(&raw_frame)?)
}
frame::rst_stream::RST_STREAM_FRAME_TYPE => {
HttpFrame::RstStream(HttpFrame::parse_frame(&raw_frame)?)
}
frame::settings::SETTINGS_FRAME_TYPE => {
HttpFrame::Settings(HttpFrame::parse_frame(&raw_frame)?)
}
frame::push_promise::PUSH_PROMISE_FRAME_TYPE => {
HttpFrame::PushPromise(HttpFrame::parse_frame(&raw_frame)?)
}
frame::ping::PING_FRAME_TYPE => HttpFrame::Ping(HttpFrame::parse_frame(&raw_frame)?),
frame::goaway::GOAWAY_FRAME_TYPE => {
HttpFrame::Goaway(HttpFrame::parse_frame(&raw_frame)?)
}
frame::window_update::WINDOW_UPDATE_FRAME_TYPE => {
HttpFrame::WindowUpdate(HttpFrame::parse_frame(&raw_frame)?)
}
frame::continuation::CONTINUATION_FRAME_TYPE => {
HttpFrame::Continuation(HttpFrame::parse_frame(&raw_frame)?)
}
_ => HttpFrame::Unknown(raw_frame.as_ref().into()),
};
Ok(frame)
}
#[inline] fn parse_frame<F: Frame>(raw_frame: &RawFrame) -> ParseFrameResult<F> {
Frame::from_raw(&raw_frame)
}
pub fn get_stream_id(&self) -> StreamId {
match self {
&HttpFrame::Data(ref f) => f.get_stream_id(),
&HttpFrame::Headers(ref f) => f.get_stream_id(),
&HttpFrame::Priority(ref f) => f.get_stream_id(),
&HttpFrame::RstStream(ref f) => f.get_stream_id(),
&HttpFrame::Settings(ref f) => f.get_stream_id(),
&HttpFrame::PushPromise(ref f) => f.get_stream_id(),
&HttpFrame::Ping(ref f) => f.get_stream_id(),
&HttpFrame::Goaway(ref f) => f.get_stream_id(),
&HttpFrame::WindowUpdate(ref f) => f.get_stream_id(),
&HttpFrame::Continuation(ref f) => f.get_stream_id(),
&HttpFrame::Unknown(ref f) => f.get_stream_id(),
}
}
pub fn frame_type(&self) -> RawHttpFrameType {
match self {
&HttpFrame::Data(..) => RawHttpFrameType::DATA,
&HttpFrame::Headers(..) => RawHttpFrameType::HEADERS,
&HttpFrame::Priority(..) => RawHttpFrameType::PRIORITY,
&HttpFrame::RstStream(..) => RawHttpFrameType::RST_STREAM,
&HttpFrame::Settings(..) => RawHttpFrameType::SETTINGS,
&HttpFrame::PushPromise(..) => RawHttpFrameType::PUSH_PROMISE,
&HttpFrame::Ping(..) => RawHttpFrameType::PING,
&HttpFrame::Goaway(..) => RawHttpFrameType::GOAWAY,
&HttpFrame::WindowUpdate(..) => RawHttpFrameType::WINDOW_UPDATE,
&HttpFrame::Continuation(..) => RawHttpFrameType::CONTINUATION,
&HttpFrame::Unknown(ref f) => RawHttpFrameType(f.frame_type()),
}
}
}
impl FrameIR for HttpFrame {
fn serialize_into(self, builder: &mut WriteBuffer) {
match self {
HttpFrame::Data(f) => f.serialize_into(builder),
HttpFrame::Headers(f) => f.serialize_into(builder),
HttpFrame::Priority(f) => f.serialize_into(builder),
HttpFrame::RstStream(f) => f.serialize_into(builder),
HttpFrame::Settings(f) => f.serialize_into(builder),
HttpFrame::PushPromise(f) => f.serialize_into(builder),
HttpFrame::Ping(f) => f.serialize_into(builder),
HttpFrame::Goaway(f) => f.serialize_into(builder),
HttpFrame::WindowUpdate(f) => f.serialize_into(builder),
HttpFrame::Continuation(f) => f.serialize_into(builder),
HttpFrame::Unknown(f) => f.serialize_into(builder),
}
}
}
impl From<DataFrame> for HttpFrame {
fn from(frame: DataFrame) -> Self {
HttpFrame::Data(frame)
}
}
impl From<HeadersFrame> for HttpFrame {
fn from(frame: HeadersFrame) -> Self {
HttpFrame::Headers(frame)
}
}
impl From<PriorityFrame> for HttpFrame {
fn from(frame: PriorityFrame) -> Self {
HttpFrame::Priority(frame)
}
}
impl From<RstStreamFrame> for HttpFrame {
fn from(frame: RstStreamFrame) -> Self {
HttpFrame::RstStream(frame)
}
}
impl From<SettingsFrame> for HttpFrame {
fn from(frame: SettingsFrame) -> Self {
HttpFrame::Settings(frame)
}
}
impl From<PushPromiseFrame> for HttpFrame {
fn from(frame: PushPromiseFrame) -> Self {
HttpFrame::PushPromise(frame)
}
}
impl From<PingFrame> for HttpFrame {
fn from(frame: PingFrame) -> Self {
HttpFrame::Ping(frame)
}
}
impl From<GoawayFrame> for HttpFrame {
fn from(frame: GoawayFrame) -> Self {
HttpFrame::Goaway(frame)
}
}
impl From<WindowUpdateFrame> for HttpFrame {
fn from(frame: WindowUpdateFrame) -> Self {
HttpFrame::WindowUpdate(frame)
}
}
impl From<ContinuationFrame> for HttpFrame {
fn from(frame: ContinuationFrame) -> Self {
HttpFrame::Continuation(frame)
}
}
#[derive(Debug, Clone)]
pub enum HttpFrameDecoded {
Data(DataFrame),
Headers(HeadersDecodedFrame),
Priority(PriorityFrame),
RstStream(RstStreamFrame),
Settings(SettingsFrame),
PushPromise(PushPromiseFrame),
Ping(PingFrame),
Goaway(GoawayFrame),
WindowUpdate(WindowUpdateFrame),
Unknown(RawFrame),
}