1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_web::body::BoxBody;
use actix_web::error::PayloadError;
use actix_web::{dev, Error, FromRequest, HttpRequest, HttpResponse};
use bytes::Bytes;
use futures_util::{future, Stream};
use pin_project::pin_project;
pub struct DavRequest {
pub request: http::Request<DavBody>,
prefix: Option<String>,
}
impl DavRequest {
pub fn prefix(&self) -> Option<&str> {
self.prefix.as_ref().map(|s| s.as_str())
}
}
impl FromRequest for DavRequest {
type Error = Error;
type Future = future::Ready<Result<DavRequest, Error>>;
fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
let mut builder = http::Request::builder()
.method(req.method().to_owned())
.uri(req.uri().to_owned())
.version(req.version().to_owned());
for (name, value) in req.headers().iter() {
builder = builder.header(name, value);
}
let path = req.match_info().path();
let tail = req.match_info().unprocessed();
let prefix = match &path[..path.len() - tail.len()] {
"" | "/" => None,
x => Some(x.to_string()),
};
let body = DavBody {
body: payload.take(),
};
let stdreq = DavRequest {
request: builder.body(body).unwrap(),
prefix,
};
future::ready(Ok(stdreq))
}
}
#[pin_project]
pub struct DavBody {
#[pin]
body: dev::Payload,
}
impl http_body::Body for DavBody {
type Data = Bytes;
type Error = io::Error;
fn poll_data(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
let this = self.project();
match this.body.poll_next(cx) {
Poll::Ready(Some(Ok(data))) => Poll::Ready(Some(Ok(data))),
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(match err {
PayloadError::Incomplete(Some(err)) => err,
PayloadError::Incomplete(None) => io::ErrorKind::BrokenPipe.into(),
PayloadError::Io(err) => err,
other => io::Error::new(io::ErrorKind::Other, format!("{:?}", other)),
}))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
fn poll_trailers(
self: Pin<&mut Self>,
_cx: &mut Context,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
Poll::Ready(Ok(None))
}
}
pub struct DavResponse(pub http::Response<crate::body::Body>);
impl From<http::Response<crate::body::Body>> for DavResponse {
fn from(resp: http::Response<crate::body::Body>) -> DavResponse {
DavResponse(resp)
}
}
impl actix_web::Responder for DavResponse {
type Body = BoxBody;
fn respond_to(self, _req: &HttpRequest) -> HttpResponse<BoxBody> {
use crate::body::{Body, BodyType};
let (parts, body) = self.0.into_parts();
let mut builder = HttpResponse::build(parts.status);
for (name, value) in parts.headers.into_iter() {
builder.append_header((name.unwrap(), value));
}
let resp = match body.inner {
BodyType::Bytes(None) => builder.body(""),
BodyType::Bytes(Some(b)) => builder.body(b),
BodyType::Empty => builder.body(""),
b @ BodyType::AsyncStream(..) => builder.streaming(Body { inner: b }),
};
resp
}
}