diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50041eec..cb224a37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,6 +57,14 @@ jobs: run: cargo clippy --features azure -- -D warnings - name: Run clippy with http feature run: cargo clippy --features http -- -D warnings + - name: Run clippy with aws-base feature + run: cargo clippy --no-default-features --features aws-base -- -D warnings + - name: Run clippy with azure-base feature + run: cargo clippy --no-default-features --features azure-base -- -D warnings + - name: Run clippy with gcp-base feature + run: cargo clippy --no-default-features --features gcp-base -- -D warnings + - name: Run clippy with http-base feature + run: cargo clippy --no-default-features --features http-base -- -D warnings - name: Run clippy with integration feature run: cargo clippy --no-default-features --features integration -- -D warnings - name: Run clippy with all features @@ -196,6 +204,8 @@ jobs: run: rustup target add wasm32-wasip1 - name: Build wasm32-wasip1 run: cargo build --all-features --target wasm32-wasip1 + - name: Build wasm32-wasip1 without reqwest + run: cargo build --no-default-features --features aws-base --target wasm32-wasip1 - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - uses: actions/setup-node@v6 diff --git a/Cargo.toml b/Cargo.toml index 8ada1048..f29a2740 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,12 +82,18 @@ futures-channel = {version = "0.3", features = ["sink"]} [features] default = ["fs"] -cloud = ["serde", "serde_json", "quick-xml", "hyper", "reqwest", "reqwest/stream", "chrono/serde", "base64", "rand", "ring", "http-body-util", "form_urlencoded", "serde_urlencoded", "tokio"] -azure = ["cloud", "httparse"] +cloud = ["cloud-base", "reqwest"] +cloud-base = ["serde", "serde_json", "quick-xml", "hyper", "chrono/serde", "base64", "rand", "ring", "http-body-util", "form_urlencoded", "serde_urlencoded", "tokio"] +azure = ["azure-base", "cloud"] +azure-base = ["cloud-base", "httparse"] fs = ["walkdir", "tokio", "nix", "windows-sys"] -gcp = ["cloud", "rustls-pki-types"] -aws = ["cloud", "crc-fast", "md-5"] -http = ["cloud"] +gcp = ["gcp-base", "cloud"] +gcp-base = ["cloud-base", "rustls-pki-types"] +aws = ["aws-base", "cloud"] +aws-base = ["cloud-base", "crc-fast", "md-5"] +http = ["http-base", "cloud"] +http-base = ["cloud-base"] +reqwest = ["dep:reqwest", "reqwest/stream"] tls-webpki-roots = ["reqwest?/rustls-tls-webpki-roots"] integration = ["rand", "tokio"] tokio = ["dep:tokio", "dep:tracing"] diff --git a/src/aws/builder.rs b/src/aws/builder.rs index 85dbaaeb..62dc2e19 100644 --- a/src/aws/builder.rs +++ b/src/aws/builder.rs @@ -29,9 +29,9 @@ use crate::config::ConfigValue; use crate::{ClientConfigKey, ClientOptions, Result, RetryConfig, StaticCredentialProvider}; use base64::Engine; use base64::prelude::BASE64_STANDARD; +use http::header::{HeaderMap, HeaderValue}; use itertools::Itertools; use md5::{Digest, Md5}; -use reqwest::header::{HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::sync::Arc; @@ -1538,6 +1538,7 @@ mod tests { assert!(builder.unsigned_payload.get().unwrap()); } + #[cfg(feature = "reqwest")] #[test] fn s3_test_endpoint_url_s3_config() { // Verify aws_endpoint_url_s3 parses to S3Endpoint config key @@ -1652,6 +1653,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn s3_default_region() { let builder = AmazonS3Builder::new() @@ -1661,6 +1663,7 @@ mod tests { assert_eq!(builder.client.config.region, "us-east-1"); } + #[cfg(feature = "reqwest")] #[test] fn s3_test_bucket_endpoint() { let builder = AmazonS3Builder::new() @@ -1760,6 +1763,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[tokio::test] async fn s3_test_proxy_url() { let s3 = AmazonS3Builder::new() @@ -1788,6 +1792,7 @@ mod tests { assert_eq!("Generic HTTP client error: builder error", err); } + #[cfg(feature = "reqwest")] #[test] fn test_invalid_config() { let err = AmazonS3Builder::new() @@ -1830,6 +1835,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn test_request_payer_config() { let s3 = AmazonS3Builder::new() @@ -1903,6 +1909,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[test] fn test_builder_eks_with_config() { let builder = AmazonS3Builder::new() @@ -1925,6 +1932,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn test_builder_web_identity_with_config() { let builder = AmazonS3Builder::new() diff --git a/src/aws/client.rs b/src/aws/client.rs index 6716bb01..1d8207c6 100644 --- a/src/aws/client.rs +++ b/src/aws/client.rs @@ -1015,6 +1015,7 @@ mod tests { use hyper::Request; use hyper::body::Incoming; + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_create_multipart_has_content_length() { let mock = MockServer::new().await; @@ -1110,6 +1111,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_default_headers_signed_request() { let mock = MockServer::new().await; @@ -1134,6 +1136,7 @@ mod tests { mock.shutdown().await; } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_default_headers_signed_bulk_delete() { let mock = MockServer::new().await; @@ -1153,6 +1156,7 @@ mod tests { mock.shutdown().await; } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_default_headers_signed_get_request() { let mock = MockServer::new().await; @@ -1175,6 +1179,7 @@ mod tests { mock.shutdown().await; } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_default_headers_signed_complete_multipart() { let mock = MockServer::new().await; diff --git a/src/aws/credential.rs b/src/aws/credential.rs index 170c3e44..df2ea678 100644 --- a/src/aws/credential.rs +++ b/src/aws/credential.rs @@ -865,11 +865,13 @@ mod tests { use crate::aws::{AmazonS3Builder, AmazonS3ConfigKey}; use crate::client::HttpClient; use crate::client::mock_server::MockServer; - use http::Response; - use reqwest::{Client, Method}; + use http::{Method, Response}; + #[cfg(feature = "reqwest")] + use reqwest::Client; use std::env; // Test generated using https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html + #[cfg(feature = "reqwest")] #[test] fn test_sign_with_signed_payload() { let client = HttpClient::new(Client::new()); @@ -914,6 +916,7 @@ mod tests { ) } + #[cfg(feature = "reqwest")] #[test] fn test_sign_with_signed_payload_request_payer() { let client = HttpClient::new(Client::new()); @@ -958,6 +961,7 @@ mod tests { ) } + #[cfg(feature = "reqwest")] #[test] fn test_sign_with_unsigned_payload() { let client = HttpClient::new(Client::new()); @@ -1085,6 +1089,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn test_sign_port() { let client = HttpClient::new(Client::new()); @@ -1128,6 +1133,7 @@ mod tests { ) } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_instance_metadata() { if env::var("TEST_INTEGRATION").is_err() { @@ -1166,6 +1172,7 @@ mod tests { assert!(!token.is_empty()) } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_mock() { let server = MockServer::new().await; @@ -1259,6 +1266,7 @@ mod tests { .unwrap_err(); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_eks_pod_credential_provider() { use crate::client::mock_server::MockServer; diff --git a/src/aws/mod.rs b/src/aws/mod.rs index 935c6531..7dab5927 100644 --- a/src/aws/mod.rs +++ b/src/aws/mod.rs @@ -31,8 +31,8 @@ use async_trait::async_trait; use futures_util::stream::BoxStream; use futures_util::{StreamExt, TryStreamExt}; -use reqwest::header::{HeaderName, IF_MATCH, IF_NONE_MATCH}; -use reqwest::{Method, StatusCode}; +use http::header::{HeaderName, IF_MATCH, IF_NONE_MATCH}; +use http::{Method, StatusCode}; use std::{sync::Arc, time::Duration}; use url::Url; @@ -58,14 +58,14 @@ mod client; mod credential; mod precondition; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] mod resolve; pub use builder::{AmazonS3Builder, AmazonS3ConfigKey}; pub use checksum::Checksum; pub use precondition::{S3ConditionalPut, S3CopyIfNotExists}; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub use resolve::resolve_bucket_region; /// This struct is used to maintain the URI path encoding @@ -118,7 +118,7 @@ impl Signer for AmazonS3 { /// ``` /// # async fn example() -> Result<(), Box> { /// # use object_store::{aws::AmazonS3Builder, path::Path, signer::Signer}; - /// # use reqwest::Method; + /// # use http::Method; /// # use std::time::Duration; /// # /// let region = "us-east-1"; @@ -515,6 +515,7 @@ mod tests { use super::*; use crate::ClientOptions; use crate::ObjectStoreExt; + #[cfg(feature = "reqwest")] use crate::client::SpawnedReqwestConnector; use crate::client::get::GetClient; use crate::client::retry::RetryContext; @@ -923,6 +924,7 @@ mod tests { /// Integration test that ensures I/O is done on an alternate threadpool /// when using the `SpawnedReqwestConnector`. + #[cfg(feature = "reqwest")] #[test] fn s3_alternate_threadpool_spawned_request_connector() { maybe_skip_integration!(); diff --git a/src/aws/precondition.rs b/src/aws/precondition.rs index b4ae938a..51b80894 100644 --- a/src/aws/precondition.rs +++ b/src/aws/precondition.rs @@ -44,7 +44,7 @@ pub enum S3CopyIfNotExists { /// other than 412. /// /// Encoded as `header-with-status:::` ignoring whitespace - HeaderWithStatus(String, String, reqwest::StatusCode), + HeaderWithStatus(String, String, http::StatusCode), /// Native Amazon S3 supports copy if not exists through a multipart upload /// where the upload copies an existing object and is completed only if the /// new object does not already exist. @@ -180,7 +180,7 @@ mod tests { let expected = Some(S3CopyIfNotExists::HeaderWithStatus( "key".to_owned(), "value".to_owned(), - reqwest::StatusCode::FORBIDDEN, + http::StatusCode::FORBIDDEN, )); assert_eq!(expected, S3CopyIfNotExists::from_str(input)); @@ -212,7 +212,7 @@ mod tests { let expected = Some(S3CopyIfNotExists::HeaderWithStatus( "key".to_owned(), "value".to_owned(), - reqwest::StatusCode::FORBIDDEN, + http::StatusCode::FORBIDDEN, )); const INPUTS: &[&str] = &[ diff --git a/src/aws/resolve.rs b/src/aws/resolve.rs index 66d1511c..a09ea537 100644 --- a/src/aws/resolve.rs +++ b/src/aws/resolve.rs @@ -47,7 +47,7 @@ impl From for crate::Error { /// /// [HeadBucket API]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html pub async fn resolve_bucket_region(bucket: &str, client_options: &ClientOptions) -> Result { - use reqwest::StatusCode; + use http::StatusCode; let endpoint = format!("https://{bucket}.s3.amazonaws.com"); diff --git a/src/azure/client.rs b/src/azure/client.rs index 6f1ad238..bacfa846 100644 --- a/src/azure/client.rs +++ b/src/azure/client.rs @@ -1374,6 +1374,7 @@ mod tests { quick_xml::de::from_str(S).unwrap(); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_build_bulk_delete_body() { let credential_provider = Arc::new(StaticCredentialProvider::new( diff --git a/src/azure/credential.rs b/src/azure/credential.rs index 1fbb101c..4e84fb8f 100644 --- a/src/azure/credential.rs +++ b/src/azure/credential.rs @@ -1075,6 +1075,7 @@ mod tests { use crate::client::mock_server::MockServer; use crate::{ObjectStoreExt, Path}; + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_managed_identity() { let server = MockServer::new().await; @@ -1133,6 +1134,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_workload_identity() { let server = MockServer::new().await; @@ -1185,6 +1187,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_no_credentials() { let server = MockServer::new().await; @@ -1218,6 +1221,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_fabric_refresh_expired_token() { let server = MockServer::new().await; diff --git a/src/azure/mod.rs b/src/azure/mod.rs index e6b9b9c2..e8e44c46 100644 --- a/src/azure/mod.rs +++ b/src/azure/mod.rs @@ -33,7 +33,7 @@ use crate::{ }; use async_trait::async_trait; use futures_util::stream::{BoxStream, StreamExt, TryStreamExt}; -use reqwest::Method; +use http::Method; use std::fmt::Debug; use std::sync::Arc; use std::time::Duration; @@ -197,7 +197,7 @@ impl Signer for MicrosoftAzure { /// ``` /// # async fn example() -> Result<(), Box> { /// # use object_store::{azure::MicrosoftAzureBuilder, path::Path, signer::Signer}; - /// # use reqwest::Method; + /// # use http::Method; /// # use std::time::Duration; /// # /// let azure = MicrosoftAzureBuilder::new() diff --git a/src/client/builder.rs b/src/client/builder.rs index f74c5ec1..fd0a7195 100644 --- a/src/client/builder.rs +++ b/src/client/builder.rs @@ -63,7 +63,7 @@ impl HttpRequestBuilder { } } - #[cfg(any(feature = "aws", feature = "azure"))] + #[cfg(any(feature = "aws-base", feature = "azure-base"))] pub(crate) fn from_parts(client: HttpClient, request: HttpRequest) -> Self { Self { client, @@ -116,7 +116,7 @@ impl HttpRequestBuilder { self } - #[cfg(feature = "aws")] + #[cfg(feature = "aws-base")] pub(crate) fn headers(mut self, headers: http::HeaderMap) -> Self { use http::header::{Entry, OccupiedEntry}; @@ -151,7 +151,7 @@ impl HttpRequestBuilder { self } - #[cfg(feature = "gcp")] + #[cfg(feature = "gcp-base")] pub(crate) fn bearer_auth(mut self, token: &str) -> Self { let value = HeaderValue::try_from(format!("Bearer {token}")); match (value, &mut self.request) { @@ -165,7 +165,7 @@ impl HttpRequestBuilder { self } - #[cfg(feature = "gcp")] + #[cfg(feature = "gcp-base")] pub(crate) fn json(mut self, s: S) -> Self { match (serde_json::to_vec(&s), &mut self.request) { (Ok(json), Ok(request)) => { @@ -177,7 +177,12 @@ impl HttpRequestBuilder { self } - #[cfg(any(test, feature = "aws", feature = "gcp", feature = "azure"))] + #[cfg(any( + test, + feature = "aws-base", + feature = "gcp-base", + feature = "azure-base" + ))] pub(crate) fn query(mut self, query: &T) -> Self { let mut error = None; if let Ok(ref mut req) = self.request { @@ -205,7 +210,7 @@ impl HttpRequestBuilder { self } - #[cfg(any(feature = "gcp", feature = "azure"))] + #[cfg(any(feature = "gcp-base", feature = "azure-base"))] pub(crate) fn form(mut self, form: T) -> Self { let mut error = None; if let Ok(ref mut req) = self.request { @@ -226,7 +231,7 @@ impl HttpRequestBuilder { self } - #[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] + #[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) fn body(mut self, b: impl Into) -> Self { if let Ok(r) = &mut self.request { *r.body_mut() = b.into(); @@ -239,7 +244,7 @@ impl HttpRequestBuilder { } } -#[cfg(any(test, feature = "azure"))] +#[cfg(any(test, feature = "azure-base"))] pub(crate) fn add_query_pairs(uri: &mut Uri, query_pairs: I) where I: IntoIterator, @@ -300,6 +305,7 @@ mod tests { assert_eq!(uri.to_string(), "https://foo@example.com/?foo=1"); } + #[cfg(feature = "reqwest")] #[test] fn test_request_builder_query() { let client = HttpClient::new(reqwest::Client::new()); diff --git a/src/client/get.rs b/src/client/get.rs index 044919b3..cacbe854 100644 --- a/src/client/get.rs +++ b/src/client/get.rs @@ -28,12 +28,12 @@ use bytes::Bytes; use futures_util::StreamExt; use futures_util::stream::BoxStream; use http::StatusCode; +use http::header::ToStrError; use http::header::{ CACHE_CONTROL, CONTENT_DISPOSITION, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_RANGE, CONTENT_TYPE, }; use http_body_util::BodyExt; -use reqwest::header::ToStrError; use std::ops::Range; use std::sync::Arc; use tracing::info; @@ -522,7 +522,7 @@ mod tests { ); } } -#[cfg(all(test, feature = "http", not(target_arch = "wasm32")))] +#[cfg(all(test, feature = "http-base", not(target_arch = "wasm32")))] mod http_tests { use crate::client::mock_server::MockServer; use crate::client::{HttpError, HttpErrorKind, HttpResponseBody}; @@ -589,6 +589,7 @@ mod http_tests { } } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_stream_retry() { let mock = MockServer::new().await; @@ -814,6 +815,7 @@ mod http_tests { ); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_retry_validate_content_range() { let mock = MockServer::new().await; diff --git a/src/client/header.rs b/src/client/header.rs index 4c9470c3..37eca7b4 100644 --- a/src/client/header.rs +++ b/src/client/header.rs @@ -49,7 +49,7 @@ pub(crate) enum Error { MissingEtag, #[error("Received header containing non-ASCII data")] - BadHeader { source: reqwest::header::ToStrError }, + BadHeader { source: http::header::ToStrError }, #[error("Last-Modified Header missing from response")] MissingLastModified, @@ -71,7 +71,7 @@ pub(crate) enum Error { } /// Extracts a PutResult from the provided [`HeaderMap`] -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) fn get_put_result( headers: &HeaderMap, version: &str, @@ -82,7 +82,7 @@ pub(crate) fn get_put_result( } /// Extracts a optional version from the provided [`HeaderMap`] -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) fn get_version(headers: &HeaderMap, version: &str) -> Result, Error> { Ok(match headers.get(version) { Some(x) => Some( diff --git a/src/client/http/body.rs b/src/client/http/body.rs index e22ccea8..554b0cf1 100644 --- a/src/client/http/body.rs +++ b/src/client/http/body.rs @@ -39,7 +39,7 @@ impl HttpRequestBody { Self(Inner::Bytes(Bytes::new())) } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub(crate) fn into_reqwest(self) -> reqwest::Body { match self.0 { Inner::Bytes(b) => b.into(), @@ -49,7 +49,7 @@ impl HttpRequestBody { } } - #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] + #[cfg(all(feature = "reqwest", target_arch = "wasm32", target_os = "unknown"))] pub(crate) fn into_reqwest(self) -> reqwest::Body { match self.0 { Inner::Bytes(b) => b.into(), @@ -196,7 +196,7 @@ impl HttpResponseBody { String::from_utf8(b.into()).map_err(|e| HttpError::new(HttpErrorKind::Decode, e)) } - #[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] + #[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) async fn json(self) -> Result { let b = self.bytes().await?; serde_json::from_slice(&b).map_err(|e| HttpError::new(HttpErrorKind::Decode, e)) diff --git a/src/client/http/connection.rs b/src/client/http/connection.rs index 69c8436d..c7cd2c14 100644 --- a/src/client/http/connection.rs +++ b/src/client/http/connection.rs @@ -16,13 +16,17 @@ // under the License. use crate::ClientOptions; +#[cfg(feature = "reqwest")] +use crate::client::HttpResponseBody; use crate::client::builder::{HttpRequestBuilder, RequestBuilderError}; -use crate::client::{HttpRequest, HttpResponse, HttpResponseBody}; +use crate::client::{HttpRequest, HttpResponse}; use async_trait::async_trait; use http::{Method, Uri}; +#[cfg(feature = "reqwest")] use http_body_util::BodyExt; use std::error::Error; use std::sync::Arc; +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] use tokio::runtime::Handle; /// An HTTP protocol error @@ -83,6 +87,7 @@ impl HttpError { } } + #[cfg(feature = "reqwest")] pub(crate) fn reqwest(e: reqwest::Error) -> Self { #[cfg(not(target_arch = "wasm32"))] let is_connect = || e.is_connect(); @@ -208,7 +213,7 @@ impl HttpClient { } #[async_trait] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] impl HttpService for reqwest::Client { async fn call(&self, req: HttpRequest) -> Result { let (parts, body) = req.into_parts(); @@ -228,7 +233,7 @@ impl HttpService for reqwest::Client { } #[async_trait] -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] +#[cfg(all(feature = "reqwest", target_arch = "wasm32", target_os = "unknown"))] impl HttpService for reqwest::Client { async fn call(&self, req: HttpRequest) -> Result { use futures_channel::{mpsc, oneshot}; @@ -288,10 +293,16 @@ pub trait HttpConnector: std::fmt::Debug + Send + Sync + 'static { /// [`HttpConnector`] using [`reqwest::Client`] #[derive(Debug, Default)] #[allow(missing_copy_implementations)] -#[cfg(not(all(target_arch = "wasm32", target_os = "wasi")))] +#[cfg(all( + feature = "reqwest", + not(all(target_arch = "wasm32", target_os = "wasi")) +))] pub struct ReqwestConnector {} -#[cfg(not(all(target_arch = "wasm32", target_os = "wasi")))] +#[cfg(all( + feature = "reqwest", + not(all(target_arch = "wasm32", target_os = "wasi")) +))] impl HttpConnector for ReqwestConnector { fn connect(&self, options: &ClientOptions) -> crate::Result { let client = options.client()?; @@ -336,12 +347,12 @@ impl HttpConnector for ReqwestConnector { /// ``` #[derive(Debug)] #[allow(missing_copy_implementations)] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub struct SpawnedReqwestConnector { runtime: Handle, } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] impl SpawnedReqwestConnector { /// Create a new [`SpawnedReqwestConnector`] with the provided [`Handle`] to /// a tokio [`Runtime`] @@ -352,7 +363,7 @@ impl SpawnedReqwestConnector { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] impl HttpConnector for SpawnedReqwestConnector { fn connect(&self, options: &ClientOptions) -> crate::Result { let spawn_service = super::SpawnService::new(options.client()?, self.runtime.clone()); @@ -360,21 +371,39 @@ impl HttpConnector for SpawnedReqwestConnector { } } -#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] +#[cfg(all(feature = "reqwest", target_arch = "wasm32", target_os = "wasi"))] pub(crate) fn http_connector( custom: Option>, ) -> crate::Result> { match custom { Some(x) => Ok(x), None => Err(crate::Error::NotSupported { - source: "WASI architectures must provide an HTTPConnector" + source: "reqwest is not supported on the WASI architecture; \ + supply a custom HttpConnector via `.with_http_connector(...)`" .to_string() .into(), }), } } -#[cfg(not(all(target_arch = "wasm32", target_os = "wasi")))] +#[cfg(all(not(feature = "reqwest"), target_arch = "wasm32", target_os = "wasi"))] +pub(crate) fn http_connector( + custom: Option>, +) -> crate::Result> { + match custom { + Some(x) => Ok(x), + None => Err(crate::Error::NotSupported { + source: "WASI architectures must provide an HttpConnector" + .to_string() + .into(), + }), + } +} + +#[cfg(all( + feature = "reqwest", + not(all(target_arch = "wasm32", target_os = "wasi")) +))] pub(crate) fn http_connector( custom: Option>, ) -> crate::Result> { @@ -383,3 +412,21 @@ pub(crate) fn http_connector( None => Ok(Arc::new(ReqwestConnector {})), } } + +#[cfg(all( + not(feature = "reqwest"), + not(all(target_arch = "wasm32", target_os = "wasi")) +))] +pub(crate) fn http_connector( + custom: Option>, +) -> crate::Result> { + match custom { + Some(x) => Ok(x), + None => Err(crate::Error::NotSupported { + source: "no built-in HTTP transport: enable the `reqwest` feature \ + or supply a custom HttpConnector via `.with_http_connector(...)`" + .to_string() + .into(), + }), + } +} diff --git a/src/client/http/spawn.rs b/src/client/http/spawn.rs index 80f3a874..2750e839 100644 --- a/src/client/http/spawn.rs +++ b/src/client/http/spawn.rs @@ -125,7 +125,7 @@ impl Body for SpawnBody { } } -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] #[cfg(test)] mod tests { use super::*; diff --git a/src/client/mod.rs b/src/client/mod.rs index 5b9f1f49..941e5a86 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -21,7 +21,7 @@ pub(crate) mod backoff; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] mod dns; #[cfg(not(target_arch = "wasm32"))] @@ -30,44 +30,45 @@ pub(crate) mod mock_server; pub(crate) mod retry; -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) mod pagination; pub(crate) mod get; -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) mod list; -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) mod token; pub(crate) mod header; -#[cfg(any(feature = "aws", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) mod s3; pub(crate) mod builder; mod http; -#[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) mod parts; pub use http::*; +use ::http::header::{HeaderMap, HeaderValue}; use async_trait::async_trait; -use reqwest::header::{HeaderMap, HeaderValue}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] use reqwest::{NoProxy, Proxy}; use crate::config::{ConfigValue, fmt_duration}; use crate::path::Path; use crate::{GetOptions, Result}; +#[cfg(feature = "reqwest")] fn map_client_error(e: reqwest::Error) -> super::Error { super::Error::Generic { store: "HTTP client", @@ -75,6 +76,7 @@ fn map_client_error(e: reqwest::Error) -> super::Error { } } +#[cfg(feature = "reqwest")] static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); /// Configuration keys for [`ClientOptions`] @@ -272,10 +274,10 @@ impl FromStr for ClientConfigKey { /// This is used to configure the client to trust a specific certificate. See /// [Self::from_pem] for an example #[derive(Debug, Clone)] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub struct Certificate(reqwest::tls::Certificate); -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] impl Certificate { /// Create a `Certificate` from a PEM encoded certificate. /// @@ -322,7 +324,7 @@ impl Certificate { #[derive(Debug, Clone)] pub struct ClientOptions { user_agent: Option>, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] root_certificates: Vec, content_type_map: HashMap, default_content_type: Option, @@ -357,7 +359,7 @@ impl Default for ClientOptions { // we opt for a slightly higher default timeout of 30 seconds Self { user_agent: None, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] root_certificates: Default::default(), content_type_map: Default::default(), default_content_type: None, @@ -489,7 +491,7 @@ impl ClientOptions { /// /// This can be used to connect to a server that has a self-signed /// certificate for example. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub fn with_root_certificate(mut self, certificate: Certificate) -> Self { self.root_certificates.push(certificate); self @@ -783,14 +785,14 @@ impl ClientOptions { /// In particular: /// * Allows HTTP as metadata endpoints do not use TLS /// * Configures a low connection timeout to provide quick feedback if not present - #[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))] + #[cfg(any(feature = "aws-base", feature = "gcp-base", feature = "azure-base"))] pub(crate) fn metadata_options(&self) -> Self { self.clone() .with_allow_http(true) .with_connect_timeout(Duration::from_secs(1)) } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))] pub(crate) fn client(&self) -> Result { let mut builder = reqwest::ClientBuilder::new(); @@ -890,7 +892,7 @@ impl ClientOptions { .map_err(map_client_error) } - #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] + #[cfg(all(feature = "reqwest", target_arch = "wasm32", target_os = "unknown"))] pub(crate) fn client(&self) -> Result { let mut builder = reqwest::ClientBuilder::new(); @@ -990,7 +992,7 @@ where } } -#[cfg(any(feature = "aws", feature = "azure", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "azure-base", feature = "gcp-base"))] mod cloud { use super::*; use crate::RetryConfig; @@ -1016,7 +1018,7 @@ mod cloud { } /// Override the minimum remaining TTL for a cached token to be used - #[cfg(any(feature = "aws", feature = "gcp"))] + #[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) fn with_min_ttl(mut self, min_ttl: Duration) -> Self { self.cache = self.cache.with_min_ttl(min_ttl); self @@ -1047,7 +1049,7 @@ mod cloud { } use crate::client::builder::HttpRequestBuilder; -#[cfg(any(feature = "aws", feature = "azure", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "azure-base", feature = "gcp-base"))] pub(crate) use cloud::*; #[cfg(test)] diff --git a/src/client/retry.rs b/src/client/retry.rs index 45b73eb8..c79012a0 100644 --- a/src/client/retry.rs +++ b/src/client/retry.rs @@ -22,9 +22,9 @@ use crate::client::backoff::{Backoff, BackoffConfig}; use crate::client::builder::HttpRequestBuilder; use crate::client::{HttpClient, HttpError, HttpErrorKind, HttpRequest, HttpResponse}; use futures_util::future::BoxFuture; +use http::StatusCode; +use http::header::LOCATION; use http::{Method, Uri}; -use reqwest::StatusCode; -use reqwest::header::LOCATION; #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] use std::time::{Duration, Instant}; use tracing::info; @@ -280,7 +280,7 @@ impl RetryableRequestBuilder { } /// Set whether this request should be retried on a 409 Conflict response. - #[cfg(feature = "aws")] + #[cfg(feature = "aws-base")] pub(crate) fn retry_on_conflict(mut self, retry_on_conflict: bool) -> Self { self.request.retry_on_conflict = retry_on_conflict; self @@ -512,13 +512,15 @@ mod tests { use crate::client::mock_server::MockServer; use crate::client::retry::{RequestError, RetryContext, RetryExt, body_contains_error}; use crate::client::{HttpClient, HttpError, HttpErrorKind, HttpResponse}; + use http::Method; use http::StatusCode; use hyper::Response; use hyper::header::LOCATION; use hyper::server::conn::http1; use hyper::service::service_fn; use hyper_util::rt::TokioIo; - use reqwest::{Client, Method}; + #[cfg(feature = "reqwest")] + use reqwest::Client; use std::convert::Infallible; use std::error::Error; use std::time::Duration; @@ -539,6 +541,7 @@ mod tests { assert!(!body_contains_error(success_response)); } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_retry() { let mock = MockServer::new().await; @@ -846,6 +849,7 @@ mod tests { mock.shutdown().await } + #[cfg(feature = "reqwest")] #[tokio::test] async fn test_503_error_body_captured() { let mock = MockServer::new().await; @@ -880,6 +884,7 @@ mod tests { mock.shutdown().await } + #[cfg(feature = "reqwest")] #[tokio::test] #[expect( deprecated, diff --git a/src/client/s3.rs b/src/client/s3.rs index 2beec612..fa96fc56 100644 --- a/src/client/s3.rs +++ b/src/client/s3.rs @@ -92,7 +92,7 @@ pub(crate) struct InitiateMultipartUploadResult { pub upload_id: String, } -#[cfg(feature = "aws")] +#[cfg(feature = "aws-base")] #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub(crate) struct CopyPartResult { diff --git a/src/client/token.rs b/src/client/token.rs index 5b680bda..147c77a1 100644 --- a/src/client/token.rs +++ b/src/client/token.rs @@ -58,7 +58,7 @@ impl Default for TokenCache { impl TokenCache { /// Override the minimum remaining TTL for a cached token to be used - #[cfg(any(feature = "aws", feature = "gcp"))] + #[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) fn with_min_ttl(self, min_ttl: Duration) -> Self { Self { min_ttl, ..self } } diff --git a/src/config.rs b/src/config.rs index 29a389d4..3707a36d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,8 +18,8 @@ use std::fmt::{Debug, Display, Formatter}; use std::str::FromStr; use std::time::Duration; +use http::header::HeaderValue; use humantime::{format_duration, parse_duration}; -use reqwest::header::HeaderValue; use crate::{Error, Result}; diff --git a/src/gcp/builder.rs b/src/gcp/builder.rs index ece16ece..beac471f 100644 --- a/src/gcp/builder.rs +++ b/src/gcp/builder.rs @@ -716,6 +716,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[tokio::test] async fn gcs_test_proxy_url() { let mut tfile = NamedTempFile::new().unwrap(); @@ -752,6 +753,7 @@ mod tests { builder.parse_url("mailto://bucket/path").unwrap_err(); } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_service_account_key_only() { let _ = GoogleCloudStorageBuilder::new() @@ -761,6 +763,7 @@ mod tests { .unwrap(); } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_with_base_url() { let no_base_url = GoogleCloudStorageBuilder::new() @@ -834,6 +837,7 @@ mod tests { } } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_explicit_creds_skip_invalid_adc() { // Create a valid service account key file @@ -862,6 +866,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_explicit_creds_with_service_account_key_skip_invalid_adc() { // Create invalid ADC file with unsupported credential type @@ -885,6 +890,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_adc_error_propagated_without_explicit_creds() { // Create invalid ADC file with unsupported credential type @@ -912,6 +918,7 @@ mod tests { ); } + #[cfg(feature = "reqwest")] #[test] fn gcs_test_with_credentials_skip_invalid_adc() { use crate::StaticCredentialProvider; diff --git a/src/gcp/mod.rs b/src/gcp/mod.rs index 8d7b26c7..b1b073dc 100644 --- a/src/gcp/mod.rs +++ b/src/gcp/mod.rs @@ -341,6 +341,7 @@ mod test { } } + #[cfg(feature = "reqwest")] #[tokio::test] #[ignore] async fn gcs_test_sign() { diff --git a/src/http/client.rs b/src/http/client.rs index 5b2d3434..4eb4c0db 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -30,8 +30,8 @@ use http::header::{ CACHE_CONTROL, CONTENT_DISPOSITION, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_TYPE, }; +use http::{Method, StatusCode}; use percent_encoding::percent_decode_str; -use reqwest::{Method, StatusCode}; use serde::Deserialize; use url::Url; diff --git a/src/lib.rs b/src/lib.rs index d3ea9ee2..e1c8ce2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,19 +80,19 @@ doc = "* Local filesystem: [`LocalFileSystem`](local::LocalFileSystem)" )] #![cfg_attr( - feature = "gcp", + feature = "gcp-base", doc = "* [`gcp`]: [Google Cloud Storage](https://cloud.google.com/storage/) support. See [`GoogleCloudStorageBuilder`](gcp::GoogleCloudStorageBuilder)" )] #![cfg_attr( - feature = "aws", + feature = "aws-base", doc = "* [`aws`]: [Amazon S3](https://aws.amazon.com/s3/). See [`AmazonS3Builder`](aws::AmazonS3Builder)" )] #![cfg_attr( - feature = "azure", + feature = "azure-base", doc = "* [`azure`]: [Azure Blob Storage](https://azure.microsoft.com/en-gb/services/storage/blobs/). See [`MicrosoftAzureBuilder`](azure::MicrosoftAzureBuilder)" )] #![cfg_attr( - feature = "http", + feature = "http-base", doc = "* [`http`]: [HTTP/WebDAV Storage](https://datatracker.ietf.org/doc/html/rfc2518). See [`HttpBuilder`](http::HttpBuilder)" )] //! @@ -537,18 +537,18 @@ //! //! [`HttpConnector`]: client::HttpConnector -#[cfg(feature = "aws")] +#[cfg(feature = "aws-base")] pub mod aws; -#[cfg(feature = "azure")] +#[cfg(feature = "azure-base")] pub mod azure; #[cfg(feature = "tokio")] pub mod buffered; #[cfg(not(target_arch = "wasm32"))] pub mod chunked; pub mod delimited; -#[cfg(feature = "gcp")] +#[cfg(feature = "gcp-base")] pub mod gcp; -#[cfg(feature = "http")] +#[cfg(feature = "http-base")] pub mod http; #[cfg(feature = "tokio")] pub mod limit; @@ -558,24 +558,28 @@ pub mod memory; pub mod path; pub mod prefix; pub mod registry; -#[cfg(feature = "cloud")] +#[cfg(feature = "cloud-base")] pub mod signer; #[cfg(feature = "tokio")] pub mod throttle; -#[cfg(feature = "cloud")] +#[cfg(feature = "cloud-base")] pub mod client; -#[cfg(feature = "cloud")] +#[cfg(feature = "cloud-base")] pub use client::{ ClientConfigKey, ClientOptions, CredentialProvider, StaticCredentialProvider, backoff::BackoffConfig, retry::RetryConfig, }; -#[cfg(all(feature = "cloud", not(target_arch = "wasm32")))] +#[cfg(all( + feature = "cloud-base", + feature = "reqwest", + not(target_arch = "wasm32") +))] pub use client::Certificate; -#[cfg(feature = "cloud")] +#[cfg(feature = "cloud-base")] mod config; mod tags; @@ -2173,12 +2177,12 @@ mod tests { store.list(Some(&path)) } - #[cfg(any(feature = "azure", feature = "aws"))] + #[cfg(any(feature = "azure-base", feature = "aws-base"))] pub(crate) async fn signing(integration: &T) where T: ObjectStore + signer::Signer, { - use reqwest::Method; + use ::http::Method; use std::time::Duration; let data = Bytes::from("hello world"); @@ -2196,7 +2200,7 @@ mod tests { assert_eq!(data, loaded); } - #[cfg(any(feature = "aws", feature = "azure"))] + #[cfg(any(feature = "aws-base", feature = "azure-base"))] pub(crate) async fn tagging(storage: Arc, validate: bool, get_tags: F) where F: Fn(Path) -> Fut + Send + Sync, @@ -2369,7 +2373,7 @@ mod tests { } #[test] - #[cfg(feature = "http")] + #[cfg(feature = "http-base")] fn test_reexported_types() { // Test HeaderMap let mut headers = HeaderMap::new(); diff --git a/src/parse.rs b/src/parse.rs index b30fea70..fedfe837 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -139,7 +139,7 @@ impl ObjectStoreScheme { } } -#[cfg(feature = "cloud")] +#[cfg(feature = "cloud-base")] macro_rules! builder_opts { ($builder:ty, $url:expr, $options:expr) => {{ let builder = $options.into_iter().fold( @@ -201,29 +201,29 @@ where #[cfg(all(feature = "fs", not(target_arch = "wasm32")))] ObjectStoreScheme::Local => Box::new(LocalFileSystem::new()) as _, ObjectStoreScheme::Memory => Box::new(InMemory::new()) as _, - #[cfg(feature = "aws")] + #[cfg(feature = "aws-base")] ObjectStoreScheme::AmazonS3 => { builder_opts!(crate::aws::AmazonS3Builder, url, _options) } - #[cfg(feature = "gcp")] + #[cfg(feature = "gcp-base")] ObjectStoreScheme::GoogleCloudStorage => { builder_opts!(crate::gcp::GoogleCloudStorageBuilder, url, _options) } - #[cfg(feature = "azure")] + #[cfg(feature = "azure-base")] ObjectStoreScheme::MicrosoftAzure => { builder_opts!(crate::azure::MicrosoftAzureBuilder, url, _options) } - #[cfg(feature = "http")] + #[cfg(feature = "http-base")] ObjectStoreScheme::Http => { let url = &url[..url::Position::BeforePath]; builder_opts!(crate::http::HttpBuilder, url, _options) } #[cfg(not(all( feature = "fs", - feature = "aws", - feature = "azure", - feature = "gcp", - feature = "http", + feature = "aws-base", + feature = "azure-base", + feature = "gcp-base", + feature = "http-base", not(target_arch = "wasm32") )))] s => { @@ -423,7 +423,11 @@ mod tests { } #[tokio::test] - #[cfg(all(feature = "http", not(target_arch = "wasm32")))] + #[cfg(all( + feature = "reqwest", + feature = "http-base", + not(target_arch = "wasm32") + ))] async fn test_url_http() { use crate::{ObjectStoreExt, client::mock_server::MockServer}; use http::{Response, header::USER_AGENT}; diff --git a/src/signer.rs b/src/signer.rs index ab3c7f91..47f3baaf 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -19,7 +19,7 @@ use crate::{Result, path::Path}; use async_trait::async_trait; -use reqwest::Method; +use http::Method; use std::{fmt, time::Duration}; use url::Url; diff --git a/src/util.rs b/src/util.rs index 162c0777..21c9f7a5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -25,11 +25,11 @@ use super::Result; use bytes::Bytes; use futures_util::{Stream, TryStreamExt, stream::StreamExt}; -#[cfg(any(feature = "azure", feature = "http"))] +#[cfg(any(feature = "azure-base", feature = "http-base"))] pub(crate) static RFC1123_FMT: &str = "%a, %d %h %Y %T GMT"; // deserialize dates according to rfc1123 -#[cfg(any(feature = "azure", feature = "http"))] +#[cfg(any(feature = "azure-base", feature = "http-base"))] pub(crate) fn deserialize_rfc1123<'de, D>( deserializer: D, ) -> Result, D::Error> @@ -42,7 +42,7 @@ where Ok(chrono::TimeZone::from_utc_datetime(&chrono::Utc, &naive)) } -#[cfg(any(feature = "aws", feature = "azure"))] +#[cfg(any(feature = "aws-base", feature = "azure-base"))] pub(crate) fn hmac_sha256(secret: impl AsRef<[u8]>, bytes: impl AsRef<[u8]>) -> ring::hmac::Tag { let key = ring::hmac::Key::new(ring::hmac::HMAC_SHA256, secret.as_ref()); ring::hmac::sign(&key, bytes.as_ref()) @@ -300,7 +300,7 @@ impl> From for GetRange { // // Do not URI-encode any of the unreserved characters that RFC 3986 defines: // A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ). -#[cfg(any(feature = "aws", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) const STRICT_ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC .remove(b'-') .remove(b'.') @@ -308,14 +308,14 @@ pub(crate) const STRICT_ENCODE_SET: percent_encoding::AsciiSet = percent_encodin .remove(b'~'); /// Computes the SHA256 digest of `body` returned as a hex encoded string -#[cfg(any(feature = "aws", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) fn hex_digest(bytes: &[u8]) -> String { let digest = ring::digest::digest(&ring::digest::SHA256, bytes); hex_encode(digest.as_ref()) } /// Returns `bytes` as a lower-case hex encoded string -#[cfg(any(feature = "aws", feature = "gcp"))] +#[cfg(any(feature = "aws-base", feature = "gcp-base"))] pub(crate) fn hex_encode(bytes: &[u8]) -> String { use std::fmt::Write; let mut out = String::with_capacity(bytes.len() * 2); diff --git a/tests/http.rs b/tests/http.rs index f23ef74f..d1aa9309 100644 --- a/tests/http.rs +++ b/tests/http.rs @@ -17,16 +17,16 @@ //! Tests the HTTP store implementation -#[cfg(feature = "http")] +#[cfg(feature = "http-base")] use object_store::{GetOptions, GetRange, ObjectStore, http::HttpBuilder, path::Path}; -#[cfg(all(feature = "http", target_arch = "wasm32", target_os = "unknown"))] +#[cfg(all(feature = "http-base", target_arch = "wasm32", target_os = "unknown"))] use wasm_bindgen_test::*; /// Tests that even when reqwest has the `gzip` feature enabled, the HTTP store /// does not error on a missing `Content-Length` header. #[tokio::test] -#[cfg(feature = "http")] +#[cfg(all(feature = "http-base", feature = "reqwest"))] async fn test_http_store_gzip() { let http_store = HttpBuilder::new() .with_url("https://raw.githubusercontent.com/apache/arrow-rs/refs/heads/main") @@ -42,7 +42,7 @@ async fn test_http_store_gzip() { .unwrap(); } -#[cfg(all(feature = "http", target_arch = "wasm32", target_os = "unknown"))] +#[cfg(all(feature = "http-base", target_arch = "wasm32", target_os = "unknown"))] #[wasm_bindgen_test] async fn basic_wasm_get() { let http_store = HttpBuilder::new()