diff --git a/config-example.toml b/config-example.toml index 1310315..cbf8c8e 100644 --- a/config-example.toml +++ b/config-example.toml @@ -93,3 +93,5 @@ request_max_body_size = 65536 # bytes max_concurrent_connections = 10000 max_concurrent_bidistream = 100 max_concurrent_unistream = 100 +max_idle_timeout = 10 # secs. 0 represents an infinite timeout. +# WARNING: If a peer or its network path malfunctions or acts maliciously, an infinite idle timeout can result in permanently hung futures! diff --git a/src/config/parse.rs b/src/config/parse.rs index 39e2dac..c5922bf 100644 --- a/src/config/parse.rs +++ b/src/config/parse.rs @@ -176,6 +176,14 @@ pub fn parse_opts(globals: &mut Globals) -> std::result::Result<(), anyhow::Erro if let Some(x) = h3option.max_concurrent_unistream { globals.h3_max_concurrent_unistream = x.into(); } + if let Some(x) = h3option.max_idle_timeout { + if x == 0u64 { + globals.h3_max_idle_timeout = None; + } else { + globals.h3_max_idle_timeout = + Some(quinn::IdleTimeout::try_from(tokio::time::Duration::from_secs(x)).unwrap()) + } + } } } diff --git a/src/config/toml.rs b/src/config/toml.rs index 258094e..cefacb2 100644 --- a/src/config/toml.rs +++ b/src/config/toml.rs @@ -23,6 +23,7 @@ pub struct Http3Option { pub max_concurrent_connections: Option, pub max_concurrent_bidistream: Option, pub max_concurrent_unistream: Option, + pub max_idle_timeout: Option, } #[derive(Deserialize, Debug, Default)] diff --git a/src/constants.rs b/src/constants.rs index 2d10747..d2fc25f 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -22,4 +22,5 @@ pub mod H3 { pub const MAX_CONCURRENT_CONNECTIONS: u32 = 4096; pub const MAX_CONCURRENT_BIDISTREAM: u32 = 64; pub const MAX_CONCURRENT_UNISTREAM: u32 = 64; + pub const MAX_IDLE_TIMEOUT: u64 = 10; // secs } diff --git a/src/globals.rs b/src/globals.rs index 6d5e5bc..0bd06a6 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -37,6 +37,8 @@ pub struct Globals { pub h3_max_concurrent_unistream: quinn::VarInt, #[cfg(feature = "http3")] pub h3_max_concurrent_connections: u32, + #[cfg(feature = "http3")] + pub h3_max_idle_timeout: Option, } #[derive(Debug, Clone, Default)] diff --git a/src/main.rs b/src/main.rs index 2fd8602..b27ed86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,6 +89,8 @@ fn main() { h3_max_concurrent_bidistream: H3::MAX_CONCURRENT_BIDISTREAM.into(), #[cfg(feature = "http3")] h3_max_concurrent_unistream: H3::MAX_CONCURRENT_UNISTREAM.into(), + #[cfg(feature = "http3")] + h3_max_idle_timeout: Some(quinn::IdleTimeout::try_from(Duration::from_secs(H3::MAX_IDLE_TIMEOUT)).unwrap()), }; if let Err(e) = parse_opts(&mut globals) { diff --git a/src/proxy/proxy_tls.rs b/src/proxy/proxy_tls.rs index 70d1d1f..416ca8a 100644 --- a/src/proxy/proxy_tls.rs +++ b/src/proxy/proxy_tls.rs @@ -130,7 +130,8 @@ where let mut transport_config_quic = TransportConfig::default(); transport_config_quic .max_concurrent_bidi_streams(self.globals.h3_max_concurrent_bidistream) - .max_concurrent_uni_streams(self.globals.h3_max_concurrent_unistream); + .max_concurrent_uni_streams(self.globals.h3_max_concurrent_unistream) + .max_idle_timeout(self.globals.h3_max_idle_timeout); let mut server_config_h3 = QuicServerConfig::with_crypto(Arc::new(rustls_server_config)); server_config_h3.transport = Arc::new(transport_config_quic);