blockless_hyper_file/
filesvr.rs

1use std::{
2    io::{Error, ErrorKind, Result},
3    pin::Pin,
4    result::Result as StdResult,
5    task::{Context, Poll},
6};
7
8use hyper::{service::Service, Request, Response, StatusCode};
9
10use std::future::Future;
11
12use crate::{
13    body::Body,
14    request_resolve::{RequestResolve, Resolved},
15    resp_builder::ResponseBuilder,
16};
17
18#[derive(Clone)]
19pub struct FileService {
20    local_root: String,
21}
22
23impl FileService {
24    pub fn new(root: impl Into<String>) -> Self {
25        let local_root = root.into();
26        Self { local_root }
27    }
28
29    async fn serv<B>(self, request: Request<B>) -> Result<Response<Body>> {
30        let resolved = RequestResolve::resolve(&self.local_root, &request).await?;
31        let resp = match resolved {
32            Resolved::IsDirectory => Response::builder()
33                .status(StatusCode::FORBIDDEN)
34                .body(Body::Empty),
35            Resolved::MethodNotMatched => Response::builder()
36                .status(StatusCode::BAD_REQUEST)
37                .body(Body::Empty),
38            Resolved::NotFound => Response::builder()
39                .status(StatusCode::NOT_FOUND)
40                .body(Body::Empty),
41            Resolved::PermissionDenied => Response::builder()
42                .status(StatusCode::FORBIDDEN)
43                .body(Body::Empty),
44            Resolved::Found(f) => ResponseBuilder::new().request(&request).build(f),
45        };
46        let resp = match resp {
47            Ok(resp) => resp,
48            Err(e) => {
49                let e = Error::new(ErrorKind::Other, e);
50                return Err(e);
51            }
52        };
53        Ok(resp)
54    }
55}
56
57impl<B> Service<Request<B>> for FileService
58where
59    B: Sync + Send + 'static,
60{
61    type Response = Response<Body>;
62
63    type Error = Error;
64
65    type Future = Pin<Box<dyn Future<Output = Result<Self::Response>> + Send>>;
66
67    fn call(&mut self, request: Request<B>) -> Self::Future {
68        Box::pin(self.clone().serv(request))
69    }
70
71    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<()>> {
72        Poll::Ready(Ok(()))
73    }
74}
75
76#[derive(Clone)]
77pub struct FileServiceMaker {
78    local_root: String,
79}
80
81impl FileServiceMaker {
82    pub fn new(local_root: impl Into<String>) -> Self {
83        let local_root = local_root.into();
84        Self { local_root }
85    }
86}
87
88impl<T> Service<T> for FileServiceMaker {
89    type Response = FileService;
90
91    type Error = hyper::Error;
92
93    type Future = Pin<Box<dyn Future<Output = StdResult<Self::Response, Self::Error>> + Send>>;
94
95    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<StdResult<(), Self::Error>> {
96        Poll::Ready(Ok(()))
97    }
98
99    fn call(&mut self, _: T) -> Self::Future {
100        let local_root = self.local_root.clone();
101        Box::pin(async move { Ok(FileService::new(local_root)) })
102    }
103}