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 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
184 read: true,
185
186 write: true,
187 write_can_empty: true,
188
189 create_dir: true,
190 delete: true,
191
192 copy: !self.config.disable_copy,
193
194 rename: true,
195
196 list: true,
197
198 shared: true,
201
202 ..Default::default()
203 });
204
205 #[allow(deprecated)]
207 if let Some(client) = self.http_client {
208 am.update_http_client(|_| client);
209 }
210
211 am.into()
212 },
213 endpoint: endpoint.to_string(),
214 server_path,
215 authorization,
216 root,
217 });
218 Ok(WebdavBackend { core })
219 }
220}
221
222#[derive(Clone)]
224pub struct WebdavBackend {
225 core: Arc<WebdavCore>,
226}
227
228impl Debug for WebdavBackend {
229 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
230 f.debug_struct("WebdavBackend")
231 .field("core", &self.core)
232 .finish()
233 }
234}
235
236impl Access for WebdavBackend {
237 type Reader = HttpBody;
238 type Writer = oio::OneShotWriter<WebdavWriter>;
239 type Lister = oio::PageLister<WebdavLister>;
240 type Deleter = oio::OneShotDeleter<WebdavDeleter>;
241
242 fn info(&self) -> Arc<AccessorInfo> {
243 self.core.info.clone()
244 }
245
246 async fn create_dir(&self, path: &str, _: OpCreateDir) -> Result<RpCreateDir> {
247 self.core.webdav_mkcol(path).await?;
248 Ok(RpCreateDir::default())
249 }
250
251 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
252 let metadata = self.core.webdav_stat(path).await?;
253 Ok(RpStat::new(metadata))
254 }
255
256 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
257 let resp = self.core.webdav_get(path, args.range(), &args).await?;
258
259 let status = resp.status();
260
261 match status {
262 StatusCode::OK | StatusCode::PARTIAL_CONTENT => {
263 Ok((RpRead::default(), resp.into_body()))
264 }
265 _ => {
266 let (part, mut body) = resp.into_parts();
267 let buf = body.to_buffer().await?;
268 Err(parse_error(Response::from_parts(part, buf)))
269 }
270 }
271 }
272
273 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
274 self.core.webdav_mkcol(get_parent(path)).await?;
276
277 Ok((
278 RpWrite::default(),
279 oio::OneShotWriter::new(WebdavWriter::new(self.core.clone(), args, path.to_string())),
280 ))
281 }
282
283 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
284 Ok((
285 RpDelete::default(),
286 oio::OneShotDeleter::new(WebdavDeleter::new(self.core.clone())),
287 ))
288 }
289
290 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
291 Ok((
292 RpList::default(),
293 oio::PageLister::new(WebdavLister::new(self.core.clone(), path, args)),
294 ))
295 }
296
297 async fn copy(&self, from: &str, to: &str, _args: OpCopy) -> Result<RpCopy> {
298 let resp = self.core.webdav_copy(from, to).await?;
299
300 let status = resp.status();
301
302 match status {
303 StatusCode::CREATED | StatusCode::NO_CONTENT => Ok(RpCopy::default()),
304 _ => Err(parse_error(resp)),
305 }
306 }
307
308 async fn rename(&self, from: &str, to: &str, _args: OpRename) -> Result<RpRename> {
309 let resp = self.core.webdav_move(from, to).await?;
310
311 let status = resp.status();
312 match status {
313 StatusCode::CREATED | StatusCode::NO_CONTENT | StatusCode::OK => {
314 Ok(RpRename::default())
315 }
316 _ => Err(parse_error(resp)),
317 }
318 }
319}