You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by er...@apache.org on 2026/06/17 13:47:22 UTC
(opendal) 01/01: feat(transport): add native-tls and webpki-roots TLS options for reqwest
This is an automated email from the ASF dual-hosted git repository.
erickguan pushed a commit to branch feat/reqwest-tls-options
in repository https://gitbox.apache.org/repos/asf/opendal.git
commit 43acc61694e3033cddaae1e0b819ad7640ec9f31
Author: Erick Guan <29...@users.noreply.github.com>
AuthorDate: Wed Jun 17 21:46:59 2026 +0800
feat(transport): add native-tls and webpki-roots TLS options for reqwest
Add TLS backend selection features to the reqwest HTTP transport crate:
- `native-tls`: Platform TLS (SChannel on Windows, Secure Transport on
macOS, OpenSSL on Linux)
- `webpki-roots`: Rustls with bundled Mozilla root certificates
The existing `rustls` (default) and `rustls-no-provider` features are
unchanged. Users enable exactly one feature via the facade crate:
`reqwest-native-tls` or `reqwest-webpki-roots`.
When the `webpki-roots` feature is active, the default reqwest client is
built with a preconfigured rustls ClientConfig using the bundled root
store. For all other backends, reqwest's own feature-flag-driven defaults
apply.
---
core/Cargo.lock | 21 +++++++++++++++++++
core/Cargo.toml | 8 ++++++++
core/http-transports/reqwest/Cargo.toml | 4 ++++
core/http-transports/reqwest/src/lib.rs | 36 ++++++++++++++++++++++++++++++++-
4 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/core/Cargo.lock b/core/Cargo.lock
index 3d31931e3..b05b47a45 100644
--- a/core/Cargo.lock
+++ b/core/Cargo.lock
@@ -4653,6 +4653,22 @@ dependencies = [
"tower-service",
]
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper 1.9.0",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
[[package]]
name = "hyper-util"
version = "0.1.20"
@@ -6499,6 +6515,8 @@ dependencies = [
"http-body 1.0.1",
"opendal-core",
"reqwest",
+ "rustls 0.23.40",
+ "webpki-roots 1.0.7",
]
[[package]]
@@ -9372,11 +9390,13 @@ dependencies = [
"http-body-util",
"hyper 1.9.0",
"hyper-rustls 0.27.9",
+ "hyper-tls",
"hyper-util",
"js-sys",
"log",
"mime",
"mime_guess",
+ "native-tls",
"percent-encoding",
"pin-project-lite",
"quinn",
@@ -9387,6 +9407,7 @@ dependencies = [
"serde_json",
"sync_wrapper 1.0.2",
"tokio",
+ "tokio-native-tls",
"tokio-rustls 0.26.4",
"tokio-util",
"tower 0.5.3",
diff --git a/core/Cargo.toml b/core/Cargo.toml
index abd30f49d..4e07d3d7d 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -121,6 +121,10 @@ layers-tail-cut = ["dep:opendal-layer-tail-cut"]
layers-throttle = ["dep:opendal-layer-throttle"]
layers-timeout = ["dep:opendal-layer-timeout"]
layers-tracing = ["dep:opendal-layer-tracing"]
+reqwest-native-tls = [
+ "http-transport-reqwest",
+ "opendal-http-transport-reqwest/native-tls",
+]
reqwest-rustls-no-provider-tls = [
"http-transport-reqwest",
"opendal-http-transport-reqwest/rustls-no-provider",
@@ -129,6 +133,10 @@ reqwest-rustls-tls = [
"http-transport-reqwest",
"opendal-http-transport-reqwest/rustls",
]
+reqwest-webpki-roots = [
+ "http-transport-reqwest",
+ "opendal-http-transport-reqwest/webpki-roots",
+]
services-aliyun-drive = ["dep:opendal-service-aliyun-drive"]
services-alluxio = ["dep:opendal-service-alluxio"]
services-azblob = ["dep:opendal-service-azblob"]
diff --git a/core/http-transports/reqwest/Cargo.toml b/core/http-transports/reqwest/Cargo.toml
index 1b72144e2..221b7cc36 100644
--- a/core/http-transports/reqwest/Cargo.toml
+++ b/core/http-transports/reqwest/Cargo.toml
@@ -32,8 +32,10 @@ all-features = true
[features]
default = []
+native-tls = ["reqwest/native-tls"]
rustls = ["reqwest/rustls"]
rustls-no-provider = ["reqwest/rustls-no-provider"]
+webpki-roots = ["rustls", "dep:rustls", "dep:webpki-roots"]
[dependencies]
bytes = { workspace = true }
@@ -44,3 +46,5 @@ opendal-core = { path = "../../core", version = "0.57.0", default-features = fal
reqwest = { version = "0.13.4", features = [
"stream",
], default-features = false }
+rustls = { version = "0.23", optional = true, default-features = false }
+webpki-roots = { version = "1", optional = true }
diff --git a/core/http-transports/reqwest/src/lib.rs b/core/http-transports/reqwest/src/lib.rs
index 6f7c49b3a..0aa3968b5 100644
--- a/core/http-transports/reqwest/src/lib.rs
+++ b/core/http-transports/reqwest/src/lib.rs
@@ -16,6 +16,22 @@
// under the License.
//! Reqwest based HTTP transport for Apache OpenDAL.
+//!
+//! # TLS backends
+//!
+//! Enable one of the following features to select a TLS backend:
+//!
+//! | Feature | Backend |
+//! |---|---|
+//! | `rustls` | Rustls with native (platform) root certificates |
+//! | `rustls-no-provider` | Rustls without a built-in crypto provider |
+//! | `native-tls` | Platform TLS (SChannel / Secure Transport / OpenSSL) |
+//! | `webpki-roots` | Rustls with bundled Mozilla root certificates |
+//!
+//! When multiple features are enabled (e.g. via `--all-features`), the
+//! `webpki-roots` client configuration takes precedence; otherwise the
+//! default `reqwest::Client::new()` is used which lets reqwest pick the
+//! backend from its own feature flags.
#![deny(missing_docs)]
@@ -38,7 +54,25 @@ use opendal_core::Result;
use opendal_core::raw::parse_content_encoding;
use opendal_core::raw::parse_content_length;
-static DEFAULT_REQWEST_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(reqwest::Client::new);
+static DEFAULT_REQWEST_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(build_default_client);
+
+#[cfg(feature = "webpki-roots")]
+fn build_default_client() -> reqwest::Client {
+ let root_store =
+ rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
+ let tls_config = rustls::ClientConfig::builder()
+ .with_root_certificates(root_store)
+ .with_no_client_auth();
+ reqwest::Client::builder()
+ .use_preconfigured_tls(tls_config)
+ .build()
+ .expect("failed to build reqwest client with webpki-roots")
+}
+
+#[cfg(not(feature = "webpki-roots"))]
+fn build_default_client() -> reqwest::Client {
+ reqwest::Client::new()
+}
/// A [`reqwest::Client`] backed HTTP transport.
///