diff --git a/src/client/client.rs b/src/client/client.rs
index 8195554bd7..f7d06933f0 100644
--- a/src/client/client.rs
+++ b/src/client/client.rs
@@ -1228,6 +1228,26 @@ impl Builder {
self
}
+ /// Sets the initial maximum of locally initiated (send) streams.Add commentMore actions
+ ///
+ /// This value will be overwritten by the value included in the initial
+ /// SETTINGS frame received from the peer as part of a [connection preface].
+ ///
+ /// Passing `None` will do nothing.
+ ///
+ /// If not set, hyper will use a default.
+ ///
+ /// [connection preface]: https://httpwg.org/specs/rfc9113.html#preface
+ #[cfg(feature = "http2")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "http2")))]
+ pub fn http2_initial_max_send_streams(
+ &mut self,
+ initial: impl Into>,
+ ) -> &mut Self {
+ self.h2_builder.initial_max_send_streams(initial);
+ self
+ }
+
/// Sets whether to use an adaptive flow control.
///
/// Enabling this will override the limits set in
diff --git a/src/client/conn/http2.rs b/src/client/conn/http2.rs
index 5697e9ee47..dee857f3a6 100644
--- a/src/client/conn/http2.rs
+++ b/src/client/conn/http2.rs
@@ -293,6 +293,23 @@ impl Builder {
self
}
+ /// Sets the initial maximum of locally initiated (send) streams.
+ ///
+ /// This value will be overwritten by the value included in the initial
+ /// SETTINGS frame received from the peer as part of a [connection preface].
+ ///
+ /// Passing `None` will do nothing.
+ ///
+ /// If not set, hyper will use a default.
+ ///
+ /// [connection preface]: https://httpwg.org/specs/rfc9113.html#preface
+ pub fn initial_max_send_streams(&mut self, initial: impl Into >) -> &mut Self {
+ if let Some(initial) = initial.into() {
+ self.h2_builder.initial_max_send_streams = initial;
+ }
+ self
+ }
+
/// Sets whether to use an adaptive flow control.
///
/// Enabling this will override the limits set in
diff --git a/src/proto/h2/client.rs b/src/proto/h2/client.rs
index 8c2a4d2e0f..c5599e2096 100644
--- a/src/proto/h2/client.rs
+++ b/src/proto/h2/client.rs
@@ -47,11 +47,21 @@ const DEFAULT_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb
const DEFAULT_MAX_FRAME_SIZE: u32 = 1024 * 16; // 16kb
const DEFAULT_MAX_SEND_BUF_SIZE: usize = 1024 * 1024; // 1mb
+// The maximum number of concurrent streams that the client is allowed to open
+// before it receives the initial SETTINGS frame from the server.
+// This default value is derived from what the HTTP/2 spec recommends as the
+// minimum value that endpoints advertise to their peers. It means that using
+// this value will minimize the chance of the failure where the local endpoint
+// attempts to open too many streams and gets rejected by the remote peer with
+// the `REFUSED_STREAM` error.
+const DEFAULT_INITIAL_MAX_SEND_STREAMS: usize = 100;
+
#[derive(Clone, Debug)]
pub(crate) struct Config {
pub(crate) adaptive_window: bool,
pub(crate) initial_conn_window_size: u32,
pub(crate) initial_stream_window_size: u32,
+ pub(crate) initial_max_send_streams: usize,
pub(crate) max_frame_size: u32,
#[cfg(feature = "runtime")]
pub(crate) keep_alive_interval: Option,
@@ -69,6 +79,7 @@ impl Default for Config {
adaptive_window: false,
initial_conn_window_size: DEFAULT_CONN_WINDOW,
initial_stream_window_size: DEFAULT_STREAM_WINDOW,
+ initial_max_send_streams: DEFAULT_INITIAL_MAX_SEND_STREAMS,
max_frame_size: DEFAULT_MAX_FRAME_SIZE,
#[cfg(feature = "runtime")]
keep_alive_interval: None,
@@ -85,6 +96,7 @@ impl Default for Config {
fn new_builder(config: &Config) -> Builder {
let mut builder = Builder::default();
builder
+ .initial_max_send_streams(config.initial_max_send_streams)
.initial_window_size(config.initial_stream_window_size)
.initial_connection_window_size(config.initial_conn_window_size)
.max_frame_size(config.max_frame_size)