Merge branch 'master' into ver/flowio
This commit is contained in:
		| @@ -3,26 +3,33 @@ use {frame, proto, Peer, ConnectionError, StreamId}; | ||||
| use http; | ||||
| use futures::{Future, Poll}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
|  | ||||
| use std::fmt; | ||||
|  | ||||
| /// In progress H2 connection binding | ||||
| pub struct Handshake<T> { | ||||
| pub struct Handshake<T, B: IntoBuf = Bytes> { | ||||
|     // TODO: unbox | ||||
|     inner: Box<Future<Item = Connection<T>, Error = ConnectionError>>, | ||||
|     inner: Box<Future<Item = Connection<T, B>, Error = ConnectionError>>, | ||||
| } | ||||
|  | ||||
| /// Marker type indicating a client peer | ||||
| #[derive(Debug)] | ||||
| pub struct Client; | ||||
|  | ||||
| pub type Connection<T> = super::Connection<T, Client>; | ||||
| pub type Connection<T, B = Bytes> = super::Connection<T, Client, B>; | ||||
|  | ||||
| pub fn handshake<T>(io: T) -> Handshake<T, Bytes> | ||||
|     where T: AsyncRead + AsyncWrite + 'static, | ||||
| { | ||||
|     handshake2(io) | ||||
| } | ||||
|  | ||||
| /// Bind an H2 client connection. | ||||
| /// | ||||
| /// Returns a future which resolves to the connection value once the H2 | ||||
| /// handshake has been completed. | ||||
| pub fn handshake<T>(io: T) -> Handshake<T> | ||||
| pub fn handshake2<T, B: IntoBuf>(io: T) -> Handshake<T, B> | ||||
|     where T: AsyncRead + AsyncWrite + 'static, | ||||
| { | ||||
|     use tokio_io::io; | ||||
| @@ -97,8 +104,8 @@ impl Peer for Client { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Future for Handshake<T> { | ||||
|     type Item = Connection<T>; | ||||
| impl<T, B: IntoBuf> Future for Handshake<T, B> { | ||||
|     type Item = Connection<T, B>; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||
| @@ -106,7 +113,10 @@ impl<T> Future for Handshake<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: fmt::Debug> fmt::Debug for Handshake<T> { | ||||
| impl<T, B> fmt::Debug for Handshake<T, B> | ||||
|     where T: fmt::Debug, | ||||
|           B: fmt::Debug + IntoBuf, | ||||
| { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(fmt, "client::Handshake") | ||||
|     } | ||||
|   | ||||
							
								
								
									
										99
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								src/error.rs
									
									
									
									
									
								
							| @@ -3,14 +3,24 @@ use std::{error, fmt, io}; | ||||
| /// The error type for HTTP/2 operations | ||||
| #[derive(Debug)] | ||||
| pub enum ConnectionError { | ||||
|     /// The HTTP/2 stream was reset | ||||
|     /// An error caused by an action taken by the remote peer. | ||||
|     /// | ||||
|     /// This is either an error received by the peer or caused by an invalid | ||||
|     /// action taken by the peer (i.e. a protocol error). | ||||
|     Proto(Reason), | ||||
|  | ||||
|     /// An `io::Error` occurred while trying to read or write. | ||||
|     Io(io::Error), | ||||
|  | ||||
|     /// An error resulting from an invalid action taken by the user of this | ||||
|     /// library. | ||||
|     User(User), | ||||
|  | ||||
|     // TODO: reserve additional variants | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct StreamError(Reason); | ||||
| pub struct Stream(Reason); | ||||
|  | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||||
| pub enum Reason { | ||||
| @@ -29,27 +39,60 @@ pub enum Reason { | ||||
|     InadequateSecurity, | ||||
|     Http11Required, | ||||
|     Other(u32), | ||||
|     // TODO: reserve additional variants | ||||
| } | ||||
|  | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||||
| pub enum User { | ||||
|     /// The specified stream ID is invalid. | ||||
|     /// | ||||
|     /// For example, using a stream ID reserved for a push promise from the | ||||
|     /// client or using a non-zero stream ID for settings. | ||||
|     InvalidStreamId, | ||||
|  | ||||
|     /// The stream ID is no longer accepting frames. | ||||
|     InactiveStreamId, | ||||
|  | ||||
|     /// The stream is not currently expecting a frame of this type. | ||||
|     UnexpectedFrameType, | ||||
|  | ||||
|     // TODO: reserve additional variants | ||||
| } | ||||
|  | ||||
| macro_rules! reason_desc { | ||||
|     ($reason:expr) => (reason_desc!($reason, "")); | ||||
|     ($reason:expr, $prefix:expr) => ({ | ||||
|         use self::Reason::*; | ||||
|  | ||||
|         match $reason { | ||||
|             Reason::NoError => concat!($prefix, "not a result of an error"), | ||||
|             Reason::ProtocolError => concat!($prefix, "unspecific protocol error detected"), | ||||
|             Reason::InternalError => concat!($prefix, "unexpected internal error encountered"), | ||||
|             Reason::FlowControlError => concat!($prefix, "flow-control protocol violated"), | ||||
|             Reason::SettingsTimeout => concat!($prefix, "settings ACK not received in timely manner"), | ||||
|             Reason::StreamClosed => concat!($prefix, "received frame when stream half-closed"), | ||||
|             Reason::FrameSizeError => concat!($prefix, "frame sent with invalid size"), | ||||
|             Reason::RefusedStream => concat!($prefix, "refused stream before processing any application logic"), | ||||
|             Reason::Cancel => concat!($prefix, "stream no longer needed"), | ||||
|             Reason::CompressionError => concat!($prefix, "unable to maintain the header compression context"), | ||||
|             Reason::ConnectError => concat!($prefix, "connection established in response to a CONNECT request was reset or abnormally closed"), | ||||
|             Reason::EnhanceYourCalm => concat!($prefix, "detected excessive load generating behavior"), | ||||
|             Reason::InadequateSecurity => concat!($prefix, "security properties do not meet minimum requirements"), | ||||
|             Reason::Http11Required => concat!($prefix, "endpoint requires HTTP/1.1"), | ||||
|             Reason::Other(_) => concat!($prefix, "other reason"), | ||||
|             NoError => concat!($prefix, "not a result of an error"), | ||||
|             ProtocolError => concat!($prefix, "unspecific protocol error detected"), | ||||
|             InternalError => concat!($prefix, "unexpected internal error encountered"), | ||||
|             FlowControlError => concat!($prefix, "flow-control protocol violated"), | ||||
|             SettingsTimeout => concat!($prefix, "settings ACK not received in timely manner"), | ||||
|             StreamClosed => concat!($prefix, "received frame when stream half-closed"), | ||||
|             FrameSizeError => concat!($prefix, "frame sent with invalid size"), | ||||
|             RefusedStream => concat!($prefix, "refused stream before processing any application logic"), | ||||
|             Cancel => concat!($prefix, "stream no longer needed"), | ||||
|             CompressionError => concat!($prefix, "unable to maintain the header compression context"), | ||||
|             ConnectError => concat!($prefix, "connection established in response to a CONNECT request was reset or abnormally closed"), | ||||
|             EnhanceYourCalm => concat!($prefix, "detected excessive load generating behavior"), | ||||
|             InadequateSecurity => concat!($prefix, "security properties do not meet minimum requirements"), | ||||
|             Http11Required => concat!($prefix, "endpoint requires HTTP/1.1"), | ||||
|             Other(_) => concat!($prefix, "other reason (ain't no tellin')"), | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| macro_rules! user_desc { | ||||
|     ($reason:expr) => (user_desc!($reason, "")); | ||||
|     ($reason:expr, $prefix:expr) => ({ | ||||
|         use self::User::*; | ||||
|  | ||||
|         match $reason { | ||||
|             InvalidStreamId => concat!($prefix, "invalid stream ID"), | ||||
|             InactiveStreamId => concat!($prefix, "inactive stream ID"), | ||||
|             UnexpectedFrameType => concat!($prefix, "unexpected frame type"), | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| @@ -68,6 +111,12 @@ impl From<Reason> for ConnectionError { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<User> for ConnectionError { | ||||
|     fn from(src: User) -> ConnectionError { | ||||
|         ConnectionError::User(src) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<ConnectionError> for io::Error { | ||||
|     fn from(src: ConnectionError) -> io::Error { | ||||
|         io::Error::new(io::ErrorKind::Other, src) | ||||
| @@ -81,6 +130,7 @@ impl fmt::Display for ConnectionError { | ||||
|         match *self { | ||||
|             Proto(reason) => write!(fmt, "protocol error: {}", reason), | ||||
|             Io(ref e) => fmt::Display::fmt(e, fmt), | ||||
|             User(e) => write!(fmt, "user error: {}", e), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -92,6 +142,7 @@ impl error::Error for ConnectionError { | ||||
|         match *self { | ||||
|             Io(ref e) => error::Error::description(e), | ||||
|             Proto(reason) => reason_desc!(reason, "protocol error: "), | ||||
|             User(user) => user_desc!(user, "user error: "), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -157,3 +208,17 @@ impl fmt::Display for Reason { | ||||
|         write!(fmt, "{}", self.description()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl User ===== | ||||
|  | ||||
| impl User { | ||||
|     pub fn description(&self) -> &str { | ||||
|         user_desc!(*self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for User { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(fmt, "{}", self.description()) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| use frame::{util, Frame, Head, Error, StreamId, Kind}; | ||||
| use bytes::{BufMut, Bytes}; | ||||
| use bytes::{BufMut, Bytes, Buf}; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct Data { | ||||
| pub struct Data<T = Bytes> { | ||||
|     stream_id: StreamId, | ||||
|     data: Bytes, | ||||
|     data: T, | ||||
|     flags: DataFlag, | ||||
|     pad_len: Option<u8>, | ||||
| } | ||||
| @@ -16,8 +16,8 @@ const END_STREAM: u8 = 0x1; | ||||
| const PADDED: u8 = 0x8; | ||||
| const ALL: u8 = END_STREAM | PADDED; | ||||
|  | ||||
| impl Data { | ||||
|     pub fn load(head: Head, mut payload: Bytes) -> Result<Data, Error> { | ||||
| impl Data<Bytes> { | ||||
|     pub fn load(head: Head, mut payload: Bytes) -> Result<Self, Error> { | ||||
|         let flags = DataFlag::load(head.flag()); | ||||
|  | ||||
|         let pad_len = if flags.is_padded() { | ||||
| @@ -34,35 +34,56 @@ impl Data { | ||||
|             pad_len: pad_len, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Data<T> { | ||||
|     pub fn new(stream_id: StreamId, data: T) -> Self { | ||||
|         Data { | ||||
|             stream_id: stream_id, | ||||
|             data: data, | ||||
|             flags: DataFlag::default(), | ||||
|             pad_len: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn stream_id(&self) -> StreamId { | ||||
|         self.stream_id | ||||
|     } | ||||
|  | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.data.len() | ||||
|     } | ||||
|  | ||||
|     pub fn is_end_stream(&self) -> bool { | ||||
|         self.flags.is_end_stream() | ||||
|     } | ||||
|  | ||||
|     pub fn encode<T: BufMut>(&self, dst: &mut T) { | ||||
|         self.head().encode(self.len(), dst); | ||||
|         dst.put(&self.data); | ||||
|     pub fn set_end_stream(&mut self) { | ||||
|         self.flags.set_end_stream() | ||||
|     } | ||||
|  | ||||
|     pub fn head(&self) -> Head { | ||||
|         Head::new(Kind::Data, self.flags.into(), self.stream_id) | ||||
|     } | ||||
|  | ||||
|     pub fn into_payload(self) -> Bytes { | ||||
|     pub fn into_payload(self) -> T { | ||||
|         self.data | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Data> for Frame { | ||||
|     fn from(src: Data) -> Frame { | ||||
| impl<T: Buf> Data<T> { | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.data.remaining() | ||||
|     } | ||||
|  | ||||
|     pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) { | ||||
|         if self.len() > dst.remaining_mut() { | ||||
|             unimplemented!(); | ||||
|         } | ||||
|  | ||||
|         self.head().encode(self.len(), dst); | ||||
|         dst.put(&mut self.data); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> From<Data<T>> for Frame<T> { | ||||
|     fn from(src: Data<T>) -> Self { | ||||
|         Frame::Data(src) | ||||
|     } | ||||
| } | ||||
| @@ -86,11 +107,22 @@ impl DataFlag { | ||||
|         self.0 & END_STREAM == END_STREAM | ||||
|     } | ||||
|  | ||||
|     pub fn set_end_stream(&mut self) { | ||||
|         self.0 |= END_STREAM | ||||
|     } | ||||
|  | ||||
|     pub fn is_padded(&self) -> bool { | ||||
|         self.0 & PADDED == PADDED | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Default for DataFlag { | ||||
|     /// Returns a `HeadersFlag` value with `END_HEADERS` set. | ||||
|     fn default() -> Self { | ||||
|         DataFlag(0) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<DataFlag> for u8 { | ||||
|     fn from(src: DataFlag) -> u8 { | ||||
|         src.0 | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| use hpack; | ||||
| use error::{ConnectionError, Reason}; | ||||
|  | ||||
| use bytes::Bytes; | ||||
|  | ||||
| /// 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 | ||||
| /// type. Obviously, the integer type should be able to support at least 4 | ||||
| @@ -53,8 +55,8 @@ pub use self::settings::{ | ||||
| pub const HEADER_LEN: usize = 9; | ||||
|  | ||||
| #[derive(Debug /*, Clone, PartialEq */)] | ||||
| pub enum Frame { | ||||
|     Data(Data), | ||||
| pub enum Frame<T = Bytes> { | ||||
|     Data(Data<T>), | ||||
|     Headers(Headers), | ||||
|     PushPromise(PushPromise), | ||||
|     Settings(Settings), | ||||
|   | ||||
| @@ -71,8 +71,8 @@ impl Ping { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Ping> for Frame { | ||||
|     fn from(src: Ping) -> Frame { | ||||
| impl<T> From<Ping> for Frame<T> { | ||||
|     fn from(src: Ping) -> Frame<T> { | ||||
|         Frame::Ping(src) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -175,8 +175,8 @@ impl Settings { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Settings> for Frame { | ||||
|     fn from(src: Settings) -> Frame { | ||||
| impl<T> From<Settings> for Frame<T> { | ||||
|     fn from(src: Settings) -> Frame<T> { | ||||
|         Frame::Settings(src) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,21 @@ | ||||
| use StreamId; | ||||
| use byteorder::{ByteOrder, NetworkEndian}; | ||||
| use byteorder::NetworkEndian; | ||||
| use bytes::{BufMut}; | ||||
| use frame::{self, Head, Kind, Error}; | ||||
|  | ||||
| const INCREMENT_MASK: u32 = 1 << 31; | ||||
|  | ||||
| type Increment = u32; | ||||
| const SIZE_INCREMENT_MASK: u32 = 1 << 31; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct WindowUpdate { | ||||
|     stream_id: StreamId, | ||||
|     increment: Increment, | ||||
|     size_increment: u32, | ||||
| } | ||||
|  | ||||
| impl WindowUpdate { | ||||
|     pub fn new(stream_id: StreamId, increment: Increment) -> WindowUpdate { | ||||
|     pub fn new(stream_id: StreamId, size_increment: u32) -> WindowUpdate { | ||||
|         WindowUpdate { | ||||
|             stream_id, | ||||
|             increment, | ||||
|             size_increment, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -25,18 +23,24 @@ impl WindowUpdate { | ||||
|         self.stream_id | ||||
|     } | ||||
|  | ||||
|     pub fn increment(&self) -> Increment { | ||||
|         self.increment | ||||
|     pub fn size_increment(&self) -> u32 { | ||||
|         self.size_increment | ||||
|     } | ||||
|  | ||||
|     /// Builds a `WindowUpdate` frame from a raw frame. | ||||
|     pub fn load(head: Head, bytes: &[u8]) -> Result<WindowUpdate, Error> { | ||||
|     pub fn load(head: Head, payload: &[u8]) -> Result<WindowUpdate, Error> { | ||||
|         debug_assert_eq!(head.kind(), ::frame::Kind::WindowUpdate); | ||||
|         if payload.len() != 4 { | ||||
|             return Err(Error::BadFrameSize); | ||||
|         } | ||||
|  | ||||
|         // Clear the most significant bit, as that is reserved and MUST be ignored | ||||
|         // when received. | ||||
|         let size_increment = unpack_octets_4!(payload, 0, u32) & !SIZE_INCREMENT_MASK; | ||||
|  | ||||
|         Ok(WindowUpdate { | ||||
|             stream_id: head.stream_id(), | ||||
|             // Clear the most significant bit, as that is reserved and MUST be ignored | ||||
|             // when received. | ||||
|             increment: NetworkEndian::read_u32(bytes) & !INCREMENT_MASK, | ||||
|             size_increment, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @@ -44,7 +48,7 @@ impl WindowUpdate { | ||||
|         trace!("encoding WINDOW_UPDATE; id={:?}", self.stream_id); | ||||
|         let head = Head::new(Kind::Ping, 0, self.stream_id); | ||||
|         head.encode(4, dst); | ||||
|         dst.put_u32::<NetworkEndian>(self.increment); | ||||
|         dst.put_u32::<NetworkEndian>(self.size_increment); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,7 @@ pub mod server; | ||||
|  | ||||
| mod util; | ||||
|  | ||||
| pub use error::{ConnectionError, StreamError, Reason}; | ||||
| pub use error::ConnectionError; | ||||
| pub use frame::{StreamId}; | ||||
| pub use proto::Connection; | ||||
|  | ||||
| @@ -42,15 +42,15 @@ use bytes::Bytes; | ||||
|  | ||||
| /// An H2 connection frame | ||||
| #[derive(Debug)] | ||||
| pub enum Frame<T> { | ||||
| pub enum Frame<T, B = Bytes> { | ||||
|     Headers { | ||||
|         id: StreamId, | ||||
|         headers: T, | ||||
|         end_of_stream: bool, | ||||
|     }, | ||||
|     Body { | ||||
|     Data { | ||||
|         id: StreamId, | ||||
|         chunk: Bytes, | ||||
|         data: B, | ||||
|         end_of_stream: bool, | ||||
|     }, | ||||
|     Trailers { | ||||
|   | ||||
| @@ -1,12 +1,14 @@ | ||||
| use {Frame, ConnectionError, Peer, StreamId}; | ||||
| use Frame; | ||||
| use client::Client; | ||||
| use frame::{Frame as WireFrame}; | ||||
| use proto::{self, FlowController, ReadySink, PeerState, State, WindowUpdate}; | ||||
| use error::{self, ConnectionError}; | ||||
| use frame::{self, StreamId}; | ||||
| use proto::{self, Peer, ReadySink, State, PeerState, WindowUpdate, FlowController}; | ||||
| use server::Server; | ||||
|  | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| use http::{request, response}; | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| @@ -21,8 +23,8 @@ use std::marker::PhantomData; | ||||
|  | ||||
| /// An H2 connection | ||||
| #[derive(Debug)] | ||||
| pub struct Connection<T, P> { | ||||
|     inner: proto::Inner<T>, | ||||
| pub struct Connection<T, P, B: IntoBuf = Bytes> { | ||||
|     inner: proto::Inner<T, B::Buf>, | ||||
|     streams: StreamMap<State>, | ||||
|     peer: PhantomData<P>, | ||||
|  | ||||
| @@ -39,12 +41,13 @@ pub struct Connection<T, P> { | ||||
|  | ||||
| type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>; | ||||
|  | ||||
| pub fn new<T, P>(transport: proto::Inner<T>, | ||||
| pub fn new<T, P, B>(transport: proto::Inner<T, B::Buf>, | ||||
|                  initial_local_window_size: u32, | ||||
|                  initial_remote_window_size: u32) | ||||
|     -> Connection<T, P> | ||||
|     -> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     Connection { | ||||
|         inner: transport, | ||||
| @@ -62,7 +65,8 @@ pub fn new<T, P>(transport: proto::Inner<T>, | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> Connection<T, P> { | ||||
| impl<T, P, B: IntoBuf> Connection<T, P, B> { | ||||
|  | ||||
|     /// Publishes local stream window updates to the remote. | ||||
|     /// | ||||
|     /// Connection window updates (StreamId=0) and stream window must be published | ||||
| @@ -118,8 +122,28 @@ impl<T, P> Connection<T, P> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Connection<T, Client> | ||||
| impl<T, P, B> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     pub fn send_data(self, | ||||
|                      id: StreamId, | ||||
|                      data: B, | ||||
|                      end_of_stream: bool) | ||||
|         -> sink::Send<Self> | ||||
|     { | ||||
|         self.send(Frame::Data { | ||||
|             id: id, | ||||
|             data: data, | ||||
|             end_of_stream: end_of_stream, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Connection<T, Client, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     pub fn send_request(self, | ||||
|                         id: StreamId, // TODO: Generate one internally? | ||||
| @@ -135,8 +159,9 @@ impl<T> Connection<T, Client> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Connection<T, Server> | ||||
| impl<T, B> Connection<T, Server, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     pub fn send_response(self, | ||||
|                         id: StreamId, // TODO: Generate one internally? | ||||
| @@ -152,17 +177,19 @@ impl<T> Connection<T, Server> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> Stream for Connection<T, P> | ||||
| impl<T, P, B> Stream for Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     type Item = Frame<P::Poll>; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Self::Item>, ConnectionError> { | ||||
|         use frame::Frame::*; | ||||
|         trace!("Connection::poll"); | ||||
|  | ||||
|     loop { | ||||
|         loop { | ||||
|             let frame = match try!(self.inner.poll()) { | ||||
|                 Async::Ready(f) => f, | ||||
|                 Async::NotReady => { | ||||
| @@ -176,7 +203,7 @@ impl<T, P> Stream for Connection<T, P> | ||||
|             trace!("received; frame={:?}", frame); | ||||
|  | ||||
|             let frame = match frame { | ||||
|                 Some(WireFrame::Headers(v)) => { | ||||
|                 Some(Headers(v)) => { | ||||
|                     // TODO: Update stream state | ||||
|                     let stream_id = v.stream_id(); | ||||
|                     let end_of_stream = v.is_end_stream(); | ||||
| @@ -204,20 +231,24 @@ impl<T, P> Stream for Connection<T, P> | ||||
|                         end_of_stream: end_of_stream, | ||||
|                     } | ||||
|                 } | ||||
|                 Some(WireFrame::Data(v)) => { | ||||
|                 Some(Data(v)) => { | ||||
|                     // TODO: Validate frame | ||||
|  | ||||
|                     let stream_id = v.stream_id(); | ||||
|                     let end_of_stream = v.is_end_stream(); | ||||
|                     match self.streams.get_mut(&stream_id) { | ||||
|                         None => return Err(error::Reason::ProtocolError.into()), | ||||
|                         Some(state) => try!(state.recv_data(end_of_stream)), | ||||
|                     } | ||||
|  | ||||
|                     Frame::Body { | ||||
|                     Frame::Data { | ||||
|                         id: stream_id, | ||||
|                         chunk: v.into_payload(), | ||||
|                         data: v.into_payload(), | ||||
|                         end_of_stream: end_of_stream, | ||||
|                     } | ||||
|                 } | ||||
|                 Some(WireFrame::WindowUpdate(v)) => { | ||||
|                     self.increment_remote_window(v.stream_id(), v.increment()); | ||||
|                 Some(WindowUpdate(v)) => { | ||||
|                     self.increment_remote_window(v.stream_id(), v.size_increment()); | ||||
|                     continue; | ||||
|                 } | ||||
|                 Some(frame) => panic!("unexpected frame; frame={:?}", frame), | ||||
| @@ -229,16 +260,19 @@ impl<T, P> Stream for Connection<T, P> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> Sink for Connection<T, P> | ||||
| impl<T, P, B> Sink for Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     type SinkItem = Frame<P::Send>; | ||||
|     type SinkItem = Frame<P::Send, B>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) | ||||
|         -> StartSend<Self::SinkItem, Self::SinkError> | ||||
|     { | ||||
|         use frame::Frame::Headers; | ||||
|  | ||||
|         // First ensure that the upstream can process a new item | ||||
|         if !try!(self.poll_ready()).is_ready() { | ||||
|             return Ok(AsyncSink::NotReady(item)); | ||||
| @@ -262,7 +296,8 @@ impl<T, P> Sink for Connection<T, P> | ||||
|                     // connections should not be factored. | ||||
|                     // | ||||
|                     if !P::is_valid_local_stream_id(id) { | ||||
|                         unimplemented!(); | ||||
|                         // TODO: clear state | ||||
|                         return Err(error::User::InvalidStreamId.into()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
| @@ -270,7 +305,7 @@ impl<T, P> Sink for Connection<T, P> | ||||
|  | ||||
|                 // We already ensured that the upstream can handle the frame, so | ||||
|                 // panic if it gets rejected. | ||||
|                 let res = try!(self.inner.start_send(WireFrame::Headers(frame))); | ||||
|                 let res = try!(self.inner.start_send(Headers(frame))); | ||||
|  | ||||
|                 // This is a one-way conversion. By checking `poll_ready` first, | ||||
|                 // it's already been determined that the inner `Sink` can accept | ||||
| @@ -279,6 +314,25 @@ impl<T, P> Sink for Connection<T, P> | ||||
|  | ||||
|                 Ok(AsyncSink::Ready) | ||||
|             } | ||||
|             Frame::Data { id, data, end_of_stream } => { | ||||
|                 // The stream must be initialized at this point | ||||
|                 match self.streams.get_mut(&id) { | ||||
|                     None => return Err(error::User::InactiveStreamId.into()), | ||||
|                     Some(state) => try!(state.send_data(end_of_stream)), | ||||
|                 } | ||||
|  | ||||
|                 let mut frame = frame::Data::new(id, data.into_buf()); | ||||
|  | ||||
|                 if end_of_stream { | ||||
|                     frame.set_end_stream(); | ||||
|                 } | ||||
|  | ||||
|                 let res = try!(self.inner.start_send(frame.into())); | ||||
|  | ||||
|                 assert!(res.is_ready()); | ||||
|  | ||||
|                 Ok(AsyncSink::Ready) | ||||
|             } | ||||
|             /* | ||||
|             Frame::Trailers { id, headers } => { | ||||
|                 unimplemented!(); | ||||
| @@ -302,9 +356,10 @@ impl<T, P> Sink for Connection<T, P> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> ReadySink for Connection<T, P> | ||||
| impl<T, P, B> ReadySink for Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), Self::SinkError> { | ||||
|         self.inner.poll_ready() | ||||
|   | ||||
| @@ -29,10 +29,7 @@ enum Partial { | ||||
|     // PushPromise(frame::PushPromise), | ||||
| } | ||||
|  | ||||
| impl<T> FramedRead<T> | ||||
|     where T: AsyncRead, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
| { | ||||
| impl<T> FramedRead<T> { | ||||
|     pub fn new(inner: length_delimited::FramedRead<T>) -> FramedRead<T> { | ||||
|         FramedRead { | ||||
|             inner: inner, | ||||
| @@ -40,9 +37,7 @@ impl<T> FramedRead<T> | ||||
|             partial: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> FramedRead<T> { | ||||
|     fn decode_frame(&mut self, mut bytes: Bytes) -> Result<Option<Frame>, ConnectionError> { | ||||
|         // Parse the head | ||||
|         let head = frame::Head::parse(&bytes); | ||||
| @@ -97,9 +92,11 @@ impl<T> FramedRead<T> { | ||||
|                 unimplemented!(); | ||||
|             } | ||||
|             Kind::WindowUpdate => { | ||||
|                 // TODO: IMPLEMENT | ||||
|                 let frame = try!(frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..])); | ||||
|                 frame.into() | ||||
|             } | ||||
|                 debug!("decoded; frame={:?}", frame); | ||||
|                 return Ok(None); | ||||
|             }, | ||||
|             Kind::Continuation => { | ||||
|                 unimplemented!(); | ||||
|             } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ use std::cmp; | ||||
| use std::io::{self, Cursor}; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct FramedWrite<T> { | ||||
| pub struct FramedWrite<T, B> { | ||||
|     /// Upstream `AsyncWrite` | ||||
|     inner: T, | ||||
|  | ||||
| @@ -21,20 +21,20 @@ pub struct FramedWrite<T> { | ||||
|     buf: Cursor<BytesMut>, | ||||
|  | ||||
|     /// Next frame to encode | ||||
|     next: Option<Next>, | ||||
|     next: Option<Next<B>>, | ||||
|  | ||||
|     /// Max frame size, this is specified by the peer | ||||
|     max_frame_size: usize, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum Next { | ||||
| enum Next<B> { | ||||
|     Data { | ||||
|         /// Length of the current frame being written | ||||
|         frame_len: usize, | ||||
|  | ||||
|         /// Data frame to encode | ||||
|         data: frame::Data | ||||
|         data: frame::Data<B>, | ||||
|     }, | ||||
|     Continuation(frame::Continuation), | ||||
| } | ||||
| @@ -50,8 +50,12 @@ const MIN_BUFFER_CAPACITY: usize = frame::HEADER_LEN + CHAIN_THRESHOLD; | ||||
| /// than 16kb, so not even close). | ||||
| const CHAIN_THRESHOLD: usize = 256; | ||||
|  | ||||
| impl<T: AsyncWrite> FramedWrite<T> { | ||||
|     pub fn new(inner: T) -> FramedWrite<T> { | ||||
| // TODO: Make generic | ||||
| impl<T, B> FramedWrite<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     pub fn new(inner: T) -> FramedWrite<T, B> { | ||||
|         FramedWrite { | ||||
|             inner: inner, | ||||
|             hpack: hpack::Encoder::default(), | ||||
| @@ -69,24 +73,27 @@ impl<T: AsyncWrite> FramedWrite<T> { | ||||
|         self.next.is_none() && !self.buf.has_remaining() | ||||
|     } | ||||
|  | ||||
|     fn frame_len(&self, data: &frame::Data) -> usize { | ||||
|     fn frame_len(&self, data: &frame::Data<B>) -> usize { | ||||
|         cmp::min(self.max_frame_size, data.len()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsyncWrite> Sink for FramedWrite<T> { | ||||
|     type SinkItem = Frame; | ||||
| impl<T, B> Sink for FramedWrite<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     type SinkItem = Frame<B>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> { | ||||
|         debug!("start_send; frame={:?}", item); | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) | ||||
|         -> StartSend<Self::SinkItem, ConnectionError> | ||||
|     { | ||||
|         if !try!(self.poll_ready()).is_ready() { | ||||
|             return Ok(AsyncSink::NotReady(item)); | ||||
|         } | ||||
|  | ||||
|         match item { | ||||
|             Frame::Data(v) => { | ||||
|             Frame::Data(mut v) => { | ||||
|                 if v.len() >= CHAIN_THRESHOLD { | ||||
|                     let head = v.head(); | ||||
|                     let len = self.frame_len(&v); | ||||
| @@ -100,7 +107,11 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | ||||
|                         data: v, | ||||
|                     }); | ||||
|                 } else { | ||||
|                     v.encode(self.buf.get_mut()); | ||||
|                     v.encode_chunk(self.buf.get_mut()); | ||||
|  | ||||
|                     // The chunk has been fully encoded, so there is no need to | ||||
|                     // keep it around | ||||
|                     assert_eq!(v.len(), 0, "chunk not fully encoded"); | ||||
|                 } | ||||
|             } | ||||
|             Frame::Headers(v) => { | ||||
| @@ -140,7 +151,6 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | ||||
|  | ||||
|         // As long as there is data to write, try to write it! | ||||
|         while !self.is_empty() { | ||||
|             trace!("writing buffer; next={:?}; rem={:?}", self.next, self.buf.remaining()); | ||||
|             try_ready!(self.inner.write_buf(&mut self.buf)); | ||||
|         } | ||||
|  | ||||
| @@ -161,7 +171,10 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsyncWrite> ReadySink for FramedWrite<T> { | ||||
| impl<T, B> ReadySink for FramedWrite<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), Self::SinkError> { | ||||
|         if !self.has_capacity() { | ||||
|             // Try flushing | ||||
| @@ -176,7 +189,7 @@ impl<T: AsyncWrite> ReadySink for FramedWrite<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Stream> Stream for FramedWrite<T> { | ||||
| impl<T: Stream, B> Stream for FramedWrite<T, B> { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
| @@ -185,14 +198,14 @@ impl<T: Stream> Stream for FramedWrite<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: io::Read> io::Read for FramedWrite<T> { | ||||
| impl<T: io::Read, B> io::Read for FramedWrite<T, B> { | ||||
|     fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { | ||||
|         self.inner.read(dst) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsyncRead> AsyncRead for FramedWrite<T> { | ||||
|     fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> | ||||
| impl<T: AsyncRead, B> AsyncRead for FramedWrite<T, B> { | ||||
|     fn read_buf<B2: BufMut>(&mut self, buf: &mut B2) -> Poll<usize, io::Error> | ||||
|         where Self: Sized, | ||||
|     { | ||||
|         self.inner.read_buf(buf) | ||||
|   | ||||
| @@ -23,24 +23,28 @@ use {frame, Peer}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio_io::codec::length_delimited; | ||||
|  | ||||
| type Inner<T> = | ||||
| use bytes::{Buf, IntoBuf}; | ||||
|  | ||||
| type Inner<T, B> = | ||||
|     Settings< | ||||
|         PingPong< | ||||
|             Framed<T>>>; | ||||
|             Framed<T, B>, | ||||
|             B>>; | ||||
|  | ||||
| type Framed<T> = | ||||
| type Framed<T, B> = | ||||
|     FramedRead< | ||||
|         FramedWrite<T>>; | ||||
|         FramedWrite<T, B>>; | ||||
|  | ||||
| /// Create a full H2 transport from an I/O handle. | ||||
| /// | ||||
| /// This is called as the final step of the client handshake future. | ||||
| pub fn from_io<T, P>(io: T, settings: frame::SettingSet) | ||||
|     -> Connection<T, P> | ||||
| pub fn from_io<T, P, B>(io: T, settings: frame::SettingSet) | ||||
|     -> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     let framed_write = FramedWrite::new(io); | ||||
|     let framed_write: FramedWrite<_, B::Buf> = FramedWrite::new(io); | ||||
|  | ||||
|     // To avoid code duplication, we're going to go this route. It is a bit | ||||
|     // weird, but oh well... | ||||
| @@ -55,9 +59,10 @@ pub fn from_io<T, P>(io: T, settings: frame::SettingSet) | ||||
| /// When the server is performing the handshake, it is able to only send | ||||
| /// `Settings` frames and is expected to receive the client preface as a byte | ||||
| /// stream. To represent this, `Settings<FramedWrite<T>>` is returned. | ||||
| pub fn server_handshaker<T>(io: T, settings: frame::SettingSet) | ||||
|     -> Settings<FramedWrite<T>> | ||||
| pub fn server_handshaker<T, B>(io: T, settings: frame::SettingSet) | ||||
|     -> Settings<FramedWrite<T, B>> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     let framed_write = FramedWrite::new(io); | ||||
|  | ||||
| @@ -65,10 +70,11 @@ pub fn server_handshaker<T>(io: T, settings: frame::SettingSet) | ||||
| } | ||||
|  | ||||
| /// Create a full H2 transport from the server handshaker | ||||
| pub fn from_server_handshaker<T, P>(transport: Settings<FramedWrite<T>>) | ||||
|     -> Connection<T, P> | ||||
| pub fn from_server_handshaker<T, P, B>(transport: Settings<FramedWrite<T, B::Buf>>) | ||||
|     -> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     let settings = transport.swap_inner(|io| { | ||||
|         // Delimit the frames | ||||
|   | ||||
| @@ -5,16 +5,16 @@ use proto::ReadySink; | ||||
|  | ||||
| /// Acknowledges ping requests from the remote. | ||||
| #[derive(Debug)] | ||||
| pub struct PingPong<T> { | ||||
| pub struct PingPong<T, U> { | ||||
|     inner: T, | ||||
|     pong: Option<Frame>, | ||||
|     pong: Option<Frame<U>>, | ||||
| } | ||||
|  | ||||
| impl<T> PingPong<T> | ||||
| impl<T, U> PingPong<T, U> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     pub fn new(inner: T) -> PingPong<T> { | ||||
|     pub fn new(inner: T) -> Self { | ||||
|         PingPong { | ||||
|             inner, | ||||
|             pong: None, | ||||
| @@ -38,9 +38,9 @@ impl<T> PingPong<T> | ||||
| /// > a PING frame with the ACK flag set in response, with an identical | ||||
| /// > payload. PING responses SHOULD be given higher priority than any | ||||
| /// > other frame. | ||||
| impl<T> Stream for PingPong<T> | ||||
| impl<T, U> Stream for PingPong<T, U> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ConnectionError; | ||||
| @@ -76,14 +76,16 @@ impl<T> Stream for PingPong<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Sink for PingPong<T> | ||||
| impl<T, U> Sink for PingPong<T, U> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     type SinkItem = Frame; | ||||
|     type SinkItem = Frame<U>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> { | ||||
|     fn start_send(&mut self, item: Self::SinkItem) | ||||
|         -> StartSend<Self::SinkItem, Self::SinkError> | ||||
|     { | ||||
|         // Pings _SHOULD_ have priority over other messages, so attempt to send pending | ||||
|         // ping frames before attempting to send `item`. | ||||
|         if self.try_send_pong()?.is_not_ready() { | ||||
| @@ -100,9 +102,9 @@ impl<T> Sink for PingPong<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> ReadySink for PingPong<T> | ||||
| impl<T, U> ReadySink for PingPong<T, U> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|   | ||||
| @@ -29,8 +29,8 @@ pub struct Settings<T> { | ||||
|     received_remote: bool, | ||||
| } | ||||
|  | ||||
| impl<T> Settings<T> | ||||
|     where T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
| impl<T, U> Settings<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     pub fn new(inner: T, local: frame::SettingSet) -> Settings<T> { | ||||
|         Settings { | ||||
| @@ -44,7 +44,7 @@ impl<T> Settings<T> | ||||
|     } | ||||
|  | ||||
|     /// Swap the inner transport while maintaining the current state. | ||||
|     pub fn swap_inner<U, F: FnOnce(T) -> U>(self, f: F) -> Settings<U> { | ||||
|     pub fn swap_inner<T2, F: FnOnce(T) -> T2>(self, f: F) -> Settings<T2> { | ||||
|         let inner = f(self.inner); | ||||
|  | ||||
|         Settings { | ||||
| @@ -88,9 +88,9 @@ impl<T> Settings<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Stream for Settings<T> | ||||
| impl<T, U> Stream for Settings<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ConnectionError; | ||||
| @@ -118,13 +118,15 @@ impl<T> Stream for Settings<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Sink for Settings<T> | ||||
|     where T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
| impl<T, U> Sink for Settings<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     type SinkItem = Frame; | ||||
|     type SinkItem = Frame<U>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> { | ||||
|     fn start_send(&mut self, item: Self::SinkItem) | ||||
|         -> StartSend<Self::SinkItem, Self::SinkError> | ||||
|     { | ||||
|         // Settings frames take priority, so `item` cannot be sent if there are | ||||
|         // any pending acks OR the local settings have been changed w/o sending | ||||
|         // an associated frame. | ||||
| @@ -147,8 +149,8 @@ impl<T> Sink for Settings<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> ReadySink for Settings<T> | ||||
|     where T: Sink<SinkItem = Frame, SinkError = ConnectionError>, | ||||
| impl<T, U> ReadySink for Settings<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|   | ||||
| @@ -1,4 +1,7 @@ | ||||
| use {ConnectionError, Reason, Peer}; | ||||
| use Peer; | ||||
| use error::ConnectionError; | ||||
| use error::Reason::*; | ||||
| use error::User::*; | ||||
| use proto::FlowController; | ||||
|  | ||||
| /// Represents the state of an H2 stream | ||||
| @@ -101,7 +104,7 @@ impl State { | ||||
|                 Ok(true) | ||||
|             } | ||||
|             Open { local, remote } => { | ||||
|                 try!(remote.check_is_headers(Reason::ProtocolError)); | ||||
|                 try!(remote.check_is_headers(ProtocolError.into())); | ||||
|  | ||||
|                 *self = if eos { | ||||
|                     HalfClosedRemote(local) | ||||
| @@ -113,7 +116,7 @@ impl State { | ||||
|                 Ok(false) | ||||
|             } | ||||
|             HalfClosedLocal(remote) => { | ||||
|                 try!(remote.check_is_headers(Reason::ProtocolError)); | ||||
|                 try!(remote.check_is_headers(ProtocolError.into())); | ||||
|  | ||||
|                 *self = if eos { | ||||
|                     Closed | ||||
| @@ -124,7 +127,36 @@ impl State { | ||||
|                 Ok(false) | ||||
|             } | ||||
|             Closed | HalfClosedRemote(..) => { | ||||
|                 Err(Reason::ProtocolError.into()) | ||||
|                 Err(ProtocolError.into()) | ||||
|             } | ||||
|             _ => unimplemented!(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn recv_data(&mut self, eos: bool) -> Result<(), ConnectionError> { | ||||
|         use self::State::*; | ||||
|  | ||||
|         match *self { | ||||
|             Open { local, remote } => { | ||||
|                 try!(remote.check_is_data(ProtocolError.into())); | ||||
|  | ||||
|                 if eos { | ||||
|                     *self = HalfClosedRemote(local); | ||||
|                 } | ||||
|  | ||||
|                 Ok(()) | ||||
|             } | ||||
|             HalfClosedLocal(remote) => { | ||||
|                 try!(remote.check_is_data(ProtocolError.into())); | ||||
|  | ||||
|                 if eos { | ||||
|                     *self = Closed; | ||||
|                 } | ||||
|  | ||||
|                 Ok(()) | ||||
|             } | ||||
|             Closed | HalfClosedRemote(..) => { | ||||
|                 Err(ProtocolError.into()) | ||||
|             } | ||||
|             _ => unimplemented!(), | ||||
|         } | ||||
| @@ -152,7 +184,7 @@ impl State { | ||||
|                 Ok(true) | ||||
|             } | ||||
|             Open { local, remote } => { | ||||
|                 try!(local.check_is_headers(Reason::InternalError)); | ||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||
|  | ||||
|                 *self = if eos { | ||||
|                     HalfClosedLocal(remote) | ||||
| @@ -164,7 +196,7 @@ impl State { | ||||
|                 Ok(false) | ||||
|             } | ||||
|             HalfClosedRemote(local) => { | ||||
|                 try!(local.check_is_headers(Reason::InternalError)); | ||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||
|  | ||||
|                 *self = if eos { | ||||
|                     Closed | ||||
| @@ -175,7 +207,36 @@ impl State { | ||||
|                 Ok(false) | ||||
|             } | ||||
|             Closed | HalfClosedLocal(..) => { | ||||
|                 Err(Reason::InternalError.into()) | ||||
|                 Err(UnexpectedFrameType.into()) | ||||
|             } | ||||
|             _ => unimplemented!(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn send_data(&mut self, eos: bool) -> Result<(), ConnectionError> { | ||||
|         use self::State::*; | ||||
|  | ||||
|         match *self { | ||||
|             Open { local, remote } => { | ||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); | ||||
|  | ||||
|                 if eos { | ||||
|                     *self = HalfClosedLocal(remote); | ||||
|                 } | ||||
|  | ||||
|                 Ok(()) | ||||
|             } | ||||
|             HalfClosedRemote(local) => { | ||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); | ||||
|  | ||||
|                 if eos { | ||||
|                     *self = Closed; | ||||
|                 } | ||||
|  | ||||
|                 Ok(()) | ||||
|             } | ||||
|             Closed | HalfClosedLocal(..) => { | ||||
|                 Err(UnexpectedFrameType.into()) | ||||
|             } | ||||
|             _ => unimplemented!(), | ||||
|         } | ||||
| @@ -184,12 +245,22 @@ impl State { | ||||
|  | ||||
| impl PeerState { | ||||
|     #[inline] | ||||
|     fn check_is_headers(&self, err: Reason) -> Result<(), ConnectionError> { | ||||
|     fn check_is_headers(&self, err: ConnectionError) -> Result<(), ConnectionError> { | ||||
|         use self::PeerState::*; | ||||
|  | ||||
|         match *self { | ||||
|             Headers => Ok(()), | ||||
|             _ => Err(err.into()), | ||||
|             _ => Err(err), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     fn check_is_data(&self, err: ConnectionError) -> Result<(), ConnectionError> { | ||||
|         use self::PeerState::*; | ||||
|  | ||||
|         match *self { | ||||
|             Data { .. } => Ok(()), | ||||
|             _ => Err(err), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,20 +3,21 @@ use {frame, proto, Peer, ConnectionError, StreamId}; | ||||
| use http; | ||||
| use futures::{Future, Sink, Poll, Async}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
|  | ||||
| use std::fmt; | ||||
|  | ||||
| /// In progress H2 connection binding | ||||
| pub struct Handshake<T> { | ||||
| pub struct Handshake<T, B: IntoBuf = Bytes> { | ||||
|     // TODO: unbox | ||||
|     inner: Box<Future<Item = Connection<T>, Error = ConnectionError>>, | ||||
|     inner: Box<Future<Item = Connection<T, B>, Error = ConnectionError>>, | ||||
| } | ||||
|  | ||||
| /// Marker type indicating a client peer | ||||
| #[derive(Debug)] | ||||
| pub struct Server; | ||||
|  | ||||
| pub type Connection<T> = super::Connection<T, Server>; | ||||
| pub type Connection<T, B = Bytes> = super::Connection<T, Server, B>; | ||||
|  | ||||
| /// Flush a Sink | ||||
| struct Flush<T> { | ||||
| @@ -31,12 +32,19 @@ struct ReadPreface<T> { | ||||
|  | ||||
| const PREFACE: [u8; 24] = *b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; | ||||
|  | ||||
| pub fn handshake<T>(io: T) -> Handshake<T, Bytes> | ||||
|     where T: AsyncRead + AsyncWrite + 'static, | ||||
| { | ||||
|     handshake2(io) | ||||
| } | ||||
|  | ||||
| /// Bind an H2 server connection. | ||||
| /// | ||||
| /// Returns a future which resolves to the connection value once the H2 | ||||
| /// handshake has been completed. | ||||
| pub fn handshake<T>(io: T) -> Handshake<T> | ||||
| pub fn handshake2<T, B: IntoBuf>(io: T) -> Handshake<T, B> | ||||
|     where T: AsyncRead + AsyncWrite + 'static, | ||||
|           B: 'static, // TODO: Why is this required but not in client? | ||||
| { | ||||
|     let transport = proto::server_handshaker(io, Default::default()); | ||||
|  | ||||
| @@ -141,8 +149,8 @@ impl Peer for Server { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Future for Handshake<T> { | ||||
|     type Item = Connection<T>; | ||||
| impl<T, B: IntoBuf> Future for Handshake<T, B> { | ||||
|     type Item = Connection<T, B>; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||
| @@ -150,7 +158,10 @@ impl<T> Future for Handshake<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: fmt::Debug> fmt::Debug for Handshake<T> { | ||||
| impl<T, B> fmt::Debug for Handshake<T, B> | ||||
|     where T: fmt::Debug, | ||||
|           B: fmt::Debug + IntoBuf, | ||||
| { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(fmt, "server::Handshake") | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user