use std::net::SocketAddr;
use std::path::PathBuf;
use std::time::Duration;
use ipnet::IpNet;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct HttpConfig {
pub listen: SocketAddr,
#[serde(with = "humantime_serde")]
pub read_timeout: Duration,
#[serde(with = "humantime_serde")]
pub write_timeout: Duration,
#[serde(with = "human_bytes")]
pub max_request_size: usize,
pub access_log: bool,
#[serde(default)]
pub trusted_proxies: Vec<IpNet>,
#[serde(default)]
pub tls: Option<TlsConfig>,
#[serde(default)]
pub h2c: bool,
#[serde(default)]
pub compression: CompressionConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
pub cert: PathBuf,
pub key: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct CompressionConfig {
pub enabled: bool,
pub algorithms: Vec<CompressionAlgorithm>,
#[serde(with = "human_bytes")]
pub min_size: usize,
}
impl Default for CompressionConfig {
fn default() -> Self {
Self {
enabled: false,
algorithms: vec![
CompressionAlgorithm::Gzip,
CompressionAlgorithm::Br,
CompressionAlgorithm::Zstd,
],
min_size: 256,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CompressionAlgorithm {
Gzip,
Br,
Zstd,
Deflate,
}
impl Default for HttpConfig {
fn default() -> Self {
Self {
listen: "0.0.0.0:8080".parse().unwrap(),
read_timeout: Duration::from_secs(10),
write_timeout: Duration::from_secs(30),
max_request_size: 10 * 1024 * 1024, access_log: false,
trusted_proxies: Vec::new(),
tls: None,
h2c: false,
compression: CompressionConfig::default(),
}
}
}
pub fn parse_byte_size(s: &str) -> Result<usize, String> {
let s = s.trim().to_lowercase();
if let Ok(n) = s.parse::<usize>() {
return Ok(n);
}
let (num_part, multiplier) = if let Some(n) = s.strip_suffix("gib") {
(n, 1024 * 1024 * 1024)
} else if let Some(n) = s.strip_suffix("gb") {
(n, 1024 * 1024 * 1024)
} else if let Some(n) = s.strip_suffix("mib") {
(n, 1024 * 1024)
} else if let Some(n) = s.strip_suffix("mb") {
(n, 1024 * 1024)
} else if let Some(n) = s.strip_suffix("kib") {
(n, 1024)
} else if let Some(n) = s.strip_suffix("kb") {
(n, 1024)
} else if let Some(n) = s.strip_suffix("b") {
(n, 1)
} else {
return Err(format!("invalid byte size: {s:?}"));
};
let num: usize = num_part
.trim()
.parse()
.map_err(|_| format!("invalid byte size number: {num_part:?}"))?;
Ok(num * multiplier)
}
mod human_bytes {
use serde::{Deserialize, Deserializer, Serializer, de};
pub fn serialize<S: Serializer>(value: &usize, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_u64(*value as u64)
}
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<usize, D::Error> {
#[derive(Deserialize)]
#[serde(untagged)]
enum ByteSize {
Str(String),
Num(usize),
}
match ByteSize::deserialize(de)? {
ByteSize::Num(n) => Ok(n),
ByteSize::Str(s) => super::parse_byte_size(&s).map_err(de::Error::custom),
}
}
}