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) }) }) }