161 lines
5.2 KiB
Rust
161 lines
5.2 KiB
Rust
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#"<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Not Found</title>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Not Found</h1>
|
|
<p>The requested resource could not be found.</p>
|
|
<p><a href="https://simple.wikipedia.org/wiki/HTTP_404"><small><em>
|
|
Read mode about this error.
|
|
</em></small></a></p>
|
|
</main>
|
|
</body>
|
|
</html>"#;
|
|
|
|
pub const STATIC_500_DEFAULT: &str = r#"<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Internal Server Error</title>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Internal Server Error</h1>
|
|
<p>DEFAULT_ERROR_MESSAGE</p>
|
|
<p><a href="https://en.wikipedia.org/wiki/HTTP_500"><small><em>
|
|
Read mode about this error.
|
|
</em></small></a></p>
|
|
</main>
|
|
</body>
|
|
</html>"#;
|
|
|
|
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<u8> {
|
|
// 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<u8> {
|
|
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<String> {
|
|
content_type_for_exension(ext.and_then(|x| x.to_str()))
|
|
}
|
|
|
|
pub fn content_type_for_exension(ext: Option<&str>) -> Option<String> {
|
|
Some(
|
|
mime_guess::from_ext(ext?)
|
|
.first()?
|
|
.essence_str()
|
|
.to_string(),
|
|
)
|
|
}
|
|
|
|
pub fn parse_modified_since<T: AsRef<str>>(modified_since: Option<T>) -> Option<DateTime<Utc>> {
|
|
modified_since.and_then(|s| {
|
|
DateTime::parse_from_rfc2822(s.as_ref())
|
|
.ok()
|
|
.map(|x| x.into())
|
|
})
|
|
}
|
|
|
|
pub fn parse_modified_since_or_epoch<T: AsRef<str>>(modified_since: Option<T>) -> DateTime<Utc> {
|
|
parse_modified_since(modified_since)
|
|
.unwrap_or_else(|| DateTime::<Utc>::from(SystemTime::UNIX_EPOCH))
|
|
}
|
|
|
|
pub fn datetime_to_secs(datetime: DateTime<Utc>) -> i64 {
|
|
datetime
|
|
.signed_duration_since::<Utc>(DateTime::<Utc>::from(SystemTime::UNIX_EPOCH))
|
|
.num_seconds()
|
|
}
|
|
|
|
// pub fn parse_modified_since_or_epoch_as_secs<T: AsRef<str>>(modified_since: Option<T>) -> 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<Item = PathBuf> + '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)
|
|
})
|
|
})
|
|
}
|