From 8f690ca232bb94829e2c6d5d6c925dde13a700a1 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Sat, 22 Aug 2026 10:16:04 -0700 Subject: [PATCH] storage: route OpenDAL through HTTP client OpenDAL 0.58 requires applications to provide an HTTP transport. Its default installer creates a standalone client, bypassing Vaultwarden DNS, redirect, proxy, timeout, and request configuration. Build the client through the internal HTTP interface and inject it into OpenDAL's public reqwest transport. --- Cargo.lock | 40 ++++++++++++++++++++++++++++------------ Cargo.toml | 2 ++ src/storage.rs | 12 +++++++++++- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0a36edf..4e63d41b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,16 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "asyncband" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a214ba60d6231afd0e805e3c27c45a1626d9debaa5a5061c45a1ea1b2f1ed0" +dependencies = [ + "hashbrown 0.17.1", + "slab", +] + [[package]] name = "atomic" version = "0.5.3" @@ -3100,15 +3110,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "mea" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31fc7d159de0085ab6dd7ff145a9819442cfd3d098f783263120503c3f3e58b0" -dependencies = [ - "slab", -] - [[package]] name = "memchr" version = "2.8.3" @@ -3437,11 +3438,12 @@ dependencies = [ [[package]] name = "opendal-core" -version = "0.58.1" +version = "0.58.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec75551ff4cf3e57da98979f6a937aaa9ddb3915bf68cc17d03df733be6646ed" +checksum = "48dbcef97d3eb7591db2c18d5cae95c836bcce07359b98d98dd6f4e861eb77b7" dependencies = [ "anyhow", + "asyncband", "base64 0.23.1", "bytes", "futures", @@ -3449,7 +3451,6 @@ dependencies = [ "jiff", "log", "md-5", - "mea", "percent-encoding", "quick-xml", "reqsign-core", @@ -3461,6 +3462,20 @@ dependencies = [ "web-time", ] +[[package]] +name = "opendal-http-transport-reqwest" +version = "0.58.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85663452ea32bbc17e8f79ab29788c846d116ec7de31451be9c787e462dcb36c" +dependencies = [ + "bytes", + "futures", + "http 1.5.0", + "http-body 1.1.0", + "opendal-core", + "reqwest", +] + [[package]] name = "opendal-service-fs" version = "0.58.1" @@ -5889,6 +5904,7 @@ dependencies = [ "num-derive", "num-traits", "opendal", + "opendal-http-transport-reqwest", "openidconnect", "openssl", "pastey 0.2.3", diff --git a/Cargo.toml b/Cargo.toml index 3e187ff3..bfd7317f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ vendored_openssl = ["openssl/vendored"] enable_mimalloc = ["dep:mimalloc"] s3 = [ "opendal/services-s3", + "dep:opendal-http-transport-reqwest", "dep:aws-config", "dep:aws-credential-types", "dep:aws-smithy-runtime-api", @@ -258,6 +259,7 @@ grass_compiler = { version = "0.13.4", default-features = false } # File are accessed through Apache OpenDAL opendal = { version = "0.58.1", default-features = false, features = ["services-fs"] } +opendal-http-transport-reqwest = { version = "0.58.1", default-features = false, features = ["rustls-no-provider"], optional = true } # For retrieving AWS credentials, including temporary SSO credentials aws-config = { version = "1.10.1", optional = true, default-features = false, features = [ diff --git a/src/storage.rs b/src/storage.rs index 689be302..855a2619 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -77,10 +77,18 @@ pub(crate) fn operator_for_path(path: &str) -> Result = LazyLock::new(|| { + // Storage endpoints are administrator-configured and may be private. + crate::http_client::get_reqwest_client_builder(false).build().expect("Failed to build OpenDAL HTTP client") + }); + pub(super) fn is_uri(path: &str) -> bool { path.starts_with("s3://") } @@ -236,7 +244,9 @@ mod s3 { builder.credential_provider_chain(ProvideCredentialChain::new().push(OpenDALS3CredentialProvider)); } - Ok(opendal::Operator::new(builder)?) + let http_transport = opendal::HttpTransporter::new(ReqwestTransport::new(HTTP_CLIENT.clone())); + let context = opendal::OperationContext::new().with_http_transport(http_transport); + Ok(opendal::Operator::new(builder)?.with_context(context)) } fn uri_has_option(uri: &opendal::OperatorUri, names: &[&str]) -> bool {