opendal/services/webdav/
backend.rs1use 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 super::DEFAULT_SCHEME;
33use crate::raw::*;
34use crate::services::WebdavConfig;
35use crate::*;
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 type Config = WebdavConfig;
139
140 fn build(self) -> Result<impl Access> {
141 debug!("backend build started: {:?}", &self);
142
143 let endpoint = match &self.config.endpoint {
144 Some(v) => v,
145 None => {
146 return Err(Error::new(ErrorKind::ConfigInvalid, "endpoint is empty")
147 .with_context("service", Scheme::Webdav));
148 }
149 };
150 let server_path = http::Uri::from_str(endpoint)
152 .map_err(|err| {
153 Error::new(ErrorKind::ConfigInvalid, "endpoint is invalid")
154 .with_context("service", Scheme::Webdav)
155 .set_source(err)
156 })?
157 .path()
158 .trim_end_matches('/')
159 .to_string();
160
161 let root = normalize_root(&self.config.root.clone().unwrap_or_default());
162 debug!("backend use root {root}");
163
164 let mut authorization = None;
165 if let Some(username) = &self.config.username {
166 authorization = Some(format_authorization_by_basic(
167 username,
168 self.config.password.as_deref().unwrap_or_default(),
169 )?);
170 }
171 if let Some(token) = &self.config.token {
172 authorization = Some(format_authorization_by_bearer(token)?)
173 }
174
175 let core = Arc::new(WebdavCore {
176 info: {
177 let am = AccessorInfo::default();
178 am.set_scheme(DEFAULT_SCHEME)
179 .set_root(&root)
180 .set_native_capability(Capability {
181 stat: true,
182
183 read: true,
184
185 write: true,
186 write_can_empty: true,
187
188 create_dir: true,
189 delete: true,
190
191 copy: !self.config.disable_copy,
192
193 rename: true,
194
195 list: true,
196
197 shared: true,
200
201 ..Default::default()
202 });
203
204 #[allow(deprecated)]
206 if let Some(client) = self.http_client {
207 am.update_http_client(|_| client);
208 }
209
210 am.into()
211 },
212 endpoint: endpoint.to_string(),
213 server_path,
214 authorization,
215 root,
216 });
217 Ok(WebdavBackend { core })
218 }
219}
220
221#[derive(Clone)]
223pub struct WebdavBackend {
224 core: Arc<WebdavCore>,
225}
226
227impl Debug for WebdavBackend {
228 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
229 f.debug_struct("WebdavBackend")
230 .field("core", &self.core)
231 .finish()
232 }
233}
234
235impl Access for WebdavBackend {
236 type Reader = HttpBody;
237 type Writer = oio::OneShotWriter<WebdavWriter>;
238 type Lister = oio::PageLister<WebdavLister>;
239 type Deleter = oio::OneShotDeleter<WebdavDeleter>;
240
241 fn info(&self) -> Arc<AccessorInfo> {
242 self.core.info.clone()
243 }
244
245 async fn create_dir(&self, path: &str, _: OpCreateDir) -> Result<RpCreateDir> {
246 self.core.webdav_mkcol(path).await?;
247 Ok(RpCreateDir::default())
248 }
249
250 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
251 let metadata = self.core.webdav_stat(path).await?;
252 Ok(RpStat::new(metadata))
253 }
254
255 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
256 let resp = self.core.webdav_get(path, args.range(), &args).await?;
257
258 let status = resp.status();
259
260 match status {
261 StatusCode::OK | StatusCode::PARTIAL_CONTENT => {
262 Ok((RpRead::default(), resp.into_body()))
263 }
264 _ => {
265 let (part, mut body) = resp.into_parts();
266 let buf = body.to_buffer().await?;
267 Err(parse_error(Response::from_parts(part, buf)))
268 }
269 }
270 }
271
272 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
273 self.core.webdav_mkcol(get_parent(path)).await?;
275
276 Ok((
277 RpWrite::default(),
278 oio::OneShotWriter::new(WebdavWriter::new(self.core.clone(), args, path.to_string())),
279 ))
280 }
281
282 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
283 Ok((
284 RpDelete::default(),
285 oio::OneShotDeleter::new(WebdavDeleter::new(self.core.clone())),
286 ))
287 }
288
289 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
290 Ok((
291 RpList::default(),
292 oio::PageLister::new(WebdavLister::new(self.core.clone(), path, args)),
293 ))
294 }
295
296 async fn copy(&self, from: &str, to: &str, _args: OpCopy) -> Result<RpCopy> {
297 let resp = self.core.webdav_copy(from, to).await?;
298
299 let status = resp.status();
300
301 match status {
302 StatusCode::CREATED | StatusCode::NO_CONTENT => Ok(RpCopy::default()),
303 _ => Err(parse_error(resp)),
304 }
305 }
306
307 async fn rename(&self, from: &str, to: &str, _args: OpRename) -> Result<RpRename> {
308 let resp = self.core.webdav_move(from, to).await?;
309
310 let status = resp.status();
311 match status {
312 StatusCode::CREATED | StatusCode::NO_CONTENT | StatusCode::OK => {
313 Ok(RpRename::default())
314 }
315 _ => Err(parse_error(resp)),
316 }
317 }
318}