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,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(()),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user