use bytes::Bytes;
use crate::codec::write_buffer::{WriteBuffer, WriteBufferTailVec};
use crate::hpack;
use crate::hpack::encoder::EncodeBuf;
use crate::solicit::frame::continuation::ContinuationFlag;
use crate::solicit::frame::flags::*;
use crate::solicit::frame::pack_header;
use crate::solicit::frame::HttpFrameType;
use crate::solicit::frame::ParseFrameError;
use crate::solicit::frame::ParseFrameResult;
use crate::solicit::frame::FRAME_HEADER_LEN;
use crate::solicit::frame::{
parse_padded_payload, Frame, FrameBuilder, FrameHeader, FrameIR, RawFrame,
};
use crate::solicit::stream_id::StreamId;
use crate::Headers;
use std::cmp;
use std::fmt;
pub const HEADERS_FRAME_TYPE: u8 = 0x1;
#[derive(Clone, PartialEq, Debug, Copy)]
pub enum HeadersFlag {
EndStream = 0x1,
EndHeaders = 0x4,
Padded = 0x8,
Priority = 0x20,
}
impl Flag for HeadersFlag {
#[inline]
fn bitmask(&self) -> u8 {
*self as u8
}
fn flags() -> &'static [Self] {
static FLAGS: &'static [HeadersFlag] = &[
HeadersFlag::EndStream,
HeadersFlag::EndHeaders,
HeadersFlag::Padded,
HeadersFlag::Priority,
];
FLAGS
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct StreamDependency {
pub stream_id: StreamId,
pub weight: u8,
pub is_exclusive: bool,
}
impl StreamDependency {
pub fn new(stream_id: StreamId, weight: u8, is_exclusive: bool) -> StreamDependency {
StreamDependency {
stream_id: stream_id,
weight: weight,
is_exclusive: is_exclusive,
}
}
pub fn parse(buf: &[u8]) -> StreamDependency {
let is_exclusive = buf[0] & 0x80 != 0;
let stream_id = {
let mut id = unpack_octets_4!(buf, 0, u32);
id &= !(1 << 31);
id
};
StreamDependency {
stream_id: stream_id,
weight: buf[4],
is_exclusive: is_exclusive,
}
}
pub fn serialize(&self) -> [u8; 5] {
let e_bit = if self.is_exclusive { 1 << 7 } else { 0 };
[
(((self.stream_id >> 24) & 0x000000FF) as u8) | e_bit,
(((self.stream_id >> 16) & 0x000000FF) as u8),
(((self.stream_id >> 8) & 0x000000FF) as u8),
(((self.stream_id) & 0x000000FF) as u8),
self.weight,
]
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct HeadersFrame {
pub flags: Flags<HeadersFlag>,
pub stream_id: StreamId,
pub header_fragment: Bytes,
pub stream_dep: Option<StreamDependency>,
pub padding_len: u8,
}
impl HeadersFrame {
pub fn new(fragment: Bytes, stream_id: StreamId) -> HeadersFrame {
HeadersFrame {
header_fragment: fragment,
stream_id,
stream_dep: None,
padding_len: 0,
flags: Flags::default(),
}
}
pub fn new_conv<B: Into<Bytes>>(fragment: B, stream_id: StreamId) -> HeadersFrame {
HeadersFrame::new(fragment.into(), stream_id)
}
pub fn with_dependency(
fragment: Vec<u8>,
stream_id: StreamId,
stream_dep: StreamDependency,
) -> HeadersFrame {
HeadersFrame {
header_fragment: Bytes::from(fragment),
stream_id: stream_id,
stream_dep: Some(stream_dep),
padding_len: 0,
flags: HeadersFlag::Priority.to_flags(),
}
}
pub fn is_headers_end(&self) -> bool {
self.flags.is_set(HeadersFlag::EndHeaders)
}
pub fn is_end_of_stream(&self) -> bool {
self.flags.is_set(HeadersFlag::EndStream)
}
pub fn set_padding(&mut self, padding_len: u8) {
self.set_flag(HeadersFlag::Padded);
self.padding_len = padding_len;
}
fn payload_len(&self) -> u32 {
let padding = if self.flags.is_set(HeadersFlag::Padded) {
1 + self.padding_len as u32
} else {
0
};
let priority = if self.flags.is_set(HeadersFlag::Priority) {
5
} else {
0
};
self.header_fragment.len() as u32 + priority + padding
}
pub fn header_fragment(&self) -> &[u8] {
&self.header_fragment
}
pub fn set_flag(&mut self, flag: HeadersFlag) {
self.flags.set(flag);
}
}
impl Frame for HeadersFrame {
type FlagType = HeadersFlag;
fn from_raw(raw_frame: &RawFrame) -> ParseFrameResult<HeadersFrame> {
let FrameHeader {
payload_len,
frame_type,
flags,
stream_id,
} = raw_frame.header();
if frame_type != HEADERS_FRAME_TYPE {
return Err(ParseFrameError::InternalError);
}
if (payload_len as usize) != raw_frame.payload().len() {
return Err(ParseFrameError::InternalError);
}
if stream_id == 0 {
return Err(ParseFrameError::StreamIdMustBeNonZero);
}
let flags = Flags::new(flags);
let padded = flags.is_set(HeadersFlag::Padded);
let (actual, pad_len) = parse_padded_payload(raw_frame.payload(), padded)?;
let priority = flags.is_set(HeadersFlag::Priority);
let (data, stream_dep) = if priority {
let dep = StreamDependency::parse(&actual[..5]);
if dep.stream_id == stream_id {
return Err(ParseFrameError::StreamDependencyOnItself(stream_id));
}
(actual.slice(5..), Some(dep))
} else {
(actual, None)
};
Ok(HeadersFrame {
header_fragment: data,
stream_id,
stream_dep,
padding_len: pad_len,
flags,
})
}
fn flags(&self) -> Flags<HeadersFlag> {
self.flags
}
fn get_stream_id(&self) -> StreamId {
self.stream_id
}
fn get_header(&self) -> FrameHeader {
FrameHeader {
payload_len: self.payload_len(),
frame_type: HEADERS_FRAME_TYPE,
flags: self.flags.0,
stream_id: self.stream_id,
}
}
}
impl FrameIR for HeadersFrame {
fn serialize_into(self, b: &mut WriteBuffer) {
b.write_header(self.get_header());
let padded = self.flags.is_set(HeadersFlag::Padded);
if padded {
b.extend_from_slice(&[self.padding_len]);
}
if self.flags.is_set(HeadersFlag::Priority) {
let dep_buf = match self.stream_dep {
Some(ref dep) => dep.serialize(),
None => panic!("Priority flag set, but no dependency information given"),
};
b.extend_from_slice(&dep_buf);
}
b.extend_from_bytes(self.header_fragment);
if padded {
b.write_padding(self.padding_len);
}
}
}
#[derive(Debug, Clone)]
pub struct HeadersDecodedFrame {
pub flags: Flags<HeadersFlag>,
pub stream_id: StreamId,
pub headers: Headers,
pub stream_dep: Option<StreamDependency>,
pub padding_len: u8,
}
impl HeadersDecodedFrame {
pub fn is_end_of_stream(&self) -> bool {
self.flags.is_set(HeadersFlag::EndStream)
}
pub fn get_stream_id(&self) -> StreamId {
self.stream_id
}
}
pub struct HeadersMultiFrame<'a> {
pub flags: Flags<HeadersFlag>,
pub stream_id: StreamId,
pub headers: Headers,
pub stream_dep: Option<StreamDependency>,
pub padding_len: u8,
pub encoder: &'a mut hpack::Encoder,
pub max_frame_size: u32,
}
impl<'a> fmt::Debug for HeadersMultiFrame<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("HeadersMultiFrame")
.field("flags", &self.flags)
.field("stream_id", &self.stream_id)
.field("headers", &self.headers)
.field("stream_id", &self.stream_id)
.field("padding_len", &self.padding_len)
.field("max_frame_size", &self.max_frame_size)
.finish()
}
}
enum HeadersFrameType {
Headers,
Continuation,
}
impl HeadersFrameType {
fn frame_type(&self) -> HttpFrameType {
match self {
HeadersFrameType::Headers => HttpFrameType::Headers,
HeadersFrameType::Continuation => HttpFrameType::Continuation,
}
}
fn make_flags(&self, header_flags: Flags<HeadersFlag>, last: bool) -> u8 {
assert!(!header_flags.is_set(HeadersFlag::EndHeaders));
match self {
HeadersFrameType::Headers => {
match last {
true => header_flags.with(HeadersFlag::EndHeaders),
false => header_flags,
}
.0
}
HeadersFrameType::Continuation => match last {
true => ContinuationFlag::EndHeaders.bitmask(),
false => 0,
},
}
}
}
struct EncodeBufForHeadersMultiFrame<'a> {
current_frame_type: HeadersFrameType,
current_frame_offset: usize,
stream_id: StreamId,
flags: Flags<HeadersFlag>,
builder: WriteBufferTailVec<'a>,
max_frame_size: u32,
}
impl<'a> EncodeBufForHeadersMultiFrame<'a> {
fn open_frame(&mut self) {
self.current_frame_offset = self.builder.remaining();
self.builder.extend_from_slice(&pack_header(&FrameHeader {
payload_len: 0,
frame_type: 0,
flags: 0,
stream_id: 0,
}));
}
fn finish_frame(&mut self, last: bool) {
let frame_length = (self.builder.remaining() - self.current_frame_offset) as u32;
debug_assert!(frame_length >= FRAME_HEADER_LEN as u32);
let length = frame_length - FRAME_HEADER_LEN as u32;
self.builder.patch_buf(
self.current_frame_offset,
&pack_header(&FrameHeader {
payload_len: length,
frame_type: self.current_frame_type.frame_type().frame_type(),
flags: self.current_frame_type.make_flags(self.flags, last),
stream_id: self.stream_id,
}),
);
}
fn rem_in_current_frame(&self) -> usize {
let current_frame_len = self.builder.remaining() - self.current_frame_offset;
debug_assert!(current_frame_len >= FRAME_HEADER_LEN);
let current_frame_payload_len = current_frame_len - FRAME_HEADER_LEN;
debug_assert!(current_frame_payload_len <= self.max_frame_size as usize);
self.max_frame_size as usize - current_frame_payload_len
}
}
impl<'a> EncodeBuf for EncodeBufForHeadersMultiFrame<'a> {
fn write_all(&mut self, mut bytes: &[u8]) {
loop {
let copy_here = cmp::min(bytes.len(), self.rem_in_current_frame());
self.builder.extend_from_slice(&bytes[..copy_here]);
bytes = &bytes[copy_here..];
if bytes.is_empty() {
return;
}
self.finish_frame(false);
self.open_frame();
self.current_frame_type = HeadersFrameType::Continuation;
}
}
fn reserve(&mut self, additional: usize) {
self.builder.reserve(additional);
}
}
impl<'a> FrameIR for HeadersMultiFrame<'a> {
fn serialize_into(self, builder: &mut WriteBuffer) {
assert!(!self.flags.is_set(HeadersFlag::EndHeaders));
let tail_vec = builder.tail_vec();
let mut buf = EncodeBufForHeadersMultiFrame {
flags: self.flags,
stream_id: self.stream_id,
current_frame_type: HeadersFrameType::Headers,
current_frame_offset: tail_vec.remaining(),
builder: tail_vec,
max_frame_size: self.max_frame_size,
};
buf.open_frame();
let headers = self
.headers
.iter()
.map(|h| (h.name().as_bytes(), h.value()));
self.encoder.encode_into(headers, &mut buf);
buf.finish_frame(true);
}
}
#[cfg(test)]
mod tests {
use super::{HeadersFlag, HeadersFrame, StreamDependency};
use crate::hpack;
use crate::solicit::frame::continuation::ContinuationFlag;
use crate::solicit::frame::flags::Flags;
use crate::solicit::frame::headers::HeadersMultiFrame;
use crate::solicit::frame::tests::build_padded_frame_payload;
use crate::solicit::frame::unpack_frames_for_test;
use crate::solicit::frame::FrameHeader;
use crate::solicit::frame::FrameIR;
use crate::solicit::frame::HttpFrame;
use crate::solicit::frame::{pack_header, Frame};
use crate::solicit::tests::common::raw_frame_from_parts;
use crate::Headers;
#[test]
fn test_parse_stream_dependency() {
{
let buf = [0, 0, 0, 1, 5];
let dep = StreamDependency::parse(&buf);
assert_eq!(dep.stream_id, 1);
assert_eq!(dep.weight, 5);
assert!(!dep.is_exclusive)
}
{
let buf = [128, 0, 0, 1, 5];
let dep = StreamDependency::parse(&buf);
assert_eq!(dep.stream_id, 1);
assert_eq!(dep.weight, 5);
assert!(dep.is_exclusive)
}
{
let buf = [255, 255, 255, 255, 5];
let dep = StreamDependency::parse(&buf);
assert_eq!(dep.stream_id, (1 << 31) - 1);
assert_eq!(dep.weight, 5);
assert!(dep.is_exclusive);
}
{
let buf = [127, 255, 255, 255, 5];
let dep = StreamDependency::parse(&buf);
assert_eq!(dep.stream_id, (1 << 31) - 1);
assert_eq!(dep.weight, 5);
assert!(!dep.is_exclusive);
}
}
#[test]
fn test_serialize_stream_dependency() {
{
let buf = [0, 0, 0, 1, 5];
let dep = StreamDependency::new(1, 5, false);
assert_eq!(buf, dep.serialize());
}
{
let buf = [128, 0, 0, 1, 5];
let dep = StreamDependency::new(1, 5, true);
assert_eq!(buf, dep.serialize());
}
{
let buf = [255, 255, 255, 255, 5];
let dep = StreamDependency::new((1 << 31) - 1, 5, true);
assert_eq!(buf, dep.serialize());
}
{
let buf = [127, 255, 255, 255, 5];
let dep = StreamDependency::new((1 << 31) - 1, 5, false);
assert_eq!(buf, dep.serialize());
}
}
#[test]
fn test_headers_frame_parse_simple() {
let data = b"123";
let payload = data.to_vec();
let header = FrameHeader::new(payload.len() as u32, 0x1, 0, 1);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: HeadersFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.header_fragment(), &data[..]);
assert_eq!(frame.flags.0, 0);
assert_eq!(frame.get_stream_id(), 1);
assert!(frame.stream_dep.is_none());
assert_eq!(0, frame.padding_len);
}
#[test]
fn test_headers_frame_parse_with_padding() {
let data = b"123";
let payload = build_padded_frame_payload(data, 6);
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x08, 1);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: HeadersFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.header_fragment(), &data[..]);
assert_eq!(frame.flags.0, 8);
assert_eq!(frame.get_stream_id(), 1);
assert!(frame.stream_dep.is_none());
assert_eq!(6, frame.padding_len);
}
#[test]
fn test_headers_frame_parse_with_priority() {
let data = b"123";
let dep = StreamDependency::new(0, 5, true);
let payload = {
let mut buf: Vec<u8> = Vec::new();
buf.extend(dep.serialize().to_vec().into_iter());
buf.extend(data.to_vec().into_iter());
buf
};
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x20, 1);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: HeadersFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.header_fragment(), &data[..]);
assert_eq!(frame.flags.0, 0x20);
assert_eq!(frame.get_stream_id(), 1);
assert_eq!(frame.stream_dep.unwrap(), dep);
assert_eq!(0, frame.padding_len);
}
#[test]
fn test_headers_frame_parse_padding_and_priority() {
let data = b"123";
let dep = StreamDependency::new(0, 5, true);
let full = {
let mut buf: Vec<u8> = Vec::new();
buf.extend(dep.serialize().to_vec().into_iter());
buf.extend(data.to_vec().into_iter());
buf
};
let payload = build_padded_frame_payload(&full, 4);
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x20 | 0x8, 1);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: HeadersFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.header_fragment(), &data[..]);
assert_eq!(frame.flags.0, 0x20 | 0x8);
assert_eq!(frame.get_stream_id(), 1);
assert_eq!(frame.stream_dep.unwrap(), dep);
assert_eq!(4, frame.padding_len);
}
#[test]
fn test_headers_frame_parse_invalid_stream_id() {
let data = b"123";
let payload = data.to_vec();
let header = FrameHeader::new(payload.len() as u32, 0x1, 0, 0);
let raw = raw_frame_from_parts(header, payload);
let frame = HeadersFrame::from_raw(&raw);
assert!(frame.is_err());
}
#[test]
fn test_headers_frame_parse_invalid_type() {
let data = b"123";
let payload = data.to_vec();
let header = FrameHeader::new(payload.len() as u32, 0x2, 0, 1);
let raw = raw_frame_from_parts(header, payload);
let frame = HeadersFrame::from_raw(&raw);
assert!(frame.is_err());
}
#[test]
fn test_headers_frame_serialize_simple() {
let data = b"123";
let payload = data.to_vec();
let header = FrameHeader::new(payload.len() as u32, 0x1, 0, 1);
let expected = {
let headers = pack_header(&header);
let mut res: Vec<u8> = Vec::new();
res.extend(headers.to_vec().into_iter());
res.extend(payload.into_iter());
res
};
let frame = HeadersFrame::new_conv(data.to_vec(), 1);
let actual = frame.serialize_into_vec();
assert_eq!(expected, actual);
}
#[test]
fn test_headers_frame_serialize_with_padding() {
let data = b"123";
let payload = build_padded_frame_payload(data, 6);
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x08, 1);
let expected = {
let headers = pack_header(&header);
let mut res: Vec<u8> = Vec::new();
res.extend(headers.to_vec().into_iter());
res.extend(payload.into_iter());
res
};
let mut frame = HeadersFrame::new_conv(data.to_vec(), 1);
frame.set_padding(6);
let actual = frame.serialize_into_vec();
assert_eq!(expected, actual);
}
#[test]
fn test_headers_frame_serialize_with_priority() {
let data = b"123";
let dep = StreamDependency::new(0, 5, true);
let payload = {
let mut buf: Vec<u8> = Vec::new();
buf.extend(dep.serialize().to_vec().into_iter());
buf.extend(data.to_vec().into_iter());
buf
};
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x20, 1);
let expected = {
let headers = pack_header(&header);
let mut res: Vec<u8> = Vec::new();
res.extend(headers.to_vec().into_iter());
res.extend(payload.into_iter());
res
};
let frame = HeadersFrame::with_dependency(data.to_vec(), 1, dep.clone());
let actual = frame.serialize_into_vec();
assert_eq!(expected, actual);
}
#[test]
fn test_headers_frame_serialize_padding_and_priority() {
let data = b"123";
let dep = StreamDependency::new(0, 5, true);
let full = {
let mut buf: Vec<u8> = Vec::new();
buf.extend(dep.serialize().to_vec().into_iter());
buf.extend(data.to_vec().into_iter());
buf
};
let payload = build_padded_frame_payload(&full, 4);
let header = FrameHeader::new(payload.len() as u32, 0x1, 0x20 | 0x8, 1);
let expected = {
let headers = pack_header(&header);
let mut res: Vec<u8> = Vec::new();
res.extend(headers.to_vec().into_iter());
res.extend(payload.into_iter());
res
};
let mut frame = HeadersFrame::with_dependency(data.to_vec(), 1, dep.clone());
frame.set_padding(4);
let actual = frame.serialize_into_vec();
assert_eq!(expected, actual);
}
#[test]
fn test_headers_frame_is_headers_end() {
let mut frame = HeadersFrame::new_conv(Vec::new(), 1);
assert!(!frame.is_headers_end());
frame.set_flag(HeadersFlag::EndHeaders);
assert!(frame.is_headers_end());
}
#[test]
fn test_headers_multi_frame() {
let mut encoder = hpack::Encoder::new();
let mut headers = Headers::ok_200();
for i in 0..1000 {
headers.add(format!("h-{}", i), format!("v-{}", i))
}
let max_frame_size = 1000;
let serialized = HeadersMultiFrame {
flags: Flags::new(0).with(HeadersFlag::EndStream),
stream_id: 2,
headers,
stream_dep: None,
padding_len: 0,
encoder: &mut encoder,
max_frame_size,
}
.serialize_into_vec();
let frames = unpack_frames_for_test(&serialized);
assert!(frames.len() > 2);
for (i, f) in frames.iter().enumerate() {
match f {
HttpFrame::Headers(h) => {
assert_eq!(0, i);
assert_eq!(max_frame_size as usize, h.header_fragment.len());
assert_eq!(Flags::new(0).with(HeadersFlag::EndStream), h.flags);
}
HttpFrame::Continuation(h) => {
assert_ne!(0, i);
let last = i == frames.len() - 1;
if !last {
assert_eq!(max_frame_size as usize, h.header_fragment.len());
assert_eq!(Flags::new(0), h.flags);
} else {
assert_eq!(Flags::new(0).with(ContinuationFlag::EndHeaders), h.flags);
}
}
_ => panic!("wrong frame type"),
}
}
}
}