use std::time::Duration;
#[derive(Clone, Debug)]
pub struct TransportConfig {
pub pool_max_idle_per_host: usize,
pub pool_idle_timeout: Option<Duration>,
pub tcp_keepalive: Option<Duration>,
pub http2_prior_knowledge: bool,
pub dns_cache_ttl: Option<Duration>,
#[cfg(feature = "http3")]
pub enable_http3: bool,
}
impl Default for TransportConfig {
fn default() -> Self {
Self {
pool_max_idle_per_host: 32,
pool_idle_timeout: Some(Duration::from_secs(90)),
tcp_keepalive: Some(Duration::from_secs(60)),
http2_prior_knowledge: false,
dns_cache_ttl: Some(Duration::from_secs(30)),
#[cfg(feature = "http3")]
enable_http3: false,
}
}
}
impl TransportConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_pool_max_idle_per_host(mut self, count: usize) -> Self {
self.pool_max_idle_per_host = count;
self
}
pub fn with_pool_idle_timeout(mut self, timeout: Option<Duration>) -> Self {
self.pool_idle_timeout = timeout;
self
}
pub fn with_tcp_keepalive(mut self, interval: Option<Duration>) -> Self {
self.tcp_keepalive = interval;
self
}
pub fn with_http2_prior_knowledge(mut self, enabled: bool) -> Self {
self.http2_prior_knowledge = enabled;
self
}
pub fn with_dns_cache_ttl(mut self, ttl: Option<Duration>) -> Self {
self.dns_cache_ttl = ttl;
self
}
#[cfg(feature = "http3")]
pub fn with_http3(mut self, enabled: bool) -> Self {
self.enable_http3 = enabled;
self
}
#[cfg(all(feature = "native-http", not(target_arch = "wasm32")))]
pub fn apply_to_builder(&self, builder: reqwest::ClientBuilder) -> reqwest::ClientBuilder {
let builder = builder
.pool_max_idle_per_host(self.pool_max_idle_per_host)
.pool_idle_timeout(self.pool_idle_timeout)
.tcp_keepalive(self.tcp_keepalive);
let builder = if self.http2_prior_knowledge {
builder.http2_prior_knowledge()
} else {
builder
};
#[cfg(feature = "http3")]
let _ = self.enable_http3;
builder
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = TransportConfig::default();
assert_eq!(cfg.pool_max_idle_per_host, 32);
assert_eq!(cfg.pool_idle_timeout, Some(Duration::from_secs(90)));
assert_eq!(cfg.tcp_keepalive, Some(Duration::from_secs(60)));
assert!(!cfg.http2_prior_knowledge);
assert_eq!(cfg.dns_cache_ttl, Some(Duration::from_secs(30)));
#[cfg(feature = "http3")]
assert!(!cfg.enable_http3);
}
#[test]
fn test_builder_chain() {
let cfg = TransportConfig::new()
.with_pool_max_idle_per_host(16)
.with_pool_idle_timeout(Some(Duration::from_secs(45)))
.with_tcp_keepalive(Some(Duration::from_secs(120)))
.with_http2_prior_knowledge(true)
.with_dns_cache_ttl(Some(Duration::from_secs(60)));
assert_eq!(cfg.pool_max_idle_per_host, 16);
assert_eq!(cfg.pool_idle_timeout, Some(Duration::from_secs(45)));
assert_eq!(cfg.tcp_keepalive, Some(Duration::from_secs(120)));
assert!(cfg.http2_prior_knowledge);
assert_eq!(cfg.dns_cache_ttl, Some(Duration::from_secs(60)));
}
#[test]
fn test_disable_pooling() {
let cfg = TransportConfig::new().with_pool_max_idle_per_host(0);
assert_eq!(cfg.pool_max_idle_per_host, 0);
}
#[test]
fn test_disable_keepalive() {
let cfg = TransportConfig::new().with_tcp_keepalive(None);
assert_eq!(cfg.tcp_keepalive, None);
}
#[test]
fn test_disable_dns_cache() {
let cfg = TransportConfig::new().with_dns_cache_ttl(None);
assert_eq!(cfg.dns_cache_ttl, None);
}
#[cfg(feature = "http3")]
#[test]
fn test_http3_flag() {
let cfg = TransportConfig::new().with_http3(true);
assert!(cfg.enable_http3);
}
#[cfg(all(feature = "native-http", not(target_arch = "wasm32")))]
#[test]
fn test_apply_to_builder_builds_client_with_non_default_config() {
let cfg = TransportConfig::new()
.with_pool_max_idle_per_host(128)
.with_pool_idle_timeout(Some(Duration::from_secs(45)))
.with_tcp_keepalive(Some(Duration::from_secs(30)))
.with_http2_prior_knowledge(false)
.with_dns_cache_ttl(Some(Duration::from_secs(60)));
let builder = reqwest::Client::builder();
let builder = cfg.apply_to_builder(builder);
let client = builder.build();
assert!(
client.is_ok(),
"reqwest::Client::build() failed with non-default TransportConfig"
);
}
#[cfg(all(feature = "native-http", not(target_arch = "wasm32")))]
#[test]
fn test_apply_to_builder_with_http2_prior_knowledge() {
let cfg = TransportConfig::new().with_http2_prior_knowledge(true);
let client = cfg.apply_to_builder(reqwest::Client::builder()).build();
assert!(
client.is_ok(),
"reqwest::Client::build() failed with http2_prior_knowledge=true"
);
}
#[cfg(all(feature = "native-http", not(target_arch = "wasm32")))]
#[test]
fn test_apply_to_builder_with_pooling_disabled() {
let cfg = TransportConfig::new()
.with_pool_max_idle_per_host(0)
.with_pool_idle_timeout(None)
.with_tcp_keepalive(None)
.with_dns_cache_ttl(None);
let client = cfg.apply_to_builder(reqwest::Client::builder()).build();
assert!(client.is_ok(), "reqwest::Client::build() failed with pooling disabled");
}
}