diff options
author | dakovalkov <dakovalkov@yandex-team.com> | 2023-12-03 13:33:55 +0300 |
---|---|---|
committer | dakovalkov <dakovalkov@yandex-team.com> | 2023-12-03 14:04:39 +0300 |
commit | 2a718325637e5302334b6d0a6430f63168f8dbb3 (patch) | |
tree | 64be81080b7df9ec1d86d053a0c394ae53fcf1fe /contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source | |
parent | e0d94a470142d95c3007e9c5d80380994940664a (diff) | |
download | ydb-2a718325637e5302334b6d0a6430f63168f8dbb3.tar.gz |
Update contrib/libs/aws-sdk-cpp to 1.11.37
Diffstat (limited to 'contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source')
75 files changed, 7557 insertions, 2083 deletions
diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp index a6b0406683c..c0f89adad01 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/AmazonWebServiceRequest.cpp @@ -18,3 +18,17 @@ AmazonWebServiceRequest::AmazonWebServiceRequest() : { } +AmazonWebServiceRequest::EndpointParameters AmazonWebServiceRequest::GetEndpointContextParams() const +{ + return AmazonWebServiceRequest::EndpointParameters(); +} + +const Aws::Http::HeaderValueCollection& AmazonWebServiceRequest::GetAdditionalCustomHeaders() const +{ + return m_additionalCustomHeaders; +} + +void AmazonWebServiceRequest::SetAdditionalCustomHeaderValue(const Aws::String& headerName, const Aws::String& headerValue) +{ + m_additionalCustomHeaders[Utils::StringUtils::ToLower(headerName.c_str())] = Utils::StringUtils::Trim(headerValue.c_str()); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp index 0711fd69d66..4fd97618f30 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Aws.cpp @@ -7,6 +7,7 @@ #include <aws/core/Aws.h> #include <aws/core/client/CoreErrors.h> #include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/CRTLogging.h> #include <aws/core/utils/logging/DefaultLogSystem.h> #include <aws/core/Globals.h> #include <aws/core/external/cjson/cJSON.h> @@ -27,6 +28,7 @@ namespace Aws Aws::Utils::Memory::InitializeAWSMemorySystem(*options.memoryManagementOptions.memoryManager); } #endif // USE_AWS_MEMORY_MANAGEMENT + Aws::InitializeCrt(); Aws::Client::CoreErrorsMapper::InitCoreErrorsMapper(); if(options.loggingOptions.logLevel != Aws::Utils::Logging::LogLevel::Off) { @@ -39,12 +41,46 @@ namespace Aws Aws::Utils::Logging::InitializeAWSLogging( Aws::MakeShared<Aws::Utils::Logging::DefaultLogSystem>(ALLOCATION_TAG, options.loggingOptions.logLevel, options.loggingOptions.defaultLogPrefix)); } + if(options.loggingOptions.crt_logger_create_fn) + { + Aws::Utils::Logging::InitializeCRTLogging(options.loggingOptions.crt_logger_create_fn()); + } + else + { + Aws::Utils::Logging::InitializeCRTLogging( + Aws::MakeShared<Aws::Utils::Logging::DefaultCRTLogSystem>(ALLOCATION_TAG, options.loggingOptions.logLevel)); + } // For users to better debugging in case multiple versions of SDK installed AWS_LOGSTREAM_INFO(ALLOCATION_TAG, "Initiate AWS SDK for C++ with Version:" << Aws::String(Aws::Version::GetVersionString())); } Aws::Config::InitConfigAndCredentialsCacheManager(); + if (options.ioOptions.clientBootstrap_create_fn) + { + Aws::SetDefaultClientBootstrap(options.ioOptions.clientBootstrap_create_fn()); + } + else + { + Aws::Crt::Io::EventLoopGroup eventLoopGroup; + Aws::Crt::Io::DefaultHostResolver defaultHostResolver(eventLoopGroup, 8, 30); + auto clientBootstrap = Aws::MakeShared<Aws::Crt::Io::ClientBootstrap>(ALLOCATION_TAG, eventLoopGroup, defaultHostResolver); + clientBootstrap->EnableBlockingShutdown(); + Aws::SetDefaultClientBootstrap(clientBootstrap); + } + + if (options.ioOptions.tlsConnectionOptions_create_fn) + { + Aws::SetDefaultTlsConnectionOptions(options.ioOptions.tlsConnectionOptions_create_fn()); + } + else + { + Aws::Crt::Io::TlsContextOptions tlsCtxOptions = Aws::Crt::Io::TlsContextOptions::InitDefaultClient(); + Aws::Crt::Io::TlsContext tlsContext(tlsCtxOptions, Aws::Crt::Io::TlsMode::CLIENT); + auto tlsConnectionOptions = Aws::MakeShared<Aws::Crt::Io::TlsConnectionOptions>(ALLOCATION_TAG, tlsContext.NewConnectionOptions()); + Aws::SetDefaultTlsConnectionOptions(tlsConnectionOptions); + } + if (options.cryptoOptions.aes_CBCFactory_create_fn) { Aws::Utils::Crypto::SetAES_CBCFactory(options.cryptoOptions.aes_CBCFactory_create_fn()); @@ -100,6 +136,7 @@ namespace Aws Aws::Http::SetInitCleanupCurlFlag(options.httpOptions.initAndCleanupCurl); Aws::Http::SetInstallSigPipeHandlerFlag(options.httpOptions.installSigPipeHandler); + Aws::Http::SetCompliantRfc3986Encoding(options.httpOptions.compliantRfc3986Encoding); Aws::Http::InitHttp(); Aws::InitializeEnumOverflowContainer(); cJSON_AS4CPP_Hooks hooks; @@ -122,13 +159,13 @@ namespace Aws Aws::Config::CleanupConfigAndCredentialsCacheManager(); - if(options.loggingOptions.logLevel != Aws::Utils::Logging::LogLevel::Off) + Aws::Client::CoreErrorsMapper::CleanupCoreErrorsMapper(); + Aws::CleanupCrt(); + if (options.loggingOptions.logLevel != Aws::Utils::Logging::LogLevel::Off) { + Aws::Utils::Logging::ShutdownCRTLogging(); Aws::Utils::Logging::ShutdownAWSLogging(); } - - Aws::Client::CoreErrorsMapper::CleanupCoreErrorsMapper(); - #ifdef USE_AWS_MEMORY_MANAGEMENT if(options.memoryManagementOptions.memoryManager) { diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp index 55f2ee92203..8c26d2389dd 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Globals.cpp @@ -2,13 +2,61 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ + +#include <aws/crt/Api.h> +#include <aws/crt/io/TlsOptions.h> +#include <aws/crt/io/Bootstrap.h> #include <aws/core/Globals.h> #include <aws/core/utils/EnumParseOverflowContainer.h> #include <aws/core/utils/memory/AWSMemory.h> +#include <aws/auth/auth.h> namespace Aws { static const char TAG[] = "GlobalEnumOverflowContainer"; + + static Aws::Crt::ApiHandle* g_apiHandle; + static std::shared_ptr<Aws::Crt::Io::ClientBootstrap> g_defaultClientBootstrap(nullptr); + static std::shared_ptr<Aws::Crt::Io::TlsConnectionOptions> g_defaultTlsConnectionOptions(nullptr); + + Aws::Crt::ApiHandle* GetApiHandle() + { + return g_apiHandle; + } + + void SetDefaultClientBootstrap(const std::shared_ptr<Aws::Crt::Io::ClientBootstrap>& clientBootstrap) + { + g_defaultClientBootstrap = clientBootstrap; + } + + Aws::Crt::Io::ClientBootstrap* GetDefaultClientBootstrap() + { + return g_defaultClientBootstrap.get(); + } + + void SetDefaultTlsConnectionOptions(const std::shared_ptr<Aws::Crt::Io::TlsConnectionOptions>& tlsConnectionOptions) + { + g_defaultTlsConnectionOptions = tlsConnectionOptions; + } + + Aws::Crt::Io::TlsConnectionOptions* GetDefaultTlsConnectionOptions() + { + return g_defaultTlsConnectionOptions.get(); + } + + void InitializeCrt() + { + g_apiHandle = Aws::New<Aws::Crt::ApiHandle>(TAG, Aws::get_aws_allocator()); + } + + void CleanupCrt() + { + Aws::SetDefaultClientBootstrap(nullptr); + Aws::SetDefaultTlsConnectionOptions(nullptr); + Aws::Delete(g_apiHandle); + g_apiHandle = nullptr; + } + static Utils::EnumParseOverflowContainer* g_enumOverflow; Utils::EnumParseOverflowContainer* GetEnumOverflowContainer() diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp index 4b18bf2a2af..620923d6cdd 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/Region.cpp @@ -15,6 +15,10 @@ namespace Aws { return Aws::Region::US_EAST_1; } + else if (region == "fips-aws-global") + { + return Aws::Region::US_EAST_1; + } else if (region == "s3-external-1") { return Aws::Region::US_EAST_1; @@ -32,5 +36,18 @@ namespace Aws return region; } } + + bool IsFipsRegion(const Aws::String& region) + { + if (region.size() >= 5 && region.compare(0, 5, "fips-") == 0) + { + return true; + } + else if (region.size() >= 5 && region.compare(region.size() - 5, 5, "-fips") == 0) + { + return true; + } + return false; + } } }
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp deleted file mode 100644 index 0baa00058f9..00000000000 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSigner.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include <aws/core/auth/AWSAuthSigner.h> - -#include <aws/core/auth/AWSCredentialsProvider.h> -#include <aws/core/client/ClientConfiguration.h> -#include <aws/core/http/HttpRequest.h> -#include <aws/core/http/HttpResponse.h> -#include <aws/core/utils/DateTime.h> -#include <aws/core/utils/HashingUtils.h> -#include <aws/core/utils/Outcome.h> -#include <aws/core/utils/StringUtils.h> -#include <aws/core/utils/logging/LogMacros.h> -#include <aws/core/utils/memory/AWSMemory.h> -#include <aws/core/utils/crypto/Sha256.h> -#include <aws/core/utils/crypto/Sha256HMAC.h> -#include <aws/core/utils/stream/PreallocatedStreamBuf.h> -#include <aws/core/utils/event/EventMessage.h> -#include <aws/core/utils/event/EventHeader.h> - -#include <cstdio> -#include <iomanip> -#include <math.h> -#include <cstring> - -using namespace Aws; -using namespace Aws::Client; -using namespace Aws::Auth; -using namespace Aws::Http; -using namespace Aws::Utils; -using namespace Aws::Utils::Logging; - -static const char* EQ = "="; -static const char* AWS_HMAC_SHA256 = "AWS4-HMAC-SHA256"; -static const char* EVENT_STREAM_CONTENT_SHA256 = "STREAMING-AWS4-HMAC-SHA256-EVENTS"; -static const char* EVENT_STREAM_PAYLOAD = "AWS4-HMAC-SHA256-PAYLOAD"; -static const char* AWS4_REQUEST = "aws4_request"; -static const char* SIGNED_HEADERS = "SignedHeaders"; -static const char* CREDENTIAL = "Credential"; -static const char* NEWLINE = "\n"; -static const char* X_AMZ_SIGNED_HEADERS = "X-Amz-SignedHeaders"; -static const char* X_AMZ_ALGORITHM = "X-Amz-Algorithm"; -static const char* X_AMZ_CREDENTIAL = "X-Amz-Credential"; -static const char* UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD"; -static const char* X_AMZ_SIGNATURE = "X-Amz-Signature"; -static const char* X_AMZN_TRACE_ID = "x-amzn-trace-id"; -static const char* X_AMZ_CONTENT_SHA256 = "x-amz-content-sha256"; -static const char* USER_AGENT = "user-agent"; -static const char* SIGNING_KEY = "AWS4"; -static const char* SIMPLE_DATE_FORMAT_STR = "%Y%m%d"; -static const char* EMPTY_STRING_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - -static const char v4LogTag[] = "AWSAuthV4Signer"; -static const char v4StreamingLogTag[] = "AWSAuthEventStreamV4Signer"; - -namespace Aws -{ - namespace Auth - { - const char SIGNATURE[] = "Signature"; - const char SIGV4_SIGNER[] = "SignatureV4"; - const char EVENTSTREAM_SIGV4_SIGNER[] = "EventStreamSignatureV4"; - const char EVENTSTREAM_SIGNATURE_HEADER[] = ":chunk-signature"; - const char EVENTSTREAM_DATE_HEADER[] = ":date"; - const char NULL_SIGNER[] = "NullSigner"; - } -} - -static Aws::String CanonicalizeRequestSigningString(HttpRequest& request, bool urlEscapePath) -{ - request.CanonicalizeRequest(); - Aws::StringStream signingStringStream; - signingStringStream << HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()); - - URI uriCpy = request.GetUri(); - // Many AWS services do not decode the URL before calculating SignatureV4 on their end. - // This results in the signature getting calculated with a double encoded URL. - // That means we have to double encode it here for the signature to match on the service side. - if(urlEscapePath) - { - // RFC3986 is how we encode the URL before sending it on the wire. - auto rfc3986EncodedPath = URI::URLEncodePathRFC3986(uriCpy.GetPath()); - uriCpy.SetPath(rfc3986EncodedPath); - // However, SignatureV4 uses this URL encoding scheme - signingStringStream << NEWLINE << uriCpy.GetURLEncodedPath() << NEWLINE; - } - else - { - // For the services that DO decode the URL first; we don't need to double encode it. - uriCpy.SetPath(uriCpy.GetURLEncodedPath()); - signingStringStream << NEWLINE << uriCpy.GetPath() << NEWLINE; - } - - if (request.GetQueryString().find('=') != std::string::npos) - { - signingStringStream << request.GetQueryString().substr(1) << NEWLINE; - } - else if (request.GetQueryString().size() > 1) - { - signingStringStream << request.GetQueryString().substr(1) << "=" << NEWLINE; - } - else - { - signingStringStream << NEWLINE; - } - - return signingStringStream.str(); -} - -static Http::HeaderValueCollection CanonicalizeHeaders(Http::HeaderValueCollection&& headers) -{ - Http::HeaderValueCollection canonicalHeaders; - for (const auto& header : headers) - { - auto trimmedHeaderName = StringUtils::Trim(header.first.c_str()); - auto trimmedHeaderValue = StringUtils::Trim(header.second.c_str()); - - //multiline gets converted to line1,line2,etc... - auto headerMultiLine = StringUtils::SplitOnLine(trimmedHeaderValue); - Aws::String headerValue = headerMultiLine.size() == 0 ? "" : headerMultiLine[0]; - - if (headerMultiLine.size() > 1) - { - for(size_t i = 1; i < headerMultiLine.size(); ++i) - { - headerValue += ","; - headerValue += StringUtils::Trim(headerMultiLine[i].c_str()); - } - } - - //duplicate spaces need to be converted to one. - Aws::String::iterator new_end = - std::unique(headerValue.begin(), headerValue.end(), - [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } - ); - headerValue.erase(new_end, headerValue.end()); - - canonicalHeaders[trimmedHeaderName] = headerValue; - } - - return canonicalHeaders; -} - -AWSAuthV4Signer::AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider, - const char* serviceName, const Aws::String& region, PayloadSigningPolicy signingPolicy, bool urlEscapePath) : - m_includeSha256HashHeader(true), - m_credentialsProvider(credentialsProvider), - m_serviceName(serviceName), - m_region(region), - m_hash(Aws::MakeUnique<Aws::Utils::Crypto::Sha256>(v4LogTag)), - m_HMAC(Aws::MakeUnique<Aws::Utils::Crypto::Sha256HMAC>(v4LogTag)), - m_unsignedHeaders({USER_AGENT, X_AMZN_TRACE_ID}), - m_payloadSigningPolicy(signingPolicy), - m_urlEscapePath(urlEscapePath) -{ - //go ahead and warm up the signing cache. - ComputeHash(credentialsProvider->GetAWSCredentials().GetAWSSecretKey(), DateTime::CalculateGmtTimestampAsString(SIMPLE_DATE_FORMAT_STR), region, m_serviceName); -} - -AWSAuthV4Signer::~AWSAuthV4Signer() -{ - // empty destructor in .cpp file to keep from needing the implementation of (AWSCredentialsProvider, Sha256, Sha256HMAC) in the header file -} - - -bool AWSAuthV4Signer::ShouldSignHeader(const Aws::String& header) const -{ - return m_unsignedHeaders.find(Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); -} - -bool AWSAuthV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const -{ - AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); - - //don't sign anonymous requests - if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) - { - return true; - } - - if (!credentials.GetSessionToken().empty()) - { - request.SetAwsSessionToken(credentials.GetSessionToken()); - } - - Aws::String payloadHash(UNSIGNED_PAYLOAD); - switch(m_payloadSigningPolicy) - { - case PayloadSigningPolicy::Always: - signBody = true; - break; - case PayloadSigningPolicy::Never: - signBody = false; - break; - case PayloadSigningPolicy::RequestDependent: - // respect the request setting - default: - break; - } - - if(signBody || request.GetUri().GetScheme() != Http::Scheme::HTTPS) - { - payloadHash = ComputePayloadHash(request); - if (payloadHash.empty()) - { - return false; - } - } - else - { - AWS_LOGSTREAM_DEBUG(v4LogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody - << " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme())); - } - - if(m_includeSha256HashHeader) - { - request.SetHeaderValue(X_AMZ_CONTENT_SHA256, payloadHash); - } - - //calculate date header to use in internal signature (this also goes into date header). - DateTime now = GetSigningTimestamp(); - Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); - request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); - - Aws::StringStream headersStream; - Aws::StringStream signedHeadersStream; - - for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) - { - if(ShouldSignHeader(header.first)) - { - headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; - signedHeadersStream << header.first.c_str() << ";"; - } - } - - Aws::String canonicalHeadersString = headersStream.str(); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); - - //calculate signed headers parameter - Aws::String signedHeadersValue = signedHeadersStream.str(); - //remove that last semi-colon - if (!signedHeadersValue.empty()) - { - signedHeadersValue.pop_back(); - } - - AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value:" << signedHeadersValue); - - //generate generalized canonicalized request string. - Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, m_urlEscapePath); - - //append v4 stuff to the canonical request string. - canonicalRequestString.append(canonicalHeadersString); - canonicalRequestString.append(NEWLINE); - canonicalRequestString.append(signedHeadersValue); - canonicalRequestString.append(NEWLINE); - canonicalRequestString.append(payloadHash); - - AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); - - //now compute sha256 on that request string - auto hashResult = m_hash->Calculate(canonicalRequestString); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); - AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); - return false; - } - - auto sha256Digest = hashResult.GetResult(); - Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); - Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); - - Aws::String signingRegion = region ? region : m_region; - Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; - Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); - auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); - - Aws::StringStream ss; - ss << AWS_HMAC_SHA256 << " " << CREDENTIAL << EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate - << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST << ", " << SIGNED_HEADERS << EQ - << signedHeadersValue << ", " << SIGNATURE << EQ << finalSignature; - - auto awsAuthString = ss.str(); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Signing request with: " << awsAuthString); - request.SetAwsAuthorization(awsAuthString); - request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); - request.SetSigningRegion(signingRegion); - return true; -} - -bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, long long expirationTimeInSeconds) const -{ - return PresignRequest(request, m_region.c_str(), expirationTimeInSeconds); -} - -bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds) const -{ - return PresignRequest(request, region, m_serviceName.c_str(), expirationInSeconds); -} - -bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationTimeInSeconds) const -{ - AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); - - //don't sign anonymous requests - if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) - { - return true; - } - - Aws::StringStream intConversionStream; - intConversionStream << expirationTimeInSeconds; - request.AddQueryStringParameter(Http::X_AMZ_EXPIRES_HEADER, intConversionStream.str()); - - if (!credentials.GetSessionToken().empty()) - { - request.AddQueryStringParameter(Http::AWS_SECURITY_TOKEN, credentials.GetSessionToken()); - } - - //calculate date header to use in internal signature (this also goes into date header). - DateTime now = GetSigningTimestamp(); - Aws::String dateQueryValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); - request.AddQueryStringParameter(Http::AWS_DATE_HEADER, dateQueryValue); - - Aws::StringStream headersStream; - Aws::StringStream signedHeadersStream; - for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) - { - if(ShouldSignHeader(header.first)) - { - headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; - signedHeadersStream << header.first.c_str() << ";"; - } - } - - Aws::String canonicalHeadersString = headersStream.str(); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); - - //calculate signed headers parameter - Aws::String signedHeadersValue(signedHeadersStream.str()); - //remove that last semi-colon - if (!signedHeadersValue.empty()) - { - signedHeadersValue.pop_back(); - } - - request.AddQueryStringParameter(X_AMZ_SIGNED_HEADERS, signedHeadersValue); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value: " << signedHeadersValue); - - Aws::StringStream ss; - Aws::String signingRegion = region ? region : m_region; - Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; - Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); - ss << credentials.GetAWSAccessKeyId() << "/" << simpleDate - << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST; - - request.AddQueryStringParameter(X_AMZ_ALGORITHM, AWS_HMAC_SHA256); - request.AddQueryStringParameter(X_AMZ_CREDENTIAL, ss.str()); - ss.str(""); - - request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); - request.SetSigningRegion(signingRegion); - - //generate generalized canonicalized request string. - Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, m_urlEscapePath); - - //append v4 stuff to the canonical request string. - canonicalRequestString.append(canonicalHeadersString); - canonicalRequestString.append(NEWLINE); - canonicalRequestString.append(signedHeadersValue); - canonicalRequestString.append(NEWLINE); - if (ServiceRequireUnsignedPayload(signingServiceName)) - { - canonicalRequestString.append(UNSIGNED_PAYLOAD); - } - else - { - canonicalRequestString.append(EMPTY_STRING_SHA256); - } - AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); - - //now compute sha256 on that request string - auto hashResult = m_hash->Calculate(canonicalRequestString); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); - AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); - return false; - } - - auto sha256Digest = hashResult.GetResult(); - auto canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); - - auto stringToSign = GenerateStringToSign(dateQueryValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); - auto finalSigningHash = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); - if (finalSigningHash.empty()) - { - return false; - } - - //add that the signature to the query string - request.AddQueryStringParameter(X_AMZ_SIGNATURE, finalSigningHash); - - return true; -} - -bool AWSAuthV4Signer::ServiceRequireUnsignedPayload(const Aws::String& serviceName) const -{ - // S3 uses a magic string (instead of the empty string) for its body hash for presigned URLs as outlined here: - // https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html - // this is true for PUT, POST, GET, DELETE and HEAD operations. - // However, other services (for example RDS) implement the specification as outlined here: - // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html - // which states that body-less requests should use the empty-string SHA256 hash. - return "s3" == serviceName || "s3-object-lambda" == serviceName; -} - -Aws::String AWSAuthV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, - const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const -{ - auto key = ComputeHash(credentials.GetAWSSecretKey(), simpleDate, region, serviceName); - return GenerateSignature(stringToSign, key); -} - -Aws::String AWSAuthV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const -{ - AWS_LOGSTREAM_DEBUG(v4LogTag, "Final String to sign: " << stringToSign); - - Aws::StringStream ss; - - auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hmac (sha256) final string"); - AWS_LOGSTREAM_DEBUG(v4LogTag, "The final string is: \"" << stringToSign << "\""); - return {}; - } - - //now we finally sign our request string with our hex encoded derived hash. - auto finalSigningDigest = hashResult.GetResult(); - - auto finalSigningHash = HashingUtils::HexEncode(finalSigningDigest); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Final computed signing hash: " << finalSigningHash); - - return finalSigningHash; -} - -Aws::String AWSAuthV4Signer::ComputePayloadHash(Aws::Http::HttpRequest& request) const -{ - if (!request.GetContentBody()) - { - AWS_LOGSTREAM_DEBUG(v4LogTag, "Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty."); - return EMPTY_STRING_SHA256; - } - - //compute hash on payload if it exists. - auto hashResult = m_hash->Calculate(*request.GetContentBody()); - - if(request.GetContentBody()) - { - request.GetContentBody()->clear(); - request.GetContentBody()->seekg(0); - } - - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hash (sha256) request body"); - return {}; - } - - auto sha256Digest = hashResult.GetResult(); - - Aws::String payloadHash(HashingUtils::HexEncode(sha256Digest)); - AWS_LOGSTREAM_DEBUG(v4LogTag, "Calculated sha256 " << payloadHash << " for payload."); - return payloadHash; -} - -Aws::String AWSAuthV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, - const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const -{ - //generate the actual string we will use in signing the final request. - Aws::StringStream ss; - - ss << AWS_HMAC_SHA256 << NEWLINE << dateValue << NEWLINE << simpleDate << "/" << region << "/" - << serviceName << "/" << AWS4_REQUEST << NEWLINE << canonicalRequestHash; - - return ss.str(); -} - -Aws::Utils::ByteBuffer AWSAuthV4Signer::ComputeHash(const Aws::String& secretKey, - const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const -{ - Aws::String signingKey(SIGNING_KEY); - signingKey.append(secretKey); - auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), - ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); - - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); - return {}; - } - - auto kDate = hashResult.GetResult(); - hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); - return {}; - } - - auto kRegion = hashResult.GetResult(); - hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); - return {}; - } - - auto kService = hashResult.GetResult(); - hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)AWS4_REQUEST, strlen(AWS4_REQUEST)), kService); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to HMAC (SHA256) request string"); - AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << AWS4_REQUEST << "\""); - return {}; - } - return hashResult.GetResult(); -} - -AWSAuthEventStreamV4Signer::AWSAuthEventStreamV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& - credentialsProvider, const char* serviceName, const Aws::String& region) : - m_serviceName(serviceName), - m_region(region), - m_credentialsProvider(credentialsProvider) -{ - - m_unsignedHeaders.emplace_back(X_AMZN_TRACE_ID); - m_unsignedHeaders.emplace_back(USER_AGENT_HEADER); -} - -bool AWSAuthEventStreamV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool /* signBody */) const -{ - AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); - - //don't sign anonymous requests - if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) - { - return true; - } - - if (!credentials.GetSessionToken().empty()) - { - request.SetAwsSessionToken(credentials.GetSessionToken()); - } - - request.SetHeaderValue(X_AMZ_CONTENT_SHA256, EVENT_STREAM_CONTENT_SHA256); - - //calculate date header to use in internal signature (this also goes into date header). - DateTime now = GetSigningTimestamp(); - Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); - request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); - - Aws::StringStream headersStream; - Aws::StringStream signedHeadersStream; - - for (const auto& header : CanonicalizeHeaders(request.GetHeaders())) - { - if(ShouldSignHeader(header.first)) - { - headersStream << header.first.c_str() << ":" << header.second.c_str() << NEWLINE; - signedHeadersStream << header.first.c_str() << ";"; - } - } - - Aws::String canonicalHeadersString = headersStream.str(); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Header String: " << canonicalHeadersString); - - //calculate signed headers parameter - Aws::String signedHeadersValue = signedHeadersStream.str(); - //remove that last semi-colon - if (!signedHeadersValue.empty()) - { - signedHeadersValue.pop_back(); - } - - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signed Headers value:" << signedHeadersValue); - - //generate generalized canonicalized request string. - Aws::String canonicalRequestString = CanonicalizeRequestSigningString(request, true/* m_urlEscapePath */); - - //append v4 stuff to the canonical request string. - canonicalRequestString.append(canonicalHeadersString); - canonicalRequestString.append(NEWLINE); - canonicalRequestString.append(signedHeadersValue); - canonicalRequestString.append(NEWLINE); - canonicalRequestString.append(EVENT_STREAM_CONTENT_SHA256); - - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Request String: " << canonicalRequestString); - - //now compute sha256 on that request string - auto hashResult = m_hash.Calculate(canonicalRequestString); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) request string"); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << canonicalRequestString << "\""); - return false; - } - - auto sha256Digest = hashResult.GetResult(); - Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); - Aws::String simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); - - Aws::String signingRegion = region ? region : m_region; - Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; - Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); - auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); - - Aws::StringStream ss; - ss << AWS_HMAC_SHA256 << " " << CREDENTIAL << EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate - << "/" << signingRegion << "/" << signingServiceName << "/" << AWS4_REQUEST << ", " << SIGNED_HEADERS << EQ - << signedHeadersValue << ", " << SIGNATURE << EQ << HashingUtils::HexEncode(finalSignature); - - auto awsAuthString = ss.str(); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signing request with: " << awsAuthString); - request.SetAwsAuthorization(awsAuthString); - request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); - request.SetSigningRegion(signingRegion); - return true; -} - -// this works regardless if the current machine is Big/Little Endian -static void WriteBigEndian(Aws::String& str, uint64_t n) -{ - int shift = 56; - while(shift >= 0) - { - str.push_back((n >> shift) & 0xFF); - shift -= 8; - } -} - -bool AWSAuthEventStreamV4Signer::SignEventMessage(Event::Message& message, Aws::String& priorSignature) const -{ - using Event::EventHeaderValue; - - Aws::StringStream stringToSign; - stringToSign << EVENT_STREAM_PAYLOAD << NEWLINE; - const DateTime now = GetSigningTimestamp(); - const auto simpleDate = now.ToGmtString(SIMPLE_DATE_FORMAT_STR); - stringToSign << now.ToGmtString(DateFormat::ISO_8601_BASIC) << NEWLINE - << simpleDate << "/" << m_region << "/" - << m_serviceName << "/aws4_request" << NEWLINE << priorSignature << NEWLINE; - - - Aws::String nonSignatureHeaders; - nonSignatureHeaders.push_back(char(sizeof(EVENTSTREAM_DATE_HEADER) - 1)); // length of the string - nonSignatureHeaders += EVENTSTREAM_DATE_HEADER; - nonSignatureHeaders.push_back(static_cast<char>(EventHeaderValue::EventHeaderType::TIMESTAMP)); // type of the value - WriteBigEndian(nonSignatureHeaders, static_cast<uint64_t>(now.Millis())); // the value of the timestamp in big-endian - - auto hashOutcome = m_hash.Calculate(nonSignatureHeaders); - if (!hashOutcome.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); - return false; - } - - const auto nonSignatureHeadersHash = hashOutcome.GetResult(); - stringToSign << HashingUtils::HexEncode(nonSignatureHeadersHash) << NEWLINE; - - if (message.GetEventPayload().empty()) - { - AWS_LOGSTREAM_WARN(v4StreamingLogTag, "Attempting to sign an empty message (no payload and no headers). " - "It is unlikely that this is the intended behavior."); - } - else - { - // use a preallocatedStreamBuf to avoid making a copy. - // The Hashing API requires either Aws::String or IStream as input. - // TODO: the hashing API should be accept 'unsigned char*' as input. - Utils::Stream::PreallocatedStreamBuf streamBuf(message.GetEventPayload().data(), message.GetEventPayload().size()); - Aws::IOStream payload(&streamBuf); - hashOutcome = m_hash.Calculate(payload); - - if (!hashOutcome.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); - return false; - } - const auto payloadHash = hashOutcome.GetResult(); - stringToSign << HashingUtils::HexEncode(payloadHash); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Payload hash - " << HashingUtils::HexEncode(payloadHash)); - } - - Utils::ByteBuffer finalSignatureDigest = GenerateSignature(m_credentialsProvider->GetAWSCredentials(), stringToSign.str(), simpleDate, m_region, m_serviceName); - const auto finalSignature = HashingUtils::HexEncode(finalSignatureDigest); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final computed signing hash: " << finalSignature); - priorSignature = finalSignature; - - message.InsertEventHeader(EVENTSTREAM_DATE_HEADER, EventHeaderValue(now.Millis(), EventHeaderValue::EventHeaderType::TIMESTAMP)); - message.InsertEventHeader(EVENTSTREAM_SIGNATURE_HEADER, std::move(finalSignatureDigest)); - - AWS_LOGSTREAM_INFO(v4StreamingLogTag, "Event chunk final signature - " << finalSignature); - return true; -} - -bool AWSAuthEventStreamV4Signer::ShouldSignHeader(const Aws::String& header) const -{ - return std::find(m_unsignedHeaders.cbegin(), m_unsignedHeaders.cend(), Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); -} - -Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, - const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const -{ - Utils::Threading::ReaderLockGuard guard(m_derivedKeyLock); - const auto& secretKey = credentials.GetAWSSecretKey(); - if (secretKey != m_currentSecretKey || simpleDate != m_currentDateStr) - { - guard.UpgradeToWriterLock(); - // double-checked lock to prevent updating twice - if (m_currentDateStr != simpleDate || m_currentSecretKey != secretKey) - { - m_currentSecretKey = secretKey; - m_currentDateStr = simpleDate; - m_derivedKey = ComputeHash(m_currentSecretKey, m_currentDateStr, region, serviceName); - } - - } - return GenerateSignature(stringToSign, m_derivedKey); -} - -Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const -{ - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final String to sign: " << stringToSign); - - Aws::StringStream ss; - - auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to hmac (sha256) final string"); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The final string is: \"" << stringToSign << "\""); - return {}; - } - - return hashResult.GetResult(); -} - -Aws::String AWSAuthEventStreamV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, - const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const -{ - //generate the actual string we will use in signing the final request. - Aws::StringStream ss; - - ss << AWS_HMAC_SHA256 << NEWLINE << dateValue << NEWLINE << simpleDate << "/" << region << "/" - << serviceName << "/" << AWS4_REQUEST << NEWLINE << canonicalRequestHash; - - return ss.str(); -} - -Aws::Utils::ByteBuffer AWSAuthEventStreamV4Signer::ComputeHash(const Aws::String& secretKey, - const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const -{ - Aws::String signingKey(SIGNING_KEY); - signingKey.append(secretKey); - auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), - ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); - - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); - return {}; - } - - auto kDate = hashResult.GetResult(); - hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); - return {}; - } - - auto kRegion = hashResult.GetResult(); - hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); - return {}; - } - - auto kService = hashResult.GetResult(); - hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)AWS4_REQUEST, strlen(AWS4_REQUEST)), kService); - if (!hashResult.IsSuccess()) - { - AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to HMAC (SHA256) request string"); - AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << AWS4_REQUEST << "\""); - return {}; - } - return hashResult.GetResult(); -} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp index bf20ede35e1..084e4bca6e2 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp @@ -48,7 +48,7 @@ static const char DEFAULT_CREDENTIALS_FILE[] = "credentials"; extern const char DEFAULT_CONFIG_FILE[] = "config"; -static const int EXPIRATION_GRACE_PERIOD = 5 * 1000; +static const int AWS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD = 5 * 1000; void AWSCredentialsProvider::Reload() { @@ -183,9 +183,10 @@ AWSCredentials ProfileConfigFileAWSCredentialsProvider::GetAWSCredentials() { RefreshIfExpired(); ReaderLockGuard guard(m_reloadLock); - auto credsFileProfileIter = m_credentialsFileLoader.GetProfiles().find(m_profileToUse); + const Aws::Map<Aws::String, Aws::Config::Profile>& profiles = m_credentialsFileLoader.GetProfiles(); + auto credsFileProfileIter = profiles.find(m_profileToUse); - if(credsFileProfileIter != m_credentialsFileLoader.GetProfiles().end()) + if(credsFileProfileIter != profiles.end()) { return credsFileProfileIter->second.GetCredentials(); } @@ -239,37 +240,71 @@ AWSCredentials InstanceProfileCredentialsProvider::GetAWSCredentials() { RefreshIfExpired(); ReaderLockGuard guard(m_reloadLock); + if (m_ec2MetadataConfigLoader) + { + const Aws::Map<Aws::String, Aws::Config::Profile> &profiles = m_ec2MetadataConfigLoader->GetProfiles(); + auto profileIter = profiles.find(Aws::Config::INSTANCE_PROFILE_KEY); + + if (profileIter != profiles.end()) { + return profileIter->second.GetCredentials(); + } + } + else + { + AWS_LOGSTREAM_ERROR(INSTANCE_LOG_TAG, "EC2 Metadata config loader is a nullptr"); + } + + return AWSCredentials(); +} + +bool InstanceProfileCredentialsProvider::ExpiresSoon() const +{ + ReaderLockGuard guard(m_reloadLock); auto profileIter = m_ec2MetadataConfigLoader->GetProfiles().find(Aws::Config::INSTANCE_PROFILE_KEY); + AWSCredentials credentials; if(profileIter != m_ec2MetadataConfigLoader->GetProfiles().end()) { - return profileIter->second.GetCredentials(); + credentials = profileIter->second.GetCredentials(); } - return AWSCredentials(); + return ((credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < AWS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD); } void InstanceProfileCredentialsProvider::Reload() { - AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Credentials have expired attempting to repull from EC2 Metadata Service."); - m_ec2MetadataConfigLoader->Load(); - AWSCredentialsProvider::Reload(); + AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Credentials have expired attempting to re-pull from EC2 Metadata Service."); + if (m_ec2MetadataConfigLoader) { + m_ec2MetadataConfigLoader->Load(); + AWSCredentialsProvider::Reload(); + } else { + AWS_LOGSTREAM_ERROR(INSTANCE_LOG_TAG, "EC2 Metadata config loader is a nullptr"); + } } void InstanceProfileCredentialsProvider::RefreshIfExpired() { AWS_LOGSTREAM_DEBUG(INSTANCE_LOG_TAG, "Checking if latest credential pull has expired."); ReaderLockGuard guard(m_reloadLock); - if (!IsTimeToRefresh(m_loadFrequencyMs)) - { - return; - } + auto profileIter = m_ec2MetadataConfigLoader->GetProfiles().find(Aws::Config::INSTANCE_PROFILE_KEY); + AWSCredentials credentials; - guard.UpgradeToWriterLock(); - if (!IsTimeToRefresh(m_loadFrequencyMs)) // double-checked lock to avoid refreshing twice + if(profileIter != m_ec2MetadataConfigLoader->GetProfiles().end()) { - return; + credentials = profileIter->second.GetCredentials(); + + if (!credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) + { + return; + } + + guard.UpgradeToWriterLock(); + if (!credentials.IsEmpty() && !IsTimeToRefresh(m_loadFrequencyMs) && !ExpiresSoon()) // double-checked lock to avoid refreshing twice + { + return; + } } + Reload(); } @@ -306,12 +341,17 @@ AWSCredentials TaskRoleCredentialsProvider::GetAWSCredentials() bool TaskRoleCredentialsProvider::ExpiresSoon() const { - return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < EXPIRATION_GRACE_PERIOD); + return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < AWS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD); } void TaskRoleCredentialsProvider::Reload() { - AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Credentials have expired or will expire, attempting to repull from ECS IAM Service."); + AWS_LOGSTREAM_INFO(TASK_ROLE_LOG_TAG, "Credentials have expired or will expire, attempting to re-pull from ECS IAM Service."); + if (!m_ecsCredentialsClient) + { + AWS_LOGSTREAM_ERROR(INSTANCE_LOG_TAG, "ECS Credentials client is a nullptr"); + return; + } auto credentialsStr = m_ecsCredentialsClient->GetECSCredentials(); if (credentialsStr.empty()) return; diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp index 8b019a16642..403bd380c46 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp @@ -77,3 +77,9 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCr AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain."); } } + +DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain(const DefaultAWSCredentialsProviderChain& chain) { + for (const auto& provider: chain.GetProviders()) { + AddProvider(provider); + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/SSOCredentialsProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/SSOCredentialsProvider.cpp index e8f780762ea..9576e9d9999 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/SSOCredentialsProvider.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/SSOCredentialsProvider.cpp @@ -33,7 +33,8 @@ SSOCredentialsProvider::SSOCredentialsProvider() : m_profileToUse(GetConfigProfi AWS_LOGSTREAM_INFO(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Setting sso credentials provider to read config from " << m_profileToUse); } -SSOCredentialsProvider::SSOCredentialsProvider(const Aws::String& profile) : m_profileToUse(profile) +SSOCredentialsProvider::SSOCredentialsProvider(const Aws::String& profile) : m_profileToUse(profile), + m_bearerTokenProvider(profile) { AWS_LOGSTREAM_INFO(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Setting sso credentials provider to read config from " << m_profileToUse); } @@ -48,15 +49,24 @@ AWSCredentials SSOCredentialsProvider::GetAWSCredentials() void SSOCredentialsProvider::Reload() { auto profile = Aws::Config::GetCachedConfigProfile(m_profileToUse); - - Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoStartUrl())); - auto profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory(); - Aws::StringStream ssToken; - ssToken << profileDirectory; - ssToken << PATH_DELIM << "sso" << PATH_DELIM << "cache" << PATH_DELIM << hashedStartUrl << ".json"; - auto ssoTokenPath = ssToken.str(); - AWS_LOGSTREAM_DEBUG(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Loading token from: " << ssoTokenPath) - Aws::String accessToken = LoadAccessTokenFile(ssoTokenPath); + const auto accessToken = [&]() -> Aws::String { + // If we have an SSO Session set, use the refreshed token. + if (profile.IsSsoSessionSet()) { + m_ssoRegion = profile.GetSsoSession().GetSsoRegion(); + auto token = m_bearerTokenProvider.GetAWSBearerToken(); + m_expiresAt = token.GetExpiration(); + return token.GetToken(); + } + Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoStartUrl())); + auto profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory(); + Aws::StringStream ssToken; + ssToken << profileDirectory; + ssToken << PATH_DELIM << "sso" << PATH_DELIM << "cache" << PATH_DELIM << hashedStartUrl << ".json"; + auto ssoTokenPath = ssToken.str(); + AWS_LOGSTREAM_DEBUG(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Loading token from: " << ssoTokenPath) + m_ssoRegion = profile.GetSsoRegion(); + return LoadAccessTokenFile(ssoTokenPath); + }(); if (accessToken.empty()) { AWS_LOGSTREAM_TRACE(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Access token for SSO not available"); return; @@ -72,7 +82,7 @@ void SSOCredentialsProvider::Reload() Aws::Client::ClientConfiguration config; config.scheme = Aws::Http::Scheme::HTTPS; - config.region = profile.GetSsoRegion(); + config.region = m_ssoRegion; AWS_LOGSTREAM_DEBUG(SSO_CREDENTIALS_PROVIDER_LOG_TAG, "Passing config to client for region: " << m_ssoRegion); Aws::Vector<Aws::String> retryableErrors; diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp index 3f48c9e0c7d..b861e6132b1 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/STSCredentialsProvider.cpp @@ -30,6 +30,8 @@ using Aws::Utils::Threading::ReaderLockGuard; using Aws::Utils::Threading::WriterLockGuard; static const char STS_ASSUME_ROLE_WEB_IDENTITY_LOG_TAG[] = "STSAssumeRoleWithWebIdentityCredentialsProvider"; +static const int STS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD = 5 * 1000; + STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider() : m_initialized(false) { @@ -145,16 +147,21 @@ void STSAssumeRoleWebIdentityCredentialsProvider::Reload() m_credentials = result.creds; } +bool STSAssumeRoleWebIdentityCredentialsProvider::ExpiresSoon() const +{ + return ((m_credentials.GetExpiration() - Aws::Utils::DateTime::Now()).count() < STS_CREDENTIAL_PROVIDER_EXPIRATION_GRACE_PERIOD); +} + void STSAssumeRoleWebIdentityCredentialsProvider::RefreshIfExpired() { ReaderLockGuard guard(m_reloadLock); - if (!m_credentials.IsExpiredOrEmpty()) + if (!m_credentials.IsEmpty() && !ExpiresSoon()) { return; } guard.UpgradeToWriterLock(); - if (!m_credentials.IsExpiredOrEmpty()) // double-checked lock to avoid refreshing twice + if (!m_credentials.IsExpiredOrEmpty() && !ExpiresSoon()) // double-checked lock to avoid refreshing twice { return; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/DefaultBearerTokenProviderChain.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/DefaultBearerTokenProviderChain.cpp new file mode 100644 index 00000000000..16b301cd678 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/DefaultBearerTokenProviderChain.cpp @@ -0,0 +1,35 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/bearer-token-provider/DefaultBearerTokenProviderChain.h> +#include <aws/core/auth/AWSBearerToken.h> +#include <aws/core/auth/bearer-token-provider/SSOBearerTokenProvider.h> +#include <aws/core/utils/logging/LogMacros.h> + + +static const char SSO_DEFAULT_BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG[] = "SSOBearerTokenProvider"; + +Aws::Auth::AWSBearerToken Aws::Auth::DefaultBearerTokenProviderChain::GetAWSBearerToken() +{ + for (auto&& bearerTokenProvider : m_providerChain) + { + if(!bearerTokenProvider) { + AWS_LOGSTREAM_FATAL(SSO_DEFAULT_BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG, + "Unexpected nullptr in DefaultBearerTokenProviderChain::m_providerChain"); + break; + } + AWSBearerToken bearerToken = bearerTokenProvider->GetAWSBearerToken(); + if(!bearerToken.IsExpiredOrEmpty()) + { + return bearerToken; + } + } + return AWSBearerToken("", Aws::Utils::DateTime(0.0)); +} + +Aws::Auth::DefaultBearerTokenProviderChain::DefaultBearerTokenProviderChain() +{ + AddProvider(Aws::MakeShared<Aws::Auth::SSOBearerTokenProvider>(SSO_DEFAULT_BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG)); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/SSOBearerTokenProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/SSOBearerTokenProvider.cpp new file mode 100644 index 00000000000..b55131e340d --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/bearer-token-provider/SSOBearerTokenProvider.cpp @@ -0,0 +1,244 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/auth/bearer-token-provider/SSOBearerTokenProvider.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/platform/FileSystem.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/FileSystemUtils.h> +#include <aws/core/client/SpecifiedRetryableErrorsRetryStrategy.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/json/JsonSerializer.h> + +using namespace Aws::Auth; + +using Aws::Utils::Threading::ReaderLockGuard; + + +static const char SSO_BEARER_TOKEN_PROVIDER_LOG_TAG[] = "SSOBearerTokenProvider"; +static const char SSO_GRANT_TYPE[] = "refresh_token"; + +const size_t SSOBearerTokenProvider::REFRESH_WINDOW_BEFORE_EXPIRATION_S = 600; +const size_t SSOBearerTokenProvider::REFRESH_ATTEMPT_INTERVAL_S = 30; + +SSOBearerTokenProvider::SSOBearerTokenProvider() + : m_profileToUse(Aws::Auth::GetConfigProfileName()), + m_lastUpdateAttempt((int64_t) 0) +{ + AWS_LOGSTREAM_INFO(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Setting sso bearerToken provider to read config from " << m_profileToUse); +} + +SSOBearerTokenProvider::SSOBearerTokenProvider(const Aws::String& awsProfile) + : m_profileToUse(awsProfile), + m_lastUpdateAttempt((int64_t) 0) +{ + AWS_LOGSTREAM_INFO(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Setting sso bearerToken provider to read config from " << m_profileToUse); +} + +AWSBearerToken SSOBearerTokenProvider::GetAWSBearerToken() +{ + Aws::Utils::Threading::ReaderLockGuard guard(m_reloadLock); + if(m_token.IsEmpty()) + { + Reload(); + } + if(!m_token.IsEmpty()) + { + const Aws::Utils::DateTime now = Aws::Utils::DateTime::Now(); + if (now >= m_token.GetExpiration() - std::chrono::seconds(REFRESH_WINDOW_BEFORE_EXPIRATION_S) && + m_lastUpdateAttempt + std::chrono::seconds(REFRESH_ATTEMPT_INTERVAL_S) < now) + { + guard.UpgradeToWriterLock(); + RefreshFromSso(); + } + } + + if(m_token.IsExpiredOrEmpty()) + { + /* If a loaded token has expired and has insufficient metadata to perform a refresh the SSO token + provider must raise an exception that the token has expired and cannot be refreshed. + Error logging and returning an empty object instead because of disabled exceptions and poor legacy API design. */ + AWS_LOGSTREAM_ERROR(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "SSOBearerTokenProvider is unable to provide a token"); + return Aws::Auth::AWSBearerToken("", Aws::Utils::DateTime(0.0)); + } + return m_token; +} + +void SSOBearerTokenProvider::Reload() +{ + CachedSsoToken cachedSsoToken = LoadAccessTokenFile(); + if(cachedSsoToken.accessToken.empty()) { + AWS_LOGSTREAM_TRACE(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Access token for SSO not available"); + return; + } + const Aws::Utils::DateTime now = Aws::Utils::DateTime::Now(); + if(cachedSsoToken.expiresAt < now) { + AWS_LOGSTREAM_ERROR(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Cached Token is already expired at " << cachedSsoToken.expiresAt.ToGmtString(Aws::Utils::DateFormat::ISO_8601)); + return; + } + + m_token.SetToken(cachedSsoToken.accessToken); + m_token.SetExpiration(cachedSsoToken.expiresAt); +} + +void SSOBearerTokenProvider::RefreshFromSso() +{ + CachedSsoToken cachedSsoToken = LoadAccessTokenFile(); + + if(!m_client) + { + Aws::Client::ClientConfiguration config; + config.scheme = Aws::Http::Scheme::HTTPS; + /* The SSO token provider must not resolve if any SSO configuration values are present directly on the profile + * instead of an `sso-session` section. The SSO token provider must ignore these configuration values if these + * values are present directly on the profile instead of an `sso-session` section. */ + // config.region = m_profile.GetSsoRegion(); // <- intentionally not used per comment above + config.region = cachedSsoToken.region; + m_client = Aws::MakeUnique<Aws::Internal::SSOCredentialsClient>(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, config); + } + + Aws::Internal::SSOCredentialsClient::SSOCreateTokenRequest ssoCreateTokenRequest; + ssoCreateTokenRequest.clientId = cachedSsoToken.clientId; + ssoCreateTokenRequest.clientSecret = cachedSsoToken.clientSecret; + ssoCreateTokenRequest.grantType = SSO_GRANT_TYPE; + ssoCreateTokenRequest.refreshToken = cachedSsoToken.refreshToken; + + if(!m_client) { + AWS_LOGSTREAM_FATAL(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Unexpected nullptr in SSOBearerTokenProvider::m_client"); + return; + } + Aws::Internal::SSOCredentialsClient::SSOCreateTokenResult result = m_client->CreateToken(ssoCreateTokenRequest); + if(!result.accessToken.empty()) + { + cachedSsoToken.accessToken = result.accessToken; + cachedSsoToken.expiresAt = Aws::Utils::DateTime::Now() + std::chrono::seconds(result.expiresIn); + if(!result.refreshToken.empty()) { + cachedSsoToken.refreshToken = result.refreshToken; + } + if(!result.clientId.empty()) { + cachedSsoToken.clientId = result.clientId; + } + } + + if(WriteAccessTokenFile(cachedSsoToken)) + { + m_token.SetToken(cachedSsoToken.accessToken); + m_token.SetExpiration(cachedSsoToken.expiresAt); + } + +} + +SSOBearerTokenProvider::CachedSsoToken SSOBearerTokenProvider::LoadAccessTokenFile() const +{ + SSOBearerTokenProvider::CachedSsoToken retValue; + + const Aws::Config::Profile& profile = Aws::Config::GetCachedConfigProfile(m_profileToUse); + if(!profile.IsSsoSessionSet()) { + AWS_LOGSTREAM_ERROR(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "SSOBearerTokenProvider set to use a profile " << m_profileToUse << " without a sso_session. Unable to load cached token."); + return retValue; + } + + Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoSession().GetName())); + Aws::String profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory(); + Aws::StringStream ssToken; + ssToken << profileDirectory; + ssToken << Aws::FileSystem::PATH_DELIM << "sso" << Aws::FileSystem::PATH_DELIM << "cache" << Aws::FileSystem::PATH_DELIM << hashedStartUrl << ".json"; + auto ssoAccessTokenPath = ssToken.str(); + AWS_LOGSTREAM_DEBUG(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Preparing to load token from: " << ssoAccessTokenPath); + + Aws::IFStream inputFile(ssoAccessTokenPath.c_str()); + if(inputFile) + { + AWS_LOGSTREAM_DEBUG(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Reading content from token file: " << ssoAccessTokenPath); + + Aws::Utils::Json::JsonValue tokenDoc(inputFile); + if (!tokenDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Failed to parse token file: " << ssoAccessTokenPath); + return retValue; + } + Utils::Json::JsonView tokenView(tokenDoc); + + retValue.accessToken = tokenView.GetString("accessToken"); + retValue.expiresAt = Aws::Utils::DateTime(tokenView.GetString("expiresAt"), Aws::Utils::DateFormat::ISO_8601); + retValue.refreshToken = tokenView.GetString("refreshToken"); + retValue.clientId = tokenView.GetString("clientId"); + retValue.clientSecret = tokenView.GetString("clientSecret"); + retValue.registrationExpiresAt = Aws::Utils::DateTime(tokenView.GetString("registrationExpiresAt"), Aws::Utils::DateFormat::ISO_8601); + retValue.region = tokenView.GetString("region"); + retValue.startUrl = tokenView.GetString("startUrl"); + + return retValue; + } + else + { + AWS_LOGSTREAM_INFO(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Unable to open token file on path: " << ssoAccessTokenPath); + return retValue; + } +} + +bool SSOBearerTokenProvider::WriteAccessTokenFile(const CachedSsoToken& token) const +{ + const Aws::Config::Profile& profile = Aws::Config::GetCachedConfigProfile(m_profileToUse); + if(!profile.IsSsoSessionSet()) { + AWS_LOGSTREAM_ERROR(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "SSOBearerTokenProvider set to use a profile " + << m_profileToUse << " without a sso_session. Unable to write a cached token."); + return false; + } + + Aws::String hashedStartUrl = Aws::Utils::HashingUtils::HexEncode(Aws::Utils::HashingUtils::CalculateSHA1(profile.GetSsoSession().GetName())); + Aws::String profileDirectory = ProfileConfigFileAWSCredentialsProvider::GetProfileDirectory(); + Aws::StringStream ssToken; + ssToken << profileDirectory; + ssToken << Aws::FileSystem::PATH_DELIM << "sso" << Aws::FileSystem::PATH_DELIM << "cache" << Aws::FileSystem::PATH_DELIM << hashedStartUrl << ".json"; + auto ssoAccessTokenPath = ssToken.str(); + AWS_LOGSTREAM_DEBUG(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Preparing to write token to: " << ssoAccessTokenPath); + + Aws::OFStream outputFileStream(ssoAccessTokenPath.c_str(), std::ios_base::out | std::ios_base::trunc); + if(outputFileStream && outputFileStream.good()) + { + AWS_LOGSTREAM_DEBUG(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Writing content to token file: " << ssoAccessTokenPath); + + Aws::Utils::Json::JsonValue cachedTokenDoc; + if(!token.accessToken.empty()) { + cachedTokenDoc.WithString("accessToken", token.accessToken); + } + if(token.expiresAt != 0.0) { + cachedTokenDoc.WithString("expiresAt", token.expiresAt.ToGmtString(Aws::Utils::DateFormat::ISO_8601)); + } + if(!token.refreshToken.empty()) { + cachedTokenDoc.WithString("refreshToken", token.refreshToken); + } + if(!token.clientId.empty()) { + cachedTokenDoc.WithString("clientId", token.clientId); + } + if(!token.clientSecret.empty()) { + cachedTokenDoc.WithString("clientSecret", token.clientSecret); + } + if(token.registrationExpiresAt != 0.0) { + cachedTokenDoc.WithString("registrationExpiresAt", token.registrationExpiresAt.ToGmtString(Aws::Utils::DateFormat::ISO_8601)); + } + if(!token.region.empty()) { + cachedTokenDoc.WithString("region", token.region); + } + if(!token.startUrl.empty()) { + cachedTokenDoc.WithString("startUrl", token.startUrl); + } + + const Aws::String& resultingJsonStr = cachedTokenDoc.View().WriteReadable();; + outputFileStream << resultingJsonStr; + + return outputFileStream.good(); + } + else + { + AWS_LOGSTREAM_INFO(SSO_BEARER_TOKEN_PROVIDER_LOG_TAG, "Unable to open token file on path for writing: " << ssoAccessTokenPath); + return false; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer-provider/BearerTokenAuthSignerProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer-provider/BearerTokenAuthSignerProvider.cpp new file mode 100644 index 00000000000..9bb9c5edae7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer-provider/BearerTokenAuthSignerProvider.cpp @@ -0,0 +1,46 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer-provider/BearerTokenAuthSignerProvider.h> + +#include <aws/core/auth/signer/AWSNullSigner.h> + +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +const char BEARER_TOKEN_AUTH_SIGNER_PROVIDER_ALLOC_TAG[] = "BearerTokenAuthSignerProvider"; + +using namespace Aws::Auth; + +BearerTokenAuthSignerProvider::BearerTokenAuthSignerProvider(const std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase> bearerTokenProvider) +{ + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthBearerSigner>(BEARER_TOKEN_AUTH_SIGNER_PROVIDER_ALLOC_TAG, bearerTokenProvider)); + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSNullSigner>(BEARER_TOKEN_AUTH_SIGNER_PROVIDER_ALLOC_TAG)); +} + +std::shared_ptr<Aws::Client::AWSAuthSigner> BearerTokenAuthSignerProvider::GetSigner(const Aws::String& signerName) const +{ + for(const auto& signer : m_signers) + { + if(!signer) { + AWS_LOGSTREAM_FATAL(BEARER_TOKEN_AUTH_SIGNER_PROVIDER_ALLOC_TAG, "Unexpected nullptr in BearerTokenAuthSignerProvider::m_signers"); + break; + } + if(signer->GetName() == signerName) + { + return signer; + } + } + AWS_LOGSTREAM_ERROR(BEARER_TOKEN_AUTH_SIGNER_PROVIDER_ALLOC_TAG, "Request's signer: '" << signerName << "' is not found in the signer's map."); + assert(false); + return nullptr; +} + +void BearerTokenAuthSignerProvider::AddSigner(std::shared_ptr<Aws::Client::AWSAuthSigner>& signer) +{ + assert(signer); + m_signers.emplace_back(signer); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSignerProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer-provider/DefaultAuthSignerProvider.cpp index 31fd6c006ba..fb7e0cfa406 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/AWSAuthSignerProvider.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer-provider/DefaultAuthSignerProvider.cpp @@ -2,10 +2,14 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ + +#include <aws/core/auth/signer-provider/DefaultAuthSignerProvider.h> + +#include <aws/core/auth/signer/AWSAuthEventStreamV4Signer.h> +#include <aws/core/auth/signer/AWSNullSigner.h> + #include <aws/core/utils/logging/LogMacros.h> -#include <aws/core/auth/AWSAuthSignerProvider.h> -#include <aws/core/auth/AWSAuthSigner.h> #include <aws/core/auth/AWSCredentialsProvider.h> #include <aws/core/utils/memory/stl/AWSAllocator.h> @@ -14,9 +18,10 @@ const char CLASS_TAG[] = "AuthSignerProvider"; using namespace Aws::Auth; DefaultAuthSignerProvider::DefaultAuthSignerProvider(const std::shared_ptr<AWSCredentialsProvider>& credentialsProvider, - const Aws::String& serviceName, const Aws::String& region) + const Aws::String& serviceName, const Aws::String& region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy signingPolicy, bool urlEscapePath) { - m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region)); + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region, signingPolicy, urlEscapePath, AWSSigningAlgorithm::SIGV4)); + m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region, signingPolicy, urlEscapePath, AWSSigningAlgorithm::ASYMMETRIC_SIGV4)); m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSAuthEventStreamV4Signer>(CLASS_TAG, credentialsProvider, serviceName.c_str(), region)); m_signers.emplace_back(Aws::MakeShared<Aws::Client::AWSNullSigner>(CLASS_TAG)); } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthBearerSigner.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthBearerSigner.cpp new file mode 100644 index 00000000000..ff14c8a3712 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthBearerSigner.cpp @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSAuthBearerSigner.h> +#include <aws/core/auth/bearer-token-provider/AWSBearerTokenProviderBase.h> + +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/http/HttpRequest.h> + +namespace Aws +{ + namespace Auth + { + const char BEARER_SIGNER[] = "Bearer"; + } + + namespace Client + { + static const char LOGGING_TAG[] = "AWSAuthBearerSigner"; + static const char AUTHORIZATION_HEADER[] = "authorization"; + + bool AWSAuthBearerSigner::SignRequest(Aws::Http::HttpRequest& ioRequest) const + { + if(Aws::Http::Scheme::HTTPS != ioRequest.GetUri().GetScheme()) + { + // Clients MUST always use TLS (https) or equivalent transport security + // when making requests with bearer tokens. + // https://datatracker.ietf.org/doc/html/rfc6750 + AWS_LOGSTREAM_ERROR(LOGGING_TAG, "HTTPS scheme must be used with a bearer token authorization"); + return false; + } + if(!m_bearerTokenProvider) + { + AWS_LOGSTREAM_FATAL(LOGGING_TAG, "Unexpected nullptr AWSAuthBearerSigner::m_bearerTokenProvider"); + return false; + } + const Aws::Auth::AWSBearerToken& token = m_bearerTokenProvider->GetAWSBearerToken(); + if(token.IsExpiredOrEmpty()) + { + AWS_LOGSTREAM_ERROR(LOGGING_TAG, "Invalid bearer token to use: expired or empty"); + return false; + } + + ioRequest.SetHeaderValue(AUTHORIZATION_HEADER, "Bearer " + token.GetToken()); + return true; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthEventStreamV4Signer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthEventStreamV4Signer.cpp new file mode 100644 index 00000000000..195e83a751a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthEventStreamV4Signer.cpp @@ -0,0 +1,320 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSAuthEventStreamV4Signer.h> +#include <aws/core/auth/signer/AWSAuthSignerCommon.h> +#include <aws/core/auth/signer/AWSAuthSignerHelper.h> + +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/crypto/Sha256HMAC.h> +#include <aws/core/utils/stream/PreallocatedStreamBuf.h> +#include <aws/core/utils/event/EventMessage.h> +#include <aws/core/utils/event/EventHeader.h> + +#include <aws/crt/auth/Credentials.h> +#include <aws/crt/http/HttpRequestResponse.h> + +#include <iomanip> +#include <cstring> + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Auth; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static const char* EVENT_STREAM_CONTENT_SHA256 = "STREAMING-AWS4-HMAC-SHA256-EVENTS"; +static const char* EVENT_STREAM_PAYLOAD = "AWS4-HMAC-SHA256-PAYLOAD"; +static const char* v4StreamingLogTag = "AWSAuthEventStreamV4Signer"; + +namespace Aws +{ + namespace Auth + { + const char EVENTSTREAM_SIGV4_SIGNER[] = "EventStreamSignatureV4"; + const char EVENTSTREAM_SIGNATURE_HEADER[] = ":chunk-signature"; + const char EVENTSTREAM_DATE_HEADER[] = ":date"; + } +} + +AWSAuthEventStreamV4Signer::AWSAuthEventStreamV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& + credentialsProvider, const char* serviceName, const Aws::String& region) : + m_serviceName(serviceName), + m_region(region), + m_credentialsProvider(credentialsProvider) +{ + + m_unsignedHeaders.emplace_back(Aws::Auth::AWSAuthHelper::X_AMZN_TRACE_ID); + m_unsignedHeaders.emplace_back(USER_AGENT_HEADER); +} + +bool AWSAuthEventStreamV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool /* signBody */) const +{ + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + if (!credentials.GetSessionToken().empty()) + { + request.SetAwsSessionToken(credentials.GetSessionToken()); + } + + request.SetHeaderValue(Aws::Auth::AWSAuthHelper::X_AMZ_CONTENT_SHA256, EVENT_STREAM_CONTENT_SHA256); + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + + for (const auto& header : Aws::Auth::AWSAuthHelper::CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << Aws::Auth::AWSAuthHelper::NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue = signedHeadersStream.str(); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signed Headers value:" << signedHeadersValue); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = Aws::Auth::AWSAuthHelper::CanonicalizeRequestSigningString(request, true/* m_urlEscapePath */); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + canonicalRequestString.append(EVENT_STREAM_CONTENT_SHA256); + + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash.Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + Aws::String simpleDate = now.ToGmtString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR); + + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + + Aws::StringStream ss; + ss << Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256 << " " << Aws::Auth::AWSAuthHelper::CREDENTIAL << Aws::Auth::AWSAuthHelper::EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << ", " << Aws::Auth::AWSAuthHelper::SIGNED_HEADERS << Aws::Auth::AWSAuthHelper::EQ + << signedHeadersValue << ", " << SIGNATURE << Aws::Auth::AWSAuthHelper::EQ << HashingUtils::HexEncode(finalSignature); + + auto awsAuthString = ss.str(); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Signing request with: " << awsAuthString); + request.SetAwsAuthorization(awsAuthString); + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + return true; +} + +// this works regardless if the current machine is Big/Little Endian +static void WriteBigEndian(Aws::String& str, uint64_t n) +{ + int shift = 56; + while(shift >= 0) + { + str.push_back((n >> shift) & 0xFF); + shift -= 8; + } +} + +bool AWSAuthEventStreamV4Signer::SignEventMessage(Event::Message& message, Aws::String& priorSignature) const +{ + using Event::EventHeaderValue; + + Aws::StringStream stringToSign; + stringToSign << EVENT_STREAM_PAYLOAD << Aws::Auth::AWSAuthHelper::NEWLINE; + const DateTime now = GetSigningTimestamp(); + const auto simpleDate = now.ToGmtString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR); + stringToSign << now.ToGmtString(DateFormat::ISO_8601_BASIC) << Aws::Auth::AWSAuthHelper::NEWLINE + << simpleDate << "/" << m_region << "/" + << m_serviceName << "/aws4_request" << Aws::Auth::AWSAuthHelper::NEWLINE << priorSignature << Aws::Auth::AWSAuthHelper::NEWLINE; + + + Aws::String nonSignatureHeaders; + nonSignatureHeaders.push_back(char(sizeof(EVENTSTREAM_DATE_HEADER) - 1)); // length of the string + nonSignatureHeaders += EVENTSTREAM_DATE_HEADER; + nonSignatureHeaders.push_back(static_cast<char>(EventHeaderValue::EventHeaderType::TIMESTAMP)); // type of the value + WriteBigEndian(nonSignatureHeaders, static_cast<uint64_t>(now.Millis())); // the value of the timestamp in big-endian + + auto hashOutcome = m_hash.Calculate(nonSignatureHeaders); + if (!hashOutcome.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); + return false; + } + + const auto nonSignatureHeadersHash = hashOutcome.GetResult(); + stringToSign << HashingUtils::HexEncode(nonSignatureHeadersHash) << Aws::Auth::AWSAuthHelper::NEWLINE; + + if (message.GetEventPayload().empty()) + { + AWS_LOGSTREAM_WARN(v4StreamingLogTag, "Attempting to sign an empty message (no payload and no headers). " + "It is unlikely that this is the intended behavior."); + } + else + { + // use a preallocatedStreamBuf to avoid making a copy. + // The Hashing API requires either Aws::String or IStream as input. + // TODO: the hashing API should be accept 'unsigned char*' as input. + Utils::Stream::PreallocatedStreamBuf streamBuf(message.GetEventPayload().data(), message.GetEventPayload().size()); + Aws::IOStream payload(&streamBuf); + hashOutcome = m_hash.Calculate(payload); + + if (!hashOutcome.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to hash (sha256) non-signature headers."); + return false; + } + const auto payloadHash = hashOutcome.GetResult(); + stringToSign << HashingUtils::HexEncode(payloadHash); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Payload hash - " << HashingUtils::HexEncode(payloadHash)); + } + + Aws::Utils::ByteBuffer finalSignatureDigest = GenerateSignature(m_credentialsProvider->GetAWSCredentials(), stringToSign.str(), simpleDate, m_region, m_serviceName); + const auto finalSignature = HashingUtils::HexEncode(finalSignatureDigest); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final computed signing hash: " << finalSignature); + priorSignature = finalSignature; + + message.InsertEventHeader(EVENTSTREAM_DATE_HEADER, EventHeaderValue(now.Millis(), EventHeaderValue::EventHeaderType::TIMESTAMP)); + message.InsertEventHeader(EVENTSTREAM_SIGNATURE_HEADER, std::move(finalSignatureDigest)); + + AWS_LOGSTREAM_INFO(v4StreamingLogTag, "Event chunk final signature - " << finalSignature); + return true; +} + +bool AWSAuthEventStreamV4Signer::ShouldSignHeader(const Aws::String& header) const +{ + return std::find(m_unsignedHeaders.cbegin(), m_unsignedHeaders.cend(), Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); +} + +Aws::Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Utils::Threading::ReaderLockGuard guard(m_derivedKeyLock); + const auto& secretKey = credentials.GetAWSSecretKey(); + if (secretKey != m_currentSecretKey || simpleDate != m_currentDateStr) + { + guard.UpgradeToWriterLock(); + // double-checked lock to prevent updating twice + if (m_currentDateStr != simpleDate || m_currentSecretKey != secretKey) + { + m_currentSecretKey = secretKey; + m_currentDateStr = simpleDate; + m_derivedKey = ComputeHash(m_currentSecretKey, m_currentDateStr, region, serviceName); + } + + } + return GenerateSignature(stringToSign, m_derivedKey); +} + +Aws::Utils::ByteBuffer AWSAuthEventStreamV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const +{ + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "Final String to sign: " << stringToSign); + + Aws::StringStream ss; + + auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to hmac (sha256) final string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The final string is: \"" << stringToSign << "\""); + return {}; + } + + return hashResult.GetResult(); +} + +Aws::String AWSAuthEventStreamV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const +{ + //generate the actual string we will use in signing the final request. + Aws::StringStream ss; + + ss << Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256 << Aws::Auth::AWSAuthHelper::NEWLINE << dateValue << Aws::Auth::AWSAuthHelper::NEWLINE << simpleDate << "/" << region << "/" + << serviceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << Aws::Auth::AWSAuthHelper::NEWLINE << canonicalRequestHash; + + return ss.str(); +} + +Aws::Utils::ByteBuffer AWSAuthEventStreamV4Signer::ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Aws::String signingKey(Aws::Auth::AWSAuthHelper::SIGNING_KEY); + signingKey.append(secretKey); + auto hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), + ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); + return {}; + } + + auto kDate = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); + return {}; + } + + auto kRegion = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); + return {}; + } + + auto kService = hashResult.GetResult(); + hashResult = m_HMAC.Calculate(ByteBuffer((unsigned char*)Aws::Auth::AWSAuthHelper::AWS4_REQUEST, strlen(Aws::Auth::AWSAuthHelper::AWS4_REQUEST)), kService); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4StreamingLogTag, "Unable to HMAC (SHA256) request string"); + AWS_LOGSTREAM_DEBUG(v4StreamingLogTag, "The request string is: \"" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << "\""); + return {}; + } + return hashResult.GetResult(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerCommon.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerCommon.cpp new file mode 100644 index 00000000000..d26f41e6b30 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerCommon.cpp @@ -0,0 +1,14 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSAuthSignerCommon.h> + +namespace Aws +{ +namespace Auth +{ +const char SIGNATURE[] = "Signature"; +} // namespace Auth +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerHelper.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerHelper.cpp new file mode 100644 index 00000000000..5f7005d1da2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthSignerHelper.cpp @@ -0,0 +1,103 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSAuthSignerHelper.h> +#include <aws/core/http/HttpTypes.h> + +#include <aws/core/http/HttpRequest.h> +#include <aws/core/http/URI.h> +#include <aws/core/utils/StringUtils.h> + +namespace Aws +{ +namespace Auth +{ + +const char* AWSAuthHelper::EQ = "="; +const char* AWSAuthHelper::AWS_HMAC_SHA256 = "AWS4-HMAC-SHA256"; +const char* AWSAuthHelper::AWS4_REQUEST = "aws4_request"; +const char* AWSAuthHelper::SIGNED_HEADERS = "SignedHeaders"; +const char* AWSAuthHelper::CREDENTIAL = "Credential"; +const char* AWSAuthHelper::NEWLINE = "\n"; +const char* AWSAuthHelper::X_AMZN_TRACE_ID = "x-amzn-trace-id"; +const char* AWSAuthHelper::X_AMZ_CONTENT_SHA256 = "x-amz-content-sha256"; +const char* AWSAuthHelper::SIGNING_KEY = "AWS4"; +const char* AWSAuthHelper::SIMPLE_DATE_FORMAT_STR = "%Y%m%d"; + +Aws::String Aws::Auth::AWSAuthHelper::CanonicalizeRequestSigningString(Aws::Http::HttpRequest& request, bool urlEscapePath) +{ + request.CanonicalizeRequest(); + Aws::StringStream signingStringStream; + signingStringStream << Aws::Http::HttpMethodMapper::GetNameForHttpMethod(request.GetMethod()); + + Aws::Http::URI uriCpy = request.GetUri(); + // Many AWS services do not decode the URL before calculating SignatureV4 on their end. + // This results in the signature getting calculated with a double encoded URL. + // That means we have to double encode it here for the signature to match on the service side. + if(urlEscapePath) + { + // RFC3986 is how we encode the URL before sending it on the wire. + uriCpy.SetPath(uriCpy.GetURLEncodedPathRFC3986()); + // However, SignatureV4 uses this URL encoding scheme + signingStringStream << AWSAuthHelper::NEWLINE << uriCpy.GetURLEncodedPath() << AWSAuthHelper::NEWLINE; + } + else + { + // For the services that DO decode the URL first; we don't need to double encode it. + signingStringStream << AWSAuthHelper::NEWLINE << uriCpy.GetURLEncodedPath() << AWSAuthHelper::NEWLINE; + } + + if (request.GetQueryString().find('=') != std::string::npos) + { + signingStringStream << request.GetQueryString().substr(1) << AWSAuthHelper::NEWLINE; + } + else if (request.GetQueryString().size() > 1) + { + signingStringStream << request.GetQueryString().substr(1) << "=" << AWSAuthHelper::NEWLINE; + } + else + { + signingStringStream << AWSAuthHelper::NEWLINE; + } + + return signingStringStream.str(); +} + +Aws::Http::HeaderValueCollection Aws::Auth::AWSAuthHelper::CanonicalizeHeaders(Aws::Http::HeaderValueCollection&& headers) +{ + Aws::Http::HeaderValueCollection canonicalHeaders; + for (const auto& header : headers) + { + auto trimmedHeaderName = Aws::Utils::StringUtils::Trim(header.first.c_str()); + auto trimmedHeaderValue = Aws::Utils::StringUtils::Trim(header.second.c_str()); + + //multiline gets converted to line1,line2,etc... + auto headerMultiLine = Aws::Utils::StringUtils::SplitOnLine(trimmedHeaderValue); + Aws::String headerValue = headerMultiLine.size() == 0 ? "" : headerMultiLine[0]; + + if (headerMultiLine.size() > 1) + { + for(size_t i = 1; i < headerMultiLine.size(); ++i) + { + headerValue += " "; + headerValue += Aws::Utils::StringUtils::Trim(headerMultiLine[i].c_str()); + } + } + + //duplicate spaces need to be converted to one. + Aws::String::iterator new_end = + std::unique(headerValue.begin(), headerValue.end(), + [=](char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); } + ); + headerValue.erase(new_end, headerValue.end()); + + canonicalHeaders[trimmedHeaderName] = headerValue; + } + + return canonicalHeaders; +} + +} // namespace Auth +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp new file mode 100644 index 00000000000..f8bfdbf8671 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp @@ -0,0 +1,580 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSAuthV4Signer.h> +#include <aws/core/auth/signer/AWSAuthSignerCommon.h> +#include <aws/core/auth/signer/AWSAuthSignerHelper.h> + +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/http/HttpRequest.h> +#include <aws/core/http/URI.h> +#include <aws/core/utils/DateTime.h> +#include <aws/core/utils/HashingUtils.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/crypto/Sha256HMAC.h> + +#include <aws/crt/auth/Credentials.h> +#include <aws/crt/http/HttpRequestResponse.h> + +#include <iomanip> +#include <cstring> + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Auth; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +static const char* X_AMZ_SIGNED_HEADERS = "X-Amz-SignedHeaders"; +static const char* X_AMZ_ALGORITHM = "X-Amz-Algorithm"; +static const char* X_AMZ_CREDENTIAL = "X-Amz-Credential"; +static const char* UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD"; +static const char* STREAMING_UNSIGNED_PAYLOAD_TRAILER = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"; +static const char* X_AMZ_SIGNATURE = "X-Amz-Signature"; +static const char* USER_AGENT = "user-agent"; +static const char* EMPTY_STRING_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + +static const char v4LogTag[] = "AWSAuthV4Signer"; +static const char v4AsymmetricLogTag[] = "AWSAuthSymmetricV4Signer"; + +namespace Aws +{ + namespace Auth + { + const char SIGV4_SIGNER[] = "SignatureV4"; + const char ASYMMETRIC_SIGV4_SIGNER[] = "AsymmetricSignatureV4"; + } +} + +AWSAuthV4Signer::AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider, const char* serviceName, + const Aws::String& region, PayloadSigningPolicy signingPolicy, bool urlEscapePath, AWSSigningAlgorithm signingAlgorithm) : + m_includeSha256HashHeader(true), + m_signingAlgorithm(signingAlgorithm), + m_credentialsProvider(credentialsProvider), + m_serviceName(serviceName), + m_region(region), + m_hash(Aws::MakeUnique<Aws::Utils::Crypto::Sha256>(v4LogTag)), + m_HMAC(Aws::MakeUnique<Aws::Utils::Crypto::Sha256HMAC>(v4LogTag)), + m_unsignedHeaders({USER_AGENT, Aws::Auth::AWSAuthHelper::X_AMZN_TRACE_ID}), + m_payloadSigningPolicy(signingPolicy), + m_urlEscapePath(urlEscapePath) +{ + //go ahead and warm up the signing cache. + ComputeHash(credentialsProvider->GetAWSCredentials().GetAWSSecretKey(), DateTime::CalculateGmtTimestampAsString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR), region, m_serviceName); +} + +AWSAuthV4Signer::~AWSAuthV4Signer() +{ + // empty destructor in .cpp file to keep from needing the implementation of (AWSCredentialsProvider, Sha256, Sha256HMAC) in the header file +} + +bool AWSAuthV4Signer::SignRequestWithSigV4a(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, + bool signBody, long long expirationTimeInSeconds, Aws::Crt::Auth::SignatureType signatureType) const +{ + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + auto crtCredentials = Aws::MakeShared<Aws::Crt::Auth::Credentials>(v4AsymmetricLogTag, + Aws::Crt::ByteCursorFromCString(credentials.GetAWSAccessKeyId().c_str()), + Aws::Crt::ByteCursorFromCString(credentials.GetAWSSecretKey().c_str()), + Aws::Crt::ByteCursorFromCString(credentials.GetSessionToken().c_str()), + credentials.GetExpiration().Seconds()); + + Aws::Crt::Auth::AwsSigningConfig awsSigningConfig; + awsSigningConfig.SetSigningAlgorithm(static_cast<Aws::Crt::Auth::SigningAlgorithm>(AWSSigningAlgorithm::ASYMMETRIC_SIGV4)); + awsSigningConfig.SetSignatureType(signatureType); + awsSigningConfig.SetRegion(region); + awsSigningConfig.SetService(serviceName); + awsSigningConfig.SetSigningTimepoint(GetSigningTimestamp().UnderlyingTimestamp()); + awsSigningConfig.SetUseDoubleUriEncode(m_urlEscapePath); + awsSigningConfig.SetShouldNormalizeUriPath(true); + awsSigningConfig.SetOmitSessionToken(false); + awsSigningConfig.SetShouldSignHeaderUserData(reinterpret_cast<void*>(const_cast<Aws::Set<Aws::String>*>(&m_unsignedHeaders))); + awsSigningConfig.SetShouldSignHeaderCallback([](const Aws::Crt::ByteCursor *name, void *user_data) { + Aws::Set<Aws::String>* unsignedHeaders = static_cast<Aws::Set<Aws::String>*>(user_data); + Aws::String headerKey(reinterpret_cast<const char*>(name->ptr), name->len); + return unsignedHeaders->find(Aws::Utils::StringUtils::ToLower(headerKey.c_str())) == unsignedHeaders->cend(); + }); + if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) + { + Aws::String payloadHash(UNSIGNED_PAYLOAD); + if(signBody || request.GetUri().GetScheme() != Http::Scheme::HTTPS) + { + if (!request.GetContentBody()) + { + AWS_LOGSTREAM_DEBUG(v4AsymmetricLogTag, "Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty."); + payloadHash = EMPTY_STRING_SHA256; + } + else + { + // The hash will be calculated from the payload during signing. + payloadHash = {}; + } + } + else + { + AWS_LOGSTREAM_DEBUG(v4AsymmetricLogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody + << " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme())); + } + awsSigningConfig.SetSignedBodyValue(payloadHash.c_str()); + awsSigningConfig.SetSignedBodyHeader(m_includeSha256HashHeader ? Aws::Crt::Auth::SignedBodyHeaderType::XAmzContentSha256 : Aws::Crt::Auth::SignedBodyHeaderType::None); + } + else if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams) + { + if (ServiceRequireUnsignedPayload(serviceName)) + { + awsSigningConfig.SetSignedBodyValue(UNSIGNED_PAYLOAD); + } + else + { + awsSigningConfig.SetSignedBodyValue(EMPTY_STRING_SHA256); + } + } + else + { + AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, "The signature type should be either \"HttpRequestViaHeaders\" or \"HttpRequestViaQueryParams\""); + return false; + } + awsSigningConfig.SetExpirationInSeconds(static_cast<uint64_t>(expirationTimeInSeconds)); + awsSigningConfig.SetCredentials(crtCredentials); + + std::shared_ptr<Aws::Crt::Http::HttpRequest> crtHttpRequest = request.ToCrtHttpRequest(); + + auto sigv4HttpRequestSigner = Aws::MakeShared<Aws::Crt::Auth::Sigv4HttpRequestSigner>(v4AsymmetricLogTag); + bool success = true; + sigv4HttpRequestSigner->SignRequest(crtHttpRequest, awsSigningConfig, + [&request, &success, signatureType](const std::shared_ptr<Aws::Crt::Http::HttpRequest>& signedCrtHttpRequest, int errorCode) { + success = (errorCode == AWS_ERROR_SUCCESS); + if (success) + { + if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) + { + for (size_t i = 0; i < signedCrtHttpRequest->GetHeaderCount(); i++) + { + Aws::Crt::Optional<Aws::Crt::Http::HttpHeader> httpHeader = signedCrtHttpRequest->GetHeader(i); + request.SetHeaderValue(Aws::String(reinterpret_cast<const char*>(httpHeader->name.ptr), httpHeader->name.len), + Aws::String(reinterpret_cast<const char*>(httpHeader->value.ptr), httpHeader->value.len)); + } + } + else if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams) + { + Aws::Http::URI newPath(reinterpret_cast<const char*>(signedCrtHttpRequest->GetPath()->ptr)); + request.GetUri().SetQueryString(newPath.GetQueryString()); + } + else + { + AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, "No action to take when signature type is neither \"HttpRequestViaHeaders\" nor \"HttpRequestViaQueryParams\""); + success = false; + } + } + else + { + AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, "Encountered internal error during signing process with AWS signature version 4 (Asymmetric):" << aws_error_str(errorCode)); + } + } + ); + return success; +} + +bool AWSAuthV4Signer::ShouldSignHeader(const Aws::String& header) const +{ + return m_unsignedHeaders.find(Aws::Utils::StringUtils::ToLower(header.c_str())) == m_unsignedHeaders.cend(); +} + +bool AWSAuthV4Signer::SignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, bool signBody) const +{ + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + + Aws::String payloadHash(UNSIGNED_PAYLOAD); + switch(m_payloadSigningPolicy) + { + case PayloadSigningPolicy::Always: + signBody = true; + break; + case PayloadSigningPolicy::Never: + signBody = false; + break; + case PayloadSigningPolicy::RequestDependent: + // respect the request setting + default: + break; + } + + if (m_signingAlgorithm == AWSSigningAlgorithm::ASYMMETRIC_SIGV4) + { + // Replace m_serviceName with signingServiceName after rebasing on S3 outposts. + return SignRequestWithSigV4a(request, signingRegion.c_str(), m_serviceName.c_str(), signBody, + 0 /* expirationTimeInSeconds doesn't matter for HttpRequestViaHeaders */, Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders); + } + + if (!credentials.GetSessionToken().empty()) + { + request.SetAwsSessionToken(credentials.GetSessionToken()); + } + + if(signBody || request.GetUri().GetScheme() != Http::Scheme::HTTPS) + { + payloadHash = ComputePayloadHash(request); + if (payloadHash.empty()) + { + return false; + } + if (request.GetRequestHash().second != nullptr) + { + Aws::String checksumHeaderKey = Aws::String("x-amz-checksum-") + request.GetRequestHash().first; + Aws::String checksumHeaderValue = HashingUtils::Base64Encode(request.GetRequestHash().second->Calculate(*(request.GetContentBody())).GetResult()); + request.SetHeaderValue(checksumHeaderKey, checksumHeaderValue); + request.SetRequestHash("", nullptr); + } + } + else + { + AWS_LOGSTREAM_DEBUG(v4LogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody + << " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme())); + if (request.GetRequestHash().second != nullptr) + { + payloadHash = STREAMING_UNSIGNED_PAYLOAD_TRAILER; + Aws::String trailerHeaderValue = Aws::String("x-amz-checksum-") + request.GetRequestHash().first; + request.SetHeaderValue(Http::AWS_TRAILER_HEADER, trailerHeaderValue); + request.SetTransferEncoding(CHUNKED_VALUE); + request.SetHeaderValue(Http::CONTENT_ENCODING_HEADER, Http::AWS_CHUNKED_VALUE); + request.SetHeaderValue(Http::DECODED_CONTENT_LENGTH_HEADER, request.GetHeaderValue(Http::CONTENT_LENGTH_HEADER)); + request.DeleteHeader(Http::CONTENT_LENGTH_HEADER); + } + } + + if(m_includeSha256HashHeader) + { + request.SetHeaderValue(Aws::Auth::AWSAuthHelper::X_AMZ_CONTENT_SHA256, payloadHash); + } + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateHeaderValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.SetHeaderValue(AWS_DATE_HEADER, dateHeaderValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + + for (const auto& header : Aws::Auth::AWSAuthHelper::CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << Aws::Auth::AWSAuthHelper::NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue = signedHeadersStream.str(); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value:" << signedHeadersValue); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = Aws::Auth::AWSAuthHelper::CanonicalizeRequestSigningString(request, m_urlEscapePath); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + canonicalRequestString.append(payloadHash); + + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash->Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + Aws::String canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + Aws::String simpleDate = now.ToGmtString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR); + + Aws::String stringToSign = GenerateStringToSign(dateHeaderValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSignature = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + + Aws::StringStream ss; + ss << Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256 << " " << Aws::Auth::AWSAuthHelper::CREDENTIAL << Aws::Auth::AWSAuthHelper::EQ << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << ", " << Aws::Auth::AWSAuthHelper::SIGNED_HEADERS << Aws::Auth::AWSAuthHelper::EQ + << signedHeadersValue << ", " << SIGNATURE << Aws::Auth::AWSAuthHelper::EQ << finalSignature; + + auto awsAuthString = ss.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signing request with: " << awsAuthString); + request.SetAwsAuthorization(awsAuthString); + return true; +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, long long expirationTimeInSeconds) const +{ + return PresignRequest(request, m_region.c_str(), expirationTimeInSeconds); +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds) const +{ + return PresignRequest(request, region, m_serviceName.c_str(), expirationInSeconds); +} + +bool AWSAuthV4Signer::PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationTimeInSeconds) const +{ + Aws::String signingRegion = region ? region : m_region; + Aws::String signingServiceName = serviceName ? serviceName : m_serviceName; + AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials(); + + //don't sign anonymous requests + if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty()) + { + return true; + } + + if (m_signingAlgorithm == AWSSigningAlgorithm::ASYMMETRIC_SIGV4) + { + return SignRequestWithSigV4a(request, signingRegion.c_str(), signingServiceName.c_str(), false /* signBody doesn't matter for HttpRequestViaHeaders */, + expirationTimeInSeconds, Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams); + } + + Aws::StringStream intConversionStream; + intConversionStream << expirationTimeInSeconds; + request.AddQueryStringParameter(Http::X_AMZ_EXPIRES_HEADER, intConversionStream.str()); + + if (!credentials.GetSessionToken().empty()) + { + request.AddQueryStringParameter(Http::AWS_SECURITY_TOKEN, credentials.GetSessionToken()); + } + + //calculate date header to use in internal signature (this also goes into date header). + DateTime now = GetSigningTimestamp(); + Aws::String dateQueryValue = now.ToGmtString(DateFormat::ISO_8601_BASIC); + request.AddQueryStringParameter(Http::AWS_DATE_HEADER, dateQueryValue); + + Aws::StringStream headersStream; + Aws::StringStream signedHeadersStream; + for (const auto& header : Aws::Auth::AWSAuthHelper::CanonicalizeHeaders(request.GetHeaders())) + { + if(ShouldSignHeader(header.first)) + { + headersStream << header.first.c_str() << ":" << header.second.c_str() << Aws::Auth::AWSAuthHelper::NEWLINE; + signedHeadersStream << header.first.c_str() << ";"; + } + } + + Aws::String canonicalHeadersString = headersStream.str(); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Header String: " << canonicalHeadersString); + + //calculate signed headers parameter + Aws::String signedHeadersValue(signedHeadersStream.str()); + //remove that last semi-colon + if (!signedHeadersValue.empty()) + { + signedHeadersValue.pop_back(); + } + + request.AddQueryStringParameter(X_AMZ_SIGNED_HEADERS, signedHeadersValue); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed Headers value: " << signedHeadersValue); + + Aws::StringStream ss; + Aws::String simpleDate = now.ToGmtString(Aws::Auth::AWSAuthHelper::SIMPLE_DATE_FORMAT_STR); + ss << credentials.GetAWSAccessKeyId() << "/" << simpleDate + << "/" << signingRegion << "/" << signingServiceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST; + + request.AddQueryStringParameter(X_AMZ_ALGORITHM, Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256); + request.AddQueryStringParameter(X_AMZ_CREDENTIAL, ss.str()); + ss.str(""); + + request.SetSigningAccessKey(credentials.GetAWSAccessKeyId()); + request.SetSigningRegion(signingRegion); + + //generate generalized canonicalized request string. + Aws::String canonicalRequestString = Aws::Auth::AWSAuthHelper::CanonicalizeRequestSigningString(request, m_urlEscapePath); + + //append v4 stuff to the canonical request string. + canonicalRequestString.append(canonicalHeadersString); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + canonicalRequestString.append(signedHeadersValue); + canonicalRequestString.append(Aws::Auth::AWSAuthHelper::NEWLINE); + if (ServiceRequireUnsignedPayload(signingServiceName)) + { + canonicalRequestString.append(UNSIGNED_PAYLOAD); + } + else + { + canonicalRequestString.append(EMPTY_STRING_SHA256); + } + AWS_LOGSTREAM_DEBUG(v4LogTag, "Canonical Request String: " << canonicalRequestString); + + //now compute sha256 on that request string + auto hashResult = m_hash->Calculate(canonicalRequestString); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to hash (sha256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << canonicalRequestString << "\""); + return false; + } + + auto sha256Digest = hashResult.GetResult(); + auto canonicalRequestHash = HashingUtils::HexEncode(sha256Digest); + + auto stringToSign = GenerateStringToSign(dateQueryValue, simpleDate, canonicalRequestHash, signingRegion, signingServiceName); + auto finalSigningHash = GenerateSignature(credentials, stringToSign, simpleDate, signingRegion, signingServiceName); + if (finalSigningHash.empty()) + { + return false; + } + + //add that the signature to the query string + request.AddQueryStringParameter(X_AMZ_SIGNATURE, finalSigningHash); + + return true; +} + +bool AWSAuthV4Signer::ServiceRequireUnsignedPayload(const Aws::String& serviceName) const +{ + // S3 uses a magic string (instead of the empty string) for its body hash for presigned URLs as outlined here: + // https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html + // this is true for PUT, POST, GET, DELETE and HEAD operations. + // However, other services (for example RDS) implement the specification as outlined here: + // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html + // which states that body-less requests should use the empty-string SHA256 hash. + return "s3" == serviceName || "s3-object-lambda" == serviceName; +} + +Aws::String AWSAuthV4Signer::GenerateSignature(const AWSCredentials& credentials, const Aws::String& stringToSign, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + auto key = ComputeHash(credentials.GetAWSSecretKey(), simpleDate, region, serviceName); + return GenerateSignature(stringToSign, key); +} + +Aws::String AWSAuthV4Signer::GenerateSignature(const Aws::String& stringToSign, const ByteBuffer& key) const +{ + AWS_LOGSTREAM_DEBUG(v4LogTag, "Final String to sign: " << stringToSign); + + Aws::StringStream ss; + + auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)stringToSign.c_str(), stringToSign.length()), key); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hmac (sha256) final string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The final string is: \"" << stringToSign << "\""); + return {}; + } + + //now we finally sign our request string with our hex encoded derived hash. + auto finalSigningDigest = hashResult.GetResult(); + + auto finalSigningHash = HashingUtils::HexEncode(finalSigningDigest); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Final computed signing hash: " << finalSigningHash); + + return finalSigningHash; +} + +Aws::String AWSAuthV4Signer::ComputePayloadHash(Aws::Http::HttpRequest& request) const +{ + if (!request.GetContentBody()) + { + AWS_LOGSTREAM_DEBUG(v4LogTag, "Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty."); + return EMPTY_STRING_SHA256; + } + + //compute hash on payload if it exists. + auto hashResult = m_hash->Calculate(*request.GetContentBody()); + + if(request.GetContentBody()) + { + request.GetContentBody()->clear(); + request.GetContentBody()->seekg(0); + } + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to hash (sha256) request body"); + return {}; + } + + auto sha256Digest = hashResult.GetResult(); + + Aws::String payloadHash(HashingUtils::HexEncode(sha256Digest)); + AWS_LOGSTREAM_DEBUG(v4LogTag, "Calculated sha256 " << payloadHash << " for payload."); + return payloadHash; +} + +Aws::String AWSAuthV4Signer::GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate, + const Aws::String& canonicalRequestHash, const Aws::String& region, const Aws::String& serviceName) const +{ + //generate the actual string we will use in signing the final request. + Aws::StringStream ss; + + ss << Aws::Auth::AWSAuthHelper::AWS_HMAC_SHA256 << Aws::Auth::AWSAuthHelper::NEWLINE << dateValue << Aws::Auth::AWSAuthHelper::NEWLINE << simpleDate << "/" << region << "/" + << serviceName << "/" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << Aws::Auth::AWSAuthHelper::NEWLINE << canonicalRequestHash; + + return ss.str(); +} + +Aws::Utils::ByteBuffer AWSAuthV4Signer::ComputeHash(const Aws::String& secretKey, + const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const +{ + Aws::String signingKey(Aws::Auth::AWSAuthHelper::SIGNING_KEY); + signingKey.append(secretKey); + auto hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)simpleDate.c_str(), simpleDate.length()), + ByteBuffer((unsigned char*)signingKey.c_str(), signingKey.length())); + + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) date string \"" << simpleDate << "\""); + return {}; + } + + auto kDate = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)region.c_str(), region.length()), kDate); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) region string \"" << region << "\""); + return {}; + } + + auto kRegion = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)serviceName.c_str(), serviceName.length()), kRegion); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Failed to HMAC (SHA256) service string \"" << m_serviceName << "\""); + return {}; + } + + auto kService = hashResult.GetResult(); + hashResult = m_HMAC->Calculate(ByteBuffer((unsigned char*)Aws::Auth::AWSAuthHelper::AWS4_REQUEST, strlen(Aws::Auth::AWSAuthHelper::AWS4_REQUEST)), kService); + if (!hashResult.IsSuccess()) + { + AWS_LOGSTREAM_ERROR(v4LogTag, "Unable to HMAC (SHA256) request string"); + AWS_LOGSTREAM_DEBUG(v4LogTag, "The request string is: \"" << Aws::Auth::AWSAuthHelper::AWS4_REQUEST << "\""); + return {}; + } + return hashResult.GetResult(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSNullSigner.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSNullSigner.cpp new file mode 100644 index 00000000000..d94cb421f2b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/auth/signer/AWSNullSigner.cpp @@ -0,0 +1,14 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/auth/signer/AWSNullSigner.h> + +namespace Aws +{ + namespace Auth + { + const char NULL_SIGNER[] = "NullSigner"; + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp index 4b2a38b4e68..d1a6f262c9d 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSClient.cpp @@ -7,11 +7,13 @@ #include <aws/core/AmazonWebServiceRequest.h> #include <aws/core/auth/AWSAuthSigner.h> #include <aws/core/auth/AWSAuthSignerProvider.h> +#include <aws/core/client/AWSUrlPresigner.h> #include <aws/core/client/AWSError.h> #include <aws/core/client/AWSErrorMarshaller.h> #include <aws/core/client/ClientConfiguration.h> #include <aws/core/client/CoreErrors.h> #include <aws/core/client/RetryStrategy.h> +#include <aws/core/client/RequestCompression.h> #include <aws/core/http/HttpClient.h> #include <aws/core/http/HttpClientFactory.h> #include <aws/core/http/HttpResponse.h> @@ -27,6 +29,9 @@ #include <aws/core/Globals.h> #include <aws/core/utils/EnumParseOverflowContainer.h> #include <aws/core/utils/crypto/MD5.h> +#include <aws/core/utils/crypto/CRC32.h> +#include <aws/core/utils/crypto/Sha256.h> +#include <aws/core/utils/crypto/Sha1.h> #include <aws/core/utils/HashingUtils.h> #include <aws/core/utils/crypto/Factories.h> #include <aws/core/utils/event/EventStream.h> @@ -35,10 +40,12 @@ #include <aws/core/Region.h> #include <aws/core/utils/DNS.h> #include <aws/core/Version.h> +#include <aws/core/platform/Environment.h> #include <aws/core/platform/OSVersionInfo.h> #include <cstring> #include <cassert> +#include <iomanip> using namespace Aws; using namespace Aws::Client; @@ -51,12 +58,15 @@ static const int SUCCESS_RESPONSE_MIN = 200; static const int SUCCESS_RESPONSE_MAX = 299; static const char AWS_CLIENT_LOG_TAG[] = "AWSClient"; +static const char AWS_LAMBDA_FUNCTION_NAME[] = "AWS_LAMBDA_FUNCTION_NAME"; +static const char X_AMZN_TRACE_ID[] = "_X_AMZN_TRACE_ID"; + //4 Minutes static const std::chrono::milliseconds TIME_DIFF_MAX = std::chrono::minutes(4); //-4 Minutes static const std::chrono::milliseconds TIME_DIFF_MIN = std::chrono::minutes(-4); -static CoreErrors GuessBodylessErrorType(Aws::Http::HttpResponseCode responseCode) +CoreErrors AWSClient::GuessBodylessErrorType(Aws::Http::HttpResponseCode responseCode) { switch (responseCode) { @@ -70,6 +80,14 @@ static CoreErrors GuessBodylessErrorType(Aws::Http::HttpResponseCode responseCod } } +bool AWSClient::DoesResponseGenerateError(const std::shared_ptr<HttpResponse>& response) +{ + if (response->HasClientError()) return true; + + int responseCode = static_cast<int>(response->GetResponseCode()); + return responseCode < SUCCESS_RESPONSE_MIN || responseCode > SUCCESS_RESPONSE_MAX; +} + struct RequestInfo { Aws::Utils::DateTime ttl; @@ -107,9 +125,10 @@ AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration, m_customizedUserAgent(!m_userAgent.empty()), m_hash(Aws::Utils::Crypto::CreateMD5Implementation()), m_requestTimeoutMs(configuration.requestTimeoutMs), - m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment) + m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment), + m_requestCompressionConfig(configuration.requestCompressionConfig) { - SetServiceClientName("AWSBaseClient"); + AWSClient::SetServiceClientName("AWSBaseClient"); } AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration, @@ -126,9 +145,10 @@ AWSClient::AWSClient(const Aws::Client::ClientConfiguration& configuration, m_customizedUserAgent(!m_userAgent.empty()), m_hash(Aws::Utils::Crypto::CreateMD5Implementation()), m_requestTimeoutMs(configuration.requestTimeoutMs), - m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment) + m_enableClockSkewAdjustment(configuration.enableClockSkewAdjustment), + m_requestCompressionConfig(configuration.requestCompressionConfig) { - SetServiceClientName("AWSBaseClient"); + AWSClient::SetServiceClientName("AWSBaseClient"); } void AWSClient::SetServiceClientName(const Aws::String& name) @@ -136,10 +156,7 @@ void AWSClient::SetServiceClientName(const Aws::String& name) m_serviceName = name; if (!m_customizedUserAgent) { - Aws::StringStream ss; - ss << "aws-sdk-cpp/" << Version::GetVersionString() << " " << Aws::OSVersionInfo::ComputeOSVersionString() - << " " << Version::GetCompilerVersionString(); - m_userAgent = ss.str(); + m_userAgent = Aws::Client::ComputeUserAgentString(); } } @@ -232,16 +249,24 @@ HttpResponseOutcome AWSClient::AttemptExhaustively(const Aws::Http::URI& uri, const char* signerRegion = signerRegionOverride; Aws::String regionFromResponse; - Aws::String invocationId = UUID::RandomUUID(); + Aws::String invocationId = Aws::Utils::UUID::RandomUUID(); RequestInfo requestInfo; requestInfo.attempt = 1; requestInfo.maxAttempts = 0; httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + AppendRecursionDetectionHeader(httpRequest); for (long retries = 0;; retries++) { - m_retryStrategy->GetSendToken(); + if(!m_retryStrategy->HasSendToken()) + { + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::SLOW_DOWN, + "", + "Unable to acquire enough send tokens to execute request.", + false/*retryable*/)); + + }; httpRequest->SetEventStreamRequest(request.IsEventStreamRequest()); outcome = AttemptOneRequest(httpRequest, request, signerName, signerRegion, signerServiceNameOverride); @@ -358,16 +383,24 @@ HttpResponseOutcome AWSClient::AttemptExhaustively(const Aws::Http::URI& uri, const char* signerRegion = signerRegionOverride; Aws::String regionFromResponse; - Aws::String invocationId = UUID::RandomUUID(); + Aws::String invocationId = Aws::Utils::UUID::RandomUUID(); RequestInfo requestInfo; requestInfo.attempt = 1; requestInfo.maxAttempts = 0; httpRequest->SetHeaderValue(Http::SDK_INVOCATION_ID_HEADER, invocationId); httpRequest->SetHeaderValue(Http::SDK_REQUEST_HEADER, requestInfo); + AppendRecursionDetectionHeader(httpRequest); for (long retries = 0;; retries++) { - m_retryStrategy->GetSendToken(); + if(!m_retryStrategy->HasSendToken()) + { + return HttpResponseOutcome(AWSError<CoreErrors>(CoreErrors::SLOW_DOWN, + "", + "Unable to acquire enough send tokens to execute request.", + false/*retryable*/)); + + }; outcome = AttemptOneRequest(httpRequest, signerName, requestName, signerRegion, signerServiceNameOverride); if (retries == 0) { @@ -452,15 +485,6 @@ HttpResponseOutcome AWSClient::AttemptExhaustively(const Aws::Http::URI& uri, return outcome; } -static bool DoesResponseGenerateError(const std::shared_ptr<HttpResponse>& response) -{ - if (response->HasClientError()) return true; - - int responseCode = static_cast<int>(response->GetResponseCode()); - return responseCode < SUCCESS_RESPONSE_MIN || responseCode > SUCCESS_RESPONSE_MAX; - -} - HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<HttpRequest>& httpRequest, const Aws::AmazonWebServiceRequest& request, const char* signerName, const char* signerRegionOverride, const char* signerServiceNameOverride) const { @@ -481,7 +505,31 @@ HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<HttpReque std::shared_ptr<HttpResponse> httpResponse( m_httpClient->MakeRequest(httpRequest, m_readRateLimiter.get(), m_writeRateLimiter.get())); - if (DoesResponseGenerateError(httpResponse)) + if (request.ShouldValidateResponseChecksum()) + { + for (const auto& hashIterator : httpRequest->GetResponseValidationHashes()) + { + Aws::String checksumHeaderKey = Aws::String("x-amz-checksum-") + hashIterator.first; + // TODO: If checksum ends with -#, then skip + if (httpResponse->HasHeader(checksumHeaderKey.c_str())) + { + Aws::String checksumHeaderValue = httpResponse->GetHeader(checksumHeaderKey.c_str()); + if (HashingUtils::Base64Encode(hashIterator.second->GetHash().GetResult()) != checksumHeaderValue) + { + AWSError<CoreErrors> error(CoreErrors::VALIDATION, "", "Response checksums mismatch", false/*retryable*/); + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, error); + return HttpResponseOutcome(error); + } + // Validate only a single checksum returned in an HTTP response + break; + } + } + } + + if (DoesResponseGenerateError(httpResponse) || request.HasEmbeddedError(httpResponse->GetResponseBody(), httpResponse->GetHeaders())) { AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); auto error = BuildAWSError(httpResponse); @@ -560,6 +608,54 @@ StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::Http::URI& u return StreamOutcome(std::move(httpResponseOutcome)); } +StreamOutcome AWSClient::MakeRequestWithUnparsedResponse(const Aws::AmazonWebServiceRequest& request, + const Aws::Endpoint::AWSEndpoint& endpoint, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + + return MakeRequestWithUnparsedResponse(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); +} + +XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::AmazonWebServiceRequest& request, + const Aws::Endpoint::AWSEndpoint& endpoint, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + + return MakeRequestWithEventStream(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); +} + XmlOutcome AWSXMLClient::MakeRequestWithEventStream(const Aws::Http::URI& uri, const Aws::AmazonWebServiceRequest& request, Http::HttpMethod method, @@ -603,6 +699,119 @@ void AWSClient::AddHeadersToRequest(const std::shared_ptr<Aws::Http::HttpRequest AddCommonHeaders(*httpRequest); } +void AWSClient::AppendHeaderValueToRequest(const std::shared_ptr<HttpRequest> &httpRequest, const String header, const String value) const +{ + if (!httpRequest->HasHeader(header.c_str())) + { + httpRequest->SetHeaderValue(header, value); + } + else + { + Aws::String contentEncoding = httpRequest->GetHeaderValue(header.c_str()); + contentEncoding.append(",").append(value); + httpRequest->SetHeaderValue(header, contentEncoding); + } +} + +void AWSClient::AddChecksumToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, + const Aws::AmazonWebServiceRequest& request) const +{ + Aws::String checksumAlgorithmName = Aws::Utils::StringUtils::ToLower(request.GetChecksumAlgorithmName().c_str()); + + // Request checksums + if (!checksumAlgorithmName.empty()) + { + // For non-streaming payload, the resolved checksum location is always header. + // For streaming payload, the resolved checksum location depends on whether it is an unsigned payload, we let AwsAuthSigner decide it. + if (checksumAlgorithmName == "crc32") + { + if (request.IsStreaming()) + { + httpRequest->SetRequestHash("crc32", Aws::MakeShared<Crypto::CRC32>(AWS_CLIENT_LOG_TAG)); + } + else + { + httpRequest->SetHeaderValue("x-amz-checksum-crc32", HashingUtils::Base64Encode(HashingUtils::CalculateCRC32(*(GetBodyStream(request))))); + } + } + else if (checksumAlgorithmName == "crc32c") + { + if (request.IsStreaming()) + { + httpRequest->SetRequestHash("crc32c", Aws::MakeShared<Crypto::CRC32C>(AWS_CLIENT_LOG_TAG)); + } + else + { + httpRequest->SetHeaderValue("x-amz-checksum-crc32c", HashingUtils::Base64Encode(HashingUtils::CalculateCRC32C(*(GetBodyStream(request))))); + } + } + else if (checksumAlgorithmName == "sha256") + { + if (request.IsStreaming()) + { + httpRequest->SetRequestHash("sha256", Aws::MakeShared<Crypto::Sha256>(AWS_CLIENT_LOG_TAG)); + } + else + { + httpRequest->SetHeaderValue("x-amz-checksum-sha256", HashingUtils::Base64Encode(HashingUtils::CalculateSHA256(*(GetBodyStream(request))))); + } + } + else if (checksumAlgorithmName == "sha1") + { + if (request.IsStreaming()) + { + httpRequest->SetRequestHash("sha1", Aws::MakeShared<Crypto::Sha1>(AWS_CLIENT_LOG_TAG)); + } + else + { + httpRequest->SetHeaderValue("x-amz-checksum-sha1", HashingUtils::Base64Encode(HashingUtils::CalculateSHA1(*(GetBodyStream(request))))); + } + } + else if (checksumAlgorithmName == "md5") + { + httpRequest->SetHeaderValue(Http::CONTENT_MD5_HEADER, HashingUtils::Base64Encode(HashingUtils::CalculateMD5(*(GetBodyStream(request))))); + } + else + { + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "Checksum algorithm: " << checksumAlgorithmName << "is not supported by SDK."); + } + } + + // Response checksums + if (request.ShouldValidateResponseChecksum()) + { + for (const Aws::String& responseChecksumAlgorithmName : request.GetResponseChecksumAlgorithmNames()) + { + checksumAlgorithmName = Aws::Utils::StringUtils::ToLower(responseChecksumAlgorithmName.c_str()); + + if (checksumAlgorithmName == "crc32c") + { + std::shared_ptr<Aws::Utils::Crypto::CRC32C> crc32c = Aws::MakeShared<Aws::Utils::Crypto::CRC32C>(AWS_CLIENT_LOG_TAG); + httpRequest->AddResponseValidationHash("crc32c", crc32c); + } + else if (checksumAlgorithmName == "crc32") + { + std::shared_ptr<Aws::Utils::Crypto::CRC32> crc32 = Aws::MakeShared<Aws::Utils::Crypto::CRC32>(AWS_CLIENT_LOG_TAG); + httpRequest->AddResponseValidationHash("crc", crc32); + } + else if (checksumAlgorithmName == "sha1") + { + std::shared_ptr<Aws::Utils::Crypto::Sha1> sha1 = Aws::MakeShared<Aws::Utils::Crypto::Sha1>(AWS_CLIENT_LOG_TAG); + httpRequest->AddResponseValidationHash("sha1", sha1); + } + else if (checksumAlgorithmName == "sha256") + { + std::shared_ptr<Aws::Utils::Crypto::Sha256> sha256 = Aws::MakeShared<Aws::Utils::Crypto::Sha256>(AWS_CLIENT_LOG_TAG); + httpRequest->AddResponseValidationHash("sha256", sha256); + } + else + { + AWS_LOGSTREAM_WARN(AWS_CLIENT_LOG_TAG, "Checksum algorithm: " << checksumAlgorithmName << " is not supported in validating response body yet."); + } + } + } +} + void AWSClient::AddContentBodyToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest, const std::shared_ptr<Aws::IOStream>& body, bool needsContentMd5, bool isChunked) const { @@ -610,7 +819,7 @@ void AWSClient::AddContentBodyToRequest(const std::shared_ptr<Aws::Http::HttpReq //If there is no body, we have a content length of 0 //note: we also used to remove content-type, but S3 actually needs content-type on InitiateMultipartUpload and it isn't - //forbiden by the spec. If we start getting weird errors related to this, make sure it isn't caused by this removal. + //forbidden by the spec. If we start getting weird errors related to this, make sure it isn't caused by this removal. if (!body) { AWS_LOGSTREAM_TRACE(AWS_CLIENT_LOG_TAG, "No content body, content-length headers"); @@ -682,11 +891,11 @@ Aws::String Aws::Client::GetAuthorizationHeader(const Aws::Http::HttpRequest& ht return authHeader.substr(signaturePosition + strlen(Aws::Auth::SIGNATURE) + 1); } -void AWSClient::BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, - const std::shared_ptr<HttpRequest>& httpRequest) const +void AWSClient::BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, const std::shared_ptr<HttpRequest>& httpRequest) const { - //do headers first since the request likely will set content-length as it's own header. + //do headers first since the request likely will set content-length as its own header. AddHeadersToRequest(httpRequest, request.GetHeaders()); + AddHeadersToRequest(httpRequest, request.GetAdditionalCustomHeaders()); if (request.IsEventStreamRequest()) { @@ -694,9 +903,31 @@ void AWSClient::BuildHttpRequest(const Aws::AmazonWebServiceRequest& request, } else { - AddContentBodyToRequest(httpRequest, request.GetBody(), request.ShouldComputeContentMd5(), request.IsStreaming() && request.IsChunked() && m_httpClient->SupportsChunkedTransferEncoding()); + //Check if compression is required + CompressionAlgorithm selectedCompressionAlgorithm = + request.GetSelectedCompressionAlgorithm(m_requestCompressionConfig); + if (Aws::Client::CompressionAlgorithm::NONE != selectedCompressionAlgorithm) { + Aws::Client::RequestCompression rc; + auto compressOutcome = rc.compress(request.GetBody(), selectedCompressionAlgorithm); + + if (compressOutcome.IsSuccess()) { + Aws::String compressionAlgorithmId = Aws::Client::GetCompressionAlgorithmId(selectedCompressionAlgorithm); + AppendHeaderValueToRequest(httpRequest, CONTENT_ENCODING_HEADER, compressionAlgorithmId); + AddContentBodyToRequest( + httpRequest, compressOutcome.GetResult(), + request.ShouldComputeContentMd5(), + request.IsStreaming() && request.IsChunked() && + m_httpClient->SupportsChunkedTransferEncoding()); + } else { + AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Failed to compress request, submitting uncompressed"); + AddContentBodyToRequest(httpRequest, request.GetBody(), request.ShouldComputeContentMd5(), request.IsStreaming() && request.IsChunked() && m_httpClient->SupportsChunkedTransferEncoding()); + } + } else { + AddContentBodyToRequest(httpRequest, request.GetBody(), request.ShouldComputeContentMd5(), request.IsStreaming() && request.IsChunked() && m_httpClient->SupportsChunkedTransferEncoding()); + } } + AddChecksumToRequest(httpRequest, request); // Pass along handlers for processing data sent/received in bytes httpRequest->SetDataReceivedEventHandler(request.GetDataReceivedEventHandler()); httpRequest->SetDataSentEventHandler(request.GetDataSentEventHandler()); @@ -710,389 +941,132 @@ void AWSClient::AddCommonHeaders(HttpRequest& httpRequest) const httpRequest.SetUserAgent(m_userAgent); } -Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, long long expirationInSeconds) +Aws::String AWSClient::GeneratePresignedUrl(const URI& uri, HttpMethod method, long long expirationInSeconds) { - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; -} - -Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) -{ - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - for (const auto& it: customizedHeaders) - { - request->SetHeaderValue(it.first.c_str(), it.second); - } - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const char* region, long long expirationInSeconds) const +Aws::String AWSClient::GeneratePresignedUrl(const URI& uri, HttpMethod method, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) { - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, region, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, customizedHeaders, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(URI& uri, HttpMethod method, const char* region, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) +Aws::String AWSClient::GeneratePresignedUrl(const URI& uri, HttpMethod method, const char* region, long long expirationInSeconds) const { - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - for (const auto& it: customizedHeaders) - { - request->SetHeaderValue(it.first.c_str(), it.second); - } - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, region, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, long long expirationInSeconds) const +Aws::String AWSClient::GeneratePresignedUrl(const URI& uri, HttpMethod method, const char* region, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) { - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, region, serviceName, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, customizedHeaders, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) +Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, long long expirationInSeconds) const { - std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - for (const auto& it: customizedHeaders) - { - request->SetHeaderValue(it.first.c_str(), it.second); - } - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*request, region, serviceName, expirationInSeconds)) - { - return request->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, - const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) { - std::shared_ptr<HttpRequest> httpRequest = - ConvertToRequestForPresigning(request, uri, method, extraParams); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*httpRequest, region, expirationInSeconds)) - { - return httpRequest->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, customizedHeaders, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, -const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const char* signerName, long long expirationInSeconds) const { - std::shared_ptr<HttpRequest> httpRequest = - ConvertToRequestForPresigning(request, uri, method, extraParams); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*httpRequest, region, serviceName, expirationInSeconds)) - { - return httpRequest->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, signerName, expirationInSeconds); } -Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, Aws::Http::HttpMethod method, - const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, const char* signerName, const Aws::Http::HeaderValueCollection& customizedHeaders, long long expirationInSeconds) { - std::shared_ptr<HttpRequest> httpRequest = - ConvertToRequestForPresigning(request, uri, method, extraParams); - auto signer = GetSignerByName(Aws::Auth::SIGV4_SIGNER); - if (signer->PresignRequest(*httpRequest, expirationInSeconds)) - { - return httpRequest->GetURIString(); - } - - return {}; + return AWSUrlPresigner(*this).GeneratePresignedUrl(uri, method, region, serviceName, signerName, customizedHeaders, expirationInSeconds); } -std::shared_ptr<Aws::Http::HttpRequest> AWSClient::ConvertToRequestForPresigning(const Aws::AmazonWebServiceRequest& request, Aws::Http::URI& uri, - Aws::Http::HttpMethod method, const Aws::Http::QueryStringParameterCollection& extraParams) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::Endpoint::AWSEndpoint& endpoint, + Aws::Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const Aws::Http::HeaderValueCollection& customizedHeaders /* = {} */, + uint64_t expirationInSeconds /* = 0 */, + const char* signerName /* = Aws::Auth::SIGV4_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) { - request.PutToPresignedUrl(uri); - std::shared_ptr<HttpRequest> httpRequest = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - - for (auto& param : extraParams) - { - httpRequest->AddQueryStringParameter(param.first.c_str(), param.second); - } - - return httpRequest; + return AWSUrlPresigner(*this).GeneratePresignedUrl(endpoint, method, customizedHeaders, expirationInSeconds, signerName, signerRegionOverride, signerServiceNameOverride); } -std::shared_ptr<Aws::Http::HttpResponse> AWSClient::MakeHttpRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, + const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const { - return m_httpClient->MakeRequest(request, m_readRateLimiter.get(), m_writeRateLimiter.get()); + return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, extraParams, expirationInSeconds); } - -//////////////////////////////////////////////////////////////////////////// -AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, - const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, - const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : - BASECLASS(configuration, signer, errorMarshaller) +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, const char* region, const char* serviceName, + const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const { + return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, serviceName, extraParams, expirationInSeconds); } -AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, - const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, - const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : - BASECLASS(configuration, signerProvider, errorMarshaller) +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* region, + const char* serviceName, + const char* signerName, + const Aws::Http::QueryStringParameterCollection& extraParams, + long long expirationInSeconds) const { + return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, region, serviceName, signerName, extraParams, expirationInSeconds); } - -JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, - const Aws::AmazonWebServiceRequest& request, - Http::HttpMethod method, - const char* signerName, - const char* signerRegionOverride, - const char* signerServiceNameOverride) const +Aws::String AWSClient::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, const Aws::Http::URI& uri, Aws::Http::HttpMethod method, + const Aws::Http::QueryStringParameterCollection& extraParams, long long expirationInSeconds) const { - HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); - if (!httpOutcome.IsSuccess()) - { - return JsonOutcome(std::move(httpOutcome)); - } - - if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) - //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. - return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(httpOutcome.GetResult()->GetResponseBody()), - httpOutcome.GetResult()->GetHeaders(), - httpOutcome.GetResult()->GetResponseCode())); - - else - return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); + return AWSUrlPresigner(*this).GeneratePresignedUrl(request, uri, method, extraParams, expirationInSeconds); } -JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, - Http::HttpMethod method, - const char* signerName, - const char* requestName, - const char* signerRegionOverride, - const char* signerServiceNameOverride) const -{ - HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); - if (!httpOutcome.IsSuccess()) - { - return JsonOutcome(std::move(httpOutcome)); - } - - if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) - { - JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); - if (!jsonValue.WasParseSuccessful()) - { - return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); - } - - //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. - return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), - httpOutcome.GetResult()->GetHeaders(), - httpOutcome.GetResult()->GetResponseCode())); +std::shared_ptr<Aws::IOStream> AWSClient::GetBodyStream(const Aws::AmazonWebServiceRequest& request) const { + if (request.GetBody() != nullptr) { + return request.GetBody(); } - - return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); + // Return an empty string stream for no body + return Aws::MakeShared<Aws::StringStream>(AWS_CLIENT_LOG_TAG, ""); } -JsonOutcome AWSJsonClient::MakeEventStreamRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const +std::shared_ptr<Aws::Http::HttpResponse> AWSClient::MakeHttpRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const { - // request is assumed to be signed - std::shared_ptr<HttpResponse> httpResponse = MakeHttpRequest(request); - - if (DoesResponseGenerateError(httpResponse)) - { - AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); - auto error = BuildAWSError(httpResponse); - return JsonOutcome(std::move(error)); - } - - AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned successful response."); - - HttpResponseOutcome httpOutcome(std::move(httpResponse)); - - if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) - { - JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); - if (!jsonValue.WasParseSuccessful()) - { - return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); - } - - //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. - return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), - httpOutcome.GetResult()->GetHeaders(), - httpOutcome.GetResult()->GetResponseCode())); - } - - return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); + return m_httpClient->MakeRequest(request, m_readRateLimiter.get(), m_writeRateLimiter.get()); } -AWSError<CoreErrors> AWSJsonClient::BuildAWSError( - const std::shared_ptr<Aws::Http::HttpResponse>& httpResponse) const +void AWSClient::AppendRecursionDetectionHeader(std::shared_ptr<Aws::Http::HttpRequest> ioRequest) { - AWSError<CoreErrors> error; - if (httpResponse->HasClientError()) - { - bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; - error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + if(!ioRequest || ioRequest->HasHeader(Aws::Http::X_AMZN_TRACE_ID_HEADER)) { + return; } - else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) - { - auto responseCode = httpResponse->GetResponseCode(); - auto errorCode = GuessBodylessErrorType(responseCode); - - Aws::StringStream ss; - ss << "No response body."; - error = AWSError<CoreErrors>(errorCode, "", ss.str(), - IsRetryableHttpResponseCode(responseCode)); - } - else - { - assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); - error = GetErrorMarshaller()->Marshall(*httpResponse); + Aws::String awsLambdaFunctionName = Aws::Environment::GetEnv(AWS_LAMBDA_FUNCTION_NAME); + if(awsLambdaFunctionName.empty()) { + return; } - - error.SetResponseHeaders(httpResponse->GetHeaders()); - error.SetResponseCode(httpResponse->GetResponseCode()); - error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); - AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, error); - return error; -} - -///////////////////////////////////////////////////////////////////////////////////////// -AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, - const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, - const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : - BASECLASS(configuration, signer, errorMarshaller) -{ -} - -AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, - const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, - const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : - BASECLASS(configuration, signerProvider, errorMarshaller) -{ -} - -XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, - const Aws::AmazonWebServiceRequest& request, - Http::HttpMethod method, - const char* signerName, - const char* signerRegionOverride, - const char* signerServiceNameOverride) const -{ - HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); - if (!httpOutcome.IsSuccess()) - { - return XmlOutcome(std::move(httpOutcome)); + Aws::String xAmznTraceIdVal = Aws::Environment::GetEnv(X_AMZN_TRACE_ID); + if(xAmznTraceIdVal.empty()) { + return; } - if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + // Escape all non-printable ASCII characters by percent encoding + Aws::OStringStream xAmznTraceIdValEncodedStr; + for(const char ch : xAmznTraceIdVal) { - XmlDocument xmlDoc = XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()); - - if (!xmlDoc.WasParseSuccessful()) + if (ch >= 0x20 && ch <= 0x7e) // ascii chars [32-126] or [' ' to '~'] are not escaped { - AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, "Xml parsing for error failed with message " << xmlDoc.GetErrorMessage().c_str()); - return AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Xml Parse Error", xmlDoc.GetErrorMessage(), false); + xAmznTraceIdValEncodedStr << ch; } - - return XmlOutcome(AmazonWebServiceResult<XmlDocument>(std::move(xmlDoc), - httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); - } - - return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); -} - -XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, - Http::HttpMethod method, - const char* signerName, - const char* requestName, - const char* signerRegionOverride, - const char* signerServiceNameOverride) const -{ - HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); - if (!httpOutcome.IsSuccess()) - { - return XmlOutcome(std::move(httpOutcome)); - } - - if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) - { - return XmlOutcome(AmazonWebServiceResult<XmlDocument>( - XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()), - httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); - } - - return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); -} - -AWSError<CoreErrors> AWSXMLClient::BuildAWSError(const std::shared_ptr<Http::HttpResponse>& httpResponse) const -{ - AWSError<CoreErrors> error; - if (httpResponse->HasClientError()) - { - bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; - error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); - } - else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) - { - auto responseCode = httpResponse->GetResponseCode(); - auto errorCode = GuessBodylessErrorType(responseCode); - - Aws::StringStream ss; - ss << "No response body."; - error = AWSError<CoreErrors>(errorCode, "", ss.str(), IsRetryableHttpResponseCode(responseCode)); - } - else - { - assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); - - // When trying to build an AWS Error from a response which is an FStream, we need to rewind the - // file pointer back to the beginning in order to correctly read the input using the XML string iterator - if ((httpResponse->GetResponseBody().tellp() > 0) - && (httpResponse->GetResponseBody().tellg() > 0)) + else { - httpResponse->GetResponseBody().seekg(0); + // A percent-encoded octet is encoded as a character triplet + xAmznTraceIdValEncodedStr << '%' // consisting of the percent character "%" + << std::hex << std::setfill('0') << std::setw(2) << std::uppercase + << (size_t) ch //followed by the two hexadecimal digits representing that octet's numeric value + << std::dec << std::setfill(' ') << std::setw(0) << std::nouppercase; } - - error = GetErrorMarshaller()->Marshall(*httpResponse); } + xAmznTraceIdVal = xAmznTraceIdValEncodedStr.str(); - error.SetResponseHeaders(httpResponse->GetHeaders()); - error.SetResponseCode(httpResponse->GetResponseCode()); - error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); - AWS_LOGSTREAM_ERROR(AWS_CLIENT_LOG_TAG, error); - return error; + ioRequest->SetHeaderValue(Aws::Http::X_AMZN_TRACE_ID_HEADER, xAmznTraceIdVal); } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp index f5fa676f986..a905dddb5cf 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSErrorMarshaller.cpp @@ -23,6 +23,7 @@ AWS_CORE_API extern const char MESSAGE_LOWER_CASE[] = "message"; AWS_CORE_API extern const char MESSAGE_CAMEL_CASE[] = "Message"; AWS_CORE_API extern const char ERROR_TYPE_HEADER[] = "x-amzn-ErrorType"; AWS_CORE_API extern const char REQUEST_ID_HEADER[] = "x-amzn-RequestId"; +AWS_CORE_API extern const char QUERY_ERROR_HEADER[] = "x-amzn-query-error"; AWS_CORE_API extern const char TYPE[] = "__type"; AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse& httpResponse) const @@ -50,6 +51,24 @@ AWSError<CoreErrors> JsonErrorMarshaller::Marshall(const Aws::Http::HttpResponse error = FindErrorByHttpResponseCode(httpResponse.GetResponseCode()); error.SetMessage(message); } + + if (httpResponse.HasHeader(QUERY_ERROR_HEADER)) + { + auto errorCodeString = httpResponse.GetHeader(QUERY_ERROR_HEADER); + auto locationOfSemicolon = errorCodeString.find_first_of(';'); + Aws::String errorCode; + + if (locationOfSemicolon != Aws::String::npos) + { + errorCode = errorCodeString.substr(0, locationOfSemicolon); + } + else + { + errorCode = errorCodeString; + } + + error.SetExceptionName(errorCode); + } } else { diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp new file mode 100644 index 00000000000..b3e19d99778 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSJsonClient.cpp @@ -0,0 +1,212 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSJsonClient.h> +#include <aws/core/AmazonWebServiceRequest.h> +#include <aws/core/auth/AWSAuthSignerProvider.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/AWSErrorMarshaller.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/client/RetryStrategy.h> +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/http/URI.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/event/EventStream.h> +#include <aws/core/utils/UUID.h> +#include <aws/core/monitoring/MonitoringManager.h> + +#include <cassert> + + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Json; + +static const char AWS_JSON_CLIENT_LOG_TAG[] = "AWSJsonClient"; + +AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signer, errorMarshaller) +{ +} + +AWSJsonClient::AWSJsonClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signerProvider, errorMarshaller) +{ +} + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::AmazonWebServiceRequest& request, + const Aws::Endpoint::AWSEndpoint& endpoint, + Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const char* signerName /* = Aws::Auth::NULL_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + return MakeRequest(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); +} + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::Endpoint::AWSEndpoint& endpoint, + Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const char* signerName /* = Aws::Auth::NULL_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + return MakeRequest(uri, method, signerName, signerRegionOverride, signerServiceNameOverride); +} + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return JsonOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(httpOutcome.GetResult()->GetResponseBody()), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + + else + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +JsonOutcome AWSJsonClient::MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return JsonOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); + if (!jsonValue.WasParseSuccessful()) + { + return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); + } + + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + } + + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +JsonOutcome AWSJsonClient::MakeEventStreamRequest(std::shared_ptr<Aws::Http::HttpRequest>& request) const +{ + // request is assumed to be signed + std::shared_ptr<HttpResponse> httpResponse = MakeHttpRequest(request); + + if (DoesResponseGenerateError(httpResponse)) + { + AWS_LOGSTREAM_DEBUG(AWS_JSON_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response"); + auto error = BuildAWSError(httpResponse); + return JsonOutcome(std::move(error)); + } + + AWS_LOGSTREAM_DEBUG(AWS_JSON_CLIENT_LOG_TAG, "Request returned successful response."); + + HttpResponseOutcome httpOutcome(std::move(httpResponse)); + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody()); + if (!jsonValue.WasParseSuccessful()) + { + return JsonOutcome(AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Json Parser Error", jsonValue.GetErrorMessage(), false)); + } + + //this is stupid, but gcc doesn't pick up the covariant on the dereference so we have to give it a little hint. + return JsonOutcome(AmazonWebServiceResult<JsonValue>(std::move(jsonValue), + httpOutcome.GetResult()->GetHeaders(), + httpOutcome.GetResult()->GetResponseCode())); + } + + return JsonOutcome(AmazonWebServiceResult<JsonValue>(JsonValue(), httpOutcome.GetResult()->GetHeaders())); +} + +AWSError<CoreErrors> AWSJsonClient::BuildAWSError( + const std::shared_ptr<Aws::Http::HttpResponse>& httpResponse) const +{ + AWSError<CoreErrors> error; + if (httpResponse->HasClientError()) + { + bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; + error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + } + else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) + { + auto responseCode = httpResponse->GetResponseCode(); + auto errorCode = AWSClient::GuessBodylessErrorType(responseCode); + + Aws::StringStream ss; + ss << "No response body."; + error = AWSError<CoreErrors>(errorCode, "", ss.str(), + IsRetryableHttpResponseCode(responseCode)); + } + else + { + assert(httpResponse->GetResponseCode() != HttpResponseCode::OK); + error = GetErrorMarshaller()->Marshall(*httpResponse); + } + + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_JSON_CLIENT_LOG_TAG, error); + return error; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSUrlPresigner.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSUrlPresigner.cpp new file mode 100644 index 00000000000..a0bc8088384 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSUrlPresigner.cpp @@ -0,0 +1,236 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSUrlPresigner.h> +#include <aws/core/client/AWSClient.h> +#include <aws/core/http/HttpClientFactory.h> + +namespace Aws +{ +namespace Client +{ + +using HttpRequest = Http::HttpRequest; +using HttpMethod = Http::HttpMethod; +using URI = Http::URI; + + +AWSUrlPresigner::AWSUrlPresigner(const AWSClient& client) + : m_awsClient(client) +{} + + +Aws::Client::AWSAuthSigner* AWSUrlPresigner::GetSignerByName(const char* name) const +{ + return m_awsClient.GetSignerByName(name); +} + +std::shared_ptr<Aws::Http::HttpRequest> +ConvertToRequestForPresigning(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const Aws::Http::QueryStringParameterCollection& extraParams) +{ + Aws::Http::URI uriCopy = uri; + request.PutToPresignedUrl(uriCopy); + std::shared_ptr<HttpRequest> httpRequest = CreateHttpRequest(uriCopy, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + + for (auto& param : extraParams) + { + httpRequest->AddQueryStringParameter(param.first.c_str(), param.second); + } + + return httpRequest; +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const URI& uri, + HttpMethod method, + long long expirationInSeconds) const +{ + const char* regionOverride = nullptr; + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const URI& uri, + HttpMethod method, + const Aws::Http::HeaderValueCollection& customizedHeaders, + long long expirationInSeconds) const +{ + const char* regionOverride = nullptr; + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, customizedHeaders, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const URI& uri, + HttpMethod method, + const char* regionOverride, + long long expirationInSeconds) const +{ + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const URI& uri, + HttpMethod method, + const char* regionOverride, + const Aws::Http::HeaderValueCollection& customizedHeaders, + long long expirationInSeconds) const +{ + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, customizedHeaders, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const char* serviceNameOverride, + long long expirationInSeconds) const +{ + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const char* serviceNameOverride, + const Aws::Http::HeaderValueCollection& customizedHeaders, + long long expirationInSeconds) const +{ + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, customizedHeaders, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const char* serviceNameOverride, + const char* signerName, + long long expirationInSeconds) const +{ + const Aws::Http::HeaderValueCollection& customizedHeaders = {}; + return GeneratePresignedUrl(uri, method, regionOverride, serviceNameOverride, signerName, customizedHeaders, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* region, + const char* serviceName, + const char* signerName, + const Aws::Http::HeaderValueCollection& customizedHeaders, + long long expirationInSeconds) const +{ + /* a real method implementation */ + if (!signerName) { + signerName = Aws::Auth::SIGV4_SIGNER; + } + std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + for (const auto& it: customizedHeaders) + { + request->SetHeaderValue(it.first.c_str(), it.second); + } + auto signer = GetSignerByName(signerName); + if (signer->PresignRequest(*request, region, serviceName, expirationInSeconds)) + { + return request->GetURIString(); + } + + return {}; +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::Endpoint::AWSEndpoint& endpoint, + Aws::Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const Aws::Http::HeaderValueCollection& customizedHeaders /* = {} */, + uint64_t expirationInSeconds /* = 0 */, + const char* signerName /* = Aws::Auth::SIGV4_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + + return GeneratePresignedUrl(uri, method, signerRegionOverride, signerServiceNameOverride, signerName, customizedHeaders, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const Aws::Http::QueryStringParameterCollection& extraParams, + long long expirationInSeconds) const +{ + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + + return GeneratePresignedUrl(request, uri, method, regionOverride, serviceNameOverride, signerName, extraParams, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const char* serviceNameOverride, + const char* signerName, + const Aws::Http::QueryStringParameterCollection& extraParams, + long long expirationInSeconds) const +{ + /* a real method implementation */ + if (!signerName) { + signerName = Aws::Auth::SIGV4_SIGNER; + } + std::shared_ptr<HttpRequest> httpRequest = + ConvertToRequestForPresigning(request, uri, method, extraParams); + auto signer = GetSignerByName(signerName); + if (signer->PresignRequest(*httpRequest, regionOverride, serviceNameOverride, expirationInSeconds)) + { + return httpRequest->GetURIString(); + } + + return {}; +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const char* regionOverride, + const char* serviceNameOverride, + const Aws::Http::QueryStringParameterCollection& extraParams, + long long expirationInSeconds) const +{ + const char* signerName = Aws::Auth::SIGV4_SIGNER; + return GeneratePresignedUrl(request, uri, method, regionOverride, serviceNameOverride, signerName, extraParams, expirationInSeconds); +} + +Aws::String AWSUrlPresigner::GeneratePresignedUrl(const Aws::AmazonWebServiceRequest& request, + const Aws::Http::URI& uri, + Aws::Http::HttpMethod method, + const Aws::Http::QueryStringParameterCollection& extraParams, + long long expirationInSeconds) const +{ + const char* regionOverride = nullptr; + const char* serviceNameOverride = nullptr; + const char* signerName = Aws::Auth::SIGV4_SIGNER; + + return GeneratePresignedUrl(request, uri, method, regionOverride, serviceNameOverride, signerName, extraParams, expirationInSeconds); +} + +} // namespace Client +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp new file mode 100644 index 00000000000..129595b9179 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AWSXmlClient.cpp @@ -0,0 +1,180 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AWSXmlClient.h> +#include <aws/core/AmazonWebServiceRequest.h> +#include <aws/core/auth/AWSAuthSignerProvider.h> +#include <aws/core/client/AWSError.h> +#include <aws/core/client/AWSErrorMarshaller.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/client/RetryStrategy.h> +#include <aws/core/http/HttpClient.h> +#include <aws/core/http/HttpResponse.h> +#include <aws/core/http/URI.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/xml/XmlSerializer.h> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/event/EventStream.h> +#include <aws/core/utils/UUID.h> + +using namespace Aws; +using namespace Aws::Client; +using namespace Aws::Http; +using namespace Aws::Utils; +using namespace Aws::Utils::Xml; + +static const char AWS_XML_CLIENT_LOG_TAG[] = "AWSXmlClient"; + +AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Client::AWSAuthSigner>& signer, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signer, errorMarshaller) +{ +} + +AWSXMLClient::AWSXMLClient(const Aws::Client::ClientConfiguration& configuration, + const std::shared_ptr<Aws::Auth::AWSAuthSignerProvider>& signerProvider, + const std::shared_ptr<AWSErrorMarshaller>& errorMarshaller) : + BASECLASS(configuration, signerProvider, errorMarshaller) +{ +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::AmazonWebServiceRequest& request, + const Aws::Endpoint::AWSEndpoint& endpoint, + Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const char* signerName /* = Aws::Auth::NULL_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + return MakeRequest(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride); +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::Endpoint::AWSEndpoint& endpoint, + const char* requestName /* = "" */, + Http::HttpMethod method /* = Http::HttpMethod::HTTP_POST */, + const char* signerName /* = Aws::Auth::NULL_SIGNER */, + const char* signerRegionOverride /* = nullptr */, + const char* signerServiceNameOverride /* = nullptr */) const +{ + const Aws::Http::URI& uri = endpoint.GetURI(); + if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().c_str(); + if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str(); + } + if (endpoint.GetAttributes()->authScheme.GetSigningName()) { + signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); + } + } + return MakeRequest(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride); +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, + const Aws::AmazonWebServiceRequest& request, + Http::HttpMethod method, + const char* signerName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return XmlOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + XmlDocument xmlDoc = XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()); + + if (!xmlDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(AWS_XML_CLIENT_LOG_TAG, "Xml parsing for error failed with message " << xmlDoc.GetErrorMessage().c_str()); + return AWSError<CoreErrors>(CoreErrors::UNKNOWN, "Xml Parse Error", xmlDoc.GetErrorMessage(), false); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(std::move(xmlDoc), + httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); +} + +XmlOutcome AWSXMLClient::MakeRequest(const Aws::Http::URI& uri, + Http::HttpMethod method, + const char* signerName, + const char* requestName, + const char* signerRegionOverride, + const char* signerServiceNameOverride) const +{ + HttpResponseOutcome httpOutcome(BASECLASS::AttemptExhaustively(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride)); + if (!httpOutcome.IsSuccess()) + { + return XmlOutcome(std::move(httpOutcome)); + } + + if (httpOutcome.GetResult()->GetResponseBody().tellp() > 0) + { + return XmlOutcome(AmazonWebServiceResult<XmlDocument>( + XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody()), + httpOutcome.GetResult()->GetHeaders(), httpOutcome.GetResult()->GetResponseCode())); + } + + return XmlOutcome(AmazonWebServiceResult<XmlDocument>(XmlDocument(), httpOutcome.GetResult()->GetHeaders())); +} + +AWSError<CoreErrors> AWSXMLClient::BuildAWSError(const std::shared_ptr<Http::HttpResponse>& httpResponse) const +{ + AWSError<CoreErrors> error; + if (httpResponse->HasClientError()) + { + bool retryable = httpResponse->GetClientErrorType() == CoreErrors::NETWORK_CONNECTION ? true : false; + error = AWSError<CoreErrors>(httpResponse->GetClientErrorType(), "", httpResponse->GetClientErrorMessage(), retryable); + } + else if (!httpResponse->GetResponseBody() || httpResponse->GetResponseBody().tellp() < 1) + { + auto responseCode = httpResponse->GetResponseCode(); + auto errorCode = AWSClient::GuessBodylessErrorType(responseCode); + + Aws::StringStream ss; + ss << "No response body."; + error = AWSError<CoreErrors>(errorCode, "", ss.str(), IsRetryableHttpResponseCode(responseCode)); + } + else + { + // When trying to build an AWS Error from a response which is an FStream, we need to rewind the + // file pointer back to the beginning in order to correctly read the input using the XML string iterator + if ((httpResponse->GetResponseBody().tellp() > 0) + && (httpResponse->GetResponseBody().tellg() > 0)) + { + httpResponse->GetResponseBody().seekg(0); + } + + error = GetErrorMarshaller()->Marshall(*httpResponse); + } + + error.SetResponseHeaders(httpResponse->GetHeaders()); + error.SetResponseCode(httpResponse->GetResponseCode()); + error.SetRemoteHostIpAddress(httpResponse->GetOriginatingRequest().GetResolvedRemoteHost()); + AWS_LOGSTREAM_ERROR(AWS_XML_CLIENT_LOG_TAG, error); + return error; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AdaptiveRetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AdaptiveRetryStrategy.cpp new file mode 100644 index 00000000000..0907b81137e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/AdaptiveRetryStrategy.cpp @@ -0,0 +1,228 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/AdaptiveRetryStrategy.h> + +#include <aws/core/client/AWSError.h> +#include <aws/core/client/CoreErrors.h> +#include <aws/core/utils/memory/stl/AWSSet.h> + +#include <cmath> +#include <thread> + +using namespace Aws::Utils::Threading; + +namespace Aws +{ + namespace Client + { + static const double MIN_FILL_RATE = 0.5; + static const double MIN_CAPACITY = 1; + + static const double SMOOTH = 0.8; + static const double BETA = 0.7; + static const double SCALE_CONSTANT = 0.4; + + // A static list containing all service exception names classified as throttled. + static const char* THROTTLING_EXCEPTIONS[] { + "Throttling", "ThrottlingException", "ThrottledException", "RequestThrottledException", + "TooManyRequestsException", "ProvisionedThroughputExceededException", "TransactionInProgressException", + "RequestLimitExceeded", "BandwidthLimitExceeded", "LimitExceededException", "RequestThrottled", + "SlowDown", "PriorRequestNotComplete", "EC2ThrottledException"}; + static const size_t THROTTLING_EXCEPTIONS_SZ = sizeof(THROTTLING_EXCEPTIONS) / sizeof(THROTTLING_EXCEPTIONS[0]); + + + // C-tor for unit testing + RetryTokenBucket::RetryTokenBucket(double fillRate, double maxCapacity, double currentCapacity, + const Aws::Utils::DateTime& lastTimestamp, double measuredTxRate, double lastTxRateBucket, + size_t requestCount, bool enabled, double lastMaxRate, const Aws::Utils::DateTime& lastThrottleTime) + : + m_fillRate(fillRate), m_maxCapacity(maxCapacity), m_currentCapacity(currentCapacity), + m_lastTimestamp(lastTimestamp), m_measuredTxRate(measuredTxRate), + m_lastTxRateBucket(lastTxRateBucket), m_requestCount(requestCount), m_enabled(enabled), + m_lastMaxRate(lastMaxRate), m_lastThrottleTime(lastThrottleTime) + {} + + bool RetryTokenBucket::Acquire(size_t amount, bool fastFail) + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + if (!m_enabled) + { + return true; + } + Refill(); + bool notEnough = amount > m_currentCapacity; + if (notEnough && fastFail) { + return false; + } + // If all the tokens couldn't be acquired immediately, wait enough + // time to fill the remainder. + if (notEnough) { + std::chrono::duration<double> waitTime((amount - m_currentCapacity) / m_fillRate); + std::this_thread::sleep_for(waitTime); + Refill(); + } + m_currentCapacity -= amount; + return true; + } + + void RetryTokenBucket::Refill(const Aws::Utils::DateTime& now) + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + + if (0 == m_lastTimestamp.Millis()) { + m_lastTimestamp = now; + return; + } + + double fillAmount = (std::abs(now.Millis() - m_lastTimestamp.Millis()))/1000.0 * m_fillRate; + m_currentCapacity = (std::min)(m_maxCapacity, m_currentCapacity + fillAmount); + m_lastTimestamp = now; + } + + void RetryTokenBucket::UpdateRate(double newRps, const Aws::Utils::DateTime& now) + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + + Refill(now); + m_fillRate = (std::max)(newRps, MIN_FILL_RATE); + m_maxCapacity = (std::max)(newRps, MIN_CAPACITY); + m_currentCapacity = (std::min)(m_currentCapacity, m_maxCapacity); + } + + void RetryTokenBucket::UpdateMeasuredRate(const Aws::Utils::DateTime& now) + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + + double t = now.Millis() / 1000.0; + double timeBucket = floor(t * 2.0) / 2.0; + m_requestCount += 1; + if (timeBucket > m_lastTxRateBucket) { + double currentRate = m_requestCount / (timeBucket - m_lastTxRateBucket); + m_measuredTxRate = (currentRate * SMOOTH) + (m_measuredTxRate * (1 - SMOOTH)); + m_requestCount = 0; + m_lastTxRateBucket = timeBucket; + } + } + + void RetryTokenBucket::UpdateClientSendingRate(bool isThrottlingResponse, const Aws::Utils::DateTime& now) + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + + UpdateMeasuredRate(now); + + double calculatedRate = 0.0; + if (isThrottlingResponse) + { + double rateToUse = m_measuredTxRate; + if (m_enabled) + rateToUse = (std::min)(rateToUse, m_fillRate); + + m_lastMaxRate = rateToUse; + m_lastThrottleTime = now; + + calculatedRate = CUBICThrottle(rateToUse); + Enable(); + } + else + { + double timeWindow = CalculateTimeWindow(); + calculatedRate = CUBICSuccess(now, timeWindow); + } + + double newRate = (std::min)(calculatedRate, 2.0 * m_measuredTxRate); + UpdateRate(newRate, now); + } + + void RetryTokenBucket::Enable() + { + std::lock_guard<std::recursive_mutex> locker(m_mutex); + m_enabled = true; + } + + double RetryTokenBucket::CalculateTimeWindow() const + { + return pow(((m_lastMaxRate * (1.0 - BETA)) / SCALE_CONSTANT), (1.0 / 3)); + } + + double RetryTokenBucket::CUBICSuccess(const Aws::Utils::DateTime& timestamp, const double timeWindow) const + { + double dt = (timestamp.Millis() - m_lastThrottleTime.Millis()) / 1000.0; + double calculatedRate = SCALE_CONSTANT * pow(dt - timeWindow, 3.0) + m_lastMaxRate; + return calculatedRate; + } + + double RetryTokenBucket::CUBICThrottle(const double rateToUse) const + { + double calculatedRate = rateToUse * BETA; + return calculatedRate; + } + + + AdaptiveRetryStrategy::AdaptiveRetryStrategy(long maxAttempts) : + StandardRetryStrategy(maxAttempts) + {} + + AdaptiveRetryStrategy::AdaptiveRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts) : + StandardRetryStrategy(retryQuotaContainer, maxAttempts) + {} + + bool AdaptiveRetryStrategy::HasSendToken() + { + return m_retryTokenBucket.Acquire(1, m_fastFail); + } + + void AdaptiveRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome) + { + if (httpResponseOutcome.IsSuccess()) + { + m_retryQuotaContainer->ReleaseRetryQuota(Aws::Client::NO_RETRY_INCREMENT); + m_retryTokenBucket.UpdateClientSendingRate(false); + } + else + { + m_retryTokenBucket.UpdateClientSendingRate(IsThrottlingResponse(httpResponseOutcome)); + } + } + + void AdaptiveRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome, const AWSError<CoreErrors>& lastError) + { + if (httpResponseOutcome.IsSuccess()) + { + m_retryQuotaContainer->ReleaseRetryQuota(lastError); + m_retryTokenBucket.UpdateClientSendingRate(false); + } + else + { + m_retryTokenBucket.UpdateClientSendingRate(IsThrottlingResponse(httpResponseOutcome)); + } + } + + bool AdaptiveRetryStrategy::IsThrottlingResponse(const HttpResponseOutcome& httpResponseOutcome) + { + if(httpResponseOutcome.IsSuccess()) + return false; + + const AWSError<CoreErrors>& error = httpResponseOutcome.GetError(); + const Aws::Client::CoreErrors enumValue = error.GetErrorType(); + switch(enumValue) + { + case Aws::Client::CoreErrors::THROTTLING: + case Aws::Client::CoreErrors::SLOW_DOWN: + return true; + default: + break; + } + + if(std::find(THROTTLING_EXCEPTIONS, + THROTTLING_EXCEPTIONS + THROTTLING_EXCEPTIONS_SZ, error.GetExceptionName()) != THROTTLING_EXCEPTIONS + THROTTLING_EXCEPTIONS_SZ) + { + return true; + } + + return false; + } + } +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index e517379a779..647c6e3f49a 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -4,8 +4,10 @@ */ #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> @@ -26,43 +28,217 @@ 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_CORE_API Aws::String ComputeUserAgentString() +Aws::String ComputeUserAgentString() { Aws::StringStream ss; - ss << "aws-sdk-cpp/" << Version::GetVersionString() << " " << Aws::OSVersionInfo::ComputeOSVersionString() - << " " << Version::GetCompilerVersionString(); + 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(); } -ClientConfiguration::ClientConfiguration() : - scheme(Aws::Http::Scheme::HTTPS), - useDualStack(false), - maxConnections(25), - httpRequestTimeoutMs(0), - requestTimeoutMs(3000), - connectTimeoutMs(1000), - enableTcpKeepAlive(true), - tcpKeepAliveIntervalMs(30000), - lowSpeedLimit(1), - proxyScheme(Aws::Http::Scheme::HTTP), - proxyPort(0), - executor(Aws::MakeShared<Aws::Utils::Threading::DefaultExecutor>(CLIENT_CONFIG_TAG)), - verifySSL(true), - writeRateLimiter(nullptr), - readRateLimiter(nullptr), - httpLibOverride(Aws::Http::TransferLibType::DEFAULT_CLIENT), - followRedirects(FollowRedirectsPolicy::DEFAULT), - disableExpectHeader(false), - enableClockSkewAdjustment(true), - enableHostPrefixInjection(true), - enableEndpointDiscovery(false), - profileName(Aws::Auth::GetConfigProfileName()) +void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig) { - AWS_LOGSTREAM_DEBUG(CLIENT_CONFIG_TAG, "ClientConfiguration will use SDK Auto Resolved profile: [" << profileName << "] if not specified by users."); + 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(); - // Initialize Retry Strategy - int maxAttempts; + 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()) { @@ -83,15 +259,21 @@ ClientConfiguration::ClientConfiguration() : } } - Aws::String retryMode = Aws::Environment::GetEnv("AWS_RETRY_MODE"); + 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 @@ -99,61 +281,55 @@ ClientConfiguration::ClientConfiguration() : retryStrategy = Aws::MakeShared<StandardRetryStrategy>(CLIENT_CONFIG_TAG, maxAttempts); } } - else - { - retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG); - } - - // Automatically determine the AWS region from environment variables, configuration file and EC2 metadata. - region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); - if (!region.empty()) - { - return; - } - - region = Aws::Environment::GetEnv("AWS_REGION"); - if (!region.empty()) + else if (retryMode == "adaptive") { - return; - } - - region = Aws::Config::GetCachedConfigValue("region"); - if (!region.empty()) - { - return; - } - - if (Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") - { - auto client = Aws::Internal::GetEC2MetadataClient(); - if (client) + if (maxAttempts < 0) { - region = client->GetCurrentRegion(); + // 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); } } - - if (!region.empty()) + else { - return; + retryStrategy = Aws::MakeShared<DefaultRetryStrategy>(CLIENT_CONFIG_TAG); } - region = Aws::String(Aws::Region::US_EAST_1); + return retryStrategy; } -ClientConfiguration::ClientConfiguration(const char* profile) : ClientConfiguration() +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) { - 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 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 << ";"; } - return; + 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; } - AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "User specified profile: [" << profile << "] is not found, will use the SDK resolved one."); + return option; } } // namespace Client diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp index 8c2c288dcd4..50a7f9308d8 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/CoreErrors.cpp @@ -18,7 +18,8 @@ using namespace Aws::Http; #pragma warning(disable : 4592) #endif -static Aws::UniquePtr<Aws::Map<Aws::String, AWSError<CoreErrors> > > s_CoreErrorsMapper(nullptr); +using ErrorsMapperContainer = Aws::Map<Aws::String, AWSError<CoreErrors> >; +static ErrorsMapperContainer* s_CoreErrorsMapper(nullptr); #ifdef _MSC_VER #pragma warning(pop) @@ -30,7 +31,7 @@ void CoreErrorsMapper::InitCoreErrorsMapper() { return; } - s_CoreErrorsMapper = Aws::MakeUnique<Aws::Map<Aws::String, AWSError<CoreErrors> > >("InitCoreErrorsMapper"); + s_CoreErrorsMapper = Aws::New<ErrorsMapperContainer>("InitCoreErrorsMapper"); s_CoreErrorsMapper->emplace("IncompleteSignature", AWSError<CoreErrors>(CoreErrors::INCOMPLETE_SIGNATURE, false)); s_CoreErrorsMapper->emplace("IncompleteSignatureException", AWSError<CoreErrors>(CoreErrors::INCOMPLETE_SIGNATURE, false)); @@ -92,10 +93,8 @@ void CoreErrorsMapper::InitCoreErrorsMapper() void CoreErrorsMapper::CleanupCoreErrorsMapper() { - if (s_CoreErrorsMapper) - { - s_CoreErrorsMapper = nullptr; - } + Aws::Delete(s_CoreErrorsMapper); + s_CoreErrorsMapper = nullptr; } AWSError<CoreErrors> CoreErrorsMapper::GetErrorForName(const char* errorName) @@ -149,3 +148,12 @@ AWS_CORE_API AWSError<CoreErrors> CoreErrorsMapper::GetErrorForHttpResponseCode( error.SetResponseCode(code); return error; } + +/** + * Overload ostream operator<< for CoreErrors enum class for a prettier output such as "103" and not "<67-00 00-00>" + */ +Aws::OStream& Aws::Client::operator<< (Aws::OStream& oStream, CoreErrors code) +{ + oStream << Aws::Utils::StringUtils::to_string(static_cast<typename std::underlying_type<HttpResponseCode>::type>(code)); + return oStream; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp index 7e57c79ffc4..405d7566cfb 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/DefaultRetryStrategy.cpp @@ -28,5 +28,5 @@ long DefaultRetryStrategy::CalculateDelayBeforeNextRetry(const AWSError<CoreErro return 0; } - return (1 << attemptedRetries) * m_scaleFactor; + return (1UL << attemptedRetries) * m_scaleFactor; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/GenericClientConfiguration.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/GenericClientConfiguration.cpp new file mode 100644 index 00000000000..f0a4e91d5ba --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/GenericClientConfiguration.cpp @@ -0,0 +1,103 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/GenericClientConfiguration.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <aws/core/utils/threading/Executor.h> + + +namespace Aws +{ +namespace Client +{ +template struct AWS_CORE_API GenericClientConfiguration<false>; + +bool IsEndpointDiscoveryEnabled(const Aws::String& endpointOverride, const Aws::String &profileName) +{ + bool enabled = true; // default value for AWS Services with enabled discovery trait + if (!endpointOverride.empty()) + { + enabled = false; + } + else + { + static const char* AWS_ENABLE_ENDPOINT_DISCOVERY_ENV_KEY = "AWS_ENABLE_ENDPOINT_DISCOVERY"; + static const char* AWS_ENABLE_ENDPOINT_DISCOVERY_PROFILE_KEY = "AWS_ENABLE_ENDPOINT_DISCOVERY"; + static const char* AWS_ENABLE_ENDPOINT_ENABLED = "true"; + static const char* AWS_ENABLE_ENDPOINT_DISABLED = "false"; + + Aws::String enableEndpointDiscovery = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_ENABLE_ENDPOINT_DISCOVERY_ENV_KEY, + profileName, + AWS_ENABLE_ENDPOINT_DISCOVERY_PROFILE_KEY, + {AWS_ENABLE_ENDPOINT_ENABLED, AWS_ENABLE_ENDPOINT_DISABLED}, + AWS_ENABLE_ENDPOINT_ENABLED); + + if (AWS_ENABLE_ENDPOINT_DISABLED == enableEndpointDiscovery) + { + // enabled by default unless explicitly disabled in ENV, profile config file, or programmatically later + enabled = false; + } + } + return enabled; +} + +GenericClientConfiguration<true>::GenericClientConfiguration() + : ClientConfiguration(), + enableHostPrefixInjection(ClientConfiguration::enableHostPrefixInjection), + enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) +{ + enableEndpointDiscovery = IsEndpointDiscoveryEnabled(this->endpointOverride, this->profileName); + enableHostPrefixInjection = false; // disabled by default in the SDK +} + +GenericClientConfiguration<true>::GenericClientConfiguration(const char* inputProfileName, bool shouldDisableIMDS) + : ClientConfiguration(inputProfileName, shouldDisableIMDS), + enableHostPrefixInjection(ClientConfiguration::enableHostPrefixInjection), + enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) +{ + enableEndpointDiscovery = IsEndpointDiscoveryEnabled(this->endpointOverride, this->profileName); + enableHostPrefixInjection = false; // disabled by default in the SDK +} + +GenericClientConfiguration<true>::GenericClientConfiguration(bool useSmartDefaults, const char* inputDefaultMode, bool shouldDisableIMDS) + : ClientConfiguration(useSmartDefaults, inputDefaultMode, shouldDisableIMDS), + enableHostPrefixInjection(ClientConfiguration::enableHostPrefixInjection), + enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) +{ + enableEndpointDiscovery = IsEndpointDiscoveryEnabled(this->endpointOverride, this->profileName); + enableHostPrefixInjection = false; // disabled by default in the SDK +} + +GenericClientConfiguration<true>::GenericClientConfiguration(const ClientConfiguration& config) + : ClientConfiguration(config), + enableHostPrefixInjection(ClientConfiguration::enableHostPrefixInjection), + enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) +{ + enableEndpointDiscovery = IsEndpointDiscoveryEnabled(this->endpointOverride, this->profileName); + enableHostPrefixInjection = false; // disabled by default in the SDK +} + +GenericClientConfiguration<true>::GenericClientConfiguration(const GenericClientConfiguration<true>& other) + : ClientConfiguration(static_cast<ClientConfiguration>(other)), + enableHostPrefixInjection(ClientConfiguration::enableHostPrefixInjection), + enableEndpointDiscovery(ClientConfiguration::enableEndpointDiscovery) +{ + if (other.enableEndpointDiscovery) { + enableEndpointDiscovery = other.enableEndpointDiscovery.value(); + } + enableHostPrefixInjection = other.enableHostPrefixInjection; +} + +GenericClientConfiguration<true>& GenericClientConfiguration<true>::operator=(const GenericClientConfiguration<true>& other) +{ + if (this != &other) { + *static_cast<ClientConfiguration*>(this) = static_cast<ClientConfiguration>(other); + } + return *this; +} + +} // namespace Client +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RequestCompression.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RequestCompression.cpp new file mode 100644 index 00000000000..e51a49049b7 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RequestCompression.cpp @@ -0,0 +1,336 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/client/RequestCompression.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/memory/AWSMemory.h> +#include <algorithm> +#include <aws/core/utils/memory/stl/AWSAllocator.h> + +#ifdef ENABLED_ZLIB_REQUEST_COMPRESSION +#include "zlib.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +#include <fcntl.h> +#include <io.h> +#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +#define SET_BINARY_MODE(file) +#endif // defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +// Defining zlib chunks to be 256k +static const size_t ZLIB_CHUNK=263144; +static const char AWS_REQUEST_COMPRESSION_ALLOCATION_TAG[] = + "RequestCompressionAlloc"; +#endif // ENABLED_ZLIB_REQUEST_COMPRESSION + +static const char AWS_REQUEST_COMPRESSION_LOG_TAG[] = "RequestCompression"; + +Aws::String Aws::Client::GetCompressionAlgorithmId(const CompressionAlgorithm &algorithm) +{ + switch (algorithm) + { + case CompressionAlgorithm::GZIP: + return "gzip"; + default: + return ""; + } +} + +#ifdef ENABLED_ZLIB_REQUEST_COMPRESSION +#ifdef USE_AWS_MEMORY_MANAGEMENT +static const char* ZlibMemTag = "zlib"; +static const size_t offset = sizeof(size_t); // to make space for size of the array +//Define custom memory allocation for zlib +// if fail to allocate, return Z_NULL +void* aws_zalloc(void * /* opaque */, unsigned items, unsigned size) +{ + unsigned sizeToAllocate = items*size; + size_t sizeToAllocateWithOffset = sizeToAllocate + offset; + if ((size != 0 && sizeToAllocate / size != items) + || (sizeToAllocateWithOffset <= sizeToAllocate )) + { + return Z_NULL; + } + char* newMem = reinterpret_cast<char*>(Aws::Malloc(ZlibMemTag, sizeToAllocateWithOffset)); + if (newMem != nullptr) { + std::size_t* pointerToSize = reinterpret_cast<std::size_t*>(newMem); + *pointerToSize = size; + return reinterpret_cast<void*>(newMem + offset); + } + else + { + return Z_NULL; + } +} + +void aws_zfree(void * /* opaque */, void * ptr) +{ + if(ptr) + { + char* shiftedMemory = reinterpret_cast<char*>(ptr); + Aws::Free(shiftedMemory - offset); + } +} + +#endif // AWS_CUSTOM_MEMORY_MANAGEMENT +#endif // ENABLED_ZLIB_REQUEST_COMPRESSION + + +iostream_outcome Aws::Client::RequestCompression::compress(std::shared_ptr<Aws::IOStream> input, + const CompressionAlgorithm &algorithm) const +{ +#ifdef ENABLED_ZLIB_REQUEST_COMPRESSION + if (algorithm == CompressionAlgorithm::GZIP) + { + // calculating stream size + input->seekg(0, input->end); + size_t streamSize = input->tellg(); + input->seekg(0, input->beg); + + AWS_LOGSTREAM_TRACE(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressing request of " << streamSize << " bytes."); + + // Preparing output + std::shared_ptr<Aws::IOStream> output = Aws::MakeShared<Aws::StringStream>(AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!output) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate output while compressing") + return false; + } + // Prepare ZLIB to compress + int ret = Z_NULL; + int flush = Z_NO_FLUSH; + z_stream strm = {}; + auto in = Aws::MakeUniqueArray<unsigned char>(ZLIB_CHUNK, AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!in) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate in buffer while compressing") + return false; + } + + auto out = Aws::MakeUniqueArray<unsigned char>(ZLIB_CHUNK, AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!out) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate out buffer while compressing") + return false; + } + + //Preparing allocators +#ifdef USE_AWS_MEMORY_MANAGEMENT + strm.zalloc = (void *(*)(void *, unsigned, unsigned)) aws_zalloc; + strm.zfree = (void (*)(void *, void *)) aws_zfree; +#else + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; +#endif + strm.opaque = Z_NULL; + + const int MAX_WINDOW_GZIP = 31; + const int DEFAULT_MEM_LEVEL_USAGE = 8; + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WINDOW_GZIP, DEFAULT_MEM_LEVEL_USAGE, Z_DEFAULT_STRATEGY); + if(ret != Z_OK) + { + return false; + } + + //Adding one to the stream size counter to account for the EOF marker. + streamSize++; + size_t toRead; + // Compress + do { + toRead = std::min(streamSize, ZLIB_CHUNK); + // Fill the buffer + if (! input->read(reinterpret_cast<char *>(in.get()), toRead)) + { + if (input->eof()) + { + //Last read need flush when exit loop + flush = Z_FINISH; + } + else { + AWS_LOGSTREAM_ERROR( + AWS_REQUEST_COMPRESSION_LOG_TAG, + "Uncompress request failed to read from stream"); + return false; + } + } + streamSize -= toRead; //left to read + strm.avail_in = (flush == Z_FINISH)?toRead-1:toRead; //skip EOF if included + strm.next_in = in.get(); + do + { + // Run deflate on buffers + strm.avail_out = ZLIB_CHUNK; + strm.next_out = out.get(); + + ret = deflate(&strm, flush); + + // writing the output + assert(ZLIB_CHUNK >= strm.avail_out); + unsigned output_size = ZLIB_CHUNK - strm.avail_out; + if(! output->write(reinterpret_cast<char *>(out.get()), output_size)) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressed request failed to write to output stream"); + return false; + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); // All data was read + } while (flush != Z_FINISH); + assert(ret == Z_STREAM_END); // Completed stream + AWS_LOGSTREAM_TRACE(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressed request to: " << strm.total_out << " bytes"); + deflateEnd(&strm); + return output; + } + else + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compress request requested in runtime without support: " << GetCompressionAlgorithmId(algorithm)); + return false; + } +#else + // If there is no support to compress, always fail calls to this method. + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compress request requested in runtime without support: " << GetCompressionAlgorithmId(algorithm)); + AWS_UNREFERENCED_PARAM(input); // silencing warning; + return false; +#endif +} + +Aws::Utils::Outcome<std::shared_ptr<Aws::IOStream>, bool> +Aws::Client::RequestCompression::uncompress(std::shared_ptr<Aws::IOStream> input, const CompressionAlgorithm &algorithm) const +{ +#ifdef ENABLED_ZLIB_REQUEST_COMPRESSION + if (algorithm == CompressionAlgorithm::GZIP) + { + // calculating stream size + input->seekg(0, input->end); + size_t streamSize = input->tellg(); + input->seekg(0, input->beg); + + AWS_LOGSTREAM_TRACE(AWS_REQUEST_COMPRESSION_LOG_TAG, "Uncompressing request of " << streamSize << " bytes."); + + // Preparing output + std::shared_ptr<Aws::IOStream> output = Aws::MakeShared<Aws::StringStream>( AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!output) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate output while uncompressing") + return false; + } + + // Prepare ZLIB to uncompress + int ret = Z_NULL; + z_stream strm = {}; + auto in = Aws::MakeUniqueArray<unsigned char>(ZLIB_CHUNK, AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!in) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate in buffer while uncompressing") + return false; + } + + auto out = Aws::MakeUniqueArray<unsigned char>(ZLIB_CHUNK, AWS_REQUEST_COMPRESSION_ALLOCATION_TAG); + if(!out) + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to allocate out buffer while uncompressing") + return false; + } + + //preparing allocation +#ifdef USE_AWS_MEMORY_MANAGEMENT + strm.zalloc = (void *(*)(void *, unsigned, unsigned)) aws_zalloc; + strm.zfree = (void (*)(void *, void *)) aws_zfree; +#else + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; +#endif + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + + const int MAX_WINDOW_GZIP = 31; + ret = inflateInit2(&strm, MAX_WINDOW_GZIP); + if (ret != Z_OK) + { + return false; + } + + //Adding one to the stream size counter to account for the EOF marker. + streamSize++; + size_t toRead; + // Decompress + do { + toRead = (streamSize < ZLIB_CHUNK)?streamSize:ZLIB_CHUNK; + if (toRead < 1) break; // Nothing left to read + // Fill the buffer + if(! input->read(reinterpret_cast<char *>(in.get()), toRead)) + { + if (input->eof()) + { + //skip passing the EOF to the buffer + toRead--; + } + else + { + AWS_LOGSTREAM_ERROR( + AWS_REQUEST_COMPRESSION_LOG_TAG, + "Compress request failed to read from stream"); + return false; + } + } + + // Filling input buffer to decompress + strm.avail_in = toRead; + strm.next_in = in.get(); + do + { + // Run inflate on buffers + strm.avail_out = ZLIB_CHUNK; + strm.next_out = out.get(); + + ret = inflate(&strm, Z_NO_FLUSH); + // Catch errors + switch (ret) + { + case Z_NEED_DICT: + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressed request failed to inflate with code: Z_NEED_DICT"); + return false; + case Z_DATA_ERROR: + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressed request failed to inflate with code: Z_DATA_ERROR"); + return false; + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Compressed request failed to inflate with code: Z_MEM_ERROR"); + return false; + } + + // writing the output + unsigned output_size = ZLIB_CHUNK - strm.avail_out; + if(! output->write(reinterpret_cast<char *>(out.get()), output_size)) { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Uncompressed request failed to write to output stream"); + return false; + } + } while (strm.avail_out == 0); + } while (ret != Z_STREAM_END); + // clean up + (void)inflateEnd(&strm); + if (ret == Z_STREAM_END) + { + AWS_LOGSTREAM_TRACE(AWS_REQUEST_COMPRESSION_LOG_TAG, "Decompressed request to: " << strm.total_out << " bytes"); + return output; + } + else + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Failed to decompress after read input completely"); + return false; + } + } + else + { + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Uncompress request requested in runtime without support: " << GetCompressionAlgorithmId(algorithm)); + return false; + } +#else + // If there is no support to compress, always fail calls to this method. + AWS_LOGSTREAM_ERROR(AWS_REQUEST_COMPRESSION_LOG_TAG, "Uncompress request requested in runtime without support: " << GetCompressionAlgorithmId(algorithm)); + AWS_UNREFERENCED_PARAM(input); // silencing warning; + return false; +#endif +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp index b439b7ca995..77b6f5abbbd 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/client/RetryStrategy.cpp @@ -17,18 +17,21 @@ namespace Aws { static const int INITIAL_RETRY_TOKENS = 500; static const int RETRY_COST = 5; - static const int NO_RETRY_INCREMENT = 1; static const int TIMEOUT_RETRY_COST = 10; StandardRetryStrategy::StandardRetryStrategy(long maxAttempts) : m_retryQuotaContainer(Aws::MakeShared<DefaultRetryQuotaContainer>("StandardRetryStrategy")), m_maxAttempts(maxAttempts) - {} + { + srand((unsigned int)time(NULL)); + } StandardRetryStrategy::StandardRetryStrategy(std::shared_ptr<RetryQuotaContainer> retryQuotaContainer, long maxAttempts) : m_retryQuotaContainer(retryQuotaContainer), m_maxAttempts(maxAttempts) - {} + { + srand((unsigned int)time(NULL)); + } void StandardRetryStrategy::RequestBookkeeping(const HttpResponseOutcome& httpResponseOutcome) { @@ -60,7 +63,8 @@ namespace Aws long StandardRetryStrategy::CalculateDelayBeforeNextRetry(const AWSError<CoreErrors>& error, long attemptedRetries) const { AWS_UNREFERENCED_PARAM(error); - return (std::min)(rand() % 1000 * (1 << attemptedRetries), 20000); + // Maximum left shift factor is capped by ceil(log2(max_delay)), to avoid wrap-around and overflow into negative values: + return (std::min)(rand() % 1000 * (1 << (std::min)(attemptedRetries, 15L)), 20000); } DefaultRetryQuotaContainer::DefaultRetryQuotaContainer() : m_retryQuota(INITIAL_RETRY_TOKENS) @@ -99,4 +103,4 @@ namespace Aws ReleaseRetryQuota(capacityAmount); } } -}
\ No newline at end of file +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp new file mode 100644 index 00000000000..ba0079bb5e8 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSConfigFileProfileConfigLoader.cpp @@ -0,0 +1,629 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/utils/memory/stl/AWSSet.h> +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char REGION_KEY[] = "region"; + static const char ACCESS_KEY_ID_KEY[] = "aws_access_key_id"; + static const char SECRET_KEY_KEY[] = "aws_secret_access_key"; + static const char SESSION_TOKEN_KEY[] = "aws_session_token"; + static const char SSO_START_URL_KEY[] = "sso_start_url"; + static const char SSO_REGION_KEY[] = "sso_region"; + static const char SSO_ACCOUNT_ID_KEY[] = "sso_account_id"; + static const char SSO_ROLE_NAME_KEY[] = "sso_role_name"; + static const char SSO_SESSION_KEY[] = "sso_session"; + static const char ROLE_ARN_KEY[] = "role_arn"; + static const char EXTERNAL_ID_KEY[] = "external_id"; + static const char CREDENTIAL_PROCESS_COMMAND[] = "credential_process"; + static const char SOURCE_PROFILE_KEY[] = "source_profile"; + static const char PROFILE_SECTION[] = "profile"; + static const char DEFAULT[] = "default"; + static const char SSO_SESSION_SECTION[] = "sso-session"; + static const char DEFAULTS_MODE_KEY[] = "defaults_mode"; + static const char EQ = '='; + static const char LEFT_BRACKET = '['; + static const char RIGHT_BRACKET = ']'; + static const char PARSER_TAG[] = "Aws::Config::ConfigFileProfileFSM"; + + // generated by python from identifier regex pattern from the spec: R"([A-Za-z0-9_\-/.%@:\+]+)": + // #py: ''.join(chr(i) for i in range(128) if re.match("[A-Za-z0-9_\-\/.%@:\+]", chr(i))) + const char IDENTIFIER_ALLOWED_CHARACTERS[] = R"(%+-./0123456789:@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz)"; + static const size_t IDENTIFIER_ALLOWED_CHARACTERS_SZ = sizeof(IDENTIFIER_ALLOWED_CHARACTERS) - 1; + const char WHITESPACE_CHARACTERS[] = "\t "; + static const size_t WHITESPACE_CHARACTERS_SZ = sizeof(WHITESPACE_CHARACTERS) - 1; + const char COMMENT_START[] = "#;"; + static const size_t COMMENT_START_SZ = sizeof(COMMENT_START) - 1; + + struct ProfilePropertyAccessFunctions + { + const char* PropertyKey; + std::function<void(Profile&, const Aws::String&)> Setter; + std::function<const Aws::String&(const Profile&)> Getter; + }; + + static const ProfilePropertyAccessFunctions PROFILE_PROPERTY_FUNCS[] = + {{REGION_KEY, &Profile::SetRegion, &Profile::GetRegion}, + //ACCESS_KEY_ID_KEY, - AwsCredentials require special handling + //SECRET_KEY_KEY, + //SESSION_TOKEN_KEY, + {SSO_START_URL_KEY, &Profile::SetSsoStartUrl, &Profile::GetSsoStartUrl}, + {SSO_REGION_KEY, &Profile::SetSsoRegion, &Profile::GetSsoRegion}, + {SSO_ACCOUNT_ID_KEY, &Profile::SetSsoAccountId, &Profile::GetSsoAccountId}, + {SSO_ROLE_NAME_KEY, &Profile::SetSsoRoleName, &Profile::GetSsoRoleName}, + //SSO_SESSION_KEY - SsoSession requires special handling + {ROLE_ARN_KEY, &Profile::SetRoleArn, &Profile::GetRoleArn}, + {EXTERNAL_ID_KEY, &Profile::SetExternalId, &Profile::GetExternalId}, + {CREDENTIAL_PROCESS_COMMAND, &Profile::SetCredentialProcess, &Profile::GetCredentialProcess}, + {SOURCE_PROFILE_KEY, &Profile::SetSourceProfile, &Profile::GetSourceProfile}, + {DEFAULTS_MODE_KEY, &Profile::SetDefaultsMode, &Profile::GetDefaultsMode}}; + + template<typename EntryT, size_t N> + const EntryT* FindInStaticArray(const EntryT (&array)[N], const Aws::String& searchKey) + { + const EntryT* found = std::find_if(array, array + N, + [&searchKey](const EntryT& entry) + { + return searchKey == entry.PropertyKey; + }); + + if(!!found && found != array + N) + return found; + + return nullptr; + } + + static const char* PROFILE_KEY_SPECIAL_HANDLING[] = + {ACCESS_KEY_ID_KEY, SECRET_KEY_KEY, SESSION_TOKEN_KEY, SSO_SESSION_KEY}; + static const size_t PROFILE_KEY_SPECIAL_HANDLING_SZ = sizeof(PROFILE_KEY_SPECIAL_HANDLING) / sizeof(PROFILE_KEY_SPECIAL_HANDLING[0]); + + struct SsoSessionPropertyAccessFunctions + { + const char* PropertyKey; + std::function<void(Profile::SsoSession&, const Aws::String&)> Setter; + std::function<const Aws::String&(const Profile::SsoSession&)> Getter; + }; + static const SsoSessionPropertyAccessFunctions SSO_SESSION_PROPERTY_FUNCS[] = + {{SSO_REGION_KEY, &Profile::SsoSession::SetSsoRegion, &Profile::SsoSession::GetSsoRegion}, + {SSO_START_URL_KEY, &Profile::SsoSession::SetSsoStartUrl, &Profile::SsoSession::GetSsoStartUrl}}; + + class ConfigFileProfileFSM + { + public: + ConfigFileProfileFSM(bool useProfilePrefix) + : m_useProfilePrefix(useProfilePrefix) + {} + + const Aws::Map<String, Profile>& GetProfiles() const { return m_foundProfiles; } + + void ParseStream(Aws::IStream& stream) + { + static const size_t ASSUME_EMPTY_LEN = 3; + State currentState = START; + Aws::String currentSectionName; + Aws::Map<Aws::String, Aws::String> currentKeyValues; + + Aws::String rawLine; + while(std::getline(stream, rawLine) && currentState != FAILURE) + { + Aws::String line = rawLine.substr(0, rawLine.find_first_of(COMMENT_START)); // ignore comments + if (line.empty() || line.length() < ASSUME_EMPTY_LEN || line.find_first_not_of(WHITESPACE_CHARACTERS) == Aws::String::npos) + { + continue; + } + + auto openPos = line.find(LEFT_BRACKET); + auto closePos = line.find(RIGHT_BRACKET); + + if(openPos != std::string::npos && closePos != std::string::npos) + { + FlushSection(currentState, currentSectionName, currentKeyValues); + currentKeyValues.clear(); + ParseSectionDeclaration(line, currentSectionName, currentState); + continue; + } + + if(PROFILE_FOUND == currentState || SSO_SESSION_FOUND == currentState) + { + auto equalsPos = line.find(EQ); + if (equalsPos != std::string::npos) + { + auto key = StringUtils::Trim(line.substr(0, equalsPos).c_str()); + auto value = StringUtils::Trim(line.substr(equalsPos + 1).c_str()); + currentKeyValues[key] = value; + continue; + } + } + + if(UNKNOWN_SECTION_FOUND == currentState) + { + // skip any unknown sections + continue; + } + + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Unexpected line in the aws shared profile: " << rawLine); + currentState = FAILURE; + break; + } + + FlushSection(currentState, currentSectionName, currentKeyValues); + + // Put sso-sessions into profiles + for(auto& profile : m_foundProfiles) + { + const Aws::String& profileSsoSessionName = profile.second.GetValue(SSO_SESSION_KEY); + if(!profileSsoSessionName.empty()) + { + auto ssoSessionIt = m_foundSsoSessions.find(profileSsoSessionName); + if(ssoSessionIt == m_foundSsoSessions.end()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "AWS profile has reference to a missing sso_session: " << profileSsoSessionName); + currentState = FAILURE; + continue; + } + auto ssoSession = ssoSessionIt->second; + auto prof = profile.second; + // If sso session and profile have conflicting start url or region, fail to parse + // the session/sso specific profile properties + auto hasConflictingStartUrls = !ssoSession.GetSsoStartUrl().empty() + && !prof.GetSsoStartUrl().empty() + && ssoSession.GetSsoStartUrl() != prof.GetSsoStartUrl(); + auto hasConflictingRegions = !ssoSession.GetSsoRegion().empty() + && !prof.GetSsoRegion().empty() + && ssoSession.GetSsoRegion() != prof.GetSsoRegion(); + if (hasConflictingStartUrls || hasConflictingRegions) { + AWS_LOGSTREAM_ERROR(PARSER_TAG, + "SSO profile has a start url or region conflict with sso session"); + prof.SetSsoStartUrl(""); + prof.SetSsoRegion(""); + prof.SetSsoAccountId(""); + prof.SetSsoRoleName(""); + continue; + } + profile.second.SetSsoSession(ssoSessionIt->second); + } + } + + if(FAILURE == currentState) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "AWS shared profile config parsing failed"); + } + } + + private: + // true means Shared Config parsing, false means Shared Credentials parsing + bool m_useProfilePrefix = false; + + enum State + { + START = 0, + PROFILE_FOUND, + SSO_SESSION_FOUND, + UNKNOWN_SECTION_FOUND, + FAILURE + }; + + /** + * Helper function to parse a single word (aka section identifier) containing allowed characters from a line and a pos + * i.e. line="[ profile default ]";identifierBegin=10 will return "default" + * @param line, a section definition line being parsed + * @param identifierBegin, an Aws::String position to start parsing + * @param oErrorMsg, a reference to Aws::String to store error message in case of a parsing error. + * @return Aws::String, e.g. "default" + */ + Aws::String ParseIdentifier(const Aws::String& line, Aws::String::size_type identifierBegin, Aws::String& oErrorMsg) + { + // pos at the beginning of section Identifier (or sso_session section keyword) + Aws::String::size_type identifierLength = 0; + Aws::String::size_type pos = identifierBegin; + while(pos < line.length()) + { + if(std::find(IDENTIFIER_ALLOWED_CHARACTERS, + IDENTIFIER_ALLOWED_CHARACTERS + IDENTIFIER_ALLOWED_CHARACTERS_SZ, + line[pos]) != IDENTIFIER_ALLOWED_CHARACTERS + IDENTIFIER_ALLOWED_CHARACTERS_SZ) + { + identifierLength++; + pos++; + } + else + { + break; + } + } + const Aws::String SECTION_END_CHARS_TO_SKIP = Aws::String(WHITESPACE_CHARACTERS) + RIGHT_BRACKET; + + if(identifierLength == 0) + { + oErrorMsg = "identifier is missing"; + return ""; + } + if(pos >= line.size() || SECTION_END_CHARS_TO_SKIP.find(line[pos]) == Aws::String::npos) { + oErrorMsg = "a blank space character or closing bracket is expected after Identifier"; + return ""; + } + Aws::String sectionIdentifier = line.substr(identifierBegin, identifierLength); + + return sectionIdentifier; + } + + /** + * A helper function to parse config section declaration line + * @param line, an input line, e.g. "[profile default]" + * @param ioSectionName, a return argument representing parsed section Identifier, e.g. "default" + * @param ioState, a return argument representing parser state, e.g. PROFILE_FOUND + */ + void ParseSectionDeclaration(const Aws::String& line, + Aws::String& ioSectionName, + State& ioState) + { + do { // goto in a form of "do { break; } while(0);" + Aws::String::size_type pos = 0; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos != Aws::String::npos && LEFT_BRACKET != line[pos]) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "First non-blank space character of a section definition must be [, line:" << line); + break; + } + pos++; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos || pos >= line.size()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Unknown section found in the aws config file: " << line); + break; + } + bool defaultProfileOrSsoSectionRequired = false; + if (m_useProfilePrefix) + { + // in configuration files, the profile name must start with profile. (eg. [profile profile-name]), + // except where the profile name is default. When the profile name is default it may start with profile + static const size_t PROFILE_KEYWORD_LENGTH = 7; + if(line.rfind(PROFILE_SECTION, pos + PROFILE_KEYWORD_LENGTH) != Aws::String::npos) + { + // skipping required (optional for default) profile keyword + pos += PROFILE_KEYWORD_LENGTH; + if(pos >= line.size() || + std::find(WHITESPACE_CHARACTERS, + WHITESPACE_CHARACTERS + WHITESPACE_CHARACTERS_SZ, + line[pos]) == WHITESPACE_CHARACTERS + WHITESPACE_CHARACTERS_SZ) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a blank space after \"profile\" keyword: " << line); + break; + } + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + } + else + { + defaultProfileOrSsoSectionRequired = true; + } + } + + Aws::String errorMsg; + Aws::String sectionIdentifier = ParseIdentifier(line, pos, errorMsg); + if (!errorMsg.empty()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Failed to parse section identifier: " << errorMsg << " " << line); + break; + } + pos += sectionIdentifier.length(); + + if(defaultProfileOrSsoSectionRequired) + { + if (sectionIdentifier != DEFAULT && sectionIdentifier != SSO_SESSION_SECTION) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "In configuration files, the profile name must start with " + "profile keyword (except default profile): " << line); + break; + } + if (sectionIdentifier != SSO_SESSION_SECTION) + { + // profile found, still pending check for closing bracket + ioState = PROFILE_FOUND; + ioSectionName = sectionIdentifier; + } + } + + if(!m_useProfilePrefix || sectionIdentifier != SSO_SESSION_SECTION) + { + // profile found, still pending check for closing bracket + ioState = PROFILE_FOUND; + ioSectionName = sectionIdentifier; + } + + if(m_useProfilePrefix && sectionIdentifier == SSO_SESSION_SECTION) + { + // "[sso_session..." found, continue parsing for sso_session identifier + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a blank space after \"sso_session\" keyword: " << line); + break; + } + + sectionIdentifier = ParseIdentifier(line, pos, errorMsg); + if (!errorMsg.empty()) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Failed to parse section identifier: " << errorMsg << " " << line); + break; + } + pos += sectionIdentifier.length(); + // sso_session found, still pending check for closing bracket + ioState = SSO_SESSION_FOUND; + ioSectionName = sectionIdentifier; + } + + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos == Aws::String::npos) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Expected a non-blank space after section identifier (i.e. missing \"]\"): " << line); + break; + } + if(line[pos] != RIGHT_BRACKET) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Missing closing bracket after Section Identifier " + "(i.e. missing \"]\" or extra non-blank characters before \"]\"): " << line); + break; + } + pos++; + pos = line.find_first_not_of(WHITESPACE_CHARACTERS, pos); + if(pos != Aws::String::npos && + std::find(COMMENT_START, COMMENT_START + COMMENT_START_SZ, line[pos]) == COMMENT_START + COMMENT_START_SZ) + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "Found unexpected characters after closing bracket of Section Identifier " << line); + break; + } + // the rest is a comment, and we don't care about it. + if ((ioState != SSO_SESSION_FOUND && ioState != PROFILE_FOUND) || ioSectionName.empty()) + { + AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unexpected parser state after attempting to parse section " << line); + break; + } + return; + } while(0); // end of goto in a form of "do { break; } while(0);" + + ioSectionName.erase(); + ioState = UNKNOWN_SECTION_FOUND; + return; + } + + /** + * A helper function to store currently being parsed section along with its properties + * (i.e. [profile default] and its key1=val1 under). + * @param currentState, a current parser State, e.g. PROFILE_FOUND + * @param currentSectionName, a current section identifier, e.g. "default" + * @param currentKeyValues, a map of parsed key-value properties of a section definition being recorded + */ + void FlushSection(const State currentState, const Aws::String& currentSectionName, Aws::Map<Aws::String, Aws::String>& currentKeyValues) + { + if(START == currentState || currentSectionName.empty()) + { + return; //nothing to flush + } + + if(PROFILE_FOUND == currentState) + { + Profile& profile = m_foundProfiles[currentSectionName]; + + for(const auto& keyVal : currentKeyValues) + { + auto setterFuncPtr = FindInStaticArray(PROFILE_PROPERTY_FUNCS, keyVal.first); + if(setterFuncPtr) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Found " << setterFuncPtr->PropertyKey << " " << keyVal.second); + setterFuncPtr->Setter(profile, keyVal.second); + } + else + { + auto specialPropertyKey = std::find_if(PROFILE_KEY_SPECIAL_HANDLING, PROFILE_KEY_SPECIAL_HANDLING + PROFILE_KEY_SPECIAL_HANDLING_SZ, + [&keyVal](const char* entry) + { + return !!entry && keyVal.first == entry; + }); + + if (specialPropertyKey && specialPropertyKey != PROFILE_KEY_SPECIAL_HANDLING + PROFILE_KEY_SPECIAL_HANDLING_SZ) + { + AWS_LOGSTREAM_INFO(PARSER_TAG, "Unknown property: " << keyVal.first << " in the profile: " << currentSectionName); + } + } + } + + auto accessKeyIdIter = currentKeyValues.find(ACCESS_KEY_ID_KEY); + Aws::String accessKey, secretKey, sessionToken; + if (accessKeyIdIter != currentKeyValues.end()) + { + accessKey = accessKeyIdIter->second; + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found access key " << accessKey); + + auto secretAccessKeyIter = currentKeyValues.find(SECRET_KEY_KEY); + auto sessionTokenIter = currentKeyValues.find(SESSION_TOKEN_KEY); + if (secretAccessKeyIter != currentKeyValues.end()) + { + secretKey = secretAccessKeyIter->second; + } + else + { + AWS_LOGSTREAM_ERROR(PARSER_TAG, "No secret access key found even though an access key was specified. This will cause all signed AWS calls to fail."); + } + + if (sessionTokenIter != currentKeyValues.end()) + { + sessionToken = sessionTokenIter->second; + } + + profile.SetCredentials(Aws::Auth::AWSCredentials(accessKey, secretKey, sessionToken)); + } + + if (!profile.GetSsoStartUrl().empty() || !profile.GetSsoRegion().empty() + || !profile.GetSsoAccountId().empty() || !profile.GetSsoRoleName().empty()) + { + // If there is no sso session, all fields are required. If an SSO session is present, + // then only account id and sso role name are required. + auto hasSession = currentKeyValues.find(SSO_SESSION_KEY) != currentKeyValues.end(); + auto hasInvalidProfileWithoutSession = !hasSession && + (profile.GetSsoStartUrl().empty() + || profile.GetSsoRegion().empty() + || profile.GetSsoAccountId().empty() + || profile.GetSsoRoleName().empty()); + auto hasInvalidProfileWithSession = hasSession && + (profile.GetSsoAccountId().empty() + || profile.GetSsoRoleName().empty()); + if (hasInvalidProfileWithoutSession || hasInvalidProfileWithSession) { + profile.SetSsoStartUrl(""); + profile.SetSsoRegion(""); + profile.SetSsoAccountId(""); + profile.SetSsoRoleName(""); + AWS_LOGSTREAM_ERROR(PARSER_TAG, "invalid SSO configuration for aws profile " << currentSectionName); + } + } + + profile.SetName(currentSectionName); + profile.SetAllKeyValPairs(std::move(currentKeyValues)); + } + else if (SSO_SESSION_FOUND == currentState) { + Profile::SsoSession& ssoSession = m_foundSsoSessions[currentSectionName]; + for(const auto& keyVal : currentKeyValues) + { + auto setterFuncPtr = FindInStaticArray(SSO_SESSION_PROPERTY_FUNCS, keyVal.first); + if(setterFuncPtr) + { + AWS_LOGSTREAM_DEBUG(PARSER_TAG, "Found sso-session property " << setterFuncPtr->PropertyKey << " " << keyVal.second); + setterFuncPtr->Setter(ssoSession, keyVal.second); + } + else + { + AWS_LOGSTREAM_INFO(PARSER_TAG, "Unknown property: " << keyVal.first << " in the sso-session: " << currentSectionName); + } + } + ssoSession.SetName(currentSectionName); + ssoSession.SetAllKeyValPairs(std::move(currentKeyValues)); + } + else + { + AWS_LOGSTREAM_FATAL(PARSER_TAG, "Unknown parser error: unexpected state " << currentState); + } + } + + Aws::Map<String, Profile> m_foundProfiles; + Aws::Map<String, Profile::SsoSession> m_foundSsoSessions; + }; + + static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader"; + + AWSConfigFileProfileConfigLoader::AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix) : + m_fileName(fileName), m_useProfilePrefix(useProfilePrefix) + { + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Initializing config loader against fileName " + << fileName << " and using profilePrefix = " << useProfilePrefix); + } + + bool AWSConfigFileProfileConfigLoader::LoadInternal() + { + m_profiles.clear(); + + Aws::IFStream inputFile(m_fileName.c_str()); + if(inputFile) + { + ConfigFileProfileFSM parser(m_useProfilePrefix); + parser.ParseStream(inputFile); + m_profiles = parser.GetProfiles(); + return m_profiles.size() > 0; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for reading."); + + return false; + } + + bool AWSConfigFileProfileConfigLoader::PersistInternal(const Aws::Map<Aws::String, Profile>& profiles) + { + Aws::OFStream outputFile(m_fileName.c_str(), std::ios_base::out | std::ios_base::trunc); + if(outputFile) + { + Aws::UnorderedMap<Aws::String, std::reference_wrapper<const Profile::SsoSession>> ssoSessionsToDump; + + for(const auto& profile : profiles) + { + Aws::String prefix = m_useProfilePrefix ? PROFILE_SECTION : ""; + + AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing profile " << profile.first << " to disk."); + + outputFile << LEFT_BRACKET << prefix << " " << profile.second.GetName() << RIGHT_BRACKET << std::endl; + const Aws::Auth::AWSCredentials& credentials = profile.second.GetCredentials(); + if (!credentials.GetAWSAccessKeyId().empty()) { + outputFile << ACCESS_KEY_ID_KEY << EQ << credentials.GetAWSAccessKeyId() << std::endl; + } + if (!credentials.GetAWSSecretKey().empty()) { + outputFile << SECRET_KEY_KEY << EQ << credentials.GetAWSSecretKey() << std::endl; + } + if(!credentials.GetSessionToken().empty()) { + outputFile << SESSION_TOKEN_KEY << EQ << credentials.GetSessionToken() << std::endl; + } + // credentials.GetExpiration().Millis() <- is not present in a config. + + for(const auto& profilePropertyPair : PROFILE_PROPERTY_FUNCS) + { + const auto& profilePropertyValue = profilePropertyPair.Getter(profile.second); + if(!profilePropertyValue.empty()) + { + outputFile << profilePropertyPair.PropertyKey << EQ << profilePropertyValue << std::endl; + } + } + + if(profile.second.IsSsoSessionSet()) + { + const auto& ssoSession = profile.second.GetSsoSession(); + const auto alreadyScheduledForDumpIt = ssoSessionsToDump.find(ssoSession.GetName()); + if (alreadyScheduledForDumpIt != ssoSessionsToDump.end() && + alreadyScheduledForDumpIt->second.get() != ssoSession) + { + AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "2 or more profiles reference 'sso-session' section " + "with the same name but different properties: " << ssoSession.GetName()); + } + else + { + ssoSessionsToDump.insert({ssoSession.GetName(), std::cref(ssoSession)}); + } + outputFile << SSO_SESSION_KEY << EQ << ssoSession.GetName() << std::endl; + } + outputFile << std::endl; + } + + for(const auto& ssoSessionPair : ssoSessionsToDump) + { + AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing sso-session " << ssoSessionPair.first << " to disk."); + const Profile::SsoSession& ssoSession = ssoSessionPair.second.get(); + outputFile << LEFT_BRACKET << SSO_SESSION_SECTION << " " << ssoSession.GetName() << RIGHT_BRACKET << std::endl; + for(const auto& ssoSessionPropertyPair : SSO_SESSION_PROPERTY_FUNCS) + { + const auto& profilePropertyValue = ssoSessionPropertyPair.Getter(ssoSession); + if(!profilePropertyValue.empty()) + { + outputFile << ssoSessionPropertyPair.PropertyKey << EQ << profilePropertyValue << std::endl; + } + } + outputFile << std::endl; + } + + AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Profiles written to config file " << m_fileName); + + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for writing."); + + return false; + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp deleted file mode 100644 index bb6acd0b3a0..00000000000 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoader.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include <aws/core/config/AWSProfileConfigLoader.h> -#include <aws/core/internal/AWSHttpResourceClient.h> -#include <aws/core/auth/AWSCredentialsProvider.h> -#include <aws/core/utils/memory/stl/AWSList.h> -#include <aws/core/utils/memory/stl/AWSStreamFwd.h> -#include <aws/core/utils/StringUtils.h> -#include <aws/core/utils/logging/LogMacros.h> -#include <aws/core/utils/json/JsonSerializer.h> -#include <fstream> - -namespace Aws -{ - namespace Config - { - using namespace Aws::Utils; - using namespace Aws::Auth; - - static const char* const CONFIG_LOADER_TAG = "Aws::Config::AWSProfileConfigLoader"; - #ifdef _MSC_VER - // VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) - AWS_SUPPRESS_WARNING(4592, - static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); - ) - #else - static Aws::UniquePtr<ConfigAndCredentialsCacheManager> s_configManager(nullptr); - #endif - - static const char CONFIG_CREDENTIALS_CACHE_MANAGER_TAG[] = "ConfigAndCredentialsCacheManager"; - - bool AWSProfileConfigLoader::Load() - { - if(LoadInternal()) - { - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully reloaded configuration."); - m_lastLoadTime = DateTime::Now(); - AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "reloaded config at " - << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); - return true; - } - - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Failed to reload configuration."); - return false; - } - - bool AWSProfileConfigLoader::PersistProfiles(const Aws::Map<Aws::String, Profile>& profiles) - { - if(PersistInternal(profiles)) - { - AWS_LOGSTREAM_INFO(CONFIG_LOADER_TAG, "Successfully persisted configuration."); - m_profiles = profiles; - m_lastLoadTime = DateTime::Now(); - AWS_LOGSTREAM_TRACE(CONFIG_LOADER_TAG, "persisted config at " - << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); - return true; - } - - AWS_LOGSTREAM_WARN(CONFIG_LOADER_TAG, "Failed to persist configuration."); - return false; - } - - static const char REGION_KEY[] = "region"; - static const char ACCESS_KEY_ID_KEY[] = "aws_access_key_id"; - static const char SECRET_KEY_KEY[] = "aws_secret_access_key"; - static const char SESSION_TOKEN_KEY[] = "aws_session_token"; - static const char SSO_START_URL_KEY[] = "sso_start_url"; - static const char SSO_REGION_KEY[] = "sso_region"; - static const char SSO_ACCOUNT_ID_KEY[] = "sso_account_id"; - static const char SSO_ROLE_NAME_KEY[] = "sso_role_name"; - static const char ROLE_ARN_KEY[] = "role_arn"; - static const char EXTERNAL_ID_KEY[] = "external_id"; - static const char CREDENTIAL_PROCESS_COMMAND[] = "credential_process"; - static const char SOURCE_PROFILE_KEY[] = "source_profile"; - static const char PROFILE_PREFIX[] = "profile "; - static const char EQ = '='; - static const char LEFT_BRACKET = '['; - static const char RIGHT_BRACKET = ']'; - static const char PARSER_TAG[] = "Aws::Config::ConfigFileProfileFSM"; - - class ConfigFileProfileFSM - { - public: - ConfigFileProfileFSM() : m_parserState(START) {} - - const Aws::Map<String, Profile>& GetProfiles() const { return m_foundProfiles; } - - void ParseStream(Aws::IStream& stream) - { - static const size_t ASSUME_EMPTY_LEN = 3; - - Aws::String line; - while(std::getline(stream, line) && m_parserState != FAILURE) - { - if (line.empty() || line.length() < ASSUME_EMPTY_LEN) - { - continue; - } - - auto openPos = line.find(LEFT_BRACKET); - auto closePos = line.find(RIGHT_BRACKET); - - switch(m_parserState) - { - - case START: - if(openPos != std::string::npos && closePos != std::string::npos) - { - FlushProfileAndReset(line, openPos, closePos); - m_parserState = PROFILE_FOUND; - } - break; - - //fallthrough here is intentional to reduce duplicate logic - case PROFILE_KEY_VALUE_FOUND: - if(openPos != std::string::npos && closePos != std::string::npos) - { - m_parserState = PROFILE_FOUND; - FlushProfileAndReset(line, openPos, closePos); - break; - } - // fall through - case PROFILE_FOUND: - { - auto equalsPos = line.find(EQ); - if (equalsPos != std::string::npos) - { - auto key = line.substr(0, equalsPos); - auto value = line.substr(equalsPos + 1); - m_profileKeyValuePairs[StringUtils::Trim(key.c_str())] = - StringUtils::Trim(value.c_str()); - m_parserState = PROFILE_KEY_VALUE_FOUND; - } - - break; - } - default: - m_parserState = FAILURE; - break; - } - } - - FlushProfileAndReset(line, std::string::npos, std::string::npos); - } - - private: - - void FlushProfileAndReset(Aws::String& line, size_t openPos, size_t closePos) - { - if(!m_currentWorkingProfile.empty() && !m_profileKeyValuePairs.empty()) - { - Profile profile; - profile.SetName(m_currentWorkingProfile); - - auto regionIter = m_profileKeyValuePairs.find(REGION_KEY); - if (regionIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found region " << regionIter->second); - profile.SetRegion(regionIter->second); - } - - auto accessKeyIdIter = m_profileKeyValuePairs.find(ACCESS_KEY_ID_KEY); - Aws::String accessKey, secretKey, sessionToken; - if (accessKeyIdIter != m_profileKeyValuePairs.end()) - { - accessKey = accessKeyIdIter->second; - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found access key " << accessKey); - - auto secretAccessKeyIter = m_profileKeyValuePairs.find(SECRET_KEY_KEY); - auto sessionTokenIter = m_profileKeyValuePairs.find(SESSION_TOKEN_KEY); - if (secretAccessKeyIter != m_profileKeyValuePairs.end()) - { - secretKey = secretAccessKeyIter->second; - } - else - { - AWS_LOGSTREAM_ERROR(PARSER_TAG, "No secret access key found even though an access key was specified. This will cause all signed AWS calls to fail."); - } - - if (sessionTokenIter != m_profileKeyValuePairs.end()) - { - sessionToken = sessionTokenIter->second; - } - - profile.SetCredentials(Aws::Auth::AWSCredentials(accessKey, secretKey, sessionToken)); - } - - auto ssoStartUrlIter = m_profileKeyValuePairs.find(SSO_START_URL_KEY); - auto ssoRegionIter = m_profileKeyValuePairs.find(SSO_REGION_KEY); - auto ssoRoleNameIter = m_profileKeyValuePairs.find(SSO_ROLE_NAME_KEY); - auto ssoAccountIdIter = m_profileKeyValuePairs.find(SSO_ACCOUNT_ID_KEY); - if (ssoStartUrlIter != m_profileKeyValuePairs.end() - || ssoRegionIter != m_profileKeyValuePairs.end() - || ssoRoleNameIter != m_profileKeyValuePairs.end() - || ssoAccountIdIter != m_profileKeyValuePairs.end()) - { - if (ssoStartUrlIter != m_profileKeyValuePairs.end() - && ssoRegionIter != m_profileKeyValuePairs.end() - && ssoRoleNameIter != m_profileKeyValuePairs.end() - && ssoAccountIdIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_start_url " << ssoStartUrlIter->second); - profile.SetSsoStartUrl(ssoStartUrlIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_region " << ssoRegionIter->second); - profile.SetSsoRegion(ssoRegionIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_account_id " << ssoAccountIdIter->second); - profile.SetSsoAccountId(ssoAccountIdIter->second); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found sso_role_name " << ssoRoleNameIter->second); - profile.SetSsoRoleName(ssoRoleNameIter->second); - } else { - AWS_LOGSTREAM_ERROR(PARSER_TAG, "invalid configuration for sso profile " << profile.GetName()); - } - } - - auto assumeRoleArnIter = m_profileKeyValuePairs.find(ROLE_ARN_KEY); - if (assumeRoleArnIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found role arn " << assumeRoleArnIter->second); - profile.SetRoleArn(assumeRoleArnIter->second); - } - - auto externalIdIter = m_profileKeyValuePairs.find(EXTERNAL_ID_KEY); - if (externalIdIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found external id " << externalIdIter->second); - profile.SetExternalId(externalIdIter->second); - } - - auto sourceProfileIter = m_profileKeyValuePairs.find(SOURCE_PROFILE_KEY); - if (sourceProfileIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found source profile " << sourceProfileIter->second); - profile.SetSourceProfile(sourceProfileIter->second); - } - - auto credentialProcessIter = m_profileKeyValuePairs.find(CREDENTIAL_PROCESS_COMMAND); - if (credentialProcessIter != m_profileKeyValuePairs.end()) - { - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found credential process " << credentialProcessIter->second); - profile.SetCredentialProcess(credentialProcessIter->second); - } - profile.SetAllKeyValPairs(m_profileKeyValuePairs); - - m_foundProfiles[profile.GetName()] = std::move(profile); - m_currentWorkingProfile.clear(); - m_profileKeyValuePairs.clear(); - } - - if(!line.empty() && openPos != std::string::npos && closePos != std::string::npos) - { - m_currentWorkingProfile = StringUtils::Trim(line.substr(openPos + 1, closePos - openPos - 1).c_str()); - StringUtils::Replace(m_currentWorkingProfile, PROFILE_PREFIX, ""); - AWS_LOGSTREAM_DEBUG(PARSER_TAG, "found profile " << m_currentWorkingProfile); - } - } - - enum State - { - START = 0, - PROFILE_FOUND, - PROFILE_KEY_VALUE_FOUND, - FAILURE - }; - - Aws::String m_currentWorkingProfile; - Aws::Map<String, String> m_profileKeyValuePairs; - State m_parserState; - Aws::Map<String, Profile> m_foundProfiles; - }; - - static const char* const CONFIG_FILE_LOADER = "Aws::Config::AWSConfigFileProfileConfigLoader"; - - AWSConfigFileProfileConfigLoader::AWSConfigFileProfileConfigLoader(const Aws::String& fileName, bool useProfilePrefix) : - m_fileName(fileName), m_useProfilePrefix(useProfilePrefix) - { - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Initializing config loader against fileName " - << fileName << " and using profilePrefix = " << useProfilePrefix); - } - - bool AWSConfigFileProfileConfigLoader::LoadInternal() - { - m_profiles.clear(); - - Aws::IFStream inputFile(m_fileName.c_str()); - if(inputFile) - { - ConfigFileProfileFSM parser; - parser.ParseStream(inputFile); - m_profiles = parser.GetProfiles(); - return m_profiles.size() > 0; - } - - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for reading."); - - return false; - } - - bool AWSConfigFileProfileConfigLoader::PersistInternal(const Aws::Map<Aws::String, Profile>& profiles) - { - Aws::OFStream outputFile(m_fileName.c_str(), std::ios_base::out | std::ios_base::trunc); - if(outputFile) - { - for(auto& profile : profiles) - { - Aws::String prefix = m_useProfilePrefix ? PROFILE_PREFIX : ""; - - AWS_LOGSTREAM_DEBUG(CONFIG_FILE_LOADER, "Writing profile " << profile.first << " to disk."); - - outputFile << LEFT_BRACKET << prefix << profile.second.GetName() << RIGHT_BRACKET << std::endl; - const Aws::Auth::AWSCredentials& credentials = profile.second.GetCredentials(); - outputFile << ACCESS_KEY_ID_KEY << EQ << credentials.GetAWSAccessKeyId() << std::endl; - outputFile << SECRET_KEY_KEY << EQ << credentials.GetAWSSecretKey() << std::endl; - - if(!credentials.GetSessionToken().empty()) - { - outputFile << SESSION_TOKEN_KEY << EQ << credentials.GetSessionToken() << std::endl; - } - - if(!profile.second.GetRegion().empty()) - { - outputFile << REGION_KEY << EQ << profile.second.GetRegion() << std::endl; - } - - if(!profile.second.GetRoleArn().empty()) - { - outputFile << ROLE_ARN_KEY << EQ << profile.second.GetRoleArn() << std::endl; - } - - if(!profile.second.GetSourceProfile().empty()) - { - outputFile << SOURCE_PROFILE_KEY << EQ << profile.second.GetSourceProfile() << std::endl; - } - - outputFile << std::endl; - } - - AWS_LOGSTREAM_INFO(CONFIG_FILE_LOADER, "Profiles written to config file " << m_fileName); - - return true; - } - - AWS_LOGSTREAM_WARN(CONFIG_FILE_LOADER, "Unable to open config file " << m_fileName << " for writing."); - - return false; - } - - static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader"; - - EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client) - : m_ec2metadataClient(client == nullptr ? Aws::MakeShared<Aws::Internal::EC2MetadataClient>(EC2_INSTANCE_PROFILE_LOG_TAG) : client) - { - } - - bool EC2InstanceProfileConfigLoader::LoadInternal() - { - auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely(); - if(credentialsStr.empty()) return false; - - Json::JsonValue credentialsDoc(credentialsStr); - if (!credentialsDoc.WasParseSuccessful()) - { - AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, - "Failed to parse output from EC2MetadataService."); - return false; - } - const char* accessKeyId = "AccessKeyId"; - const char* secretAccessKey = "SecretAccessKey"; - Aws::String accessKey, secretKey, token; - - auto credentialsView = credentialsDoc.View(); - accessKey = credentialsView.GetString(accessKeyId); - AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG, - "Successfully pulled credentials from metadata service with access key " << accessKey); - - secretKey = credentialsView.GetString(secretAccessKey); - token = credentialsView.GetString("Token"); - - auto region = m_ec2metadataClient->GetCurrentRegion(); - - Profile profile; - profile.SetCredentials(AWSCredentials(accessKey, secretKey, token)); - profile.SetRegion(region); - profile.SetName(INSTANCE_PROFILE_KEY); - - m_profiles[INSTANCE_PROFILE_KEY] = profile; - - return true; - } - - ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() : - m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()), - m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/) - { - ReloadCredentialsFile(); - ReloadConfigFile(); - } - - void ConfigAndCredentialsCacheManager::ReloadConfigFile() - { - Aws::Utils::Threading::WriterLockGuard guard(m_configLock); - m_configFileLoader.SetFileName(Aws::Auth::GetConfigProfileFilename()); - m_configFileLoader.Load(); - } - - void ConfigAndCredentialsCacheManager::ReloadCredentialsFile() - { - Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock); - m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()); - m_credentialsFileLoader.Load(); - } - - bool ConfigAndCredentialsCacheManager::HasConfigProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - return (m_configFileLoader.GetProfiles().count(profileName) == 1); - } - - Aws::Config::Profile ConfigAndCredentialsCacheManager::GetConfigProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - const auto& profiles = m_configFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second; - } - - Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetConfigProfiles() const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - return m_configFileLoader.GetProfiles(); - } - - Aws::String ConfigAndCredentialsCacheManager::GetConfig(const Aws::String& profileName, const Aws::String& key) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); - const auto& profiles = m_configFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second.GetValue(key); - } - - bool ConfigAndCredentialsCacheManager::HasCredentialsProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - return (m_credentialsFileLoader.GetProfiles().count(profileName) == 1); - } - - Aws::Config::Profile ConfigAndCredentialsCacheManager::GetCredentialsProfile(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - const auto &profiles = m_credentialsFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second; - } - - Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetCredentialsProfiles() const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - return m_credentialsFileLoader.GetProfiles(); - } - - Aws::Auth::AWSCredentials ConfigAndCredentialsCacheManager::GetCredentials(const Aws::String& profileName) const - { - Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); - const auto& profiles = m_credentialsFileLoader.GetProfiles(); - const auto &iter = profiles.find(profileName); - if (iter == profiles.end()) - { - return {}; - } - return iter->second.GetCredentials(); - } - - void InitConfigAndCredentialsCacheManager() - { - if (s_configManager) - { - return; - } - s_configManager = Aws::MakeUnique<ConfigAndCredentialsCacheManager>(CONFIG_CREDENTIALS_CACHE_MANAGER_TAG); - } - - void CleanupConfigAndCredentialsCacheManager() - { - if (!s_configManager) - { - return; - } - s_configManager = nullptr; - } - - void ReloadCachedConfigFile() - { - assert(s_configManager); - s_configManager->ReloadConfigFile(); - } - - void ReloadCachedCredentialsFile() - { - assert(s_configManager); - s_configManager->ReloadCredentialsFile(); - } - - bool HasCachedConfigProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->HasConfigProfile(profileName); - } - - Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->GetConfigProfile(profileName); - } - - Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles() - { - assert(s_configManager); - return s_configManager->GetConfigProfiles(); - } - - Aws::String GetCachedConfigValue(const Aws::String &profileName, const Aws::String &key) - { - assert(s_configManager); - return s_configManager->GetConfig(profileName, key); - } - - Aws::String GetCachedConfigValue(const Aws::String &key) - { - assert(s_configManager); - return s_configManager->GetConfig(Aws::Auth::GetConfigProfileName(), key); - } - - bool HasCachedCredentialsProfile(const Aws::String& profileName) - { - assert(s_configManager); - return s_configManager->HasCredentialsProfile(profileName); - } - - Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String &profileName) - { - assert(s_configManager); - return s_configManager->GetCredentialsProfile(profileName); - } - - Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles() - { - assert(s_configManager); - return s_configManager->GetCredentialsProfiles(); - } - - Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String &profileName) - { - assert(s_configManager); - return s_configManager->GetCredentials(profileName); - } - } // Config namespace -} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp new file mode 100644 index 00000000000..cb7b19d0ceb --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/AWSProfileConfigLoaderBase.cpp @@ -0,0 +1,50 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoaderBase.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char* const CONFIG_LOADER_BASE_TAG = "Aws::Config::AWSProfileConfigLoaderBase"; + + bool AWSProfileConfigLoader::Load() + { + if(LoadInternal()) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Successfully reloaded configuration."); + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_BASE_TAG, "reloaded config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Failed to reload configuration."); + return false; + } + + bool AWSProfileConfigLoader::PersistProfiles(const Aws::Map<Aws::String, Profile>& profiles) + { + if(PersistInternal(profiles)) + { + AWS_LOGSTREAM_INFO(CONFIG_LOADER_BASE_TAG, "Successfully persisted configuration."); + m_profiles = profiles; + m_lastLoadTime = DateTime::Now(); + AWS_LOGSTREAM_TRACE(CONFIG_LOADER_BASE_TAG, "persisted config at " + << m_lastLoadTime.ToGmtString(DateFormat::ISO_8601)); + return true; + } + + AWS_LOGSTREAM_WARN(CONFIG_LOADER_BASE_TAG, "Failed to persist configuration."); + return false; + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp new file mode 100644 index 00000000000..b47fe72a0a2 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/ConfigAndCredentialsCacheManager.cpp @@ -0,0 +1,206 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/ConfigAndCredentialsCacheManager.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <fstream> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + #ifdef _MSC_VER + // VS2015 compiler's bug, warning s_CoreErrorsMapper: symbol will be dynamically initialized (implementation limitation) + AWS_SUPPRESS_WARNING(4592, + static ConfigAndCredentialsCacheManager* s_configManager(nullptr); + ) + #else + static ConfigAndCredentialsCacheManager* s_configManager(nullptr); + #endif + + static const char CONFIG_CREDENTIALS_CACHE_MANAGER_TAG[] = "ConfigAndCredentialsCacheManager"; + + + ConfigAndCredentialsCacheManager::ConfigAndCredentialsCacheManager() : + m_credentialsFileLoader(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()), + m_configFileLoader(Aws::Auth::GetConfigProfileFilename(), true/*use profile prefix*/) + { + ReloadCredentialsFile(); + ReloadConfigFile(); + } + + void ConfigAndCredentialsCacheManager::ReloadConfigFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_configLock); + m_configFileLoader.SetFileName(Aws::Auth::GetConfigProfileFilename()); + m_configFileLoader.Load(); + } + + void ConfigAndCredentialsCacheManager::ReloadCredentialsFile() + { + Aws::Utils::Threading::WriterLockGuard guard(m_credentialsLock); + m_credentialsFileLoader.SetFileName(Aws::Auth::ProfileConfigFileAWSCredentialsProvider::GetCredentialsProfileFilename()); + m_credentialsFileLoader.Load(); + } + + bool ConfigAndCredentialsCacheManager::HasConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return (m_configFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetConfigProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetConfigProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + return m_configFileLoader.GetProfiles(); + } + + Aws::String ConfigAndCredentialsCacheManager::GetConfig(const Aws::String& profileName, const Aws::String& key) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_configLock); + const auto& profiles = m_configFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetValue(key); + } + + bool ConfigAndCredentialsCacheManager::HasCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return (m_credentialsFileLoader.GetProfiles().count(profileName) == 1); + } + + Aws::Config::Profile ConfigAndCredentialsCacheManager::GetCredentialsProfile(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto &profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second; + } + + Aws::Map<Aws::String, Aws::Config::Profile> ConfigAndCredentialsCacheManager::GetCredentialsProfiles() const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + return m_credentialsFileLoader.GetProfiles(); + } + + Aws::Auth::AWSCredentials ConfigAndCredentialsCacheManager::GetCredentials(const Aws::String& profileName) const + { + Aws::Utils::Threading::ReaderLockGuard guard(m_credentialsLock); + const auto& profiles = m_credentialsFileLoader.GetProfiles(); + const auto &iter = profiles.find(profileName); + if (iter == profiles.end()) + { + return {}; + } + return iter->second.GetCredentials(); + } + + void InitConfigAndCredentialsCacheManager() + { + if (s_configManager) + { + return; + } + s_configManager = Aws::New<ConfigAndCredentialsCacheManager>(CONFIG_CREDENTIALS_CACHE_MANAGER_TAG); + } + + void CleanupConfigAndCredentialsCacheManager() + { + Aws::Delete(s_configManager); + s_configManager = nullptr; + } + + void ReloadCachedConfigFile() + { + assert(s_configManager); + s_configManager->ReloadConfigFile(); + } + + void ReloadCachedCredentialsFile() + { + assert(s_configManager); + s_configManager->ReloadCredentialsFile(); + } + + bool HasCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasConfigProfile(profileName); + } + + Aws::Config::Profile GetCachedConfigProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->GetConfigProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedConfigProfiles() + { + assert(s_configManager); + return s_configManager->GetConfigProfiles(); + } + + Aws::String GetCachedConfigValue(const Aws::String &profileName, const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(profileName, key); + } + + Aws::String GetCachedConfigValue(const Aws::String &key) + { + assert(s_configManager); + return s_configManager->GetConfig(Aws::Auth::GetConfigProfileName(), key); + } + + bool HasCachedCredentialsProfile(const Aws::String& profileName) + { + assert(s_configManager); + return s_configManager->HasCredentialsProfile(profileName); + } + + Aws::Config::Profile GetCachedCredentialsProfile(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentialsProfile(profileName); + } + + Aws::Map<Aws::String, Aws::Config::Profile> GetCachedCredentialsProfiles() + { + assert(s_configManager); + return s_configManager->GetCredentialsProfiles(); + } + + Aws::Auth::AWSCredentials GetCachedCredentials(const Aws::String &profileName) + { + assert(s_configManager); + return s_configManager->GetCredentials(profileName); + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp new file mode 100644 index 00000000000..0b505b2c003 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp @@ -0,0 +1,112 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/auth/AWSCredentialsProvider.h> +#include <aws/core/utils/memory/stl/AWSList.h> +#include <aws/core/utils/logging/LogMacros.h> +#include <aws/core/utils/json/JsonSerializer.h> +#include <fstream> +#include <random> + +namespace Aws +{ + namespace Config + { + using namespace Aws::Utils; + using namespace Aws::Auth; + + static const char* const INTERNAL_EXCEPTION_PHRASE = "InternalServiceException"; + static const int64_t FIVE_MINUTE_MILLIS = 60000 * 5; + static const int64_t TEN_MINUTE_MILLIS = 60000 * 10; + + static const char* const EC2_INSTANCE_PROFILE_LOG_TAG = "Aws::Config::EC2InstanceProfileConfigLoader"; + + EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& client) + { + if(client == nullptr) + { + Aws::Internal::InitEC2MetadataClient(); + m_ec2metadataClient = Aws::Internal::GetEC2MetadataClient(); + } + else + { + m_ec2metadataClient = client; + } + } + + bool EC2InstanceProfileConfigLoader::LoadInternal() + { + // re-use old credentials until we need to call IMDS again. + if (DateTime::Now().Millis() < this->credentialsValidUntilMillis) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Skipping IMDS call until " << this->credentialsValidUntilMillis); + return true; + } + this->credentialsValidUntilMillis = DateTime::Now().Millis(); + + if (!m_ec2metadataClient) { + AWS_LOGSTREAM_FATAL(EC2_INSTANCE_PROFILE_LOG_TAG, "EC2MetadataClient is a nullptr!") + return false; + } + auto credentialsStr = m_ec2metadataClient->GetDefaultCredentialsSecurely(); + if(credentialsStr.empty()) return false; + + Json::JsonValue credentialsDoc(credentialsStr); + if (!credentialsDoc.WasParseSuccessful()) + { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Failed to parse output from EC2MetadataService."); + return false; + } + + const char* accessKeyId = "AccessKeyId"; + const char* secretAccessKey = "SecretAccessKey"; + const char* expiration = "Expiration"; + const char* code = "Code"; + Aws::String accessKey, secretKey, token; + + auto credentialsView = credentialsDoc.View(); + DateTime expirationTime(credentialsView.GetString(expiration), Aws::Utils::DateFormat::ISO_8601); + // re-use old credentials and not block if the IMDS call failed or if the latest credential is in the past + if (expirationTime.WasParseSuccessful() && DateTime::Now() > expirationTime) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "Expiration Time of Credentials in the past, refusing to update credentials"); + this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime(); + return true; + } else if (credentialsView.GetString(code) == INTERNAL_EXCEPTION_PHRASE) { + AWS_LOGSTREAM_ERROR(EC2_INSTANCE_PROFILE_LOG_TAG, + "IMDS call failed, refusing to update credentials"); + this->credentialsValidUntilMillis = DateTime::Now().Millis() + calculateRetryTime(); + return true; + } + accessKey = credentialsView.GetString(accessKeyId); + AWS_LOGSTREAM_INFO(EC2_INSTANCE_PROFILE_LOG_TAG, + "Successfully pulled credentials from metadata service with access key " << accessKey); + + secretKey = credentialsView.GetString(secretAccessKey); + token = credentialsView.GetString("Token"); + + auto region = m_ec2metadataClient->GetCurrentRegion(); + + Profile profile; + profile.SetCredentials(AWSCredentials(accessKey, secretKey, token)); + profile.SetRegion(region); + profile.SetName(INSTANCE_PROFILE_KEY); + + m_profiles[INSTANCE_PROFILE_KEY] = profile; + + return true; + } + + int64_t EC2InstanceProfileConfigLoader::calculateRetryTime() const { + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution<int64_t> dist(FIVE_MINUTE_MILLIS, TEN_MINUTE_MILLIS); + return dist(gen); + } + } // Config namespace +} // Aws namespace diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp new file mode 100644 index 00000000000..7b54066fb3f --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/config/defaults/ClientConfigurationDefaults.cpp @@ -0,0 +1,197 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +/** + * Please note that this file is autogenerated. + * The backwards compatibility of the default values provided by new client configuration defaults is not guaranteed; + * the values might change over time. + */ + +#include <aws/common/platform.h> // for AWS_OS_IOS macro +#include <aws/core/config/defaults/ClientConfigurationDefaults.h> +#include <aws/core/config/AWSProfileConfigLoader.h> +#include <aws/core/client/ClientConfiguration.h> +#include <aws/core/internal/AWSHttpResourceClient.h> +#include <aws/core/platform/Environment.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> + +namespace Aws +{ + namespace Config + { + namespace Defaults + { + static const char* CLIENT_CONFIG_DEFAULTS_TAG = "ClientConfigurationDefaults"; + + void SetSmartDefaultsConfigurationParameters(Aws::Client::ClientConfiguration& clientConfig, + const Aws::String& defaultMode, + bool hasEc2MetadataRegion, + const Aws::String& ec2MetadataRegion) + { + const Aws::String caseInsensitiveMode = ResolveDefaultModeName(clientConfig, + defaultMode, + Aws::Config::GetCachedConfigValue("defaults_mode"), + hasEc2MetadataRegion, + ec2MetadataRegion); + + if(caseInsensitiveMode == "legacy") + { + return SetLegacyClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "standard") + { + return SetStandardClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "in-region") + { + return SetInRegionClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "cross-region") + { + return SetCrossRegionClientConfiguration(clientConfig); + } + + if(caseInsensitiveMode == "mobile") + { + return SetMobileClientConfiguration(clientConfig); + } + return SetLegacyClientConfiguration(clientConfig); + } + + bool isMobile() + { +#if defined(AWS_OS_IOS) || defined (__ANDROID__) + return true; +#else + return false; +#endif + } + + const char* ResolveAutoClientConfiguration(const Aws::Client::ClientConfiguration& clientConfig, + const Aws::String& ec2MetadataRegion) + { + // Check if we're on mobile, CPP SDK is statically built, so we can check how we were built + if(isMobile()) + { + return "mobile"; + } + // We're not on mobile (best we can tell). See if we can determine whether we're an in-region or + // cross-region client. + Aws::String current_region; + Aws::String env_region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + if(!Aws::Environment::GetEnv("AWS_EXECUTION_ENV").empty()) + { + // We're running in an AWS service environment, so we can trust the region environment variables + // to be the current region, if they're set + current_region = Aws::Environment::GetEnv("AWS_REGION"); + if(current_region.empty()) + { + current_region = Aws::Environment::GetEnv("AWS_DEFAULT_REGION"); + } + } + if(current_region.empty()) + { + current_region = ec2MetadataRegion; + } + if(!current_region.empty() && !clientConfig.region.empty()) + { + if(current_region == clientConfig.region) + { + return "in-region"; + } + else + { + return "cross-region"; + } + } + // We don't seem to be mobile, and we couldn't determine whether we're running within an AWS region. + // Fall back to standard. + return "standard"; + } + + void SetLegacyClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("default"); + } + + void SetStandardClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 3100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetInRegionClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 1100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetCrossRegionClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 3100; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + void SetMobileClientConfiguration(Aws::Client::ClientConfiguration& clientConfig) + { + clientConfig.connectTimeoutMs = 30000; + clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + } + + Aws::String ResolveDefaultModeName(const Aws::Client::ClientConfiguration& clientConfig, + Aws::String requestedDefaultMode, + const Aws::String& configFileDefaultMode, + bool hasEc2MetadataRegion, + Aws::String ec2MetadataRegion) + { + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = Aws::Environment::GetEnv("AWS_DEFAULTS_MODE"); + } + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = configFileDefaultMode; + } + if (Aws::Utils::StringUtils::ToLower(requestedDefaultMode.c_str()) == "auto") + { + if (!hasEc2MetadataRegion && + Aws::Utils::StringUtils::ToLower(Aws::Environment::GetEnv("AWS_EC2_METADATA_DISABLED").c_str()) != "true") + { + auto client = Aws::Internal::GetEC2MetadataClient(); + if (client) + { + ec2MetadataRegion = client->GetCurrentRegion(); + } + } + requestedDefaultMode = ResolveAutoClientConfiguration(clientConfig, ec2MetadataRegion); + return requestedDefaultMode; + } + if (requestedDefaultMode.empty()) + { + requestedDefaultMode = "legacy"; + return requestedDefaultMode; + } + + requestedDefaultMode = Aws::Utils::StringUtils::ToLower(requestedDefaultMode.c_str()); + if (requestedDefaultMode != "legacy" && + requestedDefaultMode != "standard" && + requestedDefaultMode != "in-region" && + requestedDefaultMode != "cross-region" && + requestedDefaultMode != "mobile") + { + AWS_LOGSTREAM_WARN(CLIENT_CONFIG_DEFAULTS_TAG, "User specified client configuration: [" + << requestedDefaultMode + << "] is not found, will use the SDK default legacy one."); + requestedDefaultMode = "legacy"; + } + return requestedDefaultMode; + } + } //namespace Defaults + } //namespace Config +} //namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSEndpoint.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSEndpoint.cpp new file mode 100644 index 00000000000..4990faff243 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSEndpoint.cpp @@ -0,0 +1,86 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/AWSEndpoint.h> +#include <aws/core/utils/DNS.h> + +namespace Aws +{ +namespace Endpoint +{ + +Aws::String AWSEndpoint::GetURL() const +{ + return m_uri.GetURIString(); +} + +void AWSEndpoint::SetURL(Aws::String url) +{ + m_uri = std::move(url); +} + +const Aws::Http::URI& AWSEndpoint::GetURI() const +{ + return m_uri; +} + +void AWSEndpoint::SetURI(Aws::Http::URI uri) +{ + m_uri = std::move(uri); +} + +AWSEndpoint::OptionalError AWSEndpoint::AddPrefixIfMissing(const Aws::String& prefix) +{ + if (m_uri.GetAuthority().rfind(prefix, 0) == 0) + { + // uri already starts with a prefix + return OptionalError(); + } + + if (Aws::Utils::IsValidHost(prefix + m_uri.GetAuthority())) + { + m_uri.SetAuthority(prefix + m_uri.GetAuthority()); + return OptionalError(); + } + + return OptionalError( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::ENDPOINT_RESOLUTION_FAILURE, "", + Aws::String("Failed to add host prefix, resulting uri is an invalid hostname: ") + prefix + m_uri.GetAuthority(), + false/*retryable*/)); +} + +void AWSEndpoint::SetQueryString(const Aws::String& queryString) +{ + m_uri.SetQueryString(queryString); +} + +const Crt::Optional<AWSEndpoint::EndpointAttributes>& AWSEndpoint::GetAttributes() const +{ + return m_attributes; +} + +Crt::Optional<AWSEndpoint::EndpointAttributes>& AWSEndpoint::AccessAttributes() +{ + return m_attributes; +} + +void AWSEndpoint::SetAttributes(AWSEndpoint::EndpointAttributes&& attributes) +{ + m_attributes = std::move(attributes); +} + +const Aws::UnorderedMap<Aws::String, Aws::String>& AWSEndpoint::GetHeaders() const +{ + return m_headers; +} + +void AWSEndpoint::SetHeaders(Aws::UnorderedMap<Aws::String, Aws::String> headers) +{ + m_headers = std::move(headers); +} + +} // namespace Endpoint +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSPartitions.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSPartitions.cpp new file mode 100644 index 00000000000..bfe3cf6147b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/AWSPartitions.cpp @@ -0,0 +1,153 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/AWSPartitions.h> +#include <aws/core/utils/memory/stl/AWSArray.h> + +namespace Aws +{ +namespace Endpoint +{ +const size_t AWSPartitions::PartitionsBlobStrLen = 3166; +const size_t AWSPartitions::PartitionsBlobSize = 3167; + +using PartitionsBlobT = Aws::Array<const char, AWSPartitions::PartitionsBlobSize>; +static constexpr PartitionsBlobT PartitionsBlob = {{ +'{','"','p','a','r','t','i','t','i','o','n','s','"',':','[','{','"','i','d','"',':','"','a','w','s', +'"',',','"','o','u','t','p','u','t','s','"',':','{','"','d','n','s','S','u','f','f','i','x','"',':', +'"','a','m','a','z','o','n','a','w','s','.','c','o','m','"',',','"','d','u','a','l','S','t','a','c', +'k','D','n','s','S','u','f','f','i','x','"',':','"','a','p','i','.','a','w','s','"',',','"','n','a', +'m','e','"',':','"','a','w','s','"',',','"','s','u','p','p','o','r','t','s','D','u','a','l','S','t', +'a','c','k','"',':','t','r','u','e',',','"','s','u','p','p','o','r','t','s','F','I','P','S','"',':', +'t','r','u','e','}',',','"','r','e','g','i','o','n','R','e','g','e','x','"',':','"','^','(','u','s', +'|','e','u','|','a','p','|','s','a','|','c','a','|','m','e','|','a','f',')','\\','\\','-','\\','\\','w', +'+','\\','\\','-','\\','\\','d','+','$','"',',','"','r','e','g','i','o','n','s','"',':','{','"','a','f', +'-','s','o','u','t','h','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':', +'"','A','f','r','i','c','a',' ','(','C','a','p','e',' ','T','o','w','n',')','"','}',',','"','a','p', +'-','e','a','s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"', +'A','s','i','a',' ','P','a','c','i','f','i','c',' ','(','H','o','n','g',' ','K','o','n','g',')','"', +'}',',','"','a','p','-','n','o','r','t','h','e','a','s','t','-','1','"',':','{','"','d','e','s','c', +'r','i','p','t','i','o','n','"',':','"','A','s','i','a',' ','P','a','c','i','f','i','c',' ','(','T', +'o','k','y','o',')','"','}',',','"','a','p','-','n','o','r','t','h','e','a','s','t','-','2','"',':', +'{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','s','i','a',' ','P','a','c','i', +'f','i','c',' ','(','S','e','o','u','l',')','"','}',',','"','a','p','-','n','o','r','t','h','e','a', +'s','t','-','3','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','s','i', +'a',' ','P','a','c','i','f','i','c',' ','(','O','s','a','k','a',')','"','}',',','"','a','p','-','s', +'o','u','t','h','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A', +'s','i','a',' ','P','a','c','i','f','i','c',' ','(','M','u','m','b','a','i',')','"','}',',','"','a', +'p','-','s','o','u','t','h','-','2','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"', +':','"','A','s','i','a',' ','P','a','c','i','f','i','c',' ','(','H','y','d','e','r','a','b','a','d', +')','"','}',',','"','a','p','-','s','o','u','t','h','e','a','s','t','-','1','"',':','{','"','d','e', +'s','c','r','i','p','t','i','o','n','"',':','"','A','s','i','a',' ','P','a','c','i','f','i','c',' ', +'(','S','i','n','g','a','p','o','r','e',')','"','}',',','"','a','p','-','s','o','u','t','h','e','a', +'s','t','-','2','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','s','i', +'a',' ','P','a','c','i','f','i','c',' ','(','S','y','d','n','e','y',')','"','}',',','"','a','p','-', +'s','o','u','t','h','e','a','s','t','-','3','"',':','{','"','d','e','s','c','r','i','p','t','i','o', +'n','"',':','"','A','s','i','a',' ','P','a','c','i','f','i','c',' ','(','J','a','k','a','r','t','a', +')','"','}',',','"','a','p','-','s','o','u','t','h','e','a','s','t','-','4','"',':','{','"','d','e', +'s','c','r','i','p','t','i','o','n','"',':','"','A','s','i','a',' ','P','a','c','i','f','i','c',' ', +'(','M','e','l','b','o','u','r','n','e',')','"','}',',','"','a','w','s','-','g','l','o','b','a','l', +'"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','W','S',' ','S','t','a', +'n','d','a','r','d',' ','g','l','o','b','a','l',' ','r','e','g','i','o','n','"','}',',','"','c','a', +'-','c','e','n','t','r','a','l','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n', +'"',':','"','C','a','n','a','d','a',' ','(','C','e','n','t','r','a','l',')','"','}',',','"','e','u', +'-','c','e','n','t','r','a','l','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n', +'"',':','"','E','u','r','o','p','e',' ','(','F','r','a','n','k','f','u','r','t',')','"','}',',','"', +'e','u','-','c','e','n','t','r','a','l','-','2','"',':','{','"','d','e','s','c','r','i','p','t','i', +'o','n','"',':','"','E','u','r','o','p','e',' ','(','Z','u','r','i','c','h',')','"','}',',','"','e', +'u','-','n','o','r','t','h','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"', +':','"','E','u','r','o','p','e',' ','(','S','t','o','c','k','h','o','l','m',')','"','}',',','"','e', +'u','-','s','o','u','t','h','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"', +':','"','E','u','r','o','p','e',' ','(','M','i','l','a','n',')','"','}',',','"','e','u','-','s','o', +'u','t','h','-','2','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','E','u', +'r','o','p','e',' ','(','S','p','a','i','n',')','"','}',',','"','e','u','-','w','e','s','t','-','1', +'"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','E','u','r','o','p','e',' ', +'(','I','r','e','l','a','n','d',')','"','}',',','"','e','u','-','w','e','s','t','-','2','"',':','{', +'"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','E','u','r','o','p','e',' ','(','L','o', +'n','d','o','n',')','"','}',',','"','e','u','-','w','e','s','t','-','3','"',':','{','"','d','e','s', +'c','r','i','p','t','i','o','n','"',':','"','E','u','r','o','p','e',' ','(','P','a','r','i','s',')', +'"','}',',','"','m','e','-','c','e','n','t','r','a','l','-','1','"',':','{','"','d','e','s','c','r', +'i','p','t','i','o','n','"',':','"','M','i','d','d','l','e',' ','E','a','s','t',' ','(','U','A','E', +')','"','}',',','"','m','e','-','s','o','u','t','h','-','1','"',':','{','"','d','e','s','c','r','i', +'p','t','i','o','n','"',':','"','M','i','d','d','l','e',' ','E','a','s','t',' ','(','B','a','h','r', +'a','i','n',')','"','}',',','"','s','a','-','e','a','s','t','-','1','"',':','{','"','d','e','s','c', +'r','i','p','t','i','o','n','"',':','"','S','o','u','t','h',' ','A','m','e','r','i','c','a',' ','(', +'S','a','o',' ','P','a','u','l','o',')','"','}',',','"','u','s','-','e','a','s','t','-','1','"',':', +'{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','U','S',' ','E','a','s','t',' ','(', +'N','.',' ','V','i','r','g','i','n','i','a',')','"','}',',','"','u','s','-','e','a','s','t','-','2', +'"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','U','S',' ','E','a','s','t', +' ','(','O','h','i','o',')','"','}',',','"','u','s','-','w','e','s','t','-','1','"',':','{','"','d', +'e','s','c','r','i','p','t','i','o','n','"',':','"','U','S',' ','W','e','s','t',' ','(','N','.',' ', +'C','a','l','i','f','o','r','n','i','a',')','"','}',',','"','u','s','-','w','e','s','t','-','2','"', +':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','U','S',' ','W','e','s','t',' ', +'(','O','r','e','g','o','n',')','"','}','}','}',',','{','"','i','d','"',':','"','a','w','s','-','c', +'n','"',',','"','o','u','t','p','u','t','s','"',':','{','"','d','n','s','S','u','f','f','i','x','"', +':','"','a','m','a','z','o','n','a','w','s','.','c','o','m','.','c','n','"',',','"','d','u','a','l', +'S','t','a','c','k','D','n','s','S','u','f','f','i','x','"',':','"','a','p','i','.','a','m','a','z', +'o','n','w','e','b','s','e','r','v','i','c','e','s','.','c','o','m','.','c','n','"',',','"','n','a', +'m','e','"',':','"','a','w','s','-','c','n','"',',','"','s','u','p','p','o','r','t','s','D','u','a', +'l','S','t','a','c','k','"',':','t','r','u','e',',','"','s','u','p','p','o','r','t','s','F','I','P', +'S','"',':','t','r','u','e','}',',','"','r','e','g','i','o','n','R','e','g','e','x','"',':','"','^', +'c','n','\\','\\','-','\\','\\','w','+','\\','\\','-','\\','\\','d','+','$','"',',','"','r','e','g','i','o', +'n','s','"',':','{','"','a','w','s','-','c','n','-','g','l','o','b','a','l','"',':','{','"','d','e', +'s','c','r','i','p','t','i','o','n','"',':','"','A','W','S',' ','C','h','i','n','a',' ','g','l','o', +'b','a','l',' ','r','e','g','i','o','n','"','}',',','"','c','n','-','n','o','r','t','h','-','1','"', +':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','C','h','i','n','a',' ','(','B', +'e','i','j','i','n','g',')','"','}',',','"','c','n','-','n','o','r','t','h','w','e','s','t','-','1', +'"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','C','h','i','n','a',' ','(', +'N','i','n','g','x','i','a',')','"','}','}','}',',','{','"','i','d','"',':','"','a','w','s','-','u', +'s','-','g','o','v','"',',','"','o','u','t','p','u','t','s','"',':','{','"','d','n','s','S','u','f', +'f','i','x','"',':','"','a','m','a','z','o','n','a','w','s','.','c','o','m','"',',','"','d','u','a', +'l','S','t','a','c','k','D','n','s','S','u','f','f','i','x','"',':','"','a','p','i','.','a','w','s', +'"',',','"','n','a','m','e','"',':','"','a','w','s','-','u','s','-','g','o','v','"',',','"','s','u', +'p','p','o','r','t','s','D','u','a','l','S','t','a','c','k','"',':','t','r','u','e',',','"','s','u', +'p','p','o','r','t','s','F','I','P','S','"',':','t','r','u','e','}',',','"','r','e','g','i','o','n', +'R','e','g','e','x','"',':','"','^','u','s','\\','\\','-','g','o','v','\\','\\','-','\\','\\','w','+','\\', +'\\','-','\\','\\','d','+','$','"',',','"','r','e','g','i','o','n','s','"',':','{','"','a','w','s','-', +'u','s','-','g','o','v','-','g','l','o','b','a','l','"',':','{','"','d','e','s','c','r','i','p','t', +'i','o','n','"',':','"','A','W','S',' ','G','o','v','C','l','o','u','d',' ','(','U','S',')',' ','g', +'l','o','b','a','l',' ','r','e','g','i','o','n','"','}',',','"','u','s','-','g','o','v','-','e','a', +'s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','W','S', +' ','G','o','v','C','l','o','u','d',' ','(','U','S','-','E','a','s','t',')','"','}',',','"','u','s', +'-','g','o','v','-','w','e','s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o', +'n','"',':','"','A','W','S',' ','G','o','v','C','l','o','u','d',' ','(','U','S','-','W','e','s','t', +')','"','}','}','}',',','{','"','i','d','"',':','"','a','w','s','-','i','s','o','"',',','"','o','u', +'t','p','u','t','s','"',':','{','"','d','n','s','S','u','f','f','i','x','"',':','"','c','2','s','.', +'i','c','.','g','o','v','"',',','"','d','u','a','l','S','t','a','c','k','D','n','s','S','u','f','f', +'i','x','"',':','"','c','2','s','.','i','c','.','g','o','v','"',',','"','n','a','m','e','"',':','"', +'a','w','s','-','i','s','o','"',',','"','s','u','p','p','o','r','t','s','D','u','a','l','S','t','a', +'c','k','"',':','f','a','l','s','e',',','"','s','u','p','p','o','r','t','s','F','I','P','S','"',':', +'t','r','u','e','}',',','"','r','e','g','i','o','n','R','e','g','e','x','"',':','"','^','u','s','\\', +'\\','-','i','s','o','\\','\\','-','\\','\\','w','+','\\','\\','-','\\','\\','d','+','$','"',',','"','r','e', +'g','i','o','n','s','"',':','{','"','a','w','s','-','i','s','o','-','g','l','o','b','a','l','"',':', +'{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','A','W','S',' ','I','S','O',' ','(', +'U','S',')',' ','g','l','o','b','a','l',' ','r','e','g','i','o','n','"','}',',','"','u','s','-','i', +'s','o','-','e','a','s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"', +':','"','U','S',' ','I','S','O',' ','E','a','s','t','"','}',',','"','u','s','-','i','s','o','-','w', +'e','s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"','U','S', +' ','I','S','O',' ','W','E','S','T','"','}','}','}',',','{','"','i','d','"',':','"','a','w','s','-', +'i','s','o','-','b','"',',','"','o','u','t','p','u','t','s','"',':','{','"','d','n','s','S','u','f', +'f','i','x','"',':','"','s','c','2','s','.','s','g','o','v','.','g','o','v','"',',','"','d','u','a', +'l','S','t','a','c','k','D','n','s','S','u','f','f','i','x','"',':','"','s','c','2','s','.','s','g', +'o','v','.','g','o','v','"',',','"','n','a','m','e','"',':','"','a','w','s','-','i','s','o','-','b', +'"',',','"','s','u','p','p','o','r','t','s','D','u','a','l','S','t','a','c','k','"',':','f','a','l', +'s','e',',','"','s','u','p','p','o','r','t','s','F','I','P','S','"',':','t','r','u','e','}',',','"', +'r','e','g','i','o','n','R','e','g','e','x','"',':','"','^','u','s','\\','\\','-','i','s','o','b','\\', +'\\','-','\\','\\','w','+','\\','\\','-','\\','\\','d','+','$','"',',','"','r','e','g','i','o','n','s','"', +':','{','"','a','w','s','-','i','s','o','-','b','-','g','l','o','b','a','l','"',':','{','"','d','e', +'s','c','r','i','p','t','i','o','n','"',':','"','A','W','S',' ','I','S','O','B',' ','(','U','S',')', +' ','g','l','o','b','a','l',' ','r','e','g','i','o','n','"','}',',','"','u','s','-','i','s','o','b', +'-','e','a','s','t','-','1','"',':','{','"','d','e','s','c','r','i','p','t','i','o','n','"',':','"', +'U','S',' ','I','S','O','B',' ','E','a','s','t',' ','(','O','h','i','o',')','"','}','}','}',']',',', +'"','v','e','r','s','i','o','n','"',':','"','1','.','1','"','}','\0' +}}; + +const char* AWSPartitions::GetPartitionsBlob() +{ + return PartitionsBlob.data(); +} + +} // namespace Endpoint +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/BuiltInParameters.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/BuiltInParameters.cpp new file mode 100644 index 00000000000..43c3e2f0f94 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/BuiltInParameters.cpp @@ -0,0 +1,135 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/BuiltInParameters.h> +#include <aws/core/utils/logging/LogMacros.h> + +static const char ENDPOINT_BUILTIN_LOG_TAG[] = "EndpointBuiltInParameters"; + +namespace Aws +{ +namespace Endpoint +{ + void BuiltInParameters::OverrideEndpoint(const Aws::String& endpoint, const Aws::Http::Scheme& scheme) + { + static const char* SDK_ENDPOINT = "Endpoint"; + + if (endpoint.compare(0, 7, "http://") == 0 || endpoint.compare(0, 8, "https://") == 0) + { + SetStringParameter(SDK_ENDPOINT, endpoint); + } + else + { + SetStringParameter(SDK_ENDPOINT, Aws::String(Aws::Http::SchemeMapper::ToString(scheme)) + "://" + endpoint); + } + } + + bool StringEndsWith(const Aws::String& str, const Aws::String& suffix) + { + if (suffix.size() > str.size()) + return false; + return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); + } + + void BuiltInParameters::SetFromClientConfiguration(const Client::ClientConfiguration& config) + { + bool forceFIPS = false; + static const char* AWS_REGION = "Region"; + if (!config.region.empty()) { + static const char* FIPS_PREFIX = "fips-"; + static const char* FIPS_SUFFIX = "-fips"; + if (config.region.rfind(FIPS_PREFIX, 0) == 0) { + // Backward compatibility layer for code hacking previous SDK version + Aws::String regionOverride = config.region.substr(sizeof(FIPS_PREFIX) - 1); + forceFIPS = true; + SetStringParameter(AWS_REGION, regionOverride); + } else if (StringEndsWith(config.region, FIPS_SUFFIX)) { + Aws::String regionOverride = config.region.substr(0, config.region.size() - sizeof(FIPS_SUFFIX) - 1); + forceFIPS = true; + SetStringParameter(AWS_REGION, regionOverride); + } else { + SetStringParameter(AWS_REGION, config.region); + } + } + + static const char* AWS_USE_FIPS = "UseFIPS"; + SetBooleanParameter(AWS_USE_FIPS, config.useFIPS || forceFIPS); + + static const char* AWS_USE_DUAL_STACK = "UseDualStack"; + SetBooleanParameter(AWS_USE_DUAL_STACK, config.useDualStack); + + if (!config.endpointOverride.empty()) { + OverrideEndpoint(config.endpointOverride, config.scheme); + + if (config.region.empty()) { + AWS_LOGSTREAM_WARN(ENDPOINT_BUILTIN_LOG_TAG, + "Endpoint is overridden but region is not set. " + "Region is required my many endpoint rule sets to resolve the endpoint. " + "And it is required to compute an aws signature."); + SetStringParameter(AWS_REGION, "region-not-set"); // dummy endpoint resolution parameter + } + } + } + + void BuiltInParameters::SetFromClientConfiguration(const Client::GenericClientConfiguration<false>& config) + { + return SetFromClientConfiguration(static_cast<const Client::ClientConfiguration&>(config)); + } + + void BuiltInParameters::SetFromClientConfiguration(const Client::GenericClientConfiguration<true>& config) + { + SetFromClientConfiguration(static_cast<const Client::ClientConfiguration&>(config)); + } + + const BuiltInParameters::EndpointParameter& BuiltInParameters::GetParameter(const Aws::String& name) const + { + const auto foundIt = std::find_if(m_params.begin(), m_params.end(), + [name](const BuiltInParameters::EndpointParameter& item) + { + return item.GetName() == name; + }); + + if (foundIt != m_params.end()) + { + return *foundIt; + } + else + { + static const BuiltInParameters::EndpointParameter BUILTIN_NOT_FOUND_PARAMETER("PARAMETER_NOT_SET", false, EndpointParameter::ParameterOrigin::CLIENT_CONTEXT); + return BUILTIN_NOT_FOUND_PARAMETER; + } + } + + void BuiltInParameters::SetParameter(EndpointParameter param) + { + const auto foundIt = std::find_if(m_params.begin(), m_params.end(), + [param](const BuiltInParameters::EndpointParameter& item) + { + return item.GetName() == param.GetName(); + }); + + if (foundIt != m_params.end()) + { + m_params.erase(foundIt); + } + m_params.emplace_back(std::move(param)); + } + + void BuiltInParameters::SetStringParameter(Aws::String name, Aws::String value) + { + return SetParameter(EndpointParameter(std::move(name), std::move(value), EndpointParameter::ParameterOrigin::BUILT_IN)); + } + + void BuiltInParameters::SetBooleanParameter(Aws::String name, bool value) + { + return SetParameter(EndpointParameter(std::move(name), value, EndpointParameter::ParameterOrigin::BUILT_IN)); + } + + const Aws::Vector<BuiltInParameters::EndpointParameter>& BuiltInParameters::GetAllParameters() const + { + return m_params; + } +} // namespace Endpoint +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/ClientContextParameters.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/ClientContextParameters.cpp new file mode 100644 index 00000000000..cdff71f6698 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/ClientContextParameters.cpp @@ -0,0 +1,61 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/ClientContextParameters.h> + +namespace Aws +{ +namespace Endpoint +{ + const ClientContextParameters::EndpointParameter& ClientContextParameters::GetParameter(const Aws::String& name) const + { + const auto foundIt = std::find_if(m_params.begin(), m_params.end(), + [name](const ClientContextParameters::EndpointParameter& item) + { + return item.GetName() == name; + }); + + if (foundIt != m_params.end()) + { + return *foundIt; + } + else + { + static const ClientContextParameters::EndpointParameter CTX_NOT_FOUND_PARAMETER("PARAMETER_NOT_SET", false, EndpointParameter::ParameterOrigin::CLIENT_CONTEXT); + return CTX_NOT_FOUND_PARAMETER; + } + } + + void ClientContextParameters::SetParameter(EndpointParameter param) + { + const auto foundIt = std::find_if(m_params.begin(), m_params.end(), + [param](const ClientContextParameters::EndpointParameter& item) + { + return item.GetName() == param.GetName(); + }); + + if (foundIt != m_params.end()) + { + m_params.erase(foundIt); + } + m_params.emplace_back(std::move(param)); + } + + void ClientContextParameters::SetStringParameter(Aws::String name, Aws::String value) + { + return SetParameter(EndpointParameter(std::move(name), std::move(value), EndpointParameter::ParameterOrigin::CLIENT_CONTEXT)); + } + + void ClientContextParameters::SetBooleanParameter(Aws::String name, bool value) + { + return SetParameter(EndpointParameter(std::move(name), value, EndpointParameter::ParameterOrigin::CLIENT_CONTEXT)); + } + + const Aws::Vector<ClientContextParameters::EndpointParameter>& ClientContextParameters::GetAllParameters() const + { + return m_params; + } +} // namespace Endpoint +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp new file mode 100644 index 00000000000..58370cd4256 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp @@ -0,0 +1,236 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/DefaultEndpointProvider.h> +#include <aws/core/utils/memory/stl/AWSMap.h> +#include <aws/crt/Api.h> + +namespace Aws +{ +namespace Endpoint +{ + +/** + * Export endpoint provider symbols from DLL + */ +template class AWS_CORE_API DefaultEndpointProvider<Aws::Client::GenericClientConfiguration<false>, + Aws::Endpoint::BuiltInParameters, + Aws::Endpoint::ClientContextParameters>; + +char CharToDec(const char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'A' && c <= 'F') + return c - 'A' + 10; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; +} + +Aws::String PercentDecode(Aws::String inputString) +{ + if (inputString.find_first_of("%") == Aws::String::npos) + { + return inputString; + } + Aws::String result; + result.reserve(inputString.size()); + + bool percentFound = false; + char firstOctet = 0; + char secondOctet = 0; + for(size_t i = 0; i < inputString.size(); ++i) + { + const char currentChar = inputString[i]; + if ('%' == currentChar) + { + if (percentFound) + { + // not percent-encoded string + result += currentChar; + } + percentFound = true; + continue; + } + + if (percentFound) + { + if ((currentChar >= '0' && currentChar <= '9') || + (currentChar >= 'A' && currentChar <= 'F') || + (currentChar >= 'a' && currentChar <= 'f')) + { + if(!firstOctet) + { + firstOctet = currentChar; + continue; + } + if(!secondOctet) + { + secondOctet = currentChar; + char encodedChar = CharToDec(firstOctet) * 16 + CharToDec(secondOctet); + result += encodedChar; + + percentFound = false; + firstOctet = 0; + secondOctet = 0; + continue; + } + } else { + // Non-percent encoded sequence + result += '%'; + if(!firstOctet) + result += firstOctet; + result += currentChar; + percentFound = false; + firstOctet = 0; + secondOctet = 0; + continue; + } + } + + if ('+' == currentChar) + { + result += ' '; + continue; + } + result += currentChar; + } + return result; +} + +AWS_CORE_API ResolveEndpointOutcome +ResolveEndpointDefaultImpl(const Aws::Crt::Endpoints::RuleEngine& ruleEngine, + const EndpointParameters& builtInParameters, + const EndpointParameters& clientContextParameters, + const EndpointParameters& endpointParameters) +{ + if(!ruleEngine) { + AWS_LOGSTREAM_FATAL(DEFAULT_ENDPOINT_PROVIDER_TAG, "Invalid CRT Rule Engine state"); + return ResolveEndpointOutcome( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::INTERNAL_FAILURE, + "", + "CRT Endpoint rule engine is not initialized", + false/*retryable*/)); + } + + Aws::Crt::Endpoints::RequestContext crtRequestCtx; + + const Aws::Vector<std::reference_wrapper<const EndpointParameters>> allParameters + = {std::cref(builtInParameters), std::cref(clientContextParameters), std::cref(endpointParameters)}; + + for (const auto& parameterClass : allParameters) + { + for(const auto& parameter : parameterClass.get()) + { + if(EndpointParameter::ParameterType::BOOLEAN == parameter.GetStoredType()) + { + AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint bool eval parameter: " << parameter.GetName() << " = " << parameter.GetBoolValueNoCheck()); + crtRequestCtx.AddBoolean(Aws::Crt::ByteCursorFromCString(parameter.GetName().c_str()), parameter.GetBoolValueNoCheck()); + } + else if(EndpointParameter::ParameterType::STRING == parameter.GetStoredType()) + { + AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint str eval parameter: " << parameter.GetName() << " = " << parameter.GetStrValueNoCheck()); + crtRequestCtx.AddString(Aws::Crt::ByteCursorFromCString(parameter.GetName().c_str()), Aws::Crt::ByteCursorFromCString(parameter.GetStrValueNoCheck().c_str())); + } + else + { + return ResolveEndpointOutcome( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER, + "", + "Invalid endpoint parameter type for parameter " + parameter.GetName(), + false/*retryable*/)); + } + } + } + + auto resolved = ruleEngine.Resolve(crtRequestCtx); + + if(resolved.has_value()) + { + if(resolved->IsError()) + { + auto crtError = resolved->GetError(); + Aws::String sdkCrtError = crtError ? Aws::String(crtError->begin(), crtError->end()) : + "CRT Rule engine resolution resulted in an unknown error"; + return ResolveEndpointOutcome( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::INVALID_PARAMETER_COMBINATION, + "", + sdkCrtError, + false/*retryable*/)); + } + else if(resolved->IsEndpoint() && resolved->GetUrl()) + { + Aws::Endpoint::AWSEndpoint endpoint; + const auto crtUrl = resolved->GetUrl(); + Aws::String sdkCrtUrl = Aws::String(crtUrl->begin(), crtUrl->end()); + AWS_LOGSTREAM_DEBUG(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint rules engine evaluated the endpoint: " << sdkCrtUrl); + endpoint.SetURL(PercentDecode(std::move(sdkCrtUrl))); + + // Transform attributes + // Each attribute consist of properties, hence converting CRT properties to SDK attributes + const auto crtProps = resolved->GetProperties(); + if (crtProps && crtProps->size() > 2) { + Aws::String sdkCrtProps = crtProps ? Aws::String(crtProps->begin(), crtProps->end()) : ""; + AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint rules evaluated props: " << sdkCrtProps); + + Internal::Endpoint::EndpointAttributes epAttributes = Internal::Endpoint::EndpointAttributes::BuildEndpointAttributesFromJson( + sdkCrtProps); + + endpoint.SetAttributes(std::move(epAttributes)); + } + + // transform headers + const auto crtHeaders = resolved->GetHeaders(); + if (crtHeaders) + { + Aws::UnorderedMap<Aws::String, Aws::String> sdkHeaders; + for (const auto& header: *crtHeaders) + { + Aws::String key(header.first.begin(), header.first.end()); + Aws::String value; + for (const auto& crtHeaderValue : header.second) + { + if(!value.empty()) { + value.insert(value.end(), ';'); + } + value.insert(value.end(), crtHeaderValue.begin(), crtHeaderValue.end()); + } + sdkHeaders.emplace(std::move(key), std::move(value)); + } + + endpoint.SetHeaders(std::move(sdkHeaders)); + } + + return ResolveEndpointOutcome(std::move(endpoint)); + } + else + { + return ResolveEndpointOutcome( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER, + "", + "Invalid AWS CRT RuleEngine state", + false/*retryable*/)); + } + } + + auto errCode = Aws::Crt::LastError(); + AWS_LOGSTREAM_DEBUG(DEFAULT_ENDPOINT_PROVIDER_TAG, "ERROR: Rule engine has failed to evaluate the endpoint: " << errCode << " " << Aws::Crt::ErrorDebugString(errCode)); + + return ResolveEndpointOutcome( + Aws::Client::AWSError<Aws::Client::CoreErrors>( + Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER, + "", + "Failed to evaluate the endpoint: null output from AWS CRT RuleEngine", + false/*retryable*/)); + +} + +} // namespace Endpoint +} // namespace Aws
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/EndpointProviderBase.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/EndpointProviderBase.cpp new file mode 100644 index 00000000000..0928186839a --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/EndpointProviderBase.cpp @@ -0,0 +1,20 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/EndpointProviderBase.h> + +namespace Aws +{ +namespace Endpoint +{ +/** + * Export endpoint provider symbols from DLL + */ +template class AWS_CORE_API EndpointProviderBase<Aws::Client::GenericClientConfiguration<false>, + Aws::Endpoint::BuiltInParameters, + Aws::Endpoint::ClientContextParameters>; + +} // namespace Endpoint +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/internal/AWSEndpointAttribute.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/internal/AWSEndpointAttribute.cpp new file mode 100644 index 00000000000..5c295bb1325 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/endpoint/internal/AWSEndpointAttribute.cpp @@ -0,0 +1,82 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/endpoint/internal/AWSEndpointAttribute.h> +#include <aws/core/utils/logging/LogMacros.h> + +static const char ENDPOINT_AUTH_SCHEME_TAG[] = "EndpointAuthScheme::BuildEndpointAuthSchemeFromJson"; + +Aws::String CrtToSdkSignerName(const Aws::String& crtSignerName) +{ + Aws::String sdkSigner = "NullSigner"; + if (crtSignerName == "sigv4") { + sdkSigner = "SignatureV4"; + } else if (crtSignerName == "sigv4a") { + sdkSigner = "AsymmetricSignatureV4"; + } else if (crtSignerName == "none") { + sdkSigner = "NullSigner"; + } else if (crtSignerName == "bearer") { + sdkSigner = "Bearer"; + } else { + AWS_LOG_WARN(ENDPOINT_AUTH_SCHEME_TAG, (Aws::String("Unknown Endpoint authSchemes signer: ") + crtSignerName).c_str()); + } + + return sdkSigner; +} + +Aws::Internal::Endpoint::EndpointAttributes +Aws::Internal::Endpoint::EndpointAttributes::BuildEndpointAttributesFromJson(const Aws::String& iJsonStr) +{ + Aws::Internal::Endpoint::EndpointAttributes attributes; + Aws::Internal::Endpoint::EndpointAuthScheme& authScheme = attributes.authScheme; + + Utils::Json::JsonValue jsonObject(iJsonStr); + if (jsonObject.WasParseSuccessful()) + { + Aws::Map<Aws::String, Utils::Json::JsonView> jsonMap = jsonObject.View().GetAllObjects(); + for (const auto& mapItemAttribute : jsonMap) + { + if (mapItemAttribute.first == "authSchemes" && mapItemAttribute.second.IsListType()) { + Aws::Utils::Array<Utils::Json::JsonView> jsonAuthSchemeArray = mapItemAttribute.second.AsArray(); + + for (size_t arrayIdx = 0; arrayIdx < jsonAuthSchemeArray.GetLength(); ++arrayIdx) + { + const Utils::Json::JsonView& property = jsonAuthSchemeArray.GetItem(arrayIdx); + for (const auto& mapItemProperty : property.GetAllObjects()) + { + if (mapItemProperty.first == "name") { + authScheme.SetName(CrtToSdkSignerName(mapItemProperty.second.AsString())); + } else if (mapItemProperty.first == "signingName") { + authScheme.SetSigningName(mapItemProperty.second.AsString()); + } else if (mapItemProperty.first == "signingRegion") { + authScheme.SetSigningRegion(mapItemProperty.second.AsString()); + } else if (mapItemProperty.first == "signingRegionSet") { + Aws::Utils::Array<Utils::Json::JsonView> signingRegionArray = mapItemProperty.second.AsArray(); + if (signingRegionArray.GetLength() != 1) { + AWS_LOG_WARN(ENDPOINT_AUTH_SCHEME_TAG, + "Signing region set size is not equal to 1"); + } + if (signingRegionArray.GetLength() > 0) { + authScheme.SetSigningRegionSet(signingRegionArray.GetItem(0).AsString()); + } + } else if (mapItemProperty.first == "disableDoubleEncoding") { + authScheme.SetDisableDoubleEncoding(mapItemProperty.second.AsBool()); + } else { + AWS_LOG_WARN(ENDPOINT_AUTH_SCHEME_TAG, Aws::String("Unknown Endpoint authSchemes attribute property: " + mapItemProperty.first).c_str()); + } + } + } + } else { + AWS_LOG_WARN(ENDPOINT_AUTH_SCHEME_TAG, Aws::String("Unknown Endpoint Attribute: " + mapItemAttribute.first).c_str()); + } + } + } + else + { + AWS_LOGSTREAM_ERROR(ENDPOINT_AUTH_SCHEME_TAG, "Json Parse failed with message: " << jsonObject.GetErrorMessage()); + } + + return attributes; +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp index d21a2e7d86b..cdcbf103e7c 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/cjson/cJSON.cpp @@ -85,12 +85,19 @@ typedef struct { const unsigned char *json; size_t position; } error; +/* + * NOTE: the use of this static global variable is not thread-safe, + * hence writing to / reading from it is disabled in this code. + * + * See https://cjson.docsforge.com/#thread-safety (concurrent reads) + * See https://github.com/aws/aws-sdk-cpp/pull/2231 (concurrent writes) static error global_error = { NULL, 0 }; CJSON_AS4CPP_PUBLIC(const char *) cJSON_AS4CPP_GetErrorPtr(void) { return (const char*) (global_error.json + global_error.position); } + */ CJSON_AS4CPP_PUBLIC(char *) cJSON_AS4CPP_GetStringValue(const cJSON * const item) { @@ -120,7 +127,7 @@ CJSON_AS4CPP_PUBLIC(double) cJSON_AS4CPP_GetNumberValue(const cJSON * const item CJSON_AS4CPP_PUBLIC(const char*) cJSON_AS4CPP_Version(void) { static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_AS4CPP_VERSION_MAJOR, CJSON_AS4CPP_VERSION_MINOR, CJSON_AS4CPP_VERSION_PATCH); + snprintf(version, sizeof(version), "%i.%i.%i", CJSON_AS4CPP_VERSION_MAJOR, CJSON_AS4CPP_VERSION_MINOR, CJSON_AS4CPP_VERSION_PATCH); return version; } @@ -569,27 +576,27 @@ static cJSON_AS4CPP_bool print_number(const cJSON * const item, printbuffer * co /* For integer which is out of the range of [INT_MIN, INT_MAX], valuestring is an integer literal. */ if (item->valuestring) { - length = sprintf((char*)number_buffer, "%s", item->valuestring); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "%s", item->valuestring); } /* This checks for NaN and Infinity */ else if (isnan(d) || isinf(d)) { - length = sprintf((char*)number_buffer, "null"); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "null"); } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.15g", d); /* Check whether the original double can be recovered */ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) { /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.17g", d); } } - /* sprintf failed or buffer overrun occurred */ + /* snprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; @@ -1018,7 +1025,7 @@ static cJSON_AS4CPP_bool print_string_ptr(const unsigned char * const input, pri break; default: /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); + snprintf((char*)output_pointer, output_buffer->length - (output_pointer - output_buffer->buffer), "u%04x", *input_pointer); output_pointer += 4; break; } @@ -1107,9 +1114,13 @@ CJSON_AS4CPP_PUBLIC(cJSON *) cJSON_AS4CPP_ParseWithLengthOpts(const char *value, parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; cJSON *item = NULL; - /* reset error position */ + /* reset error position + * + * NOTE: disabled due to thread safety (see note at the top of this file). + * global_error.json = NULL; global_error.position = 0; + */ if (value == NULL || 0 == buffer_length) { @@ -1175,7 +1186,9 @@ fail: *return_parse_end = (const char*)local_error.json + local_error.position; } + /* NOTE: disabled due to thread safety (see note at the top of this file). global_error = local_error; + */ } return NULL; @@ -2470,7 +2483,7 @@ CJSON_AS4CPP_PUBLIC(cJSON *) cJSON_AS4CPP_CreateInt64(long long num) if (num > INT_MAX || num < INT_MIN) { char buf[21]; - sprintf(buf, "%lld", num); + snprintf(buf, sizeof(buf), "%lld", num); item->valuestring = (char*)cJSON_AS4CPP_strdup((const unsigned char*)buf, &global_hooks); } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp index ebe0fd9eec0..151a3686765 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp @@ -135,13 +135,15 @@ struct Entity { char value; }; -static const int NUM_ENTITIES = 5; +static const int NUM_ENTITIES = 7; static const Entity entities[NUM_ENTITIES] = { - { "quot", 4, DOUBLE_QUOTE }, - { "amp", 3, '&' }, - { "apos", 4, SINGLE_QUOTE }, - { "lt", 2, '<' }, - { "gt", 2, '>' } + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' }, + { "#xA", 3, LF }, + { "#xD", 3, CR } }; @@ -2396,6 +2398,8 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : _restrictedEntityFlag[(unsigned char)'&'] = true; _restrictedEntityFlag[(unsigned char)'<'] = true; _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice + _restrictedEntityFlag[(unsigned char)LF] = true; + _restrictedEntityFlag[(unsigned char)CR] = true; _buffer.Push( 0 ); } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp index a556e39a5d8..a08b21f9b58 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpClientFactory.cpp @@ -121,9 +121,11 @@ namespace Aws void InitStaticState() override { + AWS_LOGSTREAM_DEBUG(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Initializing Http Static State"); #if ENABLE_CURL_CLIENT if(s_InitCleanupCurlFlag) { + AWS_LOGSTREAM_DEBUG(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Initializing Curl Http Client"); CurlHttpClient::InitGlobalState(); } #if !defined (_WIN32) @@ -139,9 +141,11 @@ namespace Aws virtual void CleanupStaticState() override { + AWS_LOGSTREAM_DEBUG(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Cleanup Http Static State"); #if ENABLE_CURL_CLIENT if(s_InitCleanupCurlFlag) { + AWS_LOGSTREAM_DEBUG(HTTP_CLIENT_FACTORY_ALLOCATION_TAG, "Cleanup Curl Http Client"); CurlHttpClient::CleanupGlobalState(); } #endif diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp index 95cb626c22e..1f109c86a92 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpRequest.cpp @@ -4,37 +4,88 @@ */ #include <aws/core/http/HttpRequest.h> - +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/http/request_response.h> +#include <aws/crt/Types.h> +#include <aws/crt/http/HttpRequestResponse.h> namespace Aws { -namespace Http -{ + namespace Http + { -const char DATE_HEADER[] = "date"; -const char AWS_DATE_HEADER[] = "X-Amz-Date"; -const char AWS_SECURITY_TOKEN[] = "X-Amz-Security-Token"; -const char ACCEPT_HEADER[] = "accept"; -const char ACCEPT_CHAR_SET_HEADER[] = "accept-charset"; -const char ACCEPT_ENCODING_HEADER[] = "accept-encoding"; -const char AUTHORIZATION_HEADER[] = "authorization"; -const char AWS_AUTHORIZATION_HEADER[] = "authorization"; -const char COOKIE_HEADER[] = "cookie"; -const char CONTENT_LENGTH_HEADER[] = "content-length"; -const char CONTENT_TYPE_HEADER[] = "content-type"; -const char TRANSFER_ENCODING_HEADER[] = "transfer-encoding"; -const char USER_AGENT_HEADER[] = "user-agent"; -const char VIA_HEADER[] = "via"; -const char HOST_HEADER[] = "host"; -const char AMZ_TARGET_HEADER[] = "x-amz-target"; -const char X_AMZ_EXPIRES_HEADER[] = "X-Amz-Expires"; -const char CONTENT_MD5_HEADER[] = "content-md5"; -const char API_VERSION_HEADER[] = "x-amz-api-version"; -const char SDK_INVOCATION_ID_HEADER[] = "amz-sdk-invocation-id"; -const char SDK_REQUEST_HEADER[] = "amz-sdk-request"; -const char CHUNKED_VALUE[] = "chunked"; + const char DATE_HEADER[] = "date"; + const char AWS_DATE_HEADER[] = "X-Amz-Date"; + const char AWS_SECURITY_TOKEN[] = "X-Amz-Security-Token"; + const char ACCEPT_HEADER[] = "accept"; + const char ACCEPT_CHAR_SET_HEADER[] = "accept-charset"; + const char ACCEPT_ENCODING_HEADER[] = "accept-encoding"; + const char AUTHORIZATION_HEADER[] = "authorization"; + const char AWS_AUTHORIZATION_HEADER[] = "authorization"; + const char COOKIE_HEADER[] = "cookie"; + const char DECODED_CONTENT_LENGTH_HEADER[] = "x-amz-decoded-content-length"; + const char CONTENT_LENGTH_HEADER[] = "content-length"; + const char CONTENT_TYPE_HEADER[] = "content-type"; + const char CONTENT_ENCODING_HEADER[] = "content-encoding"; + const char TRANSFER_ENCODING_HEADER[] = "transfer-encoding"; + const char USER_AGENT_HEADER[] = "user-agent"; + const char VIA_HEADER[] = "via"; + const char HOST_HEADER[] = "host"; + const char AMZ_TARGET_HEADER[] = "x-amz-target"; + const char X_AMZ_EXPIRES_HEADER[] = "X-Amz-Expires"; + const char CONTENT_MD5_HEADER[] = "content-md5"; + const char API_VERSION_HEADER[] = "x-amz-api-version"; + const char AWS_TRAILER_HEADER[] = "x-amz-trailer"; + const char SDK_INVOCATION_ID_HEADER[] = "amz-sdk-invocation-id"; + const char SDK_REQUEST_HEADER[] = "amz-sdk-request"; + const char CHUNKED_VALUE[] = "chunked"; + const char AWS_CHUNKED_VALUE[] = "aws-chunked"; + const char X_AMZN_TRACE_ID_HEADER[] = "X-Amzn-Trace-Id"; + const char ALLOCATION_TAG[] = "HttpRequestConversion"; + const char X_AMZN_ERROR_TYPE[] = "x-amzn-errortype"; -} // Http -} // Aws + std::shared_ptr<Aws::Crt::Http::HttpRequest> HttpRequest::ToCrtHttpRequest() + { + auto request = Aws::MakeShared<Aws::Crt::Http::HttpRequest>(ALLOCATION_TAG); + request->SetBody([&]() -> std::shared_ptr<IOStream> { + const std::shared_ptr<Aws::IOStream>& body = GetContentBody(); + if (body) { + return body; + } + // Return an empty string stream for no body + return Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG, ""); + }()); + auto headers = GetHeaders(); + for (const auto& it: headers) + { + Aws::Crt::Http::HttpHeader header; + header.name = Aws::Crt::ByteCursorFromCString(it.first.c_str()); + header.value = Aws::Crt::ByteCursorFromCString(it.second.c_str()); + request->AddHeader(header); + } + // Need a different URL encoding here. + // CRT sigv4 don't any encoding if double encoding is off, need to encode the path before passing to CRT. + const URI& uri = m_uri; + Aws::StringStream ss; + Aws::StringStream port; + if (uri.GetScheme() == Scheme::HTTP && uri.GetPort() != HTTP_DEFAULT_PORT) + { + port << ":" << uri.GetPort(); + } + else if (uri.GetScheme() == Scheme::HTTPS && uri.GetPort() != HTTPS_DEFAULT_PORT) + { + port << ":" << uri.GetPort(); + } + ss << SchemeMapper::ToString(uri.GetScheme()) << SEPARATOR << uri.GetAuthority() << port.str() + << ((uri.GetPath() == "/") ? "" : URI::URLEncodePath(uri.GetPath())) + << uri.GetQueryString(); + request->SetPath(Aws::Crt::ByteCursorFromCString(ss.str().c_str())); + const char *method = HttpMethodMapper::GetNameForHttpMethod(m_method); + request->SetMethod(Aws::Crt::ByteCursorFromCString(method)); + return request; + } + + } // Http +} // Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpResponse.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpResponse.cpp new file mode 100644 index 00000000000..d4e08336531 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/HttpResponse.cpp @@ -0,0 +1,24 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/http/HttpResponse.h> + +#include <aws/core/utils/memory/stl/AWSStreamFwd.h> +#include <aws/core/utils/StringUtils.h> + +namespace Aws +{ + namespace Http + { + /** + * Overload ostream operator<< for HttpResponseCode enum class for a prettier output such as "200" and not "<C8-00 00-00>" + */ + Aws::OStream& operator<< (Aws::OStream& oStream, HttpResponseCode code) + { + oStream << Aws::Utils::StringUtils::to_string(static_cast<typename std::underlying_type<HttpResponseCode>::type>(code)); + return oStream; + } + } // Http +} // Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp index a2239df54b1..0bc3c092458 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/URI.cpp @@ -5,9 +5,8 @@ #include <aws/core/http/URI.h> -#include <aws/core/utils/StringUtils.h> -#include <aws/core/utils/memory/stl/AWSStringStream.h> #include <aws/core/utils/memory/stl/AWSSet.h> +#include <aws/core/utils/logging/LogMacros.h> #include <cstdlib> #include <cctype> @@ -25,10 +24,52 @@ namespace Http const char* SEPARATOR = "://"; +bool s_compliantRfc3986Encoding = false; +void SetCompliantRfc3986Encoding(bool compliant) { s_compliantRfc3986Encoding = compliant; } + +Aws::String urlEncodeSegment(const Aws::String& segment) +{ + // consolidates legacy escaping logic into one local method + if (s_compliantRfc3986Encoding) + { + return StringUtils::URLEncode(segment.c_str()); + } + else + { + Aws::StringStream ss; + ss << std::hex << std::uppercase; + for(unsigned char c : segment) // alnum results in UB if the value of c is not unsigned char & is not EOF + { + // RFC 3986 §2.3 unreserved characters + if (StringUtils::IsAlnum(c)) + { + ss << c; + continue; + } + switch(c) + { + // §2.3 unreserved characters + // The path section of the URL allows unreserved characters to appear unescaped + case '-': case '_': case '.': case '~': + // RFC 3986 §2.2 Reserved characters + // NOTE: this implementation does not accurately implement the RFC on purpose to accommodate for + // discrepancies in the implementations of URL encoding between AWS services for legacy reasons. + case '$': case '&': case ',': + case ':': case '=': case '@': + ss << c; + break; + default: + ss << '%' << std::setfill('0') << std::setw(2) << (int)c << std::setw(0); + } + } + return ss.str(); + } +} + } // namespace Http } // namespace Aws -URI::URI() : m_scheme(Scheme::HTTP), m_port(HTTP_DEFAULT_PORT) +URI::URI() : m_scheme(Scheme::HTTP), m_port(HTTP_DEFAULT_PORT), m_pathHasTrailingSlash(false) { } @@ -102,7 +143,7 @@ void URI::SetScheme(Scheme value) Aws::String URI::URLEncodePathRFC3986(const Aws::String& path) { - if(path.empty()) + if (path.empty()) { return path; } @@ -114,34 +155,10 @@ Aws::String URI::URLEncodePathRFC3986(const Aws::String& path) // escape characters appearing in a URL path according to RFC 3986 for (const auto& segment : pathParts) { - ss << '/'; - for(unsigned char c : segment) // alnum results in UB if the value of c is not unsigned char & is not EOF - { - // §2.3 unreserved characters - if (StringUtils::IsAlnum(c)) - { - ss << c; - continue; - } - switch(c) - { - // §2.3 unreserved characters - case '-': case '_': case '.': case '~': - // The path section of the URL allow reserved characters to appear unescaped - // RFC 3986 §2.2 Reserved characters - // NOTE: this implementation does not accurately implement the RFC on purpose to accommodate for - // discrepancies in the implementations of URL encoding between AWS services for legacy reasons. - case '$': case '&': case ',': - case ':': case '=': case '@': - ss << c; - break; - default: - ss << '%' << std::setfill('0') << std::setw(2) << (int)((unsigned char)c) << std::setw(0); - } - } + ss << '/' << urlEncodeSegment(segment); } - //if the last character was also a slash, then add that back here. + // if the last character was also a slash, then add that back here. if (path.back() == '/') { ss << '/'; @@ -176,23 +193,65 @@ Aws::String URI::URLEncodePath(const Aws::String& path) } } -void URI::SetPath(const Aws::String& value) +Aws::String URI::GetPath() const { - const Aws::Vector<Aws::String> pathParts = StringUtils::Split(value, '/'); - Aws::String path; - path.reserve(value.length() + 1/* in case we have to append slash before the path. */); + Aws::String path = ""; - for (const auto& segment : pathParts) + for (auto const& segment : m_pathSegments) { path.push_back('/'); path.append(segment); } - if (value.back() == '/') + if (m_pathSegments.empty() || m_pathHasTrailingSlash) { path.push_back('/'); } - m_path = std::move(path); + + return path; +} + +Aws::String URI::GetURLEncodedPath() const +{ + Aws::StringStream ss; + + for (auto const& segment : m_pathSegments) + { + ss << '/' << StringUtils::URLEncode(segment.c_str()); + } + + if (m_pathSegments.empty() || m_pathHasTrailingSlash) + { + ss << '/'; + } + + return ss.str(); +} + +Aws::String URI::GetURLEncodedPathRFC3986() const +{ + Aws::StringStream ss; + ss << std::hex << std::uppercase; + + // escape characters appearing in a URL path according to RFC 3986 + // (mostly; there is some non-standards legacy support that can be disabled) + for (const auto& segment : m_pathSegments) + { + ss << '/' << urlEncodeSegment(segment); + } + + if (m_pathSegments.empty() || m_pathHasTrailingSlash) + { + ss << '/'; + } + + return ss.str(); +} + +void URI::SetPath(const Aws::String& value) +{ + m_pathSegments.clear(); + AddPathSegments(value); } //ugh, this isn't even part of the canonicalization spec. It is part of how our services have implemented their signers though.... @@ -347,9 +406,9 @@ Aws::String URI::GetURIString(bool includeQueryString) const ss << ":" << m_port; } - if(m_path != "/") + if (!m_pathSegments.empty()) { - ss << URLEncodePathRFC3986(m_path); + ss << GetURLEncodedPathRFC3986(); } if(includeQueryString) @@ -397,10 +456,26 @@ void URI::ExtractAndSetAuthority(const Aws::String& uri) authorityStart += 3; } - size_t posOfEndOfAuthorityPort = uri.find(':', authorityStart); - size_t posOfEndOfAuthoritySlash = uri.find('/', authorityStart); - size_t posOfEndOfAuthorityQuery = uri.find('?', authorityStart); - size_t posEndOfAuthority = (std::min)({posOfEndOfAuthorityPort, posOfEndOfAuthoritySlash, posOfEndOfAuthorityQuery}); + size_t posEndOfAuthority=0; + // are we extracting an ipv6 address? + if (uri.length() > authorityStart && uri.at(authorityStart) == '[') + { + posEndOfAuthority = uri.find(']', authorityStart); + if (posEndOfAuthority == Aws::String::npos) { + AWS_LOGSTREAM_ERROR("Uri", "Malformed uri: " << uri.c_str()); + } + else + { + ++posEndOfAuthority; + } + } + else + { + size_t posOfEndOfAuthorityPort = uri.find(':', authorityStart); + size_t posOfEndOfAuthoritySlash = uri.find('/', authorityStart); + size_t posOfEndOfAuthorityQuery = uri.find('?', authorityStart); + posEndOfAuthority = (std::min)({posOfEndOfAuthorityPort, posOfEndOfAuthoritySlash, posOfEndOfAuthorityQuery}); + } if (posEndOfAuthority == Aws::String::npos) { posEndOfAuthority = uri.length(); @@ -422,11 +497,25 @@ void URI::ExtractAndSetPort(const Aws::String& uri) authorityStart += 3; } - size_t positionOfPortDelimiter = uri.find(':', authorityStart); + size_t portSearchStart = authorityStart; + // are we extracting an ipv6 address? + if (uri.length() > portSearchStart && uri.at(portSearchStart) == '[') + { + size_t posEndOfAuthority = uri.find(']', portSearchStart); + if (posEndOfAuthority == Aws::String::npos) { + AWS_LOGSTREAM_ERROR("Uri", "Malformed uri: " << uri.c_str()); + } + else + { + portSearchStart = posEndOfAuthority; + } + } + + size_t positionOfPortDelimiter = uri.find(':', portSearchStart); bool hasPort = positionOfPortDelimiter != Aws::String::npos; - if ((uri.find('/', authorityStart) < positionOfPortDelimiter) || (uri.find('?', authorityStart) < positionOfPortDelimiter)) + if ((uri.find('/', portSearchStart) < positionOfPortDelimiter) || (uri.find('?', portSearchStart) < positionOfPortDelimiter)) { hasPort = false; } @@ -506,5 +595,5 @@ Aws::String URI::GetFormParameters() const bool URI::CompareURIParts(const URI& other) const { - return m_scheme == other.m_scheme && m_authority == other.m_authority && m_path == other.m_path && m_queryString == other.m_queryString; + return m_scheme == other.m_scheme && m_authority == other.m_authority && GetPath() == other.GetPath() && m_queryString == other.m_queryString; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp index 1a965cd7950..a6684c640a8 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHandleContainer.cpp @@ -43,7 +43,7 @@ CURL* CurlHandleContainer::AcquireCurlHandle() } CURL* handle = m_handleContainer.Acquire(); - AWS_LOGSTREAM_INFO(CURL_HANDLE_CONTAINER_TAG, "Connection has been released. Continuing."); + AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Connection has been released. Continuing."); AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Returning connection handle " << handle); return handle; } @@ -52,6 +52,9 @@ void CurlHandleContainer::ReleaseCurlHandle(CURL* handle) { if (handle) { +#if LIBCURL_VERSION_NUM >= 0x074D00 // 7.77.0 + curl_easy_setopt(handle, CURLOPT_COOKIEFILE, NULL); // workaround a mem leak on curl +#endif curl_easy_reset(handle); SetDefaultOptionsOnHandle(handle); AWS_LOGSTREAM_DEBUG(CURL_HANDLE_CONTAINER_TAG, "Releasing curl handle " << handle); diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp index 95132f5df0e..0f64b150629 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/curl/CurlHttpClient.cpp @@ -7,9 +7,12 @@ #include <aws/core/http/HttpRequest.h> #include <aws/core/http/standard/StandardHttpResponse.h> #include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/HashingUtils.h> #include <aws/core/utils/logging/LogMacros.h> #include <aws/core/utils/ratelimiter/RateLimiterInterface.h> #include <aws/core/utils/DateTime.h> +#include <aws/core/utils/crypto/Hash.h> +#include <aws/core/utils/Outcome.h> #include <aws/core/monitoring/HttpClientMetrics.h> #include <cassert> #include <algorithm> @@ -146,17 +149,34 @@ struct CurlReadCallbackContext m_client(client), m_curlHandle(curlHandle), m_rateLimiter(limiter), - m_request(request) + m_request(request), + m_chunkEnd(false) {} const CurlHttpClient* m_client; CURL* m_curlHandle; Aws::Utils::RateLimits::RateLimiterInterface* m_rateLimiter; HttpRequest* m_request; + bool m_chunkEnd; }; static const char* CURL_HTTP_CLIENT_TAG = "CurlHttpClient"; +static int64_t GetContentLengthFromHeader(CURL* connectionHandle, + bool& hasContentLength) { +#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0 + curl_off_t contentLength = {}; + CURLcode res = curl_easy_getinfo( + connectionHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); +#else + double contentLength = {}; + CURLcode res = curl_easy_getinfo( + connectionHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength); +#endif + hasContentLength = (res == CURLE_OK) && (contentLength != -1); + return hasContentLength ? static_cast<int64_t>(contentLength) : -1; +} + static size_t WriteData(char* ptr, size_t size, size_t nmemb, void* userdata) { if (ptr) @@ -176,8 +196,13 @@ static size_t WriteData(char* ptr, size_t size, size_t nmemb, void* userdata) context->m_rateLimiter->ApplyAndPayForCost(static_cast<int64_t>(sizeToWrite)); } + for (const auto& hashIterator : context->m_request->GetResponseValidationHashes()) + { + hashIterator.second->Update(reinterpret_cast<unsigned char*>(ptr), sizeToWrite); + } + response->GetResponseBody().write(ptr, static_cast<std::streamsize>(sizeToWrite)); - if (context->m_request->IsEventStreamRequest()) + if (context->m_request->IsEventStreamRequest() && !response->HasHeader(Aws::Http::X_AMZN_ERROR_TYPE)) { response->GetResponseBody().flush(); } @@ -214,8 +239,7 @@ static size_t WriteHeader(char* ptr, size_t size, size_t nmemb, void* userdata) return 0; } - -static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata) +static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata, bool isStreaming) { CurlReadCallbackContext* context = reinterpret_cast<CurlReadCallbackContext*>(userdata); if(context == nullptr) @@ -232,10 +256,20 @@ static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata) HttpRequest* request = context->m_request; const std::shared_ptr<Aws::IOStream>& ioStream = request->GetContentBody(); - const size_t amountToRead = size * nmemb; + size_t amountToRead = size * nmemb; + bool isAwsChunked = request->HasHeader(Aws::Http::CONTENT_ENCODING_HEADER) && + request->GetHeaderValue(Aws::Http::CONTENT_ENCODING_HEADER) == Aws::Http::AWS_CHUNKED_VALUE; + // aws-chunk = hex(chunk-size) + CRLF + chunk-data + CRLF + // Needs to reserve bytes of sizeof(hex(chunk-size)) + sizeof(CRLF) + sizeof(CRLF) + if (isAwsChunked) + { + Aws::String amountToReadHexString = Aws::Utils::StringUtils::ToHexString(amountToRead); + amountToRead -= (amountToReadHexString.size() + 4); + } + if (ioStream != nullptr && amountToRead > 0) { - if (request->IsEventStreamRequest()) + if (isStreaming) { if (ioStream->readsome(ptr, amountToRead) == 0 && !ioStream->eof()) { @@ -247,6 +281,39 @@ static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata) ioStream->read(ptr, amountToRead); } size_t amountRead = static_cast<size_t>(ioStream->gcount()); + + if (isAwsChunked) + { + if (amountRead > 0) + { + if (request->GetRequestHash().second != nullptr) + { + request->GetRequestHash().second->Update(reinterpret_cast<unsigned char*>(ptr), amountRead); + } + + Aws::String hex = Aws::Utils::StringUtils::ToHexString(amountRead); + memmove(ptr + hex.size() + 2, ptr, amountRead); + memmove(ptr + hex.size() + 2 + amountRead, "\r\n", 2); + memmove(ptr, hex.c_str(), hex.size()); + memmove(ptr + hex.size(), "\r\n", 2); + amountRead += hex.size() + 4; + } + else if (!context->m_chunkEnd) + { + Aws::StringStream chunkedTrailer; + chunkedTrailer << "0\r\n"; + if (request->GetRequestHash().second != nullptr) + { + chunkedTrailer << "x-amz-checksum-" << request->GetRequestHash().first << ":" + << HashingUtils::Base64Encode(request->GetRequestHash().second->GetHash().GetResult()) << "\r\n"; + } + chunkedTrailer << "\r\n"; + amountRead = chunkedTrailer.str().size(); + memcpy(ptr, chunkedTrailer.str().c_str(), amountRead); + context->m_chunkEnd = true; + } + } + auto& sentHandler = request->GetDataSentEventHandler(); if (sentHandler) { @@ -264,6 +331,14 @@ static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata) return 0; } +static size_t ReadBodyStreaming(char* ptr, size_t size, size_t nmemb, void* userdata) { + return ReadBody(ptr, size, nmemb, userdata, true); +} + +static size_t ReadBodyFunc(char* ptr, size_t size, size_t nmemb, void* userdata) { + return ReadBody(ptr, size, nmemb, userdata, false); +} + static size_t SeekBody(void* userdata, curl_off_t offset, int origin) { CurlReadCallbackContext* context = reinterpret_cast<CurlReadCallbackContext*>(userdata); @@ -358,7 +433,11 @@ void SetOptCodeForHttpMethod(CURL* requestHandle, const std::shared_ptr<HttpRequ } else { +#if LIBCURL_VERSION_NUM >= 0x070c01 // 7.12.1 + curl_easy_setopt(requestHandle, CURLOPT_UPLOAD, 1L); +#else curl_easy_setopt(requestHandle, CURLOPT_PUT, 1L); +#endif } break; case HttpMethod::HTTP_HEAD: @@ -579,6 +658,9 @@ std::shared_ptr<HttpResponse> CurlHttpClient::MakeRequest(const std::shared_ptr< curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, m_caFile.c_str()); } + // enable the cookie engine without reading any initial cookies. + curl_easy_setopt(connectionHandle, CURLOPT_COOKIEFILE, ""); + // only set by android test builds because the emulator is missing a cert needed for aws services #ifdef TEST_CERT_PATH curl_easy_setopt(connectionHandle, CURLOPT_CAPATH, TEST_CERT_PATH); @@ -664,12 +746,13 @@ std::shared_ptr<HttpResponse> CurlHttpClient::MakeRequest(const std::shared_ptr< if (request->GetContentBody()) { - curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, ReadBody); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, ReadBodyFunc); curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &readContext); curl_easy_setopt(connectionHandle, CURLOPT_SEEKFUNCTION, SeekBody); curl_easy_setopt(connectionHandle, CURLOPT_SEEKDATA, &readContext); - if (request->IsEventStreamRequest()) + if (request->IsEventStreamRequest() && !response->HasHeader(Aws::Http::X_AMZN_ERROR_TYPE)) { + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, ReadBodyStreaming); curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 0L); #if LIBCURL_VERSION_NUM >= 0x072000 // 7.32.0 curl_easy_setopt(connectionHandle, CURLOPT_XFERINFOFUNCTION, CurlProgressCallback); @@ -714,15 +797,18 @@ std::shared_ptr<HttpResponse> CurlHttpClient::MakeRequest(const std::shared_ptr< AWS_LOGSTREAM_DEBUG(CURL_HTTP_CLIENT_TAG, "Returned content type " << contentType); } + bool hasContentLength = false; + int64_t contentLength = + GetContentLengthFromHeader(connectionHandle, hasContentLength); + if (request->GetMethod() != HttpMethod::HTTP_HEAD && writeContext.m_client->IsRequestProcessingEnabled() && - response->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER)) + hasContentLength) { - const Aws::String& contentLength = response->GetHeader(Aws::Http::CONTENT_LENGTH_HEADER); int64_t numBytesResponseReceived = writeContext.m_numBytesResponseReceived; AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Response content-length header: " << contentLength); AWS_LOGSTREAM_TRACE(CURL_HTTP_CLIENT_TAG, "Response body length: " << numBytesResponseReceived); - if (StringUtils::ConvertToInt64(contentLength.c_str()) != numBytesResponseReceived) + if (contentLength != numBytesResponseReceived) { response->SetClientErrorType(CoreErrors::NETWORK_CONNECTION); response->SetClientErrorMessage("Response body length doesn't match the content-length header."); diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp index 47a0ee4faca..87b857ca24e 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpRequest.cpp @@ -4,7 +4,7 @@ */ #include <aws/core/http/standard/StandardHttpRequest.h> - +#include <aws/core/utils/logging/LogMacros.h> #include <aws/core/utils/StringUtils.h> #include <iostream> @@ -15,6 +15,8 @@ using namespace Aws::Http; using namespace Aws::Http::Standard; using namespace Aws::Utils; +static const char* STANDARD_HTTP_REQUEST_LOG_TAG = "StandardHttpRequest"; + static bool IsDefaultPort(const URI& uri) { switch(uri.GetPort()) @@ -59,8 +61,13 @@ HeaderValueCollection StandardHttpRequest::GetHeaders() const const Aws::String& StandardHttpRequest::GetHeaderValue(const char* headerName) const { - auto iter = headerMap.find(headerName); + auto iter = headerMap.find(StringUtils::ToLower(headerName)); assert (iter != headerMap.end()); + if (iter == headerMap.end()) { + AWS_LOGSTREAM_ERROR(STANDARD_HTTP_REQUEST_LOG_TAG, "Requested a header value for a missing header key: " << headerName); + static const Aws::String EMPTY_STRING = ""; + return EMPTY_STRING; + } return iter->second; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp index 92d7a062b6c..8b62ae5e634 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/http/standard/StandardHttpResponse.cpp @@ -6,6 +6,7 @@ #include <aws/core/http/standard/StandardHttpResponse.h> #include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/logging/LogMacros.h> #include <aws/core/utils/memory/AWSMemory.h> #include <istream> @@ -14,6 +15,7 @@ using namespace Aws::Http; using namespace Aws::Http::Standard; using namespace Aws::Utils; +static const char* STANDARD_HTTP_RESPONSE_LOG_TAG = "StandardHttpResponse"; HeaderValueCollection StandardHttpResponse::GetHeaders() const { @@ -35,6 +37,12 @@ bool StandardHttpResponse::HasHeader(const char* headerName) const const Aws::String& StandardHttpResponse::GetHeader(const Aws::String& headerName) const { Aws::Map<Aws::String, Aws::String>::const_iterator foundValue = headerMap.find(StringUtils::ToLower(headerName.c_str())); + assert(foundValue != headerMap.end()); + if (foundValue == headerMap.end()) { + AWS_LOGSTREAM_ERROR(STANDARD_HTTP_RESPONSE_LOG_TAG, "Requested a header value for a missing header key: " << headerName); + static const Aws::String EMPTY_STRING = ""; + return EMPTY_STRING; + } return foundValue->second; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp index 2f372ec82a7..ca664cc6c43 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp @@ -140,12 +140,12 @@ namespace Aws } const Aws::Client::AWSError<Aws::Client::CoreErrors> error = [this, &response]() { - if (response->HasClientError() || response->GetResponseBody().tellp() < 1) + if (response->HasClientError() || response->GetResponseCode() == HttpResponseCode::REQUEST_NOT_MADE) { AWS_LOGSTREAM_ERROR(m_logtag.c_str(), "Http request to retrieve credentials failed"); return AWSError<CoreErrors>(CoreErrors::NETWORK_CONNECTION, true); // Retryable } - else if (m_errorMarshaller) + else if (m_errorMarshaller && response->GetResponseBody().tellp() > 0) { return m_errorMarshaller->Marshall(*response); } @@ -170,14 +170,23 @@ namespace Aws } } - EC2MetadataClient::EC2MetadataClient(const char* endpoint) - : AWSHttpResourceClient(EC2_METADATA_CLIENT_LOG_TAG), m_endpoint(endpoint), m_tokenRequired(true) + EC2MetadataClient::EC2MetadataClient(const char *endpoint) : + AWSHttpResourceClient(EC2_METADATA_CLIENT_LOG_TAG), + m_endpoint(endpoint), + m_disableIMDS(false), + m_tokenRequired(true) { + } - EC2MetadataClient::EC2MetadataClient(const Aws::Client::ClientConfiguration &clientConfiguration, const char *endpoint) - : AWSHttpResourceClient(clientConfiguration, EC2_METADATA_CLIENT_LOG_TAG), m_endpoint(endpoint), m_tokenRequired(true) + EC2MetadataClient::EC2MetadataClient(const Aws::Client::ClientConfiguration &clientConfiguration, + const char *endpoint) : + AWSHttpResourceClient(clientConfiguration, EC2_METADATA_CLIENT_LOG_TAG), + m_endpoint(endpoint), + m_disableIMDS(clientConfiguration.disableIMDS), + m_tokenRequired(true) { + } EC2MetadataClient::~EC2MetadataClient() @@ -190,15 +199,20 @@ namespace Aws return GetResource(m_endpoint.c_str(), resourcePath, nullptr/*authToken*/); } +#if !defined(DISABLE_IMDSV1) Aws::String EC2MetadataClient::GetDefaultCredentials() const { + if (m_disableIMDS) { + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Skipping call to IMDS Service"); + return {}; + } std::unique_lock<std::recursive_mutex> locker(m_tokenMutex); if (m_tokenRequired) { return GetDefaultCredentialsSecurely(); } - AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Getting default credentials for ec2 instance"); + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Getting default credentials for ec2 instance from " << m_endpoint); auto result = GetResourceWithAWSWebServiceResult(m_endpoint.c_str(), EC2_SECURITY_CREDENTIALS_RESOURCE, nullptr); Aws::String credentialsString = result.GetPayload(); auto httpResponseCode = result.GetResponseCode(); @@ -232,14 +246,20 @@ namespace Aws AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource " << ss.str()); return GetResource(ss.str().c_str()); } +#endif Aws::String EC2MetadataClient::GetDefaultCredentialsSecurely() const { + if (m_disableIMDS) { + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Skipping call to IMDS Service"); + return {}; + } std::unique_lock<std::recursive_mutex> locker(m_tokenMutex); - if (!m_tokenRequired) - { +#if !defined(DISABLE_IMDSV1) + if (!m_tokenRequired) { return GetDefaultCredentials(); } +#endif Aws::StringStream ss; ss << m_endpoint << EC2_IMDS_TOKEN_RESOURCE; @@ -257,12 +277,14 @@ namespace Aws { return {}; } +#if !defined(DISABLE_IMDSV1) else if (result.GetResponseCode() != HttpResponseCode::OK || trimmedTokenString.empty()) { m_tokenRequired = false; AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Calling EC2MetadataService to get token failed, falling back to less secure way."); return GetDefaultCredentials(); } +#endif m_token = trimmedTokenString; locker.unlock(); ss.str(""); @@ -278,7 +300,7 @@ namespace Aws AWS_LOGSTREAM_DEBUG(m_logtag.c_str(), "Calling EC2MetadataService resource, " << EC2_SECURITY_CREDENTIALS_RESOURCE << " with token returned profile string " << trimmedProfileString); - if (securityCredentials.size() == 0) + if (securityCredentials.empty()) { AWS_LOGSTREAM_WARN(m_logtag.c_str(), "Calling EC2Metadataservice to get profiles failed"); return {}; @@ -296,6 +318,10 @@ namespace Aws Aws::String EC2MetadataClient::GetCurrentRegion() const { + if (m_disableIMDS) { + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "Skipping call to IMDS Service"); + return {}; + } if (!m_region.empty()) { return m_region; @@ -311,6 +337,7 @@ namespace Aws std::lock_guard<std::recursive_mutex> locker(m_tokenMutex); if (m_tokenRequired) { + GetDefaultCredentialsSecurely(); regionRequest->SetHeaderValue(EC2_IMDS_TOKEN_HEADER, m_token); } } @@ -351,6 +378,16 @@ namespace Aws return region; } + void EC2MetadataClient::SetEndpoint(const Aws::String& endpoint) + { + m_endpoint = endpoint; + } + + Aws::String EC2MetadataClient::GetEndpoint() const + { + return Aws::String(m_endpoint); + } + #ifdef _MSC_VER // VS2015 compiler's bug, warning s_ec2metadataClient: symbol will be dynamically initialized (implementation limitation) AWS_SUPPRESS_WARNING(4592, @@ -366,7 +403,39 @@ namespace Aws { return; } - s_ec2metadataClient = Aws::MakeShared<EC2MetadataClient>(EC2_METADATA_CLIENT_LOG_TAG); + Aws::String ec2MetadataServiceEndpoint = Aws::Environment::GetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT"); + if (ec2MetadataServiceEndpoint.empty()) + { + Aws::String ec2MetadataServiceEndpointMode = Aws::Environment::GetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE").c_str(); + if (ec2MetadataServiceEndpointMode.length() == 0 ) + { + ec2MetadataServiceEndpoint = "http://169.254.169.254"; //default to IPv4 default endpoint + } + else + { + if (ec2MetadataServiceEndpointMode.length() == 4 ) + { + if (Aws::Utils::StringUtils::CaselessCompare(ec2MetadataServiceEndpointMode.c_str(), "ipv4")) + { + ec2MetadataServiceEndpoint = "http://169.254.169.254"; //default to IPv4 default endpoint + } + else if (Aws::Utils::StringUtils::CaselessCompare(ec2MetadataServiceEndpointMode.c_str(), "ipv6")) + { + ec2MetadataServiceEndpoint = "http://[fd00:ec2::254]"; + } + else + { + AWS_LOGSTREAM_ERROR(EC2_METADATA_CLIENT_LOG_TAG, "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE can only be set to ipv4 or ipv6, received: " << ec2MetadataServiceEndpointMode ); + } + } + else + { + AWS_LOGSTREAM_ERROR(EC2_METADATA_CLIENT_LOG_TAG, "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE can only be set to ipv4 or ipv6, received: " << ec2MetadataServiceEndpointMode ); + } + } + } + AWS_LOGSTREAM_INFO(EC2_METADATA_CLIENT_LOG_TAG, "Using IMDS endpoint: " << ec2MetadataServiceEndpoint); + s_ec2metadataClient = Aws::MakeShared<EC2MetadataClient>(EC2_METADATA_CLIENT_LOG_TAG, ec2MetadataServiceEndpoint.c_str()); } void CleanupEC2MetadataClient() @@ -383,7 +452,6 @@ namespace Aws return s_ec2metadataClient; } - ECSCredentialsClient::ECSCredentialsClient(const char* resourcePath, const char* endpoint, const char* token) : AWSHttpResourceClient(ECS_CREDENTIALS_CLIENT_LOG_TAG), m_resourcePath(resourcePath), m_endpoint(endpoint), m_token(token) @@ -510,6 +578,17 @@ namespace Aws { SetErrorMarshaller(Aws::MakeUnique<Aws::Client::JsonErrorMarshaller>(SSO_RESOURCE_CLIENT_LOG_TAG)); + m_endpoint = buildEndpoint(clientConfiguration, "portal.sso.", "federation/credentials"); + m_oidcEndpoint = buildEndpoint(clientConfiguration, "oidc.", "token"); + + AWS_LOGSTREAM_INFO(SSO_RESOURCE_CLIENT_LOG_TAG, "Creating SSO ResourceClient with endpoint: " << m_endpoint); + } + + Aws::String SSOCredentialsClient::buildEndpoint( + const Aws::Client::ClientConfiguration& clientConfiguration, + const Aws::String& domain, + const Aws::String& endpoint) + { Aws::StringStream ss; if (clientConfiguration.scheme == Aws::Http::Scheme::HTTP) { @@ -525,15 +604,12 @@ namespace Aws auto hash = Aws::Utils::HashingUtils::HashString(clientConfiguration.region.c_str()); AWS_LOGSTREAM_DEBUG(SSO_RESOURCE_CLIENT_LOG_TAG, "Preparing SSO client for region: " << clientConfiguration.region); - - ss << "portal.sso." << clientConfiguration.region << ".amazonaws.com/federation/credentials"; + ss << domain << clientConfiguration.region << ".amazonaws.com/" << endpoint; if (hash == CN_NORTH_1_HASH || hash == CN_NORTHWEST_1_HASH) { ss << ".cn"; } - m_endpoint = ss.str(); - - AWS_LOGSTREAM_INFO(SSO_RESOURCE_CLIENT_LOG_TAG, "Creating SSO ResourceClient with endpoint: " << m_endpoint); + return ss.str(); } SSOCredentialsClient::SSOGetRoleCredentialsResult SSOCredentialsClient::GetSSOCredentials(const SSOGetRoleCredentialsRequest &request) @@ -571,5 +647,70 @@ namespace Aws result.creds = creds; return result; } + + // An internal SSO CreateToken implementation to lightweight core package and not introduce a dependency on sso-oidc + SSOCredentialsClient::SSOCreateTokenResult SSOCredentialsClient::CreateToken(const SSOCreateTokenRequest& request) + { + std::shared_ptr<HttpRequest> httpRequest(CreateHttpRequest(m_oidcEndpoint, HttpMethod::HTTP_POST, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + SSOCreateTokenResult result; + if(!httpRequest) { + AWS_LOGSTREAM_FATAL(SSO_RESOURCE_CLIENT_LOG_TAG, "Failed to CreateHttpRequest: nullptr returned"); + return result; + } + httpRequest->SetUserAgent(ComputeUserAgentString()); + + Json::JsonValue requestDoc; + if(!request.clientId.empty()) { + requestDoc.WithString("clientId", request.clientId); + } + if(!request.clientSecret.empty()) { + requestDoc.WithString("clientSecret", request.clientSecret); + } + if(!request.grantType.empty()) { + requestDoc.WithString("grantType", request.grantType); + } + if(!request.refreshToken.empty()) { + requestDoc.WithString("refreshToken", request.refreshToken); + } + + std::shared_ptr<Aws::IOStream> body = Aws::MakeShared<Aws::StringStream>("SSO_BEARER_TOKEN_CREATE_TOKEN"); + if(!body) { + AWS_LOGSTREAM_FATAL(SSO_RESOURCE_CLIENT_LOG_TAG, "Failed to allocate body"); // exceptions disabled + return result; + } + *body << requestDoc.View().WriteReadable();; + + httpRequest->AddContentBody(body); + body->seekg(0, body->end); + auto streamSize = body->tellg(); + body->seekg(0, body->beg); + Aws::StringStream contentLength; + contentLength << streamSize; + httpRequest->SetContentLength(contentLength.str()); + httpRequest->SetContentType("application/json"); + + Aws::String rawReply = GetResourceWithAWSWebServiceResult(httpRequest).GetPayload(); + Json::JsonValue refreshTokenDoc(rawReply); + Utils::Json::JsonView jsonValue = refreshTokenDoc.View(); + + if(jsonValue.ValueExists("accessToken")) { + result.accessToken = jsonValue.GetString("accessToken"); + } + if(jsonValue.ValueExists("tokenType")) { + result.tokenType = jsonValue.GetString("tokenType"); + } + if(jsonValue.ValueExists("expiresIn")) { + result.expiresIn = jsonValue.GetInteger("expiresIn"); + } + if(jsonValue.ValueExists("idToken")) { + result.idToken = jsonValue.GetString("idToken"); + } + if(jsonValue.ValueExists("refreshToken")) { + result.refreshToken = jsonValue.GetString("refreshToken"); + } + + return result; + } } } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp index 7a8d3adb41c..d6891933c7c 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp @@ -25,16 +25,18 @@ namespace Aws /** * Global factory to create global metrics instance. */ - static Aws::UniquePtr<Monitors> s_monitors; + static Monitors* s_monitors(nullptr); Aws::Vector<void*> OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) { - assert(s_monitors); Aws::Vector<void*> contexts; - contexts.reserve(s_monitors->size()); - for (const auto& interface: *s_monitors) + if (s_monitors) { - contexts.emplace_back(interface->OnRequestStarted(serviceName, requestName, request)); + contexts.reserve(s_monitors->size()); + for (const auto& interface: *s_monitors) + { + contexts.emplace_back(interface->OnRequestStarted(serviceName, requestName, request)); + } } return contexts; } @@ -42,48 +44,56 @@ namespace Aws void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts) { - assert(s_monitors); - assert(contexts.size() == s_monitors->size()); - size_t index = 0; - for (const auto& interface: *s_monitors) + if (s_monitors) { - interface->OnRequestSucceeded(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestSucceeded(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + } } } void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, const Aws::Vector<void*>& contexts) { - assert(s_monitors); - assert(contexts.size() == s_monitors->size()); - size_t index = 0; - for (const auto& interface: *s_monitors) + if (s_monitors) { - interface->OnRequestFailed(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestFailed(serviceName, requestName, request, outcome, metricsFromCore, contexts[index++]); + } } } void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts) { - assert(s_monitors); - assert(contexts.size() == s_monitors->size()); - size_t index = 0; - for (const auto& interface: *s_monitors) + if (s_monitors) { - interface->OnRequestRetry(serviceName, requestName, request, contexts[index++]); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnRequestRetry(serviceName, requestName, request, contexts[index++]); + } } } void OnFinish(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request, const Aws::Vector<void*>& contexts) { - assert(s_monitors); - assert(contexts.size() == s_monitors->size()); - size_t index = 0; - for (const auto& interface: *s_monitors) + if (s_monitors) { - interface->OnFinish(serviceName, requestName, request, contexts[index++]); + assert(contexts.size() == s_monitors->size()); + size_t index = 0; + for (const auto& interface: *s_monitors) + { + interface->OnFinish(serviceName, requestName, request, contexts[index++]); + } } } @@ -93,7 +103,8 @@ namespace Aws { return; } - s_monitors = Aws::MakeUnique<Monitors>(MonitoringTag); + assert(Aws::get_aws_allocator() != nullptr); + s_monitors = Aws::New<Monitors>(MonitoringTag); for (const auto& function: monitoringFactoryCreateFunctions) { auto factory = function(); @@ -117,11 +128,7 @@ namespace Aws void CleanupMonitoring() { - if (!s_monitors) - { - return; - } - + Aws::Delete(s_monitors); s_monitors = nullptr; } } // namespace Monitoring diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp index b690c90c2dd..5ef76dcfc67 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/DateTimeCommon.cpp @@ -176,7 +176,7 @@ static int GetWeekDayNumberFromStr(const char* timeString, size_t startIndex, si } } -//Get the 0-11 monthy number from a string representing Month. Case insensitive and will stop on abbreviation +//Get the 0-11 monthly number from a string representing Month. Case insensitive and will stop on abbreviation static int GetMonthNumberFromStr(const char* timeString, size_t startIndex, size_t stopIndex) { if (stopIndex - startIndex < 3) @@ -842,7 +842,9 @@ public: break; case 6: - if ((c == 'Z' || c == '+' || c == '-' ) && (index - stateStartIndex == 3)) + if ((c == 'Z' || c == '+' || c == '-' ) && + (index - stateStartIndex >= 3) && + (index - stateStartIndex <= 9)) { m_tz[0] = c; m_state = 7; @@ -1268,6 +1270,12 @@ double DateTime::SecondsWithMSPrecision() const return timestamp.count(); } +int64_t DateTime::Seconds() const +{ + auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(m_time.time_since_epoch()); + return timestamp.count(); +} + int64_t DateTime::Millis() const { auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch()); diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Document.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Document.cpp new file mode 100644 index 00000000000..ef8210aeb1e --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/Document.cpp @@ -0,0 +1,673 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/Document.h> + +#include <iterator> +#include <algorithm> +#include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/json/JsonSerializer.h> + +using namespace Aws::Utils; + +Document::Document() : m_wasParseSuccessful(true) +{ + m_json = nullptr; +} + +Document::Document(cJSON* value) : + m_json(cJSON_AS4CPP_Duplicate(value, true /* recurse */)), + m_wasParseSuccessful(true) +{ +} + +Document::Document(const Aws::String& value) : m_wasParseSuccessful(true) +{ + const char* return_parse_end; + m_json = cJSON_AS4CPP_ParseWithOpts(value.c_str(), &return_parse_end, 1/*require_null_terminated*/); + + if (!m_json || cJSON_AS4CPP_IsInvalid(m_json)) + { + m_wasParseSuccessful = false; + m_errorMessage = "Failed to parse JSON at: "; + m_errorMessage += return_parse_end; + } +} + +Document::Document(Aws::IStream& istream) : m_wasParseSuccessful(true) +{ + Aws::StringStream memoryStream; + std::copy(std::istreambuf_iterator<char>(istream), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(memoryStream)); + const char* return_parse_end; + const auto input = memoryStream.str(); + m_json = cJSON_AS4CPP_ParseWithOpts(input.c_str(), &return_parse_end, 1/*require_null_terminated*/); + + if (!m_json || cJSON_AS4CPP_IsInvalid(m_json)) + { + m_wasParseSuccessful = false; + m_errorMessage = "Failed to parse JSON. Invalid input at: "; + m_errorMessage += return_parse_end; + } +} + +Document::Document(const Document& value) : + m_json(cJSON_AS4CPP_Duplicate(value.m_json, true/*recurse*/)), + m_wasParseSuccessful(value.m_wasParseSuccessful), + m_errorMessage(value.m_errorMessage) +{ +} + +Document::Document(Document&& value) : + m_json(value.m_json), + m_wasParseSuccessful(value.m_wasParseSuccessful), + m_errorMessage(std::move(value.m_errorMessage)) +{ + value.m_json = nullptr; +} + +Document::Document(const Json::JsonView& view) : + m_json(cJSON_AS4CPP_Duplicate(view.m_value, true/*recurse*/)), + m_wasParseSuccessful(true), + m_errorMessage({}) +{ +} + +void Document::Destroy() +{ + cJSON_AS4CPP_Delete(m_json); +} + +Document::~Document() +{ + Destroy(); +} + +Document& Document::operator=(const Document& other) +{ + if (this == &other) + { + return *this; + } + + Destroy(); + m_json = cJSON_AS4CPP_Duplicate(other.m_json, true /*recurse*/); + m_wasParseSuccessful = other.m_wasParseSuccessful; + m_errorMessage = other.m_errorMessage; + return *this; +} + +Document& Document::operator=(Document&& other) +{ + if (this == &other) + { + return *this; + } + + using std::swap; + swap(m_json, other.m_json); + swap(m_errorMessage, other.m_errorMessage); + m_wasParseSuccessful = other.m_wasParseSuccessful; + return *this; +} + +Document& Document::operator=(const Json::JsonView& other) +{ + Destroy(); + m_json = cJSON_AS4CPP_Duplicate(other.m_value, true /*recurse*/); + m_wasParseSuccessful = true; + m_errorMessage = {}; + return *this; +} + +bool Document::operator==(const Document& other) const +{ + return cJSON_AS4CPP_Compare(m_json, other.m_json, true /*case-sensitive*/) != 0; +} + +bool Document::operator!=(const Document& other) const +{ + return !(*this == other); +} + +static void AddOrReplace(cJSON* root, const char* key, cJSON* value) +{ + const auto existing = cJSON_AS4CPP_GetObjectItemCaseSensitive(root, key); + if (existing) + { + cJSON_AS4CPP_ReplaceItemInObjectCaseSensitive(root, key, value); + } + else + { + cJSON_AS4CPP_AddItemToObject(root, key, value); + } +} + +Document& Document::WithString(const char* key, const Aws::String& value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + const auto val = cJSON_AS4CPP_CreateString(value.c_str()); + AddOrReplace(m_json, key, val); + return *this; +} + +Document& Document::WithString(const Aws::String& key, const Aws::String& value) +{ + return WithString(key.c_str(), value); +} + +Document& Document::AsString(const Aws::String& value) +{ + Destroy(); + m_json = cJSON_AS4CPP_CreateString(value.c_str()); + return *this; +} + +Document& Document::WithBool(const char* key, bool value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + const auto val = cJSON_AS4CPP_CreateBool(value); + AddOrReplace(m_json, key, val); + return *this; +} + +Document& Document::WithBool(const Aws::String& key, bool value) +{ + return WithBool(key.c_str(), value); +} + +Document& Document::AsBool(bool value) +{ + Destroy(); + m_json = cJSON_AS4CPP_CreateBool(value); + return *this; +} + +Document& Document::WithInteger(const char* key, int value) +{ + return WithDouble(key, static_cast<double>(value)); +} + +Document& Document::WithInteger(const Aws::String& key, int value) +{ + return WithDouble(key.c_str(), static_cast<double>(value)); +} + +Document& Document::AsInteger(int value) +{ + Destroy(); + m_json = cJSON_AS4CPP_CreateNumber(static_cast<double>(value)); + return *this; +} + +Document& Document::WithInt64(const char* key, long long value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + const auto val = cJSON_AS4CPP_CreateInt64(value); + AddOrReplace(m_json, key, val); + return *this; +} + +Document& Document::WithInt64(const Aws::String& key, long long value) +{ + return WithInt64(key.c_str(), value); +} + +Document& Document::AsInt64(long long value) +{ + Destroy(); + m_json = cJSON_AS4CPP_CreateInt64(value); + return *this; +} + +Document& Document::WithDouble(const char* key, double value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + const auto val = cJSON_AS4CPP_CreateNumber(value); + AddOrReplace(m_json, key, val); + return *this; +} + +Document& Document::WithDouble(const Aws::String& key, double value) +{ + return WithDouble(key.c_str(), value); +} + +Document& Document::AsDouble(double value) +{ + Destroy(); + m_json = cJSON_AS4CPP_CreateNumber(value); + return *this; +} + +Document& Document::WithArray(const char* key, const Array<Aws::String>& array) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + auto arrayValue = cJSON_AS4CPP_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AS4CPP_AddItemToArray(arrayValue, cJSON_AS4CPP_CreateString(array[i].c_str())); + } + + AddOrReplace(m_json, key, arrayValue); + return *this; +} + +Document& Document::WithArray(const Aws::String& key, const Array<Aws::String>& array) +{ + return WithArray(key.c_str(), array); +} + +Document& Document::WithArray(const Aws::String& key, const Array<Document>& array) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + auto arrayValue = cJSON_AS4CPP_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AS4CPP_AddItemToArray(arrayValue, cJSON_AS4CPP_Duplicate(array[i].m_json, true /*recurse*/)); + } + + AddOrReplace(m_json, key.c_str(), arrayValue); + return *this; +} + +Document& Document::WithArray(const Aws::String& key, Array<Document>&& array) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + auto arrayValue = cJSON_AS4CPP_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AS4CPP_AddItemToArray(arrayValue, array[i].m_json); + array[i].m_json = nullptr; + } + + AddOrReplace(m_json, key.c_str(), arrayValue); + return *this; +} + +Document& Document::AsArray(const Array<Document>& array) +{ + auto arrayValue = cJSON_AS4CPP_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AS4CPP_AddItemToArray(arrayValue, cJSON_AS4CPP_Duplicate(array[i].m_json, true /*recurse*/)); + } + + Destroy(); + m_json = arrayValue; + return *this; +} + +Document& Document::AsArray(Array<Document>&& array) +{ + auto arrayValue = cJSON_AS4CPP_CreateArray(); + for (unsigned i = 0; i < array.GetLength(); ++i) + { + cJSON_AS4CPP_AddItemToArray(arrayValue, array[i].m_json); + array[i].m_json = nullptr; + } + + Destroy(); + m_json = arrayValue; + return *this; +} + +Document& Document::WithObject(const char* key, const Document& value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + const auto copy = value.m_json == nullptr ? cJSON_AS4CPP_CreateObject() : cJSON_AS4CPP_Duplicate(value.m_json, true /*recurse*/); + AddOrReplace(m_json, key, copy); + return *this; +} + +Document& Document::WithObject(const Aws::String& key, const Document& value) +{ + return WithObject(key.c_str(), value); +} + +Document& Document::WithObject(const char* key, Document&& value) +{ + if (!m_json) + { + m_json = cJSON_AS4CPP_CreateObject(); + } + + AddOrReplace(m_json, key, value.m_json == nullptr ? cJSON_AS4CPP_CreateObject() : value.m_json); + value.m_json = nullptr; + return *this; +} + +Document& Document::WithObject(const Aws::String& key, Document&& value) +{ + return WithObject(key.c_str(), std::move(value)); +} + +Document& Document::AsObject(const Document& value) +{ + *this = value; + return *this; +} + +Document& Document::AsObject(Document && value) +{ + *this = std::move(value); + return *this; +} + +DocumentView Document::View() const +{ + return *this; +} + +DocumentView::DocumentView() : m_json(nullptr) +{ +} + +DocumentView::DocumentView(const Document& value) : m_json(value.m_json) +{ +} + +DocumentView::DocumentView(cJSON* v) : m_json(v) +{ +} + +DocumentView& DocumentView::operator=(const Document& value) +{ + m_json = value.m_json; + return *this; +} + +DocumentView& DocumentView::operator=(cJSON* value) +{ + m_json = value; + return *this; +} + +Aws::String DocumentView::GetString(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + auto str = cJSON_AS4CPP_GetStringValue(item); + return str ? str : ""; +} + +Aws::String DocumentView::AsString() const +{ + const char* str = cJSON_AS4CPP_GetStringValue(m_json); + if (str == nullptr) + { + return {}; + } + return str; +} + +bool DocumentView::IsString() const +{ + return cJSON_AS4CPP_IsString(m_json) != 0; +} + +bool DocumentView::GetBool(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + assert(item); + return item->valueint != 0; +} + +bool DocumentView::AsBool() const +{ + assert(cJSON_AS4CPP_IsBool(m_json)); + return cJSON_AS4CPP_IsTrue(m_json) != 0; +} + +bool DocumentView::IsBool() const +{ + return cJSON_AS4CPP_IsBool(m_json) != 0; +} + +int DocumentView::GetInteger(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + assert(item); + return item->valueint; +} + +int DocumentView::AsInteger() const +{ + assert(cJSON_AS4CPP_IsNumber(m_json)); // can be double or value larger than int_max, but at least not UB + return m_json->valueint; +} + +bool DocumentView::IsIntegerType() const +{ + if (!cJSON_AS4CPP_IsNumber(m_json)) + { + return false; + } + + if (m_json->valuestring) + { + Aws::String valueString = m_json->valuestring; + return std::all_of(valueString.begin(), valueString.end(), [](unsigned char c){ return ::isdigit(c) || c == '+' || c == '-'; }); + } + return m_json->valuedouble == static_cast<long long>(m_json->valuedouble); +} + +int64_t DocumentView::GetInt64(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + assert(item); + if (item->valuestring) + { + return Aws::Utils::StringUtils::ConvertToInt64(item->valuestring); + } + else + { + return static_cast<int64_t>(item->valuedouble); + } +} + +int64_t DocumentView::AsInt64() const +{ + assert(cJSON_AS4CPP_IsNumber(m_json)); + if (m_json->valuestring) + { + return Aws::Utils::StringUtils::ConvertToInt64(m_json->valuestring); + } + else + { + return static_cast<int64_t>(m_json->valuedouble); + } +} + +double DocumentView::GetDouble(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + assert(item); + return item->valuedouble; +} + +double DocumentView::AsDouble() const +{ + assert(cJSON_AS4CPP_IsNumber(m_json)); + return m_json->valuedouble; +} + +bool DocumentView::IsFloatingPointType() const +{ + if (!cJSON_AS4CPP_IsNumber(m_json)) + { + return false; + } + + if (m_json->valuestring) + { + Aws::String valueString = m_json->valuestring; + return std::any_of(valueString.begin(), valueString.end(), [](unsigned char c){ return !::isdigit(c) && c != '+' && c != '-'; }); + } + return m_json->valuedouble != static_cast<long long>(m_json->valuedouble); +} + +Array<DocumentView> DocumentView::GetArray(const Aws::String& key) const +{ + assert(m_json); + auto array = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + assert(cJSON_AS4CPP_IsArray(array)); + Array<DocumentView> returnArray(cJSON_AS4CPP_GetArraySize(array)); + + auto element = array->child; + for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) + { + returnArray[i] = element; + } + + return returnArray; +} + +Array<DocumentView> DocumentView::AsArray() const +{ + assert(cJSON_AS4CPP_IsArray(m_json)); + Array<DocumentView> returnArray(cJSON_AS4CPP_GetArraySize(m_json)); + + auto element = m_json->child; + + for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) + { + returnArray[i] = element; + } + + return returnArray; +} + +bool DocumentView::IsListType() const +{ + return cJSON_AS4CPP_IsArray(m_json) != 0; +} + +DocumentView DocumentView::GetObject(const Aws::String& key) const +{ + assert(m_json); + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + return item; +} + +DocumentView DocumentView::AsObject() const +{ + assert(cJSON_AS4CPP_IsObject(m_json) || cJSON_AS4CPP_IsNull(m_json)); + return m_json; +} + +bool DocumentView::IsObject() const +{ + return cJSON_AS4CPP_IsObject(m_json) != 0; +} + +bool DocumentView::IsNull() const +{ + return cJSON_AS4CPP_IsNull(m_json) != 0; +} + +Aws::Map<Aws::String, DocumentView> DocumentView::GetAllObjects() const +{ + Aws::Map<Aws::String, DocumentView> valueMap; + if (!m_json) + { + return valueMap; + } + + for (auto iter = m_json->child; iter; iter = iter->next) + { + valueMap.emplace(std::make_pair(Aws::String(iter->string), DocumentView(iter))); + } + + return valueMap; +} + +bool DocumentView::ValueExists(const Aws::String& key) const +{ + if (!cJSON_AS4CPP_IsObject(m_json)) + { + return false; + } + + auto item = cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()); + return !(item == nullptr || cJSON_AS4CPP_IsNull(item)); +} + +bool DocumentView::KeyExists(const Aws::String& key) const +{ + if (!cJSON_AS4CPP_IsObject(m_json)) + { + return false; + } + + return cJSON_AS4CPP_GetObjectItemCaseSensitive(m_json, key.c_str()) != nullptr;; +} + +Aws::String DocumentView::WriteCompact() const +{ + if (!m_json) + { + return "null"; + } + + auto temp = cJSON_AS4CPP_PrintUnformatted(m_json); + Aws::String out(temp); + cJSON_AS4CPP_free(temp); + return out; +} + +Aws::String DocumentView::WriteReadable() const +{ + if (!m_json) + { + return "null"; + } + + auto temp = cJSON_AS4CPP_Print(m_json); + Aws::String out(temp); + cJSON_AS4CPP_free(temp); + return out; +} + +Document DocumentView::Materialize() const +{ + return m_json; +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp index 0e49a616343..0431835a615 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/HashingUtils.cpp @@ -11,6 +11,7 @@ #include <aws/core/utils/crypto/Sha256HMAC.h> #include <aws/core/utils/crypto/Sha1.h> #include <aws/core/utils/crypto/MD5.h> +#include <aws/core/utils/crypto/CRC32.h> #include <aws/core/utils/Outcome.h> #include <aws/core/utils/memory/stl/AWSStringStream.h> #include <aws/core/utils/memory/stl/AWSList.h> @@ -234,6 +235,30 @@ ByteBuffer HashingUtils::CalculateMD5(Aws::IOStream& stream) return hash.Calculate(stream).GetResult(); } +ByteBuffer HashingUtils::CalculateCRC32(const Aws::String& str) +{ + CRC32 hash; + return hash.Calculate(str).GetResult(); +} + +ByteBuffer HashingUtils::CalculateCRC32(Aws::IOStream& stream) +{ + CRC32 hash; + return hash.Calculate(stream).GetResult(); +} + +ByteBuffer HashingUtils::CalculateCRC32C(const Aws::String& str) +{ + CRC32C hash; + return hash.Calculate(str).GetResult(); +} + +ByteBuffer HashingUtils::CalculateCRC32C(Aws::IOStream& stream) +{ + CRC32C hash; + return hash.Calculate(stream).GetResult(); +} + int HashingUtils::HashString(const char* strToHash) { if (!strToHash) @@ -242,7 +267,7 @@ int HashingUtils::HashString(const char* strToHash) unsigned hash = 0; while (char charValue = *strToHash++) { - hash = charValue + 31 * hash; + hash = charValue + 31 * hash; } return hash; diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CRC32.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CRC32.cpp new file mode 100644 index 00000000000..c09806fbe0b --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/CRC32.cpp @@ -0,0 +1,218 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#include <aws/core/utils/crypto/CRC32.h> +#include <aws/core/utils/Outcome.h> +#include <aws/core/utils/crypto/Factories.h> +#include <aws/crt/Types.h> +#include <aws/checksums/crc.h> +#include <aws/common/byte_buf.h> + +using namespace Aws::Utils::Crypto; + +static Aws::Utils::ByteBuffer ByteBufferFromInt32(uint32_t value) +{ + Aws::Utils::ByteBuffer buffer(4); + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = value & 0xFF; + return buffer; +} + +CRC32::CRC32() : + m_hashImpl(CreateCRC32Implementation()) +{ +} + +CRC32::~CRC32() +{ +} + +HashResult CRC32::Calculate(const Aws::String& str) +{ + return m_hashImpl->Calculate(str); +} + +HashResult CRC32::Calculate(Aws::IStream& stream) +{ + return m_hashImpl->Calculate(stream); +} + +void CRC32::Update(unsigned char* buffer, size_t bufferSize) +{ + m_hashImpl->Update(buffer, bufferSize); +} + +HashResult CRC32::GetHash() +{ + return m_hashImpl->GetHash(); +} + +CRC32C::CRC32C() : + m_hashImpl(CreateCRC32CImplementation()) +{ +} + +CRC32C::~CRC32C() +{ +} + +HashResult CRC32C::Calculate(const Aws::String& str) +{ + return m_hashImpl->Calculate(str); +} + +HashResult CRC32C::Calculate(Aws::IStream& stream) +{ + return m_hashImpl->Calculate(stream); +} + + +void CRC32C::Update(unsigned char* buffer, size_t bufferSize) +{ + m_hashImpl->Update(buffer, bufferSize); +} + +HashResult CRC32C::GetHash() +{ + return m_hashImpl->GetHash(); +} + + +CRC32Impl::CRC32Impl() : m_runningCrc32(0) {} + +HashResult CRC32Impl::Calculate(const Aws::String& str) +{ + Aws::Crt::ByteCursor byteCursor = Aws::Crt::ByteCursorFromArray(reinterpret_cast<const uint8_t*>(str.data()), str.size()); + + uint32_t runningCrc32 = 0; + while (byteCursor.len > INT_MAX) + { + runningCrc32 = aws_checksums_crc32(byteCursor.ptr, INT_MAX, runningCrc32); + aws_byte_cursor_advance(&byteCursor, INT_MAX); + } + runningCrc32 = aws_checksums_crc32(byteCursor.ptr, static_cast<int>(byteCursor.len), runningCrc32); + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(runningCrc32); + return HashResult(std::move(hash)); +} + +HashResult CRC32Impl::Calculate(Aws::IStream& stream) +{ + uint32_t runningCrc32 = 0; + + auto currentPos = stream.tellg(); + if (currentPos == std::ios::pos_type(-1)) + { + currentPos = 0; + stream.clear(); + } + + stream.seekg(0, stream.beg); + + uint8_t streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; + while (stream.good()) + { + stream.read(reinterpret_cast<char*>(streamBuffer), Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); + auto bytesRead = stream.gcount(); + + if (bytesRead > 0) + { + runningCrc32 = aws_checksums_crc32(streamBuffer, static_cast<int>(bytesRead), runningCrc32); + } + } + + stream.clear(); + stream.seekg(currentPos, stream.beg); + + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(runningCrc32); + return HashResult(std::move(hash)); +} + +void CRC32Impl::Update(unsigned char* buffer, size_t bufferSize) +{ + Aws::Crt::ByteCursor byteCursor = Aws::Crt::ByteCursorFromArray(buffer, bufferSize); + + while (byteCursor.len > INT_MAX) + { + m_runningCrc32 = aws_checksums_crc32(byteCursor.ptr, INT_MAX, m_runningCrc32); + aws_byte_cursor_advance(&byteCursor, INT_MAX); + } + m_runningCrc32 = aws_checksums_crc32(byteCursor.ptr, static_cast<int>(byteCursor.len), m_runningCrc32); +} + +HashResult CRC32Impl::GetHash() +{ + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(m_runningCrc32); + return HashResult(std::move(hash)); +} + +CRC32CImpl::CRC32CImpl() : m_runningCrc32c(0) {} + +HashResult CRC32CImpl::Calculate(const Aws::String& str) +{ + Aws::Crt::ByteCursor byteCursor = Aws::Crt::ByteCursorFromArray(reinterpret_cast<const uint8_t*>(str.data()), str.size()); + + uint32_t runningCrc32c = 0; + while (byteCursor.len > INT_MAX) + { + runningCrc32c = aws_checksums_crc32c(byteCursor.ptr, INT_MAX, runningCrc32c); + aws_byte_cursor_advance(&byteCursor, INT_MAX); + } + runningCrc32c = aws_checksums_crc32c(byteCursor.ptr, static_cast<int>(byteCursor.len), runningCrc32c); + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(runningCrc32c); + return HashResult(std::move(hash)); +} + +HashResult CRC32CImpl::Calculate(Aws::IStream& stream) +{ + uint32_t runningCrc32c = 0; + + auto currentPos = stream.tellg(); + if (currentPos == std::ios::pos_type(-1)) + { + currentPos = 0; + stream.clear(); + } + + stream.seekg(0, stream.beg); + + uint8_t streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; + while (stream.good()) + { + stream.read(reinterpret_cast<char*>(streamBuffer), Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); + auto bytesRead = stream.gcount(); + + if (bytesRead > 0) + { + runningCrc32c = aws_checksums_crc32c(streamBuffer, static_cast<int>(bytesRead), runningCrc32c); + } + } + + stream.clear(); + stream.seekg(currentPos, stream.beg); + + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(runningCrc32c); + return HashResult(std::move(hash)); +} + +void CRC32CImpl::Update(unsigned char* buffer, size_t bufferSize) +{ + Aws::Crt::ByteCursor byteCursor = Aws::Crt::ByteCursorFromArray(buffer, bufferSize); + + while (byteCursor.len > INT_MAX) + { + m_runningCrc32c = aws_checksums_crc32c(byteCursor.ptr, INT_MAX, m_runningCrc32c); + aws_byte_cursor_advance(&byteCursor, INT_MAX); + } + m_runningCrc32c = aws_checksums_crc32c(byteCursor.ptr, static_cast<int>(byteCursor.len), m_runningCrc32c); +} + +HashResult CRC32CImpl::GetHash() +{ + const Aws::Utils::ByteBuffer& hash = ByteBufferFromInt32(m_runningCrc32c); + return HashResult(std::move(hash)); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp index bf14ace1ad3..f442878a90b 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/MD5.cpp @@ -11,7 +11,7 @@ using namespace Aws::Utils::Crypto; -MD5::MD5() : +MD5::MD5() : m_hashImpl(CreateMD5Implementation()) { } @@ -28,4 +28,14 @@ HashResult MD5::Calculate(const Aws::String& str) HashResult MD5::Calculate(Aws::IStream& stream) { return m_hashImpl->Calculate(stream); -}
\ No newline at end of file +} + +void MD5::Update(unsigned char* buffer, size_t bufferSize) +{ + return m_hashImpl->Update(buffer, bufferSize); +} + +HashResult MD5::GetHash() +{ + return m_hashImpl->GetHash(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha1.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha1.cpp index 5da3e63d28f..a6783e18f0f 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha1.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha1.cpp @@ -28,3 +28,13 @@ HashResult Sha1::Calculate(Aws::IStream& stream) { return m_hashImpl->Calculate(stream); } + +void Sha1::Update(unsigned char* buffer, size_t bufferSize) +{ + return m_hashImpl->Update(buffer, bufferSize); +} + +HashResult Sha1::GetHash() +{ + return m_hashImpl->GetHash(); +}
\ No newline at end of file diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp index a8aa5ae8790..48612e8cf03 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/Sha256.cpp @@ -27,4 +27,14 @@ HashResult Sha256::Calculate(const Aws::String& str) HashResult Sha256::Calculate(Aws::IStream& stream) { return m_hashImpl->Calculate(stream); -}
\ No newline at end of file +} + +void Sha256::Update(unsigned char* buffer, size_t bufferSize) +{ + return m_hashImpl->Update(buffer, bufferSize); +} + +HashResult Sha256::GetHash() +{ + return m_hashImpl->GetHash(); +} diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp index 88ca147d116..cba90af4f4d 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/factory/Factories.cpp @@ -7,6 +7,7 @@ #include <aws/core/utils/crypto/Factories.h> #include <aws/core/utils/crypto/Hash.h> #include <aws/core/utils/crypto/HMAC.h> +#include <aws/core/utils/crypto/CRC32.h> #if ENABLE_BCRYPT_ENCRYPTION #error #include <aws/core/utils/crypto/bcrypt/CryptoImpl.h> @@ -35,6 +36,18 @@ static std::shared_ptr<HashFactory>& GetMD5Factory() return s_MD5Factory; } +static std::shared_ptr<HashFactory>& GetCRC32Factory() +{ + static std::shared_ptr<HashFactory> s_CRC32Factory(nullptr); + return s_CRC32Factory; +} + +static std::shared_ptr<HashFactory>& GetCRC32CFactory() +{ + static std::shared_ptr<HashFactory> s_CRC32CFactory(nullptr); + return s_CRC32CFactory; +} + static std::shared_ptr<HashFactory>& GetSha1Factory() { static std::shared_ptr<HashFactory> s_Sha1Factory(nullptr); @@ -136,6 +149,24 @@ public: } }; +class DefaultCRC32Factory : public HashFactory +{ +public: + std::shared_ptr<Hash> CreateImplementation() const override + { + return Aws::MakeShared<CRC32Impl>(s_allocationTag); + } +}; + +class DefaultCRC32CFactory : public HashFactory +{ +public: + std::shared_ptr<Hash> CreateImplementation() const override + { + return Aws::MakeShared<CRC32CImpl>(s_allocationTag); + } +}; + class DefaultSHA1Factory : public HashFactory { public: @@ -667,6 +698,16 @@ void Aws::Utils::Crypto::InitCrypto() GetMD5Factory()->InitStaticState(); } + if(!GetCRC32Factory()) + { + GetCRC32Factory() = Aws::MakeShared<DefaultCRC32Factory>(s_allocationTag); + } + + if(!GetCRC32CFactory()) + { + GetCRC32CFactory() = Aws::MakeShared<DefaultCRC32CFactory>(s_allocationTag); + } + if(GetSha1Factory()) { GetSha1Factory()->InitStaticState(); @@ -754,6 +795,16 @@ void Aws::Utils::Crypto::CleanupCrypto() GetMD5Factory() = nullptr; } + if(GetCRC32CFactory()) + { + GetCRC32Factory() = nullptr; + } + + if(GetCRC32CFactory()) + { + GetCRC32CFactory() = nullptr; + } + if(GetSha1Factory()) { GetSha1Factory()->CleanupStaticState(); @@ -809,6 +860,16 @@ void Aws::Utils::Crypto::SetMD5Factory(const std::shared_ptr<HashFactory>& facto GetMD5Factory() = factory; } +void Aws::Utils::Crypto::SetCRC32Factory(const std::shared_ptr<HashFactory>& factory) +{ + GetCRC32Factory() = factory; +} + +void Aws::Utils::Crypto::SetCRC32CFactory(const std::shared_ptr<HashFactory>& factory) +{ + GetCRC32CFactory() = factory; +} + void Aws::Utils::Crypto::SetSha1Factory(const std::shared_ptr<HashFactory>& factory) { GetSha1Factory() = factory; @@ -854,6 +915,16 @@ std::shared_ptr<Hash> Aws::Utils::Crypto::CreateMD5Implementation() return GetMD5Factory()->CreateImplementation(); } +std::shared_ptr<Hash> Aws::Utils::Crypto::CreateCRC32Implementation() +{ + return GetCRC32Factory()->CreateImplementation(); +} + +std::shared_ptr<Hash> Aws::Utils::Crypto::CreateCRC32CImplementation() +{ + return GetCRC32CFactory()->CreateImplementation(); +} + std::shared_ptr<Hash> Aws::Utils::Crypto::CreateSha1Implementation() { return GetSha1Factory()->CreateImplementation(); @@ -967,5 +1038,5 @@ std::shared_ptr<SymmetricCipher> Aws::Utils::Crypto::CreateAES_KeyWrapImplementa std::shared_ptr<SecureRandomBytes> Aws::Utils::Crypto::CreateSecureRandomBytesImplementation() { - return GetSecureRandom(); + return GetSecureRandomFactory()->CreateImplementation(); } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp index 3a89265e6ec..faebde3a8d5 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/crypto/openssl/CryptoImpl.cpp @@ -8,6 +8,7 @@ #include <aws/core/utils/memory/AWSMemory.h> #include <aws/core/utils/crypto/openssl/CryptoImpl.h> #include <aws/core/utils/Outcome.h> +#include <openssl/crypto.h> #include <openssl/md5.h> #ifdef OPENSSL_IS_BORINGSSL @@ -47,9 +48,19 @@ namespace Aws */ #if defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER == 0x20000000L) #undef OPENSSL_VERSION_NUMBER +#if LIBRESSL_VERSION_NUMBER < 0x3050000fL #define OPENSSL_VERSION_NUMBER 0x1000107fL +#else +#define OPENSSL_VERSION_NUMBER 0x1010000fL +#endif #endif + #define OPENSSL_VERSION_LESS_1_1 (OPENSSL_VERSION_NUMBER < 0x10100003L) +#define OPENSSL_VERSION_LESS_3_0 (OPENSSL_VERSION_NUMBER < 0x30000000L) + +#if !OPENSSL_VERSION_LESS_3_0 +#error #include <openssl/core_names.h> +#endif #if OPENSSL_VERSION_LESS_1_1 static const char* OPENSSL_INTERNALS_TAG = "OpenSSLCallbackState"; @@ -65,7 +76,7 @@ namespace Aws #else OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS /*options*/ ,NULL /* OpenSSL init settings*/ ); #endif -#if !defined(OPENSSL_IS_BORINGSSL) +#if !(defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) OPENSSL_add_all_algorithms_noconf(); #endif #if OPENSSL_VERSION_LESS_1_1 @@ -168,6 +179,22 @@ namespace Aws EVP_MD_CTX *m_ctx; }; + MD5OpenSSLImpl::MD5OpenSSLImpl() + { + m_ctx = EVP_MD_CTX_create(); + assert(m_ctx != nullptr); +#if !defined(OPENSSL_IS_BORINGSSL) + EVP_MD_CTX_set_flags(m_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + EVP_DigestInit_ex(m_ctx, EVP_md5(), nullptr); + } + + MD5OpenSSLImpl::~MD5OpenSSLImpl() + { + EVP_MD_CTX_destroy(m_ctx); + m_ctx = nullptr; + } + HashResult MD5OpenSSLImpl::Calculate(const Aws::String& str) { OpensslCtxRAIIGuard guard; @@ -222,6 +249,34 @@ namespace Aws return HashResult(std::move(hash)); } + void MD5OpenSSLImpl::Update(unsigned char* buffer, size_t bufferSize) + { + EVP_DigestUpdate(m_ctx, buffer, bufferSize); + } + + HashResult MD5OpenSSLImpl::GetHash() + { + ByteBuffer hash(EVP_MD_size(EVP_md5())); + EVP_DigestFinal(m_ctx, hash.GetUnderlyingData(), nullptr); + return HashResult(std::move(hash)); + } + + Sha1OpenSSLImpl::Sha1OpenSSLImpl() + { + m_ctx = EVP_MD_CTX_create(); + assert(m_ctx != nullptr); +#if !defined(OPENSSL_IS_BORINGSSL) + EVP_MD_CTX_set_flags(m_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + EVP_DigestInit_ex(m_ctx, EVP_sha1(), nullptr); + } + + Sha1OpenSSLImpl::~Sha1OpenSSLImpl() + { + EVP_MD_CTX_destroy(m_ctx); + m_ctx = nullptr; + } + HashResult Sha1OpenSSLImpl::Calculate(const Aws::String& str) { OpensslCtxRAIIGuard guard; @@ -272,6 +327,34 @@ namespace Aws return HashResult(std::move(hash)); } + void Sha1OpenSSLImpl::Update(unsigned char* buffer, size_t bufferSize) + { + EVP_DigestUpdate(m_ctx, buffer, bufferSize); + } + + HashResult Sha1OpenSSLImpl::GetHash() + { + ByteBuffer hash(EVP_MD_size(EVP_sha1())); + EVP_DigestFinal(m_ctx, hash.GetUnderlyingData(), nullptr); + return HashResult(std::move(hash)); + } + + Sha256OpenSSLImpl::Sha256OpenSSLImpl() + { + m_ctx = EVP_MD_CTX_create(); + assert(m_ctx != nullptr); +#if !defined(OPENSSL_IS_BORINGSSL) + EVP_MD_CTX_set_flags(m_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); +#endif + EVP_DigestInit_ex(m_ctx, EVP_sha256(), nullptr); + } + + Sha256OpenSSLImpl::~Sha256OpenSSLImpl() + { + EVP_MD_CTX_destroy(m_ctx); + m_ctx = nullptr; + } + HashResult Sha256OpenSSLImpl::Calculate(const Aws::String& str) { OpensslCtxRAIIGuard guard; @@ -322,13 +405,28 @@ namespace Aws return HashResult(std::move(hash)); } + void Sha256OpenSSLImpl::Update(unsigned char* buffer, size_t bufferSize) + { + EVP_DigestUpdate(m_ctx, buffer, bufferSize); + } + + HashResult Sha256OpenSSLImpl::GetHash() + { + ByteBuffer hash(EVP_MD_size(EVP_sha256())); + EVP_DigestFinal(m_ctx, hash.GetUnderlyingData(), nullptr); + return HashResult(std::move(hash)); + } + class HMACRAIIGuard { public: HMACRAIIGuard() { #if OPENSSL_VERSION_LESS_1_1 m_ctx = Aws::New<HMAC_CTX>("AllocSha256HAMCOpenSSLContext"); -#else +#elif OPENSSL_VERSION_LESS_3_0 m_ctx = HMAC_CTX_new(); +#else + m_mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + m_ctx = EVP_MAC_CTX_new(m_mac); #endif assert(m_ctx != nullptr); } @@ -336,17 +434,29 @@ namespace Aws ~HMACRAIIGuard() { #if OPENSSL_VERSION_LESS_1_1 Aws::Delete<HMAC_CTX>(m_ctx); -#else +#elif OPENSSL_VERSION_LESS_3_0 HMAC_CTX_free(m_ctx); +#else + EVP_MAC_free(m_mac); + EVP_MAC_CTX_free(m_ctx); #endif m_ctx = nullptr; } +#if OPENSSL_VERSION_LESS_3_0 HMAC_CTX* getResource() { +#else + EVP_MAC_CTX* getResource() { +#endif return m_ctx; } private: +#if OPENSSL_VERSION_LESS_3_0 HMAC_CTX *m_ctx; +#else + EVP_MAC *m_mac; + EVP_MAC_CTX *m_ctx; +#endif }; HashResult Sha256HMACOpenSSLImpl::Calculate(const ByteBuffer& toSign, const ByteBuffer& secret) @@ -356,20 +466,36 @@ namespace Aws memset(digest.GetUnderlyingData(), 0, length); HMACRAIIGuard guard; +#if OPENSSL_VERSION_LESS_3_0 HMAC_CTX* m_ctx = guard.getResource(); +#else + EVP_MAC_CTX* m_ctx = guard.getResource(); +#endif #if OPENSSL_VERSION_LESS_1_1 HMAC_CTX_init(m_ctx); #endif +#if OPENSSL_VERSION_LESS_3_0 HMAC_Init_ex(m_ctx, secret.GetUnderlyingData(), static_cast<int>(secret.GetLength()), EVP_sha256(), NULL); HMAC_Update(m_ctx, toSign.GetUnderlyingData(), toSign.GetLength()); HMAC_Final(m_ctx, digest.GetUnderlyingData(), &length); +#else + char sha256[] {"SHA256"}; + OSSL_PARAM ossl_params[2]; + ossl_params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, sha256, 0); + ossl_params[1] = OSSL_PARAM_construct_end(); + EVP_MAC_init(m_ctx, secret.GetUnderlyingData(), + static_cast<int>(secret.GetLength()), ossl_params); + EVP_MAC_update(m_ctx, toSign.GetUnderlyingData(), toSign.GetLength()); + EVP_MAC_final(m_ctx, digest.GetUnderlyingData(), NULL, length); +#endif #if OPENSSL_VERSION_LESS_1_1 HMAC_CTX_cleanup(m_ctx); -#else +#elif OPENSSL_VERSION_LESS_3_0 HMAC_CTX_reset(m_ctx); #endif return HashResult(std::move(digest)); @@ -547,7 +673,7 @@ namespace Aws CryptoBuffer finalBlock(GetBlockSizeBytes()); int writtenSize = static_cast<int>(finalBlock.GetLength()); int ret = EVP_DecryptFinal_ex(m_decryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize); -#if OPENSSL_VERSION_NUMBER > 0x1010104fL //1.1.1d +#if !defined(OPENSSL_IS_AWSLC) && OPENSSL_VERSION_NUMBER > 0x1010104fL //1.1.1d if (ret <= 0) #else if (ret <= 0 && !m_emptyPlaintext) // see details why making exception for empty string at: https://github.com/aws/aws-sdk-cpp/issues/1413 diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp index f70a6c88f61..053ff938d44 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamDecoder.cpp @@ -72,9 +72,7 @@ namespace Aws assert(handler); if (!handler) { - AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Payload received, but decoder encountered internal errors before." - "ErrorCode: " << EventStreamErrorsMapper::GetNameForError(handler->GetInternalError()) << ", " - "ErrorMessage: " << handler->GetEventPayloadAsString()); + AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Payload received, but handler is null."); return; } handler->WriteMessageEventPayload(static_cast<unsigned char*>(payload->buffer), payload->len); @@ -129,9 +127,7 @@ namespace Aws assert(handler); if (!handler) { - AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Payload received, but decoder encountered internal errors before." - "ErrorCode: " << EventStreamErrorsMapper::GetNameForError(handler->GetInternalError()) << ", " - "ErrorMessage: " << handler->GetEventPayloadAsString()); + AWS_LOGSTREAM_ERROR(EVENT_STREAM_DECODER_CLASS_TAG, "Header received, but handler is null."); return; } diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp index ef7104e839c..750bf9e1e6d 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/event/EventStreamEncoder.cpp @@ -80,80 +80,83 @@ namespace Aws Aws::Vector<unsigned char> EventStreamEncoder::EncodeAndSign(const Aws::Utils::Event::Message& msg) { - aws_event_stream_message encoded = Encode(msg); - aws_event_stream_message signedMessage = Sign(&encoded); + Aws::Vector<unsigned char> outputBits; - const auto signedMessageLength = signedMessage.message_buffer ? aws_event_stream_message_total_length(&signedMessage) : 0; + aws_event_stream_message encoded; + if (InitEncodedStruct(msg, &encoded)) + { + aws_event_stream_message signedMessage; + if (InitSignedStruct(&encoded, &signedMessage)) + { + // success! + const auto signedMessageBuffer = aws_event_stream_message_buffer(&signedMessage); + const auto signedMessageLength = aws_event_stream_message_total_length(&signedMessage); + outputBits.reserve(signedMessageLength); + outputBits.insert(outputBits.end(), signedMessageBuffer, signedMessageBuffer + signedMessageLength); + + aws_event_stream_message_clean_up(&signedMessage); + } + aws_event_stream_message_clean_up(&encoded); + } - Aws::Vector<unsigned char> outputBits(signedMessage.message_buffer, signedMessage.message_buffer + signedMessageLength); - aws_event_stream_message_clean_up(&encoded); - aws_event_stream_message_clean_up(&signedMessage); return outputBits; } - aws_event_stream_message EventStreamEncoder::Encode(const Aws::Utils::Event::Message& msg) + bool EventStreamEncoder::InitEncodedStruct(const Aws::Utils::Event::Message& msg, aws_event_stream_message* encoded) { + bool success = false; + aws_array_list headers; EncodeHeaders(msg, &headers); - aws_byte_buf payload; - payload.len = msg.GetEventPayload().size(); - // this const_cast is OK because aws_byte_buf will only be "read from" by the following functions. - payload.buffer = const_cast<uint8_t*>(msg.GetEventPayload().data()); - payload.capacity = 0; - payload.allocator = nullptr; + aws_byte_buf payload = aws_byte_buf_from_array(msg.GetEventPayload().data(), msg.GetEventPayload().size()); - aws_event_stream_message encoded; - if(aws_event_stream_message_init(&encoded, get_aws_allocator(), &headers, &payload) == AWS_OP_ERR) + if(aws_event_stream_message_init(encoded, get_aws_allocator(), &headers, &payload) == AWS_OP_SUCCESS) + { + success = true; + } + else { AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from payload."); - aws_event_stream_headers_list_cleanup(&headers); - // GCC 4.9.4 issues a warning with -Wextra if we simply do - // return {}; - aws_event_stream_message empty{nullptr, nullptr, 0}; - return empty; } + aws_event_stream_headers_list_cleanup(&headers); - return encoded; + return success; } - aws_event_stream_message EventStreamEncoder::Sign(aws_event_stream_message* msg) + bool EventStreamEncoder::InitSignedStruct(const aws_event_stream_message* msg, aws_event_stream_message* signedmsg) { - const auto msglen = msg->message_buffer ? aws_event_stream_message_total_length(msg) : 0; + bool success = false; + + const auto msgbuf = aws_event_stream_message_buffer(msg); + const auto msglen = aws_event_stream_message_total_length(msg); Event::Message signedMessage; - signedMessage.WriteEventPayload(msg->message_buffer, msglen); + signedMessage.WriteEventPayload(msgbuf, msglen); assert(m_signer); - if (!m_signer->SignEventMessage(signedMessage, m_signatureSeed)) + if (m_signer->SignEventMessage(signedMessage, m_signatureSeed)) { - AWS_LOGSTREAM_ERROR(TAG, "Failed to sign event message frame."); - // GCC 4.9.4 issues a warning with -Wextra if we simply do - // return {}; - aws_event_stream_message empty{nullptr, nullptr, 0}; - return empty; - } - - aws_array_list headers; - EncodeHeaders(signedMessage, &headers); + aws_array_list headers; + EncodeHeaders(signedMessage, &headers); - aws_byte_buf payload; - payload.len = signedMessage.GetEventPayload().size(); - payload.buffer = signedMessage.GetEventPayload().data(); - payload.capacity = 0; - payload.allocator = nullptr; + aws_byte_buf payload = aws_byte_buf_from_array(signedMessage.GetEventPayload().data(), signedMessage.GetEventPayload().size()); - aws_event_stream_message signedmsg; - if(aws_event_stream_message_init(&signedmsg, get_aws_allocator(), &headers, &payload)) - { - AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from payload."); + if(aws_event_stream_message_init(signedmsg, get_aws_allocator(), &headers, &payload) == AWS_OP_SUCCESS) + { + success = true; + } + else + { + AWS_LOGSTREAM_ERROR(TAG, "Error creating event-stream message from payload."); + } aws_event_stream_headers_list_cleanup(&headers); - // GCC 4.9.4 issues a warning with -Wextra if we simply do - // return {}; - aws_event_stream_message empty{nullptr, nullptr, 0}; - return empty; } - aws_event_stream_headers_list_cleanup(&headers); - return signedmsg; + else + { + AWS_LOGSTREAM_ERROR(TAG, "Failed to sign event message frame."); + } + + return success; } } // namespace Event diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp index 9358d00c0a8..ebfd5d44568 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/json/JsonSerializer.cpp @@ -9,6 +9,7 @@ #include <algorithm> #include <aws/core/utils/memory/stl/AWSStringStream.h> #include <aws/core/utils/StringUtils.h> +#include <aws/core/utils/Document.h> using namespace Aws::Utils; using namespace Aws::Utils::Json; @@ -68,6 +69,13 @@ JsonValue::JsonValue(JsonValue&& value) : value.m_value = nullptr; } +JsonValue::JsonValue(const Aws::Utils::DocumentView& value) : + m_value(cJSON_AS4CPP_Duplicate(value.m_json, true/*recurse*/)), + m_wasParseSuccessful(true), + m_errorMessage({}) +{ +} + void JsonValue::Destroy() { cJSON_AS4CPP_Delete(m_value); @@ -106,6 +114,15 @@ JsonValue& JsonValue::operator=(JsonValue&& other) return *this; } +JsonValue& JsonValue::operator=(const Aws::Utils::DocumentView& other) +{ + Destroy(); + m_value = cJSON_AS4CPP_Duplicate(other.m_json, true /*recurse*/); + m_wasParseSuccessful = true; + m_errorMessage = {}; + return *this; +} + static void AddOrReplace(cJSON* root, const char* key, cJSON* value) { const auto existing = cJSON_AS4CPP_GetObjectItemCaseSensitive(root, key); diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogSystem.cpp new file mode 100644 index 00000000000..81f94d0d3af --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogSystem.cpp @@ -0,0 +1,107 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/logging/CRTLogSystem.h> +#include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/LogSystemInterface.h> +#include <aws/core/utils/Array.h> +#include <aws/common/common.h> +#include <cstdarg> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +namespace Aws +{ + namespace Utils + { + namespace Logging + { + static int s_aws_logger_redirect_log( + struct aws_logger *logger, + enum aws_log_level log_level, + aws_log_subject_t subject, + const char *format, ...) + { + DefaultCRTLogSystem* crtLogSystem = reinterpret_cast<DefaultCRTLogSystem*>(logger->p_impl); + Logging::LogLevel logLevel = static_cast<LogLevel>(log_level); + const char* subjectName = aws_log_subject_name(subject); + va_list args; + va_start(args, format); + crtLogSystem->Log(logLevel, subjectName, format, args); + va_end(args); + return AWS_OP_SUCCESS; + } + + static enum aws_log_level s_aws_logger_redirect_get_log_level(struct aws_logger *logger, aws_log_subject_t subject) { + (void)subject; + DefaultCRTLogSystem* crtLogSystem = reinterpret_cast<DefaultCRTLogSystem*>(logger->p_impl); + return (aws_log_level)(crtLogSystem->GetLogLevel()); + } + + static void s_aws_logger_redirect_clean_up(struct aws_logger *logger) { + (void)logger; + } + + static int s_aws_logger_redirect_set_log_level(struct aws_logger *logger, enum aws_log_level log_level) + { + DefaultCRTLogSystem* crtLogSystem = reinterpret_cast<DefaultCRTLogSystem*>(logger->p_impl); + crtLogSystem->SetLogLevel(static_cast<LogLevel>(log_level)); + return AWS_OP_SUCCESS; + } + + static struct aws_logger_vtable s_aws_logger_redirect_vtable = { + s_aws_logger_redirect_log, // .log + s_aws_logger_redirect_get_log_level, // .get_log_level + s_aws_logger_redirect_clean_up, // .clean_up + s_aws_logger_redirect_set_log_level // set_log_level + }; + + DefaultCRTLogSystem::DefaultCRTLogSystem(LogLevel logLevel) : + m_logLevel(logLevel), + m_logger() + { + m_logger.vtable = &s_aws_logger_redirect_vtable; + m_logger.allocator = Aws::get_aws_allocator(); + m_logger.p_impl = this; + + aws_logger_set(&m_logger); + } + + DefaultCRTLogSystem::~DefaultCRTLogSystem() + { + if (aws_logger_get() == &m_logger) + { + aws_logger_set(NULL); + aws_logger_clean_up(&m_logger); + } + } + + void DefaultCRTLogSystem::Log(LogLevel logLevel, const char* subjectName, const char* formatStr, va_list args) + { + va_list tmp_args; + va_copy(tmp_args, args); + #ifdef _WIN32 + const int requiredLength = _vscprintf(formatStr, tmp_args) + 1; + #else + const int requiredLength = vsnprintf(nullptr, 0, formatStr, tmp_args) + 1; + #endif + va_end(tmp_args); + + Array<char> outputBuff(requiredLength); + #ifdef _WIN32 + vsnprintf_s(outputBuff.GetUnderlyingData(), requiredLength, _TRUNCATE, formatStr, args); + #else + vsnprintf(outputBuff.GetUnderlyingData(), requiredLength, formatStr, args); + #endif // _WIN32 + + Aws::OStringStream logStream; + logStream << outputBuff.GetUnderlyingData(); + Logging::GetLogSystem()->LogStream(logLevel, subjectName, logStream); + } + } + } +} + diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogging.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogging.cpp new file mode 100644 index 00000000000..5875ead9c01 --- /dev/null +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/CRTLogging.cpp @@ -0,0 +1,31 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/core/utils/logging/CRTLogging.h> +#include <aws/common/logging.h> +#include <memory> + +using namespace Aws::Utils; +using namespace Aws::Utils::Logging; + +namespace Aws +{ +namespace Utils +{ +namespace Logging { + +static std::shared_ptr<CRTLogSystemInterface> CRTLogSystem(nullptr); + +void InitializeCRTLogging(const std::shared_ptr<CRTLogSystemInterface>& crtLogSystem) { + CRTLogSystem = crtLogSystem; +} + +void ShutdownCRTLogging() { + CRTLogSystem = nullptr; +} + +} // namespace Logging +} // namespace Utils +} // namespace Aws diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp index 41c4d7e09c5..26348b68fe2 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/logging/FormattedLogSystem.cpp @@ -72,7 +72,7 @@ void FormattedLogSystem::Log(LogLevel logLevel, const char* tag, const char* for va_list tmp_args; //unfortunately you cannot consume a va_list twice va_copy(tmp_args, args); //so we have to copy it - #ifdef WIN32 + #ifdef _WIN32 const int requiredLength = _vscprintf(formatStr, tmp_args) + 1; #else const int requiredLength = vsnprintf(nullptr, 0, formatStr, tmp_args) + 1; @@ -80,11 +80,11 @@ void FormattedLogSystem::Log(LogLevel logLevel, const char* tag, const char* for va_end(tmp_args); Array<char> outputBuff(requiredLength); - #ifdef WIN32 + #ifdef _WIN32 vsnprintf_s(outputBuff.GetUnderlyingData(), requiredLength, _TRUNCATE, formatStr, args); #else vsnprintf(outputBuff.GetUnderlyingData(), requiredLength, formatStr, args); - #endif // WIN32 + #endif // _WIN32 ss << outputBuff.GetUnderlyingData() << std::endl; diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp index 6d1f90ed124..26c92eaafdf 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/ResponseStream.cpp @@ -5,6 +5,7 @@ #include <aws/core/utils/stream/ResponseStream.h> #include <aws/core/utils/memory/stl/AWSStringStream.h> +#include <aws/core/utils/logging/LogMacros.h> #if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__) #include <aws/core/utils/stream/SimpleStreamBuf.h> @@ -15,6 +16,8 @@ using DefaultStreamBufType = Aws::StringBuf; using namespace Aws::Utils::Stream; +const int ResponseStream::ResponseStream::xindex = std::ios_base::xalloc(); + ResponseStream::ResponseStream(void) : m_underlyingStream(nullptr) { @@ -23,16 +26,20 @@ ResponseStream::ResponseStream(void) : ResponseStream::ResponseStream(Aws::IOStream* underlyingStreamToManage) : m_underlyingStream(underlyingStreamToManage) { + RegisterStream(); } ResponseStream::ResponseStream(const Aws::IOStreamFactory& factory) : m_underlyingStream(factory()) { + RegisterStream(); } ResponseStream::ResponseStream(ResponseStream&& toMove) : m_underlyingStream(toMove.m_underlyingStream) { + toMove.DeregisterStream(); toMove.m_underlyingStream = nullptr; + RegisterStream(); } ResponseStream& ResponseStream::operator=(ResponseStream&& toMove) @@ -43,12 +50,26 @@ ResponseStream& ResponseStream::operator=(ResponseStream&& toMove) } ReleaseStream(); + toMove.DeregisterStream(); m_underlyingStream = toMove.m_underlyingStream; toMove.m_underlyingStream = nullptr; + RegisterStream(); return *this; } +Aws::IOStream& ResponseStream::GetUnderlyingStream() const +{ + if (!m_underlyingStream) + { + assert(m_underlyingStream); + AWS_LOGSTREAM_FATAL("ResponseStream", "Unexpected nullptr m_underlyingStream"); + static DefaultUnderlyingStream fallbackStream; // we are already in UB, let's just not crash existing apps + return fallbackStream; + } + return *m_underlyingStream; +} + ResponseStream::~ResponseStream() { ReleaseStream(); @@ -58,13 +79,53 @@ void ResponseStream::ReleaseStream() { if (m_underlyingStream) { - m_underlyingStream->flush(); + DeregisterStream(); Aws::Delete(m_underlyingStream); } m_underlyingStream = nullptr; } +void ResponseStream::RegisterStream() +{ + if (m_underlyingStream) + { + ResponseStream* pThat = static_cast<ResponseStream*>(m_underlyingStream->pword(ResponseStream::xindex)); + if (pThat != nullptr) + { + // callback is already registered + assert(pThat != this); // Underlying stream must not be owned by more than one ResponseStream + } + else + { + m_underlyingStream->register_callback(ResponseStream::StreamCallback, ResponseStream::xindex); + } + m_underlyingStream->pword(ResponseStream::xindex) = this; + } +} + +void ResponseStream::DeregisterStream() +{ + if (m_underlyingStream) + { + assert(static_cast<ResponseStream*>(m_underlyingStream->pword(ResponseStream::xindex)) == this); // Attempt to deregister another ResponseStream's stream + m_underlyingStream->pword(ResponseStream::xindex) = nullptr; // ios does not support deregister, so just erasing the context + } +} + +void ResponseStream::StreamCallback(Aws::IOStream::event evt, std::ios_base& stream, int idx) +{ + if (evt == std::ios_base::erase_event) + { + ResponseStream* pThis = static_cast<ResponseStream*>(stream.pword(idx)); + if (pThis) + { + // m_underlyingStream is being destructed, let's avoid double destruction or having a dangling pointer + pThis->m_underlyingStream = nullptr; + } + } +} + static const char *DEFAULT_STREAM_TAG = "DefaultUnderlyingStream"; DefaultUnderlyingStream::DefaultUnderlyingStream() : diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp index 6e429947445..dbf77ab6468 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/stream/SimpleStreamBuf.cpp @@ -5,6 +5,7 @@ */ #include <aws/core/utils/stream/SimpleStreamBuf.h> +#include <aws/core/utils/logging/LogMacros.h> #include <algorithm> #include <cassert> @@ -123,7 +124,14 @@ bool SimpleStreamBuf::GrowBuffer() if(currentSize > 0) { - std::memcpy(newBuffer, m_buffer, currentSize); + if(m_buffer) + { + std::memcpy(newBuffer, m_buffer, currentSize); + } + else + { + AWS_LOGSTREAM_FATAL(SIMPLE_STREAMBUF_ALLOCATION_TAG, "Unexpected nullptr m_buffer"); + } } if(m_buffer) diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp index 4a3c4209c41..f9538f00336 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/threading/Executor.cpp @@ -14,10 +14,15 @@ using namespace Aws::Utils::Threading; bool DefaultExecutor::SubmitToThread(std::function<void()>&& fx) { - auto main = [fx, this] { - fx(); - Detach(std::this_thread::get_id()); - }; + // Generalized lambda capture is C++14, using std::bind as a workaround to force moving fx (instead of copying) + std::function<void()> main = std::bind( + [this](std::function<void()>& storedFx) + { + storedFx(); + Detach(std::this_thread::get_id()); + }, + std::move(fx) + ); State expected; do @@ -25,7 +30,7 @@ bool DefaultExecutor::SubmitToThread(std::function<void()>&& fx) expected = State::Free; if(m_state.compare_exchange_strong(expected, State::Locked)) { - std::thread t(main); + std::thread t(std::move(main)); const auto id = t.get_id(); // copy the id before we std::move the thread m_threads.emplace(id, std::move(t)); m_state = State::Free; diff --git a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp index c06befaf9b0..2d91f700005 100644 --- a/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp +++ b/contrib/libs/aws-sdk-cpp/aws-cpp-sdk-core/source/utils/xml/XmlSerializer.cpp @@ -23,6 +23,8 @@ Aws::String Aws::Utils::Xml::DecodeEscapedXmlText(const Aws::String& textToDecod StringUtils::Replace(decodedString, "<", "<"); StringUtils::Replace(decodedString, ">", ">"); StringUtils::Replace(decodedString, "&", "&"); + StringUtils::Replace(decodedString, "
", "\n"); + StringUtils::Replace(decodedString, "
", "\r"); return decodedString; } |