use clap::Parser;
use mime_guess::mime::FromStrError;
use mime_guess::Mime;
use crate::deserialize::{DeserializeMap, OneOrMany};
use serde::Deserialize;
use std::ffi::OsString;
use std::path::PathBuf;
use crate::compression_algorithm::CompressionAlgorithm;
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(try_from = "String")]
pub enum MimeMatch {
Exact(Mime),
Type(String),
Prefix(String),
Suffix(String),
}
impl TryFrom<&str> for MimeMatch {
type Error = FromStrError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(if let Some(prefix) = value.strip_suffix('*') {
if let Some(type_) = prefix.strip_suffix('/') {
Self::Type(type_.to_owned())
} else {
Self::Prefix(prefix.to_owned())
}
} else if let Some(suffix) = value.strip_prefix('*') {
Self::Suffix(suffix.to_owned())
} else {
Self::Exact(value.parse()?)
})
}
}
impl TryFrom<String> for MimeMatch {
type Error = FromStrError;
fn try_from(value: String) -> Result<Self, Self::Error> {
value.as_str().try_into()
}
}
#[derive(Debug, Default, Parser)]
pub struct StaticFilesOpt {
#[clap(short, long, value_parser = clap::value_parser!(OsString))]
pub root: Option<PathBuf>,
#[clap(long)]
pub canonicalize_uri: Option<bool>,
#[clap(long)]
pub index_file: Option<Vec<String>>,
#[clap(long)]
pub page_404: Option<String>,
#[clap(long, value_parser = clap::value_parser!(String))]
pub precompressed: Option<Vec<CompressionAlgorithm>>,
#[clap(long)]
pub declare_charset: Option<String>,
#[clap(long, value_parser = clap::value_parser!(String))]
pub declare_charset_types: Option<Vec<MimeMatch>>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticFilesConf {
pub root: Option<PathBuf>,
pub canonicalize_uri: bool,
pub index_file: OneOrMany<String>,
pub page_404: Option<String>,
pub precompressed: OneOrMany<CompressionAlgorithm>,
pub declare_charset: String,
pub declare_charset_types: OneOrMany<MimeMatch>,
}
impl StaticFilesConf {
pub fn merge_with_opt(&mut self, opt: StaticFilesOpt) {
if opt.root.is_some() {
self.root = opt.root;
}
if let Some(canonicalize_uri) = opt.canonicalize_uri {
self.canonicalize_uri = canonicalize_uri;
}
if let Some(index_file) = opt.index_file {
self.index_file = index_file.into();
}
if opt.page_404.is_some() {
self.page_404 = opt.page_404;
}
if let Some(precompressed) = opt.precompressed {
self.precompressed = precompressed.into();
}
if let Some(declare_charset) = opt.declare_charset {
self.declare_charset = declare_charset;
}
if let Some(declare_charset_types) = opt.declare_charset_types {
self.declare_charset_types = declare_charset_types.into();
}
}
}
impl Default for StaticFilesConf {
fn default() -> Self {
Self {
root: None,
canonicalize_uri: true,
index_file: Default::default(),
page_404: None,
precompressed: Default::default(),
declare_charset: "utf-8".to_owned(),
declare_charset_types: Default::default(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use test_log::test;
#[test]
fn mime_match_parsing() {
assert_eq!(
MimeMatch::try_from("*").unwrap(),
MimeMatch::Prefix("".to_owned())
);
assert_eq!(
MimeMatch::try_from("text*").unwrap(),
MimeMatch::Prefix("text".to_owned())
);
assert_eq!(
MimeMatch::try_from("text/*").unwrap(),
MimeMatch::Type("text".to_owned())
);
assert_eq!(
MimeMatch::try_from("*+xml").unwrap(),
MimeMatch::Suffix("+xml".to_owned())
);
assert_eq!(
MimeMatch::try_from("text/xml").unwrap(),
MimeMatch::Exact("text/xml".parse().unwrap())
);
}
}