Work
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use super::Error;
|
||||
|
||||
use bytes::{BufMut, BigEndian};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Head {
|
||||
kind: Kind,
|
||||
@@ -25,9 +27,19 @@ pub enum Kind {
|
||||
|
||||
pub type StreamId = u32;
|
||||
|
||||
const STREAM_ID_MASK: StreamId = 0x80000000;
|
||||
|
||||
// ===== impl Head =====
|
||||
|
||||
impl Head {
|
||||
pub fn new(kind: Kind, flag: u8, stream_id: StreamId) -> Head {
|
||||
Head {
|
||||
kind: kind,
|
||||
flag: flag,
|
||||
stream_id: stream_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an HTTP/2.0 frame header
|
||||
pub fn parse(header: &[u8]) -> Head {
|
||||
Head {
|
||||
@@ -48,6 +60,21 @@ impl Head {
|
||||
pub fn flag(&self) -> u8 {
|
||||
self.flag
|
||||
}
|
||||
|
||||
pub fn encode_len(&self) -> usize {
|
||||
super::FRAME_HEADER_LEN
|
||||
}
|
||||
|
||||
pub fn encode<T: BufMut>(&self, payload_len: usize, dst: &mut T) -> Result<(), Error> {
|
||||
debug_assert_eq!(self.encode_len(), dst.remaining_mut());
|
||||
debug_assert!(self.stream_id & STREAM_ID_MASK == 0);
|
||||
|
||||
dst.put_uint::<BigEndian>(payload_len as u64, 3);
|
||||
dst.put_u8(self.kind as u8);
|
||||
dst.put_u8(self.flag);
|
||||
dst.put_u32::<BigEndian>(self.stream_id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the next 4 octets in the given buffer, assuming they represent an
|
||||
@@ -58,7 +85,7 @@ impl Head {
|
||||
fn parse_stream_id(buf: &[u8]) -> StreamId {
|
||||
let unpacked = unpack_octets_4!(buf, 0, u32);
|
||||
// Now clear the most significant bit, as that is reserved and MUST be ignored when received.
|
||||
unpacked & !0x80000000
|
||||
unpacked & !STREAM_ID_MASK
|
||||
}
|
||||
|
||||
// ===== impl Kind =====
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use bytes::Bytes;
|
||||
use error::{ConnectionError, Reason};
|
||||
use bytes::{Bytes, BytesMut, BufMut};
|
||||
|
||||
use std::io;
|
||||
|
||||
/// A helper macro that unpacks a sequence of 4 bytes found in the buffer with
|
||||
/// the given identifier, starting at the given offset, into the given integer
|
||||
@@ -29,10 +32,27 @@ mod util;
|
||||
|
||||
pub use self::data::Data;
|
||||
pub use self::head::{Head, Kind, StreamId};
|
||||
pub use self::settings::Settings;
|
||||
pub use self::unknown::Unknown;
|
||||
|
||||
const FRAME_HEADER_LEN: usize = 9;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Frame {
|
||||
/*
|
||||
Data(DataFrame<'a>),
|
||||
HeadersFrame(HeadersFrame<'a>),
|
||||
RstStreamFrame(RstStreamFrame),
|
||||
SettingsFrame(SettingsFrame),
|
||||
PingFrame(PingFrame),
|
||||
GoawayFrame(GoawayFrame<'a>),
|
||||
WindowUpdateFrame(WindowUpdateFrame),
|
||||
UnknownFrame(RawFrame<'a>),
|
||||
*/
|
||||
Settings(Settings),
|
||||
Unknown(Unknown),
|
||||
}
|
||||
|
||||
/// Errors that can occur during parsing an HTTP/2 frame.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
@@ -64,26 +84,22 @@ pub enum Error {
|
||||
|
||||
/// The payload length specified by the frame header was not the
|
||||
/// value necessary for the specific frame type.
|
||||
InvalidPayloadLength
|
||||
InvalidPayloadLength,
|
||||
|
||||
/// Received a payload with an ACK settings frame
|
||||
InvalidPayloadAckSettings,
|
||||
|
||||
/// An invalid stream identifier was provided.
|
||||
///
|
||||
/// This is returned if a settings frame is received with a stream
|
||||
/// identifier other than zero.
|
||||
InvalidStreamId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Frame {
|
||||
/*
|
||||
Data(DataFrame<'a>),
|
||||
HeadersFrame(HeadersFrame<'a>),
|
||||
RstStreamFrame(RstStreamFrame),
|
||||
SettingsFrame(SettingsFrame),
|
||||
PingFrame(PingFrame),
|
||||
GoawayFrame(GoawayFrame<'a>),
|
||||
WindowUpdateFrame(WindowUpdateFrame),
|
||||
UnknownFrame(RawFrame<'a>),
|
||||
*/
|
||||
Unknown(Unknown),
|
||||
}
|
||||
// ===== impl Frame ======
|
||||
|
||||
impl Frame {
|
||||
pub fn load(mut frame: Bytes) -> Frame {
|
||||
pub fn load(mut frame: Bytes) -> Result<Frame, Error> {
|
||||
let head = Head::parse(&frame);
|
||||
|
||||
// Extract the payload from the frame
|
||||
@@ -91,8 +107,44 @@ impl Frame {
|
||||
|
||||
|
||||
match head.kind() {
|
||||
Kind::Unknown => Frame::Unknown(Unknown::new(head, frame)),
|
||||
Kind::Unknown => {
|
||||
let unknown = Unknown::new(head, frame);
|
||||
Ok(Frame::Unknown(unknown))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_len(&self) -> usize {
|
||||
use self::Frame::*;
|
||||
|
||||
match *self {
|
||||
Settings(ref frame) => frame.encode_len(),
|
||||
Unknown(ref frame) => frame.encode_len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(&self, dst: &mut BytesMut) -> Result<(), Error> {
|
||||
use self::Frame::*;
|
||||
|
||||
debug_assert!(dst.remaining_mut() >= self.encode_len());
|
||||
|
||||
match *self {
|
||||
Settings(ref frame) => frame.encode(dst),
|
||||
Unknown(ref frame) => frame.encode(dst),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl Error =====
|
||||
|
||||
impl From<Error> for ConnectionError {
|
||||
fn from(src: Error) -> ConnectionError {
|
||||
use self::Error::*;
|
||||
|
||||
match src {
|
||||
// TODO: implement
|
||||
_ => ConnectionError::Proto(Reason::ProtocolError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
src/frame/reader.rs
Normal file
40
src/frame/reader.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use ConnectionError;
|
||||
use super::Frame;
|
||||
use futures::*;
|
||||
use bytes::BytesMut;
|
||||
use std::io;
|
||||
|
||||
pub struct Reader<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> Stream for Reader<T>
|
||||
where T: Stream<Item = BytesMut, Error = io::Error>,
|
||||
{
|
||||
type Item = Frame;
|
||||
type Error = ConnectionError;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Frame>, ConnectionError> {
|
||||
match try_ready!(self.inner.poll()) {
|
||||
Some(bytes) => {
|
||||
Frame::load(bytes.freeze())
|
||||
.map(|frame| Async::Ready(Some(frame)))
|
||||
.map_err(ConnectionError::from)
|
||||
}
|
||||
None => Ok(Async::Ready(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sink> Sink for Reader<T> {
|
||||
type SinkItem = T::SinkItem;
|
||||
type SinkError = T::SinkError;
|
||||
|
||||
fn start_send(&mut self, item: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> {
|
||||
self.inner.start_send(item)
|
||||
}
|
||||
|
||||
fn poll_complete(&mut self) -> Poll<(), T::SinkError> {
|
||||
self.inner.poll_complete()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use frame::{Error, Head};
|
||||
use bytes::Bytes;
|
||||
use frame::{Error, Head, Kind};
|
||||
use bytes::{Bytes, BytesMut, BufMut, BigEndian};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
pub struct Settings {
|
||||
flag: SettingsFlag,
|
||||
// Fields
|
||||
@@ -41,8 +41,7 @@ impl Settings {
|
||||
debug_assert_eq!(head.kind(), ::frame::Kind::Settings);
|
||||
|
||||
if head.stream_id() != 0 {
|
||||
// TODO: raise ProtocolError
|
||||
unimplemented!();
|
||||
return Err(Error::InvalidStreamId);
|
||||
}
|
||||
|
||||
// Load the flag
|
||||
@@ -51,8 +50,7 @@ impl Settings {
|
||||
if flag.is_ack() {
|
||||
// Ensure that the payload is empty
|
||||
if payload.len() > 0 {
|
||||
// TODO: raise a FRAME_SIZE_ERROR
|
||||
unimplemented!();
|
||||
return Err(Error::InvalidPayloadLength);
|
||||
}
|
||||
|
||||
// Return the ACK frame
|
||||
@@ -64,7 +62,7 @@ impl Settings {
|
||||
|
||||
// Ensure the payload length is correct, each setting is 6 bytes long.
|
||||
if payload.len() % 6 != 0 {
|
||||
return Err(Error::PartialSettingLength);
|
||||
return Err(Error::InvalidPayloadAckSettings);
|
||||
}
|
||||
|
||||
let mut settings = Settings::default();
|
||||
@@ -96,6 +94,57 @@ impl Settings {
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
pub fn encode_len(&self) -> usize {
|
||||
super::FRAME_HEADER_LEN + self.payload_len()
|
||||
}
|
||||
|
||||
fn payload_len(&self) -> usize {
|
||||
let mut len = 0;
|
||||
self.for_each(|_| len += 6);
|
||||
len
|
||||
}
|
||||
|
||||
pub fn encode(&self, dst: &mut BytesMut) -> Result<(), Error> {
|
||||
// Create & encode an appropriate frame head
|
||||
let head = Head::new(Kind::Settings, self.flag.into(), 0);
|
||||
let payload_len = self.payload_len();
|
||||
|
||||
try!(head.encode(payload_len, dst));
|
||||
|
||||
// Encode the settings
|
||||
self.for_each(|setting| setting.encode(dst));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn for_each<F: FnMut(Setting)>(&self, mut f: F) {
|
||||
use self::Setting::*;
|
||||
|
||||
if let Some(v) = self.header_table_size {
|
||||
f(HeaderTableSize(v));
|
||||
}
|
||||
|
||||
if let Some(v) = self.enable_push {
|
||||
f(EnablePush(if v { 1 } else { 0 }));
|
||||
}
|
||||
|
||||
if let Some(v) = self.max_concurrent_streams {
|
||||
f(MaxConcurrentStreams(v));
|
||||
}
|
||||
|
||||
if let Some(v) = self.initial_window_size {
|
||||
f(InitialWindowSize(v));
|
||||
}
|
||||
|
||||
if let Some(v) = self.max_frame_size {
|
||||
f(MaxFrameSize(v));
|
||||
}
|
||||
|
||||
if let Some(v) = self.max_header_list_size {
|
||||
f(MaxHeaderListSize(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl Setting =====
|
||||
@@ -134,6 +183,22 @@ impl Setting {
|
||||
|
||||
Setting::from_id(id, val)
|
||||
}
|
||||
|
||||
fn encode(&self, dst: &mut BytesMut) {
|
||||
use self::Setting::*;
|
||||
|
||||
let (kind, val) = match *self {
|
||||
HeaderTableSize(v) => (1, v),
|
||||
EnablePush(v) => (2, v),
|
||||
MaxConcurrentStreams(v) => (3, v),
|
||||
InitialWindowSize(v) => (4, v),
|
||||
MaxFrameSize(v) => (5, v),
|
||||
MaxHeaderListSize(v) => (6, v),
|
||||
};
|
||||
|
||||
dst.put_u16::<BigEndian>(kind);
|
||||
dst.put_u32::<BigEndian>(val);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl SettingsFlag =====
|
||||
@@ -151,3 +216,9 @@ impl SettingsFlag {
|
||||
self.0 & ACK == ACK
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SettingsFlag> for u8 {
|
||||
fn from(src: SettingsFlag) -> u8 {
|
||||
src.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use frame::Head;
|
||||
use bytes::Bytes;
|
||||
use frame::{Head, Error};
|
||||
use bytes::{Bytes, BytesMut, BufMut};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Unknown {
|
||||
@@ -14,4 +14,14 @@ impl Unknown {
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_len(&self) -> usize {
|
||||
self.head.encode_len() + self.payload.len()
|
||||
}
|
||||
|
||||
pub fn encode(&self, dst: &mut BytesMut) -> Result<(), Error> {
|
||||
try!(self.head.encode(self.payload.len(), dst));
|
||||
dst.put(&self.payload);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
1
src/frame/writer.rs
Normal file
1
src/frame/writer.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub struct Writer;
|
||||
Reference in New Issue
Block a user