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:
Sean McArthur
2017-12-18 11:09:38 -08:00
committed by GitHub
parent edaeaa8941
commit 1ea9a8fc7e
19 changed files with 684 additions and 125 deletions

View File

@@ -3,19 +3,20 @@
use {SendStream, RecvStream, ReleaseCapacity};
use codec::{Codec, RecvError};
use frame::{self, Reason, Settings, StreamId};
use proto::{self, Connection, Prioritized};
use proto::{self, Config, Connection, Prioritized};
use bytes::{Buf, Bytes, IntoBuf};
use futures::{self, Async, Future, Poll};
use http::{Request, Response};
use tokio_io::{AsyncRead, AsyncWrite};
use std::{convert, fmt, mem};
use std::time::Duration;
/// In progress H2 connection binding
#[must_use = "futures do nothing unless polled"]
pub struct Handshake<T, B: IntoBuf = Bytes> {
/// SETTINGS frame that will be sent once the connection is established.
settings: Settings,
/// The config to pass to Connection::new after handshake succeeds.
builder: Builder,
/// The current state of the handshake.
state: Handshaking<T, B>
}
@@ -27,8 +28,15 @@ pub struct Server<T, B: IntoBuf> {
}
/// Build a Server
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Builder {
/// Time to keep locally reset streams around before reaping.
reset_stream_duration: Duration,
/// Maximum number of locally reset streams to keep at a time.
reset_stream_max: usize,
/// Initial `Settings` frame to send as part of the handshake.
settings: Settings,
}
@@ -95,23 +103,23 @@ where
B: IntoBuf,
B::Buf: 'static,
{
fn handshake2(io: T, settings: Settings) -> Handshake<T, B> {
fn handshake2(io: T, builder: Builder) -> Handshake<T, B> {
// Create the codec.
let mut codec = Codec::new(io);
if let Some(max) = settings.max_frame_size() {
if let Some(max) = builder.settings.max_frame_size() {
codec.set_max_recv_frame_size(max as usize);
}
// Send initial settings frame.
codec
.buffer(settings.clone().into())
.buffer(builder.settings.clone().into())
.expect("invalid SETTINGS frame");
// Create the handshake future.
let state = Handshaking::from(codec);
Handshake { settings, state }
Handshake { builder, state }
}
/// Sets the target window size for the whole connection.
@@ -204,6 +212,26 @@ impl Builder {
self
}
/// Set the maximum number of concurrent locally reset streams.
///
/// Locally reset streams are to "ignore frames from the peer for some
/// time". While waiting for that time, locally reset streams "waste"
/// space in order to be able to ignore those frames. This setting
/// can limit how many extra streams are left waiting for "some time".
pub fn max_concurrent_reset_streams(&mut self, max: usize) -> &mut Self {
self.reset_stream_max = max;
self
}
/// Set the maximum number of concurrent locally reset streams.
///
/// Locally reset streams are to "ignore frames from the peer for some
/// time", but that time is unspecified. Set that time with this setting.
pub fn reset_stream_duration(&mut self, dur: Duration) -> &mut Self {
self.reset_stream_duration = dur;
self
}
/// Bind an H2 server connection.
///
/// Returns a future which resolves to the connection value once the H2
@@ -214,7 +242,17 @@ impl Builder {
B: IntoBuf,
B::Buf: 'static,
{
Server::handshake2(io, self.settings.clone())
Server::handshake2(io, self.clone())
}
}
impl Default for Builder {
fn default() -> Builder {
Builder {
reset_stream_duration: Duration::from_secs(proto::DEFAULT_RESET_STREAM_SECS),
reset_stream_max: proto::DEFAULT_RESET_STREAM_MAX,
settings: Settings::default(),
}
}
}
@@ -357,8 +395,12 @@ impl<T, B: IntoBuf> Future for Handshake<T, B>
unreachable!("Handshake::poll() state was not advanced completely!")
};
let server = poll?.map(|codec| {
let connection =
Connection::new(codec, &self.settings, 2.into());
let connection = Connection::new(codec, Config {
next_stream_id: 2.into(),
reset_stream_duration: self.builder.reset_stream_duration,
reset_stream_max: self.builder.reset_stream_max,
settings: self.builder.settings.clone(),
});
trace!("Handshake::poll(); connection established!");
Server { connection }
});