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)]
30#[serde(default)]
31pub struct HttpConfig {
32 pub listen: SocketAddr,
34 #[serde(with = "humantime_serde")]
36 pub read_timeout: Duration,
37 #[serde(with = "humantime_serde")]
39 pub write_timeout: Duration,
40 #[serde(with = "human_bytes")]
43 pub max_request_size: usize,
44 pub access_log: bool,
46 #[serde(default)]
50 pub trusted_proxies: Vec<IpNet>,
51 #[serde(default)]
54 pub tls: Option<TlsConfig>,
55 #[serde(default)]
57 pub h2c: bool,
58 #[serde(default)]
60 pub compression: CompressionConfig,
61 #[serde(default)]
63 pub hooks: Vec<HookConfig>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct TlsConfig {
69 pub cert: PathBuf,
71 pub key: PathBuf,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(default)]
78pub struct CompressionConfig {
79 pub enabled: bool,
81 pub algorithms: Vec<CompressionAlgorithm>,
84 #[serde(with = "human_bytes")]
86 pub min_size: usize,
87}
88
89impl Default for CompressionConfig {
90 fn default() -> Self {
91 Self {
92 enabled: false,
93 algorithms: vec![
94 CompressionAlgorithm::Gzip,
95 CompressionAlgorithm::Br,
96 CompressionAlgorithm::Zstd,
97 ],
98 min_size: 256,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(rename_all = "lowercase")]
105pub enum CompressionAlgorithm {
106 Gzip,
107 Br,
108 Zstd,
109 Deflate,
110}
111
112impl Default for HttpConfig {
113 fn default() -> Self {
114 Self {
115 listen: "0.0.0.0:8080".parse().unwrap(),
116 read_timeout: Duration::from_secs(10),
117 write_timeout: Duration::from_secs(30),
118 max_request_size: 10 * 1024 * 1024, access_log: false,
120 trusted_proxies: Vec::new(),
121 tls: None,
122 h2c: false,
123 compression: CompressionConfig::default(),
124 hooks: Vec::new(),
125 }
126 }
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
134#[serde(rename_all = "snake_case")]
135pub enum HookMode {
136 Sync,
137 Async,
138}
139
140#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
142#[serde(rename_all = "snake_case")]
143pub enum HookErrorBehavior {
144 #[default]
146 FailOpen,
147 FailClosed,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct HookConfig {
154 pub event: String,
157 pub lua: PathBuf,
159 #[serde(default = "default_hook_mode")]
161 pub mode: HookMode,
162 #[serde(default = "default_timeout_ms")]
164 pub timeout_ms: u64,
165 #[serde(default)]
167 pub on_error: HookErrorBehavior,
168}
169
170fn default_hook_mode() -> HookMode {
171 HookMode::Sync
172}
173
174fn default_timeout_ms() -> u64 {
175 5
176}
177
178pub fn parse_byte_size(s: &str) -> Result<usize, String> {
183 let s = s.trim().to_lowercase();
184
185 if let Ok(n) = s.parse::<usize>() {
187 return Ok(n);
188 }
189
190 let (num_part, multiplier) = if let Some(n) = s.strip_suffix("gib") {
191 (n, 1024 * 1024 * 1024)
192 } else if let Some(n) = s.strip_suffix("gb") {
193 (n, 1024 * 1024 * 1024)
194 } else if let Some(n) = s.strip_suffix("mib") {
195 (n, 1024 * 1024)
196 } else if let Some(n) = s.strip_suffix("mb") {
197 (n, 1024 * 1024)
198 } else if let Some(n) = s.strip_suffix("kib") {
199 (n, 1024)
200 } else if let Some(n) = s.strip_suffix("kb") {
201 (n, 1024)
202 } else if let Some(n) = s.strip_suffix("b") {
203 (n, 1)
204 } else {
205 return Err(format!("invalid byte size: {s:?}"));
206 };
207
208 let num: usize = num_part
209 .trim()
210 .parse()
211 .map_err(|_| format!("invalid byte size number: {num_part:?}"))?;
212
213 Ok(num * multiplier)
214}
215
216mod human_bytes {
217 use serde::{Deserialize, Deserializer, Serializer, de};
218
219 pub fn serialize<S: Serializer>(value: &usize, ser: S) -> Result<S::Ok, S::Error> {
220 ser.serialize_u64(*value as u64)
221 }
222
223 pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<usize, D::Error> {
224 #[derive(Deserialize)]
225 #[serde(untagged)]
226 enum ByteSize {
227 Str(String),
228 Num(usize),
229 }
230
231 match ByteSize::deserialize(de)? {
232 ByteSize::Num(n) => Ok(n),
233 ByteSize::Str(s) => super::parse_byte_size(&s).map_err(de::Error::custom),
234 }
235 }
236}