AWS SDK for C++

AWS SDK for C++ Version 1.11.809

Loading...
Searching...
No Matches
AwsSmithyClient.h
1
5#pragma once
6
7#include <smithy/client/AwsSmithyClientBase.h>
8#include <smithy/client/AwsSmithyClientAsyncRequestContext.h>
9#include <smithy/client/common/AwsSmithyRequestSigning.h>
10#include <smithy/identity/identity/AwsIdentity.h>
11#include <smithy/identity/auth/AuthSchemeOption.h>
12#include <smithy/identity/auth/AuthSchemeResolverBase.h>
13#include <smithy/tracing/TelemetryProvider.h>
14
15#include <aws/crt/Variant.h>
16
17#include <aws/core/client/ClientConfiguration.h>
18#include <aws/core/http/HttpResponse.h>
19#include <aws/core/utils/memory/stl/AWSMap.h>
20#include <aws/core/utils/FutureOutcome.h>
21#include <aws/core/utils/Outcome.h>
22#include <aws/core/utils/threading/Executor.h>
23#include <aws/core/http/HttpResponse.h>
24#include <aws/core/http/HttpClientFactory.h>
25#include <smithy/identity/signer/built-in/SignerProperties.h>
26#include <smithy/client/AwsLegacyClient.h>
27
28namespace smithy {
29 namespace client {
30 template <typename OutcomeT, typename ClientT, typename RequestT, typename HandlerT>
31 class SmithyBidirectionalStreamingTask;
32 }
33}
34
35namespace smithy {
36namespace client
37{
38 template<const char* ServiceNameT,
39 typename ServiceClientConfigurationT,
40 typename ServiceAuthSchemeResolverT,
41 typename AuthSchemesVariantT,
42 typename EndpointProviderT,
43 typename SerializerT,
44 typename ResponseT,
45 typename ErrorMarshallerT>
46 class AwsSmithyClientT : public AwsSmithyClientBase, public AwsLegacyClientT<ServiceNameT, ResponseT,
47 AwsSmithyClientT<ServiceNameT,
48 ServiceClientConfigurationT,
49 ServiceAuthSchemeResolverT,
50 AuthSchemesVariantT,
51 EndpointProviderT,
52 SerializerT,
53 ResponseT,
54 ErrorMarshallerT>>
55 {
56 public:
57 static_assert(std::is_base_of<Aws::Client::AWSErrorMarshaller, ErrorMarshallerT>::value, "MarshallerT must be derived from class Aws::Client::AWSErrorMarshaller");
58
59 explicit AwsSmithyClientT(const ServiceClientConfigurationT& clientConfig,
60 const Aws::String& serviceName,
61 const Aws::String& serviceUserAgentName,
62 const std::shared_ptr<Aws::Http::HttpClient>& httpClient,
63 const std::shared_ptr<Aws::Client::AWSErrorMarshaller>& errorMarshaller,
64 const std::shared_ptr<EndpointProviderT> endpointProvider,
65 const std::shared_ptr<ServiceAuthSchemeResolverT>& authSchemeResolver,
67 : AwsSmithyClientBase(Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, clientConfig),
68 serviceName,
69 serviceUserAgentName,
70 httpClient,
71 errorMarshaller),
72 m_clientConfiguration(*static_cast<ServiceClientConfigurationT*>(AwsSmithyClientBase::m_clientConfig.get())),
73 m_endpointProvider(endpointProvider),
74 m_authSchemeResolver(authSchemeResolver),
75 m_authSchemes(authSchemes),
76 m_serializer(Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider))
77 {
78 initClient();
79 }
80
82 : AwsSmithyClientBase(other,
83 Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, other.m_clientConfiguration),
84 Aws::Http::CreateHttpClient(other.m_clientConfiguration),
85 Aws::MakeShared<ErrorMarshallerT>(ServiceNameT)),
86 m_clientConfiguration(*static_cast<ServiceClientConfigurationT*>(m_clientConfig.get()))
87 {
88 m_endpointProvider = other.m_endpointProvider; /* shallow copy */
89 m_authSchemeResolver = other.m_authSchemeResolver; /* shallow copy */
91 m_serializer = Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider);
92 initClient();
93 }
94
96 {
97 if(this != &other)
98 {
102 Aws::MakeShared<ErrorMarshallerT>(ServiceNameT));
103
104 m_endpointProvider = other.m_endpointProvider; /* shallow copy */
105 m_authSchemeResolver = other.m_authSchemeResolver; /* shallow copy */
107 m_serializer = Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider);
108 initClient();
109 }
110 return *this;
111 }
112
114 AwsSmithyClientBase(std::move(static_cast<AwsSmithyClientBase&&>(other)),
115 Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, std::move(other.m_clientConfiguration))),
116 m_clientConfiguration{*static_cast<ServiceClientConfigurationT*>(m_clientConfig.get())},
117 m_endpointProvider(std::move(other.m_endpointProvider)),
119 m_authSchemes(std::move(other.m_authSchemes)),
120 m_serializer(std::move(other.m_serializer))
121 {
122 }
123
125 {
126 if(this != &other)
127 {
128 m_clientConfiguration = std::move(other.m_clientConfiguration);
129 AwsSmithyClientBase::baseMoveAssign(std::move(static_cast<AwsSmithyClientBase&&>(other)));
130
131 m_endpointProvider = std::move(other.m_endpointProvider);
132 m_authSchemeResolver = std::move(other.m_authSchemeResolver);
133 m_authSchemes = std::move(other.m_authSchemes);
134 m_serializer = std::move(other.m_serializer);
135 }
136 return *this;
137 }
138
139 virtual ~AwsSmithyClientT() = default;
140
141 protected:
142 template <typename OutcomeT, typename ClientT, typename RequestT, typename HandlerT>
144
145 template <typename OutcomeT, typename ClientT, typename RequestT, typename EncoderStreamT, typename HandlerT>
147
148 void initClient() {
150 m_endpointProvider->InitBuiltInParameters(m_clientConfiguration);
152 } else {
153 AWS_LOGSTREAM_FATAL(ServiceNameT, "Unable to init client: endpoint provider=" << m_endpointProvider
154 << " or " << "authSchemeResolver=" << m_authSchemeResolver << " are null!");
155 }
156 }
157
158 inline const char* GetServiceClientName() const override { return m_serviceName.c_str(); }
159
161 {
162 assert(m_endpointProvider);
163 ResolveEndpointOutcome resolveEndpointOutcome = m_endpointProvider->ResolveEndpoint(endpointParameters);
164 if (resolveEndpointOutcome.IsSuccess())
165 {
166 epCallback(resolveEndpointOutcome.GetResult());
167 }
168 return resolveEndpointOutcome;
169 }
170
172 {
173 assert(m_authSchemeResolver);
174 typename ServiceAuthSchemeResolverT::ServiceAuthSchemeParameters identityParams;
175
176 identityParams.serviceName = m_serviceName;
177 identityParams.operation = ctx.m_requestName;
178 identityParams.region = m_clientConfiguration.region;
179 identityParams.authPreferences = m_clientConfiguration.authPreferences;
180
181 if (ctx.m_pRequest) {
182 // refactor once auth scheme resolver will use it's own rule set
183 const auto& epParams = ctx.m_pRequest->GetEndpointContextParams();
184 for (const auto& epParam : epParams) {
186 if(epParam.GetStoredType() == ParameterType::STRING) {
187 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrValueNoCheck()});
188 } else if (epParam.GetStoredType() == ParameterType::BOOLEAN) {
189 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetBoolValueNoCheck()});
190 } else if (epParam.GetStoredType() == ParameterType::STRING_ARRAY) {
191 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrArrayValueNoCheck()});
192 } else {
193 assert(!"Unknown endpoint parameter!");
194 }
195 }
196 const auto& serviceParams = ctx.m_pRequest->GetServiceSpecificParameters();
197 if (serviceParams) {
198 for (const auto& serviceParam : serviceParams->parameterMap) {
199 identityParams.additionalProperties.insert({serviceParam.first, serviceParam.second});
200 }
201 }
202 }
203
204 Aws::Vector<AuthSchemeOption> authSchemeOptions = ctx.m_authResolver == nullptr ? m_authSchemeResolver->resolveAuthScheme(identityParams) : ctx.m_authResolver->resolveAuthScheme(identityParams);
205
206 auto authSchemeOptionIt = std::find_if(authSchemeOptions.begin(), authSchemeOptions.end(),
207 [this](const AuthSchemeOption& opt)
208 {
209 return m_authSchemes.find(opt.schemeId) != m_authSchemes.end();
210 });
211 assert(authSchemeOptionIt != authSchemeOptions.end());
212
213 if (authSchemeOptionIt != authSchemeOptions.end()) {
214 return SelectAuthSchemeOptionOutcome(*authSchemeOptionIt);
215 }
217 "",
218 "Failed to select an auth scheme",
219 false/*retryable*/);
220 }
221
222 SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AwsSmithyClientAsyncRequestContext& ctx) const override
223 {
225 }
226
227 SigningEventOutcome SignEventMessage(Aws::Utils::Event::Message& message, Aws::String &seed, const std::shared_ptr<AwsSmithyClientAsyncRequestContext>& ctx) const
228 {
230 }
231
232 bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const override
233 {
235 }
236
239 }
240
242 return GetContextEndpointParametersImpl(ctx);
243 }
244
246 const char* requestName,
248 EndpointUpdateCallback&& endpointCallback,
249 AuthResolvedCallback&& authCallback = nullptr) const
250 {
251 auto httpResponseOutcome = MakeRequestSync(request, requestName, method, std::move(endpointCallback), std::move(authCallback));
252 return m_serializer->Deserialize(std::move(httpResponseOutcome), GetServiceClientName(), requestName);
253 }
254
256 EndpointUpdateCallback&& endpointCallback,
258 const Aws::String& region,
259 const Aws::String& serviceName,
260 long long expirationInSeconds,
261 const Aws::Http::HeaderValueCollection& customizedHeaders,
262 const std::shared_ptr<Aws::Http::ServiceSpecificParameters> serviceSpecificParameters) const
263 {
264 ExtractUriCallback getUriCallback = [&](Aws::Http::URI& uri, Aws::String& signerRegionOverride,
265 Aws::String& signerServiceNameOverride, const AuthSchemeOption& authSchemeOption) -> bool{
266
268 const auto authSchemeEpParams = authSchemeOption.endpointParameters();
269 epParams.insert(epParams.end(), authSchemeEpParams.begin(), authSchemeEpParams.end());
270 if(serviceSpecificParameters)
271 {
272 auto bucketIt = serviceSpecificParameters->parameterMap.find("bucketName");
273 if(bucketIt != serviceSpecificParameters->parameterMap.end())
274 {
275 auto bucket = bucketIt->second;
276 epParams.emplace_back(Aws::String("Bucket"), bucket);
277 }
278 }
279
280 auto epResolutionOutcome = this->ResolveEndpoint(std::move(epParams), std::move(endpointCallback));
281 if (!epResolutionOutcome.IsSuccess())
282 {
283 AWS_LOGSTREAM_ERROR(ServiceNameT, "Presigned URL generating failed. Encountered error: " << epResolutionOutcome.GetError().GetMessage());
284 return false;
285 }
286 auto endpoint = std::move(epResolutionOutcome.GetResultWithOwnership());
287 uri = endpoint.GetURI();
288 signerRegionOverride = region;
289 signerServiceNameOverride = serviceName;
290 //signer name is needed for some identity resolvers
291 if (endpoint.GetAttributes()) {
292 if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) {
293 signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str();
294 }
295 if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) {
296 signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str();
297 }
298 if (endpoint.GetAttributes()->authScheme.GetSigningName()) {
299 signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str();
300 }
301 }
302 return true;
303 };
304
305 CreateHttpRequestCallback createHttpRequestCallback = [&customizedHeaders, &serviceSpecificParameters](const Aws::Http::URI& uri, const Aws::Http::HttpMethod& method) -> std::shared_ptr<HttpRequest> {
306 std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
307 request->SetServiceSpecificParameters(serviceSpecificParameters);
308 for (const auto& it: customizedHeaders)
309 {
310 request->SetHeaderValue(it.first.c_str(), it.second);
311 }
312 return request;
313 };
314
316 std::move(getUriCallback),
317 std::move(createHttpRequestCallback),
318 method,
319 region,
320 serviceName,
321 expirationInSeconds);
322 }
323
324 /* Service client specific config, the actual object is stored in AwsSmithyClientBase by pointer
325 * In order to avoid config object duplication, smithy template client access it by a reference.
326 * So that base client has it by base config pointer, child smithy client has it by child config reference.
327 */
328 ServiceClientConfigurationT& m_clientConfiguration;
329 std::shared_ptr<EndpointProviderT> m_endpointProvider{};
330 std::shared_ptr<ServiceAuthSchemeResolverT> m_authSchemeResolver{};
332 std::shared_ptr<SerializerT> m_serializer{};
333 private:
334 using ExtractUriCallback = std::function<bool (Aws::Http::URI&, Aws::String& region, Aws::String& serviceName,const AuthSchemeOption&)>;
335 using CreateHttpRequestCallback = std::function<std::shared_ptr<HttpRequest> (const Aws::Http::URI&, const Aws::Http::HttpMethod&)>;
336
338 ExtractUriCallback&& getUriCallback,
339 CreateHttpRequestCallback&& createHttpRequestCallback,
341 const Aws::String& region,
342 const Aws::String& serviceName,
343 long long expirationInSeconds) const
344 {
346 auto authSchemeOptionOutcome = SelectAuthSchemeOption( ctx);
347 auto authSchemeOption = std::move(authSchemeOptionOutcome.GetResultWithOwnership());
348 Aws::Http::URI uri;
349 Aws::String signerRegionOverride = region;
350 Aws::String signerServiceNameOverride = serviceName;
351 if(!getUriCallback(uri , signerRegionOverride, signerServiceNameOverride, authSchemeOption))
352 {
353 return {};
354 }
355 std::shared_ptr<HttpRequest> request = createHttpRequestCallback(uri, method);
356 if (AwsClientRequestSigning<AuthSchemesVariantT>::PreSignRequest(request, authSchemeOption, m_authSchemes, signerRegionOverride, signerServiceNameOverride, expirationInSeconds).IsSuccess())
357 {
358 return request->GetURIString();
359 }
360 return {};
361 }
362
363 friend class AwsLegacyClientT<ServiceNameT, ResponseT, AwsSmithyClientT<ServiceNameT,
364 ServiceClientConfigurationT,
365 ServiceAuthSchemeResolverT,
366 AuthSchemesVariantT,
367 EndpointProviderT,
368 SerializerT,
369 ResponseT,
370 ErrorMarshallerT>>;
371
372 GetContextEndpointParametersOutcome GetContextEndpointParametersImpl(const AwsSmithyClientAsyncRequestContext& ctx) const {
374 const auto resolvedAccountId = ctx.m_awsIdentity->accountId();
375 const auto resolvedNonEmptyAccountId = resolvedAccountId.has_value() && !resolvedAccountId.value().empty();
376 // Set user agent if account ID was resolved in identity provider
377 if (resolvedNonEmptyAccountId) {
379 }
380 // Only set EP param if client configuration does not have a configured account ID and we resolved a account id
381 if (resolvedNonEmptyAccountId && m_clientConfiguration.accountId.empty()) {
382 endpointParameters.emplace_back("AccountId", resolvedAccountId.value(), Aws::Endpoint::EndpointParameter::ParameterOrigin::OPERATION_CONTEXT);
383 }
384 return endpointParameters;
385 }
386 };
387
388} // namespace client
389} // namespace smithy
virtual EndpointParameters GetEndpointContextParams() const
void AddUserAgentFeature(Aws::Client::UserAgentFeature feature) const
virtual std::shared_ptr< Http::ServiceSpecificParameters > GetServiceSpecificParameters() const
bool IsSuccess() const
Definition Outcome.h:180
const R & GetResult() const
Definition Outcome.h:135
static SigningEventOutcome SignEventMessage(Aws::Utils::Event::Message &message, Aws::String &seed, const std::shared_ptr< client::AwsSmithyClientAsyncRequestContext > &ctx, const Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > &authSchemes)
static SigningOutcome SignRequest(std::shared_ptr< HttpRequest > HTTPRequest, const client::AwsSmithyClientAsyncRequestContext &ctx, const Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > &authSchemes)
static IdentityOutcome ResolveIdentity(const client::AwsSmithyClientAsyncRequestContext &ctx, const Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > &authSchemes)
static bool AdjustClockSkew(HttpResponseOutcome &outcome, const AuthSchemeOption &authSchemeOption, const Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > &authSchemes)
std::shared_ptr< smithy::AuthSchemeResolverBase<> > m_authResolver
Aws::Utils::Outcome< Aws::Vector< Aws::Endpoint::EndpointParameter >, AWSCoreError > GetContextEndpointParametersOutcome
void baseCopyAssign(const AwsSmithyClientBase &other, std::shared_ptr< Aws::Http::HttpClient > httpClient, std::shared_ptr< Aws::Client::AWSErrorMarshaller > errorMarshaller)
std::function< void(Aws::Endpoint::AWSEndpoint &)> EndpointUpdateCallback
Aws::Utils::Outcome< AuthSchemeOption, AWSCoreError > SelectAuthSchemeOptionOutcome
void baseMoveAssign(AwsSmithyClientBase &&other)
HttpResponseOutcome MakeRequestSync(Aws::AmazonWebServiceRequest const *const request, const char *requestName, Aws::Http::HttpMethod method, EndpointUpdateCallback &&endpointCallback, AuthResolvedCallback &&authCallback) const
const Aws::UniquePtr< Aws::Client::ClientConfiguration > m_clientConfig
std::function< void(std::shared_ptr< AwsSmithyClientAsyncRequestContext >)> AuthResolvedCallback
SelectAuthSchemeOptionOutcome SelectAuthSchemeOption(const AwsSmithyClientAsyncRequestContext &ctx) const override
virtual ~AwsSmithyClientT()=default
GetContextEndpointParametersOutcome GetContextEndpointParameters(const AwsSmithyClientAsyncRequestContext &ctx) const override
AwsSmithyClientT(const ServiceClientConfigurationT &clientConfig, const Aws::String &serviceName, const Aws::String &serviceUserAgentName, const std::shared_ptr< Aws::Http::HttpClient > &httpClient, const std::shared_ptr< Aws::Client::AWSErrorMarshaller > &errorMarshaller, const std::shared_ptr< EndpointProviderT > endpointProvider, const std::shared_ptr< ServiceAuthSchemeResolverT > &authSchemeResolver, const Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > &authSchemes)
const char * GetServiceClientName() const override
std::shared_ptr< ServiceAuthSchemeResolverT > m_authSchemeResolver
AwsSmithyClientT & operator=(const AwsSmithyClientT &other)
ResolveEndpointOutcome ResolveEndpoint(const Aws::Endpoint::EndpointParameters &endpointParameters, EndpointUpdateCallback &&epCallback) const override
Aws::UnorderedMap< Aws::String, AuthSchemesVariantT > m_authSchemes
SigningEventOutcome SignEventMessage(Aws::Utils::Event::Message &message, Aws::String &seed, const std::shared_ptr< AwsSmithyClientAsyncRequestContext > &ctx) const
ResponseT MakeRequestDeserialize(Aws::AmazonWebServiceRequest const *const request, const char *requestName, Aws::Http::HttpMethod method, EndpointUpdateCallback &&endpointCallback, AuthResolvedCallback &&authCallback=nullptr) const
IdentityOutcome ResolveIdentity(const AwsSmithyClientAsyncRequestContext &ctx) const override
AwsSmithyClientT & operator=(AwsSmithyClientT &&other)
Aws::String GeneratePresignedUrl(EndpointUpdateCallback &&endpointCallback, Aws::Http::HttpMethod method, const Aws::String &region, const Aws::String &serviceName, long long expirationInSeconds, const Aws::Http::HeaderValueCollection &customizedHeaders, const std::shared_ptr< Aws::Http::ServiceSpecificParameters > serviceSpecificParameters) const
bool AdjustClockSkew(HttpResponseOutcome &outcome, const AuthSchemeOption &authSchemeOption) const override
SigningOutcome SignHttpRequest(std::shared_ptr< HttpRequest > httpRequest, const AwsSmithyClientAsyncRequestContext &ctx) const override
ServiceClientConfigurationT & m_clientConfiguration
std::shared_ptr< SerializerT > m_serializer
AwsSmithyClientT(AwsSmithyClientT &&other)
AwsSmithyClientT(const AwsSmithyClientT &other)
std::shared_ptr< EndpointProviderT > m_endpointProvider
Aws::Vector< Aws::Endpoint::EndpointParameter > EndpointParameters
AWS_CORE_API std::shared_ptr< HttpClient > CreateHttpClient(const Aws::Client::ClientConfiguration &clientConfiguration)
Aws::Map< Aws::String, Aws::String > HeaderValueCollection
Definition HttpTypes.h:56
AWS_CORE_API Aws::IOStream * DefaultResponseStreamFactoryMethod()
std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > > String
Definition AWSString.h:97
std::vector< T, Aws::Allocator< T > > Vector
Definition AWSVector.h:17
std::unordered_map< K, V, std::hash< K >, std::equal_to< K >, Aws::Allocator< std::pair< const K, V > > > UnorderedMap
Definition AWSMap.h:21