wip: refactor, compiles
This commit is contained in:
		| @@ -80,6 +80,21 @@ impl<T> Frame<T> { | ||||
|             &Settings(_) => StreamId::zero(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn is_end_stream(&self) -> bool { | ||||
|         use self::Frame::*; | ||||
|  | ||||
|         match self { | ||||
|             &Headers(ref v) => v.is_end_stream(), | ||||
|             &Data(ref v) => v.is_end_stream(), | ||||
|             &Reset(ref v) => true, | ||||
|  | ||||
|             &PushPromise(_) | | ||||
|             &WindowUpdate(_) | | ||||
|             &Ping(_) | | ||||
|             &Settings(_) => false, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Errors that can occur during parsing an HTTP/2 frame. | ||||
|   | ||||
| @@ -16,6 +16,15 @@ impl Reset { | ||||
|             error_code: error.into(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn stream_id(&self) -> StreamId { | ||||
|         self.stream_id | ||||
|     } | ||||
|  | ||||
|     pub fn reason(&self) -> Reason { | ||||
|         self.error_code.into() | ||||
|     } | ||||
|  | ||||
|     pub fn load(head: Head, payload: &[u8]) -> Result<Reset, Error> { | ||||
|         if payload.len() != 4 { | ||||
|             return Err(Error::InvalidPayloadLength); | ||||
| @@ -35,14 +44,6 @@ impl Reset { | ||||
|         head.encode(4, dst); | ||||
|         dst.put_u32::<BigEndian>(self.error_code); | ||||
|     } | ||||
|  | ||||
|     pub fn stream_id(&self) -> StreamId { | ||||
|         self.stream_id | ||||
|     } | ||||
|  | ||||
|     pub fn reason(&self) -> Reason { | ||||
|         self.error_code.into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> From<Reset> for frame::Frame<B> { | ||||
|   | ||||
| @@ -85,7 +85,6 @@ pub trait Peer { | ||||
|     /// remote node. | ||||
|     fn is_valid_remote_stream_id(id: StreamId) -> bool; | ||||
|  | ||||
|  | ||||
|     fn can_create_local_stream() -> bool; | ||||
|     fn can_create_remote_stream() -> bool { | ||||
|         !Self::can_create_local_stream() | ||||
|   | ||||
| @@ -3,6 +3,7 @@ use client::Client; | ||||
| use error; | ||||
| use frame::{self, SettingSet, StreamId}; | ||||
| use proto::*; | ||||
| use proto::ping_pong::PingPayload; | ||||
| use server::Server; | ||||
|  | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
| @@ -32,37 +33,23 @@ pub fn new<T, P, B>(transport: Transport<T, P, B::Buf>) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // impl<T, P, B> ControlSettings for Connection<T, P, B> | ||||
| //     where T: AsyncRead + AsyncWrite, | ||||
| //           B: IntoBuf, | ||||
| // { | ||||
| //     fn update_local_settings(&mut self, local: frame::SettingSet) -> Result<(), ConnectionError> { | ||||
| //         self.inner.update_local_settings(local) | ||||
| //     } | ||||
|  | ||||
| impl<T, P, B> ControlSettings for Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     fn update_local_settings(&mut self, local: frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.update_local_settings(local) | ||||
|     } | ||||
| //     fn local_settings(&self) -> &SettingSet { | ||||
| //         self.inner.local_settings() | ||||
| //     } | ||||
|  | ||||
|     fn local_settings(&self) -> &SettingSet { | ||||
|         self.inner.local_settings() | ||||
|     } | ||||
| //     fn remote_settings(&self) -> &SettingSet { | ||||
| //         self.inner.remote_settings() | ||||
| //     } | ||||
| // } | ||||
|  | ||||
|     fn remote_settings(&self) -> &SettingSet { | ||||
|         self.inner.remote_settings() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, B> ControlPing for Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, B> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
| @@ -146,21 +133,7 @@ impl<T, P, B> Stream for Connection<T, P, B> | ||||
|         } | ||||
|  | ||||
|         loop { | ||||
|             let frame = match try!(self.inner.poll()) { | ||||
|                 Async::Ready(f) => f, | ||||
|  | ||||
|                 // XXX is this necessary? | ||||
|                 Async::NotReady => { | ||||
|                     // Receiving new frames may depend on ensuring that the write buffer | ||||
|                     // is clear (e.g. if window updates need to be sent), so `poll_complete` | ||||
|                     // is called here.  | ||||
|                     try_ready!(self.poll_complete()); | ||||
|  | ||||
|                     // If the write buffer is cleared, attempt to poll the underlying | ||||
|                     // stream once more because it, may have been made ready. | ||||
|                     try_ready!(self.inner.poll()) | ||||
|                 } | ||||
|             }; | ||||
|             let frame = try_ready!(self.inner.poll()); | ||||
|  | ||||
|             trace!("poll; frame={:?}", frame); | ||||
|             let frame = match frame { | ||||
| @@ -214,34 +187,20 @@ impl<T, P, B> Sink for Connection<T, P, B> | ||||
|             return Ok(AsyncSink::NotReady(item)); | ||||
|         } | ||||
|  | ||||
|         match item { | ||||
|         let frame = match item { | ||||
|             Frame::Headers { id, headers, end_of_stream } => { | ||||
|                 // This is a one-way conversion. By checking `poll_ready` first (above), | ||||
|                 // it's already been determined that the inner `Sink` can accept the item. | ||||
|                 // If the item is rejected, then there is a bug. | ||||
|                 let frame = P::convert_send_message(id, headers, end_of_stream); | ||||
|                 let res = self.inner.start_send(frame::Frame::Headers(frame))?; | ||||
|                 assert!(res.is_ready()); | ||||
|                 Ok(AsyncSink::Ready) | ||||
|                 let f = P::convert_send_message(id, headers, end_of_stream); | ||||
|                 frame::Frame::Headers(f) | ||||
|             } | ||||
|  | ||||
|             Frame::Data { id, data, end_of_stream } => { | ||||
|                 if self.inner.stream_is_reset(id).is_some() { | ||||
|                     return Err(error::User::StreamReset.into()); | ||||
|                 } | ||||
|  | ||||
|                 let frame = frame::Data::from_buf(id, data.into_buf(), end_of_stream); | ||||
|                 let res = try!(self.inner.start_send(frame.into())); | ||||
|                 assert!(res.is_ready()); | ||||
|                 Ok(AsyncSink::Ready) | ||||
|                 frame::Data::from_buf(id, data.into_buf(), end_of_stream).into() | ||||
|             } | ||||
|  | ||||
|             Frame::Reset { id, error } => { | ||||
|                 let f = frame::Reset::new(id, error); | ||||
|                 let res = self.inner.start_send(f.into())?; | ||||
|                 assert!(res.is_ready()); | ||||
|                 Ok(AsyncSink::Ready) | ||||
|             } | ||||
|             Frame::Reset { id, error } => frame::Reset::new(id, error).into(), | ||||
|  | ||||
|             /* | ||||
|             Frame::Trailers { id, headers } => { | ||||
| @@ -255,7 +214,11 @@ impl<T, P, B> Sink for Connection<T, P, B> | ||||
|             } | ||||
|             */ | ||||
|             _ => unimplemented!(), | ||||
|         } | ||||
|         }; | ||||
|  | ||||
|         let res = self.inner.start_send(frame)?; | ||||
|         assert!(res.is_ready()); | ||||
|         Ok(AsyncSink::Ready) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|   | ||||
| @@ -4,6 +4,20 @@ use proto::*; | ||||
|  | ||||
| use std::collections::VecDeque; | ||||
|  | ||||
| /// Exposes flow control states to "upper" layers of the transport (i.e. above | ||||
| /// FlowControl). | ||||
| pub trait ControlFlow { | ||||
|     /// Polls for the next window update from the remote. | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError>; | ||||
|  | ||||
|     /// Increases the local receive capacity of a stream. | ||||
|     /// | ||||
|     /// This may cause a window update to be sent to the remote. | ||||
|     /// | ||||
|     /// Fails if the given stream is not active. | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError>; | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct FlowControl<T>  { | ||||
|     inner: T, | ||||
| @@ -80,30 +94,6 @@ impl<T: ControlStreams> FlowControl<T> { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Proxies access to streams. | ||||
| impl<T: ControlStreams> ControlStreams for FlowControl<T> { | ||||
|    fn local_streams(&self) -> &StreamMap { | ||||
|         self.inner.local_streams() | ||||
|     } | ||||
|  | ||||
|     fn local_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         self.inner.local_streams_mut() | ||||
|     } | ||||
|  | ||||
|     fn remote_streams(&self) -> &StreamMap { | ||||
|         self.inner.local_streams() | ||||
|     } | ||||
|  | ||||
|     fn remote_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         self.inner.local_streams_mut() | ||||
|     } | ||||
|  | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Exposes a public upward API for flow control. | ||||
| impl<T: ControlStreams> ControlFlow for FlowControl<T> { | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||
| @@ -139,7 +129,7 @@ impl<T: ControlStreams> ControlFlow for FlowControl<T> { | ||||
|                 self.local_pending_streams.push_back(id); | ||||
|             } | ||||
|             Ok(()) | ||||
|         } else if let Some(rst) = self.get_reset(id) { | ||||
|         } else if let Some(rst) = self.inner.get_reset(id) { | ||||
|             Err(error::User::StreamReset(rst).into()) | ||||
|         } else { | ||||
|             Err(error::User::InvalidStreamId.into()) | ||||
| @@ -147,16 +137,6 @@ impl<T: ControlStreams> ControlFlow for FlowControl<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for FlowControl<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> FlowControl<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| @@ -172,7 +152,7 @@ impl<T, U> FlowControl<T> | ||||
|         } | ||||
|  | ||||
|         while let Some(id) = self.local_pending_streams.pop_front() { | ||||
|             if self.stream_is_reset(id).is_none() { | ||||
|             if self.inner.get_reset(id).is_none() { | ||||
|                 let update = self.local_flow_controller(id).and_then(|s| s.apply_window_update()); | ||||
|                 if let Some(incr) = update { | ||||
|                     try_ready!(self.try_send(frame::WindowUpdate::new(id, incr))); | ||||
| @@ -193,71 +173,6 @@ impl<T, U> FlowControl<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Applies an update to an endpoint'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. | ||||
| impl<T> ApplySettings for FlowControl<T>  | ||||
|     where T: ApplySettings, | ||||
|           T: ControlStreams | ||||
| { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set)?; | ||||
|  | ||||
|         let old_window_size = self.local_initial; | ||||
|         let new_window_size = set.initial_window_size(); | ||||
|         if new_window_size == old_window_size { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         let mut streams = self.inner.streams_mut(); | ||||
|         if new_window_size < old_window_size { | ||||
|             let decr = old_window_size - new_window_size; | ||||
|             streams.shrink_all_local_windows(decr); | ||||
|         } else {  | ||||
|             let incr = new_window_size - old_window_size; | ||||
|             streams.expand_all_local_windows(incr); | ||||
|         } | ||||
|          | ||||
|         self.local_initial = new_window_size; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set)?; | ||||
|  | ||||
|         let old_window_size = self.remote_initial; | ||||
|         let new_window_size = set.initial_window_size(); | ||||
|         if new_window_size == old_window_size { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         let mut streams = self.inner.streams_mut(); | ||||
|         if new_window_size < old_window_size { | ||||
|             let decr = old_window_size - new_window_size; | ||||
|             streams.shrink_all_remote_windows(decr); | ||||
|         } else {  | ||||
|             let incr = new_window_size - old_window_size; | ||||
|             streams.expand_all_remote_windows(incr); | ||||
|         } | ||||
|          | ||||
|         self.remote_initial = new_window_size; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Stream for FlowControl<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| @@ -310,7 +225,7 @@ impl<T, U> Sink for FlowControl<T> | ||||
|     fn start_send(&mut self, frame: Frame<U>) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         debug_assert!(self.stream_is_reset(frame.stream_id()).is_none()); | ||||
|         debug_assert!(self.inner.get_reset(frame.stream_id()).is_none()); | ||||
|  | ||||
|         // Ensures that: | ||||
|         // 1. all pending local window updates have been sent to the remote. | ||||
| @@ -333,8 +248,7 @@ impl<T, U> Sink for FlowControl<T> | ||||
|  | ||||
|             // Ensure there's enough capacity on stream. | ||||
|             { | ||||
|                 let mut fc = self.streams_mut() | ||||
|                     .remote_flow_controller(v.stream_id()) | ||||
|                 let mut fc = self.inner.remote_flow_controller(v.stream_id()) | ||||
|                     .expect("no remote stream for data frame"); | ||||
|                 if fc.claim_window(sz).is_err() { | ||||
|                     return Err(error::User::FlowControlViolation.into()) | ||||
| @@ -367,3 +281,116 @@ impl<T, U> ReadySink for FlowControl<T> | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Applies an update to an endpoint'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. | ||||
| impl<T> ApplySettings for FlowControl<T>  | ||||
|     where T: ApplySettings, | ||||
|           T: ControlStreams | ||||
| { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set)?; | ||||
|  | ||||
|         let old_window_size = self.local_initial; | ||||
|         let new_window_size = set.initial_window_size(); | ||||
|         if new_window_size == old_window_size { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         self.inner.local_update_inital_window_size(old_window_size, new_window_size); | ||||
|         self.local_initial = new_window_size; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set)?; | ||||
|  | ||||
|         let old_window_size = self.remote_initial; | ||||
|         let new_window_size = set.initial_window_size(); | ||||
|         if new_window_size == old_window_size { | ||||
|             return Ok(()); | ||||
|         } | ||||
|  | ||||
|         self.inner.remote_update_inital_window_size(old_window_size, new_window_size); | ||||
|         self.remote_initial = new_window_size; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for FlowControl<T> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         T::is_valid_remote_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         T::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.inner.get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.inner.reset_stream(id, cause) | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_local_active(id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_remote_active(id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.inner.local_active_len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.inner.remote_active_len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.local_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.remote_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for FlowControl<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										131
									
								
								src/proto/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								src/proto/mod.rs
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| use {frame, ConnectionError, Peer, StreamId}; | ||||
| use error::Reason; | ||||
| use frame::SettingSet; | ||||
| use frame::{Frame, SettingSet}; | ||||
|  | ||||
| use bytes::{Buf, IntoBuf}; | ||||
| use futures::*; | ||||
| @@ -16,21 +16,27 @@ mod ping_pong; | ||||
| mod ready; | ||||
| mod settings; | ||||
| mod state; | ||||
| mod stream_recv; | ||||
| mod stream_send; | ||||
| mod stream_recv_close; | ||||
| mod stream_recv_open; | ||||
| mod stream_send_close; | ||||
| mod stream_send_open; | ||||
| mod stream_store; | ||||
|  | ||||
| pub use self::connection::Connection; | ||||
| pub use self::flow_control::FlowControl; | ||||
| pub use self::flow_control_state::{FlowControlState, WindowUnderflow}; | ||||
| pub use self::framed_read::FramedRead; | ||||
| pub use self::framed_write::FramedWrite; | ||||
| pub use self::ping_pong::PingPong; | ||||
| pub use self::ready::ReadySink; | ||||
| pub use self::settings::Settings; | ||||
| pub use self::stream_recv::StreamRecv; | ||||
| pub use self::stream_send::StreamSend; | ||||
|  | ||||
| use self::state::{StreamMap, StreamState}; | ||||
| use self::flow_control::{ControlFlow, FlowControl}; | ||||
| use self::flow_control_state::{FlowControlState, WindowUnderflow}; | ||||
| use self::framed_read::FramedRead; | ||||
| use self::framed_write::FramedWrite; | ||||
| use self::ping_pong::{ControlPing, PingPayload, PingPong}; | ||||
| use self::ready::ReadySink; | ||||
| use self::settings::{ApplySettings, ControlSettings, Settings}; | ||||
| use self::state::{StreamState, PeerState}; | ||||
| use self::stream_recv_close::StreamRecvClose; | ||||
| use self::stream_recv_open::StreamRecvOpen; | ||||
| use self::stream_send_close::StreamSendClose; | ||||
| use self::stream_send_open::StreamSendOpen; | ||||
| use self::stream_store::{ControlStreams, StreamStore}; | ||||
|  | ||||
| /// Represents the internals of an HTTP/2 connection. | ||||
| /// | ||||
| @@ -91,10 +97,12 @@ type Transport<T, P, B>= | ||||
|             P>>; | ||||
|  | ||||
| type Streams<T, P> = | ||||
|     StreamSend< | ||||
|         FlowControl< | ||||
|             StreamRecv<T, P>>, | ||||
|         P>; | ||||
|     StreamSendOpen< | ||||
|         StreamRecvClose< | ||||
|             FlowControl< | ||||
|                 StreamSendClose< | ||||
|                     StreamRecvOpen< | ||||
|                         StreamStore<T, P>>>>>>; | ||||
|  | ||||
| type Codec<T, B> = | ||||
|     FramedRead< | ||||
| @@ -102,21 +110,6 @@ type Codec<T, B> = | ||||
|  | ||||
| pub type WindowSize = u32; | ||||
|  | ||||
| /// Exposes settings to "upper" layers of the transport (i.e. from Settings up to---and | ||||
| /// above---Connection). | ||||
| pub trait ControlSettings { | ||||
|     fn update_local_settings(&mut self, set: frame::SettingSet) -> Result<(), ConnectionError>; | ||||
|     fn local_settings(&self) -> &SettingSet; | ||||
|     fn remote_settings(&self) -> &SettingSet; | ||||
| } | ||||
|  | ||||
| /// Allows settings updates to be pushed "down" the transport (i.e. from Settings down to | ||||
| /// FramedWrite). | ||||
| pub trait ApplySettings { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>; | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>; | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub struct WindowUpdate { | ||||
|     stream_id: StreamId, | ||||
| @@ -137,61 +130,6 @@ impl WindowUpdate { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Exposes flow control states to "upper" layers of the transport (i.e. above | ||||
| /// FlowControl). | ||||
| pub trait ControlFlow { | ||||
|     /// Polls for the next window update from the remote. | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError>; | ||||
|  | ||||
|     /// Increases the local receive capacity of a stream. | ||||
|     /// | ||||
|     /// This may cause a window update to be sent to the remote. | ||||
|     /// | ||||
|     /// Fails if the given stream is not active. | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError>; | ||||
| } | ||||
|  | ||||
| /// Exposes stream states to "upper" layers of the transport (i.e. from StreamTracker up | ||||
| /// to Connection). | ||||
| pub trait ControlStreams { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool; | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         !id.is_zero() && !Self::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn get_active(&self, id: StreamId) -> Option<&StreamState> { | ||||
|         self.streams(id).get_active(id) | ||||
|     } | ||||
|  | ||||
|     fn get_active_mut(&mut self, id: StreamId) -> Option<&mut StreamState>  { | ||||
|         self.streams_mut(id).get_active_mut(id) | ||||
|     } | ||||
|  | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.streams(id).get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.streams_mut(id).reset(id, cause); | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.streams_mut(id).local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.streams_mut(id).remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub type PingPayload = [u8; 8]; | ||||
|  | ||||
| pub trait ControlPing { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError>; | ||||
|     fn take_pong(&mut self) -> Option<PingPayload>; | ||||
| } | ||||
|  | ||||
| /// Create a full H2 transport from an I/O handle. | ||||
| /// | ||||
| /// This is called as the final step of the client handshake future. | ||||
| @@ -249,17 +187,20 @@ pub fn from_server_handshaker<T, P, B>(settings: Settings<FramedWrite<T, B::Buf> | ||||
|             .num_skip(0) // Don't skip the header | ||||
|             .new_read(io); | ||||
|  | ||||
|         StreamSend::new( | ||||
|         StreamSendOpen::new( | ||||
|             initial_remote_window_size, | ||||
|             remote_max_concurrency, | ||||
|             FlowControl::new( | ||||
|                 initial_local_window_size, | ||||
|                 initial_remote_window_size, | ||||
|                 StreamRecv::new( | ||||
|             StreamRecvClose::new( | ||||
|                 FlowControl::new( | ||||
|                     initial_local_window_size, | ||||
|                     local_max_concurrency, | ||||
|                     PingPong::new( | ||||
|                         FramedRead::new(framed))))) | ||||
|                     initial_remote_window_size, | ||||
|                     StreamSendClose::new( | ||||
|                         StreamRecvOpen::new( | ||||
|                             initial_local_window_size, | ||||
|                             local_max_concurrency, | ||||
|                             StreamStore::new( | ||||
|                                 PingPong::new( | ||||
|                                     FramedRead::new(framed)))))))) | ||||
|     }); | ||||
|  | ||||
|     connection::new(transport) | ||||
|   | ||||
| @@ -1,9 +1,16 @@ | ||||
| use ConnectionError; | ||||
| use {ConnectionError, StreamId}; | ||||
| use frame::{Frame, Ping, SettingSet}; | ||||
| use proto::{ApplySettings, ControlPing, PingPayload, ReadySink}; | ||||
| use proto::{ApplySettings, ReadySink, ControlStreams, FlowControlState}; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| pub type PingPayload = [u8; 8]; | ||||
|  | ||||
| pub trait ControlPing { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError>; | ||||
|     fn take_pong(&mut self) -> Option<PingPayload>; | ||||
| } | ||||
|  | ||||
| /// Acknowledges ping requests from the remote. | ||||
| #[derive(Debug)] | ||||
| pub struct PingPong<T, U> { | ||||
| @@ -29,16 +36,6 @@ impl<T, U> PingPong<T, U> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ApplySettings, U> ApplySettings for PingPong<T, U> { | ||||
|     fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> ControlPing for PingPong<T, U> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
| @@ -172,6 +169,16 @@ impl<T, U> ReadySink for PingPong<T, U> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ApplySettings, U> ApplySettings for PingPong<T, U> { | ||||
|     fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod test { | ||||
|     use super::*; | ||||
|   | ||||
| @@ -7,8 +7,21 @@ use bytes::BufMut; | ||||
|  | ||||
| use std::io; | ||||
|  | ||||
| /// Exposes settings to "upper" layers of the transport (i.e. from Settings up to---and | ||||
| /// above---Connection). | ||||
| pub trait ControlSettings { | ||||
|     fn update_local_settings(&mut self, set: frame::SettingSet) -> Result<(), ConnectionError>; | ||||
|     fn local_settings(&self) -> &SettingSet; | ||||
|     fn remote_settings(&self) -> &SettingSet; | ||||
| } | ||||
|  | ||||
| /// Allows settings updates to be pushed "down" the transport (i.e. from Settings down to | ||||
| /// FramedWrite). | ||||
| pub trait ApplySettings { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>; | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>; | ||||
| } | ||||
|  | ||||
| // TODO  | ||||
| #[derive(Debug)] | ||||
| pub struct Settings<T> { | ||||
|     // Upstream transport | ||||
| @@ -95,48 +108,6 @@ impl<T, U> Settings<T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for Settings<T> { | ||||
|    fn local_streams(&self) -> &StreamMap { | ||||
|         self.inner.local_streams() | ||||
|     } | ||||
|  | ||||
|     fn local_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         self.inner.local_streams_mut() | ||||
|     } | ||||
|  | ||||
|     fn remote_streams(&self) -> &StreamMap { | ||||
|         self.inner.local_streams() | ||||
|     } | ||||
|  | ||||
|     fn remote_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         self.inner.local_streams_mut() | ||||
|     } | ||||
|  | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlFlow> ControlFlow for Settings<T> { | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||
|         self.inner.poll_window_update() | ||||
|     } | ||||
|  | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> { | ||||
|         self.inner.expand_window(id, incr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for Settings<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> ControlSettings for Settings<T>{ | ||||
|     fn update_local_settings(&mut self, local: frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.local = local; | ||||
| @@ -244,3 +215,23 @@ impl<T: AsyncRead> AsyncRead for Settings<T> { | ||||
|         self.inner.prepare_uninitialized_buffer(buf) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlFlow> ControlFlow for Settings<T> { | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||
|         self.inner.poll_window_update() | ||||
|     } | ||||
|  | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> { | ||||
|         self.inner.expand_window(id, incr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for Settings<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -291,104 +291,3 @@ impl PeerState { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // TODO track reserved streams | ||||
| // TODO constrain the size of `reset` | ||||
| #[derive(Debug, Default)] | ||||
| pub struct StreamMap<P> { | ||||
|     /// Holds active streams initiated by the local endpoint. | ||||
|     local_active: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     /// Holds active streams initiated by the remote endpoint. | ||||
|     remote_active: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     /// Holds active streams initiated by the remote. | ||||
|     reset: OrderMap<StreamId, Reason, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     _phantom: PhantomData<P>, | ||||
| } | ||||
|  | ||||
| impl<P: Peer> StreamMap<P> { | ||||
|     pub fn active(&mut self, id: StreamId) -> Option<&StreamState> { | ||||
|         assert!(!id.is_zero()); | ||||
|         if P::is_valid_local_stream_id(id) { | ||||
|             self.local_active.get(id) | ||||
|         } else { | ||||
|             self.remote_active.get(id) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn active_mut(&mut self, id: StreamId) -> Option<&mut StreamState> { | ||||
|         assert!(!id.is_zero()); | ||||
|         if P::is_valid_local_stream_id(id) { | ||||
|             self.local_active.get_mut(id) | ||||
|         } else { | ||||
|             self.remote_active.get_mut(id) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn local_active(&self, id: StreamId) -> Option<&StreamState> { | ||||
|         self.local_active.get(&id) | ||||
|     } | ||||
|  | ||||
|     pub fn local_active_mut(&mut self, id: StreamId) -> Option<&mut StreamState> { | ||||
|         self.local_active.get_mut(&id) | ||||
|     } | ||||
|  | ||||
|     pub fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.get_active_mut(id).and_then(|s| s.local_flow_controller()) | ||||
|     } | ||||
|  | ||||
|     pub fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.get_active_mut(id).and_then(|s| s.remote_flow_controller()) | ||||
|     } | ||||
|  | ||||
|     pub fn localis_active(&mut self, id: StreamId) -> bool { | ||||
|         self.active.contains_key(&id) | ||||
|     } | ||||
|  | ||||
|     pub fn active_count(&self) -> usize { | ||||
|         self.active.len() | ||||
|     } | ||||
|  | ||||
|     pub fn reset(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.reset.insert(id, cause); | ||||
|         self.active.remove(&id); | ||||
|     } | ||||
|  | ||||
|     pub fn get_reset(&mut self, id: StreamId) -> Option<Reason> { | ||||
|         self.reset.get(&id).map(|r| *r) | ||||
|     } | ||||
|  | ||||
|     pub fn shrink_all_local_windows(&mut self, decr: u32) { | ||||
|         for (_, mut s) in &mut self.active { | ||||
|             if let Some(fc) = s.local_flow_controller() { | ||||
|                 fc.shrink_window(decr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn expand_all_local_windows(&mut self, incr: u32) { | ||||
|         for (_, mut s) in &mut self.active { | ||||
|             if let Some(fc) = s.local_flow_controller() { | ||||
|                 fc.expand_window(incr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn shrink_all_remote_windows(&mut self, decr: u32) { | ||||
|         for (_, mut s) in &mut self.active { | ||||
|             if let Some(fc) = s.remote_flow_controller() { | ||||
|                 fc.shrink_window(decr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn expand_all_remote_windows(&mut self, incr: u32) { | ||||
|         for (_, mut s) in &mut self.active { | ||||
|             if let Some(fc) = s.remote_flow_controller() { | ||||
|                 fc.expand_window(incr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,407 +0,0 @@ | ||||
| use ConnectionError; | ||||
| use client::Client; | ||||
| use error::Reason; | ||||
| use error::User; | ||||
| use frame::{self, Frame}; | ||||
| use proto::*; | ||||
| use server::Server; | ||||
|  | ||||
| use fnv::FnvHasher; | ||||
| use ordermap::OrderMap; | ||||
| use std::hash::BuildHasherDefault; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| // TODO track "last stream id" for GOAWAY. | ||||
| // TODO track/provide "next" stream id. | ||||
| // TODO reset_streams needs to be bounded. | ||||
| // TODO track reserved streams (PUSH_PROMISE). | ||||
|  | ||||
| /// Tracks a connection's streams. | ||||
| #[derive(Debug)] | ||||
| pub struct StreamRecv<T, P> { | ||||
|     inner: T, | ||||
|     peer: PhantomData<P>, | ||||
|  | ||||
|     local: StreamMap, | ||||
|     local_max_concurrency: Option<u32>, | ||||
|     local_initial_window_size: WindowSize, | ||||
|  | ||||
|     remote: StreamMap, | ||||
|     remote_max_concurrency: Option<u32>, | ||||
|     remote_initial_window_size: WindowSize, | ||||
|     remote_pending_refuse: Option<StreamId>, | ||||
| } | ||||
|  | ||||
| impl<T, P, U> StreamRecv<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer | ||||
| { | ||||
|     pub fn new(initial_window_size: WindowSize, | ||||
|                max_concurrency: Option<u32>, | ||||
|                inner: T) | ||||
|         -> StreamRecv<T, P> | ||||
|     { | ||||
|         StreamRecv { | ||||
|             inner, | ||||
|             peer: PhantomData, | ||||
|  | ||||
|             local: StreamMap::default(), | ||||
|             remote: StreamMap::default(), | ||||
|             max_concurrency, | ||||
|             initial_window_size, | ||||
|             remote_pending_refuse: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn try_open_remote(&mut self, frame: Frame) -> Result<(), ConnectionError> { | ||||
|         unimplemented!() | ||||
|     } | ||||
|  | ||||
|     pub fn try_close(&mut self, frame: Frame) -> Result<(), ConnectionError> { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> StreamRecv<T, P> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer | ||||
| { | ||||
|     fn send_refusal(&mut self, id: StreamId) -> Poll<(), ConnectionError> { | ||||
|         debug_assert!(self.remote_pending_refused.is_none()); | ||||
|  | ||||
|         let f = frame::Reset::new(id, Reason::RefusedStream); | ||||
|         match self.inner.start_send(f.into())? { | ||||
|             AsyncSink::Ready => { | ||||
|                 self.reset(id, Reason::RefusedStream); | ||||
|                 Ok(Async::Ready(())) | ||||
|             } | ||||
|             AsyncSink::NotReady(_) => { | ||||
|                 self.pending_refused = Some(id); | ||||
|                 Ok(Async::NotReady) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> ControlStreams for StreamRecv<T, P> | ||||
|     where P: Peer | ||||
| { | ||||
|    fn local_streams(&self) -> &StreamMap { | ||||
|         &self.local | ||||
|     } | ||||
|  | ||||
|     fn local_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         &mut self.local | ||||
|     } | ||||
|  | ||||
|     fn remote_streams(&self) -> &StreamMap { | ||||
|         &self.remote | ||||
|     } | ||||
|  | ||||
|     fn remote_streams_mut(&mut self) -> &mut StreamMap { | ||||
|         &mut self.remote | ||||
|     } | ||||
|  | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         P::is_valid_local_stream_id(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Handles updates to `SETTINGS_MAX_CONCURRENT_STREAMS`. | ||||
| /// | ||||
| /// > Indicates the maximum number of concurrent streams that the senderg will allow. This | ||||
| /// > limit is directional: it applies to the number of streams that the sender permits | ||||
| /// > the receiver to create. Initially, there is no limit to this value. It is | ||||
| /// > recommended that this value be no smaller than 100, so as to not unnecessarily limit | ||||
| /// > parallelism. | ||||
| /// > | ||||
| /// > A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by | ||||
| /// > endpoints. A zero value does prevent the creation of new streams; however, this can | ||||
| /// > also happen for any limit that is exhausted with active streams. Servers SHOULD only | ||||
| /// > set a zero value for short durations; if a server does not wish to accept requests, | ||||
| /// > closing the connection is more appropriate. | ||||
| /// | ||||
| /// > An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a | ||||
| /// > value that is below the current number of open streams can either close streams that | ||||
| /// > exceed the new value or allow streams to complete. | ||||
| /// | ||||
| /// This module does NOT close streams when the setting changes. | ||||
| impl<T, P> ApplySettings for StreamRecv<T, P> | ||||
|     where T: ApplySettings | ||||
| { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.max_concurrency = set.max_concurrent_streams(); | ||||
|         self.initial_window_size = set.initial_window_size(); | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> ControlPing for StreamRecv<T, P> | ||||
|     where T: ControlPing | ||||
| { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> Stream for StreamRecv<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer, | ||||
| { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         // Since there's only one slot for pending refused streams, it must be cleared | ||||
|         // before polling  a frame from the transport. | ||||
|         if let Some(id) = self.pending_refused.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         loop { | ||||
|             match try_ready!(self.inner.poll()) { | ||||
|                 Some(Headers(v)) => { | ||||
|                     let id = v.stream_id(); | ||||
|                     let eos = v.is_end_stream(); | ||||
|  | ||||
|                     if self.get_reset(id).is_some() { | ||||
|                         // TODO send the remote errors when it sends us frames on reset | ||||
|                         // streams. | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     if let Some(mut s) = self.get_active_mut(id) { | ||||
|                         let created = s.recv_headers(eos, self.initial_window_size)?; | ||||
|                         assert!(!created); | ||||
|                         return Ok(Async::Ready(Some(Headers(v)))); | ||||
|                     } | ||||
|  | ||||
|                     // Ensure that receiving this frame will not violate the local max | ||||
|                     // stream concurrency setting. Ensure that the stream is refused | ||||
|                     // before processing additional frames. | ||||
|                     if let Some(max) = self.max_concurrency { | ||||
|                         let max = max as usize; | ||||
|                         if !self.local.is_active(id) && self.local.active_count() >= max - 1 { | ||||
|                             // This frame would violate our local max concurrency, so reject | ||||
|                             // the stream. | ||||
|                             try_ready!(self.send_refusal(id)); | ||||
|  | ||||
|                             // Try to process another frame (hopefully for an active | ||||
|                             // stream). | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     let is_closed = { | ||||
|                         let stream = self.active_streams.entry(id) | ||||
|                             .or_insert_with(|| StreamState::default()); | ||||
|  | ||||
|                         let initialized = | ||||
|                             stream.recv_headers(eos, self.initial_window_size)?; | ||||
|  | ||||
|                         if initialized { | ||||
|                             if !P::is_valid_remote_stream_id(id) { | ||||
|                                 return Err(Reason::ProtocolError.into()); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         stream.is_closed() | ||||
|                     }; | ||||
|  | ||||
|                     if is_closed { | ||||
|                         self.active_streams.remove(id); | ||||
|                         self.reset_streams.insert(id, Reason::NoError); | ||||
|                     } | ||||
|  | ||||
|                     return Ok(Async::Ready(Some(Headers(v)))); | ||||
|                 } | ||||
|  | ||||
|                 Some(Data(v)) => { | ||||
|                     let id = v.stream_id(); | ||||
|  | ||||
|                     if self.get_reset(id).is_some() { | ||||
|                         // TODO send the remote errors when it sends us frames on reset | ||||
|                         // streams. | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     let is_closed = { | ||||
|                         let stream = match self.active_streams.get_mut(id) { | ||||
|                             None => return Err(Reason::ProtocolError.into()), | ||||
|                             Some(s) => s, | ||||
|                         }; | ||||
|                         stream.recv_data(v.is_end_stream())?; | ||||
|                         stream.is_closed() | ||||
|                     }; | ||||
|  | ||||
|                     if is_closed { | ||||
|                         self.reset(id, Reason::NoError); | ||||
|                     } | ||||
|  | ||||
|                     return Ok(Async::Ready(Some(Data(v)))); | ||||
|                 } | ||||
|  | ||||
|                 Some(Reset(v)) => { | ||||
|                     // Set or update the reset reason. | ||||
|                     self.reset(v.stream_id(), v.reason()); | ||||
|                     return Ok(Async::Ready(Some(Reset(v)))); | ||||
|                 } | ||||
|  | ||||
|                 Some(f) => { | ||||
|                     let id = f.stream_id(); | ||||
|  | ||||
|                     if self.get_reset(id).is_some() { | ||||
|                         // TODO send the remote errors when it sends us frames on reset | ||||
|                         // streams. | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     return Ok(Async::Ready(Some(f))); | ||||
|                 } | ||||
|  | ||||
|                 None => { | ||||
|                     return Ok(Async::Ready(None)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> Sink for StreamRecv<T, P> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer, | ||||
| { | ||||
|     type SinkItem = T::SinkItem; | ||||
|     type SinkError = T::SinkError; | ||||
|  | ||||
|     fn start_send(&mut self, frame: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         // Must be enforced through higher levels. | ||||
|         debug_assert!(self.stream_is_reset(item.stream_id()).is_none()); | ||||
|  | ||||
|         // The local must complete refusing the remote stream before sending any other | ||||
|         // frames. | ||||
|         if let Some(id) = self.pending_refused.take() { | ||||
|             if self.send_refusal(id)?.is_not_ready() { | ||||
|                 return Ok(AsyncSink::NotReady(item)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         match frame { | ||||
|             Headers(v) => { | ||||
|                 let id = v.stream_id(); | ||||
|                 let eos = v.is_end_stream(); | ||||
|  | ||||
|                 // Transition the stream state, creating a new entry if needed | ||||
|                 // | ||||
|                 // TODO: Response can send multiple headers frames before body (1xx | ||||
|                 // responses). | ||||
|                 // | ||||
|                 // ACTUALLY(ver), maybe not? | ||||
|                 //   https://github.com/http2/http2-spec/commit/c83c8d911e6b6226269877e446a5cad8db921784 | ||||
|  | ||||
|                 // Ensure that sending this frame would not violate the remote's max | ||||
|                 // stream concurrency setting. | ||||
|                 if let Some(max) = self.remote_max_concurrency { | ||||
|                     let max = max as usize; | ||||
|                     if !self.active_streams.has_stream(id) | ||||
|                     && self.active_streams.len() >= max - 1 { | ||||
|                         // This frame would violate our local max concurrency, so reject | ||||
|                         // the stream. | ||||
|                         if self.send_refusal(id)?.is_not_ready() { | ||||
|                             return Ok(AsyncSink::NotReady(Headers(v))); | ||||
|                         } | ||||
|  | ||||
|                         // Try to process another frame (hopefully for an active | ||||
|                         // stream). | ||||
|                         return Err(User::MaxConcurrencyExceeded.into()) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 let is_closed = { | ||||
|                     let stream = self.active_streams.entry(id) | ||||
|                         .or_insert_with(|| StreamState::default()); | ||||
|  | ||||
|                     let initialized = | ||||
|                         stream.send_headers::<P>(eos, self.initial_remote_window_size)?; | ||||
|  | ||||
|                     if initialized { | ||||
|                         // TODO: Ensure available capacity for a new stream | ||||
|                         // This won't be as simple as self.streams.len() as closed | ||||
|                         // connections should not be factored. | ||||
|                         if !P::is_valid_local_stream_id(id) { | ||||
|                             // TODO: clear state | ||||
|                             return Err(User::InvalidStreamId.into()); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     stream.is_closed() | ||||
|                 }; | ||||
|  | ||||
|                 if is_closed { | ||||
|                     self.active_streams.remove(id); | ||||
|                     self.reset_streams.insert(id, Reason::NoError); | ||||
|                 } | ||||
|  | ||||
|                 self.inner.start_send(Headers(v)) | ||||
|             } | ||||
|  | ||||
|             Data(v) => { | ||||
|                 match self.active_streams.get_mut(v.stream_id()) { | ||||
|                     None => return Err(User::InactiveStreamId.into()), | ||||
|                     Some(stream) => { | ||||
|                         stream.send_data(v.is_end_stream())?; | ||||
|                         self.inner.start_send(Data(v)) | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Reset(v) => { | ||||
|                 let id = v.stream_id(); | ||||
|                 self.active_streams.remove(id); | ||||
|                 self.reset_streams.insert(id, v.reason()); | ||||
|                 self.inner.start_send(Reset(v)) | ||||
|             } | ||||
|  | ||||
|             frame => self.inner.start_send(frame), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||
|         if let Some(id) = self.pending_refused.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<T, P, U> ReadySink for StreamRecv<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
|           P: Peer, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         if let Some(id) = self.pending_refused.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										157
									
								
								src/proto/stream_recv_close.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/proto/stream_recv_close.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| use {ConnectionError}; | ||||
| use error::Reason; | ||||
| use error::User; | ||||
| use frame::{self, Frame}; | ||||
| use proto::*; | ||||
| use proto::ready::ReadySink; | ||||
|  | ||||
| use fnv::FnvHasher; | ||||
| use futures::*; | ||||
| use ordermap::OrderMap; | ||||
| use std::hash::BuildHasherDefault; | ||||
|  | ||||
| // TODO track "last stream id" for GOAWAY. | ||||
| // TODO track/provide "next" stream id. | ||||
| // TODO reset_streams needs to be bounded. | ||||
| // TODO track reserved streams (PUSH_PROMISE). | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct StreamRecvClose<T> { | ||||
|     inner: T, | ||||
| } | ||||
|  | ||||
| impl<T, U> StreamRecvClose<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     pub fn new(inner: T) -> StreamRecvClose<T> { | ||||
|         StreamRecvClose { inner } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Stream for StreamRecvClose<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         let frame = try_ready!(self.inner.poll()); | ||||
|  | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> Sink for StreamRecvClose<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type SinkItem = Frame<U>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Frame<U>, ConnectionError> { | ||||
|         self.inner.start_send(item) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> ReadySink for StreamRecvClose<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for StreamRecvClose<T> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         T::is_valid_remote_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         T::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.inner.get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.inner.reset_stream(id, cause) | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_local_active(id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_remote_active(id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.inner.local_active_len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.inner.remote_active_len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.local_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.remote_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ApplySettings> ApplySettings for StreamRecvClose<T> { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlFlow> ControlFlow for StreamRecvClose<T> { | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||
|         self.inner.poll_window_update() | ||||
|     } | ||||
|  | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> { | ||||
|         self.inner.expand_window(id, incr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for StreamRecvClose<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										352
									
								
								src/proto/stream_recv_open.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								src/proto/stream_recv_open.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,352 @@ | ||||
| use ConnectionError; | ||||
| use frame::{Frame, StreamId}; | ||||
| use proto::*; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| /// Tracks a connection's streams. | ||||
| #[derive(Debug)] | ||||
| pub struct StreamRecvOpen<T> { | ||||
|     inner: T, | ||||
|     max_concurrency: Option<u32>, | ||||
|     initial_window_size: WindowSize, | ||||
|     pending_refuse: Option<StreamId>, | ||||
| } | ||||
|  | ||||
| impl<T> StreamRecvOpen<T> { | ||||
|  | ||||
|     pub fn new<U>(initial_window_size: WindowSize, | ||||
|                   max_concurrency: Option<u32>, | ||||
|                   inner: T) | ||||
|             -> StreamRecvOpen<T> | ||||
|         where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|             T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|             T: ControlStreams, | ||||
|     { | ||||
|         StreamRecvOpen { | ||||
|             inner, | ||||
|             max_concurrency, | ||||
|             initial_window_size, | ||||
|             pending_refuse: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| impl<T, U> StreamRecvOpen<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     fn send_refusal(&mut self, id: StreamId) -> Poll<(), ConnectionError> { | ||||
|         debug_assert!(self.pending_refuse.is_none()); | ||||
|  | ||||
|         let f = frame::Reset::new(id, Reason::RefusedStream); | ||||
|         match self.inner.start_send(f.into())? { | ||||
|             AsyncSink::Ready => { | ||||
|                 self.inner.reset_stream(id, Reason::RefusedStream); | ||||
|                 Ok(Async::Ready(())) | ||||
|             } | ||||
|             AsyncSink::NotReady(_) => { | ||||
|                 self.pending_refuse = Some(id); | ||||
|                 Ok(Async::NotReady) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Handles updates to `SETTINGS_MAX_CONCURRENT_STREAMS`. | ||||
| /// | ||||
| /// > Indicates the maximum number of concurrent streams that the senderg will allow. This | ||||
| /// > limit is directional: it applies to the number of streams that the sender permits | ||||
| /// > the receiver to create. Initially, there is no limit to this value. It is | ||||
| /// > recommended that this value be no smaller than 100, so as to not unnecessarily limit | ||||
| /// > parallelism. | ||||
| /// > | ||||
| /// > A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by | ||||
| /// > endpoints. A zero value does prevent the creation of new streams; however, this can | ||||
| /// > also happen for any limit that is exhausted with active streams. Servers SHOULD only | ||||
| /// > set a zero value for short durations; if a server does not wish to accept requests, | ||||
| /// > closing the connection is more appropriate. | ||||
| /// | ||||
| /// > An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a | ||||
| /// > value that is below the current number of open streams can either close streams that | ||||
| /// > exceed the new value or allow streams to complete. | ||||
| /// | ||||
| /// This module does NOT close streams when the setting changes. | ||||
| impl<T> ApplySettings for StreamRecvOpen<T> | ||||
|     where T: ApplySettings | ||||
| { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.max_concurrency = set.max_concurrent_streams(); | ||||
|         self.initial_window_size = set.initial_window_size(); | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> Stream for StreamRecvOpen<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         // Since there's only one slot for pending refused streams, it must be cleared | ||||
|         // before polling  a frame from the transport. | ||||
|         if let Some(id) = self.pending_refuse.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         loop { | ||||
|             let frame = match try_ready!(self.inner.poll()) { | ||||
|                 None => return Ok(Async::Ready(None)), | ||||
|                 Some(f) => f, | ||||
|             }; | ||||
|  | ||||
|             let id = frame.stream_id(); | ||||
|             if id.is_zero() { | ||||
|                 return Ok(Async::Ready(Some(frame))); | ||||
|             } | ||||
|  | ||||
|             if self.inner.get_reset(id).is_some() { | ||||
|                 // For now, just ignore frames on reset streams. | ||||
|                 // TODO tell the remote to knock it off? | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if T::is_valid_remote_id(id) { | ||||
|                 unimplemented!() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> Sink for StreamRecvOpen<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type SinkItem = T::SinkItem; | ||||
|     type SinkError = T::SinkError; | ||||
|  | ||||
|     fn start_send(&mut self, frame: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         // The local must complete refusing the remote stream before sending any other | ||||
|         // frames. | ||||
|         if let Some(id) = self.pending_refuse.take() { | ||||
|             if self.send_refusal(id)?.is_not_ready() { | ||||
|                 return Ok(AsyncSink::NotReady(frame)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         let id = frame.stream_id(); | ||||
|         if !id.is_zero() { | ||||
|             // enforced by StreamSend. | ||||
|             debug_assert!(self.inner.get_reset(id).is_none()); | ||||
|  | ||||
|             let eos = frame.is_end_stream(); | ||||
|         } | ||||
|  | ||||
|         self.inner.start_send(frame) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||
|         if let Some(id) = self.pending_refuse.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<T, U> ReadySink for StreamRecvOpen<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         if let Some(id) = self.pending_refuse.take() { | ||||
|             try_ready!(self.send_refusal(id)); | ||||
|         } | ||||
|  | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
|     // Some(Headers(v)) => { | ||||
|     //     let id = v.stream_id(); | ||||
|     //     let eos = v.is_end_stream(); | ||||
|  | ||||
|     //     if self.get_reset(id).is_some() { | ||||
|     //         // TODO send the remote errors when it sends us frames on reset | ||||
|     //         // streams. | ||||
|     //         continue; | ||||
|     //     } | ||||
|  | ||||
|     //     if let Some(mut s) = self.get_active_mut(id) { | ||||
|     //         let created = s.recv_headers(eos, self.initial_window_size)?; | ||||
|     //         assert!(!created); | ||||
|     //         return Ok(Async::Ready(Some(Headers(v)))); | ||||
|     //     } | ||||
|  | ||||
|     //     // Ensure that receiving this frame will not violate the local max | ||||
|     //     // stream concurrency setting. Ensure that the stream is refused | ||||
|     //     // before processing additional frames. | ||||
|     //     if let Some(max) = self.max_concurrency { | ||||
|     //         let max = max as usize; | ||||
|     //         if !self.local.is_active(id) && self.local.active_count() >= max - 1 { | ||||
|     //             // This frame would violate our local max concurrency, so reject | ||||
|     //             // the stream. | ||||
|     //             try_ready!(self.send_refusal(id)); | ||||
|  | ||||
|     //             // Try to process another frame (hopefully for an active | ||||
|     //             // stream). | ||||
|     //             continue; | ||||
|     //         } | ||||
|     //     } | ||||
|  | ||||
|     //     let is_closed = { | ||||
|     //         let stream = self.active_streams.entry(id) | ||||
|     //             .or_insert_with(|| StreamState::default()); | ||||
|  | ||||
|     //         let initialized = | ||||
|     //             stream.recv_headers(eos, self.initial_window_size)?; | ||||
|  | ||||
|     //         if initialized { | ||||
|     //             if !P::is_valid_remote_stream_id(id) { | ||||
|     //                 return Err(Reason::ProtocolError.into()); | ||||
|     //             } | ||||
|     //         } | ||||
|  | ||||
|     //         stream.is_closed() | ||||
|     //     }; | ||||
|  | ||||
|     //     if is_closed { | ||||
|     //         self.active_streams.remove(id); | ||||
|     //         self.reset_streams.insert(id, Reason::NoError); | ||||
|     //     } | ||||
|  | ||||
|     //     return Ok(Async::Ready(Some(Headers(v)))); | ||||
|     // } | ||||
|  | ||||
|     // Some(Data(v)) => { | ||||
|     //     let id = v.stream_id(); | ||||
|  | ||||
|     //     if self.get_reset(id).is_some() { | ||||
|     //         // TODO send the remote errors when it sends us frames on reset | ||||
|     //         // streams. | ||||
|     //         continue; | ||||
|     //     } | ||||
|  | ||||
|     //     let is_closed = { | ||||
|     //         let stream = match self.active_streams.get_mut(id) { | ||||
|     //             None => return Err(Reason::ProtocolError.into()), | ||||
|     //             Some(s) => s, | ||||
|     //         }; | ||||
|     //         stream.recv_data(v.is_end_stream())?; | ||||
|     //         stream.is_closed() | ||||
|     //     }; | ||||
|  | ||||
|     //     if is_closed { | ||||
|     //         self.reset(id, Reason::NoError); | ||||
|     //     } | ||||
|  | ||||
|     //     return Ok(Async::Ready(Some(Data(v)))); | ||||
|     // } | ||||
|  | ||||
|     // Some(Reset(v)) => { | ||||
|     //     // Set or update the reset reason. | ||||
|     //     self.reset(v.stream_id(), v.reason()); | ||||
|     //     return Ok(Async::Ready(Some(Reset(v)))); | ||||
|     // } | ||||
|  | ||||
|     // Some(f) => { | ||||
|     //     let id = f.stream_id(); | ||||
|  | ||||
|     //     if self.get_reset(id).is_some() { | ||||
|     //         // TODO send the remote errors when it sends us frames on reset | ||||
|     //         // streams. | ||||
|     //         continue; | ||||
|     //     } | ||||
|  | ||||
|     //     return Ok(Async::Ready(Some(f))); | ||||
|     // } | ||||
|  | ||||
|     // None => { | ||||
|     //     return Ok(Async::Ready(None)); | ||||
|     // } | ||||
|  | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         T::is_valid_remote_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         T::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.inner.get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.inner.reset_stream(id, cause) | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_local_active(id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_remote_active(id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.inner.local_active_len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.inner.remote_active_len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.local_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.remote_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for StreamRecvOpen<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
| @@ -1,217 +0,0 @@ | ||||
| use {ConnectionError}; | ||||
| use error::Reason; | ||||
| use error::User; | ||||
| use frame::{self, Frame}; | ||||
| use proto::*; | ||||
|  | ||||
| use fnv::FnvHasher; | ||||
| use ordermap::OrderMap; | ||||
| use std::hash::BuildHasherDefault; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| // TODO track "last stream id" for GOAWAY. | ||||
| // TODO track/provide "next" stream id. | ||||
| // TODO reset_streams needs to be bounded. | ||||
| // TODO track reserved streams (PUSH_PROMISE). | ||||
|  | ||||
| /// Tracks a connection's streams. | ||||
| #[derive(Debug)] | ||||
| pub struct StreamSend<T, P> { | ||||
|     inner: T, | ||||
|     peer: PhantomData<P>, | ||||
|     max_concurrency: Option<u32>, | ||||
|     initial_window_size: WindowSize, | ||||
| } | ||||
|  | ||||
| impl<T, P, U> StreamSend<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer | ||||
| { | ||||
|     pub fn new(initial_window_size: WindowSize, | ||||
|                max_concurrency: Option<u32>, | ||||
|                inner: T) | ||||
|         -> StreamSend<T, P> | ||||
|     { | ||||
|         StreamSend { | ||||
|             inner, | ||||
|             peer: PhantomData, | ||||
|             max_concurrency, | ||||
|             initial_window_size, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn try_open_local(&mut self, frame: Frame) -> Result<(), ConnectionError> { | ||||
|         unimplemented!() | ||||
|     } | ||||
|  | ||||
|     pub fn try_close(&mut self, frame: Frame) -> Result<(), ConnectionError> { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Handles updates to `SETTINGS_MAX_CONCURRENT_STREAMS`. | ||||
| /// | ||||
| /// > Indicates the maximum number of concurrent streams that the senderg will allow. This | ||||
| /// > limit is directional: it applies to the number of streams that the sender permits | ||||
| /// > the receiver to create. Initially, there is no limit to this value. It is | ||||
| /// > recommended that this value be no smaller than 100, so as to not unnecessarily limit | ||||
| /// > parallelism. | ||||
| /// > | ||||
| /// > A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by | ||||
| /// > endpoints. A zero value does prevent the creation of new streams; however, this can | ||||
| /// > also happen for any limit that is exhausted with active streams. Servers SHOULD only | ||||
| /// > set a zero value for short durations; if a server does not wish to accept requests, | ||||
| /// > closing the connection is more appropriate. | ||||
| /// | ||||
| /// > An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a | ||||
| /// > value that is below the current number of open streams can either close streams that | ||||
| /// > exceed the new value or allow streams to complete. | ||||
| /// | ||||
| /// This module does NOT close streams when the setting changes. | ||||
| impl<T, P> ApplySettings for StreamSend<T, P> | ||||
|     where T: ApplySettings | ||||
| { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.max_concurrency = set.max_concurrent_streams(); | ||||
|         self.initial_window_size = set.initial_window_size(); | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> ControlPing for StreamSend<T, P> | ||||
|     where T: ControlPing | ||||
| { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> Stream for StreamSend<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
|           P: Peer, | ||||
| { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> Sink for StreamSend<T, P> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
|           P: Peer, | ||||
| { | ||||
|     type SinkItem = T::SinkItem; | ||||
|     type SinkError = T::SinkError; | ||||
|  | ||||
|     fn start_send(&mut self, item: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         // Must be enforced through higher levels. | ||||
|         if let Some(rst) = self.inner.get_reset(item.stream_id()) { | ||||
|             return Err(User::StreamReset(rst).into()); | ||||
|         } | ||||
|  | ||||
|         match item { | ||||
|             Headers(v) => { | ||||
|                 let id = v.stream_id(); | ||||
|                 let eos = v.is_end_stream(); | ||||
|  | ||||
|                 // Transition the stream state, creating a new entry if needed | ||||
|                 // | ||||
|                 // TODO: Response can send multiple headers frames before body (1xx | ||||
|                 // responses). | ||||
|                 // | ||||
|                 // ACTUALLY(ver), maybe not? | ||||
|                 //   https://github.com/http2/http2-spec/commit/c83c8d911e6b6226269877e446a5cad8db921784 | ||||
|  | ||||
|                 // Ensure that sending this frame would not violate the remote's max | ||||
|                 // stream concurrency setting. | ||||
|                 if let Some(max) = self.max_concurrency { | ||||
|                     let max = max as usize; | ||||
|                     let streams = self.inner.streams(); | ||||
|                     if !streams.is_active(id) && streams.active_count() >= max - 1 { | ||||
|                         return Err(User::MaxConcurrencyExceeded.into()) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 let is_closed = { | ||||
|                     let stream = self.active_streams.entry(id) | ||||
|                         .or_insert_with(|| StreamState::default()); | ||||
|  | ||||
|                     let initialized = | ||||
|                         stream.send_headers::<P>(eos, self.initial_window_size)?; | ||||
|  | ||||
|                     if initialized { | ||||
|                         // TODO: Ensure available capacity for a new stream | ||||
|                         // This won't be as simple as self.streams.len() as closed | ||||
|                         // connections should not be factored. | ||||
|                         if !P::is_valid_local_stream_id(id) { | ||||
|                             // TODO: clear state | ||||
|                             return Err(User::InvalidStreamId.into()); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     stream.is_closed() | ||||
|                 }; | ||||
|  | ||||
|                 if is_closed { | ||||
|                     self.active_streams.remove(id); | ||||
|                     self.reset_streams.insert(id, Reason::NoError); | ||||
|                 } | ||||
|  | ||||
|                 self.inner.start_send(Headers(v)) | ||||
|             } | ||||
|  | ||||
|             Data(v) => { | ||||
|                 match self.active_streams.get_mut(v.stream_id()) { | ||||
|                     None => return Err(User::InactiveStreamId.into()), | ||||
|                     Some(stream) => { | ||||
|                         stream.send_data(v.is_end_stream())?; | ||||
|                         self.inner.start_send(Data(v)) | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Reset(v) => { | ||||
|                 let id = v.stream_id(); | ||||
|                 self.active_streams.remove(id); | ||||
|                 self.reset_streams.insert(id, v.reason()); | ||||
|                 self.inner.start_send(Reset(v)) | ||||
|             } | ||||
|  | ||||
|             frame => self.inner.start_send(frame), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> ReadySink for StreamSend<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
|           T: ReadySink, | ||||
|           P: Peer, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										141
									
								
								src/proto/stream_send_close.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/proto/stream_send_close.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| use ConnectionError; | ||||
| use client::Client; | ||||
| use error::Reason; | ||||
| use error::User; | ||||
| use frame::{self, Frame}; | ||||
| use proto::*; | ||||
|  | ||||
| use futures::*; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| // TODO track "last stream id" for GOAWAY. | ||||
| // TODO track/provide "next" stream id. | ||||
| // TODO reset_streams needs to be bounded. | ||||
| // TODO track reserved streams (PUSH_PROMISE). | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct StreamSendClose<T> { | ||||
|     inner: T, | ||||
| } | ||||
|  | ||||
| impl<T, U> StreamSendClose<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     pub fn new(inner: T) -> StreamSendClose<T> { | ||||
|         StreamSendClose { inner } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Stream for StreamSendClose<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Frame>, ConnectionError> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> Sink for StreamSendClose<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type SinkItem = Frame<U>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Frame<U>, ConnectionError> { | ||||
|         self.inner.start_send(item) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> ReadySink for StreamSendClose<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ApplySettings> ApplySettings for StreamSendClose<T> { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for StreamSendClose<T> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         T::is_valid_remote_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         T::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.inner.get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.inner.reset_stream(id, cause) | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_local_active(id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_remote_active(id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.inner.local_active_len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.inner.remote_active_len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.local_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.remote_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for StreamSendClose<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										224
									
								
								src/proto/stream_send_open.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/proto/stream_send_open.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| use ConnectionError; | ||||
| use error::User::{InvalidStreamId, StreamReset}; | ||||
| use frame::{Frame, SettingSet}; | ||||
| use proto::*; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct StreamSendOpen<T> { | ||||
|     inner: T, | ||||
|  | ||||
|     max_concurrency: Option<u32>, | ||||
|     initial_window_size: WindowSize, | ||||
| } | ||||
|  | ||||
| impl<T, U> StreamSendOpen<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     pub fn new(initial_window_size: WindowSize, | ||||
|                max_concurrency: Option<u32>, | ||||
|                inner: T) | ||||
|             -> StreamSendOpen<T> | ||||
|     { | ||||
|         StreamSendOpen { | ||||
|             inner, | ||||
|             max_concurrency, | ||||
|             initial_window_size, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Handles updates to `SETTINGS_MAX_CONCURRENT_STREAMS`. | ||||
| /// | ||||
| /// > Indicates the maximum number of concurrent streams that the senderg will allow. This | ||||
| /// > limit is directional: it applies to the number of streams that the sender permits | ||||
| /// > the receiver to create. Initially, there is no limit to this value. It is | ||||
| /// > recommended that this value be no smaller than 100, so as to not unnecessarily limit | ||||
| /// > parallelism. | ||||
| /// > | ||||
| /// > A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by | ||||
| /// > endpoints. A zero value does prevent the creation of new streams; however, this can | ||||
| /// > also happen for any limit that is exhausted with active streams. Servers SHOULD only | ||||
| /// > set a zero value for short durations; if a server does not wish to accept requests, | ||||
| /// > closing the connection is more appropriate. | ||||
| /// | ||||
| /// > An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a | ||||
| /// > value that is below the current number of open streams can either close streams that | ||||
| /// > exceed the new value or allow streams to complete. | ||||
| /// | ||||
| /// This module does NOT close streams when the setting changes. | ||||
| impl<T: ApplySettings> ApplySettings for StreamSendOpen<T> { | ||||
|     fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.max_concurrency = set.max_concurrent_streams(); | ||||
|         self.initial_window_size = set.initial_window_size(); | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> Stream for StreamSendOpen<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Frame>, ConnectionError> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> Sink for StreamSendOpen<T> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
| { | ||||
|     type SinkItem = T::SinkItem; | ||||
|     type SinkError = T::SinkError; | ||||
|  | ||||
|     fn start_send(&mut self, frame: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         use frame::Frame::*; | ||||
|  | ||||
|         let id = frame.stream_id(); | ||||
|         if id.is_zero() { | ||||
|             // Nothing to do on connection frames. | ||||
|             return self.inner.start_send(frame); | ||||
|         } | ||||
|  | ||||
|         // Reset the stream immediately and send the Reset on the underlying transport. | ||||
|         if let Reset(rst) = frame { | ||||
|             self.inner.reset_stream(id, rst.reason()); | ||||
|             return self.inner.start_send(Reset(rst)); | ||||
|         } | ||||
|  | ||||
|         // Ensure that the stream hasn't been closed otherwise. | ||||
|         if let Some(reason) = self.inner.get_reset(id) { | ||||
|             return Err(StreamReset(reason).into()) | ||||
|         } | ||||
|  | ||||
|         if T::is_valid_local_id(id) { | ||||
|             if self.inner.is_local_active(id) { | ||||
|                 // If the frame ends thestream, it will be handled in stream_recv. | ||||
|                 return self.inner.start_send(frame); | ||||
|             } | ||||
|  | ||||
|             if T::can_create_local_stream() { | ||||
|                 let has_capacity = match self.max_concurrency { | ||||
|                     None => true, | ||||
|                     Some(max) => self.inner.local_active_len() < (max as usize), | ||||
|                 }; | ||||
|                 if has_capacity { | ||||
|                     // create that shit. | ||||
|                     unimplemented!(); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             if self.inner.is_remote_active(id) { | ||||
|                 // If the frame was part of a remote stream, it MUST already exist. If the | ||||
|                 // frame ends thestream, it will be handled in stream_recv. | ||||
|                 return self.inner.start_send(frame); | ||||
|             } | ||||
|  | ||||
|             if let Reset(rst) = frame { | ||||
|                 return self.inner.start_send(Reset(rst)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Tried to send a frame on a stream | ||||
|         return Err(InvalidStreamId.into()); | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, U> ReadySink for StreamSendOpen<T> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ControlStreams, | ||||
|           T: ReadySink, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlStreams> ControlStreams for StreamSendOpen<T> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         T::is_valid_local_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         T::is_valid_remote_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         T::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.inner.get_reset(id) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         self.inner.reset_stream(id, cause) | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_local_active(id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.inner.is_remote_active(id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.inner.local_active_len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.inner.remote_active_len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.local_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         self.inner.remote_update_inital_window_size(old_sz, new_sz) | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.local_flow_controller(id) | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         self.inner.remote_flow_controller(id) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlFlow> ControlFlow for StreamSendOpen<T> { | ||||
|     fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||
|         self.inner.poll_window_update() | ||||
|     } | ||||
|  | ||||
|     fn expand_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> { | ||||
|         self.inner.expand_window(id, incr) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ControlPing> ControlPing for StreamSendOpen<T> { | ||||
|     fn start_ping(&mut self, body: PingPayload) -> StartSend<PingPayload, ConnectionError> { | ||||
|         self.inner.start_ping(body) | ||||
|     } | ||||
|  | ||||
|     fn take_pong(&mut self) -> Option<PingPayload> { | ||||
|         self.inner.take_pong() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										250
									
								
								src/proto/stream_store.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								src/proto/stream_store.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,250 @@ | ||||
| use {ConnectionError, Peer, StreamId}; | ||||
| use error::Reason; | ||||
| use proto::*; | ||||
|  | ||||
| use fnv::FnvHasher; | ||||
| use ordermap::OrderMap; | ||||
| use std::hash::BuildHasherDefault; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| /// Exposes stream states to "upper" layers of the transport (i.e. from StreamTracker up | ||||
| /// to Connection). | ||||
| pub trait ControlStreams { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool; | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool; | ||||
|  | ||||
|     fn can_create_local_stream() -> bool; | ||||
|     fn can_create_remote_stream() -> bool { | ||||
|         !Self::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason>; | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason); | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool; | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool; | ||||
|  | ||||
|     fn local_active_len(&self) -> usize; | ||||
|     fn remote_active_len(&self) -> usize; | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState>; | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState>; | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); | ||||
|  | ||||
|     // fn get_active(&self, id: StreamId) -> Option<&StreamState> { | ||||
|     //     self.streams(id).get_active(id) | ||||
|     // } | ||||
|  | ||||
|     // fn get_active_mut(&mut self, id: StreamId) -> Option<&mut StreamState>  { | ||||
|     //     self.streams_mut(id).get_active_mut(id) | ||||
|     // } | ||||
| } | ||||
|  | ||||
| /// Holds the underlying stream state to be accessed by upper layers. | ||||
| // TODO track reserved streams | ||||
| // TODO constrain the size of `reset` | ||||
| #[derive(Debug, Default)] | ||||
| pub struct StreamStore<T, P> { | ||||
|     inner: T, | ||||
|  | ||||
|     /// Holds active streams initiated by the local endpoint. | ||||
|     local_active: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     /// Holds active streams initiated by the remote endpoint. | ||||
|     remote_active: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     /// Holds active streams initiated by the remote. | ||||
|     reset: OrderMap<StreamId, Reason, BuildHasherDefault<FnvHasher>>, | ||||
|  | ||||
|     _phantom: PhantomData<P>, | ||||
| } | ||||
|  | ||||
| impl<T, P, U> StreamStore<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
|           T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           P: Peer, | ||||
| { | ||||
|     pub fn new(inner: T) -> StreamStore<T, P> { | ||||
|         StreamStore { | ||||
|             inner, | ||||
|             local_active: OrderMap::default(), | ||||
|             remote_active: OrderMap::default(), | ||||
|             reset: OrderMap::default(), | ||||
|             _phantom: PhantomData, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P> Stream for StreamStore<T, P> | ||||
|     where T: Stream<Item = Frame, Error = ConnectionError>, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ConnectionError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Frame>, ConnectionError> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> Sink for StreamStore<T, P> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
| { | ||||
|     type SinkItem = Frame<U>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Frame<U>, ConnectionError> { | ||||
|         self.inner.start_send(item) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P, U> ReadySink for StreamStore<T, P> | ||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||
|           T: ReadySink, | ||||
| { | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, P: Peer> ControlStreams for StreamStore<T, P> { | ||||
|     fn is_valid_local_id(id: StreamId) -> bool { | ||||
|         P::is_valid_local_stream_id(id) | ||||
|     } | ||||
|  | ||||
|     fn is_valid_remote_id(id: StreamId) -> bool { | ||||
|         P::is_valid_remote_stream_id(id) | ||||
|     } | ||||
|  | ||||
|     fn can_create_local_stream() -> bool { | ||||
|         P::can_create_local_stream() | ||||
|     } | ||||
|  | ||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||
|         self.reset.get(&id).map(|r| *r) | ||||
|     } | ||||
|  | ||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||
|         if P::is_valid_local_stream_id(id) { | ||||
|             self.local_active.remove(&id); | ||||
|         } else { | ||||
|             self.remote_active.remove(&id); | ||||
|         } | ||||
|         self.reset.insert(id, cause); | ||||
|     } | ||||
|  | ||||
|     fn is_local_active(&self, id: StreamId) -> bool { | ||||
|         self.local_active.contains_key(&id) | ||||
|     } | ||||
|  | ||||
|     fn is_remote_active(&self, id: StreamId) -> bool { | ||||
|         self.remote_active.contains_key(&id) | ||||
|     } | ||||
|  | ||||
|     fn local_active_len(&self) -> usize { | ||||
|         self.local_active.len() | ||||
|     } | ||||
|  | ||||
|     fn remote_active_len(&self) -> usize { | ||||
|         self.remote_active.len() | ||||
|     } | ||||
|  | ||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         if new_sz < old_sz { | ||||
|             let decr = old_sz - new_sz; | ||||
|  | ||||
|             for s in self.local_active.values_mut() { | ||||
|                 if let Some(fc) = s.local_flow_controller() { | ||||
|                     fc.shrink_window(decr); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for s in self.remote_active.values_mut() { | ||||
|                 if let Some(fc) = s.local_flow_controller() { | ||||
|                     fc.shrink_window(decr); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             let incr = new_sz - old_sz; | ||||
|  | ||||
|             for s in self.local_active.values_mut() { | ||||
|                 if let Some(fc) = s.local_flow_controller() { | ||||
|                     fc.expand_window(incr); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for s in self.remote_active.values_mut() { | ||||
|                 if let Some(fc) = s.local_flow_controller() { | ||||
|                     fc.expand_window(incr); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32) { | ||||
|         if new_sz < old_sz { | ||||
|             let decr = old_sz - new_sz; | ||||
|  | ||||
|             for s in self.local_active.values_mut() { | ||||
|                 if let Some(fc) = s.remote_flow_controller() { | ||||
|                     fc.shrink_window(decr); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for s in self.remote_active.values_mut() { | ||||
|                 if let Some(fc) = s.remote_flow_controller() { | ||||
|                     fc.shrink_window(decr); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             let incr = new_sz - old_sz; | ||||
|  | ||||
|             for s in self.local_active.values_mut() { | ||||
|                 if let Some(fc) = s.remote_flow_controller() { | ||||
|                     fc.expand_window(incr); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for s in self.remote_active.values_mut() { | ||||
|                 if let Some(fc) = s.remote_flow_controller() { | ||||
|                     fc.expand_window(incr); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn local_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         if id.is_zero() { | ||||
|             None | ||||
|         } else if P::is_valid_local_stream_id(id) { | ||||
|             self.local_active.get_mut(&id).and_then(|s| s.local_flow_controller()) | ||||
|         } else { | ||||
|             self.remote_active.get_mut(&id).and_then(|s| s.local_flow_controller()) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||
|         if id.is_zero() { | ||||
|             None | ||||
|         } else if P::is_valid_local_stream_id(id) { | ||||
|             self.local_active.get_mut(&id).and_then(|s| s.remote_flow_controller()) | ||||
|         } else { | ||||
|             self.remote_active.get_mut(&id).and_then(|s| s.remote_flow_controller()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: ApplySettings, P> ApplySettings for StreamStore<T, P> { | ||||
|     fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_local_settings(set) | ||||
|     } | ||||
|  | ||||
|     fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> { | ||||
|         self.inner.apply_remote_settings(set) | ||||
|     } | ||||
| } | ||||
| @@ -110,7 +110,7 @@ impl Peer for Server { | ||||
|     type Send = http::response::Head; | ||||
|     type Poll = http::request::Head; | ||||
|  | ||||
|     fn is_valid_local_stream_id(_id: StreamId) -> bool { | ||||
|     fn is_valid_local_stream_id(id: StreamId) -> bool { | ||||
|         id.is_server_initiated() | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user