use std::fs;
use std::path::{Path, PathBuf};
use crate::Response;
pub fn get_mime_type(path: &str) -> &'static str {
let ext = Path::new(path)
.extension()
.and_then(|e| e.to_str())
.unwrap_or("");
match ext {
"html" | "htm" => "text/html;charset=utf-8",
"css" => "text/css;charset=utf-8",
"js" => "application/javascript;charset=utf-8",
"json" => "application/json",
"png" => "image/png",
"jpg" | "jpeg" => "image/jpeg",
"gif" => "image/gif",
"svg" => "image/svg+xml",
"ico" => "image/x-icon",
"webp" => "image/webp",
"txt" => "text/plain;charset=utf-8",
"xml" => "application/xml",
"pdf" => "application/pdf",
"zip" => "application/zip",
"woff" => "font/woff",
"woff2" => "font/woff2",
"ttf" => "font/ttf",
"otf" => "font/otf",
"mp4" => "video/mp4",
"webm" => "video/webm",
"mp3" => "audio/mpeg",
"wav" => "audio/wav",
"wasm" => "application/wasm",
_ => "application/octet-stream",
}
}
pub fn serve_file(root_dir: &str, url_path: &str) -> Response {
let relative_path = url_path.trim_start_matches('/');
let file_path = PathBuf::from(root_dir).join(relative_path);
let canonical_root = match fs::canonicalize(root_dir) {
Ok(p) => p,
Err(_) => return Response::internal_error(),
};
let canonical_path = match fs::canonicalize(&file_path) {
Ok(p) => p,
Err(_) => {
let index_path = file_path.join("index.html");
match fs::canonicalize(&index_path) {
Ok(p) => p,
Err(_) => return Response::not_found(),
}
}
};
if !canonical_path.starts_with(&canonical_root) {
return Response::not_found();
}
if canonical_path.is_dir() {
let index_path = canonical_path.join("index.html");
if index_path.is_file() {
match fs::read(&index_path) {
Ok(data) => {
let mut resp = Response::new(200, data);
resp.headers = vec![
("Content-Type".to_string(), "text/html;charset=utf-8".to_string()),
];
return resp;
}
Err(_) => return Response::not_found(),
}
}
return Response::not_found();
}
match fs::read(&canonical_path) {
Ok(data) => {
let mime = get_mime_type(canonical_path.to_str().unwrap_or(""));
let mut resp = Response::new(200, data);
resp.headers = vec![
("Content-Type".to_string(), mime.to_string()),
];
resp
}
Err(_) => Response::not_found(),
}
}