rustical_dav/resource/
axum_service.rs1use super::methods::{axum_route_propfind, axum_route_proppatch};
2use crate::resource::{
3 ResourceService,
4 axum_methods::AxumMethods,
5 methods::{axum_route_copy, axum_route_move},
6};
7use axum::{
8 body::Body,
9 extract::FromRequestParts,
10 handler::Handler,
11 http::{Request, Response},
12 response::IntoResponse,
13};
14use futures_util::future::BoxFuture;
15use headers::HeaderMapExt;
16use http::{HeaderValue, StatusCode};
17use std::convert::Infallible;
18use tower::Service;
19
20#[derive(Clone)]
21pub struct AxumService<RS: ResourceService + AxumMethods> {
22 resource_service: RS,
23}
24
25impl<RS: ResourceService + AxumMethods> AxumService<RS> {
26 pub fn new(resource_service: RS) -> Self {
27 Self { resource_service }
28 }
29}
30
31impl<RS: ResourceService + AxumMethods + Clone + Send + Sync> Service<Request<Body>>
32 for AxumService<RS>
33where
34 RS::Error: IntoResponse + Send + Sync + 'static,
35 RS::Principal: FromRequestParts<RS>,
36{
37 type Error = Infallible;
38 type Response = Response<Body>;
39 type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
40
41 #[inline]
42 fn poll_ready(
43 &mut self,
44 _cx: &mut std::task::Context<'_>,
45 ) -> std::task::Poll<Result<(), Self::Error>> {
46 Ok(()).into()
47 }
48
49 #[inline]
50 fn call(&mut self, req: Request<Body>) -> Self::Future {
51 use crate::resource::methods::axum_route_delete;
52 let mut propfind_service =
53 Handler::with_state(axum_route_propfind::<RS>, self.resource_service.clone());
54 let mut proppatch_service =
55 Handler::with_state(axum_route_proppatch::<RS>, self.resource_service.clone());
56 let mut delete_service =
57 Handler::with_state(axum_route_delete::<RS>, self.resource_service.clone());
58 let mut move_service =
59 Handler::with_state(axum_route_move::<RS>, self.resource_service.clone());
60 let mut copy_service =
61 Handler::with_state(axum_route_copy::<RS>, self.resource_service.clone());
62 let mut options_service = Handler::with_state(route_options::<RS>, ());
63 match req.method().as_str() {
64 "PROPFIND" => return Box::pin(Service::call(&mut propfind_service, req)),
65 "PROPPATCH" => return Box::pin(Service::call(&mut proppatch_service, req)),
66 "DELETE" => return Box::pin(Service::call(&mut delete_service, req)),
67 "OPTIONS" => return Box::pin(Service::call(&mut options_service, req)),
68 "MOVE" => return Box::pin(Service::call(&mut move_service, req)),
69 "COPY" => return Box::pin(Service::call(&mut copy_service, req)),
70 "REPORT" => {
71 if let Some(svc) = RS::report() {
72 return svc(self.resource_service.clone(), req);
73 }
74 }
75 "GET" | "HEAD" => {
76 if let Some(svc) = RS::get() {
77 return svc(self.resource_service.clone(), req);
78 }
79 }
80 "POST" => {
81 if let Some(svc) = RS::post() {
82 return svc(self.resource_service.clone(), req);
83 }
84 }
85 "MKCOL" => {
86 if let Some(svc) = RS::mkcol() {
87 return svc(self.resource_service.clone(), req);
88 }
89 }
90 "MKCALENDAR" => {
91 if let Some(svc) = RS::mkcalendar() {
92 return svc(self.resource_service.clone(), req);
93 }
94 }
95 "PUT" => {
96 if let Some(svc) = RS::put() {
97 return svc(self.resource_service.clone(), req);
98 }
99 }
100 _ => {}
101 };
102 Box::pin(async move {
103 Ok(Response::builder()
104 .status(StatusCode::METHOD_NOT_ALLOWED)
105 .body(Body::from("Method not allowed"))
106 .unwrap())
107 })
108 }
109}
110
111async fn route_options<RS: ResourceService + AxumMethods>() -> Response<Body> {
112 let mut resp = Response::builder().status(StatusCode::OK);
116 let headers = resp.headers_mut().unwrap();
117 headers.insert("DAV", HeaderValue::from_static(RS::DAV_HEADER));
118 headers.typed_insert(RS::allow_header());
119 resp.body(Body::empty()).unwrap()
120}