From 45bb39307abb9527ba8a88254514e4124cab9de8 Mon Sep 17 00:00:00 2001 From: sbiscigl Date: Fri, 17 Jul 2026 15:19:55 -0400 Subject: [PATCH] Create class based on bound out BDD endpoint engine in crt --- .../aws/core/endpoint/BDDEndpointProvider.h | 54 ++++ .../core/endpoint/DefaultEndpointProvider.h | 84 +----- .../endpoint/internal/CrtEndpointProvider.h | 99 +++++++ .../endpoint/internal/CrtEndpointResolver.h | 268 ++++++++++++++++++ .../source/endpoint/BDDEndpointProvider.cpp | 30 ++ .../endpoint/DefaultEndpointProvider.cpp | 232 +-------------- .../source/transfer/TransferManager.cpp | 3 +- .../endpoint/BDDEndpointProviderTest.cpp | 136 +++++++++ .../aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp | 1 + 9 files changed, 601 insertions(+), 306 deletions(-) create mode 100644 src/aws-cpp-sdk-core/include/aws/core/endpoint/BDDEndpointProvider.h create mode 100644 src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointProvider.h create mode 100644 src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointResolver.h create mode 100644 src/aws-cpp-sdk-core/source/endpoint/BDDEndpointProvider.cpp create mode 100644 tests/aws-cpp-sdk-core-tests/endpoint/BDDEndpointProviderTest.cpp diff --git a/src/aws-cpp-sdk-core/include/aws/core/endpoint/BDDEndpointProvider.h b/src/aws-cpp-sdk-core/include/aws/core/endpoint/BDDEndpointProvider.h new file mode 100644 index 000000000000..c30bf7fa1c72 --- /dev/null +++ b/src/aws-cpp-sdk-core/include/aws/core/endpoint/BDDEndpointProvider.h @@ -0,0 +1,54 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include + +#include + +namespace Aws +{ + namespace Endpoint + { + /** + * Resolves an endpoint using the compiled-bytecode CRT BDD engine. + */ + AWS_CORE_API ResolveEndpointOutcome + ResolveEndpointBddImpl(const Aws::Crt::Endpoints::BddEngine& bddEngine, + const EndpointParameters& builtInParameters, + const EndpointParameters& clientContextParameters, + const EndpointParameters& endpointParameters); + + /** + * Resolves endpoints from compiled BDD bytecode via the CRT BddEngine. Drop-in + * replacement for DefaultEndpointProvider. + * + * WARNING: non-owning. The engine points directly into the bytecode blob passed to + * the constructor; the caller is responsible for keeping it alive for the lifetime of + * this provider. Generated clients pass GetRulesBlob() (static storage), which satisfies this. + */ + template + class AWS_CORE_API BDDEndpointProvider : public CrtEndpointProvider + { + public: + using CrtEndpointProvider::CrtEndpointProvider; + + virtual ~BDDEndpointProvider() = default; + }; + + /** + * Export endpoint provider symbols for Windows DLL, otherwise declare as extern + */ + AWS_CORE_EXTERN template class AWS_CORE_API BDDEndpointProvider; + } // namespace Endpoint +} // namespace Aws diff --git a/src/aws-cpp-sdk-core/include/aws/core/endpoint/DefaultEndpointProvider.h b/src/aws-cpp-sdk-core/include/aws/core/endpoint/DefaultEndpointProvider.h index e9be67008284..575744b69623 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/endpoint/DefaultEndpointProvider.h +++ b/src/aws-cpp-sdk-core/include/aws/core/endpoint/DefaultEndpointProvider.h @@ -6,20 +6,10 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include "aws/core/utils/logging/LogMacros.h" - namespace Aws { namespace Endpoint @@ -33,6 +23,7 @@ namespace Aws * @param clientContextParameters * @param endpointParameters * @return + * Resolves an endpoint using the JSON-ruleset CRT rule engine. */ AWS_CORE_API ResolveEndpointOutcome ResolveEndpointDefaultImpl(const Aws::Crt::Endpoints::RuleEngine& ruleEngine, @@ -41,78 +32,19 @@ namespace Aws const EndpointParameters& endpointParameters); /** - * Default endpoint provider template used in this SDK. + * Resolves endpoints from a JSON ruleset blob via the CRT Aws::Crt::Endpoints::RuleEngine. */ template - class AWS_CORE_API DefaultEndpointProvider : public EndpointProviderBase + class AWS_CORE_API DefaultEndpointProvider : public CrtEndpointProvider { public: - DefaultEndpointProvider(const char* endpointRulesBlob, const size_t endpointRulesBlobSz) - : m_crtRuleEngine(Aws::Crt::ByteCursorFromArray((const uint8_t*) endpointRulesBlob, endpointRulesBlobSz), - Aws::Crt::ByteCursorFromArray((const uint8_t*) AWSPartitions::GetPartitionsBlob(), AWSPartitions::PartitionsBlobSize)) - { - if(!m_crtRuleEngine) { - AWS_LOGSTREAM_FATAL(DEFAULT_ENDPOINT_PROVIDER_TAG, "Invalid CRT Rule Engine state"); - } - } - - virtual ~DefaultEndpointProvider() - { - } - - void InitBuiltInParameters(const ClientConfigurationT& config) override - { - m_builtInParameters.SetFromClientConfiguration(config); - } - - void InitBuiltInParameters(const ClientConfigurationT& config, const Aws::String& serviceName) override - { - m_builtInParameters.SetFromClientConfiguration(config, serviceName); - } - - /** - * Default implementation of the ResolveEndpoint - */ - ResolveEndpointOutcome ResolveEndpoint(const EndpointParameters& endpointParameters) const override - { - auto ResolveEndpointDefaultImpl = Aws::Endpoint::ResolveEndpointDefaultImpl; - return ResolveEndpointDefaultImpl(m_crtRuleEngine, m_builtInParameters.GetAllParameters(), m_clientContextParameters.GetAllParameters(), endpointParameters); - }; - - const ClientContextParametersT& GetClientContextParameters() const override - { - return m_clientContextParameters; - } - ClientContextParametersT& AccessClientContextParameters() override - { - return m_clientContextParameters; - } - - const BuiltInParametersT& GetBuiltInParameters() const - { - return m_builtInParameters; - } - BuiltInParametersT& AccessBuiltInParameters() - { - return m_builtInParameters; - } - - void OverrideEndpoint(const Aws::String& endpoint) override - { - m_builtInParameters.OverrideEndpoint(endpoint); - } - - protected: - /* Crt RuleEngine evaluator built using the service's Rule engine */ - Aws::Crt::Endpoints::RuleEngine m_crtRuleEngine; - - /* Also known as a configurable parameters defined by the AWS Service in their c2j/smithy model definition */ - ClientContextParametersT m_clientContextParameters; + using CrtEndpointProvider::CrtEndpointProvider; - /* Also known as parameters on the ClientConfiguration in this SDK */ - BuiltInParametersT m_builtInParameters; + virtual ~DefaultEndpointProvider() = default; }; /** diff --git a/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointProvider.h b/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointProvider.h new file mode 100644 index 000000000000..86f322c06a5d --- /dev/null +++ b/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointProvider.h @@ -0,0 +1,99 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace Aws { + namespace Endpoint { + /** + * Endpoint provider backed by a CRT endpoint engine. The two things that differ between + * the JSON-ruleset and BDD-bytecode providers are captured as template parameters: + * - RulesEngineT: the CRT engine type (Aws::Crt::Endpoints::RuleEngine or BddEngine), + * both constructed from a ruleset blob plus the partitions blob. + * - ResolveFn: the resolution entry point for that engine. It is an out-of-line exported + * symbol (ResolveEndpointDefaultImpl / ResolveEndpointBddImpl) so the resolution body + * lives once in aws-cpp-sdk-core rather than inlined into every service binary. + * Everything else (parameter storage, init, override, accessors) is shared here. + */ + template + class CrtEndpointProvider : public EndpointProviderBase { + public: + CrtEndpointProvider(const char *endpointRulesBlob, const size_t endpointRulesBlobSz) + : m_crtEngine(Aws::Crt::ByteCursorFromArray((const uint8_t *) endpointRulesBlob, endpointRulesBlobSz), + Aws::Crt::ByteCursorFromArray((const uint8_t *) AWSPartitions::GetPartitionsBlob(), + AWSPartitions::PartitionsBlobSize)) { + if (!m_crtEngine) { + AWS_LOGSTREAM_FATAL("CrtEndpointProvider", "Invalid CRT endpoint engine state"); + } + } + + virtual ~CrtEndpointProvider() = default; + + void InitBuiltInParameters(const ClientConfigurationT &config) override { + m_builtInParameters.SetFromClientConfiguration(config); + } + + void InitBuiltInParameters(const ClientConfigurationT &config, const Aws::String &serviceName) override { + m_builtInParameters.SetFromClientConfiguration(config, serviceName); + } + + ResolveEndpointOutcome ResolveEndpoint(const EndpointParameters &endpointParameters) const override { + return ResolveFn(m_crtEngine, m_builtInParameters.GetAllParameters(), + m_clientContextParameters.GetAllParameters(), endpointParameters); + }; + + const ClientContextParametersT &GetClientContextParameters() const override { + return m_clientContextParameters; + } + + ClientContextParametersT &AccessClientContextParameters() override { + return m_clientContextParameters; + } + + const BuiltInParametersT &GetBuiltInParameters() const { + return m_builtInParameters; + } + + BuiltInParametersT &AccessBuiltInParameters() { + return m_builtInParameters; + } + + void OverrideEndpoint(const Aws::String &endpoint) override { + m_builtInParameters.OverrideEndpoint(endpoint); + } + + protected: + /* Crt endpoint engine (RuleEngine or BddEngine) built from the service's ruleset blob */ + RulesEngineT m_crtEngine; + + /* Also known as a configurable parameters defined by the AWS Service in their c2j/smithy model definition */ + ClientContextParametersT m_clientContextParameters; + + /* Also known as parameters on the ClientConfiguration in this SDK */ + BuiltInParametersT m_builtInParameters; + }; + } // namespace Endpoint +} // namespace Aws diff --git a/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointResolver.h b/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointResolver.h new file mode 100644 index 000000000000..3c9d8c9913d1 --- /dev/null +++ b/src/aws-cpp-sdk-core/include/aws/core/endpoint/internal/CrtEndpointResolver.h @@ -0,0 +1,268 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace Aws +{ + namespace Internal + { + namespace Endpoint + { + static const char CRT_ENDPOINT_RESOLVER_TAG[] = "Aws::Endpoint::CRTEndpointResolver"; + + inline 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; + } + + inline 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; + } + + /** + * Resolve an endpoint using any CRT engine (RuleEngine or BddEngine). + */ + template + Aws::Endpoint::ResolveEndpointOutcome ResolveEndpointImpl( + const EngineT& engine, + const Aws::Endpoint::EndpointParameters& builtInParameters, + const Aws::Endpoint::EndpointParameters& clientContextParameters, + const Aws::Endpoint::EndpointParameters& endpointParameters) + { + using namespace Aws::Endpoint; + + if(!engine) { + AWS_LOGSTREAM_FATAL(CRT_ENDPOINT_RESOLVER_TAG, "Invalid CRT endpoint engine state"); + return ResolveEndpointOutcome( + Aws::Client::AWSError( + Aws::Client::CoreErrors::INTERNAL_FAILURE, + "", + "CRT endpoint engine is not initialized", + false/*retryable*/)); + } + + Aws::Crt::Endpoints::RequestContext crtRequestCtx; + + const Aws::Vector> 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(CRT_ENDPOINT_RESOLVER_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(CRT_ENDPOINT_RESOLVER_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 if(EndpointParameter::ParameterType::STRING_ARRAY == parameter.GetStoredType()) + { + Aws::Crt::Vector byteCursorArray; + byteCursorArray.reserve(parameter.GetStrArrayValueNoCheck().size()); + for (const auto &e: parameter.GetStrArrayValueNoCheck()) + { + byteCursorArray.emplace_back(Aws::Crt::ByteCursorFromCString(e.c_str())); + } + AWS_LOGSTREAM_TRACE(CRT_ENDPOINT_RESOLVER_TAG, + "Endpoint str array eval parameter: " << + parameter.GetName() << " = " << + [¶meter]() -> Aws::String { + Aws::OStringStream os; + for (const auto &e: parameter.GetStrArrayValueNoCheck()) + { + os<( + Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER, + "", + "Invalid endpoint parameter type for parameter " + parameter.GetName(), + false/*retryable*/)); + } + } + } + + auto resolved = engine.Resolve(crtRequestCtx); + + if(resolved.has_value()) + { + if(resolved->IsError()) + { + auto crtError = resolved->GetError(); + Aws::String sdkCrtError = crtError ? Aws::String(crtError->begin(), crtError->end()) : + "CRT endpoint engine resolution resulted in an unknown error"; + return ResolveEndpointOutcome( + Aws::Client::AWSError( + 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(CRT_ENDPOINT_RESOLVER_TAG, "Endpoint 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(CRT_ENDPOINT_RESOLVER_TAG, "Endpoint engine 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 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::INVALID_QUERY_PARAMETER, + "", + "Invalid AWS CRT endpoint engine state", + false/*retryable*/)); + } + } + + auto errCode = Aws::Crt::LastError(); + AWS_LOGSTREAM_DEBUG(CRT_ENDPOINT_RESOLVER_TAG, "ERROR: Endpoint engine has failed to evaluate the endpoint: " << errCode << " " << Aws::Crt::ErrorDebugString(errCode)); + + return ResolveEndpointOutcome( + Aws::Client::AWSError( + Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER, + "", + "Failed to evaluate the endpoint: null output from AWS CRT endpoint engine", + false/*retryable*/)); + } + } // namespace Endpoint + } // namespace Internal +} // namespace Aws diff --git a/src/aws-cpp-sdk-core/source/endpoint/BDDEndpointProvider.cpp b/src/aws-cpp-sdk-core/source/endpoint/BDDEndpointProvider.cpp new file mode 100644 index 000000000000..1a9f7ef8dd4d --- /dev/null +++ b/src/aws-cpp-sdk-core/source/endpoint/BDDEndpointProvider.cpp @@ -0,0 +1,30 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +namespace Aws +{ +namespace Endpoint +{ + +#ifndef AWS_CORE_EXPORTS // Except for Windows DLL +template class BDDEndpointProvider; +#endif + +AWS_CORE_API ResolveEndpointOutcome +ResolveEndpointBddImpl(const Aws::Crt::Endpoints::BddEngine& bddEngine, + const EndpointParameters& builtInParameters, + const EndpointParameters& clientContextParameters, + const EndpointParameters& endpointParameters) +{ + return Aws::Internal::Endpoint::ResolveEndpointImpl(bddEngine, builtInParameters, clientContextParameters, endpointParameters); +} + +} // namespace Endpoint +} // namespace Aws diff --git a/src/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp b/src/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp index 527c3ca91fa6..12c49145dc4a 100644 --- a/src/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp +++ b/src/aws-cpp-sdk-core/source/endpoint/DefaultEndpointProvider.cpp @@ -4,8 +4,7 @@ */ #include -#include -#include +#include namespace Aws { @@ -21,239 +20,14 @@ template class DefaultEndpointProvider; #endif -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::INTERNAL_FAILURE, - "", - "CRT Endpoint rule engine is not initialized", - false/*retryable*/)); - } - - Aws::Crt::Endpoints::RequestContext crtRequestCtx; - - const Aws::Vector> 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 if(EndpointParameter::ParameterType::STRING_ARRAY == parameter.GetStoredType()) - { - Aws::Crt::Vector byteCursorArray; - byteCursorArray.reserve(parameter.GetStrArrayValueNoCheck().size()); - for (const auto &e: parameter.GetStrArrayValueNoCheck()) - { - byteCursorArray.emplace_back(Aws::Crt::ByteCursorFromCString(e.c_str())); - } - AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, - "Endpoint str array eval parameter: " << - parameter.GetName() << " = " << - [¶meter]() -> Aws::String { - Aws::OStringStream os; - for (const auto &e: parameter.GetStrArrayValueNoCheck()) - { - os<( - 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::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 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::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::INVALID_QUERY_PARAMETER, - "", - "Failed to evaluate the endpoint: null output from AWS CRT RuleEngine", - false/*retryable*/)); - + return Aws::Internal::Endpoint::ResolveEndpointImpl(ruleEngine, builtInParameters, clientContextParameters, endpointParameters); } } // namespace Endpoint -} // namespace Aws \ No newline at end of file +} // namespace Aws diff --git a/src/aws-cpp-sdk-transfer/source/transfer/TransferManager.cpp b/src/aws-cpp-sdk-transfer/source/transfer/TransferManager.cpp index 506b3c40245d..caaea75408cb 100644 --- a/src/aws-cpp-sdk-transfer/source/transfer/TransferManager.cpp +++ b/src/aws-cpp-sdk-transfer/source/transfer/TransferManager.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1662,7 +1663,7 @@ namespace Aws using SetChecksumFunc = std::function; using ChecksumEnum = S3::Model::ChecksumAlgorithm; static constexpr size_t CHECKSUM_ALGS_SIZE = 5; - static std::array, CHECKSUM_ALGS_SIZE> SET_CHECKSUM_METHODS = {{ + static Aws::Array, CHECKSUM_ALGS_SIZE> SET_CHECKSUM_METHODS = {{ {ChecksumEnum::CRC64NVME, [](Aws::S3::Model::CompletedPart& part, const Aws::String& checksum) -> void { part.SetChecksumCRC64NVME(checksum); }}, {ChecksumEnum::CRC32, diff --git a/tests/aws-cpp-sdk-core-tests/endpoint/BDDEndpointProviderTest.cpp b/tests/aws-cpp-sdk-core-tests/endpoint/BDDEndpointProviderTest.cpp new file mode 100644 index 000000000000..ac58a88b2828 --- /dev/null +++ b/tests/aws-cpp-sdk-core-tests/endpoint/BDDEndpointProviderTest.cpp @@ -0,0 +1,136 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include + +namespace { + +/** + * BDD bytecode compiled from: + * { + * "version": "1.1", + * "parameters": { "Region": { "type": "string", "required": false } }, + * "conditions": [ + * { "fn": "isSet", "argv": [{"ref": "Region"}] }, + * { "fn": "aws.partition", "argv": [{"ref": "Region"}], "assign": "partitionResult" } + * ], + * "results": [ + * { "endpoint": { "url": "https://example.{Region}.{partitionResult#dnsSuffix}" } }, + * { "error": "unable to determine endpoint for region: {Region}" }, + * { "endpoint": { "url": "https://example.amazonaws.com" } } + * ], + * "root": 2, "nodeCount": 3 + * } + * + * When Region is set: resolves to https://example.{Region}.amazonaws.com + * When Region is not set: resolves to https://example.amazonaws.com + */ +static const uint8_t TestBddBytecode[] = { + 0x52, 0x44, 0x50, 0x45, 0xa6, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x31, 0x24, + 0x24, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x24, 0x24, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x24, 0x24, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x7b, 0x52, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x7d, 0x2e, 0x7b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x23, 0x64, 0x6e, 0x73, 0x53, + 0x75, 0x66, 0x66, 0x69, 0x78, 0x7d, 0x24, 0x24, 0x75, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x3a, + 0x20, 0x7b, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x7d, 0x24, 0x24, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0x77, 0x73, + 0x2e, 0x63, 0x6f, 0x6d, 0x24, 0x24, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, + 0x01, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x04, 0x05, 0x00, 0x06, 0x00, 0x00, 0x10, 0x0c, 0x01, 0x00, + 0x04, 0x05, 0x00, 0x06, 0x00, 0x01, 0x0d, 0x00, 0x0f, 0x00, 0x03, 0x00, + 0x20, 0x01, 0x1e, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x01, 0x54, 0x00, 0x31, 0x00, 0x20, 0x01, 0x87, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x03, 0xe1, 0xf5, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01, 0xe1, + 0xf5, 0x05, 0x02, 0xe1, 0xf5, 0x05 +}; +static const size_t TestBddBytecodeSize = sizeof(TestBddBytecode); + +} // namespace + +class BDDEndpointProviderTest : public Aws::Testing::AwsCppSdkGTestSuite { +}; + +TEST_F(BDDEndpointProviderTest, ConstructionWithValidBytecodeSucceeds) +{ + auto provider = Aws::MakeShared>("BDDEndpointProviderTest", + reinterpret_cast(TestBddBytecode), TestBddBytecodeSize); + ASSERT_NE(provider, nullptr); +} + +TEST_F(BDDEndpointProviderTest, ResolveEndpointWithRegionReturnsCorrectUrl) +{ + auto provider = Aws::MakeShared>("BDDEndpointProviderTest", + reinterpret_cast(TestBddBytecode), TestBddBytecodeSize); + + Aws::Endpoint::EndpointParameters parameters; + parameters.emplace_back(Aws::String("Region"), Aws::String("us-west-2"), + Aws::Endpoint::EndpointParameter::ParameterOrigin::STATIC_CONTEXT); + + auto result = provider->ResolveEndpoint(parameters); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_EQ(result.GetResult().GetURL(), "https://example.us-west-2.amazonaws.com"); +} + +TEST_F(BDDEndpointProviderTest, ResolveEndpointWithoutRegionReturnsFallback) +{ + auto provider = Aws::MakeShared>("BDDEndpointProviderTest", + reinterpret_cast(TestBddBytecode), TestBddBytecodeSize); + + Aws::Endpoint::EndpointParameters parameters; + + auto result = provider->ResolveEndpoint(parameters); + EXPECT_TRUE(result.IsSuccess()); + EXPECT_EQ(result.GetResult().GetURL(), "https://example.amazonaws.com"); +} + +TEST_F(BDDEndpointProviderTest, ConstructionWithInvalidBytecodeLogsError) +{ + static const uint8_t invalidBytecode[] = {0x00, 0x01, 0x02, 0x03}; + + auto provider = Aws::MakeShared>("BDDEndpointProviderTest", + reinterpret_cast(invalidBytecode), sizeof(invalidBytecode)); + + Aws::Endpoint::EndpointParameters parameters; + parameters.emplace_back(Aws::String("Region"), Aws::String("us-east-1"), + Aws::Endpoint::EndpointParameter::ParameterOrigin::STATIC_CONTEXT); + + auto result = provider->ResolveEndpoint(parameters); + EXPECT_FALSE(result.IsSuccess()); +} + +TEST_F(BDDEndpointProviderTest, ResolveEndpointWithDifferentRegions) +{ + auto provider = Aws::MakeShared>("BDDEndpointProviderTest", + reinterpret_cast(TestBddBytecode), TestBddBytecodeSize); + + const Aws::Array, 3> testCases{{ + {"us-east-1", "https://example.us-east-1.amazonaws.com"}, + {"eu-west-1", "https://example.eu-west-1.amazonaws.com"}, + {"ap-southeast-1", "https://example.ap-southeast-1.amazonaws.com"}, + }}; + + for (const auto& testCase : testCases) + { + Aws::Endpoint::EndpointParameters parameters; + parameters.emplace_back(Aws::String("Region"), testCase.first, + Aws::Endpoint::EndpointParameter::ParameterOrigin::STATIC_CONTEXT); + + auto result = provider->ResolveEndpoint(parameters); + EXPECT_TRUE(result.IsSuccess()) << "Failed for region: " << testCase.first; + EXPECT_EQ(result.GetResult().GetURL(), testCase.second) << "Failed for region: " << testCase.first; + } +} diff --git a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp index 8e86de4b5d26..dd748b0d9ee5 100644 --- a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp +++ b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include