ClientConfiguration.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/client/ClientConfiguration.h>
  6. #include <aws/core/config/defaults/ClientConfigurationDefaults.h>
  7. #include <aws/core/auth/AWSCredentialsProvider.h>
  8. #include <aws/core/client/DefaultRetryStrategy.h>
  9. #include <aws/core/client/AdaptiveRetryStrategy.h>
  10. #include <aws/core/platform/Environment.h>
  11. #include <aws/core/platform/OSVersionInfo.h>
  12. #include <aws/core/utils/memory/AWSMemory.h>
  13. #include <aws/core/utils/StringUtils.h>
  14. #include <aws/core/utils/threading/Executor.h>
  15. #include <aws/core/utils/memory/stl/AWSStringStream.h>
  16. #include <aws/core/Version.h>
  17. #include <aws/core/config/AWSProfileConfigLoader.h>
  18. #include <aws/core/utils/logging/LogMacros.h>
  19. namespace Aws
  20. {
  21. namespace Auth
  22. {
  23. AWS_CORE_API Aws::String GetConfigProfileFilename();
  24. }
  25. namespace Client
  26. {
  27. static const char* CLIENT_CONFIG_TAG = "ClientConfiguration";
  28. static const char* USE_REQUEST_COMPRESSION_ENV_VAR = "USE_REQUEST_COMPRESSION";
  29. static const char* USE_REQUEST_COMPRESSION_CONFIG_VAR = "use_request_compression";
  30. static const char* REQUEST_MIN_COMPRESSION_SIZE_BYTES_ENV_VAR = "REQUEST_MIN_COMPRESSION_SIZE_BYTES";
  31. static const char* REQUEST_MIN_COMPRESSION_SIZE_BYTES_CONFIG_VAR = "request_min_compression_size_bytes";
  32. Aws::String ComputeUserAgentString()
  33. {
  34. Aws::StringStream ss;
  35. ss << "aws-sdk-cpp/" << Version::GetVersionString() << " "
  36. #if defined(AWS_USER_AGENT_CUSTOMIZATION)
  37. #define XSTR(V) STR(V)
  38. #define STR(V) #V
  39. << XSTR(AWS_USER_AGENT_CUSTOMIZATION) << " "
  40. #undef STR
  41. #undef XSTR
  42. #endif
  43. << Aws::OSVersionInfo::ComputeOSVersionString() << " "
  44. << Version::GetCompilerVersionString();
  45. return ss.str();
  46. }
  47. void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig)
  48. {
  49. clientConfig.scheme = Aws::Http::Scheme::HTTPS;
  50. clientConfig.useDualStack = false;
  51. clientConfig.useFIPS = false;
  52. clientConfig.maxConnections = 25;
  53. clientConfig.httpRequestTimeoutMs = 0;
  54. clientConfig.requestTimeoutMs = 3000;
  55. clientConfig.connectTimeoutMs = 1000;
  56. clientConfig.enableTcpKeepAlive = true;
  57. clientConfig.tcpKeepAliveIntervalMs = 30000;
  58. clientConfig.lowSpeedLimit = 1;
  59. clientConfig.proxyScheme = Aws::Http::Scheme::HTTP;
  60. clientConfig.proxyPort = 0;
  61. clientConfig.executor = Aws::MakeShared<Aws::Utils::Threading::DefaultExecutor>(CLIENT_CONFIG_TAG);
  62. clientConfig.verifySSL = true;
  63. clientConfig.writeRateLimiter = nullptr;
  64. clientConfig.readRateLimiter = nullptr;
  65. clientConfig.httpLibOverride = Aws::Http::TransferLibType::DEFAULT_CLIENT;
  66. clientConfig.followRedirects = FollowRedirectsPolicy::DEFAULT;
  67. clientConfig.disableExpectHeader = false;
  68. clientConfig.enableClockSkewAdjustment = true;
  69. clientConfig.enableHostPrefixInjection = true;
  70. clientConfig.profileName = Aws::Auth::GetConfigProfileName();
  71. Aws::String useCompressionConfig = clientConfig.LoadConfigFromEnvOrProfile(
  72. USE_REQUEST_COMPRESSION_ENV_VAR,
  73. Aws::Auth::GetConfigProfileName(),
  74. USE_REQUEST_COMPRESSION_CONFIG_VAR,
  75. {"ENABLE", "DISABLE", "enable", "disable"},
  76. "ENABLE"
  77. );
  78. if (Aws::Utils::StringUtils::ToLower(useCompressionConfig.c_str()) == "disable") {
  79. clientConfig.requestCompressionConfig.useRequestCompression = Aws::Client::UseRequestCompression::DISABLE;
  80. AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "Request Compression disabled");
  81. } else {
  82. //Using default to true for forward compatibility in case new config is added but SDK is not updated.
  83. clientConfig.requestCompressionConfig.useRequestCompression = Aws::Client::UseRequestCompression::ENABLE;
  84. AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "Request Compression enabled");
  85. }
  86. // Getting min request compression length
  87. Aws::String minRequestCompressionString = Aws::Environment::GetEnv(REQUEST_MIN_COMPRESSION_SIZE_BYTES_ENV_VAR);
  88. if (minRequestCompressionString.empty())
  89. {
  90. minRequestCompressionString = Aws::Config::GetCachedConfigValue(REQUEST_MIN_COMPRESSION_SIZE_BYTES_CONFIG_VAR);
  91. }
  92. if (!minRequestCompressionString.empty()) {
  93. clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes = static_cast<int>(Aws::Utils::StringUtils::ConvertToInt32(minRequestCompressionString.c_str()));
  94. if (clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes > 10485760) {
  95. AWS_LOGSTREAM_ERROR(CLIENT_CONFIG_TAG, "ClientConfiguration for MinReqCompression is unsupported, received: " << clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes);
  96. }
  97. }
  98. AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use MinReqCompression: " << clientConfig.requestCompressionConfig.requestMinCompressionSizeBytes);
  99. AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use SDK Auto Resolved profile: [" << clientConfig.profileName << "] if not specified by users.");
  100. // Automatically determine the AWS region from environment variables, configuration file and EC2 metadata.
  101. clientConfig.region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION");
  102. if (!clientConfig.region.empty())
  103. {
  104. return;
  105. }
  106. clientConfig.region = Aws::Environment::GetEnv("AWS_REGION");
  107. if (!clientConfig.region.empty())
  108. {
  109. return;
  110. }
  111. clientConfig.region = Aws::Config::GetCachedConfigValue("region");
  112. if (!clientConfig.region.empty())
  113. {
  114. return;
  115. }
  116. // Set the endpoint to interact with EC2 instance's metadata service
  117. Aws::String ec2MetadataServiceEndpoint = Aws::Environment::GetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT");
  118. if (! ec2MetadataServiceEndpoint.empty())
  119. {
  120. //By default we use the IPv4 default metadata service address
  121. auto client = Aws::Internal::GetEC2MetadataClient();
  122. if (client != nullptr)
  123. {
  124. client->SetEndpoint(ec2MetadataServiceEndpoint);
  125. }
  126. }
  127. }
  128. ClientConfiguration::ClientConfiguration()
  129. {
  130. this->disableIMDS = false;
  131. setLegacyClientConfigurationParameters(*this);
  132. retryStrategy = InitRetryStrategy();
  133. if (!this->disableIMDS &&
  134. region.empty() &&
  135. Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true")
  136. {
  137. auto client = Aws::Internal::GetEC2MetadataClient();
  138. if (client)
  139. {
  140. region = client->GetCurrentRegion();
  141. }
  142. }
  143. if (!region.empty())
  144. {
  145. return;
  146. }
  147. region = Aws::String(Aws::Region::US_EAST_1);
  148. }
  149. ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisableIMDS)
  150. {
  151. this->disableIMDS = shouldDisableIMDS;
  152. setLegacyClientConfigurationParameters(*this);
  153. // Call EC2 Instance Metadata service only once
  154. Aws::String ec2MetadataRegion;
  155. bool hasEc2MetadataRegion = false;
  156. if (!this->disableIMDS &&
  157. region.empty() &&
  158. Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") {
  159. auto client = Aws::Internal::GetEC2MetadataClient();
  160. if (client)
  161. {
  162. ec2MetadataRegion = client->GetCurrentRegion();
  163. hasEc2MetadataRegion = true;
  164. region = ec2MetadataRegion;
  165. }
  166. }
  167. if(region.empty())
  168. {
  169. region = Aws::String(Aws::Region::US_EAST_1);
  170. }
  171. if (profile && Aws::Config::HasCachedConfigProfile(profile)) {
  172. this->profileName = Aws::String(profile);
  173. AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG,
  174. "Use user specified profile: [" << this->profileName << "] for ClientConfiguration.");
  175. auto tmpRegion = Aws::Config::GetCachedConfigProfile(this->profileName).GetRegion();
  176. if (!tmpRegion.empty()) {
  177. region = tmpRegion;
  178. }
  179. Aws::String profileDefaultsMode = Aws::Config::GetCachedConfigProfile(this->profileName).GetDefaultsMode();
  180. Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, profileDefaultsMode,
  181. hasEc2MetadataRegion, ec2MetadataRegion);
  182. return;
  183. }
  184. if (!retryStrategy)
  185. {
  186. retryStrategy = InitRetryStrategy();
  187. }
  188. AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "User specified profile: [" << profile << "] is not found, will use the SDK resolved one.");
  189. }
  190. ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char* defaultMode, bool shouldDisableIMDS)
  191. {
  192. this->disableIMDS = shouldDisableIMDS;
  193. setLegacyClientConfigurationParameters(*this);
  194. // Call EC2 Instance Metadata service only once
  195. Aws::String ec2MetadataRegion;
  196. bool hasEc2MetadataRegion = false;
  197. if (!this->disableIMDS &&
  198. region.empty() &&
  199. Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true")
  200. {
  201. auto client = Aws::Internal::GetEC2MetadataClient();
  202. if (client)
  203. {
  204. ec2MetadataRegion = client->GetCurrentRegion();
  205. hasEc2MetadataRegion = true;
  206. region = ec2MetadataRegion;
  207. }
  208. }
  209. if (region.empty())
  210. {
  211. region = Aws::String(Aws::Region::US_EAST_1);
  212. }
  213. Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, defaultMode, hasEc2MetadataRegion, ec2MetadataRegion);
  214. }
  215. std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode)
  216. {
  217. int maxAttempts = 0;
  218. Aws::String maxAttemptsString = Aws::Environment::GetEnv("AWS_MAX_ATTEMPTS");
  219. if (maxAttemptsString.empty())
  220. {
  221. maxAttemptsString = Aws::Config::GetCachedConfigValue("max_attempts");
  222. }
  223. // In case users specify 0 explicitly to disable retry.
  224. if (maxAttemptsString == "0")
  225. {
  226. maxAttempts = 0;
  227. }
  228. else
  229. {
  230. maxAttempts = static_cast<int>(Aws::Utils::StringUtils::ConvertToInt32(maxAttemptsString.c_str()));
  231. if (maxAttempts == 0)
  232. {
  233. AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Retry Strategy will use the default max attempts.");
  234. maxAttempts = -1;
  235. }
  236. }
  237. if (retryMode.empty())
  238. {
  239. retryMode = Aws::Environment::GetEnv("AWS_RETRY_MODE");
  240. }
  241. if (retryMode.empty())
  242. {
  243. retryMode = Aws::Config::GetCachedConfigValue("retry_mode");
  244. }
  245. std::shared_ptr<RetryStrategy> retryStrategy;
  246. if (retryMode == "standard")
  247. {
  248. if (maxAttempts < 0)
  249. {
  250. // negative value set above force usage of default max attempts
  251. retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG);
  252. }
  253. else
  254. {
  255. retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
  256. }
  257. }
  258. else if (retryMode == "adaptive")
  259. {
  260. if (maxAttempts < 0)
  261. {
  262. // negative value set above force usage of default max attempts
  263. retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG);
  264. }
  265. else
  266. {
  267. retryStrategy = Aws::MakeShared<AdaptiveRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts);
  268. }
  269. }
  270. else
  271. {
  272. retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG);
  273. }
  274. return retryStrategy;
  275. }
  276. Aws::String ClientConfiguration::LoadConfigFromEnvOrProfile(const Aws::String& envKey,
  277. const Aws::String& profile,
  278. const Aws::String& profileProperty,
  279. const Aws::Vector<Aws::String>& allowedValues,
  280. const Aws::String& defaultValue)
  281. {
  282. Aws::String option = Aws::Environment::GetEnv(envKey.c_str());
  283. if (option.empty()) {
  284. option = Aws::Config::GetCachedConfigValue(profile, profileProperty);
  285. }
  286. option = Aws::Utils::StringUtils::ToLower(option.c_str());
  287. if (option.empty()) {
  288. return defaultValue;
  289. }
  290. if (!allowedValues.empty() && std::find(allowedValues.cbegin(), allowedValues.cend(), option) == allowedValues.cend()) {
  291. Aws::OStringStream expectedStr;
  292. expectedStr << "[";
  293. for(const auto& allowed : allowedValues) {
  294. expectedStr << allowed << ";";
  295. }
  296. expectedStr << "]";
  297. AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "Unrecognised value for " << envKey << ": " << option <<
  298. ". Using default instead: " << defaultValue <<
  299. ". Expected empty or one of: " << expectedStr.str());
  300. option = defaultValue;
  301. }
  302. return option;
  303. }
  304. } // namespace Client
  305. } // namespace Aws