dhttp/services/
files.rs

1//! Files service
2
3use std::path::PathBuf;
4
5use tokio::fs;
6
7use crate::core::{HttpService, HttpResult, HttpRead};
8use crate::reqres::{res, HttpRequest, HttpMethod, StatusCode};
9use crate::util::path;
10
11/// Hosts a directory with static files
12pub struct FilesService {
13    pub path: PathBuf,
14}
15
16impl FilesService {
17    pub fn new(path: impl Into<PathBuf>) -> FilesService {
18        FilesService { path: path.into() }
19    }
20}
21
22impl HttpService for FilesService {
23    async fn request(&self, route: &str, req: &HttpRequest, _body: &mut dyn HttpRead) -> HttpResult {
24        let path = self.path.join(path::sanitize(route)?);
25
26        let metadata = fs::metadata(&path).await?;
27
28        if metadata.is_dir() {
29            Err(StatusCode::NOT_FOUND.into())
30        } else {
31            res::file(req, &path).await
32        }
33    }
34
35    fn filter(&self, _route: &str, req: &HttpRequest) -> HttpResult<()> {
36        if req.method != HttpMethod::Get && req.method != HttpMethod::Head {
37            return Err(StatusCode::METHOD_NOT_ALLOWED.into());
38        }
39        if req.len > 0 { return Err(StatusCode::REQUEST_ENTITY_TOO_LARGE.into()); }
40        Ok(())
41    }
42}