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:
		
							
								
								
									
										121
									
								
								src/codec/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/codec/error.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| use frame::{Reason, StreamId}; | ||||
|  | ||||
| use std::{error, fmt, io}; | ||||
|  | ||||
| /// Errors that are received | ||||
| #[derive(Debug)] | ||||
| pub enum RecvError { | ||||
|     Connection(Reason), | ||||
|     Stream { | ||||
|         id: StreamId, | ||||
|         reason: Reason, | ||||
|     }, | ||||
|     Io(io::Error), | ||||
| } | ||||
|  | ||||
| /// Errors caused by sending a message | ||||
| #[derive(Debug)] | ||||
| pub enum SendError { | ||||
|     /// User error | ||||
|     User(UserError), | ||||
|  | ||||
|     /// I/O error | ||||
|     Io(io::Error), | ||||
| } | ||||
|  | ||||
| /// Errors caused by users of the library | ||||
| #[derive(Debug)] | ||||
| pub enum UserError { | ||||
|     /// The stream ID is no longer accepting frames. | ||||
|     InactiveStreamId, | ||||
|  | ||||
|     /// The stream is not currently expecting a frame of this type. | ||||
|     UnexpectedFrameType, | ||||
|  | ||||
|     /// The payload size is too big | ||||
|     PayloadTooBig, | ||||
|  | ||||
|     /// The application attempted to initiate too many streams to remote. | ||||
|     Rejected, | ||||
| } | ||||
|  | ||||
| // ===== impl RecvError ===== | ||||
|  | ||||
| impl From<io::Error> for RecvError { | ||||
|     fn from(src: io::Error) -> Self { | ||||
|         RecvError::Io(src) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl error::Error for RecvError { | ||||
|     fn description(&self) -> &str { | ||||
|         use self::RecvError::*; | ||||
|  | ||||
|         match *self { | ||||
|             Connection(ref reason) => reason.description(), | ||||
|             Stream { ref reason, .. } => reason.description(), | ||||
|             Io(ref e) => e.description(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for RecvError { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         use std::error::Error; | ||||
|         write!(fmt, "{}", self.description()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl SendError ===== | ||||
|  | ||||
| impl error::Error for SendError { | ||||
|     fn description(&self) -> &str { | ||||
|         use self::SendError::*; | ||||
|  | ||||
|         match *self { | ||||
|             User(ref e) => e.description(), | ||||
|             Io(ref e) => e.description(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for SendError { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         use std::error::Error; | ||||
|         write!(fmt, "{}", self.description()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<io::Error> for SendError { | ||||
|     fn from(src: io::Error) -> Self { | ||||
|         SendError::Io(src) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<UserError> for SendError { | ||||
|     fn from(src: UserError) -> Self { | ||||
|         SendError::User(src) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl UserError ===== | ||||
|  | ||||
| impl error::Error for UserError { | ||||
|     fn description(&self) -> &str { | ||||
|         use self::UserError::*; | ||||
|  | ||||
|         match *self { | ||||
|             InactiveStreamId => "inactive stream", | ||||
|             UnexpectedFrameType => "unexpected frame type", | ||||
|             PayloadTooBig => "payload too big", | ||||
|             Rejected => "rejected", | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for UserError { | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         use std::error::Error; | ||||
|         write!(fmt, "{}", self.description()) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										248
									
								
								src/codec/framed_read.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/codec/framed_read.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,248 @@ | ||||
| use codec::RecvError; | ||||
| use frame::{self, Frame, Kind}; | ||||
| use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE; | ||||
| use frame::Reason::*; | ||||
|  | ||||
| use hpack; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| use bytes::BytesMut; | ||||
|  | ||||
| use tokio_io::AsyncRead; | ||||
| use tokio_io::codec::length_delimited; | ||||
|  | ||||
| #[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>, RecvError> { | ||||
|         use self::RecvError::*; | ||||
|  | ||||
|         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> Stream for FramedRead<T> | ||||
|     where T: AsyncRead, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = RecvError; | ||||
|  | ||||
|     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))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										260
									
								
								src/codec/framed_write.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								src/codec/framed_write.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | ||||
| use codec::UserError; | ||||
| use codec::UserError::*; | ||||
| use frame::{self, Frame, FrameSize}; | ||||
| use hpack; | ||||
|  | ||||
| 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, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Returns `Ready` when `send` is able to accept a frame | ||||
|     /// | ||||
|     /// Calling this function may result in the current contents of the buffer | ||||
|     /// to be flushed to `T`. | ||||
|     pub fn poll_ready(&mut self) -> Poll<(), io::Error> { | ||||
|         if !self.has_capacity() { | ||||
|             // Try flushing | ||||
|             try!(self.flush()); | ||||
|  | ||||
|             if !self.has_capacity() { | ||||
|                 return Ok(Async::NotReady); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
|  | ||||
|     /// Buffer a frame. | ||||
|     /// | ||||
|     /// `poll_ready` must be called first to ensure that a frame may be | ||||
|     /// accepted. | ||||
|     pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> { | ||||
|         // Ensure that we have enough capacity to accept the write. | ||||
|         assert!(self.has_capacity()); | ||||
|  | ||||
|         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); | ||||
|                 } | ||||
|  | ||||
|                 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(()) | ||||
|     } | ||||
|  | ||||
|     /// Flush buffered data to the wire | ||||
|     pub fn flush(&mut self) -> Poll<(), io::Error> { | ||||
|         trace!("flush"); | ||||
|  | ||||
|         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(())) | ||||
|     } | ||||
|  | ||||
|     /// Close the codec | ||||
|     pub fn shutdown(&mut self) -> Poll<(), io::Error> { | ||||
|         try_ready!(self.flush()); | ||||
|         self.inner.shutdown().map_err(Into::into) | ||||
|     } | ||||
|  | ||||
|     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> { | ||||
|     /// Returns the max frame size that can be sent | ||||
|     pub fn max_frame_size(&self) -> usize { | ||||
|         self.max_frame_size as usize | ||||
|     } | ||||
|  | ||||
|     /// Apply settings received by the peer | ||||
|     pub fn apply_remote_settings(&mut self, settings: &frame::Settings) { | ||||
|         if let Some(val) = settings.max_frame_size() { | ||||
|             self.max_frame_size = val; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Retrieve the last data frame that has been sent | ||||
|     pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | ||||
|         self.last_data_frame.take() | ||||
|     } | ||||
|  | ||||
|     pub fn get_mut(&mut self) -> &mut T { | ||||
|         &mut self.inner | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										148
									
								
								src/codec/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/codec/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| mod error; | ||||
| mod framed_read; | ||||
| mod framed_write; | ||||
|  | ||||
| pub use self::error::{SendError, RecvError, UserError}; | ||||
|  | ||||
| use self::framed_read::FramedRead; | ||||
| use self::framed_write::FramedWrite; | ||||
|  | ||||
| use frame::{self, Frame, Data, Settings}; | ||||
|  | ||||
| use futures::*; | ||||
|  | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio_io::codec::length_delimited; | ||||
|  | ||||
| use bytes::Buf; | ||||
|  | ||||
| use std::io; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub struct Codec<T, B> { | ||||
|     inner: FramedRead<FramedWrite<T, B>>, | ||||
| } | ||||
|  | ||||
| impl<T, B> Codec<T, B> | ||||
|     where T: AsyncRead + AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     pub fn new(io: T) -> Self { | ||||
|         // Wrap with writer | ||||
|         let framed_write = FramedWrite::new(io); | ||||
|  | ||||
|         // Delimit the frames | ||||
|         let delimited = 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 inner = FramedRead::new(delimited); | ||||
|  | ||||
|         Codec { inner } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Codec<T, B> { | ||||
|     /// Apply a settings received from the peer | ||||
|     pub fn apply_remote_settings(&mut self, 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 fn take_last_data_frame(&mut self) -> Option<Data<B>> { | ||||
|         self.framed_write().take_last_data_frame() | ||||
|     } | ||||
|  | ||||
|     /// Returns the max frame size that can be sent to the peer | ||||
|     pub fn max_send_frame_size(&self) -> usize { | ||||
|         self.inner.get_ref().max_frame_size() | ||||
|     } | ||||
|  | ||||
|     pub fn get_mut(&mut self) -> &mut T { | ||||
|         self.inner.get_mut().get_mut() | ||||
|     } | ||||
|  | ||||
|     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: AsyncWrite, | ||||
|           B: Buf, | ||||
| { | ||||
|     /// Returns `Ready` when the codec can buffer a frame | ||||
|     pub fn poll_ready(&mut self) -> Poll<(), io::Error> { | ||||
|         self.framed_write().poll_ready() | ||||
|     } | ||||
|  | ||||
|     /// Buffer a frame. | ||||
|     /// | ||||
|     /// `poll_ready` must be called first to ensure that a frame may be | ||||
|     /// accepted. | ||||
|     /// | ||||
|     /// TODO: Rename this to avoid conflicts with Sink::buffer | ||||
|     pub fn buffer(&mut self, item: Frame<B>) -> Result<(), UserError> | ||||
|     { | ||||
|         self.framed_write().buffer(item) | ||||
|     } | ||||
|  | ||||
|     /// Flush buffered data to the wire | ||||
|     pub fn flush(&mut self) -> Poll<(), io::Error> { | ||||
|         self.framed_write().flush() | ||||
|     } | ||||
|  | ||||
|     /// Shutdown the send half | ||||
|     pub fn shutdown(&mut self) -> Poll<(), io::Error> { | ||||
|         self.framed_write().shutdown() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T, B> Stream for Codec<T, B> | ||||
|     where T: AsyncRead, | ||||
| { | ||||
|     type Item = Frame; | ||||
|     type Error = RecvError; | ||||
|  | ||||
|     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 = SendError; | ||||
|  | ||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> { | ||||
|         if !self.poll_ready()?.is_ready() { | ||||
|             return Ok(AsyncSink::NotReady(item)); | ||||
|         } | ||||
|  | ||||
|         self.buffer(item)?; | ||||
|         Ok(AsyncSink::Ready) | ||||
|     } | ||||
|  | ||||
|     fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { | ||||
|         self.flush()?; | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
|  | ||||
|     fn close(&mut self) -> Poll<(), Self::SinkError> { | ||||
|         self.shutdown()?; | ||||
|         Ok(Async::Ready(())) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user