1use std::{
16 convert::TryInto,
17 io,
18 pin::Pin,
19 task::{Context, Poll},
20};
21
22use actix_web::body::BoxBody;
23use actix_web::error::PayloadError;
24use actix_web::{dev, Error, FromRequest, HttpRequest, HttpResponse};
25use bytes::Bytes;
26use futures_util::{future, Stream};
27use pin_project::pin_project;
28
29pub struct DavRequest {
33 pub request: http::Request<DavBody>,
34 prefix: Option<String>,
35}
36
37impl DavRequest {
38 pub fn prefix(&self) -> Option<&str> {
40 self.prefix.as_ref().map(|s| s.as_str())
41 }
42}
43
44impl FromRequest for DavRequest {
45 type Error = Error;
46 type Future = future::Ready<Result<DavRequest, Error>>;
47
48 fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
49 let mut builder = http::Request::builder()
50 .method(req.method().as_ref())
51 .uri(req.uri().to_string())
52 .version(from_actix_http_version(req.version()));
53 for (name, value) in req.headers().iter() {
54 builder = builder.header(name.as_str(), value.as_ref());
55 }
56 let path = req.match_info().unprocessed();
57 let tail = req.match_info().unprocessed();
58 let prefix = match &path[..path.len() - tail.len()] {
59 "" | "/" => None,
60 x => Some(x.to_string()),
61 };
62
63 let body = DavBody {
64 body: payload.take(),
65 };
66 let stdreq = DavRequest {
67 request: builder.body(body).unwrap(),
68 prefix,
69 };
70 future::ready(Ok(stdreq))
71 }
72}
73
74#[pin_project]
78pub struct DavBody {
79 #[pin]
80 body: dev::Payload,
81}
82
83impl http_body::Body for DavBody {
84 type Data = Bytes;
85 type Error = io::Error;
86
87 fn poll_frame(
88 self: Pin<&mut Self>,
89 cx: &mut Context<'_>,
90 ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
91 self.project()
92 .body
93 .poll_next(cx)
94 .map_ok(http_body::Frame::data)
95 .map_err(|err| match err {
96 PayloadError::Incomplete(Some(err)) => err,
97 PayloadError::Incomplete(None) => io::ErrorKind::BrokenPipe.into(),
98 PayloadError::Io(err) => err,
99 err => io::Error::new(io::ErrorKind::Other, format!("{err:?}")),
100 })
101 }
102}
103
104pub struct DavResponse(pub http::Response<crate::body::Body>);
108
109impl From<http::Response<crate::body::Body>> for DavResponse {
110 fn from(resp: http::Response<crate::body::Body>) -> DavResponse {
111 DavResponse(resp)
112 }
113}
114
115impl actix_web::Responder for DavResponse {
116 type Body = BoxBody;
117
118 fn respond_to(self, _req: &HttpRequest) -> HttpResponse<BoxBody> {
119 use crate::body::{Body, BodyType};
120
121 let (parts, body) = self.0.into_parts();
122 let mut builder = HttpResponse::build(parts.status.as_u16().try_into().unwrap());
123 for (name, value) in parts.headers.into_iter() {
124 builder.append_header((name.unwrap().as_str(), value.as_ref()));
125 }
126 let resp = match body.inner {
132 BodyType::Bytes(None) => builder.body(""),
133 BodyType::Bytes(Some(b)) => builder.body(b),
134 BodyType::Empty => builder.body(""),
135 b @ BodyType::AsyncStream(..) => builder.streaming(Body { inner: b }),
136 };
137 resp
138 }
139}
140
141fn from_actix_http_version(v: actix_web::http::Version) -> http::Version {
144 match v {
145 actix_web::http::Version::HTTP_3 => http::Version::HTTP_3,
146 actix_web::http::Version::HTTP_2 => http::Version::HTTP_2,
147 actix_web::http::Version::HTTP_11 => http::Version::HTTP_11,
148 actix_web::http::Version::HTTP_10 => http::Version::HTTP_10,
149 actix_web::http::Version::HTTP_09 => http::Version::HTTP_09,
150 v => unreachable!("unexpected HTTP version {:?}", v),
151 }
152}