blockless_hyper_file/
filesvr.rs1use 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}