use std::sync::{RwLock, RwLockReadGuard};
use std::time::Duration;
#[derive(Clone, Debug, Default)]
pub struct ConnectionLimits {
pub handler_timeout: Option<Duration>,
pub max_body_size: Option<usize>,
pub h3_read_timeout: Option<Duration>,
pub max_webtransport_frame_size: Option<usize>,
pub webtransport_read_timeout: Option<Duration>,
pub max_webtransport_sessions: Option<usize>,
pub webtransport_datagram_max_size: Option<usize>,
pub webtransport_datagram_rate: Option<u64>,
pub webtransport_datagram_drop_metric: bool,
pub h3_chunk_size: Option<usize>,
pub h3_yield_bytes: Option<usize>,
}
#[derive(Clone, Debug, Default)]
pub struct ServerConfig {
pub connection_limits: ConnectionLimits,
#[cfg(feature = "quic")]
pub quic_transport: Option<crate::server::quic::QuicTransportConfig>,
}
#[derive(Default)]
struct ServerConfigRegistry {
inner: RwLock<ServerConfig>,
}
static CONFIG_REGISTRY: ServerConfigRegistry = ServerConfigRegistry {
inner: RwLock::new(ServerConfig {
connection_limits: ConnectionLimits {
handler_timeout: None,
max_body_size: None,
h3_read_timeout: None,
max_webtransport_frame_size: None,
webtransport_read_timeout: None,
max_webtransport_sessions: None,
webtransport_datagram_max_size: None,
webtransport_datagram_rate: None,
webtransport_datagram_drop_metric: false,
h3_chunk_size: None,
h3_yield_bytes: None,
},
#[cfg(feature = "quic")]
quic_transport: None,
}),
};
impl ServerConfigRegistry {
pub fn set(config: ServerConfig) {
if let Ok(mut guard) = CONFIG_REGISTRY.inner.write() {
*guard = config;
}
}
pub fn get() -> RwLockReadGuard<'static, ServerConfig> {
CONFIG_REGISTRY
.inner
.read()
.expect("server config registry poisoned")
}
}
pub fn set_global_server_config(config: ServerConfig) {
ServerConfigRegistry::set(config);
}
pub fn global_server_config() -> RwLockReadGuard<'static, ServerConfig> {
ServerConfigRegistry::get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_connection_limits_default() {
let limits = ConnectionLimits::default();
assert_eq!(limits.handler_timeout, None);
assert_eq!(limits.max_body_size, None);
assert_eq!(limits.h3_read_timeout, None);
assert_eq!(limits.max_webtransport_frame_size, None);
assert_eq!(limits.webtransport_read_timeout, None);
assert_eq!(limits.max_webtransport_sessions, None);
assert_eq!(limits.webtransport_datagram_max_size, None);
assert_eq!(limits.webtransport_datagram_rate, None);
assert!(!limits.webtransport_datagram_drop_metric);
assert_eq!(limits.h3_chunk_size, None);
assert_eq!(limits.h3_yield_bytes, None);
}
#[test]
fn test_connection_limits_clone() {
let limits = ConnectionLimits {
handler_timeout: Some(std::time::Duration::from_secs(30)),
max_body_size: Some(1024),
h3_read_timeout: Some(std::time::Duration::from_secs(20)),
max_webtransport_frame_size: Some(4096),
webtransport_read_timeout: Some(std::time::Duration::from_secs(10)),
max_webtransport_sessions: Some(100),
webtransport_datagram_max_size: Some(1350),
webtransport_datagram_rate: Some(1000),
webtransport_datagram_drop_metric: true,
h3_chunk_size: Some(32 * 1024),
h3_yield_bytes: Some(512 * 1024),
};
let cloned = limits.clone();
assert_eq!(cloned.handler_timeout, limits.handler_timeout);
assert_eq!(cloned.max_body_size, limits.max_body_size);
assert_eq!(cloned.h3_read_timeout, limits.h3_read_timeout);
assert_eq!(
cloned.max_webtransport_frame_size,
limits.max_webtransport_frame_size
);
assert_eq!(
cloned.webtransport_read_timeout,
limits.webtransport_read_timeout
);
assert_eq!(
cloned.max_webtransport_sessions,
limits.max_webtransport_sessions
);
assert_eq!(
cloned.webtransport_datagram_max_size,
limits.webtransport_datagram_max_size
);
assert_eq!(
cloned.webtransport_datagram_rate,
limits.webtransport_datagram_rate
);
assert_eq!(
cloned.webtransport_datagram_drop_metric,
limits.webtransport_datagram_drop_metric
);
assert_eq!(cloned.h3_chunk_size, limits.h3_chunk_size);
assert_eq!(cloned.h3_yield_bytes, limits.h3_yield_bytes);
}
#[test]
fn test_server_config_default() {
let config = ServerConfig::default();
assert_eq!(config.connection_limits.handler_timeout, None);
assert_eq!(config.connection_limits.max_body_size, None);
}
#[test]
fn test_server_config_clone() {
let config = ServerConfig {
connection_limits: ConnectionLimits {
handler_timeout: Some(std::time::Duration::from_secs(60)),
..Default::default()
},
..Default::default()
};
let cloned = config.clone();
assert_eq!(
cloned.connection_limits.handler_timeout,
config.connection_limits.handler_timeout
);
}
#[test]
fn test_set_global_server_config() {
let custom_config = ServerConfig {
connection_limits: ConnectionLimits {
handler_timeout: Some(std::time::Duration::from_secs(120)),
max_body_size: Some(2048),
..Default::default()
},
..Default::default()
};
set_global_server_config(custom_config);
let config = global_server_config();
assert_eq!(
config.connection_limits.handler_timeout,
Some(std::time::Duration::from_secs(120))
);
assert_eq!(config.connection_limits.max_body_size, Some(2048));
}
#[test]
fn test_global_server_config_multiple_reads() {
set_global_server_config(ServerConfig::default());
let config1 = global_server_config();
let config2 = global_server_config();
assert_eq!(
config1.connection_limits.handler_timeout,
config2.connection_limits.handler_timeout
);
}
#[test]
fn test_connection_limits_debug() {
let limits = ConnectionLimits {
handler_timeout: Some(std::time::Duration::from_secs(30)),
..Default::default()
};
let debug_str = format!("{:?}", limits);
assert!(debug_str.contains("ConnectionLimits"));
}
#[test]
fn test_server_config_debug() {
let config = ServerConfig::default();
let debug_str = format!("{:?}", config);
assert!(debug_str.contains("ServerConfig"));
}
}