DefaultEndpointProvider.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/endpoint/DefaultEndpointProvider.h>
  6. #include <aws/core/utils/memory/stl/AWSMap.h>
  7. #include <aws/crt/Api.h>
  8. namespace Aws
  9. {
  10. namespace Endpoint
  11. {
  12. /**
  13. * Export endpoint provider symbols from DLL
  14. */
  15. template class AWS_CORE_API DefaultEndpointProvider<Aws::Client::GenericClientConfiguration<false>,
  16. Aws::Endpoint::BuiltInParameters,
  17. Aws::Endpoint::ClientContextParameters>;
  18. char CharToDec(const char c)
  19. {
  20. if(c >= '0' && c <= '9')
  21. return c - '0';
  22. if(c >= 'A' && c <= 'F')
  23. return c - 'A' + 10;
  24. if(c >= 'a' && c <= 'f')
  25. return c - 'a' + 10;
  26. return 0;
  27. }
  28. Aws::String PercentDecode(Aws::String inputString)
  29. {
  30. if (inputString.find_first_of("%") == Aws::String::npos)
  31. {
  32. return inputString;
  33. }
  34. Aws::String result;
  35. result.reserve(inputString.size());
  36. bool percentFound = false;
  37. char firstOctet = 0;
  38. char secondOctet = 0;
  39. for(size_t i = 0; i < inputString.size(); ++i)
  40. {
  41. const char currentChar = inputString[i];
  42. if ('%' == currentChar)
  43. {
  44. if (percentFound)
  45. {
  46. // not percent-encoded string
  47. result += currentChar;
  48. }
  49. percentFound = true;
  50. continue;
  51. }
  52. if (percentFound)
  53. {
  54. if ((currentChar >= '0' && currentChar <= '9') ||
  55. (currentChar >= 'A' && currentChar <= 'F') ||
  56. (currentChar >= 'a' && currentChar <= 'f'))
  57. {
  58. if(!firstOctet)
  59. {
  60. firstOctet = currentChar;
  61. continue;
  62. }
  63. if(!secondOctet)
  64. {
  65. secondOctet = currentChar;
  66. char encodedChar = CharToDec(firstOctet) * 16 + CharToDec(secondOctet);
  67. result += encodedChar;
  68. percentFound = false;
  69. firstOctet = 0;
  70. secondOctet = 0;
  71. continue;
  72. }
  73. } else {
  74. // Non-percent encoded sequence
  75. result += '%';
  76. if(!firstOctet)
  77. result += firstOctet;
  78. result += currentChar;
  79. percentFound = false;
  80. firstOctet = 0;
  81. secondOctet = 0;
  82. continue;
  83. }
  84. }
  85. if ('+' == currentChar)
  86. {
  87. result += ' ';
  88. continue;
  89. }
  90. result += currentChar;
  91. }
  92. return result;
  93. }
  94. AWS_CORE_API ResolveEndpointOutcome
  95. ResolveEndpointDefaultImpl(const Aws::Crt::Endpoints::RuleEngine& ruleEngine,
  96. const EndpointParameters& builtInParameters,
  97. const EndpointParameters& clientContextParameters,
  98. const EndpointParameters& endpointParameters)
  99. {
  100. if(!ruleEngine) {
  101. AWS_LOGSTREAM_FATAL(DEFAULT_ENDPOINT_PROVIDER_TAG, "Invalid CRT Rule Engine state");
  102. return ResolveEndpointOutcome(
  103. Aws::Client::AWSError<Aws::Client::CoreErrors>(
  104. Aws::Client::CoreErrors::INTERNAL_FAILURE,
  105. "",
  106. "CRT Endpoint rule engine is not initialized",
  107. false/*retryable*/));
  108. }
  109. Aws::Crt::Endpoints::RequestContext crtRequestCtx;
  110. const Aws::Vector<std::reference_wrapper<const EndpointParameters>> allParameters
  111. = {std::cref(builtInParameters), std::cref(clientContextParameters), std::cref(endpointParameters)};
  112. for (const auto& parameterClass : allParameters)
  113. {
  114. for(const auto& parameter : parameterClass.get())
  115. {
  116. if(EndpointParameter::ParameterType::BOOLEAN == parameter.GetStoredType())
  117. {
  118. AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint bool eval parameter: " << parameter.GetName() << " = " << parameter.GetBoolValueNoCheck());
  119. crtRequestCtx.AddBoolean(Aws::Crt::ByteCursorFromCString(parameter.GetName().c_str()), parameter.GetBoolValueNoCheck());
  120. }
  121. else if(EndpointParameter::ParameterType::STRING == parameter.GetStoredType())
  122. {
  123. AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint str eval parameter: " << parameter.GetName() << " = " << parameter.GetStrValueNoCheck());
  124. crtRequestCtx.AddString(Aws::Crt::ByteCursorFromCString(parameter.GetName().c_str()), Aws::Crt::ByteCursorFromCString(parameter.GetStrValueNoCheck().c_str()));
  125. }
  126. else
  127. {
  128. return ResolveEndpointOutcome(
  129. Aws::Client::AWSError<Aws::Client::CoreErrors>(
  130. Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER,
  131. "",
  132. "Invalid endpoint parameter type for parameter " + parameter.GetName(),
  133. false/*retryable*/));
  134. }
  135. }
  136. }
  137. auto resolved = ruleEngine.Resolve(crtRequestCtx);
  138. if(resolved.has_value())
  139. {
  140. if(resolved->IsError())
  141. {
  142. auto crtError = resolved->GetError();
  143. Aws::String sdkCrtError = crtError ? Aws::String(crtError->begin(), crtError->end()) :
  144. "CRT Rule engine resolution resulted in an unknown error";
  145. return ResolveEndpointOutcome(
  146. Aws::Client::AWSError<Aws::Client::CoreErrors>(
  147. Aws::Client::CoreErrors::INVALID_PARAMETER_COMBINATION,
  148. "",
  149. sdkCrtError,
  150. false/*retryable*/));
  151. }
  152. else if(resolved->IsEndpoint() && resolved->GetUrl())
  153. {
  154. Aws::Endpoint::AWSEndpoint endpoint;
  155. const auto crtUrl = resolved->GetUrl();
  156. Aws::String sdkCrtUrl = Aws::String(crtUrl->begin(), crtUrl->end());
  157. AWS_LOGSTREAM_DEBUG(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint rules engine evaluated the endpoint: " << sdkCrtUrl);
  158. endpoint.SetURL(PercentDecode(std::move(sdkCrtUrl)));
  159. // Transform attributes
  160. // Each attribute consist of properties, hence converting CRT properties to SDK attributes
  161. const auto crtProps = resolved->GetProperties();
  162. if (crtProps && crtProps->size() > 2) {
  163. Aws::String sdkCrtProps = crtProps ? Aws::String(crtProps->begin(), crtProps->end()) : "";
  164. AWS_LOGSTREAM_TRACE(DEFAULT_ENDPOINT_PROVIDER_TAG, "Endpoint rules evaluated props: " << sdkCrtProps);
  165. Internal::Endpoint::EndpointAttributes epAttributes = Internal::Endpoint::EndpointAttributes::BuildEndpointAttributesFromJson(
  166. sdkCrtProps);
  167. endpoint.SetAttributes(std::move(epAttributes));
  168. }
  169. // transform headers
  170. const auto crtHeaders = resolved->GetHeaders();
  171. if (crtHeaders)
  172. {
  173. Aws::UnorderedMap<Aws::String, Aws::String> sdkHeaders;
  174. for (const auto& header: *crtHeaders)
  175. {
  176. Aws::String key(header.first.begin(), header.first.end());
  177. Aws::String value;
  178. for (const auto& crtHeaderValue : header.second)
  179. {
  180. if(!value.empty()) {
  181. value.insert(value.end(), ';');
  182. }
  183. value.insert(value.end(), crtHeaderValue.begin(), crtHeaderValue.end());
  184. }
  185. sdkHeaders.emplace(std::move(key), std::move(value));
  186. }
  187. endpoint.SetHeaders(std::move(sdkHeaders));
  188. }
  189. return ResolveEndpointOutcome(std::move(endpoint));
  190. }
  191. else
  192. {
  193. return ResolveEndpointOutcome(
  194. Aws::Client::AWSError<Aws::Client::CoreErrors>(
  195. Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER,
  196. "",
  197. "Invalid AWS CRT RuleEngine state",
  198. false/*retryable*/));
  199. }
  200. }
  201. auto errCode = Aws::Crt::LastError();
  202. AWS_LOGSTREAM_DEBUG(DEFAULT_ENDPOINT_PROVIDER_TAG, "ERROR: Rule engine has failed to evaluate the endpoint: " << errCode << " " << Aws::Crt::ErrorDebugString(errCode));
  203. return ResolveEndpointOutcome(
  204. Aws::Client::AWSError<Aws::Client::CoreErrors>(
  205. Aws::Client::CoreErrors::INVALID_QUERY_PARAMETER,
  206. "",
  207. "Failed to evaluate the endpoint: null output from AWS CRT RuleEngine",
  208. false/*retryable*/));
  209. }
  210. } // namespace Endpoint
  211. } // namespace Aws