/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/config/defaults/ClientConfigurationDefaults.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/client/DefaultRetryStrategy.h>
#include <aws/core/client/AdaptiveRetryStrategy.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/platform/OSVersionInfo.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/threading/Executor.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>
#include <aws/core/Version.h>
#include <aws/core/config/AWSProfileConfigLoader.h>
#include <aws/core/utils/logging/LogMacros.h>
namespace Aws
{
namespace Auth
{
AWS_CORE_API Aws::String GetConfigProfileFilename();
}
namespace Client
{
static const char* CLIENT_CONFIG_TAG = "ClientConfiguration";
static const char* USE_REQUEST_COMPRESSION_ENV_VAR = "USE_REQUEST_COMPRESSION";
static const char* USE_REQUEST_COMPRESSION_CONFIG_VAR = "use_request_compression";
static const char* REQUEST_MIN_COMPRESSION_SIZE_BYTES_ENV_VAR = "REQUEST_MIN_COMPRESSION_SIZE_BYTES";
static const char* REQUEST_MIN_COMPRESSION_SIZE_BYTES_CONFIG_VAR = "request_min_compression_size_bytes";
Aws::String ComputeUserAgentString()
{
Aws::StringStream ss;
ss << "aws-sdk-cpp/" << Version::GetVersionString() << " "
#if defined(AWS_USER_AGENT_CUSTOMIZATION)
#define XSTR(V) STR(V)
#define STR(V) #V
<< XSTR(AWS_USER_AGENT_CUSTOMIZATION) << " "
#undef STR
#undef XSTR
#endif
<< Aws::OSVersionInfo::ComputeOSVersionString() << " "
<< Version::GetCompilerVersionString();
return ss.str();
}
void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig)
{
clientConfig.scheme = Aws::Http::Scheme::HTTPS;
clientConfig.useDualStack = false;
clientConfig.useFIPS = false;
clientConfig.maxConnections = 25;
clientConfig.httpRequestTimeoutMs = 0;
clientConfig.requestTimeoutMs = 3000;
clientConfig.connectTimeoutMs = 1000;
clientConfig.enableTcpKeepAlive = true;
clientConfig.tcpKeepAliveIntervalMs = 30000;
clientConfig.lowSpeedLimit = 1;
clientConfig.proxyScheme = Aws::Http::Scheme::HTTP;
clientConfig.proxyPort = 0;
clientConfig.executor = Aws::MakeShared<Aws::Utils::Threading::DefaultExecutor>(CLIENT_CONFIG_TAG);
clientConfig.verifySSL = true;
clientConfig.writeRateLimiter = nullptr;
clientConfig.readRateLimiter = nullptr;
clientConfig.httpLibOverride = Aws::Http::TransferLibType::DEFAULT_CLIENT;
clientConfig.followRedirects = FollowRedirectsPolicy::DEFAULT;
clientConfig.disableExpectHeader = false;
clientConfig.enableClockSkewAdjustment = true;
clientConfig.enableHostPrefixInjection = true;
clientConfig.profileName = Aws::Auth::GetConfigProfileName();
Aws::String useCompressionConfig = clientConfig.LoadConfigFromEnvOrProfile(
USE_REQUEST_COMPRESSION_ENV_VAR,
Aws::Auth::GetConfigProfileName(),
USE_REQUEST_COMPRESSION_CONFIG_VAR,
{"ENABLE", "DISABLE", "enable", "disable"},
"ENABLE"
);
if (Aws::Utils::StringUtils::ToLower(useCompressionConfig.c_str()) == "disable") {
clientConfig.requestCompressionConfig.useRequestCompression = Aws::Client::UseRequestCompression::DISABLE;
AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "Request Compression disabled");
} else {
//Using default to true for forward compatibility in case new config is added but SDK is not updated.
clientConfig.requestCompressionConfig.useRequestCompression = Aws::Client::UseRequestCompression::ENABLE;
AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "Request Compression enabled");
}
// Getting min request compression length
Aws::String minRequestCompressionString = Aws::Environment::GetEnv(REQUEST_MIN_COMPRESSION_SIZE_BYTES_ENV_VAR);
if (minRequestCompressionString.empty())
{
minRequestCompressionString = Aws::Config::GetCachedConfigValue(REQUEST_MIN_COMPRESSION_SIZE_BYTES_CONFIG_VAR);
}
if (!minRequestCompressionString.empty()) {
clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes = static_cast<int>(Aws::Utils::StringUtils::ConvertToInt32(minRequestCompressionString.c_str()));
if (clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes > 10485760) {
AWS_LOGSTREAM_ERROR(CLIENT_CONFIG_TAG, "ClientConfiguration for MinReqCompression is unsupported, received: " << clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes);
}
}
AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use MinReqCompression: " << clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes);
AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use SDK Auto Resolved profile: [" << clientConfig.profileName << "] if not specified by users.");
// Automatically determine the AWS region from environment variables, configuration file and EC2 metadata.
clientConfig.region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION");
if (!clientConfig.region.empty())
{
return;
}
clientConfig.region = Aws::Environment::GetEnv("AWS_REGION");
if (!clientConfig.region.empty())
{
return;
}
clientConfig.region = Aws::Config::GetCachedConfigValue("region");
if (!clientConfig.region.empty())
{
return;
}
// Set the endpoint to interact with EC2 instance's metadata service
Aws::String ec2MetadataServiceEndpoint = Aws::Environment::GetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT");
if (! ec2MetadataServiceEndpoint.empty())
{
//By default we use the IPv4 default metadata service address
auto client = Aws::Internal::GetEC2MetadataClient();
if (client != nullptr)
{
client->SetEndpoint(ec2MetadataServiceEndpoint);
}
}
}
ClientConfiguration::ClientConfiguration()
{
this->disableIMDS = false;
setLegacyClientConfigurationParameters(*this);
retryStrategy = InitRetryStrategy();
if (!this->disableIMDS &&
region.empty() &&
Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true")
{
auto client = Aws::Internal::GetEC2MetadataClient();
if (client)
{
region = client->GetCurrentRegion();
}
}
if (!region.empty())
{
return;
}
region = Aws::String(Aws::Region::US_EAST_1);
}
ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisableIMDS)
{
this->disableIMDS = shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
// Call EC2 Instance Metadata service only once
Aws::String ec2MetadataRegion;
bool hasEc2MetadataRegion = false;
if (!this->disableIMDS &&
region.empty() &&
Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") {
auto client = Aws::Internal::GetEC2MetadataClient();
if (client)
{
ec2MetadataRegion = client->GetCurrentRegion();
hasEc2MetadataRegion = true;
region = ec2MetadataRegion;
}
}
if(region.empty())
{
region = Aws::String(Aws::Region::US_EAST_1);
}
if (profile && Aws::Config::HasCachedConfigProfile(profile)) {
this->profileName = Aws::String(profile);
AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG,
"Use user specified profile: [" << this->profileName << "] for ClientConfiguration.");
auto tmpRegion = Aws::Config::GetCachedConfigProfile(this->profileName).GetRegion();
if (!tmpRegion.empty()) {
region = tmpRegion;
}
Aws::String profileDefaultsMode = Aws::Config::GetCachedConfigProfile(this->profileName).GetDefaultsMode();
Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, profileDefaultsMode,
hasEc2MetadataRegion, ec2MetadataRegion);
return;
}
if (!retryStrategy)
{
retryStrategy = InitRetryStrategy();
}
AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "User specified profile: [" << profile << "] is not found, will use the SDK resolved one.");
}
ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char* defaultMode, bool shouldDisableIMDS)
{
this->disableIMDS = shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
// Call EC2 Instance Metadata service only once
Aws::String ec2MetadataRegion;
bool hasEc2MetadataRegion = false;
if (!this->disableIMDS &&
region.empty() &&
Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true")
{
auto client = Aws::Internal::GetEC2MetadataClient();
if (client)
{
ec2MetadataRegion = client->GetCurrentRegion();
hasEc2MetadataRegion = true;
region = ec2MetadataRegion;
}
}
if (region.empty())
{
region = Aws::String(Aws::Region::US_EAST_1);
}
Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, defaultMode, hasEc2MetadataRegion, ec2MetadataRegion);
}
std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode)
{
int maxAttempts = 0;
Aws::String maxAttemptsString = Aws::Environment::GetEnv("AWS_MAX_ATTEMPTS");
if (maxAttemptsString.empty())
{
maxAttemptsString = Aws::Config::GetCachedConfigValue("max_attempts");
}
// In case users specify 0 explicitly to disable retry.
if (maxAttemptsString == "0")
{
maxAttempts = 0;
}
else
{
maxAttempts = static_cast<int>(Aws::Utils::StringUtils::ConvertToInt32(maxAttemptsString.c_str()));
if (maxAttempts == 0)
{
AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Retry Strategy will use the default max attempts.");
maxAttempts = -1;
}
}
if (retryMode.empty())
{
retryMode = Aws::Environment::GetEnv("AWS_RETRY_MODE");
}
if (retryMode.empty())
{
retryMode = Aws::Config::GetCachedConfigValue("retry_mode");
}
std::shared_ptr<RetryStrategy> retryStrategy;
if (retryMode == "standard")
{
if (maxAttempts < 0)
{
// negative value set above force usage of default max attempts
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG);
}
else
{
retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
}
}
else if (retryMode == "adaptive")
{
if (maxAttempts < 0)
{
// negative value set above force usage of default max attempts
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG);
}
else
{
retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
}
}
else
{
retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG);
}
return retryStrategy;
}
Aws::String ClientConfiguration::LoadConfigFromEnvOrProfile(const Aws::String& envKey,
const Aws::String& profile,
const Aws::String& profileProperty,
const Aws::Vector<Aws::String>& allowedValues,
const Aws::String& defaultValue)
{
Aws::String option = Aws::Environment::GetEnv(envKey.c_str());
if (option.empty()) {
option = Aws::Config::GetCachedConfigValue(profile, profileProperty);
}
option = Aws::Utils::StringUtils::ToLower(option.c_str());
if (option.empty()) {
return defaultValue;
}
if (!allowedValues.empty() && std::find(allowedValues.cbegin(), allowedValues.cend(), option) == allowedValues.cend()) {
Aws::OStringStream expectedStr;
expectedStr << "[";
for(const auto& allowed : allowedValues) {
expectedStr << allowed << ";";
}
expectedStr << "]";
AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Unrecognised value for " << envKey << ": " << option <<
". Using default instead: " << defaultValue <<
". Expected empty or one of: " << expectedStr.str());
option = defaultValue;
}
return option;
}
} // namespace Client
} // namespace Aws