From dedcb674f35eaec765a42b550caabe6f694d86d1 Mon Sep 17 00:00:00 2001 From: Noah Kennedy Date: Fri, 19 Jan 2024 12:21:00 -0600 Subject: [PATCH] feat(http2): add config for `max_local_error_reset_streams` in server (#3528) This change exposes a tunable for the max_local_error_reset_streams parameter in h2. --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/proto/h2/server.rs | 4 ++++ src/server/conn.rs | 17 +++++++++++++++++ src/server/server.rs | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 088b600f3d..77be302ca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ http = "0.2" http-body = "0.4" httpdate = "1.0" httparse = "1.8" -h2 = { version = "0.3.17", optional = true } +h2 = { version = "0.3.24", optional = true } itoa = "1" tracing = { version = "0.1", default-features = false, features = ["std"] } pin-project-lite = "0.2.4" diff --git a/src/lib.rs b/src/lib.rs index e5e4cfc56e..3729aac62d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, deny(rust_2018_idioms))] #![cfg_attr(all(test, feature = "full"), deny(unreachable_pub))] -#![cfg_attr(all(test, feature = "full"), deny(warnings))] +#![cfg_attr(all(test, feature = "full", not(feature = "nightly")), deny(warnings))] #![cfg_attr(all(test, feature = "nightly"), feature(test))] #![cfg_attr(docsrs, feature(doc_cfg))] diff --git a/src/proto/h2/server.rs b/src/proto/h2/server.rs index b4e8d68a15..b7bff590ff 100644 --- a/src/proto/h2/server.rs +++ b/src/proto/h2/server.rs @@ -39,6 +39,7 @@ const DEFAULT_STREAM_WINDOW: u32 = 1024 * 1024; // 1mb const DEFAULT_MAX_FRAME_SIZE: u32 = 1024 * 16; // 16kb const DEFAULT_MAX_SEND_BUF_SIZE: usize = 1024 * 400; // 400kb const DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE: u32 = 16 << 20; // 16 MB "sane default" taken from golang http2 +const DEFAULT_MAX_LOCAL_ERROR_RESET_STREAMS: usize = 1024; #[derive(Clone, Debug)] pub(crate) struct Config { @@ -49,6 +50,7 @@ pub(crate) struct Config { pub(crate) enable_connect_protocol: bool, pub(crate) max_concurrent_streams: Option, pub(crate) max_pending_accept_reset_streams: Option, + pub(crate) max_local_error_reset_streams: Option, #[cfg(feature = "runtime")] pub(crate) keep_alive_interval: Option, #[cfg(feature = "runtime")] @@ -67,6 +69,7 @@ impl Default for Config { enable_connect_protocol: false, max_concurrent_streams: None, max_pending_accept_reset_streams: None, + max_local_error_reset_streams: Some(DEFAULT_MAX_LOCAL_ERROR_RESET_STREAMS), #[cfg(feature = "runtime")] keep_alive_interval: None, #[cfg(feature = "runtime")] @@ -125,6 +128,7 @@ where .initial_connection_window_size(config.initial_conn_window_size) .max_frame_size(config.max_frame_size) .max_header_list_size(config.max_header_list_size) + .max_local_error_reset_streams(config.max_local_error_reset_streams) .max_send_buffer_size(config.max_send_buffer_size); if let Some(max) = config.max_concurrent_streams { builder.max_concurrent_streams(max); diff --git a/src/server/conn.rs b/src/server/conn.rs index 8ce4c95193..951c9ee5cd 100644 --- a/src/server/conn.rs +++ b/src/server/conn.rs @@ -414,6 +414,23 @@ impl Http { self } + /// Configures the maximum number of pending reset streams allowed before a GOAWAY will be sent. + /// + /// This will default to the default value set by the [`h2` crate](https://crates.io/crates/h2). + /// As of v0.3.17, it is 20. + /// + /// See for more information. + #[cfg(feature = "http2")] + #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] + pub fn http2_max_local_error_reset_streams( + &mut self, + max: impl Into>, + ) -> &mut Self { + self.h2_builder.max_local_error_reset_streams = max.into(); + + self + } + /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. /// diff --git a/src/server/server.rs b/src/server/server.rs index 6d7d69e51b..4cccedd98a 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -387,6 +387,21 @@ impl Builder { self } + /// Configures the maximum number of local reset streams allowed before a GOAWAY will be sent. + /// + /// If not set, hyper will use a default, currently of 1024. + /// + /// If `None` is supplied, hyper will not apply any limit. + /// This is not advised, as it can potentially expose servers to DOS vulnerabilities. + /// + /// See for more information. + #[cfg(feature = "http2")] + #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] + pub fn http2_max_local_error_reset_streams(mut self, max: impl Into>) -> Self { + self.protocol.http2_max_local_error_reset_streams(max); + self + } + /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 /// stream-level flow control. ///