use std::io;
use std::borrow::Cow;
use http::StreamId;
use http::frame::{FrameBuilder, FrameIR, Flag, Frame, FrameHeader, RawFrame, parse_padded_payload};
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Copy)]
pub enum HeadersFlag {
EndStream = 0x1,
EndHeaders = 0x4,
Padded = 0x8,
Priority = 0x20,
}
impl Flag for HeadersFlag {
#[inline]
fn bitmask(&self) -> u8 {
*self as u8
}
}
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(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)]
#[derive(Debug)]
#[derive(Clone)]
pub struct HeadersFrame<'a> {
header_fragment: Cow<'a, [u8]>,
pub stream_id: StreamId,
pub stream_dep: Option<StreamDependency>,
pub padding_len: Option<u8>,
flags: u8,
}
impl<'a> HeadersFrame<'a> {
pub fn new(fragment: Vec<u8>, stream_id: StreamId) -> HeadersFrame<'a> {
HeadersFrame {
header_fragment: Cow::Owned(fragment),
stream_id: stream_id,
stream_dep: None,
padding_len: None,
flags: 0,
}
}
pub fn with_dependency(fragment: Vec<u8>,
stream_id: StreamId,
stream_dep: StreamDependency)
-> HeadersFrame<'a> {
HeadersFrame {
header_fragment: Cow::Owned(fragment),
stream_id: stream_id,
stream_dep: Some(stream_dep),
padding_len: None,
flags: HeadersFlag::Priority.bitmask(),
}
}
pub fn is_headers_end(&self) -> bool {
self.is_set(HeadersFlag::EndHeaders)
}
pub fn is_end_of_stream(&self) -> bool {
self.is_set(HeadersFlag::EndStream)
}
pub fn set_padding(&mut self, padding_len: u8) {
self.padding_len = Some(padding_len);
self.set_flag(HeadersFlag::Padded);
}
fn payload_len(&self) -> u32 {
let padding = if self.is_set(HeadersFlag::Padded) {
1 + self.padding_len.unwrap_or(0) as u32
} else {
0
};
let priority = if self.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 |= flag.bitmask();
}
}
impl<'a> Frame<'a> for HeadersFrame<'a> {
type FlagType = HeadersFlag;
fn from_raw(raw_frame: &'a RawFrame) -> Option<HeadersFrame<'a>> {
let (len, frame_type, flags, stream_id) = raw_frame.header();
if frame_type != 0x1 {
return None;
}
if (len as usize) != raw_frame.payload().len() {
return None;
}
if stream_id == 0 {
return None;
}
let padded = (flags & HeadersFlag::Padded.bitmask()) != 0;
let (actual, pad_len) = if padded {
match parse_padded_payload(&raw_frame.payload()) {
Some((data, pad_len)) => (data, Some(pad_len)),
None => return None,
}
} else {
(raw_frame.payload(), None)
};
let priority = (flags & HeadersFlag::Priority.bitmask()) != 0;
let (data, stream_dep) = if priority {
(&actual[5..], Some(StreamDependency::parse(&actual[..5])))
} else {
(actual, None)
};
Some(HeadersFrame {
header_fragment: Cow::Borrowed(data),
stream_id: stream_id,
stream_dep: stream_dep,
padding_len: pad_len,
flags: flags,
})
}
fn is_set(&self, flag: HeadersFlag) -> bool {
(self.flags & flag.bitmask()) != 0
}
fn get_stream_id(&self) -> StreamId {
self.stream_id
}
fn get_header(&self) -> FrameHeader {
(self.payload_len(), 0x1, self.flags, self.stream_id)
}
}
impl<'a> FrameIR for HeadersFrame<'a> {
fn serialize_into<B: FrameBuilder>(self, b: &mut B) -> io::Result<()> {
try!(b.write_header(self.get_header()));
let padded = self.is_set(HeadersFlag::Padded);
if padded {
try!(b.write_all(&[self.padding_len.unwrap_or(0)]));
}
if self.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"),
};
try!(b.write_all(&dep_buf));
}
try!(b.write_all(&self.header_fragment));
if padded {
try!(b.write_padding(self.padding_len.unwrap_or(0)));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{HeadersFrame, HeadersFlag, StreamDependency};
use http::frame::tests::build_padded_frame_payload;
use http::tests::common::{raw_frame_from_parts, serialize_frame};
use http::frame::{pack_header, Frame};
#[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 = (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);
assert_eq!(frame.get_stream_id(), 1);
assert!(frame.stream_dep.is_none());
assert!(frame.padding_len.is_none());
}
#[test]
fn test_headers_frame_parse_with_padding() {
let data = b"123";
let payload = build_padded_frame_payload(data, 6);
let header = (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, 8);
assert_eq!(frame.get_stream_id(), 1);
assert!(frame.stream_dep.is_none());
assert_eq!(frame.padding_len.unwrap(), 6);
}
#[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 = (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, 0x20);
assert_eq!(frame.get_stream_id(), 1);
assert_eq!(frame.stream_dep.unwrap(), dep);
assert!(frame.padding_len.is_none());
}
#[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 = (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, 0x20 | 0x8);
assert_eq!(frame.get_stream_id(), 1);
assert_eq!(frame.stream_dep.unwrap(), dep);
assert_eq!(frame.padding_len.unwrap(), 4);
}
#[test]
fn test_headers_frame_parse_invalid_stream_id() {
let data = b"123";
let payload = data.to_vec();
let header = (payload.len() as u32, 0x1, 0, 0);
let raw = raw_frame_from_parts(header, payload);
let frame: Option<HeadersFrame> = Frame::from_raw(&raw);
assert!(frame.is_none());
}
#[test]
fn test_headers_frame_parse_invalid_type() {
let data = b"123";
let payload = data.to_vec();
let header = (payload.len() as u32, 0x2, 0, 1);
let raw = raw_frame_from_parts(header, payload);
let frame: Option<HeadersFrame> = Frame::from_raw(&raw);
assert!(frame.is_none());
}
#[test]
fn test_headers_frame_serialize_simple() {
let data = b"123";
let payload = data.to_vec();
let header = (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(data.to_vec(), 1);
let actual = serialize_frame(&frame);
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 = (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(data.to_vec(), 1);
frame.set_padding(6);
let actual = serialize_frame(&frame);
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 = (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 = serialize_frame(&frame);
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 = (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 = serialize_frame(&frame);
assert_eq!(expected, actual);
}
#[test]
fn test_headers_frame_is_headers_end() {
let mut frame = HeadersFrame::new(vec![], 1);
assert!(!frame.is_headers_end());
frame.set_flag(HeadersFlag::EndHeaders);
assert!(frame.is_headers_end());
}
}