use crate::app::error_handler;
use crate::http::headers::HeaderType;
use crate::http::mime::MimeType;
use crate::http::{Request, Response, StatusCode};
use crate::route::{try_find_path, LocatedPath};
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
const INDEX_FILES: [&str; 2] = ["index.html", "index.htm"];
pub fn serve_file<T>(file_path: &'static str) -> impl Fn(Request, Arc<T>) -> Response {
let path_buf = PathBuf::from(file_path);
move |_, _| {
if let Ok(mut file) = File::open(&path_buf) {
let mut buf = Vec::new();
if file.read_to_end(&mut buf).is_ok() {
return if let Some(extension) = path_buf.extension() {
Response::new(StatusCode::OK, buf).with_header(
HeaderType::ContentType,
MimeType::from_extension(extension.to_str().unwrap()).to_string(),
)
} else {
Response::new(StatusCode::OK, buf)
};
}
}
error_handler(StatusCode::NotFound)
}
}
pub fn serve_as_file_path<T>(directory_path: &'static str) -> impl Fn(Request, Arc<T>) -> Response {
move |request: Request, _| {
let directory_path = directory_path.strip_suffix('/').unwrap_or(directory_path);
let file_path = request.uri.strip_prefix('/').unwrap_or(&request.uri);
let path = format!("{}/{}", directory_path, file_path);
let path_buf = PathBuf::from(path);
if let Ok(mut file) = File::open(&path_buf) {
let mut buf = Vec::new();
if file.read_to_end(&mut buf).is_ok() {
return if let Some(extension) = path_buf.extension() {
Response::new(StatusCode::OK, buf).with_header(
HeaderType::ContentType,
MimeType::from_extension(extension.to_str().unwrap()).to_string(),
)
} else {
Response::new(StatusCode::OK, buf)
};
}
}
error_handler(StatusCode::NotFound)
}
}
pub fn serve_dir<T>(directory_path: &'static str) -> impl Fn(Request, Arc<T>, &str) -> Response {
move |request: Request, _, route| {
let route_without_wildcard = route.strip_suffix('*').unwrap_or(route);
let uri_without_route = request
.uri
.strip_prefix(route_without_wildcard)
.unwrap_or(&request.uri);
let located = try_find_path(directory_path, uri_without_route, &INDEX_FILES);
if let Some(located) = located {
match located {
LocatedPath::Directory => Response::empty(StatusCode::MovedPermanently)
.with_header(HeaderType::Location, format!("{}/", &request.uri)),
LocatedPath::File(path) => {
if let Ok(mut file) = File::open(&path) {
let mut buf = Vec::new();
if file.read_to_end(&mut buf).is_ok() {
return if let Some(extension) = path.extension() {
Response::new(StatusCode::OK, buf).with_header(
HeaderType::ContentType,
MimeType::from_extension(extension.to_str().unwrap())
.to_string(),
)
} else {
Response::new(StatusCode::OK, buf)
};
}
}
error_handler(StatusCode::InternalError)
}
}
} else {
error_handler(StatusCode::NotFound)
}
}
}
pub fn redirect<T>(location: &'static str) -> impl Fn(Request, Arc<T>) -> Response {
move |_, _| Response::redirect(location)
}