AWS SDK for C++

AWS SDK for C++ Version 1.11.606

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 {
29namespace client
30{
31 template<const char* ServiceNameT,
32 typename ServiceClientConfigurationT,
33 typename ServiceAuthSchemeResolverT,
34 typename AuthSchemesVariantT,
35 typename EndpointProviderT,
36 typename SerializerT,
37 typename ResponseT,
38 typename ErrorMarshallerT>
39 class AwsSmithyClientT : public AwsSmithyClientBase, public AwsLegacyClientT<ServiceNameT, ResponseT,
40 AwsSmithyClientT<ServiceNameT,
41 ServiceClientConfigurationT,
42 ServiceAuthSchemeResolverT,
43 AuthSchemesVariantT,
44 EndpointProviderT,
45 SerializerT,
46 ResponseT,
47 ErrorMarshallerT>>
48 {
49 public:
50 static_assert(std::is_base_of<Aws::Client::AWSErrorMarshaller, ErrorMarshallerT>::value, "MarshallerT must be derived from class Aws::Client::AWSErrorMarshaller");
51
52 explicit AwsSmithyClientT(const ServiceClientConfigurationT& clientConfig,
53 const Aws::String& serviceName,
54 const Aws::String& serviceUserAgentName,
55 const std::shared_ptr<Aws::Http::HttpClient>& httpClient,
56 const std::shared_ptr<Aws::Client::AWSErrorMarshaller>& errorMarshaller,
57 const std::shared_ptr<EndpointProviderT> endpointProvider,
58 const std::shared_ptr<ServiceAuthSchemeResolverT>& authSchemeResolver,
60 : AwsSmithyClientBase(Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, clientConfig),
61 serviceName,
62 serviceUserAgentName,
63 httpClient,
64 errorMarshaller),
65 m_clientConfiguration(*static_cast<ServiceClientConfigurationT*>(AwsSmithyClientBase::m_clientConfig.get())),
66 m_endpointProvider(endpointProvider),
67 m_authSchemeResolver(authSchemeResolver),
68 m_authSchemes(authSchemes),
69 m_serializer(Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider))
70 {
71 initClient();
72 }
73
75 : AwsSmithyClientBase(other,
76 Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, other.m_clientConfiguration),
77 Aws::Http::CreateHttpClient(other.m_clientConfiguration),
78 Aws::MakeShared<ErrorMarshallerT>(ServiceNameT)),
79 m_clientConfiguration(*static_cast<ServiceClientConfigurationT*>(m_clientConfig.get()))
80 {
81 m_endpointProvider = other.m_endpointProvider; /* shallow copy */
82 m_authSchemeResolver = other.m_authSchemeResolver; /* shallow copy */
84 m_serializer = Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider);
85 initClient();
86 }
87
89 {
90 if(this != &other)
91 {
95 Aws::MakeShared<ErrorMarshallerT>(ServiceNameT));
96
97 m_endpointProvider = other.m_endpointProvider; /* shallow copy */
98 m_authSchemeResolver = other.m_authSchemeResolver; /* shallow copy */
100 m_serializer = Aws::MakeShared<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider);
101 initClient();
102 }
103 return *this;
104 }
105
107 AwsSmithyClientBase(std::move(static_cast<AwsSmithyClientBase&&>(other)),
108 Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, std::move(other.m_clientConfiguration))),
109 m_clientConfiguration{*static_cast<ServiceClientConfigurationT*>(m_clientConfig.get())},
110 m_endpointProvider(std::move(other.m_endpointProvider)),
112 m_authSchemes(std::move(other.m_authSchemes)),
113 m_serializer(std::move(other.m_serializer))
114 {
115 }
116
118 {
119 if(this != &other)
120 {
121 m_clientConfiguration = std::move(other.m_clientConfiguration);
122 AwsSmithyClientBase::baseMoveAssign(std::move(static_cast<AwsSmithyClientBase&&>(other)));
123
124 m_endpointProvider = std::move(other.m_endpointProvider);
125 m_authSchemeResolver = std::move(other.m_authSchemeResolver);
126 m_authSchemes = std::move(other.m_authSchemes);
127 m_serializer = std::move(other.m_serializer);
128 }
129 return *this;
130 }
131
132 virtual ~AwsSmithyClientT() = default;
133
134 protected:
135 void initClient() {
137 m_endpointProvider->InitBuiltInParameters(m_clientConfiguration);
139 } else {
140 AWS_LOGSTREAM_FATAL(ServiceNameT, "Unable to init client: endpoint provider=" << m_endpointProvider
141 << " or " << "authSchemeResolver=" << m_authSchemeResolver << " are null!");
142 }
143 }
144
145 inline const char* GetServiceClientName() const override { return m_serviceName.c_str(); }
146
148 {
149 assert(m_endpointProvider);
150 ResolveEndpointOutcome resolveEndpointOutcome = m_endpointProvider->ResolveEndpoint(endpointParameters);
151 if (resolveEndpointOutcome.IsSuccess())
152 {
153 epCallback(resolveEndpointOutcome.GetResult());
154 }
155 return resolveEndpointOutcome;
156 }
157
159 {
160 assert(m_authSchemeResolver);
161 typename ServiceAuthSchemeResolverT::ServiceAuthSchemeParameters identityParams;
162
163 identityParams.serviceName = m_serviceName;
164 identityParams.operation = ctx.m_requestName;
165 identityParams.region = m_clientConfiguration.region;
166
167 if (ctx.m_pRequest) {
168 // refactor once auth scheme resolver will use it's own rule set
169 const auto& epParams = ctx.m_pRequest->GetEndpointContextParams();
170 for (const auto& epParam : epParams) {
172 if(epParam.GetStoredType() == ParameterType::STRING) {
173 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrValueNoCheck()});
174 } else if (epParam.GetStoredType() == ParameterType::BOOLEAN) {
175 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetBoolValueNoCheck()});
176 } else if (epParam.GetStoredType() == ParameterType::STRING_ARRAY) {
177 identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrArrayValueNoCheck()});
178 } else {
179 assert(!"Unknown endpoint parameter!");
180 }
181 }
182 const auto& serviceParams = ctx.m_pRequest->GetServiceSpecificParameters();
183 if (serviceParams) {
184 for (const auto& serviceParam : serviceParams->parameterMap) {
185 identityParams.additionalProperties.insert({serviceParam.first, serviceParam.second});
186 }
187 }
188 }
189
190 Aws::Vector<AuthSchemeOption> authSchemeOptions = m_authSchemeResolver->resolveAuthScheme(identityParams);
191
192 auto authSchemeOptionIt = std::find_if(authSchemeOptions.begin(), authSchemeOptions.end(),
193 [this](const AuthSchemeOption& opt)
194 {
195 return m_authSchemes.find(opt.schemeId) != m_authSchemes.end();
196 });
197 assert(authSchemeOptionIt != authSchemeOptions.end());
198
199 if (authSchemeOptionIt != authSchemeOptions.end()) {
200 return SelectAuthSchemeOptionOutcome(*authSchemeOptionIt);
201 }
203 "",
204 "Failed to select an auth scheme",
205 false/*retryable*/);
206 }
207
208 SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AwsSmithyClientAsyncRequestContext& ctx) const override
209 {
211 }
212
213 bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const override
214 {
216 }
217
220 }
221
223 return GetContextEndpointParametersImpl(ctx);
224 }
225
227 const char* requestName,
229 EndpointUpdateCallback&& endpointCallback) const
230 {
231 auto httpResponseOutcome = MakeRequestSync(request, requestName, method, std::move(endpointCallback));
232 return m_serializer->Deserialize(std::move(httpResponseOutcome), GetServiceClientName(), requestName);
233 }
234
236 EndpointUpdateCallback&& endpointCallback,
238 const Aws::String& region,
239 const Aws::String& serviceName,
240 long long expirationInSeconds,
241 const Aws::Http::HeaderValueCollection& customizedHeaders,
242 const std::shared_ptr<Aws::Http::ServiceSpecificParameters> serviceSpecificParameters) const
243 {
244 ExtractUriCallback getUriCallback = [&](Aws::Http::URI& uri, Aws::String& signerRegionOverride,
245 Aws::String& signerServiceNameOverride, const AuthSchemeOption& authSchemeOption) -> bool{
246
248 const auto authSchemeEpParams = authSchemeOption.endpointParameters();
249 epParams.insert(epParams.end(), authSchemeEpParams.begin(), authSchemeEpParams.end());
250 if(serviceSpecificParameters)
251 {
252 auto bucketIt = serviceSpecificParameters->parameterMap.find("bucketName");
253 if(bucketIt != serviceSpecificParameters->parameterMap.end())
254 {
255 auto bucket = bucketIt->second;
256 epParams.emplace_back(Aws::String("Bucket"), bucket);
257 }
258 }
259
260 auto epResolutionOutcome = this->ResolveEndpoint(std::move(epParams), std::move(endpointCallback));
261 if (!epResolutionOutcome.IsSuccess())
262 {
263 AWS_LOGSTREAM_ERROR(ServiceNameT, "Presigned URL generating failed. Encountered error: " << epResolutionOutcome.GetError().GetMessage());
264 return false;
265 }
266 auto endpoint = std::move(epResolutionOutcome.GetResultWithOwnership());
267 uri = endpoint.GetURI();
268 signerRegionOverride = region;
269 signerServiceNameOverride = serviceName;
270 //signer name is needed for some identity resolvers
271 if (endpoint.GetAttributes()) {
272 if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) {
273 signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str();
274 }
275 if (endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) {
276 signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegionSet()->c_str();
277 }
278 if (endpoint.GetAttributes()->authScheme.GetSigningName()) {
279 signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str();
280 }
281 }
282 return true;
283 };
284
285 CreateHttpRequestCallback createHttpRequestCallback = [&customizedHeaders, &serviceSpecificParameters](const Aws::Http::URI& uri, const Aws::Http::HttpMethod& method) -> std::shared_ptr<HttpRequest> {
286 std::shared_ptr<HttpRequest> request = CreateHttpRequest(uri, method, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
287 request->SetServiceSpecificParameters(serviceSpecificParameters);
288 for (const auto& it: customizedHeaders)
289 {
290 request->SetHeaderValue(it.first.c_str(), it.second);
291 }
292 return request;
293 };
294
296 std::move(getUriCallback),
297 std::move(createHttpRequestCallback),
298 method,
299 region,
300 serviceName,
301 expirationInSeconds);
302 }
303
304 /* Service client specific config, the actual object is stored in AwsSmithyClientBase by pointer
305 * In order to avoid config object duplication, smithy template client access it by a reference.
306 * So that base client has it by base config pointer, child smithy client has it by child config reference.
307 */
308 ServiceClientConfigurationT& m_clientConfiguration;
309 std::shared_ptr<EndpointProviderT> m_endpointProvider{};
310 std::shared_ptr<ServiceAuthSchemeResolverT> m_authSchemeResolver{};
312 std::shared_ptr<SerializerT> m_serializer{};
313 private:
314 using ExtractUriCallback = std::function<bool (Aws::Http::URI&, Aws::String& region, Aws::String& serviceName,const AuthSchemeOption&)>;
315 using CreateHttpRequestCallback = std::function<std::shared_ptr<HttpRequest> (const Aws::Http::URI&, const Aws::Http::HttpMethod&)>;
316
318 ExtractUriCallback&& getUriCallback,
319 CreateHttpRequestCallback&& createHttpRequestCallback,
321 const Aws::String& region,
322 const Aws::String& serviceName,
323 long long expirationInSeconds) const
324 {
326 auto authSchemeOptionOutcome = SelectAuthSchemeOption( ctx);
327 auto authSchemeOption = std::move(authSchemeOptionOutcome.GetResultWithOwnership());
328 Aws::Http::URI uri;
329 Aws::String signerRegionOverride = region;
330 Aws::String signerServiceNameOverride = serviceName;
331 if(!getUriCallback(uri , signerRegionOverride, signerServiceNameOverride, authSchemeOption))
332 {
333 return {};
334 }
335 std::shared_ptr<HttpRequest> request = createHttpRequestCallback(uri, method);
336 if (AwsClientRequestSigning<AuthSchemesVariantT>::PreSignRequest(request, authSchemeOption, m_authSchemes, signerRegionOverride, signerServiceNameOverride, expirationInSeconds).IsSuccess())
337 {
338 return request->GetURIString();
339 }
340 return {};
341 }
342
343 friend class AwsLegacyClientT<ServiceNameT, ResponseT, AwsSmithyClientT<ServiceNameT,
344 ServiceClientConfigurationT,
345 ServiceAuthSchemeResolverT,
346 AuthSchemesVariantT,
347 EndpointProviderT,
348 SerializerT,
349 ResponseT,
350 ErrorMarshallerT>>;
351
352 GetContextEndpointParametersOutcome GetContextEndpointParametersImpl(const AwsSmithyClientAsyncRequestContext& ctx) const {
354 const auto resolvedAccountId = ctx.m_awsIdentity->accountId();
355 const auto resolvedNonEmptyAccountId = resolvedAccountId.has_value() && !resolvedAccountId.value().empty();
356 // Set user agent if account ID was resolved in identity provider
357 if (resolvedNonEmptyAccountId) {
359 }
360 // Only set EP param if client configuration does not have a configured account ID and we resolved a account id
361 if (resolvedNonEmptyAccountId && m_clientConfiguration.accountId.empty()) {
362 endpointParameters.emplace_back("AccountId", resolvedAccountId.value(), Aws::Endpoint::EndpointParameter::ParameterOrigin::OPERATION_CONTEXT);
363 }
364 return endpointParameters;
365 }
366 };
367
368} // namespace client
369} // 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:178
const R & GetResult() const
Definition Outcome.h:133
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)
Aws::Utils::Outcome< Aws::Vector< Aws::Endpoint::EndpointParameter >, AWSCoreError > GetContextEndpointParametersOutcome
HttpResponseOutcome MakeRequestSync(Aws::AmazonWebServiceRequest const *const request, const char *requestName, Aws::Http::HttpMethod method, EndpointUpdateCallback &&endpointCallback) const
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)
const Aws::UniquePtr< Aws::Client::ClientConfiguration > m_clientConfig
SelectAuthSchemeOptionOutcome SelectAuthSchemeOption(const AwsSmithyClientAsyncRequestContext &ctx) const override
ResponseT MakeRequestDeserialize(Aws::AmazonWebServiceRequest const *const request, const char *requestName, Aws::Http::HttpMethod method, EndpointUpdateCallback &&endpointCallback) const
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
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