use std::{
ffi::OsStr,
fs,
path::{Path, PathBuf},
time::SystemTime,
};
use chrono::{DateTime, Utc};
pub static DOUBLE_NEW_LINES_UNIX: [u8; 2] = [b'\n', b'\n'];
pub static DOUBLE_NEW_LINES_WIN: [u8; 4] = [b'\r', b'\n', b'\r', b'\n'];
pub const STATIC_404_DEFAULT: &str = r#"
Not Found
Not Found
The requested resource could not be found.
Read mode about this error.
"#;
pub const STATIC_500_DEFAULT: &str = r#"
Internal Server Error
Internal Server Error
DEFAULT_ERROR_MESSAGE
Read mode about this error.
"#;
pub fn render_http500(reason: Option<&str>) -> String {
STATIC_500_DEFAULT.replace(
"DEFAULT_ERROR_MESSAGE",
reason.unwrap_or("A generic and unspecified error happened server-side."),
)
}
pub const HEX_ASCII_VALID_STR: &str = "0123456789ABCDEFabcdef";
//pub static HEX_ASCII_VALID_STA: &str = HEX_ASCII_VALID_STR;
pub static HEX_ASCII_VALID_STA_U8: &[u8] = HEX_ASCII_VALID_STR.as_bytes();
pub static PCT_ASCII: u8 = "%".as_bytes()[0];
pub static QSM_ASCII: u8 = "?".as_bytes()[0];
pub static AMP_ASCII: u8 = "&".as_bytes()[0];
pub static EQL_ASCII: u8 = "=".as_bytes()[0];
// pub fn charhex2val(c: char) -> Option {
// HEX_ASCII_VALID_STA.chars().position(|x| x == c).map(|x| (if x < 16 {x} else {x-6}) as u8 )
// }
pub fn bytehex2val(c: u8) -> Option {
HEX_ASCII_VALID_STA_U8
.iter()
.position(|x| *x == c)
.map(|x| (if x < 16 { x } else { x - 6 }) as u8)
}
pub fn content_type_for_exension_osstr(ext: Option<&OsStr>) -> Option {
content_type_for_exension(ext.and_then(|x| x.to_str()))
}
pub fn content_type_for_exension(ext: Option<&str>) -> Option {
Some(
mime_guess::from_ext(ext?)
.first()?
.essence_str()
.to_string(),
)
}
pub fn parse_modified_since>(modified_since: Option) -> Option> {
modified_since.and_then(|s| {
DateTime::parse_from_rfc2822(s.as_ref())
.ok()
.map(|x| x.into())
})
}
pub fn parse_modified_since_or_epoch>(modified_since: Option) -> DateTime {
parse_modified_since(modified_since)
.unwrap_or_else(|| DateTime::::from(SystemTime::UNIX_EPOCH))
}
pub fn datetime_to_secs(datetime: DateTime) -> i64 {
datetime
.signed_duration_since::(DateTime::::from(SystemTime::UNIX_EPOCH))
.num_seconds()
}
// pub fn parse_modified_since_or_epoch_as_secs>(modified_since: Option) -> i64 {
// datetime_to_secs(parse_modified_since_or_epoch(modified_since))
// }
pub fn gen_true() -> bool {
true
}
pub fn escape_html(src: &str) -> String {
src.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
.replace('\'', "'")
}
#[inline(always)]
pub fn search_for_file<'a>(
route_dot_path: &'a Path,
requested_file: &'a str,
try_files: &'a [String],
subdomain: Option<&'a str>,
) -> impl Iterator- + 'a {
route_dot_path
.canonicalize()
.into_iter()
.flat_map(move |route_path_canonical| {
Some(route_path_canonical.clone())
.into_iter()
.chain(subdomain.and_then(|df| route_dot_path.join(df).canonicalize().ok()))
.map(move |x| (x, route_path_canonical.clone()))
})
.flat_map(move |(route_path, route_path_canonical)| {
let requested_relative_path = route_path.join(requested_file);
Some(requested_relative_path.clone())
.into_iter()
.chain(try_files.iter().flat_map(move |try_file| {
Some(requested_relative_path.join(try_file))
.into_iter()
.chain(try_file.starts_with('.').then_some(()).and_then(|_| {
requested_relative_path
.file_name()
.and_then(OsStr::to_str)
.map(|fnm| {
requested_relative_path
.with_file_name(format!("{}{}", fnm, try_file))
})
}))
}))
.map(move |x| (x, route_path_canonical.clone()))
})
.filter_map(move |(possible_path, route_path_canonical)| {
fs::canonicalize(possible_path)
.into_iter()
.find(|canonical_path| {
canonical_path.is_file() && canonical_path.starts_with(&route_path_canonical)
})
})
}