This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 4c1e7cd75 feat(webdav): disable_create_dir for servers without
PROPFIND (#7177)
4c1e7cd75 is described below
commit 4c1e7cd75e30446a47e40fef184fb8a9018e83d3
Author: Weihang Lo <[email protected]>
AuthorDate: Mon Feb 2 09:39:22 2026 -0500
feat(webdav): disable_create_dir for servers without PROPFIND (#7177)
Some WebDAV-compatible servers like bazel-remote don't implement the
full WebDAV protocol. Specifically, they don't support the PROPFIND
method and don't require explicit directory creation before writing
files.
Currently, OpenDAL's WebDAV `write()` always calls `webdav_mkcol()`
before writing to ensure parent directories exist. This uses PROPFIND
to check directory existence, which fails on servers that don't
support it. For example, bazel-remote returns `405 Method Not Allowed.
This adds a new `disable_create_dir` configuration option that skips
the automatic parent directory creation in write operations.
* Builder API:
```rust
let op = Webdav::default()
.endpoint("http://bazel-remote:8080")
.disable_create_dir(true)
.build()?;
```
* Via URI:
```
webdav://bazel-remote:8080?disable_create_dir=true
```
* Environment variable:
```
OPENDAL_WEBDAV_DISABLE_CREATE_DIR=true
```
---
core/services/webdav/src/backend.rs | 22 ++++++++++++++++++++--
core/services/webdav/src/config.rs | 24 ++++++++++++++++++++++++
core/services/webdav/src/core.rs | 3 +++
3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/core/services/webdav/src/backend.rs
b/core/services/webdav/src/backend.rs
index 61929dea7..807c8d525 100644
--- a/core/services/webdav/src/backend.rs
+++ b/core/services/webdav/src/backend.rs
@@ -104,6 +104,21 @@ impl WebdavBuilder {
self
}
+ /// Disable automatic parent directory creation before write operations.
+ ///
+ /// By default, OpenDAL creates parent directories using MKCOL before
writing files.
+ /// This requires PROPFIND support to check directory existence.
+ ///
+ /// Some WebDAV-compatible servers (e.g., bazel-remote) don't support
PROPFIND
+ /// or don't require explicit directory creation. Enable this option to
skip
+ /// the MKCOL calls and write files directly.
+ ///
+ /// Default: false
+ pub fn disable_create_dir(mut self, disable: bool) -> Self {
+ self.config.disable_create_dir = disable;
+ self
+ }
+
/// Enable user metadata support via WebDAV PROPPATCH.
///
/// This feature requires the WebDAV server to support RFC4918 PROPPATCH
method.
@@ -225,6 +240,7 @@ impl Builder for WebdavBuilder {
.config
.user_metadata_uri
.unwrap_or_else(|| DEFAULT_USER_METADATA_URI.to_string()),
+ disable_create_dir: self.config.disable_create_dir,
});
Ok(WebdavBackend { core })
}
@@ -274,8 +290,10 @@ impl Access for WebdavBackend {
}
async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite,
Self::Writer)> {
- // Ensure parent path exists
- self.core.webdav_mkcol(get_parent(path)).await?;
+ // Ensure parent path exists (unless disabled for servers that don't
support PROPFIND)
+ if !self.core.disable_create_dir {
+ self.core.webdav_mkcol(get_parent(path)).await?;
+ }
Ok((
RpWrite::default(),
diff --git a/core/services/webdav/src/config.rs
b/core/services/webdav/src/config.rs
index f37ca1ef4..d09506869 100644
--- a/core/services/webdav/src/config.rs
+++ b/core/services/webdav/src/config.rs
@@ -39,6 +39,17 @@ pub struct WebdavConfig {
pub root: Option<String>,
/// WebDAV Service doesn't support copy.
pub disable_copy: bool,
+ /// Disable automatic parent directory creation before write operations.
+ ///
+ /// By default, OpenDAL creates parent directories using MKCOL before
writing files.
+ /// This requires PROPFIND support to check directory existence.
+ ///
+ /// Some WebDAV-compatible servers (e.g., bazel-remote) don't support
PROPFIND
+ /// or don't require explicit directory creation. Enable this option to
skip
+ /// the MKCOL calls and write files directly.
+ ///
+ /// Default: false
+ pub disable_create_dir: bool,
/// Enable user metadata support via WebDAV PROPPATCH.
///
/// This feature requires the WebDAV server to support RFC4918 PROPPATCH
method.
@@ -71,6 +82,7 @@ impl Debug for WebdavConfig {
.field("username", &self.username)
.field("root", &self.root)
.field("disable_copy", &self.disable_copy)
+ .field("disable_create_dir", &self.disable_create_dir)
.field("enable_user_metadata", &self.enable_user_metadata)
.field("user_metadata_prefix", &self.user_metadata_prefix)
.field("user_metadata_uri", &self.user_metadata_uri)
@@ -144,4 +156,16 @@ mod tests {
let cfg = WebdavConfig::from_uri(&uri).unwrap();
assert!(cfg.disable_copy);
}
+
+ #[test]
+ fn from_uri_propagates_disable_create_dir() {
+ let uri = OperatorUri::new(
+ "webdav://dav.example.com",
+ vec![("disable_create_dir".to_string(), "true".to_string())],
+ )
+ .unwrap();
+
+ let cfg = WebdavConfig::from_uri(&uri).unwrap();
+ assert!(cfg.disable_create_dir);
+ }
}
diff --git a/core/services/webdav/src/core.rs b/core/services/webdav/src/core.rs
index c06af3141..57a52dcba 100644
--- a/core/services/webdav/src/core.rs
+++ b/core/services/webdav/src/core.rs
@@ -93,6 +93,8 @@ pub struct WebdavCore {
pub user_metadata_prefix: String,
/// XML namespace URI for user metadata properties.
pub user_metadata_uri: String,
+ /// Skip automatic parent directory creation before writes.
+ pub disable_create_dir: bool,
}
impl Debug for WebdavCore {
@@ -102,6 +104,7 @@ impl Debug for WebdavCore {
.field("root", &self.root)
.field("user_metadata_prefix", &self.user_metadata_prefix)
.field("user_metadata_uri", &self.user_metadata_uri)
+ .field("disable_create_dir", &self.disable_create_dir)
.finish_non_exhaustive()
}
}