use std::io;
use http::StreamId;
use http::frame::{FrameBuilder, FrameIR, Flag, Frame, FrameHeader, RawFrame};
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Copy)]
pub enum HttpSetting {
HeaderTableSize(u32),
EnablePush(u32),
MaxConcurrentStreams(u32),
InitialWindowSize(u32),
MaxFrameSize(u32),
MaxHeaderListSize(u32),
}
impl HttpSetting {
pub fn from_id(id: u16, val: u32) -> Option<HttpSetting> {
match id {
1 => Some(HttpSetting::HeaderTableSize(val)),
2 => Some(HttpSetting::EnablePush(val)),
3 => Some(HttpSetting::MaxConcurrentStreams(val)),
4 => Some(HttpSetting::InitialWindowSize(val)),
5 => Some(HttpSetting::MaxFrameSize(val)),
6 => Some(HttpSetting::MaxHeaderListSize(val)),
_ => None,
}
}
fn parse_setting(raw_setting: &[u8]) -> Option<HttpSetting> {
let id: u16 = ((raw_setting[0] as u16) << 8) | (raw_setting[1] as u16);
let val: u32 = unpack_octets_4!(raw_setting, 2, u32);
HttpSetting::from_id(id, val)
}
pub fn get_id(&self) -> u16 {
match *self {
HttpSetting::HeaderTableSize(_) => 1,
HttpSetting::EnablePush(_) => 2,
HttpSetting::MaxConcurrentStreams(_) => 3,
HttpSetting::InitialWindowSize(_) => 4,
HttpSetting::MaxFrameSize(_) => 5,
HttpSetting::MaxHeaderListSize(_) => 6,
}
}
pub fn get_val(&self) -> u32 {
match *self {
HttpSetting::HeaderTableSize(ref val) |
HttpSetting::EnablePush(ref val) |
HttpSetting::MaxConcurrentStreams(ref val) |
HttpSetting::InitialWindowSize(ref val) |
HttpSetting::MaxFrameSize(ref val) |
HttpSetting::MaxHeaderListSize(ref val) => *val,
}
}
fn serialize(&self) -> [u8; 6] {
let (id, val) = (self.get_id(), self.get_val());
[((id >> 8) & 0x00FF) as u8,
((id ) & 0x00FF) as u8,
(((val >> 24) & 0x000000FF) as u8),
(((val >> 16) & 0x000000FF) as u8),
(((val >> 8) & 0x000000FF) as u8),
(((val ) & 0x000000FF) as u8)]
}
}
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Copy)]
pub enum SettingsFlag {
Ack = 0x1,
}
impl Flag for SettingsFlag {
#[inline]
fn bitmask(&self) -> u8 {
*self as u8
}
}
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Clone)]
pub struct SettingsFrame {
pub settings: Vec<HttpSetting>,
flags: u8,
}
impl SettingsFrame {
pub fn new() -> SettingsFrame {
SettingsFrame {
settings: Vec::new(),
flags: 0,
}
}
pub fn new_ack() -> SettingsFrame {
SettingsFrame {
settings: Vec::new(),
flags: SettingsFlag::Ack.bitmask(),
}
}
pub fn add_setting(&mut self, setting: HttpSetting) {
self.settings.push(setting);
}
pub fn set_ack(&mut self) {
self.set_flag(SettingsFlag::Ack)
}
pub fn is_ack(&self) -> bool {
self.is_set(SettingsFlag::Ack)
}
fn payload_len(&self) -> u32 {
6 * self.settings.len() as u32
}
fn parse_payload(payload: &[u8]) -> Option<Vec<HttpSetting>> {
if payload.len() % 6 != 0 {
return None;
}
Some(payload.chunks(6)
.filter_map(|chunk| HttpSetting::parse_setting(chunk))
.collect())
}
pub fn set_flag(&mut self, flag: SettingsFlag) {
self.flags |= flag.bitmask();
}
}
impl<'a> Frame<'a> for SettingsFrame {
type FlagType = SettingsFlag;
fn from_raw(raw_frame: &RawFrame) -> Option<SettingsFrame> {
let (len, frame_type, flags, stream_id) = raw_frame.header();
if frame_type != 0x4 {
return None;
}
if (len as usize) != raw_frame.payload().len() {
return None;
}
if stream_id != 0 {
return None;
}
if (flags & SettingsFlag::Ack.bitmask()) != 0 {
return if len == 0 {
Some(SettingsFrame {
settings: Vec::new(),
flags: flags,
})
} else {
None
}
}
match SettingsFrame::parse_payload(&raw_frame.payload()) {
Some(settings) => {
Some(SettingsFrame {
settings: settings,
flags: flags,
})
}
None => None,
}
}
fn is_set(&self, flag: SettingsFlag) -> bool {
(self.flags & flag.bitmask()) != 0
}
fn get_stream_id(&self) -> StreamId {
0
}
fn get_header(&self) -> FrameHeader {
(self.payload_len(), 0x4, self.flags, 0)
}
}
impl FrameIR for SettingsFrame {
fn serialize_into<B: FrameBuilder>(self, b: &mut B) -> io::Result<()> {
try!(b.write_header(self.get_header()));
for setting in &self.settings {
try!(b.write_all(&setting.serialize()));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{HttpSetting, SettingsFrame};
use http::tests::common::{raw_frame_from_parts, serialize_frame};
use http::frame::{pack_header, Frame};
#[test]
fn test_settings_frame_parse_no_ack_one_setting() {
let payload = [0, 1, 0, 0, 0, 1];
let header = (payload.len() as u32, 4, 0, 0);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: SettingsFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.settings, vec![HttpSetting::HeaderTableSize(1)]);
assert_eq!(frame.get_header(), header);
}
#[test]
fn test_settings_frame_parse_no_ack_multiple_settings() {
let settings = vec![
HttpSetting::HeaderTableSize(1),
HttpSetting::MaxHeaderListSize(5),
HttpSetting::EnablePush(0),
];
let payload = {
let mut res: Vec<u8> = Vec::new();
for s in settings.iter().map(|s| s.serialize()) {
res.extend(s.to_vec().into_iter());
}
res
};
let header = (payload.len() as u32, 4, 0, 0);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: SettingsFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.settings, settings);
assert_eq!(frame.get_header(), header);
assert!(!frame.is_ack());
}
#[test]
fn test_settings_frame_parse_no_ack_duplicate_settings() {
let settings = vec![
HttpSetting::HeaderTableSize(1),
HttpSetting::MaxHeaderListSize(5),
HttpSetting::EnablePush(0),
HttpSetting::HeaderTableSize(2),
];
let payload = {
let mut res: Vec<u8> = Vec::new();
for s in settings.iter().map(|s| s.serialize()) {
res.extend(s.to_vec().into_iter());
}
res
};
let header = (payload.len() as u32, 4, 0, 0);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: SettingsFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.settings, settings);
assert_eq!(frame.get_header(), header);
assert!(!frame.is_ack());
}
#[test]
fn test_settings_frame_parse_no_ack_unknown_setting() {
let settings = vec![
HttpSetting::HeaderTableSize(1),
HttpSetting::MaxHeaderListSize(5),
];
let payload = {
let mut res: Vec<u8> = Vec::new();
for s in settings.iter().map(|s| s.serialize()) {
res.extend(s.to_vec().into_iter());
}
res.extend(vec![0, 10, 0, 0, 0, 0].into_iter());
for s in settings.iter().map(|s| s.serialize()) {
res.extend(s.to_vec().into_iter());
}
res
};
let header = (payload.len() as u32, 4, 0, 0);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: SettingsFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.settings.len(), 4);
assert_eq!(&frame.settings[0..2], &settings[..]);
assert_eq!(&frame.settings[2..], &settings[..]);
assert!(!frame.is_ack());
}
#[test]
fn test_settings_frame_parse_ack_no_settings() {
let payload = [];
let header = (payload.len() as u32, 4, 1, 0);
let raw = raw_frame_from_parts(header.clone(), payload.to_vec());
let frame: SettingsFrame = Frame::from_raw(&raw).unwrap();
assert_eq!(frame.settings, vec![]);
assert_eq!(frame.get_header(), header);
assert!(frame.is_ack());
}
#[test]
fn test_settings_frame_parse_ack_with_settings() {
let settings = [HttpSetting::EnablePush(0)];
let payload = {
let mut res: Vec<u8> = Vec::new();
for s in settings.iter().map(|s| s.serialize()) {
res.extend(s.to_vec().into_iter());
}
res
};
let header = (payload.len() as u32, 4, 1, 0);
let raw = raw_frame_from_parts(header, payload);
let frame: Option<SettingsFrame> = Frame::from_raw(&raw);
assert!(frame.is_none());
}
#[test]
fn test_settings_frame_parse_not_stream_zero() {
let payload = vec![];
let header = (payload.len() as u32, 4, 1, 1);
let raw = raw_frame_from_parts(header, payload);
let frame: Option<SettingsFrame> = Frame::from_raw(&raw);
assert!(frame.is_none());
}
#[test]
fn test_settings_frame_parse_not_multiple_of_six() {
let payload = vec![1, 2, 3];
let header = (payload.len() as u32, 4, 0, 0);
let raw = raw_frame_from_parts(header, payload);
let frame: Option<SettingsFrame> = Frame::from_raw(&raw);
assert!(frame.is_none());
}
#[test]
fn test_settings_frame_serialize_no_ack_settings() {
let mut frame = SettingsFrame::new();
frame.add_setting(HttpSetting::EnablePush(0));
let expected = {
let mut res: Vec<u8> = Vec::new();
res.extend(pack_header(&(6, 4, 0, 0)).to_vec().into_iter());
res.extend(HttpSetting::EnablePush(0).serialize().to_vec().into_iter());
res
};
let serialized = serialize_frame(&frame);
assert_eq!(serialized, expected);
}
#[test]
fn test_settings_frame_serialize_no_ack_multiple_settings() {
let mut frame = SettingsFrame::new();
frame.add_setting(HttpSetting::EnablePush(0));
frame.add_setting(HttpSetting::MaxHeaderListSize(0));
let expected = {
let mut res: Vec<u8> = Vec::new();
res.extend(pack_header(&(6 * 2, 4, 0, 0)).to_vec().into_iter());
res.extend(HttpSetting::EnablePush(0).serialize().to_vec().into_iter());
res.extend(HttpSetting::MaxHeaderListSize(0).serialize().to_vec().into_iter());
res
};
let serialized = serialize_frame(&frame);
assert_eq!(serialized, expected);
}
#[test]
fn test_settings_frame_serialize_ack() {
let frame = SettingsFrame::new_ack();
let expected = pack_header(&(0, 4, 1, 0)).to_vec();
let serialized = serialize_frame(&frame);
assert_eq!(serialized, expected);
}
#[test]
fn test_setting_deserialize() {
{
let buf = [0, 1, 0, 0, 1, 0];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::HeaderTableSize(1 << 8));
}
{
let buf = [0, 2, 0, 0, 0, 1];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::EnablePush(1));
}
{
let buf = [0, 3, 0, 0, 0, 0];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::MaxConcurrentStreams(0));
}
{
let buf = [0, 4, 0, 0, 0, 1];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::InitialWindowSize(1));
}
{
let buf = [0, 5, 0, 0, 0, 255];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::MaxFrameSize((1 << 8) - 1));
}
{
let buf = [0, 6, 0, 0, 0, 255];
let setting = HttpSetting::parse_setting(&buf).unwrap();
assert_eq!(setting, HttpSetting::MaxHeaderListSize((1 << 8) - 1));
}
{
let buf = [0, 7, 0, 0, 0, 255];
let setting = HttpSetting::parse_setting(&buf);
assert!(setting.is_none());
}
{
let buf = [0, 0, 0, 0, 0, 255];
let setting = HttpSetting::parse_setting(&buf);
assert!(setting.is_none());
}
}
#[test]
fn test_setting_serialize() {
{
let buf = [0, 1, 0, 0, 1, 0];
let setting = HttpSetting::HeaderTableSize(1 << 8);
assert_eq!(buf, setting.serialize());
}
{
let buf = [0, 2, 0, 0, 0, 1];
let setting = HttpSetting::EnablePush(1);
assert_eq!(buf, setting.serialize());
}
{
let buf = [0, 3, 0, 0, 0, 0];
let setting = HttpSetting::MaxConcurrentStreams(0);
assert_eq!(buf, setting.serialize());
}
{
let buf = [0, 4, 0, 0, 0, 1];
let setting = HttpSetting::InitialWindowSize(1);
assert_eq!(buf, setting.serialize());
}
{
let buf = [0, 5, 0, 0, 0, 255];
let setting = HttpSetting::MaxFrameSize((1 << 8) - 1);
assert_eq!(buf, setting.serialize());
}
{
let buf = [0, 6, 0, 0, 0, 255];
let setting = HttpSetting::MaxHeaderListSize((1 << 8) - 1);
assert_eq!(buf, setting.serialize());
}
}
}