75 lines
2.1 KiB
Rust
75 lines
2.1 KiB
Rust
//! FileServer
|
|
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
use crate::{
|
|
error::*,
|
|
request::{HttpMethod, HttpRequest},
|
|
responder::Responder,
|
|
response::{HttpResponse, HttpStatus},
|
|
};
|
|
|
|
pub struct FileServer {
|
|
root: PathBuf,
|
|
}
|
|
|
|
impl FileServer {
|
|
pub fn new(root: &PathBuf) -> Result<FileServer> {
|
|
if !root.is_dir() {
|
|
return Err(Error::new(
|
|
ErrorKind::DirNotFound,
|
|
&root.display().to_string(),
|
|
));
|
|
}
|
|
|
|
Ok(Self {
|
|
root: root.to_owned(),
|
|
})
|
|
}
|
|
|
|
pub fn get_contents(&self, path: PathBuf) -> Option<Vec<u8>> {
|
|
let mut fullpath = self.root.as_path().join(path);
|
|
// default to index.html
|
|
if fullpath.is_dir() {
|
|
fullpath.push("index.html");
|
|
}
|
|
fs::read(fullpath).ok()
|
|
}
|
|
}
|
|
|
|
impl Responder for FileServer {
|
|
fn respond(&self, req: HttpRequest) -> HttpResponse {
|
|
if req.version != "HTTP/1.1" {
|
|
return HttpResponse::new_empty(HttpStatus::HTTPVersionNotSupported);
|
|
}
|
|
|
|
if req.method != HttpMethod::GET {
|
|
return HttpResponse::new_empty(HttpStatus::MethodNotAllowed);
|
|
}
|
|
|
|
let content_type = match req.path.extension() {
|
|
Some(s) => match s.as_encoded_bytes() {
|
|
b"html" | b"htm" => "text/html",
|
|
b"txt" => "text/plain",
|
|
b"css" => "text/css",
|
|
b"js" => "text/javascript",
|
|
b"pdf" => "application/pdf",
|
|
b"json" => "application/json",
|
|
b"xml" => "application/xml",
|
|
b"gif" => "image/gif",
|
|
b"jpeg" | b"jpg" => "image/jpg",
|
|
b"png" => "image/png",
|
|
_ => "text/plain",
|
|
},
|
|
None => "text/html",
|
|
};
|
|
|
|
if let Some(content) = self.get_contents(req.path) {
|
|
HttpResponse::new(HttpStatus::Ok, content).add_header("Content-Type", content_type)
|
|
} else {
|
|
HttpResponse::new_empty(HttpStatus::NotFound).add_header("Connection", "close")
|
|
}
|
|
}
|
|
}
|