1use std::convert::Infallible;
9#[cfg(any(docsrs, feature = "localfs"))]
10use std::path::Path;
11
12use warp::{
13 Filter, Reply,
14 filters::BoxedFilter,
15 http::{HeaderMap, Method},
16};
17
18use crate::{DavHandler, body::Body};
19#[cfg(any(docsrs, feature = "localfs"))]
20use crate::{fakels::FakeLs, localfs::LocalFs};
21
22pub fn dav_handler(handler: DavHandler) -> BoxedFilter<(impl Reply,)> {
27 use http::uri::Uri;
28 use warp::path::{FullPath, Tail};
29
30 warp::method()
31 .and(warp::path::full())
32 .and(warp::path::tail())
33 .and(warp::header::headers_cloned())
34 .and(warp::body::stream())
35 .and_then(
36 move |method: Method,
37 path_full: FullPath,
38 path_tail: Tail,
39 headers: HeaderMap,
40 body| {
41 let handler = handler.clone();
42
43 async move {
44 let path_str = path_full.as_str();
46 let uri = path_str.parse::<Uri>().unwrap();
47 let mut builder = http::Request::builder().method(method.as_ref()).uri(uri);
48 for (k, v) in headers.iter() {
49 builder = builder.header(k.as_str(), v.as_ref());
50 }
51 let request = builder.body(body).unwrap();
52
53 let response = if handler.config.prefix.is_some() {
54 handler.handle_stream(request).await
56 } else {
57 let path_len = path_str.len();
59 let tail_len = path_tail.as_str().len();
60 let prefix = path_str[..path_len - tail_len].to_string();
61 let config = DavHandler::builder().strip_prefix(prefix);
62 handler.handle_stream_with(config, request).await
63 };
64
65 let response = warp_response(response).unwrap();
67 Ok::<_, Infallible>(response)
68 }
69 },
70 )
71 .boxed()
72}
73
74#[cfg(any(docsrs, feature = "localfs"))]
96pub fn dav_dir(
97 base: impl AsRef<Path>,
98 index_html: bool,
99 auto_index_over_get: bool,
100) -> BoxedFilter<(impl Reply,)> {
101 debug_assert!(
102 auto_index_over_get,
103 "See documentation of dav_server::warp::dav_dir(...)."
104 );
105 let mut builder = DavHandler::builder()
106 .filesystem(LocalFs::new(base, false, false, false))
107 .locksystem(FakeLs::new())
108 .autoindex(auto_index_over_get);
109 if index_html {
110 builder = builder.indexfile("index.html".to_string())
111 }
112 let handler = builder.build_handler();
113 dav_handler(handler)
114}
115
116#[cfg(any(docsrs, feature = "localfs"))]
119pub fn dav_file(file: impl AsRef<Path>) -> BoxedFilter<(impl Reply,)> {
120 let handler = DavHandler::builder()
121 .filesystem(LocalFs::new_file(file, false))
122 .locksystem(FakeLs::new())
123 .build_handler();
124 dav_handler(handler)
125}
126
127fn warp_response(
130 response: http::Response<Body>,
131) -> Result<warp::http::Response<warp::hyper::Body>, warp::http::Error> {
132 let (parts, body) = response.into_parts();
133 let mut response = warp::http::Response::builder()
135 .version(warp_http_version(parts.version))
136 .status(parts.status.as_u16());
137 let headers = parts.headers.into_iter().filter_map(|(k, v)| Some((k?, v)));
139 for (k, v) in headers {
140 response = response.header(k.as_str(), v.as_ref());
141 }
142 response.body(warp::hyper::Body::wrap_stream(body))
143}
144
145fn warp_http_version(v: http::Version) -> warp::http::Version {
148 match v {
149 http::Version::HTTP_3 => warp::http::Version::HTTP_3,
150 http::Version::HTTP_2 => warp::http::Version::HTTP_2,
151 http::Version::HTTP_11 => warp::http::Version::HTTP_11,
152 http::Version::HTTP_10 => warp::http::Version::HTTP_10,
153 http::Version::HTTP_09 => warp::http::Version::HTTP_09,
154 v => unreachable!("unexpected HTTP version {:?}", v),
155 }
156}