Refactor errors (#46)
This patch does a bunch of refactoring, mostly around error types, but it also
paves the way to allow `Codec` to be used standalone.
* `Codec` (and `FramedRead` / `FramedWrite`) is broken out into a codec module.
* An h2-codec crate is created that re-exports the frame and codec modules.
* New error types are introduced in the internals:
  * `RecvError` represents errors caused by trying to receive a frame.
  * `SendError` represents errors caused by trying to send a frame.
  * `UserError` is an enum of potential errors caused by invalid usage
    by the user of the lib.
  * `ProtoError` is either a `Reason` or an `io::Error`. However it doesn't
    specify connection or stream level.
  * `h2::Error` is an opaque error type and is the only error type exposed
    by the public API (used to be `ConnectionError`).
There are misc code changes to enable this as well. The biggest is a new "sink"
API for `Codec`. It provides buffer which queues up a frame followed by flush
which writes everything that is queued. This departs from the `Sink` trait in
order to provide more accurate error values. For example, buffer can never fail
(but it will panic if `poll_ready` is not called first).
			
			
This commit is contained in:
		| @@ -1,77 +0,0 @@ | ||||
| use super::*; | ||||
| use futures::*; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct Codec<T, B> { | ||||
|     inner: FramedRead<FramedWrite<T, B>>, | ||||
| } | ||||
|  | ||||
| impl<T, B> Codec<T, B> { | ||||
|     pub fn apply_remote_settings(&mut self, frame: &frame::Settings) { | ||||
|         self.framed_read().apply_remote_settings(frame); | ||||
|         self.framed_write().apply_remote_settings(frame); | ||||
|     } | ||||
|  | ||||
|     /// Takes the data payload value that was fully written to the socket | ||||
|     pub(crate) fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | ||||
|         self.framed_write().take_last_data_frame() | ||||
|     } | ||||
|  | ||||
|     pub fn max_send_frame_size(&self) -> usize { | ||||
|         self.inner.get_ref().max_frame_size() | ||||
|     } | ||||
|  | ||||
|     fn framed_read(&mut self) -> &mut FramedRead<FramedWrite<T, B>> { | ||||
|         &mut self.inner | ||||
|     } | ||||
|  | ||||
|     fn framed_write(&mut self) -> &mut FramedWrite<T, B> { | ||||
|         self.inner.get_mut() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Codec<T, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     pub fn from_framed(inner: FramedRead<FramedWrite<T, B>>) -> Self { | ||||
|         Codec { inner } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Codec<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.poll_ready() | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| impl<T, B> futures::Stream for Codec<T, B> | ||||
|     where T: AsyncRead, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ProtoError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Frame>, Self::Error> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Sink for Codec<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     type SinkItem = Frame<B>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> { | ||||
|         self.inner.start_send(item) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { | ||||
|         self.inner.poll_complete() | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +1,11 @@ | ||||
| use {client, frame, server, ConnectionError}; | ||||
| use {client, frame, server, proto}; | ||||
| use frame::Reason; | ||||
| use codec::{SendError, RecvError}; | ||||
|  | ||||
| use proto::*; | ||||
|  | ||||
| use http::Request; | ||||
| use futures::{Sink, Stream}; | ||||
| use futures::{Stream}; | ||||
| use bytes::{Bytes, IntoBuf}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
|  | ||||
| @@ -73,7 +75,10 @@ impl<T, P, B> Connection<T, P, B> | ||||
|     } | ||||
|  | ||||
|     /// Returns `Ready` when the connection is ready to receive a frame. | ||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|     /// | ||||
|     /// Returns `RecvError` as this may raise errors that are caused by delayed | ||||
|     /// processing of received frames. | ||||
|     fn poll_ready(&mut self) -> Poll<(), RecvError> { | ||||
|         // The order of these calls don't really matter too much as only one | ||||
|         // should have pending work. | ||||
|         try_ready!(self.ping_pong.send_pending_pong(&mut self.codec)); | ||||
| @@ -83,84 +88,97 @@ impl<T, P, B> Connection<T, P, B> | ||||
|         Ok(().into()) | ||||
|     } | ||||
|  | ||||
|     /// Returns `Ready` when new the connection is able to support a new request stream. | ||||
|     pub fn poll_send_request_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.streams.poll_send_request_ready() | ||||
|     } | ||||
|  | ||||
|     /// Advances the internal state of the connection. | ||||
|     pub fn poll(&mut self) -> Poll<(), ConnectionError> { | ||||
|         use error::ConnectionError::*; | ||||
|     pub fn poll(&mut self) -> Poll<(), proto::Error> { | ||||
|         use codec::RecvError::*; | ||||
|  | ||||
|         loop { | ||||
|             // TODO: probably clean up this glob of code | ||||
|             match self.state { | ||||
|                 // When open, continue to poll a frame | ||||
|                 State::Open => {}, | ||||
|                 // In an error state | ||||
|                 _ => { | ||||
|                     try_ready!(self.poll_complete()); | ||||
|                 State::Open => { | ||||
|                     match self.poll2() { | ||||
|                         // The connection has shutdown normally | ||||
|                         Ok(Async::Ready(())) => return Ok(().into()), | ||||
|                         // The connection is not ready to make progress | ||||
|                         Ok(Async::NotReady) => { | ||||
|                             // Ensure all window updates have been sent. | ||||
|                             // | ||||
|                             // This will also handle flushing `self.codec` | ||||
|                             try_ready!(self.streams.poll_complete(&mut self.codec)); | ||||
|  | ||||
|                     // GO_AWAY frame has been sent, return the error | ||||
|                     return Err(self.state.error().unwrap().into()); | ||||
|                 } | ||||
|             } | ||||
|                             return Ok(Async::NotReady); | ||||
|                         } | ||||
|                         // Attempting to read a frame resulted in a connection level | ||||
|                         // error. This is handled by setting a GO_AWAY frame followed by | ||||
|                         // terminating the connection. | ||||
|                         Err(Connection(e)) => { | ||||
|                             debug!("Connection::poll; err={:?}", e); | ||||
|  | ||||
|             match self.poll2() { | ||||
|                 Err(Proto(e)) => { | ||||
|                     debug!("Connection::poll; err={:?}", e); | ||||
|                     let last_processed_id = self.streams.recv_err(&e.into()); | ||||
|                     let frame = frame::GoAway::new(last_processed_id, e); | ||||
|                             // Reset all active streams | ||||
|                             let last_processed_id = self.streams.recv_err(&e.into()); | ||||
|  | ||||
|                     self.state = State::GoAway(frame); | ||||
|                             // Create the GO_AWAY frame with the last_processed_id | ||||
|                             let frame = frame::GoAway::new(last_processed_id, e); | ||||
|  | ||||
|                             // Transition to the going away state. | ||||
|                             self.state = State::GoAway(frame); | ||||
|                         } | ||||
|                         // Attempting to read a frame resulted in a stream level error. | ||||
|                         // This is handled by resetting the frame then trying to read | ||||
|                         // another frame. | ||||
|                         Err(Stream { id, reason }) => { | ||||
|                             trace!("stream level error; id={:?}; reason={:?}", id, reason); | ||||
|                             self.streams.send_reset(id, reason); | ||||
|                         } | ||||
|                         // Attempting to read a frame resulted in an I/O error. All | ||||
|                         // active streams must be reset. | ||||
|                         // | ||||
|                         // TODO: Are I/O errors recoverable? | ||||
|                         Err(Io(e)) => { | ||||
|                             let e = e.into(); | ||||
|  | ||||
|                             // Reset all active streams | ||||
|                             self.streams.recv_err(&e); | ||||
|  | ||||
|                             // Return the error | ||||
|                             return Err(e); | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 State::GoAway(frame) => { | ||||
|                     // Ensure the codec is ready to accept the frame | ||||
|                     try_ready!(self.codec.poll_ready()); | ||||
|  | ||||
|                     // Buffer the GO_AWAY frame | ||||
|                     self.codec.buffer(frame.into()) | ||||
|                         .ok().expect("invalid GO_AWAY frame"); | ||||
|  | ||||
|                     // GO_AWAY sent, transition the connection to an errored state | ||||
|                     self.state = State::Flush(frame.reason()); | ||||
|                 } | ||||
|                 Err(e) => { | ||||
|                     // TODO: Are I/O errors recoverable? | ||||
|                     self.streams.recv_err(&e); | ||||
|                     return Err(e); | ||||
|                 State::Flush(reason) => { | ||||
|                     // Flush the codec | ||||
|                     try_ready!(self.codec.flush()); | ||||
|  | ||||
|                     // Transition the state to error | ||||
|                     self.state = State::Error(reason); | ||||
|                 } | ||||
|                 State::Error(reason) => { | ||||
|                     return Err(reason.into()); | ||||
|                 } | ||||
|                 ret => return ret, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll2(&mut self) -> Poll<(), ConnectionError> { | ||||
|     fn poll2(&mut self) -> Poll<(), RecvError> { | ||||
|         use frame::Frame::*; | ||||
|         use proto::ProtoError::*; | ||||
|  | ||||
|         loop { | ||||
|             // First, ensure that the `Connection` is able to receive a frame | ||||
|             try_ready!(self.poll_ready()); | ||||
|  | ||||
|             trace!("polling codec"); | ||||
|  | ||||
|             let frame = match self.codec.poll() { | ||||
|                 // Receive a frame | ||||
|                 Ok(Async::Ready(frame)) => frame, | ||||
|                 // Socket not ready, try to flush any pending data | ||||
|                 Ok(Async::NotReady) => { | ||||
|                     // Flush any pending writes | ||||
|                     let _ = try!(self.poll_complete()); | ||||
|                     return Ok(Async::NotReady); | ||||
|                 } | ||||
|                 // Connection level error, set GO_AWAY and close connection | ||||
|                 Err(Connection(reason)) => { | ||||
|                     return Err(ConnectionError::Proto(reason)); | ||||
|                 } | ||||
|                 // Stream level error, reset the stream | ||||
|                 Err(Stream { id, reason }) => { | ||||
|                     trace!("stream level error; id={:?}; reason={:?}", id, reason); | ||||
|                     self.streams.send_reset(id, reason); | ||||
|                     continue; | ||||
|                 } | ||||
|                 // I/O error, nothing more can be done | ||||
|                 Err(Io(err)) => { | ||||
|                     return Err(err.into()); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             debug!("recv; frame={:?}", frame); | ||||
|  | ||||
|             match frame { | ||||
|             match try_ready!(self.codec.poll()) { | ||||
|                 Some(Headers(frame)) => { | ||||
|                     trace!("recv HEADERS; frame={:?}", frame); | ||||
|                     try!(self.streams.recv_headers(frame)); | ||||
| @@ -184,7 +202,7 @@ impl<T, P, B> Connection<T, P, B> | ||||
|                 Some(GoAway(_)) => { | ||||
|                     // TODO: handle the last_processed_id. Also, should this be | ||||
|                     // handled as an error? | ||||
|                     // let _ = ConnectionError::Proto(frame.reason()); | ||||
|                     // let _ = RecvError::Proto(frame.reason()); | ||||
|                     return Ok(().into()); | ||||
|                 } | ||||
|                 Some(Ping(frame)) => { | ||||
| @@ -207,46 +225,20 @@ impl<T, P, B> Connection<T, P, B> | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|         loop { | ||||
|             match self.state { | ||||
|                 State::Open => { | ||||
|                     try_ready!(self.poll_ready()); | ||||
|  | ||||
|                     // Ensure all window updates have been sent. | ||||
|                     try_ready!(self.streams.poll_complete(&mut self.codec)); | ||||
|  | ||||
|                     return Ok(().into()); | ||||
|                 } | ||||
|                 State::GoAway(frame) => { | ||||
|                     if !self.codec.start_send(frame.into())?.is_ready() { | ||||
|                         // Not ready to send the frame... try again later. | ||||
|                         return Ok(Async::NotReady); | ||||
|                     } | ||||
|  | ||||
|                     // GO_AWAY sent, transition the connection to an errored state | ||||
|                     self.state = State::Flush(frame.reason()); | ||||
|                 } | ||||
|                 State::Flush(reason) => { | ||||
|                     try_ready!(self.codec.poll_complete()); | ||||
|                     self.state = State::Error(reason); | ||||
|                 } | ||||
|                 State::Error(..) => { | ||||
|                     return Ok(().into()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Connection<T, client::Peer, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     /// Returns `Ready` when new the connection is able to support a new request stream. | ||||
|     pub fn poll_send_request_ready(&mut self) -> Async<()> { | ||||
|         self.streams.poll_send_request_ready() | ||||
|     } | ||||
|  | ||||
|     /// Initialize a new HTTP/2.0 stream and send the message. | ||||
|     pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool) | ||||
|         -> Result<StreamRef<B::Buf, client::Peer>, ConnectionError> | ||||
|         -> Result<StreamRef<B::Buf, client::Peer>, SendError> | ||||
|     { | ||||
|         self.streams.send_request(request, end_of_stream) | ||||
|     } | ||||
| @@ -260,14 +252,3 @@ impl<T, B> Connection<T, server::Peer, B> | ||||
|         self.streams.next_incoming() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ====== impl State ===== | ||||
|  | ||||
| impl State { | ||||
|     fn error(&self) -> Option<Reason> { | ||||
|         match *self { | ||||
|             State::Error(reason) => Some(reason), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										34
									
								
								src/proto/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/proto/error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| use frame::Reason; | ||||
| use codec::RecvError; | ||||
|  | ||||
| use std::io; | ||||
|  | ||||
| /// Either an H2 reason  or an I/O error | ||||
| #[derive(Debug)] | ||||
| pub enum Error { | ||||
|     Proto(Reason), | ||||
|     Io(io::Error), | ||||
| } | ||||
|  | ||||
| impl Error { | ||||
|     pub fn into_connection_recv_error(self) -> RecvError { | ||||
|         use self::Error::*; | ||||
|  | ||||
|         match self { | ||||
|             Proto(reason) => RecvError::Connection(reason), | ||||
|             Io(e) => RecvError::Io(e), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Reason> for Error { | ||||
|     fn from(src: Reason) -> Self { | ||||
|         Error::Proto(src) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<io::Error> for Error { | ||||
|     fn from(src: io::Error) -> Self { | ||||
|         Error::Io(src) | ||||
|     } | ||||
| } | ||||
| @@ -1,278 +0,0 @@ | ||||
| use {hpack, ConnectionError}; | ||||
| use frame::{self, Frame, Kind}; | ||||
| use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE; | ||||
| use proto::*; | ||||
| use error::Reason::*; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| use bytes::BytesMut; | ||||
|  | ||||
| use tokio_io::AsyncRead; | ||||
| use tokio_io::codec::length_delimited; | ||||
|  | ||||
| use std::io; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct FramedRead<T> { | ||||
|     inner: length_delimited::FramedRead<T>, | ||||
|  | ||||
|     // hpack decoder state | ||||
|     hpack: hpack::Decoder, | ||||
|  | ||||
|     partial: Option<Partial>, | ||||
| } | ||||
|  | ||||
| /// Partially loaded headers frame | ||||
| #[derive(Debug)] | ||||
| struct Partial { | ||||
|     /// Empty frame | ||||
|     frame: Continuable, | ||||
|  | ||||
|     /// Partial header payload | ||||
|     buf: BytesMut, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum Continuable { | ||||
|     Headers(frame::Headers), | ||||
|     // Decode the Continuation frame but ignore it... | ||||
|     // Ignore(StreamId), | ||||
|     // PushPromise(frame::PushPromise), | ||||
| } | ||||
|  | ||||
| impl<T> FramedRead<T> { | ||||
|     pub fn new(inner: length_delimited::FramedRead<T>) -> FramedRead<T> { | ||||
|         FramedRead { | ||||
|             inner: inner, | ||||
|             hpack: hpack::Decoder::new(DEFAULT_SETTINGS_HEADER_TABLE_SIZE), | ||||
|             partial: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn apply_remote_settings(&mut self, _settings: &frame::Settings) { | ||||
|         // TODO: Is this needed? | ||||
|     } | ||||
|  | ||||
|     fn decode_frame(&mut self, mut bytes: BytesMut) -> Result<Option<Frame>, ProtoError> { | ||||
|         use self::ProtoError::*; | ||||
|  | ||||
|         trace!("decoding frame from {}B", bytes.len()); | ||||
|  | ||||
|         // Parse the head | ||||
|         let head = frame::Head::parse(&bytes); | ||||
|  | ||||
|         if self.partial.is_some() && head.kind() != Kind::Continuation { | ||||
|             return Err(Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         let kind = head.kind(); | ||||
|  | ||||
|         trace!("    -> kind={:?}", kind); | ||||
|  | ||||
|         let frame = match kind { | ||||
|             Kind::Settings => { | ||||
|                 let res = frame::Settings::load(head, &bytes[frame::HEADER_LEN..]); | ||||
|  | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::Ping => { | ||||
|                 let res = frame::Ping::load(head, &bytes[frame::HEADER_LEN..]); | ||||
|  | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::WindowUpdate => { | ||||
|                 let res = frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..]); | ||||
|  | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::Data => { | ||||
|                 let _ = bytes.split_to(frame::HEADER_LEN); | ||||
|                 let res = frame::Data::load(head, bytes.freeze()); | ||||
|  | ||||
|                 // TODO: Should this always be connection level? Probably not... | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::Headers => { | ||||
|                 // Drop the frame header | ||||
|                 // TODO: Change to drain: carllerche/bytes#130 | ||||
|                 let _ = bytes.split_to(frame::HEADER_LEN); | ||||
|  | ||||
|                 // Parse the header frame w/o parsing the payload | ||||
|                 let (mut headers, payload) = match frame::Headers::load(head, bytes) { | ||||
|                     Ok(res) => res, | ||||
|                     Err(frame::Error::InvalidDependencyId) => { | ||||
|                         // A stream cannot depend on itself. An endpoint MUST | ||||
|                         // treat this as a stream error (Section 5.4.2) of type | ||||
|                         // `PROTOCOL_ERROR`. | ||||
|                         return Err(Stream { | ||||
|                             id: head.stream_id(), | ||||
|                             reason: ProtocolError, | ||||
|                         }); | ||||
|                     } | ||||
|                     _ => return Err(Connection(ProtocolError)), | ||||
|                 }; | ||||
|  | ||||
|                 if headers.is_end_headers() { | ||||
|                     // Load the HPACK encoded headers & return the frame | ||||
|                     match headers.load_hpack(payload, &mut self.hpack) { | ||||
|                         Ok(_) => {} | ||||
|                         Err(frame::Error::MalformedMessage) => { | ||||
|                             return Err(Stream { | ||||
|                                 id: head.stream_id(), | ||||
|                                 reason: ProtocolError, | ||||
|                             }); | ||||
|                         } | ||||
|                         Err(_) => return Err(Connection(ProtocolError)), | ||||
|                     } | ||||
|  | ||||
|                     headers.into() | ||||
|                 } else { | ||||
|                     // Defer loading the frame | ||||
|                     self.partial = Some(Partial { | ||||
|                         frame: Continuable::Headers(headers), | ||||
|                         buf: payload, | ||||
|                     }); | ||||
|  | ||||
|                     return Ok(None); | ||||
|                 } | ||||
|             } | ||||
|             Kind::Reset => { | ||||
|                 let res = frame::Reset::load(head, &bytes[frame::HEADER_LEN..]); | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::GoAway => { | ||||
|                 let res = frame::GoAway::load(&bytes[frame::HEADER_LEN..]); | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::PushPromise => { | ||||
|                 let res = frame::PushPromise::load(head, &bytes[frame::HEADER_LEN..]); | ||||
|                 res.map_err(|_| Connection(ProtocolError))?.into() | ||||
|             } | ||||
|             Kind::Priority => { | ||||
|                 if head.stream_id() == 0 { | ||||
|                     // Invalid stream identifier | ||||
|                     return Err(Connection(ProtocolError)); | ||||
|                 } | ||||
|  | ||||
|                 match frame::Priority::load(head, &bytes[frame::HEADER_LEN..]) { | ||||
|                     Ok(frame) => frame.into(), | ||||
|                     Err(frame::Error::InvalidDependencyId) => { | ||||
|                         // A stream cannot depend on itself. An endpoint MUST | ||||
|                         // treat this as a stream error (Section 5.4.2) of type | ||||
|                         // `PROTOCOL_ERROR`. | ||||
|                         return Err(Stream { | ||||
|                             id: head.stream_id(), | ||||
|                             reason: ProtocolError, | ||||
|                         }); | ||||
|                     } | ||||
|                     Err(_) => return Err(Connection(ProtocolError)), | ||||
|                 } | ||||
|             } | ||||
|             Kind::Continuation => { | ||||
|                 // TODO: Un-hack this | ||||
|                 let end_of_headers = (head.flag() & 0x4) == 0x4; | ||||
|  | ||||
|                 let mut partial = match self.partial.take() { | ||||
|                     Some(partial) => partial, | ||||
|                     None => return Err(Connection(ProtocolError)), | ||||
|                 }; | ||||
|  | ||||
|                 // Extend the buf | ||||
|                 partial.buf.extend_from_slice(&bytes[frame::HEADER_LEN..]); | ||||
|  | ||||
|                 if !end_of_headers { | ||||
|                     self.partial = Some(partial); | ||||
|                     return Ok(None); | ||||
|                 } | ||||
|  | ||||
|                 match partial.frame { | ||||
|                     Continuable::Headers(mut frame) => { | ||||
|                         // The stream identifiers must match | ||||
|                         if frame.stream_id() != head.stream_id() { | ||||
|                             return Err(Connection(ProtocolError)); | ||||
|                         } | ||||
|  | ||||
|                         match frame.load_hpack(partial.buf, &mut self.hpack) { | ||||
|                             Ok(_) => {} | ||||
|                             Err(frame::Error::MalformedMessage) => { | ||||
|                                 return Err(Stream { | ||||
|                                     id: head.stream_id(), | ||||
|                                     reason: ProtocolError, | ||||
|                                 }); | ||||
|                             } | ||||
|                             Err(_) => return Err(Connection(ProtocolError)), | ||||
|                         } | ||||
|  | ||||
|                         frame.into() | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Kind::Unknown => { | ||||
|                 // Unknown frames are ignored | ||||
|                 return Ok(None); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         Ok(Some(frame)) | ||||
|     } | ||||
|  | ||||
|     pub fn get_ref(&self) -> &T { | ||||
|         self.inner.get_ref() | ||||
|     } | ||||
|  | ||||
|     pub fn get_mut(&mut self) -> &mut T { | ||||
|         self.inner.get_mut() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T> futures::Stream for FramedRead<T> | ||||
|     where T: AsyncRead, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = ProtoError; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<Frame>, Self::Error> { | ||||
|         loop { | ||||
|             trace!("poll"); | ||||
|             let bytes = match try_ready!(self.inner.poll()) { | ||||
|                 Some(bytes) => bytes, | ||||
|                 None => return Ok(Async::Ready(None)), | ||||
|             }; | ||||
|  | ||||
|             trace!("poll; bytes={}B", bytes.len()); | ||||
|             if let Some(frame) = try!(self.decode_frame(bytes)) { | ||||
|                 return Ok(Async::Ready(Some(frame))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Sink> Sink for FramedRead<T> { | ||||
|     type SinkItem = T::SinkItem; | ||||
|     type SinkError = T::SinkError; | ||||
|  | ||||
|     fn start_send(&mut self, item: T::SinkItem) -> StartSend<T::SinkItem, T::SinkError> { | ||||
|         self.inner.get_mut().start_send(item) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||
|         self.inner.get_mut().poll_complete() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsyncWrite, B: Buf> FramedRead<FramedWrite<T, B>> { | ||||
|     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         self.inner.get_mut().poll_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: io::Write> io::Write for FramedRead<T> { | ||||
|     fn write(&mut self, src: &[u8]) -> io::Result<usize> { | ||||
|         self.inner.get_mut().write(src) | ||||
|     } | ||||
|  | ||||
|     fn flush(&mut self) -> io::Result<()> { | ||||
|         self.inner.get_mut().flush() | ||||
|     } | ||||
| } | ||||
| @@ -1,262 +0,0 @@ | ||||
| use {hpack, ConnectionError}; | ||||
| use error::User::*; | ||||
| use frame::{self, Frame, FrameSize}; | ||||
|  | ||||
| use futures::*; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use bytes::{BytesMut, Buf, BufMut}; | ||||
|  | ||||
| use std::io::{self, Cursor}; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct FramedWrite<T, B> { | ||||
|     /// Upstream `AsyncWrite` | ||||
|     inner: T, | ||||
|  | ||||
|     /// HPACK encoder | ||||
|     hpack: hpack::Encoder, | ||||
|  | ||||
|     /// Write buffer | ||||
|     /// | ||||
|     /// TODO: Should this be a ring buffer? | ||||
|     buf: Cursor<BytesMut>, | ||||
|  | ||||
|     /// Next frame to encode | ||||
|     next: Option<Next<B>>, | ||||
|  | ||||
|     /// Last data frame | ||||
|     last_data_frame: Option<frame::Data<B>>, | ||||
|  | ||||
|     /// Max frame size, this is specified by the peer | ||||
|     max_frame_size: FrameSize, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum Next<B> { | ||||
|     Data(frame::Data<B>), | ||||
|     Continuation(frame::Continuation), | ||||
| } | ||||
|  | ||||
| /// Initialze the connection with this amount of write buffer. | ||||
| const DEFAULT_BUFFER_CAPACITY: usize = 4 * 1_024; | ||||
|  | ||||
| /// Min buffer required to attempt to write a frame | ||||
| const MIN_BUFFER_CAPACITY: usize = frame::HEADER_LEN + CHAIN_THRESHOLD; | ||||
|  | ||||
| /// Chain payloads bigger than this. The remote will never advertise a max frame | ||||
| /// size less than this (well, the spec says the max frame size can't be less | ||||
| /// than 16kb, so not even close). | ||||
| const CHAIN_THRESHOLD: usize = 256; | ||||
|  | ||||
| // TODO: Make generic | ||||
| impl<T, B> FramedWrite<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     pub fn new(inner: T) -> FramedWrite<T, B> { | ||||
|         FramedWrite { | ||||
|             inner: inner, | ||||
|             hpack: hpack::Encoder::default(), | ||||
|             buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | ||||
|             next: None, | ||||
|             last_data_frame: None, | ||||
|             max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         if !self.has_capacity() { | ||||
|             // Try flushing | ||||
|             try!(self.poll_complete()); | ||||
|  | ||||
|             if !self.has_capacity() { | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
|  | ||||
|     fn has_capacity(&self) -> bool { | ||||
|         self.next.is_none() && self.buf.get_ref().remaining_mut() >= MIN_BUFFER_CAPACITY | ||||
|     } | ||||
|  | ||||
|     fn is_empty(&self) -> bool { | ||||
|         match self.next { | ||||
|             Some(Next::Data(ref frame)) => !frame.payload().has_remaining(), | ||||
|             _ => !self.buf.has_remaining(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> FramedWrite<T, B> { | ||||
|     pub fn max_frame_size(&self) -> usize { | ||||
|         self.max_frame_size as usize | ||||
|     } | ||||
|  | ||||
|     pub fn apply_remote_settings(&mut self, settings: &frame::Settings) { | ||||
|         if let Some(val) = settings.max_frame_size() { | ||||
|             self.max_frame_size = val; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | ||||
|         self.last_data_frame.take() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Sink for FramedWrite<T, B> | ||||
|     where T: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     type SinkItem = Frame<B>; | ||||
|     type SinkError = ConnectionError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) | ||||
|         -> StartSend<Self::SinkItem, ConnectionError> | ||||
|     { | ||||
|         if !try!(self.poll_ready()).is_ready() { | ||||
|             return Ok(AsyncSink::NotReady(item)); | ||||
|         } | ||||
|  | ||||
|         debug!("send; frame={:?}", item); | ||||
|  | ||||
|         match item { | ||||
|             Frame::Data(mut v) => { | ||||
|                 // Ensure that the payload is not greater than the max frame. | ||||
|                 let len = v.payload().remaining(); | ||||
|  | ||||
|                 if len > self.max_frame_size() { | ||||
|                     return Err(PayloadTooBig.into()); | ||||
|                 } | ||||
|  | ||||
|                 if len >= CHAIN_THRESHOLD { | ||||
|                     let head = v.head(); | ||||
|  | ||||
|                     // Encode the frame head to the buffer | ||||
|                     head.encode(len, self.buf.get_mut()); | ||||
|  | ||||
|                     // Save the data frame | ||||
|                     self.next = Some(Next::Data(v)); | ||||
|                 } else { | ||||
|                     v.encode_chunk(self.buf.get_mut()); | ||||
|  | ||||
|                     // The chunk has been fully encoded, so there is no need to | ||||
|                     // keep it around | ||||
|                     assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); | ||||
|  | ||||
|                     // Save off the last frame... | ||||
|                     self.last_data_frame = Some(v); | ||||
|                 } | ||||
|             } | ||||
|             Frame::Headers(v) => { | ||||
|                 if let Some(continuation) = v.encode(&mut self.hpack, self.buf.get_mut()) { | ||||
|                     self.next = Some(Next::Continuation(continuation)); | ||||
|                 } | ||||
|             } | ||||
|             Frame::PushPromise(v) => { | ||||
|                 debug!("unimplemented PUSH_PROMISE write; frame={:?}", v); | ||||
|                 unimplemented!(); | ||||
|             } | ||||
|             Frame::Settings(v) => { | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded settings; rem={:?}", self.buf.remaining()); | ||||
|             } | ||||
|             Frame::GoAway(v) => { | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded go_away; rem={:?}", self.buf.remaining()); | ||||
|             } | ||||
|             Frame::Ping(v) => { | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded ping; rem={:?}", self.buf.remaining()); | ||||
|             } | ||||
|             Frame::WindowUpdate(v) => { | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded window_update; rem={:?}", self.buf.remaining()); | ||||
|             } | ||||
|  | ||||
|             Frame::Priority(_) => { | ||||
|                 /* | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded priority; rem={:?}", self.buf.remaining()); | ||||
|                 */ | ||||
|                 unimplemented!(); | ||||
|             } | ||||
|             Frame::Reset(v) => { | ||||
|                 v.encode(self.buf.get_mut()); | ||||
|                 trace!("encoded reset; rem={:?}", self.buf.remaining()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(AsyncSink::Ready) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||
|         trace!("poll_complete"); | ||||
|  | ||||
|         while !self.is_empty() { | ||||
|             match self.next { | ||||
|                 Some(Next::Data(ref mut frame)) => { | ||||
|                     let mut buf = Buf::by_ref(&mut self.buf).chain(frame.payload_mut()); | ||||
|                     try_ready!(self.inner.write_buf(&mut buf)); | ||||
|                 } | ||||
|                 _ => { | ||||
|                     try_ready!(self.inner.write_buf(&mut self.buf)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // The data frame has been written, so unset it | ||||
|         match self.next.take() { | ||||
|             Some(Next::Data(frame)) => { | ||||
|                 self.last_data_frame = Some(frame); | ||||
|             } | ||||
|             Some(Next::Continuation(_)) => { | ||||
|                 unimplemented!(); | ||||
|             } | ||||
|             None => {} | ||||
|         } | ||||
|  | ||||
|         trace!("flushing buffer"); | ||||
|         // Flush the upstream | ||||
|         try_nb!(self.inner.flush()); | ||||
|  | ||||
|         // Clear internal buffer | ||||
|         self.buf.set_position(0); | ||||
|         self.buf.get_mut().clear(); | ||||
|  | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
|  | ||||
|     fn close(&mut self) -> Poll<(), ConnectionError> { | ||||
|         try_ready!(self.poll_complete()); | ||||
|         self.inner.shutdown().map_err(Into::into) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Stream, B> Stream for FramedWrite<T, B> { | ||||
|     type Item = T::Item; | ||||
|     type Error = T::Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Option<T::Item>, T::Error> { | ||||
|         self.inner.poll() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: io::Read, B> io::Read for FramedWrite<T, B> { | ||||
|     fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { | ||||
|         self.inner.read(dst) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: AsyncRead, B> AsyncRead for FramedWrite<T, B> { | ||||
|     fn read_buf<B2: BufMut>(&mut self, buf: &mut B2) -> Poll<usize, io::Error> | ||||
|         where Self: Sized, | ||||
|     { | ||||
|         self.inner.read_buf(buf) | ||||
|     } | ||||
|  | ||||
|     unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { | ||||
|         self.inner.prepare_uninitialized_buffer(buf) | ||||
|     } | ||||
| } | ||||
| @@ -1,109 +1,35 @@ | ||||
| mod codec; | ||||
| mod connection; | ||||
| mod framed_read; | ||||
| mod framed_write; | ||||
| mod error; | ||||
| mod peer; | ||||
| mod ping_pong; | ||||
| mod settings; | ||||
| mod streams; | ||||
|  | ||||
| pub(crate) use self::connection::Connection; | ||||
| pub(crate) use self::error::Error; | ||||
| pub(crate) use self::peer::Peer; | ||||
| pub(crate) use self::streams::{Streams, StreamRef}; | ||||
|  | ||||
| use self::codec::Codec; | ||||
| use self::framed_read::FramedRead; | ||||
| use self::framed_write::FramedWrite; | ||||
| use codec::Codec; | ||||
|  | ||||
| use self::ping_pong::PingPong; | ||||
| use self::settings::Settings; | ||||
| use self::streams::Prioritized; | ||||
|  | ||||
| use ConnectionError; | ||||
| use error::Reason; | ||||
| use frame::{self, Frame, StreamId}; | ||||
| use frame::{self, Frame}; | ||||
|  | ||||
| use futures::{self, task, Poll, Async, AsyncSink}; | ||||
| use futures::{task, Poll, Async}; | ||||
| use futures::task::Task; | ||||
| use bytes::{Buf, IntoBuf}; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio_io::codec::length_delimited; | ||||
|  | ||||
| use std::{fmt, io}; | ||||
| use bytes::Buf; | ||||
|  | ||||
| /// Either a Client or a Server | ||||
| pub trait Peer { | ||||
|     /// Message type sent into the transport | ||||
|     type Send; | ||||
|  | ||||
|     /// Message type polled from the transport | ||||
|     type Poll: fmt::Debug; | ||||
|  | ||||
|     fn is_server() -> bool; | ||||
|  | ||||
|     fn convert_send_message( | ||||
|         id: StreamId, | ||||
|         headers: Self::Send, | ||||
|         end_of_stream: bool) -> frame::Headers; | ||||
|  | ||||
|     fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ProtoError>; | ||||
| } | ||||
| use tokio_io::AsyncWrite; | ||||
|  | ||||
| pub type PingPayload = [u8; 8]; | ||||
|  | ||||
| pub type WindowSize = u32; | ||||
|  | ||||
| /// Errors that are received | ||||
| #[derive(Debug)] | ||||
| pub enum ProtoError { | ||||
|     Connection(Reason), | ||||
|     Stream { | ||||
|         id: StreamId, | ||||
|         reason: Reason, | ||||
|     }, | ||||
|     Io(io::Error), | ||||
| } | ||||
|  | ||||
| // Constants | ||||
| // TODO: Move these into `frame` | ||||
| pub const DEFAULT_INITIAL_WINDOW_SIZE: WindowSize = 65_535; | ||||
| pub const MAX_WINDOW_SIZE: WindowSize = (1 << 31) - 1; | ||||
|  | ||||
| /// Create a transport prepared to handle the server handshake. | ||||
| /// | ||||
| /// When the server is performing the handshake, it is able to only send | ||||
| /// `Settings` frames and is expected to receive the client preface as a byte | ||||
| /// stream. To represent this, `Settings<FramedWrite<T>>` is returned. | ||||
| pub(crate) fn framed_write<T, B>(io: T) -> FramedWrite<T, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     FramedWrite::new(io) | ||||
| } | ||||
|  | ||||
| /// Create a full H2 transport from the server handshaker | ||||
| pub(crate) fn from_framed_write<T, P, B>(framed_write: FramedWrite<T, Prioritized<B::Buf>>) | ||||
|     -> Connection<T, P, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           P: Peer, | ||||
|           B: IntoBuf, | ||||
| { | ||||
|     // Delimit the frames. | ||||
|     let framed = length_delimited::Builder::new() | ||||
|         .big_endian() | ||||
|         .length_field_length(3) | ||||
|         .length_adjustment(9) | ||||
|         .num_skip(0) // Don't skip the header | ||||
|         // TODO: make this configurable and allow it to be changed during | ||||
|         // runtime. | ||||
|         .max_frame_length(frame::DEFAULT_MAX_FRAME_SIZE as usize) | ||||
|         .new_read(framed_write); | ||||
|  | ||||
|     let codec = Codec::from_framed(FramedRead::new(framed)); | ||||
|  | ||||
|     Connection::new(codec) | ||||
| } | ||||
|  | ||||
| // ===== impl ProtoError ===== | ||||
|  | ||||
| impl From<io::Error> for ProtoError { | ||||
|     fn from(src: io::Error) -> Self { | ||||
|         ProtoError::Io(src) | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										22
									
								
								src/proto/peer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/proto/peer.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| use frame::{Headers, StreamId}; | ||||
| use codec::RecvError; | ||||
|  | ||||
| use std::fmt; | ||||
|  | ||||
| /// Either a Client or a Server | ||||
| pub trait Peer { | ||||
|     /// Message type sent into the transport | ||||
|     type Send; | ||||
|  | ||||
|     /// Message type polled from the transport | ||||
|     type Poll: fmt::Debug; | ||||
|  | ||||
|     fn is_server() -> bool; | ||||
|  | ||||
|     fn convert_send_message( | ||||
|         id: StreamId, | ||||
|         headers: Self::Send, | ||||
|         end_of_stream: bool) -> Headers; | ||||
|  | ||||
|     fn convert_poll_message(headers: Headers) -> Result<Self::Poll, RecvError>; | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| use frame::Ping; | ||||
| use proto::*; | ||||
|  | ||||
| use futures::Sink; | ||||
| use std::io; | ||||
|  | ||||
| /// Acknowledges ping requests from the remote. | ||||
| #[derive(Debug)] | ||||
| @@ -45,15 +45,16 @@ impl<B> PingPong<B> | ||||
|     } | ||||
|  | ||||
|     /// Send any pending pongs. | ||||
|     pub fn send_pending_pong<T>(&mut self, dst: &mut Codec<T, B>) -> Poll<(), ConnectionError> | ||||
|     pub fn send_pending_pong<T>(&mut self, dst: &mut Codec<T, B>) -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         if let Some(pong) = self.sending_pong.take() { | ||||
|             if let AsyncSink::NotReady(pong) = dst.start_send(pong)? { | ||||
|                 // If the pong can't be sent, save it. | ||||
|             if !dst.poll_ready()?.is_ready() { | ||||
|                 self.sending_pong = Some(pong); | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|  | ||||
|             dst.buffer(pong).ok().expect("invalid pong frame"); | ||||
|         } | ||||
|  | ||||
|         Ok(Async::Ready(())) | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| use frame; | ||||
| use codec::RecvError; | ||||
| use proto::*; | ||||
|  | ||||
| use futures::Sink; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct Settings { | ||||
|     /// Received SETTINGS frame pending processing. The ACK must be written to | ||||
| @@ -31,7 +30,7 @@ impl Settings { | ||||
|     pub fn send_pending_ack<T, B, C, P>(&mut self, | ||||
|                                         dst: &mut Codec<T, B>, | ||||
|                                         streams: &mut Streams<C, P>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), RecvError> | ||||
|         where T: AsyncWrite, | ||||
|               B: Buf, | ||||
|               C: Buf, | ||||
| @@ -40,13 +39,17 @@ impl Settings { | ||||
|         trace!("send_pending_ack; pending={:?}", self.pending); | ||||
|  | ||||
|         if let Some(ref settings) = self.pending { | ||||
|             let frame = frame::Settings::ack(); | ||||
|  | ||||
|             if let AsyncSink::NotReady(_) = dst.start_send(frame.into())? { | ||||
|             if !dst.poll_ready()?.is_ready() { | ||||
|                 trace!("failed to send ACK"); | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|  | ||||
|             // Create an ACK settings frame | ||||
|             let frame = frame::Settings::ack(); | ||||
|  | ||||
|             // Buffer the settings frame | ||||
|             dst.buffer(frame.into()).ok().expect("invalid settings frame"); | ||||
|  | ||||
|             trace!("ACK sent; applying settings"); | ||||
|  | ||||
|             dst.apply_remote_settings(settings); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use ConnectionError; | ||||
| use frame::Reason; | ||||
| use frame::Reason::*; | ||||
| use proto::*; | ||||
| use error::Reason::*; | ||||
|  | ||||
| #[derive(Copy, Clone, Debug)] | ||||
| pub struct FlowControl { | ||||
| @@ -67,15 +67,15 @@ impl FlowControl { | ||||
|     /// Increase the window size. | ||||
|     /// | ||||
|     /// This is called after receiving a WINDOW_UPDATE frame | ||||
|     pub fn inc_window(&mut self, sz: WindowSize) -> Result<(), ConnectionError> { | ||||
|     pub fn inc_window(&mut self, sz: WindowSize) -> Result<(), Reason> { | ||||
|         let (val, overflow) = self.window_size.overflowing_add(sz as i32); | ||||
|  | ||||
|         if overflow { | ||||
|             return Err(FlowControlError.into()); | ||||
|             return Err(FlowControlError); | ||||
|         } | ||||
|  | ||||
|         if val > MAX_WINDOW_SIZE as i32 { | ||||
|             return Err(FlowControlError.into()); | ||||
|             return Err(FlowControlError); | ||||
|         } | ||||
|  | ||||
|         trace!("inc_window; sz={}; old={}; new={}", sz, self.window_size, val); | ||||
|   | ||||
| @@ -20,11 +20,9 @@ use self::state::State; | ||||
| use self::store::{Store, Entry}; | ||||
| use self::stream::Stream; | ||||
|  | ||||
| use {frame, ConnectionError}; | ||||
| use frame::StreamId; | ||||
| use proto::*; | ||||
| use error::Reason::*; | ||||
| use error::User::*; | ||||
|  | ||||
| use http::{Request, Response}; | ||||
| use bytes::Bytes; | ||||
|   | ||||
| @@ -1,9 +1,14 @@ | ||||
| use super::*; | ||||
| use super::store::Resolve; | ||||
|  | ||||
| use bytes::buf::Take; | ||||
| use futures::Sink; | ||||
| use frame::Reason; | ||||
|  | ||||
| use codec::UserError; | ||||
| use codec::UserError::*; | ||||
|  | ||||
| use bytes::buf::Take; | ||||
|  | ||||
| use std::io; | ||||
| use std::{fmt, cmp}; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| @@ -80,7 +85,7 @@ impl<B, P> Prioritize<B, P> | ||||
|                      frame: frame::Data<B>, | ||||
|                      stream: &mut store::Ptr<B, P>, | ||||
|                      task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         let sz = frame.payload().remaining(); | ||||
|  | ||||
| @@ -93,9 +98,9 @@ impl<B, P> Prioritize<B, P> | ||||
|  | ||||
|         if !stream.state.is_send_streaming() { | ||||
|             if stream.state.is_closed() { | ||||
|                 return Err(InactiveStreamId.into()); | ||||
|                 return Err(InactiveStreamId); | ||||
|             } else { | ||||
|                 return Err(UnexpectedFrameType.into()); | ||||
|                 return Err(UnexpectedFrameType); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -115,7 +120,7 @@ impl<B, P> Prioritize<B, P> | ||||
|         } | ||||
|  | ||||
|         if frame.is_end_stream() { | ||||
|             try!(stream.state.send_close()); | ||||
|             stream.state.send_close(); | ||||
|         } | ||||
|  | ||||
|         trace!("send_data (2); available={}; buffered={}", | ||||
| @@ -161,7 +166,7 @@ impl<B, P> Prioritize<B, P> | ||||
|     pub fn recv_stream_window_update(&mut self, | ||||
|                                      inc: WindowSize, | ||||
|                                      stream: &mut store::Ptr<B, P>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), Reason> | ||||
|     { | ||||
|         trace!("recv_stream_window_update; stream={:?}; state={:?}; inc={}; flow={:?}", | ||||
|                stream.id, stream.state, inc, stream.send_flow); | ||||
| @@ -179,7 +184,7 @@ impl<B, P> Prioritize<B, P> | ||||
|     pub fn recv_connection_window_update(&mut self, | ||||
|                                          inc: WindowSize, | ||||
|                                          store: &mut Store<B, P>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), Reason> | ||||
|     { | ||||
|         // Update the connection's window | ||||
|         self.flow.inc_window(inc)?; | ||||
| @@ -284,7 +289,7 @@ impl<B, P> Prioritize<B, P> | ||||
|     pub fn poll_complete<T>(&mut self, | ||||
|                             store: &mut Store<B, P>, | ||||
|                             dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         // Ensure codec is ready | ||||
| @@ -303,22 +308,17 @@ impl<B, P> Prioritize<B, P> | ||||
|                 Some(frame) => { | ||||
|                     trace!("writing frame={:?}", frame); | ||||
|  | ||||
|                     let res = dst.start_send(frame)?; | ||||
|  | ||||
|                     // We already verified that `dst` is ready to accept the | ||||
|                     // write | ||||
|                     assert!(res.is_ready()); | ||||
|                     dst.buffer(frame).ok().expect("invalid frame"); | ||||
|  | ||||
|                     // Ensure the codec is ready to try the loop again. | ||||
|                     try_ready!(dst.poll_ready()); | ||||
|  | ||||
|                     // Because, always try to reclaim... | ||||
|                     self.reclaim_frame(store, dst); | ||||
|  | ||||
|                 } | ||||
|                 None => { | ||||
|                     // Try to flush the codec. | ||||
|                     try_ready!(dst.poll_complete()); | ||||
|                     try_ready!(dst.flush()); | ||||
|  | ||||
|                     // This might release a data frame... | ||||
|                     if !self.reclaim_frame(store, dst) { | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| use {client, server, frame, HeaderMap, ConnectionError}; | ||||
| use {client, server, frame, proto}; | ||||
| use frame::Reason; | ||||
| use codec::{RecvError, UserError}; | ||||
| use proto::*; | ||||
| use super::*; | ||||
|  | ||||
| use error::Reason::*; | ||||
| use futures::Sink; | ||||
| use http::HeaderMap; | ||||
|  | ||||
| use std::io; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| @@ -41,14 +43,14 @@ pub(super) struct Recv<B, P> | ||||
|     /// Refused StreamId, this represents a frame that must be sent out. | ||||
|     refused: Option<StreamId>, | ||||
|  | ||||
|     _p: PhantomData<(B)>, | ||||
|     _p: PhantomData<B>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(super) enum Event<T> { | ||||
|     Headers(T), | ||||
|     Data(Bytes), | ||||
|     Trailers(::HeaderMap), | ||||
|     Trailers(HeaderMap), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| @@ -103,7 +105,7 @@ impl<B, P> Recv<B, P> | ||||
|     /// | ||||
|     /// Returns the stream state if successful. `None` if refused | ||||
|     pub fn open(&mut self, id: StreamId) | ||||
|         -> Result<Option<StreamId>, ConnectionError> | ||||
|         -> Result<Option<StreamId>, RecvError> | ||||
|     { | ||||
|         assert!(self.refused.is_none()); | ||||
|  | ||||
| @@ -123,7 +125,7 @@ impl<B, P> Recv<B, P> | ||||
|     pub fn recv_headers(&mut self, | ||||
|                         frame: frame::Headers, | ||||
|                         stream: &mut store::Ptr<B, P>) | ||||
|         -> Result<(), ProtoError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         trace!("opening stream; init_window={}", self.init_window_sz); | ||||
|         let is_initial = stream.state.recv_open(frame.is_end_stream())?; | ||||
| @@ -137,7 +139,7 @@ impl<B, P> Recv<B, P> | ||||
|                 self.next_stream_id = frame.stream_id(); | ||||
|                 self.next_stream_id.increment(); | ||||
|             } else { | ||||
|                 return Err(ProtoError::Connection(ProtocolError)); | ||||
|                 return Err(RecvError::Connection(ProtocolError)); | ||||
|             } | ||||
|  | ||||
|             // TODO: be smarter about this logic | ||||
| @@ -184,13 +186,13 @@ impl<B, P> Recv<B, P> | ||||
|     pub fn recv_trailers(&mut self, | ||||
|                          frame: frame::Headers, | ||||
|                          stream: &mut store::Ptr<B, P>) | ||||
|         -> Result<(), ProtoError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         // Transition the state | ||||
|         stream.state.recv_close()?; | ||||
|  | ||||
|         if stream.ensure_content_length_zero().is_err() { | ||||
|             return Err(ProtoError::Stream { | ||||
|             return Err(RecvError::Stream { | ||||
|                 id: stream.id, | ||||
|                 reason: ProtocolError, | ||||
|             }); | ||||
| @@ -205,11 +207,12 @@ impl<B, P> Recv<B, P> | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Releases capacity back to the connection | ||||
|     pub fn release_capacity(&mut self, | ||||
|                             capacity: WindowSize, | ||||
|                             stream: &mut store::Ptr<B, P>, | ||||
|                             task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         if capacity > stream.in_flight_recv_data { | ||||
|             // TODO: Handle error | ||||
| @@ -246,7 +249,7 @@ impl<B, P> Recv<B, P> | ||||
|     pub fn recv_data(&mut self, | ||||
|                      frame: frame::Data, | ||||
|                      stream: &mut store::Ptr<B, P>) | ||||
|         -> Result<(), ProtoError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let sz = frame.payload().len(); | ||||
|  | ||||
| @@ -259,7 +262,7 @@ impl<B, P> Recv<B, P> | ||||
|         if !stream.state.is_recv_streaming() { | ||||
|             // Receiving a DATA frame when not expecting one is a protocol | ||||
|             // error. | ||||
|             return Err(ProtoError::Connection(ProtocolError)); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         trace!("recv_data; size={}; connection={}; stream={}", | ||||
| @@ -268,7 +271,7 @@ impl<B, P> Recv<B, P> | ||||
|         // Ensure that there is enough capacity on the connection before acting | ||||
|         // on the stream. | ||||
|         if self.flow.window_size() < sz || stream.recv_flow.window_size() < sz { | ||||
|             return Err(ProtoError::Connection(FlowControlError)); | ||||
|             return Err(RecvError::Connection(FlowControlError)); | ||||
|         } | ||||
|  | ||||
|         // Update connection level flow control | ||||
| @@ -281,7 +284,7 @@ impl<B, P> Recv<B, P> | ||||
|         stream.in_flight_recv_data += sz; | ||||
|  | ||||
|         if stream.dec_content_length(frame.payload().len()).is_err() { | ||||
|             return Err(ProtoError::Stream { | ||||
|             return Err(RecvError::Stream { | ||||
|                 id: stream.id, | ||||
|                 reason: ProtocolError, | ||||
|             }); | ||||
| @@ -289,14 +292,14 @@ impl<B, P> Recv<B, P> | ||||
|  | ||||
|         if frame.is_end_stream() { | ||||
|             if stream.ensure_content_length_zero().is_err() { | ||||
|                 return Err(ProtoError::Stream { | ||||
|                 return Err(RecvError::Stream { | ||||
|                     id: stream.id, | ||||
|                     reason: ProtocolError, | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             if stream.state.recv_close().is_err() { | ||||
|                 return Err(ProtoError::Connection(ProtocolError)); | ||||
|                 return Err(RecvError::Connection(ProtocolError)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -314,13 +317,14 @@ impl<B, P> Recv<B, P> | ||||
|                              send: &Send<B, P>, | ||||
|                              stream: store::Key, | ||||
|                              store: &mut Store<B, P>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         // First, make sure that the values are legit | ||||
|         self.ensure_can_reserve(frame.promised_id())?; | ||||
|  | ||||
|         // Make sure that the stream state is valid | ||||
|         store[stream].state.ensure_recv_open()?; | ||||
|         store[stream].state.ensure_recv_open() | ||||
|             .map_err(|e| e.into_connection_recv_error())?; | ||||
|  | ||||
|         // TODO: Streams in the reserved states do not count towards the concurrency | ||||
|         // limit. However, it seems like there should be a cap otherwise this | ||||
| @@ -361,18 +365,19 @@ impl<B, P> Recv<B, P> | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), ConnectionError> { | ||||
|     /// Ensures that `id` is not in the `Idle` state. | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> { | ||||
|         if id >= self.next_stream_id { | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(ProtocolError); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream<B, P>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let err = ConnectionError::Proto(frame.reason()); | ||||
|         let err = proto::Error::Proto(frame.reason()); | ||||
|  | ||||
|         // Notify the stream | ||||
|         stream.state.recv_err(&err); | ||||
| @@ -381,7 +386,7 @@ impl<B, P> Recv<B, P> | ||||
|     } | ||||
|  | ||||
|     /// Handle a received error | ||||
|     pub fn recv_err(&mut self, err: &ConnectionError, stream: &mut Stream<B, P>) { | ||||
|     pub fn recv_err(&mut self, err: &proto::Error, stream: &mut Stream<B, P>) { | ||||
|         // Receive an error | ||||
|         stream.state.recv_err(err); | ||||
|  | ||||
| @@ -415,17 +420,17 @@ impl<B, P> Recv<B, P> | ||||
|  | ||||
|     /// Returns true if the remote peer can initiate a stream with the given ID. | ||||
|     fn ensure_can_open(&self, id: StreamId) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         if !P::is_server() { | ||||
|             // Remote is a server and cannot open streams. PushPromise is | ||||
|             // registered by reserving, so does not go through this path. | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         // Ensure that the ID is a valid server initiated ID | ||||
|         if !id.is_client_initiated() { | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -433,16 +438,16 @@ impl<B, P> Recv<B, P> | ||||
|  | ||||
|     /// Returns true if the remote peer can reserve a stream with the given ID. | ||||
|     fn ensure_can_reserve(&self, promised_id: StreamId) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         // TODO: Are there other rules? | ||||
|         if P::is_server() { | ||||
|             // The remote is a client and cannot reserve | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         if !promised_id.is_server_initiated() { | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -450,31 +455,28 @@ impl<B, P> Recv<B, P> | ||||
|  | ||||
|     /// Send any pending refusals. | ||||
|     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         if let Some(stream_id) = self.refused.take() { | ||||
|         if let Some(stream_id) = self.refused { | ||||
|             try_ready!(dst.poll_ready()); | ||||
|  | ||||
|             // Create the RST_STREAM frame | ||||
|             let frame = frame::Reset::new(stream_id, RefusedStream); | ||||
|  | ||||
|             match dst.start_send(frame.into())? { | ||||
|                 AsyncSink::Ready => { | ||||
|                     self.reset(stream_id, RefusedStream); | ||||
|                     return Ok(Async::Ready(())); | ||||
|                 } | ||||
|                 AsyncSink::NotReady(_) => { | ||||
|                     self.refused = Some(stream_id); | ||||
|                     return Ok(Async::NotReady); | ||||
|                 } | ||||
|             } | ||||
|             // Buffer the frame | ||||
|             dst.buffer(frame.into()).ok().expect("invalid RST_STREAM frame"); | ||||
|         } | ||||
|  | ||||
|         self.refused = None; | ||||
|  | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
|  | ||||
|     pub fn poll_complete<T>(&mut self, | ||||
|                             store: &mut Store<B, P>, | ||||
|                             dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         // Send any pending connection level window updates | ||||
| @@ -488,7 +490,7 @@ impl<B, P> Recv<B, P> | ||||
|  | ||||
|     /// Send connection level window update | ||||
|     fn send_connection_window_update<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         let incr = self.flow.unclaimed_capacity(); | ||||
| @@ -496,11 +498,14 @@ impl<B, P> Recv<B, P> | ||||
|         if incr > 0 { | ||||
|             let frame = frame::WindowUpdate::new(StreamId::zero(), incr); | ||||
|  | ||||
|             if dst.start_send(frame.into())?.is_ready() { | ||||
|                 self.flow.inc_window(incr).ok().expect("unexpected flow control state"); | ||||
|             } else { | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|             // Ensure the codec has capacity | ||||
|             try_ready!(dst.poll_ready()); | ||||
|  | ||||
|             // Buffer the WINDOW_UPDATE frame | ||||
|             dst.buffer(frame.into()).ok().expect("invalid WINDOW_UPDATE frame"); | ||||
|  | ||||
|             // Update flow control | ||||
|             self.flow.inc_window(incr).ok().expect("unexpected flow control state"); | ||||
|         } | ||||
|  | ||||
|         Ok(().into()) | ||||
| @@ -511,7 +516,7 @@ impl<B, P> Recv<B, P> | ||||
|     pub fn send_stream_window_updates<T>(&mut self, | ||||
|                                          store: &mut Store<B, P>, | ||||
|                                          dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         loop { | ||||
| @@ -534,10 +539,11 @@ impl<B, P> Recv<B, P> | ||||
|             let incr = stream.recv_flow.unclaimed_capacity(); | ||||
|  | ||||
|             if incr > 0 { | ||||
|                 // Create the WINDOW_UPDATE frame | ||||
|                 let frame = frame::WindowUpdate::new(stream.id, incr); | ||||
|                 let res = dst.start_send(frame.into())?; | ||||
|  | ||||
|                 assert!(res.is_ready()); | ||||
|                 // Buffer it | ||||
|                 dst.buffer(frame.into()).ok().expect("invalid WINDOW_UPDATE frame"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -548,8 +554,9 @@ impl<B, P> Recv<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn poll_data(&mut self, stream: &mut Stream<B, P>) | ||||
|         -> Poll<Option<Bytes>, ConnectionError> | ||||
|         -> Poll<Option<Bytes>, proto::Error> | ||||
|     { | ||||
|         // TODO: Return error when the stream is reset | ||||
|         match stream.pending_recv.pop_front(&mut self.buffer) { | ||||
|             Some(Event::Data(payload)) => { | ||||
|                 Ok(Some(payload).into()) | ||||
| @@ -575,7 +582,7 @@ impl<B, P> Recv<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn poll_trailers(&mut self, stream: &mut Stream<B, P>) | ||||
|         -> Poll<Option<HeaderMap>, ConnectionError> | ||||
|         -> Poll<Option<HeaderMap>, proto::Error> | ||||
|     { | ||||
|         match stream.pending_recv.pop_front(&mut self.buffer) { | ||||
|             Some(Event::Trailers(trailers)) => { | ||||
| @@ -599,10 +606,6 @@ impl<B, P> Recv<B, P> | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn reset(&mut self, _stream_id: StreamId, _reason: Reason) { | ||||
|         unimplemented!(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Recv<B, server::Peer> | ||||
| @@ -610,15 +613,10 @@ impl<B> Recv<B, server::Peer> | ||||
| { | ||||
|     /// TODO: Should this fn return `Result`? | ||||
|     pub fn take_request(&mut self, stream: &mut store::Ptr<B, server::Peer>) | ||||
|         -> Result<Request<()>, ConnectionError> | ||||
|         -> Request<()> | ||||
|     { | ||||
|         match stream.pending_recv.pop_front(&mut self.buffer) { | ||||
|             Some(Event::Headers(request)) => Ok(request), | ||||
|                 /* | ||||
|                 // TODO: This error should probably be caught on receipt of the | ||||
|                 // frame vs. now. | ||||
|                 Ok(server::Peer::convert_poll_message(frame)?) | ||||
|                 */ | ||||
|             Some(Event::Headers(request)) => request, | ||||
|             _ => panic!(), | ||||
|         } | ||||
|     } | ||||
| @@ -628,7 +626,7 @@ impl<B> Recv<B, client::Peer> | ||||
|     where B: Buf, | ||||
| { | ||||
|     pub fn poll_response(&mut self, stream: &mut store::Ptr<B, client::Peer>) | ||||
|         -> Poll<Response<()>, ConnectionError> { | ||||
|         -> Poll<Response<()>, proto::Error> { | ||||
|         // If the buffer is not empty, then the first frame must be a HEADERS | ||||
|         // frame or the user violated the contract. | ||||
|         match stream.pending_recv.pop_front(&mut self.buffer) { | ||||
|   | ||||
| @@ -1,11 +1,14 @@ | ||||
| use {frame, ConnectionError}; | ||||
| use client; | ||||
| use frame::{self, Reason}; | ||||
| use codec::{RecvError, UserError}; | ||||
| use codec::UserError::*; | ||||
| use proto::*; | ||||
| use super::*; | ||||
|  | ||||
| use error::User::*; | ||||
|  | ||||
| use bytes::Buf; | ||||
|  | ||||
| use std::io; | ||||
|  | ||||
| /// Manages state transitions related to outbound frames. | ||||
| #[derive(Debug)] | ||||
| pub(super) struct Send<B, P> | ||||
| @@ -53,24 +56,11 @@ where B: Buf, | ||||
|         self.init_window_sz | ||||
|     } | ||||
|  | ||||
|     pub fn poll_open_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         try!(self.ensure_can_open()); | ||||
|  | ||||
|         if let Some(max) = self.max_streams { | ||||
|             if max <= self.num_streams { | ||||
|                 self.blocked_open = Some(task::current()); | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return Ok(Async::Ready(())); | ||||
|     } | ||||
|  | ||||
|     /// Update state reflecting a new, locally opened stream | ||||
|     /// | ||||
|     /// Returns the stream state if successful. `None` if refused | ||||
|     pub fn open(&mut self) | ||||
|         -> Result<StreamId, ConnectionError> | ||||
|         -> Result<StreamId, UserError> | ||||
|     { | ||||
|         try!(self.ensure_can_open()); | ||||
|  | ||||
| @@ -93,7 +83,7 @@ where B: Buf, | ||||
|                         frame: frame::Headers, | ||||
|                         stream: &mut store::Ptr<B, P>, | ||||
|                         task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         trace!("send_headers; frame={:?}; init_window={:?}", frame, self.init_window_sz); | ||||
|         // Update the state | ||||
| @@ -145,7 +135,7 @@ where B: Buf, | ||||
|                      frame: frame::Data<B>, | ||||
|                      stream: &mut store::Ptr<B, P>, | ||||
|                      task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         self.prioritize.send_data(frame, stream, task) | ||||
|     } | ||||
| @@ -154,14 +144,14 @@ where B: Buf, | ||||
|                          frame: frame::Headers, | ||||
|                          stream: &mut store::Ptr<B, P>, | ||||
|                          task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         // TODO: Should this logic be moved into state.rs? | ||||
|         if !stream.state.is_send_streaming() { | ||||
|             return Err(UnexpectedFrameType.into()); | ||||
|         } | ||||
|  | ||||
|         stream.state.send_close()?; | ||||
|         stream.state.send_close(); | ||||
|  | ||||
|         trace!("send_trailers -- queuing; frame={:?}", frame); | ||||
|         self.prioritize.queue_frame(frame.into(), stream, task); | ||||
| @@ -172,7 +162,7 @@ where B: Buf, | ||||
|     pub fn poll_complete<T>(&mut self, | ||||
|                             store: &mut Store<B, P>, | ||||
|                             dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         self.prioritize.poll_complete(store, dst) | ||||
| @@ -184,7 +174,7 @@ where B: Buf, | ||||
|     } | ||||
|  | ||||
|     pub fn poll_capacity(&mut self, stream: &mut store::Ptr<B, P>) | ||||
|         -> Poll<Option<WindowSize>, ConnectionError> | ||||
|         -> Poll<Option<WindowSize>, UserError> | ||||
|     { | ||||
|         if !stream.state.is_send_streaming() { | ||||
|             return Ok(Async::Ready(None)); | ||||
| @@ -214,7 +204,7 @@ where B: Buf, | ||||
|     pub fn recv_connection_window_update(&mut self, | ||||
|                                          frame: frame::WindowUpdate, | ||||
|                                          store: &mut Store<B, P>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), Reason> | ||||
|     { | ||||
|         self.prioritize.recv_connection_window_update(frame.size_increment(), store) | ||||
|     } | ||||
| @@ -223,11 +213,13 @@ where B: Buf, | ||||
|                                      sz: WindowSize, | ||||
|                                      stream: &mut store::Ptr<B, P>, | ||||
|                                      task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), Reason> | ||||
|     { | ||||
|         if let Err(e) = self.prioritize.recv_stream_window_update(sz, stream) { | ||||
|             debug!("recv_stream_window_update !!; err={:?}", e); | ||||
|             self.send_reset(FlowControlError.into(), stream, task); | ||||
|  | ||||
|             return Err(e); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -237,7 +229,7 @@ where B: Buf, | ||||
|                                  settings: &frame::Settings, | ||||
|                                  store: &mut Store<B, P>, | ||||
|                                  task: &mut Option<Task>) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         if let Some(val) = settings.max_concurrent_streams() { | ||||
|             self.max_streams = Some(val as usize); | ||||
| @@ -283,13 +275,14 @@ where B: Buf, | ||||
|  | ||||
|                     // TODO: Should this notify the producer? | ||||
|  | ||||
|                     Ok(()) | ||||
|                     Ok::<_, RecvError>(()) | ||||
|                 })?; | ||||
|             } else if val > old_val { | ||||
|                 let inc = val - old_val; | ||||
|  | ||||
|                 store.for_each(|mut stream| { | ||||
|                     self.recv_stream_window_update(inc, &mut stream, task) | ||||
|                         .map_err(RecvError::Connection) | ||||
|                 })?; | ||||
|             } | ||||
|         } | ||||
| @@ -297,9 +290,9 @@ where B: Buf, | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), ConnectionError> { | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> { | ||||
|         if id >= self.next_stream_id { | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(ProtocolError); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -316,10 +309,10 @@ where B: Buf, | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the local actor can initiate a stream with the given ID. | ||||
|     fn ensure_can_open(&self) -> Result<(), ConnectionError> { | ||||
|     fn ensure_can_open(&self) -> Result<(), UserError> { | ||||
|         if P::is_server() { | ||||
|             // Servers cannot open streams. PushPromise must first be reserved. | ||||
|             return Err(UnexpectedFrameType.into()); | ||||
|             return Err(UnexpectedFrameType); | ||||
|         } | ||||
|  | ||||
|         // TODO: Handle StreamId overflow | ||||
| @@ -327,3 +320,18 @@ where B: Buf, | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Send<B, client::Peer> | ||||
| where B: Buf, | ||||
| { | ||||
|     pub fn poll_open_ready(&mut self) -> Async<()> { | ||||
|         if let Some(max) = self.max_streams { | ||||
|             if max <= self.num_streams { | ||||
|                 self.blocked_open = Some(task::current()); | ||||
|                 return Async::NotReady; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return Async::Ready(()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| use ConnectionError; | ||||
| use proto::ProtoError; | ||||
| use error::Reason; | ||||
| use error::Reason::*; | ||||
| use error::User::*; | ||||
| use frame::Reason; | ||||
| use frame::Reason::*; | ||||
| use codec::{RecvError, UserError}; | ||||
| use codec::UserError::*; | ||||
| use proto; | ||||
|  | ||||
| use self::Inner::*; | ||||
| use self::Peer::*; | ||||
| @@ -82,7 +82,7 @@ enum Cause { | ||||
|  | ||||
| impl State { | ||||
|     /// Opens the send-half of a stream if it is not already open. | ||||
|     pub fn send_open(&mut self, eos: bool) -> Result<(), ConnectionError> { | ||||
|     pub fn send_open(&mut self, eos: bool) -> Result<(), UserError> { | ||||
|         let local = Peer::Streaming; | ||||
|  | ||||
|         self.inner = match self.inner { | ||||
| @@ -115,7 +115,7 @@ impl State { | ||||
|             } | ||||
|             _ => { | ||||
|                 // All other transitions result in a protocol error | ||||
|                 return Err(UnexpectedFrameType.into()); | ||||
|                 return Err(UnexpectedFrameType); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
| @@ -126,7 +126,7 @@ impl State { | ||||
|     /// frame is received. | ||||
|     /// | ||||
|     /// Returns true if this transitions the state to Open | ||||
|     pub fn recv_open(&mut self, eos: bool) -> Result<bool, ProtoError> { | ||||
|     pub fn recv_open(&mut self, eos: bool) -> Result<bool, RecvError> { | ||||
|         let remote = Peer::Streaming; | ||||
|         let mut initial = false; | ||||
|  | ||||
| @@ -174,7 +174,7 @@ impl State { | ||||
|             } | ||||
|             _ => { | ||||
|                 // All other transitions result in a protocol error | ||||
|                 return Err(ProtoError::Connection(ProtocolError)); | ||||
|                 return Err(RecvError::Connection(ProtocolError)); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
| @@ -182,18 +182,18 @@ impl State { | ||||
|     } | ||||
|  | ||||
|     /// Transition from Idle -> ReservedRemote | ||||
|     pub fn reserve_remote(&mut self) -> Result<(), ConnectionError> { | ||||
|     pub fn reserve_remote(&mut self) -> Result<(), RecvError> { | ||||
|         match self.inner { | ||||
|             Idle => { | ||||
|                 self.inner = ReservedRemote; | ||||
|                 Ok(()) | ||||
|             } | ||||
|             _ => Err(ProtocolError.into()), | ||||
|             _ => Err(RecvError::Connection(ProtocolError)), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Indicates that the remote side will not send more data to the local. | ||||
|     pub fn recv_close(&mut self) -> Result<(), ProtoError> { | ||||
|     pub fn recv_close(&mut self) -> Result<(), RecvError> { | ||||
|         match self.inner { | ||||
|             Open { local, .. } => { | ||||
|                 // The remote side will continue to receive data. | ||||
| @@ -206,39 +206,38 @@ impl State { | ||||
|                 self.inner = Closed(None); | ||||
|                 Ok(()) | ||||
|             } | ||||
|             _ => Err(ProtoError::Connection(ProtocolError)), | ||||
|             _ => Err(RecvError::Connection(ProtocolError)), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn recv_err(&mut self, err: &ConnectionError) { | ||||
|     pub fn recv_err(&mut self, err: &proto::Error) { | ||||
|         use proto::Error::*; | ||||
|  | ||||
|         match self.inner { | ||||
|             Closed(..) => {} | ||||
|             _ => { | ||||
|                 trace!("recv_err; err={:?}", err); | ||||
|                 self.inner = Closed(match *err { | ||||
|                     ConnectionError::Proto(reason) => Some(Cause::Proto(reason)), | ||||
|                     ConnectionError::Io(..) => Some(Cause::Io), | ||||
|                     ref e => panic!("cannot terminate stream with user error; err={:?}", e), | ||||
|                     Proto(reason) => Some(Cause::Proto(reason)), | ||||
|                     Io(..) => Some(Cause::Io), | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Indicates that the local side will not send more data to the local. | ||||
|     pub fn send_close(&mut self) -> Result<(), ConnectionError> { | ||||
|     pub fn send_close(&mut self) { | ||||
|         match self.inner { | ||||
|             Open { remote, .. } => { | ||||
|                 // The remote side will continue to receive data. | ||||
|                 trace!("send_close: Open => HalfClosedLocal({:?})", remote); | ||||
|                 self.inner = HalfClosedLocal(remote); | ||||
|                 Ok(()) | ||||
|             } | ||||
|             HalfClosedRemote(..) => { | ||||
|                 trace!("send_close: HalfClosedRemote => Closed"); | ||||
|                 self.inner = Closed(None); | ||||
|                 Ok(()) | ||||
|             } | ||||
|             _ => Err(ProtocolError.into()), | ||||
|             _ => panic!("transition send_close on unexpected state"), | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -307,16 +306,16 @@ impl State { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn ensure_recv_open(&self) -> Result<(), ConnectionError> { | ||||
|     pub fn ensure_recv_open(&self) -> Result<(), proto::Error> { | ||||
|         use std::io; | ||||
|  | ||||
|         // TODO: Is this correct? | ||||
|         match self.inner { | ||||
|             Closed(Some(Cause::Proto(reason))) => { | ||||
|                 Err(ConnectionError::Proto(reason)) | ||||
|                 Err(proto::Error::Proto(reason)) | ||||
|             } | ||||
|             Closed(Some(Cause::Io)) => { | ||||
|                 Err(ConnectionError::Io(io::ErrorKind::BrokenPipe.into())) | ||||
|                 Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())) | ||||
|             } | ||||
|             _ => Ok(()), | ||||
|         } | ||||
|   | ||||
| @@ -127,8 +127,8 @@ impl<B, P> Store<B, P> | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn for_each<F>(&mut self, mut f: F) -> Result<(), ConnectionError> | ||||
|         where F: FnMut(Ptr<B, P>) -> Result<(), ConnectionError>, | ||||
|     pub fn for_each<F, E>(&mut self, mut f: F) -> Result<(), E> | ||||
|         where F: FnMut(Ptr<B, P>) -> Result<(), E>, | ||||
|     { | ||||
|         for &key in self.ids.values() { | ||||
|             f(Ptr { | ||||
|   | ||||
| @@ -1,8 +1,13 @@ | ||||
| use {client, server, HeaderMap}; | ||||
| use {client, server, proto}; | ||||
| use frame::Reason; | ||||
| use codec::{SendError, RecvError, UserError}; | ||||
| use proto::*; | ||||
| use super::*; | ||||
| use super::store::Resolve; | ||||
|  | ||||
| use http::HeaderMap; | ||||
|  | ||||
| use std::io; | ||||
| use std::sync::{Arc, Mutex}; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| @@ -66,7 +71,7 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|     /// Process inbound headers | ||||
|     pub fn recv_headers(&mut self, frame: frame::Headers) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let id = frame.stream_id(); | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
| @@ -97,7 +102,7 @@ impl<B, P> Streams<B, P> | ||||
|             } else { | ||||
|                 if !frame.is_end_stream() { | ||||
|                     // TODO: Is this the right error | ||||
|                     return Err(ProtocolError.into()); | ||||
|                     return Err(RecvError::Connection(ProtocolError)); | ||||
|                 } | ||||
|  | ||||
|                 actions.recv.recv_trailers(frame, stream) | ||||
| @@ -105,20 +110,18 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|             // TODO: extract this | ||||
|             match res { | ||||
|                 Ok(()) => Ok(()), | ||||
|                 Err(ProtoError::Connection(reason)) => Err(reason.into()), | ||||
|                 Err(ProtoError::Stream { reason, .. }) => { | ||||
|                 Err(RecvError::Stream { reason, .. }) => { | ||||
|                     // Reset the stream. | ||||
|                     actions.send.send_reset(reason, stream, &mut actions.task); | ||||
|                     Ok(()) | ||||
|                 } | ||||
|                 Err(ProtoError::Io(_)) => unreachable!(), | ||||
|                 res => res, | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn recv_data(&mut self, frame: frame::Data) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -127,25 +130,23 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|         let stream = match me.store.find_mut(&id) { | ||||
|             Some(stream) => stream, | ||||
|             None => return Err(ProtocolError.into()), | ||||
|             None => return Err(RecvError::Connection(ProtocolError)), | ||||
|         }; | ||||
|  | ||||
|         me.actions.transition(stream, |actions, stream| { | ||||
|             match actions.recv.recv_data(frame, stream) { | ||||
|                 Ok(()) => Ok(()), | ||||
|                 Err(ProtoError::Connection(reason)) => Err(reason.into()), | ||||
|                 Err(ProtoError::Stream { reason, .. }) => { | ||||
|                 Err(RecvError::Stream { reason, .. }) => { | ||||
|                     // Reset the stream. | ||||
|                     actions.send.send_reset(reason, stream, &mut actions.task); | ||||
|                     Ok(()) | ||||
|                 } | ||||
|                 Err(ProtoError::Io(_)) => unreachable!(), | ||||
|                 res => res, | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn recv_reset(&mut self, frame: frame::Reset) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -153,14 +154,16 @@ impl<B, P> Streams<B, P> | ||||
|         let id = frame.stream_id(); | ||||
|  | ||||
|         if id.is_zero() { | ||||
|             return Err(ProtocolError.into()); | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         let stream = match me.store.find_mut(&id) { | ||||
|             Some(stream) => stream, | ||||
|             None => { | ||||
|                 // TODO: Are there other error cases? | ||||
|                 me.actions.ensure_not_idle(id)?; | ||||
|                 me.actions.ensure_not_idle(id) | ||||
|                     .map_err(RecvError::Connection)?; | ||||
|  | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         }; | ||||
| @@ -173,7 +176,7 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
|  | ||||
|     /// Handle a received error and return the ID of the last processed stream. | ||||
|     pub fn recv_err(&mut self, err: &ConnectionError) -> StreamId { | ||||
|     pub fn recv_err(&mut self, err: &proto::Error) -> StreamId { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -182,14 +185,14 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|         me.store.for_each(|mut stream| { | ||||
|             actions.recv.recv_err(err, &mut *stream); | ||||
|             Ok(()) | ||||
|             Ok::<_, ()>(()) | ||||
|         }).ok().expect("unexpected error processing error"); | ||||
|  | ||||
|         last_processed_id | ||||
|     } | ||||
|  | ||||
|     pub fn recv_window_update(&mut self, frame: frame::WindowUpdate) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let id = frame.stream_id(); | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
| @@ -197,15 +200,22 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|         if id.is_zero() { | ||||
|             me.actions.send.recv_connection_window_update( | ||||
|                 frame, &mut me.store)?; | ||||
|                 frame, &mut me.store) | ||||
|                 .map_err(RecvError::Connection)?; | ||||
|         } else { | ||||
|             // The remote may send window updates for streams that the local now | ||||
|             // considers closed. It's ok... | ||||
|             if let Some(mut stream) = me.store.find_mut(&id) { | ||||
|                 me.actions.send.recv_stream_window_update( | ||||
|                     frame.size_increment(), &mut stream, &mut me.actions.task)?; | ||||
|                 // This result is ignored as there is nothing to do when there | ||||
|                 // is an error. The stream is reset by the function on error and | ||||
|                 // the error is informational. | ||||
|                 let _ = me.actions.send.recv_stream_window_update( | ||||
|                     frame.size_increment(), | ||||
|                     &mut stream, | ||||
|                     &mut me.actions.task); | ||||
|             } else { | ||||
|                 me.actions.recv.ensure_not_idle(id)?; | ||||
|                 me.actions.recv.ensure_not_idle(id) | ||||
|                     .map_err(RecvError::Connection)?; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -213,7 +223,7 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn recv_push_promise(&mut self, frame: frame::PushPromise) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -222,7 +232,7 @@ impl<B, P> Streams<B, P> | ||||
|  | ||||
|         let stream = match me.store.find_mut(&id) { | ||||
|             Some(stream) => stream.key(), | ||||
|             None => return Err(ProtocolError.into()), | ||||
|             None => return Err(RecvError::Connection(ProtocolError)), | ||||
|         }; | ||||
|  | ||||
|         me.actions.recv.recv_push_promise( | ||||
| @@ -246,7 +256,7 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
| @@ -255,7 +265,7 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||
|         -> Poll<(), ConnectionError> | ||||
|         -> Poll<(), io::Error> | ||||
|         where T: AsyncWrite, | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
| @@ -277,7 +287,7 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn apply_remote_settings(&mut self, frame: &frame::Settings) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), RecvError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -286,15 +296,8 @@ impl<B, P> Streams<B, P> | ||||
|             frame, &mut me.store, &mut me.actions.task) | ||||
|     } | ||||
|  | ||||
|     pub fn poll_send_request_ready(&mut self) -> Poll<(), ConnectionError> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
|         me.actions.send.poll_open_ready() | ||||
|     } | ||||
|  | ||||
|     pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool) | ||||
|         -> Result<StreamRef<B, P>, ConnectionError> | ||||
|         -> Result<StreamRef<B, P>, SendError> | ||||
|     { | ||||
|         use http::method; | ||||
|         use super::stream::ContentLength; | ||||
| @@ -370,6 +373,17 @@ impl<B, P> Streams<B, P> | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Streams<B, client::Peer> | ||||
|     where B: Buf, | ||||
| { | ||||
|     pub fn poll_send_request_ready(&mut self) -> Async<()> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
|         me.actions.send.poll_open_ready() | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl StreamRef ===== | ||||
|  | ||||
| impl<B, P> StreamRef<B, P> | ||||
| @@ -377,7 +391,7 @@ impl<B, P> StreamRef<B, P> | ||||
|           P: Peer, | ||||
| { | ||||
|     pub fn send_data(&mut self, data: B, end_of_stream: bool) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -393,7 +407,8 @@ impl<B, P> StreamRef<B, P> | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), ConnectionError> | ||||
|     pub fn send_trailers(&mut self, trailers: HeaderMap) | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -420,7 +435,7 @@ impl<B, P> StreamRef<B, P> | ||||
|     } | ||||
|  | ||||
|     pub fn send_response(&mut self, response: Response<()>, end_of_stream: bool) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -444,7 +459,7 @@ impl<B, P> StreamRef<B, P> | ||||
|         me.actions.recv.body_is_empty(&stream) | ||||
|     } | ||||
|  | ||||
|     pub fn poll_data(&mut self) -> Poll<Option<Bytes>, ConnectionError> { | ||||
|     pub fn poll_data(&mut self) -> Poll<Option<Bytes>, proto::Error> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -453,7 +468,7 @@ impl<B, P> StreamRef<B, P> | ||||
|         me.actions.recv.poll_data(&mut stream) | ||||
|     } | ||||
|  | ||||
|     pub fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, ConnectionError> { | ||||
|     pub fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, proto::Error> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -465,7 +480,7 @@ impl<B, P> StreamRef<B, P> | ||||
|     /// Releases recv capacity back to the peer. This will result in sending | ||||
|     /// WINDOW_UPDATE frames on both the stream and connection. | ||||
|     pub fn release_capacity(&mut self, capacity: WindowSize) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), UserError> | ||||
|     { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
| @@ -497,7 +512,7 @@ impl<B, P> StreamRef<B, P> | ||||
|     } | ||||
|  | ||||
|     /// Request to be notified when the stream's capacity increases | ||||
|     pub fn poll_capacity(&mut self) -> Poll<Option<WindowSize>, ConnectionError> { | ||||
|     pub fn poll_capacity(&mut self) -> Poll<Option<WindowSize>, UserError> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -517,7 +532,7 @@ impl<B> StreamRef<B, server::Peer> | ||||
|     /// # Panics | ||||
|     /// | ||||
|     /// This function panics if the request isn't present. | ||||
|     pub fn take_request(&self) -> Result<Request<()>, ConnectionError> { | ||||
|     pub fn take_request(&self) -> Request<()> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -529,7 +544,7 @@ impl<B> StreamRef<B, server::Peer> | ||||
| impl<B> StreamRef<B, client::Peer> | ||||
|     where B: Buf, | ||||
| { | ||||
|     pub fn poll_response(&mut self) -> Poll<Response<()>, ConnectionError> { | ||||
|     pub fn poll_response(&mut self) -> Poll<Response<()>, proto::Error> { | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
| @@ -557,7 +572,7 @@ impl<B, P> Actions<B, P> | ||||
|           P: Peer, | ||||
| { | ||||
|     fn ensure_not_idle(&mut self, id: StreamId) | ||||
|         -> Result<(), ConnectionError> | ||||
|         -> Result<(), Reason> | ||||
|     { | ||||
|         if self.is_local_init(id) { | ||||
|             self.send.ensure_not_idle(id) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user