61 lines
1.9 KiB
Rust
61 lines
1.9 KiB
Rust
/// A simple handler for disk based files. Will optionally chop off a prefix.
|
|
use super::{Handler as MajHandler, Request, Result};
|
|
use crate::Response;
|
|
use async_trait::async_trait;
|
|
use std::ffi::OsStr;
|
|
use std::path::PathBuf;
|
|
|
|
pub struct Handler {
|
|
base_dir: PathBuf,
|
|
}
|
|
|
|
impl Handler {
|
|
/// Serves static files from an OS directory with a given prefix chopped off.
|
|
pub fn new(base_dir: PathBuf) -> Self {
|
|
Handler { base_dir: base_dir }
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl MajHandler for Handler {
|
|
async fn handle(&self, r: Request) -> Result<Response> {
|
|
let mut path = std::path::PathBuf::from(&self.base_dir);
|
|
if let Some(segments) = r.url.path_segments() {
|
|
path.extend(segments);
|
|
}
|
|
|
|
log::debug!("opening file {:?}", path);
|
|
|
|
match async_std::fs::metadata(&path).await {
|
|
Ok(stat) => {
|
|
if stat.is_dir() {
|
|
if r.url.as_str().ends_with('/') {
|
|
path.push("index.gmi");
|
|
} else {
|
|
// Send a redirect when the URL for a directory has no trailing slash.
|
|
return Ok(Response::perm_redirect(format!("{}/", r.url)));
|
|
}
|
|
}
|
|
}
|
|
Err(why) => {
|
|
log::error!("file {} not found: {}", path.to_str().unwrap(), why);
|
|
return Ok(Response::not_found());
|
|
}
|
|
}
|
|
|
|
let mut file = async_std::fs::File::open(&path).await?;
|
|
let mut buf: Vec<u8> = Vec::new();
|
|
async_std::io::copy(&mut file, &mut buf).await?;
|
|
|
|
// Send header.
|
|
if path.extension() == Some(OsStr::new("gmi"))
|
|
|| path.extension() == Some(OsStr::new("gemini"))
|
|
{
|
|
return Ok(Response::gemini(buf));
|
|
}
|
|
|
|
let mime = mime_guess::from_path(&path).first_or_octet_stream();
|
|
Ok(Response::with_body(mime.essence_str().to_string(), buf))
|
|
}
|
|
}
|