1use std::fmt::Debug;
19use std::fmt::Formatter;
20use std::str::FromStr;
21use std::sync::Arc;
22
23use http::Response;
24use http::StatusCode;
25use log::debug;
26
27use super::core::*;
28use super::delete::WebdavDeleter;
29use super::error::parse_error;
30use super::lister::WebdavLister;
31use super::writer::WebdavWriter;
32use crate::raw::*;
33use crate::services::WebdavConfig;
34use crate::*;
35
36impl Configurator for WebdavConfig {
37 type Builder = WebdavBuilder;
38
39 #[allow(deprecated)]
40 fn into_builder(self) -> Self::Builder {
41 WebdavBuilder {
42 config: self,
43 http_client: None,
44 }
45 }
46}
47
48#[doc = include_str!("docs.md")]
50#[derive(Default)]
51pub struct WebdavBuilder {
52 config: WebdavConfig,
53
54 #[deprecated(since = "0.53.0", note = "Use `Operator::update_http_client` instead")]
55 http_client: Option<HttpClient>,
56}
57
58impl Debug for WebdavBuilder {
59 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60 let mut d = f.debug_struct("WebdavBuilder");
61
62 d.field("config", &self.config);
63
64 d.finish_non_exhaustive()
65 }
66}
67
68impl WebdavBuilder {
69 pub fn endpoint(mut self, endpoint: &str) -> Self {
73 self.config.endpoint = if endpoint.is_empty() {
74 None
75 } else {
76 Some(endpoint.to_string())
77 };
78
79 self
80 }
81
82 pub fn username(mut self, username: &str) -> Self {
86 if !username.is_empty() {
87 self.config.username = Some(username.to_owned());
88 }
89 self
90 }
91
92 pub fn password(mut self, password: &str) -> Self {
96 if !password.is_empty() {
97 self.config.password = Some(password.to_owned());
98 }
99 self
100 }
101
102 pub fn token(mut self, token: &str) -> Self {
106 if !token.is_empty() {
107 self.config.token = Some(token.to_string());
108 }
109 self
110 }
111
112 pub fn root(mut self, root: &str) -> Self {
114 self.config.root = if root.is_empty() {
115 None
116 } else {
117 Some(root.to_string())
118 };
119
120 self
121 }
122
123 #[deprecated(since = "0.53.0", note = "Use `Operator::update_http_client` instead")]
130 #[allow(deprecated)]
131 pub fn http_client(mut self, client: HttpClient) -> Self {
132 self.http_client = Some(client);
133 self
134 }
135}
136
137impl Builder for WebdavBuilder {
138 const SCHEME: Scheme = Scheme::Webdav;
139 type Config = WebdavConfig;
140
141 fn build(self) -> Result<impl Access> {
142 debug!("backend build started: {:?}", &self);
143
144 let endpoint = match &self.config.endpoint {
145 Some(v) => v,
146 None => {
147 return Err(Error::new(ErrorKind::ConfigInvalid, "endpoint is empty")
148 .with_context("service", Scheme::Webdav));
149 }
150 };
151 let server_path = http::Uri::from_str(endpoint)
153 .map_err(|err| {
154 Error::new(ErrorKind::ConfigInvalid, "endpoint is invalid")
155 .with_context("service", Scheme::Webdav)
156 .set_source(err)
157 })?
158 .path()
159 .trim_end_matches('/')
160 .to_string();
161
162 let root = normalize_root(&self.config.root.clone().unwrap_or_default());
163 debug!("backend use root {}", root);
164
165 let mut authorization = None;
166 if let Some(username) = &self.config.username {
167 authorization = Some(format_authorization_by_basic(
168 username,
169 self.config.password.as_deref().unwrap_or_default(),
170 )?);
171 }
172 if let Some(token) = &self.config.token {
173 authorization = Some(format_authorization_by_bearer(token)?)
174 }
175
176 let core = Arc::new(WebdavCore {
177 info: {
178 let am = AccessorInfo::default();
179 am.set_scheme(Scheme::Webdav)
180 .set_root(&root)
181 .set_native_capability(Capability {
182 stat: true,
183 stat_has_content_length: true,
184 stat_has_content_type: true,
185 stat_has_etag: true,
186 stat_has_last_modified: true,
187
188 read: true,
189
190 write: true,
191 write_can_empty: true,
192
193 create_dir: true,
194 delete: true,
195
196 copy: !self.config.disable_copy,
197
198 rename: true,
199
200 list: true,
201 list_has_content_length: true,
202 list_has_content_type: true,
203 list_has_etag: true,
204 list_has_last_modified: true,
205
206 shared: true,
209
210 ..Default::default()
211 });
212
213 #[allow(deprecated)]
215 if let Some(client) = self.http_client {
216 am.update_http_client(|_| client);
217 }
218
219 am.into()
220 },
221 endpoint: endpoint.to_string(),
222 server_path,
223 authorization,
224 root,
225 });
226 Ok(WebdavBackend { core })
227 }
228}
229
230#[derive(Clone)]
232pub struct WebdavBackend {
233 core: Arc<WebdavCore>,
234}
235
236impl Debug for WebdavBackend {
237 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
238 f.debug_struct("WebdavBackend")
239 .field("core", &self.core)
240 .finish()
241 }
242}
243
244impl Access for WebdavBackend {
245 type Reader = HttpBody;
246 type Writer = oio::OneShotWriter<WebdavWriter>;
247 type Lister = oio::PageLister<WebdavLister>;
248 type Deleter = oio::OneShotDeleter<WebdavDeleter>;
249 type BlockingReader = ();
250 type BlockingWriter = ();
251 type BlockingLister = ();
252 type BlockingDeleter = ();
253
254 fn info(&self) -> Arc<AccessorInfo> {
255 self.core.info.clone()
256 }
257
258 async fn create_dir(&self, path: &str, _: OpCreateDir) -> Result<RpCreateDir> {
259 self.core.webdav_mkcol(path).await?;
260 Ok(RpCreateDir::default())
261 }
262
263 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
264 let metadata = self.core.webdav_stat(path).await?;
265 Ok(RpStat::new(metadata))
266 }
267
268 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
269 let resp = self.core.webdav_get(path, args.range(), &args).await?;
270
271 let status = resp.status();
272
273 match status {
274 StatusCode::OK | StatusCode::PARTIAL_CONTENT => {
275 Ok((RpRead::default(), resp.into_body()))
276 }
277 _ => {
278 let (part, mut body) = resp.into_parts();
279 let buf = body.to_buffer().await?;
280 Err(parse_error(Response::from_parts(part, buf)))
281 }
282 }
283 }
284
285 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
286 self.core.webdav_mkcol(get_parent(path)).await?;
288
289 Ok((
290 RpWrite::default(),
291 oio::OneShotWriter::new(WebdavWriter::new(self.core.clone(), args, path.to_string())),
292 ))
293 }
294
295 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
296 Ok((
297 RpDelete::default(),
298 oio::OneShotDeleter::new(WebdavDeleter::new(self.core.clone())),
299 ))
300 }
301
302 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
303 Ok((
304 RpList::default(),
305 oio::PageLister::new(WebdavLister::new(self.core.clone(), path, args)),
306 ))
307 }
308
309 async fn copy(&self, from: &str, to: &str, _args: OpCopy) -> Result<RpCopy> {
310 let resp = self.core.webdav_copy(from, to).await?;
311
312 let status = resp.status();
313
314 match status {
315 StatusCode::CREATED | StatusCode::NO_CONTENT => Ok(RpCopy::default()),
316 _ => Err(parse_error(resp)),
317 }
318 }
319
320 async fn rename(&self, from: &str, to: &str, _args: OpRename) -> Result<RpRename> {
321 let resp = self.core.webdav_move(from, to).await?;
322
323 let status = resp.status();
324 match status {
325 StatusCode::CREATED | StatusCode::NO_CONTENT | StatusCode::OK => {
326 Ok(RpRename::default())
327 }
328 _ => Err(parse_error(resp)),
329 }
330 }
331}