closer to flow control
This commit is contained in:
		| @@ -1,6 +1,8 @@ | |||||||
| use std::{error, fmt, io}; | use std::{error, fmt, io}; | ||||||
|  |  | ||||||
| /// The error type for HTTP/2 operations | /// The error type for HTTP/2 operations | ||||||
|  | /// | ||||||
|  | /// XXX does this sufficiently destinguish stream-level errors from connection-level errors? | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum ConnectionError { | pub enum ConnectionError { | ||||||
|     /// An error caused by an action taken by the remote peer. |     /// An error caused by an action taken by the remote peer. | ||||||
| @@ -56,6 +58,10 @@ pub enum User { | |||||||
|     /// The stream is not currently expecting a frame of this type. |     /// The stream is not currently expecting a frame of this type. | ||||||
|     UnexpectedFrameType, |     UnexpectedFrameType, | ||||||
|  |  | ||||||
|  |     /// The connection or stream does not have a sufficient flow control window to | ||||||
|  |     /// transmit a Data frame to the remote. | ||||||
|  |     FlowControlViolation, | ||||||
|  |  | ||||||
|     // TODO: reserve additional variants |     // TODO: reserve additional variants | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -93,6 +99,7 @@ macro_rules! user_desc { | |||||||
|             InvalidStreamId => concat!($prefix, "invalid stream ID"), |             InvalidStreamId => concat!($prefix, "invalid stream ID"), | ||||||
|             InactiveStreamId => concat!($prefix, "inactive stream ID"), |             InactiveStreamId => concat!($prefix, "inactive stream ID"), | ||||||
|             UnexpectedFrameType => concat!($prefix, "unexpected frame type"), |             UnexpectedFrameType => concat!($prefix, "unexpected frame type"), | ||||||
|  |             FlowControlViolation => concat!($prefix, "flow control violation"), | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ use bytes::{BufMut, Bytes, Buf}; | |||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Data<T = Bytes> { | pub struct Data<T = Bytes> { | ||||||
|     stream_id: StreamId, |     stream_id: StreamId, | ||||||
|  |     data_len: usize, | ||||||
|     data: T, |     data: T, | ||||||
|     flags: DataFlag, |     flags: DataFlag, | ||||||
|     pad_len: Option<u8>, |     pad_len: Option<u8>, | ||||||
| @@ -26,9 +27,9 @@ impl Data<Bytes> { | |||||||
|         } else { |         } else { | ||||||
|             None |             None | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         Ok(Data { |         Ok(Data { | ||||||
|             stream_id: head.stream_id(), |             stream_id: head.stream_id(), | ||||||
|  |             data_len: payload.len(), | ||||||
|             data: payload, |             data: payload, | ||||||
|             flags: flags, |             flags: flags, | ||||||
|             pad_len: pad_len, |             pad_len: pad_len, | ||||||
| @@ -37,15 +38,6 @@ impl Data<Bytes> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> Data<T> { | 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 { |     pub fn stream_id(&self) -> StreamId { | ||||||
|         self.stream_id |         self.stream_id | ||||||
|     } |     } | ||||||
| @@ -62,14 +54,24 @@ impl<T> Data<T> { | |||||||
|         Head::new(Kind::Data, self.flags.into(), self.stream_id) |         Head::new(Kind::Data, self.flags.into(), self.stream_id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn len(&self) -> usize { | ||||||
|  |         self.data_len | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn into_payload(self) -> T { |     pub fn into_payload(self) -> T { | ||||||
|         self.data |         self.data | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: Buf> Data<T> { | impl<T: Buf> Data<T> { | ||||||
|     pub fn len(&self) -> usize { |     pub fn from_buf(stream_id: StreamId, data: T) -> Self { | ||||||
|         self.data.remaining() |         Data { | ||||||
|  |             stream_id: stream_id, | ||||||
|  |             data_len: data.remaining(), | ||||||
|  |             data: data, | ||||||
|  |             flags: DataFlag::default(), | ||||||
|  |             pad_len: None, | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) { |     pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) { | ||||||
|   | |||||||
| @@ -113,11 +113,6 @@ pub enum Error { | |||||||
|     Hpack(hpack::DecoderError), |     Hpack(hpack::DecoderError), | ||||||
| } | } | ||||||
|  |  | ||||||
| // ===== impl Frame ====== |  | ||||||
|  |  | ||||||
| impl Frame { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ===== impl Error ===== | // ===== impl Error ===== | ||||||
|  |  | ||||||
| impl From<Error> for ConnectionError { | impl From<Error> for ConnectionError { | ||||||
|   | |||||||
| @@ -18,6 +18,12 @@ pub struct SettingSet { | |||||||
|     max_header_list_size: Option<u32>, |     max_header_list_size: Option<u32>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl SettingSet { | ||||||
|  |     pub fn initial_window_size(&self) -> u32 { | ||||||
|  |         self.initial_window_size.unwrap_or(65_535) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// An enum that lists all valid settings that can be sent in a SETTINGS | /// An enum that lists all valid settings that can be sent in a SETTINGS | ||||||
| /// frame. | /// frame. | ||||||
| /// | /// | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ use frame::{self, Head, Kind, Error}; | |||||||
|  |  | ||||||
| const SIZE_INCREMENT_MASK: u32 = 1 << 31; | const SIZE_INCREMENT_MASK: u32 = 1 << 31; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Copy, Clone, Debug)] | ||||||
| pub struct WindowUpdate { | pub struct WindowUpdate { | ||||||
|     stream_id: StreamId, |     stream_id: StreamId, | ||||||
|     size_increment: u32, |     size_increment: u32, | ||||||
| @@ -52,8 +52,8 @@ impl WindowUpdate { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<WindowUpdate> for frame::Frame { | impl<B> From<WindowUpdate> for frame::Frame<B> { | ||||||
|     fn from(src: WindowUpdate) -> frame::Frame { |     fn from(src: WindowUpdate) -> Self { | ||||||
|         frame::Frame::WindowUpdate(src) |         frame::Frame::WindowUpdate(src) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -51,6 +51,8 @@ pub enum Frame<T, B = Bytes> { | |||||||
|     Data { |     Data { | ||||||
|         id: StreamId, |         id: StreamId, | ||||||
|         data: B, |         data: B, | ||||||
|  |         /// TODO figure out how to make this a requirement on `B` | ||||||
|  |         data_len: usize, | ||||||
|         end_of_stream: bool, |         end_of_stream: bool, | ||||||
|     }, |     }, | ||||||
|     Trailers { |     Trailers { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ use Frame; | |||||||
| use client::Client; | use client::Client; | ||||||
| use error::{self, ConnectionError}; | use error::{self, ConnectionError}; | ||||||
| use frame::{self, StreamId}; | use frame::{self, StreamId}; | ||||||
| use proto::{self, Peer, ReadySink, State, PeerState, WindowUpdate, FlowController}; | use proto::{self, Peer, ReadySink, State, FlowController}; | ||||||
| use server::Server; | use server::Server; | ||||||
|  |  | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| @@ -15,12 +15,9 @@ use futures::*; | |||||||
| use ordermap::OrderMap; | use ordermap::OrderMap; | ||||||
| use fnv::FnvHasher; | use fnv::FnvHasher; | ||||||
|  |  | ||||||
| use std::collections::VecDeque; |  | ||||||
| use std::hash::BuildHasherDefault; | use std::hash::BuildHasherDefault; | ||||||
| use std::marker::PhantomData; | use std::marker::PhantomData; | ||||||
|  |  | ||||||
| // TODO get window size from `inner`. |  | ||||||
|  |  | ||||||
| /// An H2 connection | /// An H2 connection | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Connection<T, P, B: IntoBuf = Bytes> { | pub struct Connection<T, P, B: IntoBuf = Bytes> { | ||||||
| @@ -30,96 +27,90 @@ pub struct Connection<T, P, B: IntoBuf = Bytes> { | |||||||
|  |  | ||||||
|     /// Tracks connection-level flow control. |     /// Tracks connection-level flow control. | ||||||
|     local_flow_controller: FlowController, |     local_flow_controller: FlowController, | ||||||
|     initial_local_window_size: u32, |  | ||||||
|     pending_local_window_updates: VecDeque<WindowUpdate>, |  | ||||||
|  |  | ||||||
|     remote_flow_controller: FlowController, |     remote_flow_controller: FlowController, | ||||||
|     initial_remote_window_size: u32, |  | ||||||
|     pending_remote_window_updates: VecDeque<WindowUpdate>, |  | ||||||
|     blocked_remote_window_update: Option<task::Task> |     pending_local_window_update: Option<frame::WindowUpdate>, | ||||||
|  |     blocked_remote_window_update: Option<task::Task>, | ||||||
| } | } | ||||||
|  |  | ||||||
| type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>; | type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>; | ||||||
|  |  | ||||||
| pub fn new<T, P, B>(transport: proto::Inner<T, B::Buf>, | 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, B> |     -> Connection<T, P, B> | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           P: Peer, |           P: Peer, | ||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| { | { | ||||||
|  |     let local_window_size = transport.local_settings().initial_window_size(); | ||||||
|  |     let remote_window_size = transport.remote_settings().initial_window_size(); | ||||||
|     Connection { |     Connection { | ||||||
|         inner: transport, |         inner: transport, | ||||||
|         streams: StreamMap::default(), |         streams: StreamMap::default(), | ||||||
|         peer: PhantomData, |         peer: PhantomData, | ||||||
|  |  | ||||||
|         local_flow_controller: FlowController::new(initial_local_window_size), |         local_flow_controller: FlowController::new(local_window_size), | ||||||
|         initial_local_window_size, |         remote_flow_controller: FlowController::new(remote_window_size), | ||||||
|         pending_local_window_updates: VecDeque::default(), |  | ||||||
|  |  | ||||||
|         remote_flow_controller: FlowController::new(initial_remote_window_size), |         pending_local_window_update: None, | ||||||
|         initial_remote_window_size, |  | ||||||
|         pending_remote_window_updates: VecDeque::default(), |  | ||||||
|         blocked_remote_window_update: None, |         blocked_remote_window_update: None, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T, P, B: IntoBuf> Connection<T, P, B> { | impl<T, P, B: IntoBuf> Connection<T, P, B> { | ||||||
|  |     pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<u32, ConnectionError> { | ||||||
|  |         if id.is_zero() { | ||||||
|  |             return match self.local_flow_controller.take_window_update() { | ||||||
|  |                     Some(incr) => Ok(Async::Ready(incr)), | ||||||
|  |                     None => { | ||||||
|  |                         self.blocked_remote_window_update = Some(task::current()); | ||||||
|  |                         Ok(Async::NotReady) | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         match self.streams.get_mut(&id).and_then(|mut s| s.take_remote_window_update()) { | ||||||
|  |             Some(incr) => Ok(Async::Ready(incr)), | ||||||
|  |             None => { | ||||||
|  |                 self.blocked_remote_window_update = Some(task::current()); | ||||||
|  |                 Ok(Async::NotReady) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// Publishes local stream window updates to the remote. |     /// Publishes local stream window updates to the remote. | ||||||
|     /// |     /// | ||||||
|     /// Connection window updates (StreamId=0) and stream window must be published |     /// Connection window updates (StreamId=0) and stream window must be published | ||||||
|     /// distinctly. |     /// distinctly. | ||||||
|     pub fn increment_local_window(&mut self, up: WindowUpdate) { |     pub fn init_send_window_update(&mut self, id: StreamId, incr: u32) { | ||||||
|         let added = match &up { |         assert!(self.pending_local_window_update.is_none()); | ||||||
|             &WindowUpdate::Connection { increment } => { |  | ||||||
|                 if increment == 0 { |         let added = if id.is_zero() { | ||||||
|                     false |             self.remote_flow_controller.add_to_window(incr); | ||||||
|  |             self.remote_flow_controller.take_window_update() | ||||||
|         } else { |         } else { | ||||||
|                     self.local_flow_controller.increment(increment); |             self.streams.get_mut(&id).and_then(|mut s| s.send_window_update(incr)) | ||||||
|                     true |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             &WindowUpdate::Stream { id, increment } => { |  | ||||||
|                 if increment == 0 { |  | ||||||
|                     false |  | ||||||
|                 } else { |  | ||||||
|                     match self.streams.get_mut(&id) { |  | ||||||
|                         Some(&mut State::Open { local: PeerState::Data(ref mut fc), .. }) | |  | ||||||
|                         Some(&mut State::HalfClosedRemote(PeerState::Data(ref mut fc))) => { |  | ||||||
|                             fc.increment(increment); |  | ||||||
|                             true |  | ||||||
|                         } |  | ||||||
|                         _ => false, |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         if added { |         if let Some(added) = added { | ||||||
|             self.pending_local_window_updates.push_back(up); |             self.pending_local_window_update = Some(frame::WindowUpdate::new(id, added)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Advertises the remote's stream window updates. |     /// Advertises the remote's stream window updates. | ||||||
|     /// |     /// | ||||||
|     /// Connection window updates (StreamId=0) and stream window updates are advertised |     /// Connection window updates (id=0) and stream window updates are advertised | ||||||
|     /// distinctly. |     /// distinctly. | ||||||
|     fn increment_remote_window(&mut self, id: StreamId, incr: u32) { |     fn recv_window_update(&mut self, id: StreamId, incr: u32) { | ||||||
|         if id.is_zero() { |         if id.is_zero() { | ||||||
|             self.remote_flow_controller.increment(incr); |             return self.remote_flow_controller.add_to_window(incr); | ||||||
|         } else { |  | ||||||
|             match self.streams.get_mut(&id) { |  | ||||||
|                 Some(&mut State::Open { remote: PeerState::Data(ref mut fc), .. }) | |  | ||||||
|                 Some(&mut State::HalfClosedLocal(PeerState::Data(ref mut fc))) => { |  | ||||||
|                     fc.increment(incr); |  | ||||||
|         } |         } | ||||||
|                 _ => {} |  | ||||||
|  |         if let Some(mut s) = self.streams.get_mut(&id) { | ||||||
|  |             s.recv_window_update(incr); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|         unimplemented!() |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T, P, B> Connection<T, P, B> | impl<T, P, B> Connection<T, P, B> | ||||||
| @@ -127,16 +118,28 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|           P: Peer, |           P: Peer, | ||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| { | { | ||||||
|  |     fn poll_send_window_update(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         if let Some(f) = self.pending_local_window_update.take() { | ||||||
|  |             if self.inner.start_send(f.into())?.is_not_ready() { | ||||||
|  |                 self.pending_local_window_update = Some(f); | ||||||
|  |                 return Ok(Async::NotReady); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Ok(Async::Ready(())) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn send_data(self, |     pub fn send_data(self, | ||||||
|                      id: StreamId, |                      id: StreamId, | ||||||
|                      data: B, |                      data: B, | ||||||
|  |                      data_len: usize, | ||||||
|                      end_of_stream: bool) |                      end_of_stream: bool) | ||||||
|         -> sink::Send<Self> |         -> sink::Send<Self> | ||||||
|     { |     { | ||||||
|         self.send(Frame::Data { |         self.send(Frame::Data { | ||||||
|             id: id, |             id, | ||||||
|             data: data, |             data_len, | ||||||
|             end_of_stream: end_of_stream, |             data, | ||||||
|  |             end_of_stream, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -201,15 +204,13 @@ impl<T, P, B> Stream for Connection<T, P, B> | |||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             trace!("received; frame={:?}", frame); |             trace!("received; frame={:?}", frame); | ||||||
|  |  | ||||||
|             let frame = match frame { |             let frame = match frame { | ||||||
|                 Some(Headers(v)) => { |                 Some(Headers(v)) => { | ||||||
|                     // TODO: Update stream state |                     // TODO: Update stream state | ||||||
|                     let stream_id = v.stream_id(); |                     let stream_id = v.stream_id(); | ||||||
|                     let end_of_stream = v.is_end_stream(); |                     let end_of_stream = v.is_end_stream(); | ||||||
|  |  | ||||||
|                     // TODO load window size from settings. |                     let init_window_size = self.inner.local_settings().initial_window_size(); | ||||||
|                     let init_window_size = 65_535; |  | ||||||
|  |  | ||||||
|                     let stream_initialized = try!(self.streams.entry(stream_id) |                     let stream_initialized = try!(self.streams.entry(stream_id) | ||||||
|                         .or_insert(State::default()) |                         .or_insert(State::default()) | ||||||
| @@ -231,26 +232,27 @@ impl<T, P, B> Stream for Connection<T, P, B> | |||||||
|                         end_of_stream: end_of_stream, |                         end_of_stream: end_of_stream, | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 Some(Data(v)) => { |  | ||||||
|                     // TODO: Validate frame |  | ||||||
|  |  | ||||||
|  |                 Some(Data(v)) => { | ||||||
|                     let stream_id = v.stream_id(); |                     let stream_id = v.stream_id(); | ||||||
|                     let end_of_stream = v.is_end_stream(); |                     let end_of_stream = v.is_end_stream(); | ||||||
|                     match self.streams.get_mut(&stream_id) { |                     match self.streams.get_mut(&stream_id) { | ||||||
|                         None => return Err(error::Reason::ProtocolError.into()), |                         None => return Err(error::Reason::ProtocolError.into()), | ||||||
|                         Some(state) => try!(state.recv_data(end_of_stream)), |                         Some(state) => try!(state.recv_data(end_of_stream, v.len())), | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     Frame::Data { |                     Frame::Data { | ||||||
|                         id: stream_id, |                         id: stream_id, | ||||||
|  |                         data_len: v.len(), | ||||||
|                         data: v.into_payload(), |                         data: v.into_payload(), | ||||||
|                         end_of_stream: end_of_stream, |                         end_of_stream, | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Some(WindowUpdate(v)) => { |                 Some(WindowUpdate(v)) => { | ||||||
|                     self.increment_remote_window(v.stream_id(), v.size_increment()); |                     self.recv_window_update(v.stream_id(), v.size_increment()); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Some(frame) => panic!("unexpected frame; frame={:?}", frame), |                 Some(frame) => panic!("unexpected frame; frame={:?}", frame), | ||||||
|                 None => return Ok(Async::Ready(None)), |                 None => return Ok(Async::Ready(None)), | ||||||
|             }; |             }; | ||||||
| @@ -268,24 +270,31 @@ impl<T, P, B> Sink for Connection<T, P, B> | |||||||
|     type SinkItem = Frame<P::Send, B>; |     type SinkItem = Frame<P::Send, B>; | ||||||
|     type SinkError = ConnectionError; |     type SinkError = ConnectionError; | ||||||
|  |  | ||||||
|  |     /// Sends a frame to the remote. | ||||||
|     fn start_send(&mut self, item: Self::SinkItem) |     fn start_send(&mut self, item: Self::SinkItem) | ||||||
|         -> StartSend<Self::SinkItem, Self::SinkError> |         -> StartSend<Self::SinkItem, Self::SinkError> | ||||||
|     { |     { | ||||||
|         use frame::Frame::Headers; |         use frame::Frame::Headers; | ||||||
|  |  | ||||||
|         // First ensure that the upstream can process a new item |         // First ensure that the upstream can process a new item. This ensures, for | ||||||
|         if !try!(self.poll_ready()).is_ready() { |         // instance, that any pending local window updates have been sent to the remote | ||||||
|  |         // before sending any other frames. | ||||||
|  |         if try!(self.poll_ready()).is_not_ready() { | ||||||
|             return Ok(AsyncSink::NotReady(item)); |             return Ok(AsyncSink::NotReady(item)); | ||||||
|         } |         } | ||||||
|  |         assert!(self.pending_local_window_update.is_none()); | ||||||
|  |  | ||||||
|         match item { |         match item { | ||||||
|             Frame::Headers { id, headers, end_of_stream } => { |             Frame::Headers { id, headers, end_of_stream } => { | ||||||
|                 // TODO load window size from settings. |                 let init_window_size = self.inner.remote_settings().initial_window_size(); | ||||||
|                 let init_window_size = 65_535; |  | ||||||
|  |  | ||||||
|                 // Transition the stream state, creating a new entry if needed |                 // Transition the stream state, creating a new entry if needed | ||||||
|                 // TODO: Response can send multiple headers frames before body |                 // | ||||||
|                 // (1xx responses). |                 // TODO: Response can send multiple headers frames before body (1xx | ||||||
|  |                 // responses). | ||||||
|  |                 // | ||||||
|  |                 // ACTUALLY(ver), maybe not? | ||||||
|  |                 //   https://github.com/http2/http2-spec/commit/c83c8d911e6b6226269877e446a5cad8db921784 | ||||||
|                 let stream_initialized = try!(self.streams.entry(id) |                 let stream_initialized = try!(self.streams.entry(id) | ||||||
|                      .or_insert(State::default()) |                      .or_insert(State::default()) | ||||||
|                      .send_headers::<P>(end_of_stream, init_window_size)); |                      .send_headers::<P>(end_of_stream, init_window_size)); | ||||||
| @@ -294,7 +303,6 @@ impl<T, P, B> Sink for Connection<T, P, B> | |||||||
|                     // TODO: Ensure available capacity for a new stream |                     // TODO: Ensure available capacity for a new stream | ||||||
|                     // This won't be as simple as self.streams.len() as closed |                     // This won't be as simple as self.streams.len() as closed | ||||||
|                     // connections should not be factored. |                     // connections should not be factored. | ||||||
|                     // |  | ||||||
|                     if !P::is_valid_local_stream_id(id) { |                     if !P::is_valid_local_stream_id(id) { | ||||||
|                         // TODO: clear state |                         // TODO: clear state | ||||||
|                         return Err(error::User::InvalidStreamId.into()); |                         return Err(error::User::InvalidStreamId.into()); | ||||||
| @@ -314,25 +322,26 @@ impl<T, P, B> Sink for Connection<T, P, B> | |||||||
|  |  | ||||||
|                 Ok(AsyncSink::Ready) |                 Ok(AsyncSink::Ready) | ||||||
|             } |             } | ||||||
|             Frame::Data { id, data, end_of_stream } => { |  | ||||||
|  |             Frame::Data { id, data, data_len, end_of_stream } => { | ||||||
|                 // The stream must be initialized at this point |                 // The stream must be initialized at this point | ||||||
|                 match self.streams.get_mut(&id) { |                 match self.streams.get_mut(&id) { | ||||||
|                     None => return Err(error::User::InactiveStreamId.into()), |                     None => return Err(error::User::InactiveStreamId.into()), | ||||||
|                     Some(state) => try!(state.send_data(end_of_stream)), |                     Some(state) => try!(state.send_data(end_of_stream, data_len)), | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 let mut frame = frame::Data::new(id, data.into_buf()); |                 let mut frame = frame::Data::from_buf(id, data.into_buf()); | ||||||
|  |  | ||||||
|                 if end_of_stream { |                 if end_of_stream { | ||||||
|                     frame.set_end_stream(); |                     frame.set_end_stream(); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 let res = try!(self.inner.start_send(frame.into())); |                 let res = try!(self.inner.start_send(frame.into())); | ||||||
|  |                 // poll_ready has already been called. | ||||||
|                 assert!(res.is_ready()); |                 assert!(res.is_ready()); | ||||||
|  |  | ||||||
|                 Ok(AsyncSink::Ready) |                 Ok(AsyncSink::Ready) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             /* |             /* | ||||||
|             Frame::Trailers { id, headers } => { |             Frame::Trailers { id, headers } => { | ||||||
|                 unimplemented!(); |                 unimplemented!(); | ||||||
| @@ -352,6 +361,7 @@ impl<T, P, B> Sink for Connection<T, P, B> | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         try_ready!(self.poll_send_window_update()); | ||||||
|         self.inner.poll_complete() |         self.inner.poll_complete() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -362,6 +372,7 @@ impl<T, P, B> ReadySink for Connection<T, P, B> | |||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| { | { | ||||||
|     fn poll_ready(&mut self) -> Poll<(), Self::SinkError> { |     fn poll_ready(&mut self) -> Poll<(), Self::SinkError> { | ||||||
|  |         try_ready!(self.poll_send_window_update()); | ||||||
|         self.inner.poll_ready() |         self.inner.poll_ready() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,23 @@ | |||||||
| #[derive(Clone, Copy, Debug)] | #[derive(Clone, Copy, Debug)] | ||||||
| pub struct WindowUnderflow; | pub struct WindowUnderflow; | ||||||
|  |  | ||||||
|  | pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535; | ||||||
|  |  | ||||||
| #[derive(Copy, Clone, Debug)] | #[derive(Copy, Clone, Debug)] | ||||||
| pub struct FlowController { | pub struct FlowController { | ||||||
|  |     /// Amount that may be claimed. | ||||||
|     window_size: u32, |     window_size: u32, | ||||||
|  |     /// Amount to be removed by future increments. | ||||||
|     underflow: u32, |     underflow: u32, | ||||||
|  |     /// The amount that has been incremented but not yet advertised (to the application or | ||||||
|  |     /// the remote). | ||||||
|  |     next_window_update: u32, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Default for FlowController { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self::new(DEFAULT_INITIAL_WINDOW_SIZE) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl FlowController { | impl FlowController { | ||||||
| @@ -12,14 +25,23 @@ impl FlowController { | |||||||
|         FlowController { |         FlowController { | ||||||
|             window_size, |             window_size, | ||||||
|             underflow: 0, |             underflow: 0, | ||||||
|  |             next_window_update: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn shrink(&mut self, sz: u32) { |     pub fn window_size(&self) -> u32 { | ||||||
|         self.underflow += sz; |         self.window_size | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn consume(&mut self, sz: u32) -> Result<(), WindowUnderflow> { |     /// Reduce future capacity of the window. | ||||||
|  |     /// | ||||||
|  |     /// This accomodates updates to SETTINGS_INITIAL_WINDOW_SIZE. | ||||||
|  |     pub fn shrink_window(&mut self, decr: u32) { | ||||||
|  |         self.underflow += decr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Claim the provided amount from the window, if there is enough space. | ||||||
|  |     pub fn claim_window(&mut self, sz: u32) -> Result<(), WindowUnderflow> { | ||||||
|         if self.window_size < sz { |         if self.window_size < sz { | ||||||
|             return Err(WindowUnderflow); |             return Err(WindowUnderflow); | ||||||
|         } |         } | ||||||
| @@ -28,13 +50,27 @@ impl FlowController { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn increment(&mut self, sz: u32) { |     /// Applies a window increment immediately. | ||||||
|  |     pub fn add_to_window(&mut self, sz: u32) { | ||||||
|         if sz <= self.underflow { |         if sz <= self.underflow { | ||||||
|             self.underflow -= sz; |             self.underflow -= sz; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         self.window_size += sz - self.underflow; |         let added = sz - self.underflow; | ||||||
|  |         self.window_size += added; | ||||||
|  |         self.next_window_update += added; | ||||||
|         self.underflow = 0; |         self.underflow = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Obtains and clears an unadvertised window update. | ||||||
|  |     pub fn take_window_update(&mut self) -> Option<u32> { | ||||||
|  |         if self.next_window_update == 0 { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let incr = self.next_window_update; | ||||||
|  |         self.next_window_update = 0; | ||||||
|  |         Some(incr) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -93,5 +93,5 @@ pub fn from_server_handshaker<T, P, B>(transport: Settings<FramedWrite<T, B::Buf | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     // Finally, return the constructed `Connection` |     // Finally, return the constructed `Connection` | ||||||
|     connection::new(settings, 65_535, 65_535) |     connection::new(settings) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,6 +43,14 @@ impl<T, U> Settings<T> | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn local_settings(&self) -> &frame::SettingSet { | ||||||
|  |         &self.local | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn remote_settings(&self) -> &frame::SettingSet { | ||||||
|  |         &self.local | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Swap the inner transport while maintaining the current state. |     /// Swap the inner transport while maintaining the current state. | ||||||
|     pub fn swap_inner<T2, F: FnOnce(T) -> T2>(self, f: F) -> Settings<T2> { |     pub fn swap_inner<T2, F: FnOnce(T) -> T2>(self, f: F) -> Settings<T2> { | ||||||
|         let inner = f(self.inner); |         let inner = f(self.inner); | ||||||
|   | |||||||
| @@ -58,106 +58,178 @@ pub enum State { | |||||||
|     Closed, |     Closed, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Copy, Clone)] |  | ||||||
| pub enum PeerState { |  | ||||||
|     Headers, |  | ||||||
|     Data(FlowController), |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl State { | impl State { | ||||||
|     pub fn increment_local_window_size(&mut self, incr: u32) { |     /// Updates the local flow controller with the given window size increment. | ||||||
|  |     /// | ||||||
|  |     /// Returns the amount of capacity created, accounting for window size changes. The | ||||||
|  |     /// caller should send the the returned window size increment to the remote. | ||||||
|  |     /// | ||||||
|  |     /// If the remote is closed, None is returned. | ||||||
|  |     pub fn send_window_update(&mut self, incr: u32) -> Option<u32> { | ||||||
|         use self::State::*; |         use self::State::*; | ||||||
|         use self::PeerState::*; |         use self::PeerState::*; | ||||||
|  |  | ||||||
|         *self = match *self { |         if incr == 0 { | ||||||
|             Open { local: Data(mut local), remote } => { |             return None; | ||||||
|                 local.increment(incr); |  | ||||||
|                 Open { local: Data(local), remote } |  | ||||||
|         } |         } | ||||||
|             HalfClosedRemote(Data(mut local)) => { |  | ||||||
|                 local.increment(incr); |         match self { | ||||||
|                 HalfClosedRemote(Data(local)) |             &mut Open { local: Data(ref mut fc), .. } | | ||||||
|  |             &mut HalfClosedRemote(Data(ref mut fc)) => { | ||||||
|  |                 fc.add_to_window(incr); | ||||||
|  |                 fc.take_window_update() | ||||||
|             } |             } | ||||||
|             s => s, |             _ => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   |   | ||||||
|  |     /// Updates the remote flow controller with the given window size increment. | ||||||
|  |     /// | ||||||
|  |     /// Returns the amount of capacity created, accounting for window size changes. The | ||||||
|  |     /// caller should send the the returned window size increment to the remote. | ||||||
|  |     pub fn recv_window_update(&mut self, incr: u32) { | ||||||
|  |         use self::State::*; | ||||||
|  |         use self::PeerState::*; | ||||||
|  |  | ||||||
|  |         if incr == 0 { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         match self { | ||||||
|  |             &mut Open { remote: Data(ref mut fc), .. } | | ||||||
|  |             &mut HalfClosedLocal(Data(ref mut fc)) => fc.add_to_window(incr), | ||||||
|  |             _ => {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn take_remote_window_update(&mut self) -> Option<u32> { | ||||||
|  |         use self::State::*; | ||||||
|  |         use self::PeerState::*; | ||||||
|  |  | ||||||
|  |         match self { | ||||||
|  |             &mut Open { remote: Data(ref mut fc), .. } | | ||||||
|  |             &mut HalfClosedLocal(Data(ref mut fc)) => fc.take_window_update(), | ||||||
|  |             _ => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Applies an update to the remote's initial window size. | ||||||
|  |     /// | ||||||
|  |     /// Per RFC 7540 §6.9.2 | ||||||
|  |     /// | ||||||
|  |     /// > In addition to changing the flow-control window for streams that are not yet | ||||||
|  |     /// > active, a SETTINGS frame can alter the initial flow-control window size for | ||||||
|  |     /// > streams with active flow-control windows (that is, streams in the "open" or | ||||||
|  |     /// > "half-closed (remote)" state). When the value of SETTINGS_INITIAL_WINDOW_SIZE | ||||||
|  |     /// > changes, a receiver MUST adjust the size of all stream flow-control windows that | ||||||
|  |     /// > it maintains by the difference between the new value and the old value. | ||||||
|  |     /// > | ||||||
|  |     /// > A change to `SETTINGS_INITIAL_WINDOW_SIZE` can cause the available space in a | ||||||
|  |     /// > flow-control window to become negative. A sender MUST track the negative | ||||||
|  |     /// > flow-control window and MUST NOT send new flow-controlled frames until it | ||||||
|  |     /// > receives WINDOW_UPDATE frames that cause the flow-control window to become | ||||||
|  |     /// > positive. | ||||||
|  |     pub fn update_remote_initial_window_size(&mut self, old: u32, new: u32) { | ||||||
|  |         use self::State::*; | ||||||
|  |         use self::PeerState::*; | ||||||
|  |  | ||||||
|  |         match self { | ||||||
|  |             &mut Open { remote: Data(ref mut fc), .. } | | ||||||
|  |             &mut HalfClosedLocal(Data(ref mut fc)) => { | ||||||
|  |                 if new < old { | ||||||
|  |                     fc.shrink_window(old - new); | ||||||
|  |                 } else { | ||||||
|  |                     fc.add_to_window(new - old); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// TODO Connection doesn't have an API for local updates yet. | ||||||
|  |     pub fn update_local_initial_window_size(&mut self, _old: u32, _new: u32) { | ||||||
|  |         //use self::State::*; | ||||||
|  |         //use self::PeerState::*; | ||||||
|  |         unimplemented!() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Transition the state to represent headers being received. |     /// Transition the state to represent headers being received. | ||||||
|     /// |     /// | ||||||
|     /// Returns true if this state transition results in iniitializing the |     /// Returns true if this state transition results in iniitializing the | ||||||
|     /// stream id. `Err` is returned if this is an invalid state transition. |     /// stream id. `Err` is returned if this is an invalid state transition. | ||||||
|     pub fn recv_headers<P: Peer>(&mut self, eos: bool, remote_window_size: u32) -> Result<bool, ConnectionError> { |     pub fn recv_headers<P: Peer>(&mut self, | ||||||
|  |                                  eos: bool, | ||||||
|  |                                  remote_window_size: u32) | ||||||
|  |         -> Result<bool, ConnectionError> | ||||||
|  |     { | ||||||
|         use self::State::*; |         use self::State::*; | ||||||
|         use self::PeerState::*; |         use self::PeerState::*; | ||||||
|  |  | ||||||
|         match *self { |         match *self { | ||||||
|             Idle => { |             Idle => { | ||||||
|                 *self = if eos { |                 let local = Headers; | ||||||
|                     HalfClosedRemote(Headers) |                 if eos { | ||||||
|  |                     *self = HalfClosedRemote(local); | ||||||
|                 } else { |                 } else { | ||||||
|                     Open { |                     *self = Open { local, remote: Data(FlowController::new(remote_window_size)) }; | ||||||
|                         local: Headers, |  | ||||||
|                         remote: Data(FlowController::new(remote_window_size)), |  | ||||||
|                 } |                 } | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 Ok(true) |                 Ok(true) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Open { local, remote } => { |             Open { local, remote } => { | ||||||
|                 try!(remote.check_is_headers(ProtocolError.into())); |                 try!(remote.check_is_headers(ProtocolError.into())); | ||||||
|  |                 if !eos { | ||||||
|                 *self = if eos { |                     // Received non-trailers HEADERS on open remote. | ||||||
|                     HalfClosedRemote(local) |                     return Err(ProtocolError.into()); | ||||||
|                 } else { |                 } | ||||||
|                     let remote = Data(FlowController::new(remote_window_size)); |                 *self = HalfClosedRemote(local); | ||||||
|                     Open { local, remote } |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 Ok(false) |                 Ok(false) | ||||||
|             } |             } | ||||||
|             HalfClosedLocal(remote) => { |  | ||||||
|                 try!(remote.check_is_headers(ProtocolError.into())); |  | ||||||
|  |  | ||||||
|                 *self = if eos { |             HalfClosedLocal(headers) => { | ||||||
|                     Closed |                 try!(headers.check_is_headers(ProtocolError.into())); | ||||||
|  |                 if eos { | ||||||
|  |                     *self = Closed; | ||||||
|                 } else { |                 } else { | ||||||
|                     HalfClosedLocal(Data(FlowController::new(remote_window_size))) |                     *self = HalfClosedLocal(Data(FlowController::new(remote_window_size))); | ||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 Ok(false) |                 Ok(false) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Closed | HalfClosedRemote(..) => { |             Closed | HalfClosedRemote(..) => { | ||||||
|                 Err(ProtocolError.into()) |                 Err(ProtocolError.into()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             _ => unimplemented!(), |             _ => unimplemented!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn recv_data(&mut self, eos: bool) -> Result<(), ConnectionError> { |     pub fn recv_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> { | ||||||
|         use self::State::*; |         use self::State::*; | ||||||
|  |  | ||||||
|         match *self { |         match *self { | ||||||
|             Open { local, remote } => { |             Open { local, remote } => { | ||||||
|                 try!(remote.check_is_data(ProtocolError.into())); |                 try!(remote.check_is_data(ProtocolError.into())); | ||||||
|  |                 try!(remote.check_window_size(len, FlowControlError.into())); | ||||||
|                 if eos { |                 if eos { | ||||||
|                     *self = HalfClosedRemote(local); |                     *self = HalfClosedRemote(local); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedLocal(remote) => { |             HalfClosedLocal(remote) => { | ||||||
|                 try!(remote.check_is_data(ProtocolError.into())); |                 try!(remote.check_is_data(ProtocolError.into())); | ||||||
|  |                 try!(remote.check_window_size(len, FlowControlError.into())); | ||||||
|                 if eos { |                 if eos { | ||||||
|                     *self = Closed; |                     *self = Closed; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Closed | HalfClosedRemote(..) => { |             Closed | HalfClosedRemote(..) => { | ||||||
|                 Err(ProtocolError.into()) |                 Err(ProtocolError.into()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             _ => unimplemented!(), |             _ => unimplemented!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -183,6 +255,7 @@ impl State { | |||||||
|  |  | ||||||
|                 Ok(true) |                 Ok(true) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Open { local, remote } => { |             Open { local, remote } => { | ||||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); |                 try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||||
|  |  | ||||||
| @@ -195,6 +268,7 @@ impl State { | |||||||
|  |  | ||||||
|                 Ok(false) |                 Ok(false) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedRemote(local) => { |             HalfClosedRemote(local) => { | ||||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); |                 try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||||
|  |  | ||||||
| @@ -206,67 +280,84 @@ impl State { | |||||||
|  |  | ||||||
|                 Ok(false) |                 Ok(false) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Closed | HalfClosedLocal(..) => { |             Closed | HalfClosedLocal(..) => { | ||||||
|                 Err(UnexpectedFrameType.into()) |                 Err(UnexpectedFrameType.into()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             _ => unimplemented!(), |             _ => unimplemented!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_data(&mut self, eos: bool) -> Result<(), ConnectionError> { |     pub fn send_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> { | ||||||
|         use self::State::*; |         use self::State::*; | ||||||
|  |  | ||||||
|         match *self { |         match *self { | ||||||
|             Open { local, remote } => { |             Open { local, remote } => { | ||||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); |                 try!(local.check_is_data(UnexpectedFrameType.into())); | ||||||
|  |                 try!(local.check_window_size(len, FlowControlViolation.into())); | ||||||
|                 if eos { |                 if eos { | ||||||
|                     *self = HalfClosedLocal(remote); |                     *self = HalfClosedLocal(remote); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedRemote(local) => { |             HalfClosedRemote(local) => { | ||||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); |                 try!(local.check_is_data(UnexpectedFrameType.into())); | ||||||
|  |                 try!(local.check_window_size(len, FlowControlViolation.into())); | ||||||
|                 if eos { |                 if eos { | ||||||
|                     *self = Closed; |                     *self = Closed; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Closed | HalfClosedLocal(..) => { |             Closed | HalfClosedLocal(..) => { | ||||||
|                 Err(UnexpectedFrameType.into()) |                 Err(UnexpectedFrameType.into()) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             _ => unimplemented!(), |             _ => unimplemented!(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl PeerState { |  | ||||||
|     #[inline] |  | ||||||
|     fn check_is_headers(&self, err: ConnectionError) -> Result<(), ConnectionError> { |  | ||||||
|         use self::PeerState::*; |  | ||||||
|  |  | ||||||
|         match *self { |  | ||||||
|             Headers => Ok(()), |  | ||||||
|             _ => Err(err), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     fn check_is_data(&self, err: ConnectionError) -> Result<(), ConnectionError> { |  | ||||||
|         use self::PeerState::*; |  | ||||||
|  |  | ||||||
|         match *self { |  | ||||||
|             Data { .. } => Ok(()), |  | ||||||
|             _ => Err(err), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Default for State { | impl Default for State { | ||||||
|     fn default() -> State { |     fn default() -> State { | ||||||
|         State::Idle |         State::Idle | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub enum PeerState { | ||||||
|  |     Headers, | ||||||
|  |     /// Contains a FlowController representing the _receiver_ of this this data stream. | ||||||
|  |     Data(FlowController), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl PeerState { | ||||||
|  |     #[inline] | ||||||
|  |     fn check_is_headers(&self, err: ConnectionError) -> Result<(), ConnectionError> { | ||||||
|  |         use self::PeerState::*; | ||||||
|  |         match self { | ||||||
|  |             &Headers => Ok(()), | ||||||
|  |             _ => Err(err), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     fn check_is_data(&self, err: ConnectionError) -> Result<(), ConnectionError> { | ||||||
|  |         use self::PeerState::*; | ||||||
|  |         match self { | ||||||
|  |             &Data(_) => Ok(()), | ||||||
|  |             _ => Err(err), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     fn check_window_size(&self, len: usize, err: ConnectionError) -> Result<(), ConnectionError> { | ||||||
|  |         use self::PeerState::*; | ||||||
|  |         match self { | ||||||
|  |             &Data(ref fc) if len <= fc.window_size() as usize=> Ok(()), | ||||||
|  |             _ => Err(err), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user