From 3d249884189abcf8ccd03f7bd7e367e3cbd90963 Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Wed, 13 Mar 2024 15:02:35 -0500 Subject: [PATCH 1/5] add support for env-defined endpoint URLs --- aws/rust-runtime/aws-config/Cargo.toml | 7 +- .../aws-config/src/default_provider.rs | 6 + .../src/default_provider/endpoint_url.rs | 79 +++++++++++ .../ignore_configured_endpoint_urls.rs | 88 ++++++++++++ .../aws-config/src/environment/mod.rs | 31 ++++- aws/rust-runtime/aws-config/src/lib.rs | 127 ++++++++++++++++-- rust-runtime/inlineable/Cargo.toml | 2 +- 7 files changed, 323 insertions(+), 17 deletions(-) create mode 100644 aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs create mode 100644 aws/rust-runtime/aws-config/src/default_provider/ignore_configured_endpoint_urls.rs diff --git a/aws/rust-runtime/aws-config/Cargo.toml b/aws/rust-runtime/aws-config/Cargo.toml index df656841b8..9df480a0f9 100644 --- a/aws/rust-runtime/aws-config/Cargo.toml +++ b/aws/rust-runtime/aws-config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-config" -version = "1.1.8" +version = "1.1.9" authors = [ "AWS Rust SDK Team ", "Russell Cohen ", @@ -26,6 +26,7 @@ allow-compilation = [] [dependencies] aws-credential-types = { path = "../../sdk/build/aws-sdk/sdk/aws-credential-types", features = ["test-util"] } +aws-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-runtime" } aws-sdk-sts = { path = "../../sdk/build/aws-sdk/sdk/sts", default-features = false } aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async" } aws-smithy-http = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-http" } @@ -33,12 +34,12 @@ aws-smithy-json = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-json" } aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime", features = ["client"] } aws-smithy-runtime-api = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["client"] } aws-smithy-types = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-types" } -aws-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-runtime" } aws-types = { path = "../../sdk/build/aws-sdk/sdk/aws-types" } hyper = { version = "0.14.26", default-features = false } time = { version = "0.3.4", features = ["parsing"] } tokio = { version = "1.13.1", features = ["sync"] } tracing = { version = "0.1" } +url = "2.5.0" # implementation detail of IMDS credentials provider fastrand = "2.0.0" @@ -59,7 +60,7 @@ aws-sdk-ssooidc = { path = "../../sdk/build/aws-sdk/sdk/ssooidc", default-featur aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "connector-hyper-0-14-x", "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.1" +tracing-test = "0.2.4" tracing-subscriber = { version = "0.3.16", features = ["fmt", "json"] } tokio = { version = "1.23.1", features = ["full", "test-util"] } diff --git a/aws/rust-runtime/aws-config/src/default_provider.rs b/aws/rust-runtime/aws-config/src/default_provider.rs index 5cbf1102ba..845093bd00 100644 --- a/aws/rust-runtime/aws-config/src/default_provider.rs +++ b/aws/rust-runtime/aws-config/src/default_provider.rs @@ -51,3 +51,9 @@ pub mod use_dual_stack; /// Default access token provider chain #[cfg(feature = "sso")] pub mod token; + +/// Default "ignore configured endpoint URLs" provider chain +pub mod ignore_configured_endpoint_urls; + +/// Default endpoint URL provider chain +pub mod endpoint_url; diff --git a/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs b/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs new file mode 100644 index 0000000000..d9c9dba971 --- /dev/null +++ b/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs @@ -0,0 +1,79 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::environment::parse_url; +use crate::provider_config::ProviderConfig; +use crate::standard_property::StandardProperty; +use aws_smithy_types::error::display::DisplayErrorContext; + +mod env { + pub(super) const ENDPOINT_URL: &str = "AWS_ENDPOINT_URL"; +} + +mod profile_key { + pub(super) const ENDPOINT_URL: &str = "endpoint_url"; +} + +/// Load the value for an endpoint URL +/// +/// This checks the following sources: +/// 1. The environment variable `AWS_ENDPOINT_URL=http://localhost` +/// 2. The profile key `endpoint_url=http://localhost` +/// +/// If invalid values are found, the provider will return None and an error will be logcged. +pub async fn endpoint_url_provider(provider_config: &ProviderConfig) -> Option { + StandardProperty::new() + .env(env::ENDPOINT_URL) + .profile(profile_key::ENDPOINT_URL) + .validate(provider_config, parse_url) + .await + .map_err( + |err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for endpoint URL setting"), + ) + .unwrap_or(None) +} + +#[cfg(test)] +mod test { + use super::endpoint_url_provider; + use super::env; + use crate::profile::profile_file::{ProfileFileKind, ProfileFiles}; + use crate::provider_config::ProviderConfig; + use aws_types::os_shim_internal::{Env, Fs}; + use tracing_test::traced_test; + + #[tokio::test] + #[traced_test] + async fn log_error_on_invalid_value() { + let conf = + ProviderConfig::empty().with_env(Env::from_slice(&[(env::ENDPOINT_URL, "not-a-url")])); + assert_eq!(None, endpoint_url_provider(&conf).await); + assert!(logs_contain("invalid value for endpoint URL setting")); + assert!(logs_contain(env::ENDPOINT_URL)); + } + + #[tokio::test] + #[traced_test] + async fn environment_priority() { + let conf = ProviderConfig::empty() + .with_env(Env::from_slice(&[(env::ENDPOINT_URL, "http://localhost")])) + .with_profile_config( + Some( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "conf") + .build(), + ), + None, + ) + .with_fs(Fs::from_slice(&[( + "conf", + "[default]\nendpoint_url = http://production", + )])); + assert_eq!( + Some("http://localhost".to_owned()), + endpoint_url_provider(&conf).await, + ); + } +} diff --git a/aws/rust-runtime/aws-config/src/default_provider/ignore_configured_endpoint_urls.rs b/aws/rust-runtime/aws-config/src/default_provider/ignore_configured_endpoint_urls.rs new file mode 100644 index 0000000000..93d908d746 --- /dev/null +++ b/aws/rust-runtime/aws-config/src/default_provider/ignore_configured_endpoint_urls.rs @@ -0,0 +1,88 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::environment::parse_bool; +use crate::provider_config::ProviderConfig; +use crate::standard_property::StandardProperty; +use aws_smithy_types::error::display::DisplayErrorContext; + +mod env { + pub(super) const IGNORE_CONFIGURED_ENDPOINT_URLS: &str = "AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"; +} + +mod profile_key { + pub(super) const IGNORE_CONFIGURED_ENDPOINT_URLS: &str = "ignore_configured_endpoint_urls"; +} + +/// Load the value for "ignore configured endpoint URLs" +/// +/// This checks the following sources: +/// 1. The environment variable `AWS_IGNORE_CONFIGURED_ENDPOINT_URLS_ENDPOINT=true/false` +/// 2. The profile key `ignore_configured_endpoint_urls=true/false` +/// +/// If invalid values are found, the provider will return None and an error will be logged. +pub async fn ignore_configured_endpoint_urls_provider( + provider_config: &ProviderConfig, +) -> Option { + StandardProperty::new() + .env(env::IGNORE_CONFIGURED_ENDPOINT_URLS) + .profile(profile_key::IGNORE_CONFIGURED_ENDPOINT_URLS) + .validate(provider_config, parse_bool) + .await + .map_err( + |err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for 'ignore configured endpoint URLs' setting"), + ) + .unwrap_or(None) +} + +#[cfg(test)] +mod test { + use super::env; + use super::ignore_configured_endpoint_urls_provider; + use crate::profile::profile_file::{ProfileFileKind, ProfileFiles}; + use crate::provider_config::ProviderConfig; + use aws_types::os_shim_internal::{Env, Fs}; + use tracing_test::traced_test; + + #[tokio::test] + #[traced_test] + async fn log_error_on_invalid_value() { + let conf = ProviderConfig::empty().with_env(Env::from_slice(&[( + env::IGNORE_CONFIGURED_ENDPOINT_URLS, + "not-a-boolean", + )])); + assert_eq!(None, ignore_configured_endpoint_urls_provider(&conf).await,); + assert!(logs_contain( + "invalid value for 'ignore configured endpoint URLs' setting" + )); + assert!(logs_contain(env::IGNORE_CONFIGURED_ENDPOINT_URLS)); + } + + #[tokio::test] + #[traced_test] + async fn environment_priority() { + let conf = ProviderConfig::empty() + .with_env(Env::from_slice(&[( + env::IGNORE_CONFIGURED_ENDPOINT_URLS, + "TRUE", + )])) + .with_profile_config( + Some( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "conf") + .build(), + ), + None, + ) + .with_fs(Fs::from_slice(&[( + "conf", + "[default]\nignore_configured_endpoint_urls = false", + )])); + assert_eq!( + Some(true), + ignore_configured_endpoint_urls_provider(&conf).await, + ); + } +} diff --git a/aws/rust-runtime/aws-config/src/environment/mod.rs b/aws/rust-runtime/aws-config/src/environment/mod.rs index 8a3f658732..3d5a35920a 100644 --- a/aws/rust-runtime/aws-config/src/environment/mod.rs +++ b/aws/rust-runtime/aws-config/src/environment/mod.rs @@ -6,7 +6,7 @@ //! Providers that load configuration from environment variables use std::error::Error; -use std::fmt::{Display, Formatter}; +use std::fmt; /// Load credentials from the environment pub mod credentials; @@ -21,9 +21,9 @@ pub(crate) struct InvalidBooleanValue { value: String, } -impl Display for InvalidBooleanValue { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{} was not a valid boolean", self.value) +impl fmt::Display for InvalidBooleanValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} is not a valid boolean", self.value) } } @@ -40,3 +40,26 @@ pub(crate) fn parse_bool(value: &str) -> Result { }) } } + +#[derive(Debug)] +pub(crate) struct InvalidUrlValue { + value: String, +} + +impl fmt::Display for InvalidUrlValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} is not a valid URL", self.value) + } +} + +impl Error for InvalidUrlValue {} + +pub(crate) fn parse_url(value: &str) -> Result { + match url::Url::parse(value) { + // We discard the parse result because it includes a trailing slash + Ok(_) => Ok(value.to_string()), + Err(_) => Err(InvalidUrlValue { + value: value.to_string(), + }), + } +} diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index f6d374d04f..9835d9d3d8 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -208,12 +208,6 @@ pub async fn load_defaults(version: BehaviorVersion) -> SdkConfig { } mod loader { - use crate::default_provider::use_dual_stack::use_dual_stack_provider; - use crate::default_provider::use_fips::use_fips_provider; - use crate::default_provider::{app_name, credentials, region, retry_config, timeout_config}; - use crate::meta::region::ProvideRegion; - use crate::profile::profile_file::ProfileFiles; - use crate::provider_config::ProviderConfig; use aws_credential_types::provider::{ token::{ProvideToken, SharedTokenProvider}, ProvideCredentials, SharedCredentialsProvider, @@ -234,6 +228,14 @@ mod loader { use aws_types::sdk_config::SharedHttpClient; use aws_types::SdkConfig; + use crate::default_provider::{ + app_name, credentials, endpoint_url, ignore_configured_endpoint_urls as ignore_ep, region, + retry_config, timeout_config, use_dual_stack, use_fips, + }; + use crate::meta::region::ProvideRegion; + use crate::profile::profile_file::ProfileFiles; + use crate::provider_config::ProviderConfig; + #[derive(Default, Debug)] enum CredentialsProviderOption { /// No provider was set by the user. We can set up the default credentials provider chain. @@ -726,13 +728,13 @@ mod loader { let use_fips = if let Some(use_fips) = self.use_fips { Some(use_fips) } else { - use_fips_provider(&conf).await + use_fips::use_fips_provider(&conf).await }; let use_dual_stack = if let Some(use_dual_stack) = self.use_dual_stack { Some(use_dual_stack) } else { - use_dual_stack_provider(&conf).await + use_dual_stack::use_dual_stack_provider(&conf).await }; let conf = conf @@ -811,6 +813,21 @@ mod loader { .timeout_config(timeout_config) .time_source(time_source); + let ignore_configured_endpoint_urls = + ignore_ep::ignore_configured_endpoint_urls_provider(&conf) + .await + .unwrap_or_default(); + if ignore_configured_endpoint_urls { + tracing::trace!( + "`ignore_configured_endpoint_urls` is set, any endpoint URLs configured in the environment will be ignored. \ + NOTE: Endpoint URLs set programmatically WILL still be respected" + ); + builder.set_endpoint_url(self.endpoint_url); + } else if self.endpoint_url.is_none() { + let endpoint_url = endpoint_url::endpoint_url_provider(&conf).await; + builder.set_endpoint_url(endpoint_url); + } + builder.set_behavior_version(self.behavior_version); builder.set_http_client(self.http_client); builder.set_app_name(app_name); @@ -818,7 +835,6 @@ mod loader { builder.set_credentials_provider(credentials_provider); builder.set_token_provider(token_provider); builder.set_sleep_impl(sleep_impl); - builder.set_endpoint_url(self.endpoint_url); builder.set_use_fips(use_fips); builder.set_use_dual_stack(use_dual_stack); builder.set_stalled_stream_protection(self.stalled_stream_protection_config); @@ -970,5 +986,98 @@ mod loader { let num_requests = num_requests.load(Ordering::Relaxed); assert!(num_requests > 0, "{}", num_requests); } + + #[tokio::test] + async fn endpoint_urls_may_be_ignored_from_env() { + let fs = Fs::from_slice(&[( + "test_config", + "[profile custom]\nendpoint_url = http://profile", + )]); + let env = Env::from_slice(&[("AWS_IGNORE_CONFIGURED_ENDPOINT_URLS", "true")]); + + let conf = base_conf().use_dual_stack(false).load().await; + assert_eq!(Some(false), conf.use_dual_stack()); + + let conf = base_conf().load().await; + assert_eq!(None, conf.use_dual_stack()); + + // Check that we get nothing back because the env said we should ignore endpoints + let config = base_conf() + .fs(fs.clone()) + .env(env) + .profile_name("custom") + .profile_files( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "test_config") + .build(), + ) + .load() + .await; + assert_eq!(None, config.endpoint_url()); + + // Check that without the env, we DO get something back + let config = base_conf() + .fs(fs) + .profile_name("custom") + .profile_files( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "test_config") + .build(), + ) + .load() + .await; + assert_eq!(Some("http://profile"), config.endpoint_url()); + } + + #[tokio::test] + async fn endpoint_urls_may_be_ignored_from_profile() { + let fs = Fs::from_slice(&[( + "test_config", + "[profile custom]\nignore_configured_endpoint_urls = true", + )]); + let env = Env::from_slice(&[("AWS_ENDPOINT_URL", "http://environment")]); + + // Check that we get nothing back because the profile said we should ignore endpoints + let config = base_conf() + .fs(fs) + .env(env.clone()) + .profile_name("custom") + .profile_files( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "test_config") + .build(), + ) + .load() + .await; + assert_eq!(None, config.endpoint_url()); + + // Check that without the profile, we DO get something back + let config = base_conf().env(env).load().await; + assert_eq!(Some("http://environment"), config.endpoint_url()); + } + + #[tokio::test] + async fn programmatic_endpoint_urls_may_not_be_ignored() { + let fs = Fs::from_slice(&[( + "test_config", + "[profile custom]\nignore_configured_endpoint_urls = true", + )]); + let env = Env::from_slice(&[("AWS_IGNORE_CONFIGURED_ENDPOINT_URLS", "true")]); + + // Check that we get something back because we explicitly set the loader's endpoint URL + let config = base_conf() + .fs(fs) + .env(env) + .endpoint_url("http://localhost") + .profile_name("custom") + .profile_files( + ProfileFiles::builder() + .with_file(ProfileFileKind::Config, "test_config") + .build(), + ) + .load() + .await; + assert_eq!(Some("http://localhost"), config.endpoint_url()); + } } } diff --git a/rust-runtime/inlineable/Cargo.toml b/rust-runtime/inlineable/Cargo.toml index 5ab9e82535..3d1dcadc60 100644 --- a/rust-runtime/inlineable/Cargo.toml +++ b/rust-runtime/inlineable/Cargo.toml @@ -32,7 +32,7 @@ once_cell = "1.16.0" percent-encoding = "2.2.0" pin-project-lite = "0.2" regex-lite = "0.1.5" -url = "2.2.2" +url = "2.5.0" [dev-dependencies] proptest = "1" From 2c4e5efd57d0084ca5feebf580cbe28c3d0addf1 Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Wed, 13 Mar 2024 15:10:34 -0500 Subject: [PATCH 2/5] add CHANGELOG.next.toml entry --- CHANGELOG.next.toml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index db78aba957..bc7581d566 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -16,3 +16,19 @@ message = "Increased minimum version of wasi crate dependency in aws-smithy-wasm references = ["smithy-rs#3476"] meta = { "breaking" = false, "tada" = false, "bug" = false } authors = ["landonxjames"] + +[[aws-sdk-rust]] +message = """ +Users may now set an endpoint URL from the env or profile file: + +- env: `AWS_ENDPOINT_URL="http://localhost"` +- profile: `endpoint_url = http://localhost` + +Users may also ignore endpoint URLs sourced from the env and profile files: + +- env: `AWS_IGNORE_CONFIGURED_ENDPOINT_URLS="true"` +- profile: `ignore_configured_endpoint_urls = true` +""" +references = ["smithy-rs#3488"] +meta = { "breaking" = false, "tada" = true, "bug" = false } +authors = ["Velfi"] From 0195c450e49fcf18520061fc39c9cae91c4ee4d4 Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Fri, 15 Mar 2024 07:39:05 -0700 Subject: [PATCH 3/5] Update aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs Co-authored-by: John DiSanti --- .../aws-config/src/default_provider/endpoint_url.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs b/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs index d9c9dba971..eaae3f2a68 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/endpoint_url.rs @@ -22,7 +22,7 @@ mod profile_key { /// 1. The environment variable `AWS_ENDPOINT_URL=http://localhost` /// 2. The profile key `endpoint_url=http://localhost` /// -/// If invalid values are found, the provider will return None and an error will be logcged. +/// If invalid values are found, the provider will return None and an error will be logged. pub async fn endpoint_url_provider(provider_config: &ProviderConfig) -> Option { StandardProperty::new() .env(env::ENDPOINT_URL) From 46491e09bb744eef8fe2276a916231c0c3454359 Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Fri, 15 Mar 2024 09:44:15 -0500 Subject: [PATCH 4/5] sync crate `url`'s versions with codegen --- aws/rust-runtime/aws-config/Cargo.toml | 2 +- rust-runtime/inlineable/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/rust-runtime/aws-config/Cargo.toml b/aws/rust-runtime/aws-config/Cargo.toml index 9df480a0f9..4fc79fa1dc 100644 --- a/aws/rust-runtime/aws-config/Cargo.toml +++ b/aws/rust-runtime/aws-config/Cargo.toml @@ -39,7 +39,7 @@ hyper = { version = "0.14.26", default-features = false } time = { version = "0.3.4", features = ["parsing"] } tokio = { version = "1.13.1", features = ["sync"] } tracing = { version = "0.1" } -url = "2.5.0" +url = "2.3.1" # implementation detail of IMDS credentials provider fastrand = "2.0.0" diff --git a/rust-runtime/inlineable/Cargo.toml b/rust-runtime/inlineable/Cargo.toml index 3d1dcadc60..7cc4d120a2 100644 --- a/rust-runtime/inlineable/Cargo.toml +++ b/rust-runtime/inlineable/Cargo.toml @@ -32,7 +32,7 @@ once_cell = "1.16.0" percent-encoding = "2.2.0" pin-project-lite = "0.2" regex-lite = "0.1.5" -url = "2.5.0" +url = "2.3.1" [dev-dependencies] proptest = "1" From f6bc3754a63f3fc9317523fb805f73515025c56a Mon Sep 17 00:00:00 2001 From: Zelda Hessler Date: Fri, 15 Mar 2024 11:55:46 -0500 Subject: [PATCH 5/5] fix endpoint bungle --- aws/rust-runtime/aws-config/src/lib.rs | 37 ++++++++++++------- .../s3/tests/service_timeout_overrides.rs | 6 +++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 9835d9d3d8..d5be002d6d 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -813,20 +813,29 @@ mod loader { .timeout_config(timeout_config) .time_source(time_source); - let ignore_configured_endpoint_urls = - ignore_ep::ignore_configured_endpoint_urls_provider(&conf) - .await - .unwrap_or_default(); - if ignore_configured_endpoint_urls { - tracing::trace!( - "`ignore_configured_endpoint_urls` is set, any endpoint URLs configured in the environment will be ignored. \ - NOTE: Endpoint URLs set programmatically WILL still be respected" - ); - builder.set_endpoint_url(self.endpoint_url); - } else if self.endpoint_url.is_none() { - let endpoint_url = endpoint_url::endpoint_url_provider(&conf).await; - builder.set_endpoint_url(endpoint_url); - } + // If an endpoint URL is set programmatically, then our work is done. + let endpoint_url = if self.endpoint_url.is_some() { + self.endpoint_url + } else { + // Otherwise, check to see if we should ignore EP URLs set in the environment. + let ignore_configured_endpoint_urls = + ignore_ep::ignore_configured_endpoint_urls_provider(&conf) + .await + .unwrap_or_default(); + + if ignore_configured_endpoint_urls { + // If yes, log a trace and return `None`. + tracing::trace!( + "`ignore_configured_endpoint_urls` is set, any endpoint URLs configured in the environment will be ignored. \ + NOTE: Endpoint URLs set programmatically WILL still be respected" + ); + None + } else { + // Otherwise, attempt to resolve one. + endpoint_url::endpoint_url_provider(&conf).await + } + }; + builder.set_endpoint_url(endpoint_url); builder.set_behavior_version(self.behavior_version); builder.set_http_client(self.http_client); diff --git a/aws/sdk/integration-tests/s3/tests/service_timeout_overrides.rs b/aws/sdk/integration-tests/s3/tests/service_timeout_overrides.rs index cc07648f65..062b04a609 100644 --- a/aws/sdk/integration-tests/s3/tests/service_timeout_overrides.rs +++ b/aws/sdk/integration-tests/s3/tests/service_timeout_overrides.rs @@ -97,7 +97,13 @@ async fn default_connect_timeout_set() { .build() ) ); + assert_eq!( + sdk_config.endpoint_url(), + Some("http://172.255.255.0:18104") + ); + let config = aws_sdk_s3::config::Builder::from(&sdk_config) + // .endpoint_url("http://172.255.255.0:18104") .timeout_config( TimeoutConfig::builder() .operation_attempt_timeout(Duration::from_secs(8))