1use std::net::SocketAddr;
2use std::path::PathBuf;
3use std::time::Duration;
4
5use ipnet::IpNet;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(default)]
32pub struct HttpConfig {
33 pub listen: SocketAddr,
35 #[serde(with = "humantime_serde")]
37 pub read_timeout: Duration,
38 #[serde(with = "humantime_serde")]
40 pub write_timeout: Duration,
41 #[serde(with = "humantime_serde")]
43 pub shutdown_timeout: Duration,
44 #[serde(with = "human_bytes")]
47 pub max_request_size: usize,
48 pub access_log: bool,
50 #[serde(default)]
54 pub trusted_proxies: Vec<IpNet>,
55 #[serde(default)]
58 pub tls: Option<TlsConfig>,
59 #[serde(default)]
61 pub h2c: bool,
62 #[serde(default)]
64 pub compression: CompressionConfig,
65 #[serde(default)]
67 pub hooks: Vec<HookConfig>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct TlsConfig {
73 pub cert: PathBuf,
75 pub key: PathBuf,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81#[serde(default)]
82pub struct CompressionConfig {
83 pub enabled: bool,
85 pub algorithms: Vec<CompressionAlgorithm>,
88 #[serde(with = "human_bytes")]
90 pub min_size: usize,
91}
92
93impl Default for CompressionConfig {
94 fn default() -> Self {
95 Self {
96 enabled: false,
97 algorithms: vec![
98 CompressionAlgorithm::Gzip,
99 CompressionAlgorithm::Br,
100 CompressionAlgorithm::Zstd,
101 ],
102 min_size: 256,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
108#[serde(rename_all = "lowercase")]
109pub enum CompressionAlgorithm {
110 Gzip,
111 Br,
112 Zstd,
113 Deflate,
114}
115
116impl Default for HttpConfig {
117 fn default() -> Self {
118 Self {
119 listen: "0.0.0.0:8080".parse().unwrap(),
120 read_timeout: Duration::from_secs(10),
121 write_timeout: Duration::from_secs(30),
122 shutdown_timeout: Duration::from_secs(30),
123 max_request_size: 10 * 1024 * 1024, access_log: false,
125 trusted_proxies: Vec::new(),
126 tls: None,
127 h2c: false,
128 compression: CompressionConfig::default(),
129 hooks: Vec::new(),
130 }
131 }
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
139#[serde(rename_all = "snake_case")]
140pub enum HookMode {
141 Sync,
142 Async,
143}
144
145#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
147#[serde(rename_all = "snake_case")]
148pub enum HookErrorBehavior {
149 #[default]
151 FailOpen,
152 FailClosed,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct HookConfig {
159 pub event: String,
162 pub lua: PathBuf,
164 #[serde(default = "default_hook_mode")]
166 pub mode: HookMode,
167 #[serde(default = "default_timeout_ms")]
169 pub timeout_ms: u64,
170 #[serde(default)]
172 pub on_error: HookErrorBehavior,
173 #[serde(default)]
177 pub required: bool,
178}
179
180fn default_hook_mode() -> HookMode {
181 HookMode::Sync
182}
183
184fn default_timeout_ms() -> u64 {
185 5
186}
187
188pub fn parse_byte_size(s: &str) -> Result<usize, String> {
193 let s = s.trim().to_lowercase();
194
195 if let Ok(n) = s.parse::<usize>() {
197 return Ok(n);
198 }
199
200 let (num_part, multiplier) = if let Some(n) = s.strip_suffix("gib") {
201 (n, 1024 * 1024 * 1024)
202 } else if let Some(n) = s.strip_suffix("gb") {
203 (n, 1024 * 1024 * 1024)
204 } else if let Some(n) = s.strip_suffix("mib") {
205 (n, 1024 * 1024)
206 } else if let Some(n) = s.strip_suffix("mb") {
207 (n, 1024 * 1024)
208 } else if let Some(n) = s.strip_suffix("kib") {
209 (n, 1024)
210 } else if let Some(n) = s.strip_suffix("kb") {
211 (n, 1024)
212 } else if let Some(n) = s.strip_suffix("b") {
213 (n, 1)
214 } else {
215 return Err(format!("invalid byte size: {s:?}"));
216 };
217
218 let num: usize = num_part
219 .trim()
220 .parse()
221 .map_err(|_| format!("invalid byte size number: {num_part:?}"))?;
222
223 Ok(num * multiplier)
224}
225
226mod human_bytes {
227 use serde::{Deserialize, Deserializer, Serializer, de};
228
229 pub fn serialize<S: Serializer>(value: &usize, ser: S) -> Result<S::Ok, S::Error> {
230 ser.serialize_u64(*value as u64)
231 }
232
233 pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<usize, D::Error> {
234 #[derive(Deserialize)]
235 #[serde(untagged)]
236 enum ByteSize {
237 Str(String),
238 Num(usize),
239 }
240
241 match ByteSize::deserialize(de)? {
242 ByteSize::Num(n) => Ok(n),
243 ByteSize::Str(s) => super::parse_byte_size(&s).map_err(de::Error::custom),
244 }
245 }
246}