CommonClient.cc 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * Copyright 2009-2017 Alibaba Cloud All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <alibabacloud/core/CommonClient.h>
  17. #include <ctime>
  18. #include <algorithm>
  19. #include <iomanip>
  20. #include <sstream>
  21. #include <alibabacloud/core/location/LocationClient.h>
  22. #include <alibabacloud/core/SimpleCredentialsProvider.h>
  23. #include "Utils.h"
  24. using namespace AlibabaCloud;
  25. using namespace Location;
  26. namespace
  27. {
  28. const std::string SERVICE_NAME = "Common";
  29. }
  30. CommonClient::CommonClient(const Credentials &credentials, const ClientConfiguration &configuration) :
  31. CoreClient(SERVICE_NAME, configuration),
  32. credentialsProvider_(std::make_shared<SimpleCredentialsProvider>(credentials)),
  33. signer_(std::make_shared<HmacSha1Signer>())
  34. {
  35. }
  36. CommonClient::CommonClient(const std::shared_ptr<CredentialsProvider>& credentialsProvider, const ClientConfiguration & configuration) :
  37. CoreClient(SERVICE_NAME, configuration),
  38. credentialsProvider_(credentialsProvider),
  39. signer_(std::make_shared<HmacSha1Signer>())
  40. {
  41. }
  42. CommonClient::CommonClient(const std::string & accessKeyId, const std::string & accessKeySecret, const ClientConfiguration & configuration) :
  43. CoreClient(SERVICE_NAME, configuration),
  44. credentialsProvider_(std::make_shared<SimpleCredentialsProvider>(accessKeyId, accessKeySecret)),
  45. signer_(std::make_shared<HmacSha1Signer>())
  46. {
  47. }
  48. CommonClient::~CommonClient()
  49. {
  50. }
  51. CommonClient::JsonOutcome CommonClient::makeRequest(const std::string &endpoint, const CommonRequest &msg, HttpRequest::Method method)const
  52. {
  53. auto outcome = AttemptRequest(endpoint, msg, method);
  54. if (outcome.isSuccess())
  55. return JsonOutcome(std::string(outcome.result().body(),
  56. outcome.result().bodySize()));
  57. else
  58. return JsonOutcome(outcome.error());
  59. }
  60. CommonClient::CommonResponseOutcome CommonClient::commonResponse(const CommonRequest & request) const
  61. {
  62. auto outcome = makeRequest(request.domain(), request, request.httpMethod());
  63. if (outcome.isSuccess())
  64. return CommonResponseOutcome(CommonResponse(outcome.result()));
  65. else
  66. return CommonResponseOutcome(Error(outcome.error()));
  67. }
  68. void CommonClient::commonResponseAsync(const CommonRequest & request, const CommonResponseAsyncHandler & handler, const std::shared_ptr<const AsyncCallerContext>& context) const
  69. {
  70. auto fn = [this, request, handler, context]()
  71. {
  72. handler(this, request, commonResponse(request), context);
  73. };
  74. asyncExecute(new Runnable(fn));
  75. }
  76. CommonClient::CommonResponseOutcomeCallable CommonClient::commonResponseCallable(const CommonRequest & request) const
  77. {
  78. auto task = std::make_shared<std::packaged_task<CommonResponseOutcome()>>(
  79. [this, request]()
  80. {
  81. return this->commonResponse(request);
  82. });
  83. asyncExecute(new Runnable([task]() { (*task)(); }));
  84. return task->get_future();
  85. }
  86. HttpRequest CommonClient::buildHttpRequest(const std::string & endpoint, const ServiceRequest & msg, HttpRequest::Method method) const
  87. {
  88. return buildHttpRequest(endpoint, dynamic_cast<const CommonRequest& >(msg), method);
  89. }
  90. HttpRequest CommonClient::buildHttpRequest(const std::string & endpoint, const CommonRequest &msg, HttpRequest::Method method) const
  91. {
  92. if (msg.requestPattern() == CommonRequest::RpcPattern)
  93. return buildRpcHttpRequest(endpoint, msg, method);
  94. else
  95. return buildRoaHttpRequest(endpoint, msg, method);
  96. }
  97. std::string CommonClient::canonicalizedHeaders(const HttpMessage::HeaderCollection &headers)const
  98. {
  99. std::map <std::string, std::string> materials;
  100. for (const auto &p : headers)
  101. {
  102. std::string key = p.first;
  103. std::transform(key.begin(), key.end(), key.begin(), ::tolower);
  104. if (key.find("x-acs-") != 0)
  105. continue;
  106. std::string value = p.second;
  107. StringReplace(value, "\t", " ");
  108. StringReplace(value, "\n", " ");
  109. StringReplace(value, "\r", " ");
  110. StringReplace(value, "\f", " ");
  111. materials[key] = value;
  112. }
  113. if (materials.empty())
  114. return std::string();
  115. std::stringstream ss;
  116. for (const auto &p : materials)
  117. ss << p.first << ":" << p.second << "\n";
  118. return ss.str();
  119. }
  120. HttpRequest CommonClient::buildRoaHttpRequest(const std::string & endpoint, const CommonRequest &msg, HttpRequest::Method method) const
  121. {
  122. const Credentials credentials = credentialsProvider_->getCredentials();
  123. Url url;
  124. url.setScheme("https");
  125. url.setHost(endpoint);
  126. url.setPath(msg.resourcePath());
  127. auto params = msg.headerParameters();
  128. std::map <std::string, std::string> queryParams;
  129. for (const auto &p : params) {
  130. if (!p.second.empty())
  131. queryParams[p.first] = p.second;
  132. }
  133. if (!queryParams.empty()) {
  134. std::stringstream queryString;
  135. for (const auto &p : queryParams)
  136. {
  137. if (p.second.empty())
  138. queryString << "&" << p.first;
  139. else
  140. queryString << "&" << p.first << "=" << p.second;
  141. }
  142. url.setQuery(queryString.str().substr(1));
  143. }
  144. HttpRequest request(url);
  145. request.setMethod(method);
  146. request.setHeader("Accept", "application/json");
  147. if (msg.hasContent()) {
  148. std::stringstream ss;
  149. ss << msg.contentSize();
  150. request.setHeader("Content-Length", ss.str());
  151. request.setHeader("Content-Type", "application/octet-stream");
  152. request.setHeader("Content-MD5", ComputeContentMD5(msg.content(), msg.contentSize()));
  153. }
  154. std::time_t t = std::time(nullptr);
  155. std::stringstream date;
  156. #if defined(__GNUG__) && __GNUC__ < 5
  157. char tmbuff[26];
  158. strftime(tmbuff, 26, "%a, %d %b %Y %T", std::gmtime(&t));
  159. date << tmbuff << " GMT";
  160. #else
  161. date << std::put_time(std::gmtime(&t), "%a, %d %b %Y %T GMT");
  162. #endif
  163. request.setHeader("Date", date.str());
  164. request.setHeader("Host", url.host());
  165. request.setHeader("x-sdk-client", std::string("CPP/").append(ALIBABACLOUD_VERSION_STR));
  166. request.setHeader("x-acs-region-id", configuration().regionId());
  167. if (!credentials.sessionToken().empty())
  168. request.setHeader("x-acs-security-token", credentials.sessionToken());
  169. request.setHeader("x-acs-signature-method", signer_->name());
  170. request.setHeader("x-acs-signature-nonce", GenerateUuid());
  171. request.setHeader("x-acs-signature-version", signer_->version());
  172. request.setHeader("x-acs-version", msg.version());
  173. std::stringstream plaintext;
  174. plaintext << HttpMethodToString(method) << "\n"
  175. << request.header("Accept") << "\n"
  176. << request.header("Content-MD5") << "\n"
  177. << request.header("Content-Type") << "\n"
  178. << request.header("Date") << "\n"
  179. << canonicalizedHeaders(request.headers());
  180. if (!url.hasQuery())
  181. plaintext << url.path();
  182. else
  183. plaintext << url.path() << "?" << url.query();
  184. std::stringstream sign;
  185. sign << "acs "
  186. << credentials.accessKeyId()
  187. << ":"
  188. << signer_->generate(plaintext.str(), credentials.accessKeySecret());
  189. request.setHeader("Authorization", sign.str());
  190. return request;
  191. }
  192. std::string CommonClient::canonicalizedQuery(const std::map<std::string, std::string>& params) const
  193. {
  194. if (params.empty())
  195. return std::string();
  196. std::stringstream ss;
  197. for (const auto &p : params)
  198. {
  199. std::string key = UrlEncode(p.first);
  200. StringReplace(key, "+", "%20");
  201. StringReplace(key, "*", "%2A");
  202. StringReplace(key, "%7E", "~");
  203. std::string value = UrlEncode(p.second);
  204. StringReplace(value, "+", "%20");
  205. StringReplace(value, "*", "%2A");
  206. StringReplace(value, "%7E", "~");
  207. ss << "&" << key << "=" << value;
  208. }
  209. return ss.str().substr(1);
  210. }
  211. HttpRequest CommonClient::buildRpcHttpRequest(const std::string & endpoint, const CommonRequest &msg, HttpRequest::Method method) const
  212. {
  213. const Credentials credentials = credentialsProvider_->getCredentials();
  214. Url url;
  215. url.setScheme("https");
  216. url.setHost(endpoint);
  217. url.setPath(msg.resourcePath());
  218. auto params = msg.queryParameters();
  219. std::map <std::string, std::string> queryParams;
  220. for (const auto &p : params) {
  221. if (!p.second.empty())
  222. queryParams[p.first] = p.second;
  223. }
  224. queryParams["AccessKeyId"] = credentials.accessKeyId();
  225. queryParams["Format"] = "JSON";
  226. queryParams["RegionId"] = configuration().regionId();
  227. queryParams["SecurityToken"] = credentials.sessionToken();
  228. queryParams["SignatureMethod"] = signer_->name();
  229. queryParams["SignatureNonce"] = GenerateUuid();
  230. queryParams["SignatureVersion"] = signer_->version();
  231. std::time_t t = std::time(nullptr);
  232. std::stringstream ss;
  233. #if defined(__GNUG__) && __GNUC__ < 5
  234. char tmbuff[26];
  235. strftime(tmbuff, 26, "%FT%TZ", std::gmtime(&t));
  236. ss << tmbuff;
  237. #else
  238. ss << std::put_time(std::gmtime(&t), "%FT%TZ");
  239. #endif
  240. queryParams["Timestamp"] = ss.str();
  241. queryParams["Version"] = msg.version();
  242. std::stringstream plaintext;
  243. plaintext << HttpMethodToString(method)
  244. << "&"
  245. << UrlEncode(url.path())
  246. << "&"
  247. << UrlEncode(canonicalizedQuery(queryParams));
  248. queryParams["Signature"] = signer_->generate(plaintext.str(), credentials.accessKeySecret() + "&");
  249. std::stringstream queryString;
  250. for (const auto &p : queryParams)
  251. queryString << "&" << p.first << "=" << UrlEncode(p.second);
  252. url.setQuery(queryString.str().substr(1));
  253. HttpRequest request(url);
  254. request.setMethod(method);
  255. request.setHeader("Host", url.host());
  256. request.setHeader("x-sdk-client", std::string("CPP/").append(ALIBABACLOUD_VERSION_STR));
  257. return request;
  258. }