Skip to content

Commit ea08eb7

Browse files
authored
Pre-requisites for Enabling Smithy Clients (#3317)
1 parent 9f6bfaf commit ea08eb7

14 files changed

+337
-376
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
#pragma once
6+
7+
#include <aws/core/AmazonWebServiceRequest.h>
8+
#include <aws/core/endpoint/AWSEndpoint.h>
9+
10+
namespace smithy {
11+
namespace client
12+
{
13+
/*
14+
This Class exists only to provide a way to access the legacy client APIs
15+
*/
16+
template<const char* ServiceNameT,
17+
typename ResponseT,
18+
typename DerivedT>
19+
class AwsLegacyClientT
20+
{
21+
protected:
22+
ResponseT MakeRequest(const Aws::Http::URI& uri,
23+
const Aws::AmazonWebServiceRequest& request,
24+
Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_POST,
25+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
26+
const char* signerRegionOverride = nullptr,
27+
const char* signerServiceNameOverride = nullptr) const
28+
{
29+
AWS_UNREFERENCED_PARAM(uri);
30+
AWS_UNREFERENCED_PARAM(signerName);
31+
AWS_UNREFERENCED_PARAM(signerRegionOverride);
32+
AWS_UNREFERENCED_PARAM(signerServiceNameOverride);
33+
AWS_LOGSTREAM_WARN(ServiceNameT, "Using Deprecated API. Please use appropriate client constructor");
34+
auto endpointCallback = [](const Aws::Endpoint::AWSEndpoint& ) {
35+
};
36+
return static_cast<const DerivedT*>(this)->MakeRequestDeserialize(&request,
37+
ServiceNameT,
38+
method,
39+
std::move(endpointCallback));
40+
}
41+
42+
ResponseT MakeRequest(const Aws::Http::URI& uri,
43+
Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_POST,
44+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
45+
const char* requestName = "",
46+
const char* signerRegionOverride = nullptr,
47+
const char* signerServiceNameOverride = nullptr) const
48+
{
49+
AWS_UNREFERENCED_PARAM(uri);
50+
AWS_UNREFERENCED_PARAM(signerName);
51+
AWS_UNREFERENCED_PARAM(signerRegionOverride);
52+
AWS_UNREFERENCED_PARAM(signerServiceNameOverride);
53+
AWS_LOGSTREAM_WARN(ServiceNameT, "Using Deprecated API. Please use appropriate client constructor");
54+
auto endpointCallback = [](const Aws::Endpoint::AWSEndpoint& ) {
55+
};
56+
return static_cast<const DerivedT*>(this)->MakeRequestDeserialize(nullptr,
57+
requestName,
58+
method,
59+
std::move(endpointCallback));
60+
}
61+
62+
ResponseT MakeRequest(const Aws::AmazonWebServiceRequest& request,
63+
const Aws::Endpoint::AWSEndpoint& endpoint,
64+
Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_POST,
65+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
66+
const char* signerRegionOverride = nullptr,
67+
const char* signerServiceNameOverride = nullptr) const
68+
{
69+
AWS_UNREFERENCED_PARAM(endpoint);
70+
AWS_UNREFERENCED_PARAM(signerName);
71+
AWS_UNREFERENCED_PARAM(signerRegionOverride);
72+
AWS_UNREFERENCED_PARAM(signerServiceNameOverride);
73+
AWS_LOGSTREAM_WARN(ServiceNameT, "Using Deprecated API. Please use appropriate client constructor");
74+
auto endpointCallback = [](const Aws::Endpoint::AWSEndpoint& ) {
75+
};
76+
return static_cast<const DerivedT*>(this)->MakeRequestDeserialize(&request,
77+
ServiceNameT,
78+
method,
79+
std::move(endpointCallback));
80+
}
81+
82+
ResponseT MakeRequest(const Aws::Endpoint::AWSEndpoint& endpoint,
83+
const char* requestName = "",
84+
Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_POST,
85+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
86+
const char* signerRegionOverride = nullptr,
87+
const char* signerServiceNameOverride = nullptr) const
88+
{
89+
AWS_UNREFERENCED_PARAM(endpoint);
90+
AWS_UNREFERENCED_PARAM(signerName);
91+
AWS_UNREFERENCED_PARAM(signerRegionOverride);
92+
AWS_UNREFERENCED_PARAM(signerServiceNameOverride);
93+
AWS_LOGSTREAM_WARN(ServiceNameT, "Using Deprecated API. Please use appropriate client constructor");
94+
auto endpointCallback = [](const Aws::Endpoint::AWSEndpoint& ) {
95+
};
96+
return static_cast<const DerivedT*>(this)->MakeRequestDeserialize(nullptr,
97+
requestName,
98+
method,
99+
std::move(endpointCallback));
100+
}
101+
102+
AwsLegacyClientT() = default;
103+
};
104+
105+
} // namespace client
106+
} // namespace smithy

src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <aws/core/http/HttpResponse.h>
2525
#include <aws/core/http/HttpClientFactory.h>
2626
#include <smithy/identity/signer/built-in/SignerProperties.h>
27+
#include <smithy/identity/auth/built-in/SigV4AuthSchemeOption.h>
28+
#include <smithy/client/AwsLegacyClient.h>
2729

2830
namespace smithy {
2931
namespace client
@@ -36,7 +38,15 @@ namespace client
3638
typename SerializerT,
3739
typename ResponseT,
3840
typename ErrorMarshallerT>
39-
class AwsSmithyClientT : public AwsSmithyClientBase
41+
class AwsSmithyClientT : public AwsSmithyClientBase, public AwsLegacyClientT<ServiceNameT, ResponseT,
42+
AwsSmithyClientT<ServiceNameT,
43+
ServiceClientConfigurationT,
44+
ServiceAuthSchemeResolverT,
45+
AuthSchemesVariantT,
46+
EndpointProviderT,
47+
SerializerT,
48+
ResponseT,
49+
ErrorMarshallerT>>
4050
{
4151
public:
4252
static_assert(std::is_base_of<Aws::Client::AWSErrorMarshaller, ErrorMarshallerT>::value, "MarshallerT must be derived from class Aws::Client::AWSErrorMarshaller");
@@ -213,6 +223,68 @@ namespace client
213223
return m_serializer->Deserialize(std::move(httpResponseOutcome), GetServiceClientName(), requestName);
214224
}
215225

226+
Aws::String GeneratePresignedUrl(
227+
EndpointUpdateCallback&& endpointCallback,
228+
Aws::Http::HttpMethod method,
229+
const Aws::String& region,
230+
const Aws::String& serviceName,
231+
long long expirationInSeconds,
232+
const Aws::Http::HeaderValueCollection& customizedHeaders,
233+
const std::shared_ptr<Aws::Http::ServiceSpecificParameters> serviceSpecificParameters) const
234+
{
235+
AwsSmithyClientAsyncRequestContext ctx;
236+
auto authSchemeOptionOutcome = SelectAuthSchemeOption( ctx);
237+
auto authSchemeOption = std::move(authSchemeOptionOutcome.GetResultWithOwnership());
238+
239+
Aws::Endpoint::EndpointParameters epParams = Aws::Endpoint::EndpointParameters();
240+
const auto authSchemeEpParams = authSchemeOption.endpointParameters();
241+
epParams.insert(epParams.end(), authSchemeEpParams.begin(), authSchemeEpParams.end());
242+
if(serviceSpecificParameters)
243+
{
244+
auto bucketIt = serviceSpecificParameters->parameterMap.find("bucketName");
245+
if(bucketIt != serviceSpecificParameters->parameterMap.end())
246+
{
247+
auto bucket = bucketIt->second;
248+
epParams.emplace_back(Aws::String("Bucket"), bucket);
249+
}
250+
}
251+
252+
auto epResolutionOutcome = this->ResolveEndpoint(std::move(epParams), std::move(endpointCallback));
253+
if (!epResolutionOutcome.IsSuccess())
254+
{
255+
AWS_LOGSTREAM_ERROR(ServiceNameT, "Presigned URL generating failed. Encountered error: " << epResolutionOutcome.GetError().GetMessage());
256+
return {};
257+
}
258+
auto endpoint = std::move(epResolutionOutcome.GetResultWithOwnership());
259+
const Aws::Http::URI& uri = endpoint.GetURI();
260+
auto signerRegionOverride = region;
261+
auto signerServiceNameOverride = serviceName;
262+
//signer name is needed for some identity resolvers
263+
if (endpoint.GetAttributes()) {
264+
if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) {
265+
signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str();
266+
}
267+
if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) {
268+
signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str();
269+
}
270+
if (endpoint.GetAttributes()->authScheme.GetSigningName()) {
271+
signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str();
272+
}
273+
}
274+
std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
275+
request->SetServiceSpecificParameters(serviceSpecificParameters);
276+
for (const auto& it: customizedHeaders)
277+
{
278+
request->SetHeaderValue(it.first.c_str(), it.second);
279+
}
280+
if (AwsClientRequestSigning<AuthSchemesVariantT>::PreSignRequest(request, authSchemeOption, m_authSchemes, signerRegionOverride, signerServiceNameOverride, expirationInSeconds).IsSuccess())
281+
{
282+
return request->GetURIString();
283+
}
284+
return {};
285+
}
286+
287+
//legacy
216288
Aws::String GeneratePresignedUrl(const Aws::Http::URI& uri,
217289
Aws::Http::HttpMethod method,
218290
const Aws::String& region,
@@ -237,7 +309,7 @@ namespace client
237309
return {};
238310
}
239311

240-
312+
241313
Aws::String GeneratePresignedUrl(const Aws::Endpoint::AWSEndpoint& endpoint,
242314
Aws::Http::HttpMethod method,
243315
const Aws::String& region,
@@ -263,8 +335,7 @@ namespace client
263335
}
264336
return GeneratePresignedUrl(uri, method, signerRegionOverride, signerServiceNameOverride, expirationInSeconds, customizedHeaders, serviceSpecificParameters);
265337
}
266-
267-
protected:
338+
268339
/* Service client specific config, the actual object is stored in AwsSmithyClientBase by pointer
269340
* In order to avoid config object duplication, smithy template client access it by a reference.
270341
* So that base client has it by base config pointer, child smithy client has it by child config reference.
@@ -274,6 +345,15 @@ namespace client
274345
std::shared_ptr<ServiceAuthSchemeResolverT> m_authSchemeResolver{};
275346
Aws::UnorderedMap<Aws::String, AuthSchemesVariantT> m_authSchemes{};
276347
std::shared_ptr<SerializerT> m_serializer{};
348+
private:
349+
friend class AwsLegacyClientT<ServiceNameT, ResponseT, AwsSmithyClientT<ServiceNameT,
350+
ServiceClientConfigurationT,
351+
ServiceAuthSchemeResolverT,
352+
AuthSchemesVariantT,
353+
EndpointProviderT,
354+
SerializerT,
355+
ResponseT,
356+
ErrorMarshallerT>>;
277357
};
278358

279359
} // namespace client

src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClientBase.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,16 @@ namespace client
7474
using HttpRequest = Aws::Http::HttpRequest;
7575
using HttpResponse = Aws::Http::HttpResponse;
7676
using CoreErrors = Aws::Client::CoreErrors;
77-
using AWSError = Aws::Client::AWSError<CoreErrors>;
78-
using ClientError = AWSError;
79-
using SigningError = AWSError;
77+
using AWSCoreError = Aws::Client::AWSError<CoreErrors>;
78+
using ClientError = AWSCoreError;
79+
using SigningError = AWSCoreError;
8080
using SigningOutcome = Aws::Utils::FutureOutcome<std::shared_ptr<Aws::Http::HttpRequest>, SigningError>;
8181
using EndpointUpdateCallback = std::function<void(Aws::Endpoint::AWSEndpoint&)>;
82-
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError>;
82+
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSCoreError>;
8383
using ResponseHandlerFunc = std::function<void(HttpResponseOutcome&&)>;
84-
using SelectAuthSchemeOptionOutcome = Aws::Utils::Outcome<AuthSchemeOption, AWSError>;
85-
using ResolveEndpointOutcome = Aws::Utils::Outcome<Aws::Endpoint::AWSEndpoint, AWSError>;
86-
using StreamOutcome = Aws::Utils::Outcome<Aws::AmazonWebServiceResult<Aws::Utils::Stream::ResponseStream>, AWSError >;
84+
using SelectAuthSchemeOptionOutcome = Aws::Utils::Outcome<AuthSchemeOption, AWSCoreError>;
85+
using ResolveEndpointOutcome = Aws::Utils::Outcome<Aws::Endpoint::AWSEndpoint, AWSCoreError>;
86+
using StreamOutcome = Aws::Utils::Outcome<Aws::AmazonWebServiceResult<Aws::Utils::Stream::ResponseStream>, AWSCoreError >;
8787

8888
/* primary constructor */
8989
AwsSmithyClientBase(Aws::UniquePtr<Aws::Client::ClientConfiguration>&& clientConfig,
@@ -149,6 +149,13 @@ namespace client
149149
void AppendToUserAgent(const Aws::String& valueToAppend);
150150

151151
protected:
152+
153+
//for backwards compatibility
154+
const std::shared_ptr<Aws::Client::AWSErrorMarshaller>& GetErrorMarshaller() const
155+
{
156+
return m_errorMarshaller;
157+
}
158+
152159
/**
153160
* Initialize client configuration with their factory method, unless the user has explicitly set the
154161
* configuration, and it is to be shallow copied between different clients, in which case, delete the

tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <aws/testing/MemoryTesting.h>
1313
#include <memory>
1414
#include <aws/s3/S3ErrorMarshaller.h>
15+
#include <aws/s3/model/HeadBucketRequest.h>
1516

1617
using namespace Aws;
1718
using namespace Aws::Client;
@@ -31,11 +32,34 @@ class S3TestClient : public S3Client
3132
template <typename ...Args>
3233
S3TestClient(Args&& ...args): S3Client(std::forward<Args>(args)...){
3334
}
35+
XmlOutcome MakeRequest(const Aws::Http::URI& uri,
36+
const Aws::AmazonWebServiceRequest& request,
37+
Aws::Http::HttpMethod method = Aws::Http::HttpMethod::HTTP_POST,
38+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
39+
const char* signerRegionOverride = nullptr,
40+
const char* signerServiceNameOverride = nullptr) const
41+
{
42+
return S3Client::MakeRequest(uri, request, method, signerName, signerRegionOverride, signerServiceNameOverride);
43+
}
44+
45+
46+
XmlOutcome MakeRequest(const Aws::Http::URI& uri,
47+
Http::HttpMethod method = Http::HttpMethod::HTTP_POST,
48+
const char* signerName = Aws::Auth::SIGV4_SIGNER,
49+
const char* requestName = "",
50+
const char* signerRegionOverride = nullptr,
51+
const char* signerServiceNameOverride = nullptr) const
52+
{
53+
return S3Client::MakeRequest(uri, method, signerName, requestName, signerRegionOverride, signerServiceNameOverride);
54+
}
55+
3456

3557
private:
3658
S3TestClient() = default;
3759

3860
friend class S3UnitTest_S3EmbeddedErrorTestNonOKResponse_Test;
61+
62+
3963
};
4064

4165
class NoRetry: public RetryStrategy
@@ -459,4 +483,41 @@ TEST_F(S3UnitTest, RequestShouldNotIncludeAChecksumIfRequiredWithMD5Header) {
459483
[](const std::pair<Aws::String, Aws::String>& keyValue) { return keyValue.first.find("x-amz-checksum") != Aws::String::npos; }));
460484
EXPECT_TRUE(std::any_of(headers.begin(), headers.end(),
461485
[](const std::pair<Aws::String, Aws::String>& keyValue) { return keyValue.first.find("content-md5") != Aws::String::npos; }));
486+
}
487+
488+
TEST_F(S3UnitTest, testLegacyApi)
489+
{
490+
HeadBucketRequest headBucketRequest;
491+
headBucketRequest.SetBucket("dummy");
492+
493+
auto uri = _s3Client->GeneratePresignedUrl("dummy",
494+
/*key=*/"", Aws::Http::HttpMethod::HTTP_HEAD);
495+
496+
//We have to mock requset because it is used to create the return body, it actually isnt used.
497+
auto mockRequest = Aws::MakeShared<Standard::StandardHttpRequest>(ALLOCATION_TAG, "mockuri", HttpMethod::HTTP_GET);
498+
mockRequest->SetResponseStreamFactory([]() -> IOStream* {
499+
return Aws::New<StringStream>(ALLOCATION_TAG, "response-string", std::ios_base::in | std::ios_base::binary);
500+
});
501+
502+
{
503+
auto mockResponse = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, mockRequest);
504+
mockResponse->SetResponseCode(HttpResponseCode::OK);
505+
_mockHttpClient->AddResponseToReturn(mockResponse);
506+
}
507+
508+
auto outcome = _s3Client->MakeRequest(uri, headBucketRequest, Aws::Http::HttpMethod::HTTP_HEAD,
509+
"SignatureV4");
510+
511+
EXPECT_TRUE(outcome.IsSuccess());
512+
513+
{
514+
auto mockResponse = Aws::MakeShared<Standard::StandardHttpResponse>(ALLOCATION_TAG, mockRequest);
515+
mockResponse->SetResponseCode(HttpResponseCode::OK);
516+
_mockHttpClient->AddResponseToReturn(mockResponse);
517+
}
518+
519+
auto outcome2 = _s3Client->MakeRequest(uri, Aws::Http::HttpMethod::HTTP_HEAD,
520+
"SignatureV4");
521+
522+
EXPECT_TRUE(outcome2.IsSuccess());
462523
}

tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/common/ServiceClientConfigurationHeader.vm

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,6 @@ namespace ${rootNamespace}
167167
IdentityProviderSupplier identityProviderSupplier = [](const ${metadata.classNamePrefix}Client &client) -> std::shared_ptr<S3ExpressIdentityProvider> {
168168
return Aws::MakeShared<DefaultS3ExpressIdentityProvider>("${metadata.classNamePrefix}ClientConfiguration", client);
169169
};
170-
#if($serviceModel.isUseSmithyClient())
171-
using SmithyIdentityProviderSupplier = std::function<std::shared_ptr<SmithyS3ExpressIdentityProvider> (const ${metadata.classNamePrefix}Client &)>;
172-
SmithyIdentityProviderSupplier smithyIdentityProviderSupplier = [](const ${metadata.classNamePrefix}Client &client) -> std::shared_ptr<SmithyS3ExpressIdentityProvider> {
173-
return Aws::MakeShared<SmithyDefaultS3ExpressIdentityProvider>("${metadata.classNamePrefix}ClientConfiguration", client);
174-
};
175-
#end
176170
#end
177171
#if($metadata.hasEndpointDiscoveryTrait)
178172

tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/s3/SmithyS3ClientHeader.vm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ namespace ${rootNamespace}
118118
${metadata.classNamePrefix}EndpointProviderBase,
119119
smithy::client::$serializer,
120120
smithy::client::$serializerOutcome,
121-
Aws::Client::${metadata.classNamePrefix}ErrorMarshaller>,
121+
Aws::Client::${metadata.classNamePrefix}ErrorMarshaller>
122122
{
123123
public:
124124
static const char* GetServiceName();

0 commit comments

Comments
 (0)