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/18 14:00:50 UTC
(opendal) branch feat/reqwest-tls-options updated: docs(transport): document TLS two-axis model in reqwest README
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
The following commit(s) were added to refs/heads/feat/reqwest-tls-options by this push:
new e5eaa081c docs(transport): document TLS two-axis model in reqwest README
e5eaa081c is described below
commit e5eaa081c653d2f775e7454366332f476f84e846
Author: Erick Guan <29...@users.noreply.github.com>
AuthorDate: Thu Jun 18 22:00:35 2026 +0800
docs(transport): document TLS two-axis model in reqwest README
Restructure the TLS documentation to explain the two independent
configuration axes (crypto provider and certificate verification) and
add practical examples for using ring and bringing your own reqwest
client.
Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
core/http-transports/reqwest/README.md | 160 ++++++++++++++++++++++++++++-----
1 file changed, 137 insertions(+), 23 deletions(-)
diff --git a/core/http-transports/reqwest/README.md b/core/http-transports/reqwest/README.md
index c7fbb2176..b1de6e26c 100644
--- a/core/http-transports/reqwest/README.md
+++ b/core/http-transports/reqwest/README.md
@@ -5,32 +5,89 @@ Reqwest-based HTTP transport for [Apache OpenDAL](https://opendal.apache.org).
This crate provides `ReqwestTransport`, an implementation of OpenDAL's
`HttpTransport` trait backed by [reqwest](https://crates.io/crates/reqwest).
-## TLS backends
+## TLS configuration
-Enable one of the following Cargo features to select a TLS backend.
-The `default` feature enables `native-tls`.
+When using Rustls, TLS configuration has two independent axes:
-- **`native-tls`** — Platform TLS (SChannel on Windows, Secure Transport
- on macOS, OpenSSL on Linux). Links against the OS TLS library. Requires
- system development packages for OpenSSL on Linux.
+| Axis | What it decides | Options |
+|------|----------------|---------|
+| **Crypto provider** | Who performs the cryptographic operations (key exchange, symmetric ciphers, hashing) | `aws-lc-rs` (default in `rustls`/`webpki-roots`), `ring`, or any custom `CryptoProvider` |
+| **Certificate verification** | How the server's TLS certificate chain is validated | Platform verifier (default in `rustls`), bundled Mozilla roots (`webpki-roots`), or custom |
-- **`rustls`** — [Rustls](https://crates.io/crates/rustls) with the
- aws-lc-rs crypto provider and platform certificate verification.
- Pure-Rust TLS stack, no system TLS dependency.
+The `native-tls` feature sidesteps both axes by delegating everything to
+the OS TLS library (SChannel / Secure Transport / OpenSSL).
-- **`rustls-no-provider`** — Rustls without a built-in crypto provider.
- You must install a `rustls::crypto::CryptoProvider` before building a
- client. Use this when you want to bring your own provider (e.g. `ring`
- or a FIPS-certified module).
+### Feature matrix
-- **`webpki-roots`** — Rustls with bundled
- [Mozilla root certificates](https://crates.io/crates/webpki-roots).
- Fully self-contained: no platform certificate store dependency. Good for
- reproducible builds and environments with a stripped-down root store.
+| Feature | Crypto provider | Certificate roots | Use when |
+|---------|----------------|-------------------|----------|
+| `native-tls` (default) | OS library | OS trust store | You want zero Rust-side TLS config |
+| `rustls` | aws-lc-rs | Platform verifier | Pure-Rust TLS with OS trust store |
+| `webpki-roots` | aws-lc-rs | Bundled Mozilla roots | Fully self-contained, no OS dependency |
+| `rustls-no-provider` | **you provide** | **you provide** | BYO crypto (ring, FIPS module, etc.) |
-In application builds, prefer selecting a single backend. In workspace or
-`--all-features` builds, Cargo may enable multiple backend features via
-feature unification; the transport picks native TLS when available.
+### Choosing a crypto provider
+
+- **aws-lc-rs** — AWS's fork of BoringSSL. Fast, FIPS-capable, but requires
+ a C compiler and has [platform constraints](https://aws.github.io/aws-lc-rs/requirements/index.html).
+- **ring** — Pure Rust + asm. Broader platform support than aws-lc-rs, no
+ C toolchain needed. See [supported targets](https://github.com/briansmith/ring#supported-targets).
+- **Custom** — Any type implementing `rustls::crypto::CryptoProvider`. Use
+ for FIPS-certified modules or exotic platforms.
+
+If `aws-lc-rs` works for your targets, use the `rustls` or `webpki-roots`
+features and you're done. If you need ring or a custom provider, use
+`rustls-no-provider` and install it yourself (see example below).
+
+### Choosing certificate verification
+
+- **Platform verifier** (used by `rustls`) — delegates to the OS trust store.
+ Certificates are validated the same way browsers on that OS validate them.
+- **Bundled Mozilla roots** (used by `webpki-roots`) — embeds Mozilla's root
+ CA set at compile time. Fully reproducible, no OS dependency, but you must
+ rebuild to pick up root store updates.
+- **Custom** — with `rustls-no-provider` you configure both axes manually via
+ `rustls::ClientConfig`.
+
+### Example: using ring with OpenDAL
+
+Use `rustls-no-provider` and install ring's `CryptoProvider` before building
+the operator:
+
+```toml
+[dependencies]
+opendal = { version = "0.57", default-features = false, features = [
+ "services-s3",
+ "http-transport-reqwest-rustls-no-provider",
+] }
+rustls = { version = "0.23", features = ["ring"], default-features = false }
+webpki-roots = "1"
+```
+
+```rust
+fn main() {
+ // Install ring as the global crypto provider before any TLS usage.
+ rustls::crypto::ring::default_provider()
+ .install_default()
+ .expect("failed to install ring crypto provider");
+
+ // Build an S3 operator — it will use ring for all TLS operations.
+ let op = opendal::Operator::via_iter("s3", [
+ ("bucket".to_string(), "my-bucket".to_string()),
+ ("region".to_string(), "us-east-1".to_string()),
+ ])
+ .expect("failed to build operator");
+}
+```
+
+With `rustls-no-provider`, reqwest delegates to whatever `CryptoProvider` is
+installed globally (or per-connection via `ClientConfig`). You handle both
+the crypto provider and certificate roots, giving full control over the TLS
+stack without this crate needing to depend on ring directly.
+
+In application builds, prefer selecting a single TLS feature. In workspace or
+`--all-features` builds, Cargo may enable multiple features via feature
+unification; the transport picks native TLS when available.
### Usage via the `opendal` facade crate
@@ -74,12 +131,69 @@ let transport = ReqwestTransport::builder()
.build()
.unwrap();
HttpTransporter::install_default(transport);
+```
+
+### Bringing your own reqwest client
+
+When you need full control over the TLS stack — custom `ClientConfig`,
+client certificates, proxy settings, or connection pool tuning — build a
+`reqwest::Client` yourself and wrap it:
+
+```toml
+[dependencies]
+opendal = { version = "0.57", default-features = false, features = [
+ "services-s3",
+ "http-transport-reqwest-rustls-no-provider",
+] }
+opendal-http-transport-reqwest = { version = "0.57", default-features = false, features = ["rustls-no-provider"] }
+rustls = { version = "0.23", features = ["ring"], default-features = false }
+webpki-roots = "1"
+```
-// You can still bring your own reqwest::Client when you want full control.
-let client = reqwest::Client::builder().build().unwrap();
-let transport = ReqwestTransport::new(client);
+```rust
+use std::time::Duration;
+
+use opendal::HttpTransporter;
+use opendal::OperationContext;
+use opendal_http_transport_reqwest::ReqwestTransport;
+
+fn main() {
+ // 1. Configure your crypto provider and certificate roots.
+ let root_store =
+ rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
+
+ let tls_config = rustls::ClientConfig::builder_with_provider(
+ rustls::crypto::ring::default_provider().into(),
+ )
+ .with_safe_default_protocol_versions()
+ .unwrap()
+ .with_root_certificates(root_store)
+ .with_no_client_auth();
+
+ // 2. Build a reqwest client with your TLS config.
+ let client = reqwest::Client::builder()
+ .tls_backend_preconfigured(tls_config)
+ .connect_timeout(Duration::from_secs(10))
+ .pool_max_idle_per_host(20)
+ .build()
+ .unwrap();
+
+ // 3. Wrap it as a ReqwestTransport and attach to an operator.
+ let transport = HttpTransporter::new(ReqwestTransport::new(client));
+
+ let op = opendal::Operator::via_iter("s3", [
+ ("bucket".to_string(), "my-bucket".to_string()),
+ ("region".to_string(), "us-east-1".to_string()),
+ ])
+ .expect("failed to build operator")
+ .with_context(OperationContext::new().with_http_transport(transport));
+}
```
+This approach gives you complete ownership over both TLS axes — pick any
+crypto provider, any certificate validation strategy, and any reqwest
+settings — while still plugging into OpenDAL's transport layer.
+
## How it fits into OpenDAL
```