Skip to content

Commit

Permalink
enable hyper1 as default http client (#3939)
Browse files Browse the repository at this point in the history
## Motivation and Context
* #1925
* awslabs/aws-sdk-rust#977

## Description
* Add a new `default-http-connector` feature to `aws-smithy-runtime`
that enables hyper 1.x with rustls+aws-lc as the default HTTP client
plugin.
* If both the legacy `connector-hyper-014-x` feature is enabled the new
feature takes precedence such that the default HTTP client plugin favors
hyper 1 if both features are enabled.
* Update codegen to enable the new `default-http-connector` feature
instead of hyper 0.14
* NOTE: we can't break the existing `rustls` feature flag so it has
instead been updated to enable the `default-http-connector` feature.
* Importantly this still uses rustls as the TLS provider but the crypto
provider now defaults to aws-lc (which is coincidentally what rustls now
defaults to as well). This is likely to break _someone_ somewhere due to
build requirements changing (e.g. CMake now be required on certain
platforms or other build tools needed).
* Updated `aws-config` to default to hyper1 for the default credentials
chain.
* We have two features in `aws-config`, `rustls` and `client-hyper`,
that seem to be used entirely to enable the `aws-smithy-runtime`
features `tls-rustls` and `connector-hyper-0-14-x` features (both are
required for the default HTTP client plugin to work prior to this PR). I
think the _intent_ behind these features was "the user is not providing
an HTTP client explicitly so we need a default one to be available".
I've added a new feature to `aws-config` for this,
`default-http-connector` and updated the existing features to be
synonyms. We don't use `rustls` or `hyper 0.14.x` directly in
`aws-config` so I think this is a more clearly defined flag and conveys
it's intent better.
* Added a new `legacy-test-util` feature flag to `aws-smithy-runtime`.
The rationale for this is that the `test-util` feature provides testing
utilities for other things from `aws-smithy-runtime` but it also brings
in the (now) legacy hyper 0.14 HTTP testing facilities. I've left
`test-util` to mean what it does today and be backwards compatibile (for
now anyway) and in future we can ship a (breaking) change to disable the
legacy test utils by default (and by extension stop compiling the legacy
hyper ecosystem in all of our tests)
* Fixed an issue in `examples/pokemon-service-common` due to codegen no
longer generating clients with the `aws-smithy-runtime/tls-rustls`
feature enabled by default (they are using the
`HyperClientBuilder::build_https()` method directly but relying on
feature unification to enable the method)

## Questions

* Bikeshed any feature flag names. e.g.
`aws-config/default-http-connector` could be more generic like
`default-providers` or something. Today we use it to mean "we need a
default HTTP client" but you can imagine a future where we need other
default runtime components to exist and be configured. Perhaps that is
what we want from this flag?
 

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
aajtodd authored Dec 12, 2024
1 parent 21f5765 commit ba89a32
Show file tree
Hide file tree
Showing 60 changed files with 990 additions and 722 deletions.
175 changes: 85 additions & 90 deletions aws/rust-runtime/Cargo.lock

Large diffs are not rendered by default.

455 changes: 345 additions & 110 deletions aws/rust-runtime/aws-config/Cargo.lock

Large diffs are not rendered by default.

26 changes: 16 additions & 10 deletions aws/rust-runtime/aws-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ repository = "https://github.com/smithy-lang/smithy-rs"

[features]
behavior-version-latest = []
client-hyper = ["aws-smithy-runtime/connector-hyper-0-14-x"]
credentials-process = ["tokio/process"]
default = ["client-hyper", "rustls", "rt-tokio", "credentials-process", "sso"]
default = ["default-http-connector", "rt-tokio", "credentials-process", "sso"]
rt-tokio = ["aws-smithy-async/rt-tokio", "aws-smithy-runtime/rt-tokio", "tokio/rt"]
rustls = ["aws-smithy-runtime/tls-rustls", "client-hyper"]
# NOTE: `client-hyper` and `rustls` were proxies for enabling the default HTTP client plugin of `aws-smithy-runtime`
# there is no direct usage otherwise on hyper or rustls in this crate. These are superceded by the more appropriately
# named `default-http-connector` feature and `client-hyper` and `rustls` are now synonyms for the same
client-hyper = ["aws-smithy-runtime/default-http-connector"]
rustls = ["client-hyper"]
default-http-connector = ["aws-smithy-runtime/default-http-connector"]
sso = ["dep:aws-sdk-sso", "dep:aws-sdk-ssooidc", "dep:ring", "dep:hex", "dep:zeroize", "aws-smithy-runtime-api/http-auth"]

# deprecated: this feature does nothing
Expand Down Expand Up @@ -53,9 +57,12 @@ zeroize = { version = "1", optional = true }
# implementation detail of SSO OIDC `CreateToken` for SSO token providers
aws-sdk-ssooidc = { path = "../../sdk/build/aws-sdk/sdk/ssooidc", default-features = false, optional = true }

proc-macro2 = {version = "1.0.92", optional = true }

[dev-dependencies]
aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "connector-hyper-0-14-x", "test-util"] }
aws-smithy-http-client = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-http-client", features = ["test-util"] }
aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async", features = ["rt-tokio", "test-util"] }
aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "test-util"] }
aws-smithy-http-client = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-http-client", features = ["hyper-1", "test-util"] }
aws-smithy-runtime-api = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["test-util"] }
futures-util = { version = "0.3.29", default-features = false }
tracing-test = "0.2.4"
Expand All @@ -66,11 +73,6 @@ tokio = { version = "1.23.1", features = ["full", "test-util"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# used for a usage example
hyper-rustls = { version = "0.24", features = ["webpki-tokio", "http2", "http1"] }
aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async", features = ["rt-tokio", "test-util"] }


[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-unknown-linux-gnu"]
Expand All @@ -83,3 +85,7 @@ rustdoc-args = ["--cfg", "docsrs"]
# Crate("aws-config", STABLE_VERSION_PROP_NAME),
[package.metadata.smithy-rs-release-tooling]
stable = true

# FIXME - workaround minimal-versions check issue with proc-macro < 1.0.60
[package.metadata.cargo-udeps.ignore]
normal = ["proc-macro2"]
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::meta::credentials::CredentialsProviderChain;
use crate::meta::region::ProvideRegion;
use crate::provider_config::ProviderConfig;

#[cfg(feature = "rustls")]
#[cfg(any(feature = "default-http-connector", feature = "rustls"))]
/// Default Credentials Provider chain
///
/// The region from the default region provider will be used
Expand Down Expand Up @@ -170,7 +170,7 @@ impl Builder {
/// Creates a `DefaultCredentialsChain`
///
/// ## Panics
/// This function will panic if no connector has been set or the `rustls`
/// This function will panic if no connector has been set or the `default-http-connector`
/// feature has been disabled.
pub async fn build(self) -> DefaultCredentialsChain {
let region = match self.region_override {
Expand Down Expand Up @@ -347,17 +347,15 @@ mod test {
}

#[tokio::test]
#[cfg(feature = "client-hyper")]
async fn no_providers_configured_err() {
use crate::provider_config::ProviderConfig;
use aws_credential_types::provider::error::CredentialsError;
use aws_smithy_async::rt::sleep::TokioSleep;
use aws_smithy_http_client::test_util::NeverTcpConnector;
use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder;

tokio::time::pause();
let conf = ProviderConfig::no_configuration()
.with_http_client(HyperClientBuilder::new().build(NeverTcpConnector::new()))
.with_http_client(NeverTcpConnector::new().into_client())
.with_time_source(StaticTimeSource::new(UNIX_EPOCH))
.with_sleep_impl(TokioSleep::new());
let provider = DefaultCredentialsChain::builder()
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/imds/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ pub(crate) mod test {
#[cfg_attr(windows, ignore)]
/// Verify that the end-to-end real client has a 1-second connect timeout
#[tokio::test]
#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
async fn one_second_connect_timeout() {
use crate::imds::client::ImdsError;
use aws_smithy_types::error::display::DisplayErrorContext;
Expand Down
6 changes: 3 additions & 3 deletions aws/rust-runtime/aws-config/src/imds/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ mod test {
}

#[tokio::test]
#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
async fn read_timeout_during_credentials_refresh_should_yield_last_retrieved_credentials() {
let client = crate::imds::Client::builder()
// 240.* can never be resolved
Expand All @@ -436,7 +436,7 @@ mod test {
}

#[tokio::test]
#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
async fn read_timeout_during_credentials_refresh_should_error_without_last_retrieved_credentials(
) {
let client = crate::imds::Client::builder()
Expand All @@ -458,7 +458,7 @@ mod test {
// TODO(https://github.com/awslabs/aws-sdk-rust/issues/1117) This test is ignored on Windows because it uses Unix-style paths
#[cfg_attr(windows, ignore)]
#[tokio::test]
#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
async fn external_timeout_during_credentials_refresh_should_yield_last_retrieved_credentials() {
use aws_smithy_async::rt::sleep::AsyncSleep;
let client = crate::imds::Client::builder()
Expand Down
31 changes: 3 additions & 28 deletions aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,31 +391,6 @@ mod loader {
///
/// If you wish to use a separate HTTP client for credentials providers when creating clients,
/// then override the HTTP client set with this function on the client-specific `Config`s.
///
/// ## Examples
///
/// ```no_run
/// # use aws_smithy_async::rt::sleep::SharedAsyncSleep;
/// #[cfg(feature = "client-hyper")]
/// # async fn create_config() {
/// use std::time::Duration;
/// use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder;
///
/// let tls_connector = hyper_rustls::HttpsConnectorBuilder::new()
/// .with_webpki_roots()
/// // NOTE: setting `https_only()` will not allow this connector to work with IMDS.
/// .https_only()
/// .enable_http1()
/// .enable_http2()
/// .build();
///
/// let hyper_client = HyperClientBuilder::new().build(tls_connector);
/// let sdk_config = aws_config::from_env()
/// .http_client(hyper_client)
/// .load()
/// .await;
/// # }
/// ```
pub fn http_client(mut self, http_client: impl HttpClient + 'static) -> Self {
self.http_client = Some(http_client.into_shared());
self
Expand Down Expand Up @@ -1128,7 +1103,7 @@ mod loader {
assert_eq!(Some(&app_name), conf.app_name());
}

#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
#[tokio::test]
async fn disable_default_credentials() {
let config = defaults(BehaviorVersion::latest())
Expand All @@ -1138,15 +1113,15 @@ mod loader {
assert!(config.credentials_provider().is_none());
}

#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
#[tokio::test]
async fn identity_cache_defaulted() {
let config = defaults(BehaviorVersion::latest()).load().await;

assert!(config.identity_cache().is_some());
}

#[cfg(feature = "rustls")]
#[cfg(feature = "default-http-connector")]
#[allow(deprecated)]
#[tokio::test]
async fn identity_cache_old_behavior_version() {
Expand Down
4 changes: 2 additions & 2 deletions aws/rust-runtime/aws-config/src/meta/credentials/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl CredentialsProviderChain {
}

/// Add a fallback to the default provider chain
#[cfg(feature = "rustls")]
#[cfg(any(feature = "default-http-connector", feature = "rustls"))]
pub async fn or_default_provider(self) -> Self {
self.or_else(
"DefaultProviderChain",
Expand All @@ -82,7 +82,7 @@ impl CredentialsProviderChain {
}

/// Creates a credential provider chain that starts with the default provider
#[cfg(feature = "rustls")]
#[cfg(any(feature = "default-http-connector", feature = "rustls"))]
pub async fn default_provider() -> Self {
Self::first_try(
"DefaultProviderChain",
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/profile/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub(crate) mod repr;
/// future::ProvideCredentials::new(self.load_credentials())
/// }
/// }
/// # if cfg!(feature = "rustls") {
/// # if cfg!(feature = "default-http-connector") {
/// let provider = ProfileFileCredentialsProvider::builder()
/// .with_custom_provider("Custom", MyCustomProvider)
/// .build();
Expand Down
2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/src/provider_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl ProviderConfig {
///
/// # Examples
/// ```no_run
/// # #[cfg(feature = "rustls")]
/// # #[cfg(feature = "default-http-connector")]
/// # fn example() {
/// use aws_config::provider_config::ProviderConfig;
/// use aws_sdk_sts::config::Region;
Expand Down
5 changes: 3 additions & 2 deletions aws/rust-runtime/aws-config/src/test_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,20 +318,21 @@ where
O: for<'a> Deserialize<'a> + Secrets + PartialEq + Debug,
E: Error,
{
#[cfg(feature = "default-http-connector")]
#[allow(unused)]
#[cfg(all(feature = "client-hyper", feature = "rustls"))]
/// Record a test case from live (remote) HTTPS traffic
///
/// The `default_connector()` from the crate will be used
pub(crate) async fn execute_from_live_traffic(&self) {
// swap out the connector generated from `http-traffic.json` for a real connector:

use std::error::Error;
let live_connector = aws_smithy_runtime::client::http::hyper_014::default_connector(
let live_connector = aws_smithy_http_client::default_connector(
&Default::default(),
self.provider_config.sleep_impl(),
)
.expect("feature gate on this function makes this always return Some");

let live_client = RecordingClient::new(live_connector);
let config = self
.provider_config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class AwsFluentClientDecorator : ClientCodegenDecorator {
rustCrate.withModule(ClientRustModule.client) {
AwsFluentClientExtensions(codegenContext, types).render(this)
}
rustCrate.mergeFeature(Feature("rustls", default = true, listOf("aws-smithy-runtime/tls-rustls")))
rustCrate.mergeFeature(Feature("rustls", default = true, listOf("aws-smithy-runtime/default-http-connector")))
}

override fun libRsCustomizations(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class IntegrationTestDependencies(
addDependency(SerdeJson)
addDependency(smithyAsync)
addDependency(smithyProtocolTestHelpers(codegenContext.runtimeConfig))
addDependency(smithyRuntime(runtimeConfig).copy(features = setOf("test-util", "wire-mock"), scope = DependencyScope.Dev))
addDependency(smithyRuntime(runtimeConfig).copy(features = setOf("test-util"), scope = DependencyScope.Dev))
addDependency(smithyRuntimeApiTestUtil(runtimeConfig))
addDependency(smithyTypes)
addDependency(Tokio)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ class EndpointBuiltInsDecoratorTest {
""",
"tokio" to CargoDependency.Tokio.toDevDependency().withFeature("rt").withFeature("macros").toType(),
"StaticReplayClient" to
CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType()
.resolve("client::http::test_util::StaticReplayClient"),
CargoDependency.smithyHttpClientTestUtil(codegenContext.runtimeConfig).toType()
.resolve("test_util::StaticReplayClient"),
"ReplayEvent" to
CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType()
.resolve("client::http::test_util::ReplayEvent"),
CargoDependency.smithyHttpClientTestUtil(codegenContext.runtimeConfig).toType()
.resolve("test_util::ReplayEvent"),
"SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig),
)
}
Expand Down
Loading

0 comments on commit ba89a32

Please sign in to comment.