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:
Carl Lerche
2017-09-02 11:12:50 -07:00
committed by GitHub
parent 6fd9674759
commit c122e97127
37 changed files with 1043 additions and 1027 deletions

View File

@@ -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(()),
}