use std::convert::Infallible;
#[cfg(any(docsrs, feature = "localfs"))]
use std::path::Path;
use warp::{
Filter, Reply,
filters::BoxedFilter,
http::{HeaderMap, Method},
};
use crate::{DavHandler, body::Body};
#[cfg(any(docsrs, feature = "localfs"))]
use crate::{fakels::FakeLs, localfs::LocalFs};
pub fn dav_handler(handler: DavHandler) -> BoxedFilter<(impl Reply,)> {
use http::uri::Uri;
use warp::path::{FullPath, Tail};
warp::method()
.and(warp::path::full())
.and(warp::path::tail())
.and(warp::header::headers_cloned())
.and(warp::body::stream())
.and_then(
move |method: Method,
path_full: FullPath,
path_tail: Tail,
headers: HeaderMap,
body| {
let handler = handler.clone();
async move {
let path_str = path_full.as_str();
let uri = path_str.parse::<Uri>().unwrap();
let mut builder = http::Request::builder().method(method.as_ref()).uri(uri);
for (k, v) in headers.iter() {
builder = builder.header(k.as_str(), v.as_ref());
}
let request = builder.body(body).unwrap();
let response = if handler.config.prefix.is_some() {
handler.handle_stream(request).await
} else {
let path_len = path_str.len();
let tail_len = path_tail.as_str().len();
let prefix = path_str[..path_len - tail_len].to_string();
let config = DavHandler::builder().strip_prefix(prefix);
handler.handle_stream_with(config, request).await
};
let response = warp_response(response).unwrap();
Ok::<_, Infallible>(response)
}
},
)
.boxed()
}
#[cfg(any(docsrs, feature = "localfs"))]
pub fn dav_dir(
base: impl AsRef<Path>,
index_html: bool,
auto_index_over_get: bool,
) -> BoxedFilter<(impl Reply,)> {
debug_assert!(
auto_index_over_get,
"See documentation of dav_server::warp::dav_dir(...)."
);
let mut builder = DavHandler::builder()
.filesystem(LocalFs::new(base, false, false, false))
.locksystem(FakeLs::new())
.autoindex(auto_index_over_get);
if index_html {
builder = builder.indexfile("index.html".to_string())
}
let handler = builder.build_handler();
dav_handler(handler)
}
#[cfg(any(docsrs, feature = "localfs"))]
pub fn dav_file(file: impl AsRef<Path>) -> BoxedFilter<(impl Reply,)> {
let handler = DavHandler::builder()
.filesystem(LocalFs::new_file(file, false))
.locksystem(FakeLs::new())
.build_handler();
dav_handler(handler)
}
fn warp_response(
response: http::Response<Body>,
) -> Result<warp::http::Response<warp::hyper::Body>, warp::http::Error> {
let (parts, body) = response.into_parts();
let mut response = warp::http::Response::builder()
.version(warp_http_version(parts.version))
.status(parts.status.as_u16());
let headers = parts.headers.into_iter().filter_map(|(k, v)| Some((k?, v)));
for (k, v) in headers {
response = response.header(k.as_str(), v.as_ref());
}
response.body(warp::hyper::Body::wrap_stream(body))
}
fn warp_http_version(v: http::Version) -> warp::http::Version {
match v {
http::Version::HTTP_3 => warp::http::Version::HTTP_3,
http::Version::HTTP_2 => warp::http::Version::HTTP_2,
http::Version::HTTP_11 => warp::http::Version::HTTP_11,
http::Version::HTTP_10 => warp::http::Version::HTTP_10,
http::Version::HTTP_09 => warp::http::Version::HTTP_09,
v => unreachable!("unexpected HTTP version {:?}", v),
}
}