ignore received frames on a stream locally reset for some time (#174)
- Adds config duration for how long to ignore frames on a reset stream - Adds config for how many reset streams can be held at a time
This commit is contained in:
@@ -60,8 +60,7 @@ enum Inner {
|
||||
Open { local: Peer, remote: Peer },
|
||||
HalfClosedLocal(Peer), // TODO: explicitly name this value
|
||||
HalfClosedRemote(Peer),
|
||||
// When reset, a reason is provided
|
||||
Closed(Option<Cause>),
|
||||
Closed(Cause),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -72,7 +71,9 @@ enum Peer {
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum Cause {
|
||||
EndStream,
|
||||
Proto(Reason),
|
||||
LocallyReset(Reason),
|
||||
Io,
|
||||
|
||||
/// The user droped all handles to the stream without explicitly canceling.
|
||||
@@ -84,7 +85,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<(), UserError> {
|
||||
let local = Peer::Streaming;
|
||||
let local = Streaming;
|
||||
|
||||
self.inner = match self.inner {
|
||||
Idle => if eos {
|
||||
@@ -107,7 +108,7 @@ impl State {
|
||||
}
|
||||
},
|
||||
HalfClosedRemote(AwaitingHeaders) => if eos {
|
||||
Closed(None)
|
||||
Closed(Cause::EndStream)
|
||||
} else {
|
||||
HalfClosedRemote(local)
|
||||
},
|
||||
@@ -124,7 +125,7 @@ impl State {
|
||||
///
|
||||
/// Returns true if this transitions the state to Open.
|
||||
pub fn recv_open(&mut self, eos: bool) -> Result<bool, RecvError> {
|
||||
let remote = Peer::Streaming;
|
||||
let remote = Streaming;
|
||||
let mut initial = false;
|
||||
|
||||
self.inner = match self.inner {
|
||||
@@ -144,7 +145,7 @@ impl State {
|
||||
initial = true;
|
||||
|
||||
if eos {
|
||||
Closed(None)
|
||||
Closed(Cause::EndStream)
|
||||
} else {
|
||||
Open {
|
||||
local: AwaitingHeaders,
|
||||
@@ -164,7 +165,7 @@ impl State {
|
||||
}
|
||||
},
|
||||
HalfClosedLocal(AwaitingHeaders) => if eos {
|
||||
Closed(None)
|
||||
Closed(Cause::EndStream)
|
||||
} else {
|
||||
HalfClosedLocal(remote)
|
||||
},
|
||||
@@ -201,13 +202,25 @@ impl State {
|
||||
},
|
||||
HalfClosedLocal(..) => {
|
||||
trace!("recv_close: HalfClosedLocal => Closed");
|
||||
self.inner = Closed(None);
|
||||
self.inner = Closed(Cause::EndStream);
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(RecvError::Connection(Reason::PROTOCOL_ERROR)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The remote explicitly sent a RST_STREAM.
|
||||
pub fn recv_reset(&mut self, reason: Reason) {
|
||||
match self.inner {
|
||||
Closed(..) => {},
|
||||
_ => {
|
||||
trace!("recv_reset; reason={:?}", reason);
|
||||
self.inner = Closed(Cause::Proto(reason));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// We noticed a protocol error.
|
||||
pub fn recv_err(&mut self, err: &proto::Error) {
|
||||
use proto::Error::*;
|
||||
|
||||
@@ -216,8 +229,8 @@ impl State {
|
||||
_ => {
|
||||
trace!("recv_err; err={:?}", err);
|
||||
self.inner = Closed(match *err {
|
||||
Proto(reason) => Some(Cause::Proto(reason)),
|
||||
Io(..) => Some(Cause::Io),
|
||||
Proto(reason) => Cause::LocallyReset(reason),
|
||||
Io(..) => Cause::Io,
|
||||
});
|
||||
},
|
||||
}
|
||||
@@ -228,7 +241,7 @@ impl State {
|
||||
Closed(..) => {},
|
||||
s => {
|
||||
trace!("recv_eof; state={:?}", s);
|
||||
self.inner = Closed(Some(Cause::Io));
|
||||
self.inner = Closed(Cause::Io);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,28 +258,34 @@ impl State {
|
||||
},
|
||||
HalfClosedRemote(..) => {
|
||||
trace!("send_close: HalfClosedRemote => Closed");
|
||||
self.inner = Closed(None);
|
||||
self.inner = Closed(Cause::EndStream);
|
||||
},
|
||||
_ => panic!("transition send_close on unexpected state"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the stream state to reset
|
||||
/// Set the stream state to reset locally.
|
||||
pub fn set_reset(&mut self, reason: Reason) {
|
||||
self.inner = Closed(Some(Cause::Proto(reason)));
|
||||
self.inner = Closed(Cause::LocallyReset(reason));
|
||||
}
|
||||
|
||||
/// Set the stream state to canceled
|
||||
pub fn set_canceled(&mut self) {
|
||||
debug_assert!(!self.is_closed());
|
||||
self.inner = Closed(Some(Cause::Canceled));
|
||||
self.inner = Closed(Cause::Canceled);
|
||||
}
|
||||
|
||||
pub fn is_canceled(&self) -> bool {
|
||||
use self::Cause::Canceled;
|
||||
|
||||
match self.inner {
|
||||
Closed(Some(Canceled)) => true,
|
||||
Closed(Cause::Canceled) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_local_reset(&self) -> bool {
|
||||
match self.inner {
|
||||
Closed(Cause::LocallyReset(_)) => true,
|
||||
Closed(Cause::Canceled) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -274,7 +293,8 @@ impl State {
|
||||
/// Returns true if the stream is already reset.
|
||||
pub fn is_reset(&self) -> bool {
|
||||
match self.inner {
|
||||
Closed(Some(_)) => true,
|
||||
Closed(Cause::EndStream) => false,
|
||||
Closed(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -294,10 +314,10 @@ impl State {
|
||||
pub fn is_send_streaming(&self) -> bool {
|
||||
match self.inner {
|
||||
Open {
|
||||
local: Peer::Streaming,
|
||||
local: Streaming,
|
||||
..
|
||||
} => true,
|
||||
HalfClosedRemote(Peer::Streaming) => true,
|
||||
HalfClosedRemote(Streaming) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -319,10 +339,10 @@ impl State {
|
||||
pub fn is_recv_streaming(&self) -> bool {
|
||||
match self.inner {
|
||||
Open {
|
||||
remote: Peer::Streaming,
|
||||
remote: Streaming,
|
||||
..
|
||||
} => true,
|
||||
HalfClosedLocal(Peer::Streaming) => true,
|
||||
HalfClosedLocal(Streaming) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -353,10 +373,12 @@ impl State {
|
||||
|
||||
// TODO: Is this correct?
|
||||
match self.inner {
|
||||
Closed(Some(Cause::Proto(reason))) => Err(proto::Error::Proto(reason)),
|
||||
Closed(Some(Cause::Canceled)) => Err(proto::Error::Proto(Reason::CANCEL)),
|
||||
Closed(Some(Cause::Io)) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())),
|
||||
Closed(None) | HalfClosedRemote(..) => Ok(false),
|
||||
Closed(Cause::Proto(reason)) |
|
||||
Closed(Cause::LocallyReset(reason)) => Err(proto::Error::Proto(reason)),
|
||||
Closed(Cause::Canceled) => Err(proto::Error::Proto(Reason::CANCEL)),
|
||||
Closed(Cause::Io) => Err(proto::Error::Io(io::ErrorKind::BrokenPipe.into())),
|
||||
Closed(Cause::EndStream) |
|
||||
HalfClosedRemote(..) => Ok(false),
|
||||
_ => Ok(true),
|
||||
}
|
||||
}
|
||||
@@ -372,6 +394,6 @@ impl Default for State {
|
||||
|
||||
impl Default for Peer {
|
||||
fn default() -> Self {
|
||||
Peer::AwaitingHeaders
|
||||
AwaitingHeaders
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user