-
Notifications
You must be signed in to change notification settings - Fork 230
Make the HTTP client backend used by Bucket pluggable #442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
The RequestImpl type alias for 1 of the 3 backends is now referenced in only one place, a new Bucket::make_request method which everything else that previously called RequestImpl::new now calls. The constructors for each of these backends are sync, as constructors should be. This will make it easier to change to a different backend factory API. The only reason these were async anyway is so that credentials_refresh could be called, but make_request can just do that.
This will make it easier to offer pluggable backends in the future.
The unification of all 3 backends under http::Request left essentially 3 copies of the same unit tests. Deduplicate those and move them to request_trait.rs because that's the substance of what they were really testing. In their place add new tests for each backend that test the request translation from http::Request to the backend's own request representation.
This will make it easier to offer pluggable backends in the future.
This is a breaking change. What used to we expressed as: bucket.with_request_timeout(...) bucket.request_timeout() bucket.set_dangereous_config(...) bucket.set_proxy(...) is now written as: bucket.with_backend(bucket.backend().with_request_timeout(...)?) bucket.backend().request_timeout() bucket.with_backend(bucket.backend().with_dangereous_config(...)?) bucket.with_backend(bucket.backend().with_proxy(...)?) Bucket no longer contains any assumptions about backends except that they accept http::Request and return http::Response.
This hides the details of s3::request::Request inside Bucket::make_request() in preparation for replacing the backend API with one better suited to pluggable backends.
The next change needs to split the Bucket type into different impl blocks with different generics. This textually moves the some of the methods so that they are grouped to fit together into the impl blocks they will need to belong to. Nothing is added or removed. This change exists only to make the diff of the next change easier to follow.
let backend = something that impls tower::Service<http::Request<...>>; let bucket = Bucket::new(...)?.with_backend(backend); There is still plenty to do, for example there is no API yet to create a bucket with a non-default backend, only get an existing bucket. But this is the basic feature.
WalkthroughThis pull request introduces a pluggable backend abstraction for HTTP requests in the S3 crate. The Changes
Sequence DiagramsequenceDiagram
actor Client
participant Bucket
participant Backend as Backend Trait
participant HTTPImpl as HTTP Implementation<br/>(Surf/Reqwest/Atto)
Note over Client,HTTPImpl: Old Flow: Concrete per-runtime handling
Client->>Bucket: make_request()
Bucket->>Bucket: RequestImpl (Surf/Reqwest/Atto)
Bucket->>HTTPImpl: Direct runtime call
HTTPImpl-->>Bucket: Response
Note over Client,HTTPImpl: New Flow: Generic Backend abstraction
Client->>Bucket: make_request()
Bucket->>Backend: call(http::Request)
Backend->>HTTPImpl: Service::call()
HTTPImpl-->>Backend: http::Response
Backend-->>Bucket: Response via ResponseBody trait
Bucket-->>Client: Result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
s3/src/utils/mod.rs (1)
291-293: Typo:"get-Type"should be"Content-Type".This appears to be a pre-existing bug where the header name is incorrectly specified as
"get-Type"instead of"Content-Type"in the sync backend'sHeadObjectResultconversion.content_type: headers - .get("get-Type") + .get("Content-Type") .map(|v| v.to_str().unwrap_or_default().to_string()),
🧹 Nitpick comments (7)
s3/src/request/async_std_backend.rs (2)
36-40: Consider returningResultinstead of panicking on invalid headers.The
expect()calls will panic if header name/value parsing fails. While this is unlikely in practice, returning an error would be more robust for a library.- for (name, value) in request.headers().iter() { - builder = builder.header( - HeaderName::from_bytes(AsRef::<[u8]>::as_ref(&name).to_vec()) - .expect("Could not parse heaeder name"), - HeaderValue::from_bytes(AsRef::<[u8]>::as_ref(&value).to_vec()) - .expect("Could not parse header value"), - ); - } + for (name, value) in request.headers().iter() { + let header_name = HeaderName::from_bytes(AsRef::<[u8]>::as_ref(&name).to_vec()) + .map_err(|e| S3Error::Surf(format!("Invalid header name: {}", e)))?; + let header_value = HeaderValue::from_bytes(AsRef::<[u8]>::as_ref(&value).to_vec()) + .map_err(|e| S3Error::Surf(format!("Invalid header value: {}", e)))?; + builder = builder.header(header_name, header_value); + }Also note the typo: "heaeder" → "header".
109-110: Consider moving struct definition before its impl block.The
SurfBackendstruct is defined after itsServiceimpl block. While valid Rust, placing the struct definition before its implementations is more conventional and improves readability.s3/src/put_object_request.rs (1)
114-125: Inconsistentwith_headersignatures between builder types.
PutObjectRequest::with_headertakeskey: &str(Line 114) whilePutObjectStreamRequest::with_headertakeskey: K where K: Into<http::HeaderName>(Line 250). This API inconsistency may confuse users expecting the same interface.Consider aligning both methods to use the more flexible
K: Into<http::HeaderName>signature, or both to use&strfor consistency.- pub fn with_header<V>(mut self, key: &str, value: V) -> Result<Self, S3Error> + pub fn with_header<K, V>(mut self, key: K, value: V) -> Result<Self, S3Error> where + K: TryInto<HeaderName>, + K::Error: Into<S3Error>, V: AsRef<str>, { - let header_name = HeaderName::from_bytes(key.as_bytes())?; + let header_name = key.try_into().map_err(Into::into)?;Also applies to: 250-261
s3/src/bucket.rs (4)
183-235: Consider harmonizing return types across builder methods.The builder methods have inconsistent return types:
with_path_stylereturnsBox<Self>with_extra_headers/with_extra_queryreturnResult<Self, S3Error>but never failwith_listobjects_v1returnsSelfThe
Resultwrappers inwith_extra_headersandwith_extra_queryare infallible — consider returningSelfdirectly to simplify the API, unless error handling is planned for a future change.
529-565: Note the asymmetric return types betweennewandnew_public.
newreturnsBox<Self>whilenew_publicreturnsSelf. This may be intentional for backwards compatibility, but it creates an inconsistent API surface. Consider documenting why this asymmetry exists or harmonizing in a future release.
482-513: Consider extracting shared logic betweencreateandcreate_with_path_style.Both methods share nearly identical code for the
RUST_S3_SKIP_LOCATION_CONSTRAINTcheck and bucket creation. Consider extracting a common helper to reduce duplication.async fn create_bucket_inner( bucket: Box<Bucket<DefaultBackend>>, config: BucketConfiguration, ) -> Result<CreateBucketResponse<DefaultBackend>, S3Error> { let command = Command::CreateBucket { config }; let response = bucket.make_request("", command).await?; let data = response_data(response, false).await?; let response_text = data.as_str()?; Ok(CreateBucketResponse { bucket, response_text: response_text.to_string(), response_code: data.status_code(), }) }
4034-4036: Typo in method name:with_dangereous_config.The method name contains a typo ("dangereous" instead of "dangerous"). If this exists in the backend implementation, consider fixing it as a separate change. Otherwise, this is a minor issue to note.
#!/bin/bash # Check if the typo exists in the backend implementation rg -n "dangereous" --type rust
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
s3/Cargo.toml(2 hunks)s3/src/bucket.rs(60 hunks)s3/src/bucket_ops.rs(1 hunks)s3/src/error.rs(2 hunks)s3/src/post_policy.rs(6 hunks)s3/src/put_object_request.rs(3 hunks)s3/src/request/async_std_backend.rs(1 hunks)s3/src/request/backend.rs(1 hunks)s3/src/request/blocking.rs(1 hunks)s3/src/request/mod.rs(1 hunks)s3/src/request/request_trait.rs(29 hunks)s3/src/request/tokio_backend.rs(3 hunks)s3/src/utils/mod.rs(2 hunks)s3/src/utils/testing.rs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
s3/src/request/mod.rs (1)
s3/src/bucket.rs (1)
backend(159-161)
s3/src/request/tokio_backend.rs (2)
s3/src/request/async_std_backend.rs (2)
poll_ready(79-81)call(83-106)s3/src/request/backend.rs (1)
call(27-27)
s3/src/request/backend.rs (4)
s3/src/utils/testing.rs (2)
call(17-23)call(31-35)s3/src/request/async_std_backend.rs (1)
call(83-106)s3/src/request/blocking.rs (1)
call(45-63)s3/src/request/tokio_backend.rs (2)
call(67-83)call(187-200)
s3/src/post_policy.rs (1)
s3/src/bucket.rs (1)
new(529-540)
s3/src/utils/testing.rs (1)
s3/src/request/backend.rs (1)
call(27-27)
s3/src/request/async_std_backend.rs (2)
s3/src/request/request_trait.rs (1)
headers(114-116)s3/src/request/backend.rs (1)
call(27-27)
s3/src/put_object_request.rs (2)
s3/src/bucket.rs (3)
backend(159-161)new(529-540)response(444-446)s3/src/request/request_trait.rs (2)
response_data(254-296)new(74-80)
s3/src/request/blocking.rs (3)
s3/src/request/tokio_backend.rs (4)
request_timeout(104-106)call(67-83)call(187-200)with_request_timeout(93-102)s3/src/request/backend.rs (1)
call(27-27)s3/src/request/async_std_backend.rs (1)
call(83-106)
s3/src/bucket.rs (3)
s3/src/request/request_trait.rs (6)
build_presigned(1004-1017)response_data(254-296)new(74-80)status_code(102-104)head(281-294)from(68-70)s3/src/request/backend.rs (1)
call(27-27)s3/src/utils/testing.rs (2)
call(17-23)call(31-35)
🔇 Additional comments (35)
s3/src/error.rs (2)
47-48: LGTM!The
InvalidStatusCodevariant is properly added to handle errors fromhttp::StatusCode::from_u16()when converting backend responses.
78-82: LGTM!The
From<Infallible>impl enables seamless error propagation with the?operator when working with services that haveError = Infallible. Usingunreachable!()is the idiomatic approach sinceInfalliblecan never be instantiated.s3/src/request/mod.rs (1)
3-3: LGTM!The
backendmodule is correctly exposed unconditionally to provide the pluggable backend abstraction layer that all feature configurations can depend on.s3/src/utils/testing.rs (1)
1-36: LGTM!
AlwaysFailBackendis a well-designed test utility that provides a deterministic failure response (HTTP 418) for both async and sync backends. The conditional compilation ensures it implements the correct service trait based on the feature flag.s3/src/bucket_ops.rs (1)
234-244: LGTM!The generic parameter
BonCreateBucketResponse<B>correctly propagates the backend type fromBucket<B>without requiring trait bounds, since the struct only holds the bucket and thesuccess()method doesn't interact with the backend.s3/src/utils/mod.rs (2)
433-465: LGTM!The
Readyfuture is a well-implemented lightweight alternative totower::util::ServiceExt::ready, avoiding a full dependency on thetowercrate. The implementation correctly:
- Polls
Service::poll_readyonce per poll- Panics defensively if polled after completion (standard Future contract)
- Returns a mutable reference to the service on success
1-2: I'm unable to execute the verification scripts due to repository clone failures in the sandbox environment. However, I can provide analysis based on Rust language semantics and the context provided in the review comment.Based on the code snippet and review context:
The
#[cfg(test)]pattern is correct: In Rust, a#[cfg(test)]module declaration at module level is a standard pattern for test-only utilities. The module is only compiled during test builds, and visibility rules apply within that test scope.Cross-module imports work: When
s3/src/post_policy.rstest code importscrate::utils::testing::AlwaysFailBackend, both the import statement and the testing module are compiled under#[cfg(test)], so this works correctly.Feature combinations: The concern about different feature combinations is valid - the tests should compile with different runtime features (tokio, async-std, sync). However, this would require actual compilation to verify.
Since I cannot execute the cargo test verification in the sandbox, the verification request cannot be fully completed. However, the pattern itself is sound and follows Rust best practices.
The
#[cfg(test)]visibility for cross-module test imports follows standard Rust patterns and should work correctly. However, actual compilation verification across feature combinations (tokio-native-tls, async-std-native-tls, sync-native-tls) would need to be performed locally or in CI to definitively confirm.s3/src/post_policy.rs (2)
61-64: LGTM!The
buildandsignmethods are correctly generalized over the backend typeB. Since these methods only access bucket metadata (name, region, credentials) and don't perform HTTP requests, no trait bounds onBare required.Also applies to: 113-113
465-480: LGTM!Test helper functions are properly updated to use
AlwaysFailBackendvia the.with_backend()pattern, ensuring tests don't accidentally make real HTTP requests.Also applies to: 482-497
s3/Cargo.toml (1)
58-59: All dependency versions are current.The verification confirms that the added dependencies are at their latest stable versions:
http-bodyv1.0.1 is the latest (July 12, 2024)http-body-utilv0.1.3 is the latest (March 11, 2025)tower-servicev0.3.3 is the latest (as of November 26, 2025)The dependency additions are appropriately gated behind optional features and do not introduce outdated or vulnerable versions.
s3/src/request/async_std_backend.rs (1)
74-107: Based on my research, I've uncovered important information about theSendbound concern. Let me provide the rewritten review:
Verify
Sendbound is actually satisfied—surf::Requestis notSend.The
Futuredeclares+ Send, butsurf::Request(the concreteRequest<NativeClient>type) contains non-Sendinternals. Ifhttp_request_to_surf_requestreturns asurf::Requestandrequest.send()holds that request across the.awaitpoint, the resulting future will be!Send, violating the trait bound and causing compilation to fail.Ensure either:
http_request_to_surf_requestconverts the request to owned,Send-compatible types before returning, or- The request is consumed immediately in
request.send()without being held acrossawaitpoints with non-Sendstate.s3/src/put_object_request.rs (1)
178-194: LGTM!The execute method cleanly delegates to the bucket's
make_requestinfrastructure and correctly usesresponse_data(response, true)to extract the ETag for PUT operations.s3/src/request/tokio_backend.rs (1)
67-83: LGTM!The
callimplementation properly converts the request, handles thefail-on-errfeature flag, and includes the response body in the error for debugging. Good use ofinto_owned()to ensure the body is owned before conversion.s3/src/request/blocking.rs (3)
57-62: LGTM!The response reconstruction correctly extracts status, headers, and body from the attohttpc response. The
unwrap()onheaders_mut()is safe here since the builder was just created with only a status.
79-82: LGTM!The
Resultreturn type maintains API consistency with other backends likeReqwestBackend, even though this implementation is infallible.
18-24: The review comment is incorrect. Session methods mutate in place and do not return values.The
attohttpc::Session::header()andSession::timeout()methods both have return type()(unit type). They take&mut selfand mutate the session in place, so the return values (units) are correctly discarded. The headers and timeout are properly applied; there is no bug here. The review comment conflates this withRequestBuilder, which uses the builder pattern and returnsSelffor chaining.s3/src/request/request_trait.rs (4)
199-230: Well-designed sealed trait pattern forResponseBody.The
ResponseBodytrait correctly uses a sealed pattern (unused_trait_should_have_only_blanket_impl) to prevent external implementations while providing a blanket impl for all compatible types. The async and sync variants are properly feature-gated.
253-296: LGTM!The
response_datafunction correctly handles both ETag extraction for PUT operations and normal body consumption. The TODO comment (Lines 270-271) appropriately documents the technical debt for future refactoring.
965-1001: LGTM!The
build_requestfunction properly orchestrates request construction: method mapping, header generation viaBuildHelper, URL construction with query handling, and body assembly. Clean and well-structured.
1276-1294: LGTM!The
testawaithelper provides a minimal spinning executor that's independent of tokio/async-std, enabling tests that don't need full runtime features. The progress check (Line 1285-1287) prevents infinite loops in case of bugs.s3/src/request/backend.rs (3)
30-52: LGTM!The async
Backendtrait correctly leverages higher-ranked trait bounds (for<'a>) to allow handling requests with arbitrary lifetimes. TheClone + Send + Syncbounds are appropriate for async contexts where the backend may be shared across tasks. The blanket implementation enables any compatibletower_service::Serviceto automatically be aBackend.
21-28: LGTM!
SyncServiceprovides a clean synchronous counterpart totower_service::Service, appropriate for blocking backends. The trait is simple and focused.
6-11: Based on my verification through web search, I've confirmed that the underlying concern about Rust's feature flag behavior is technically correct: Cargo features are additive (unified), meaning multiple features can be enabled simultaneously. When that happens, having multiple#[cfg(feature = "...")]blocks with the same target name (likeDefaultBackend) will produce duplicate definitions, causing Rust compilation error E0592.However, I cannot verify whether:
- The codebase implements safeguards (e.g.,
compile_error!guards, module-based separation)- Cargo.toml enforces mutual exclusivity at the package level
- CI/tests prevent this scenario from occurring
Since the repository clone failed and I cannot inspect the actual implementation details to confirm whether mitigations are in place, the verification remains inconclusive.
Verify feature flag mutual exclusivity for
DefaultBackend.Three separate
#[cfg]blocks defineDefaultBackendfor different features (with-async-std,sync,with-tokio). Cargo features are additive by default, so enabling multiple features simultaneously would cause duplicate definitions, resulting in a Rust compilation error (E0592). Verify that either:
- A
compile_error!guard prevents incompatible features from being enabled together, or- Cargo.toml enforces feature-level mutual exclusivity constraints, or
- The feature design has been refactored to handle additive features safely.
s3/src/bucket.rs (12)
40-54: LGTM!The new imports properly support the pluggable backend abstraction. The
Cowtype for request bodies, backend traits, and response handling utilities are all correctly imported.
132-181: LGTM!The generic
Bucket<B>design is clean. Thewith_backendmethod correctly clones all bucket configuration while allowing backend substitution, enabling composable backend customization (e.g., adding timeouts as shown in tests).
237-273: LGTM!The
exec_requestmethods properly abstract over the backend trait. The async variant correctly polls for service readiness before invoking the backend, while the sync variant assumes immediate readiness. Request cloning inside the retry loop is necessary andCow<'_, [u8]>makes this efficient for borrowed payloads.
275-280: LGTM!The 7-day (604800 seconds) maximum is correct per AWS S3 presigned URL limits.
1283-1296: LGTM!The stream handling correctly uses
http_body_util::BodyExtto convert the response body to a data stream. The error mapping properly transforms the body error type intoS3Error.
2064-2074: LGTM!The
head_objectimplementation correctly discards the body (HEAD responses have no body) and extracts headers to construct the result.
3002-3061: LGTM!Test helper functions are correctly updated to use the new
Box<Bucket<DefaultBackend>>return type, consistent with theBucket::newsignature change.
4090-4110: Good test coverage for the pluggable backend feature.This test effectively validates the core capability: injecting a custom backend that returns controlled responses. The
AlwaysFailBackendreturning 418 (I'm a teapot) is a clever way to verify the custom backend is being used.
644-651: LGTM!The
presign_postimplementation correctly clones and boxes the bucket for thePostPolicy::signmethod, which requires ownership of the bucket.
3068-3072: LGTM!The generic test function signatures allow testing with any backend implementation, which is excellent for verifying custom backend behavior. The trait bounds correctly constrain the backend to produce compatible responses.
1590-1590: LGTM!The
FuturesUnorderedimport is correctly placed within the function scope where it's used for bounded parallel multipart uploads.
3943-3965: The review comment is incorrect. SurfBackend (async-std) intentionally does not supportwith_request_timeout.The web search confirms that
with_request_timeoutis only honored by theattohttpcandhyperbackends. Thesurfbackend (used withwith-async-stdfeature) has its own timeout mechanism viasurf::Config::set_timeout(). The test's feature gate#[cfg(any(feature = "with-tokio", feature = "sync"))]correctly excludes async-std because SurfBackend lacks thewith_request_timeoutmethod—not due to an oversight, but by design. Enabling this test for async-std would be incorrect and would likely fail at runtime.
| fn fake_credentials() -> Credentials { | ||
| let access_key = "AKIAIOSFODNN7EXAMPLE"; | ||
| let secert_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; | ||
| Credentials::new(Some(access_key), Some(secert_key), None, None, None).unwrap() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in variable name: secert_key → secret_key.
Minor typo in the test helper that doesn't affect functionality but reduces code clarity.
fn fake_credentials() -> Credentials {
let access_key = "AKIAIOSFODNN7EXAMPLE";
- let secert_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
- Credentials::new(Some(access_key), Some(secert_key), None, None, None).unwrap()
+ let secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
+ Credentials::new(Some(access_key), Some(secret_key), None, None, None).unwrap()
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fn fake_credentials() -> Credentials { | |
| let access_key = "AKIAIOSFODNN7EXAMPLE"; | |
| let secert_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; | |
| Credentials::new(Some(access_key), Some(secert_key), None, None, None).unwrap() | |
| } | |
| fn fake_credentials() -> Credentials { | |
| let access_key = "AKIAIOSFODNN7EXAMPLE"; | |
| let secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"; | |
| Credentials::new(Some(access_key), Some(secret_key), None, None, None).unwrap() | |
| } |
🤖 Prompt for AI Agents
In s3/src/request/request_trait.rs around lines 1298 to 1302, there's a typo in
the test helper variable name `secert_key`; rename it to `secret_key` and update
any references within the function to use the corrected identifier so the code
is clearer (no behavior change).
| { | ||
| type Response = http::Response<reqwest::Body>; | ||
| type Error = S3Error; | ||
| type Future = Pin<Box<dyn Future<Output = Result<Self::Response, S3Error>> + Send>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Future trait import.
Line 61 uses Future in the type alias, but there's no use std::future::Future; import visible. This will cause a compilation error.
Add the missing import at the top of the file:
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
+use std::future::Future;
use tower_service::Service;Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In s3/src/request/tokio_backend.rs around line 61 the type alias references
Future but the file is missing the import; add the missing import line `use
std::future::Future;` near the other use statements at the top of the file so
the type alias `type Future = Pin<Box<dyn Future<Output = Result<Self::Response,
S3Error>> + Send>>;` compiles.
| /// .set_dangereous_config(true, true)?; | ||
| /// # Ok(()) | ||
| /// # } | ||
| /// ``` | ||
| #[cfg(any(feature = "tokio-native-tls", feature = "tokio-rustls-tls"))] | ||
| pub fn with_dangereous_config( | ||
| &self, | ||
| accept_invalid_certs: bool, | ||
| accept_invalid_hostnames: bool, | ||
| ) -> Result<Self, S3Error> { | ||
| let client_options = ClientOptions { | ||
| accept_invalid_certs, | ||
| accept_invalid_hostnames, | ||
| ..self.client_options.clone() | ||
| }; | ||
| Ok(Self { | ||
| http_client: client(&client_options)?, | ||
| client_options, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in method name: dangereous → dangerous.
The method with_dangereous_config (Line 141) and the docstring reference to set_dangereous_config (Line 136) contain a typo. Since this is a public API, consider fixing before release.
- /// let bucket = Bucket::new("my-bucket", Region::from_str("us-east-1")?, Credentials::default()?)?
- /// .set_dangereous_config(true, true)?;
+ /// let bucket = Bucket::new("my-bucket", Region::from_str("us-east-1")?, Credentials::default()?)?
+ /// .set_dangerous_config(true, true)?;
/// # Ok(())
/// # }
/// ```
#[cfg(any(feature = "tokio-native-tls", feature = "tokio-rustls-tls"))]
- pub fn with_dangereous_config(
+ pub fn with_dangerous_config(🤖 Prompt for AI Agents
In s3/src/request/tokio_backend.rs around lines 136 to 155, the public API
method and doc reference use the typoed name "dangereous" instead of
"dangerous"; rename the method to with_dangerous_config and update the docstring
examples to set_dangerous_config (and any other text occurrences) to match;
update all internal and public call sites to the new name, and to avoid breaking
existing users consider adding a small deprecated wrapper function named
with_dangereous_config that calls the new with_dangerous_config and is annotated
with #[deprecated] (plus update tests and documentation).
Traits are defined which backends must implement:
tower::Serviceinterface.ResponseBodythat the backend must return.Minimal new dependencies are taken, notably
http-bodybut not the wholetowercrate, only the small crate with the trait definition.All 3 built-in backends, Reqwest, Surf, and Atto, implement the necessary traits. Exactly one of them is compiled depending on feature flags and exposed as
DefaultBackendso that everything works the same as before by default.Future work will be 2 refactor some functionality such as retries and the
fail-on-errfeature astower::Layermiddleware.This is a somewhat breaking change and so will require a semver bump but I tried to keep it as unintrusive as possible.
This change is
Summary by CodeRabbit
Release Notes
Breaking Changes
New Features
✏️ Tip: You can customize this high-level summary in your review settings.