diff options
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 82 |
1 files changed, 76 insertions, 6 deletions
diff --git a/src/config.rs b/src/config.rs index c686930..a7abf3b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,7 +3,14 @@ use serde::{ de::{value, Error, SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, }; -use std::{collections::HashMap, fmt, fs::read_to_string, net::SocketAddr, path::PathBuf}; +use std::{ + collections::{HashMap, HashSet}, + fmt, + fs::read_to_string, + marker::PhantomData, + net::SocketAddr, + path::PathBuf, +}; #[derive(Debug, Serialize, Deserialize)] pub struct Config { @@ -12,7 +19,7 @@ pub struct Config { #[serde(default)] pub limits: Limits, #[serde(default)] - pub hosts: HashMap<String, HostConfig>, + pub hosts: HashMap<String, Route>, } #[derive(Debug, Serialize, Deserialize)] @@ -37,10 +44,28 @@ pub struct HttpsConfig { } #[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum HostConfig { - Backend { backend: SocketAddr }, - Files { files: FileserverConfig }, +pub struct Route(#[serde(deserialize_with = "seq_or_not")] pub Vec<RouteFilter>); + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum RouteFilter { + HttpBasicAuth { + #[serde(flatten)] + config: HttpBasicAuthConfig, + }, + Proxy { + backend: SocketAddr, + }, + Files { + #[serde(flatten)] + config: FileserverConfig, + }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct HttpBasicAuthConfig { + pub realm: String, + pub valid: HashSet<String>, } #[derive(Debug, Serialize, Deserialize)] @@ -50,6 +75,51 @@ pub struct FileserverConfig { pub index: bool, } +// try deser Vec<T> but fall back to deser T and putting that in Vec +fn seq_or_not<'de, D, V: Deserialize<'de>>(des: D) -> Result<Vec<V>, D::Error> +where + D: Deserializer<'de>, +{ + struct SeqOrNot<V>(PhantomData<V>); + impl<'de, V: Deserialize<'de>> Visitor<'de> for SeqOrNot<V> { + type Value = Vec<V>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence or not a sequence") + } + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: serde::de::EnumAccess<'de>, + { + Ok(vec![V::deserialize(value::EnumAccessDeserializer::new( + data, + ))?]) + } + fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> + where + A: serde::de::MapAccess<'de>, + { + Ok(vec![V::deserialize(value::MapAccessDeserializer::new( + map, + ))?]) + } + fn visit_str<E>(self, val: &str) -> Result<Vec<V>, E> + where + E: Error, + { + Ok(vec![V::deserialize(value::StrDeserializer::new(val))?]) + } + + fn visit_seq<A>(self, val: A) -> Result<Vec<V>, A::Error> + where + A: SeqAccess<'de>, + { + Vec::<V>::deserialize(value::SeqAccessDeserializer::new(val)) + } + } + des.deserialize_any(SeqOrNot::<V>(PhantomData)) +} + // fall back to expecting a single string and putting that in a 1-length vector fn string_or_seq<'de, D>(des: D) -> Result<Vec<SocketAddr>, D::Error> where |