1 /*
2 * Copyright 1999-2019 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
17 #include <algorithm>
18 #include <alibabacloud/core/AlibabaCloud.h>
19 #include <alibabacloud/core/CommonClient.h>
20 #include <alibabacloud/core/SimpleCredentialsProvider.h>
21 #include <alibabacloud/core/location/LocationClient.h>
22 #include <ctime>
23 #include <iomanip>
24 #include <sstream>
25 #ifdef USE_AOS_TIME_POSIX_API
26 #include <posix/timer.h>
27 #endif
28 #include <alibabacloud/core/Utils.h>
29
30 namespace AlibabaCloud {
31
32 namespace {
33 const std::string SERVICE_NAME = "Common";
34 }
35
CommonClient(const Credentials & credentials,const ClientConfiguration & configuration)36 CommonClient::CommonClient(const Credentials &credentials,
37 const ClientConfiguration &configuration)
38 : CoreClient(SERVICE_NAME, configuration),
39 credentialsProvider_(
40 std::make_shared<SimpleCredentialsProvider>(credentials)),
41 signer_(std::make_shared<HmacSha1Signer>()) {}
42
CommonClient(const std::shared_ptr<CredentialsProvider> & credentialsProvider,const ClientConfiguration & configuration)43 CommonClient::CommonClient(
44 const std::shared_ptr<CredentialsProvider> &credentialsProvider,
45 const ClientConfiguration &configuration)
46 : CoreClient(SERVICE_NAME, configuration),
47 credentialsProvider_(credentialsProvider),
48 signer_(std::make_shared<HmacSha1Signer>()) {}
49
CommonClient(const std::string & accessKeyId,const std::string & accessKeySecret,const ClientConfiguration & configuration)50 CommonClient::CommonClient(const std::string &accessKeyId,
51 const std::string &accessKeySecret,
52 const ClientConfiguration &configuration)
53 : CoreClient(SERVICE_NAME, configuration),
54 credentialsProvider_(std::make_shared<SimpleCredentialsProvider>(
55 accessKeyId, accessKeySecret)),
56 signer_(std::make_shared<HmacSha1Signer>()) {}
57
~CommonClient()58 CommonClient::~CommonClient() {}
59
60 CommonClient::JsonOutcome
makeRequest(const std::string & endpoint,const CommonRequest & msg,HttpRequest::Method method) const61 CommonClient::makeRequest(const std::string &endpoint, const CommonRequest &msg,
62 HttpRequest::Method method) const {
63 auto outcome = AttemptRequest(endpoint, msg, method);
64 if (outcome.isSuccess())
65 return JsonOutcome(
66 std::string(outcome.result().body(), outcome.result().bodySize()));
67 else
68 return JsonOutcome(outcome.error());
69 }
70
71 CommonClient::CommonResponseOutcome
commonResponse(const CommonRequest & request) const72 CommonClient::commonResponse(const CommonRequest &request) const {
73 auto outcome = makeRequest(request.domain(), request, request.httpMethod());
74 if (outcome.isSuccess())
75 return CommonResponseOutcome(CommonResponse(outcome.result()));
76 else
77 return CommonResponseOutcome(Error(outcome.error()));
78 }
79
commonResponseAsync(const CommonRequest & request,const CommonResponseAsyncHandler & handler,const std::shared_ptr<const AsyncCallerContext> & context) const80 void CommonClient::commonResponseAsync(
81 const CommonRequest &request, const CommonResponseAsyncHandler &handler,
82 const std::shared_ptr<const AsyncCallerContext> &context) const {
83 auto fn = [this, request, handler, context]() {
84 handler(this, request, commonResponse(request), context);
85 };
86
87 asyncExecute(new Runnable(fn));
88 }
89
90 CommonClient::CommonResponseOutcomeCallable
commonResponseCallable(const CommonRequest & request) const91 CommonClient::commonResponseCallable(const CommonRequest &request) const {
92 auto task = std::make_shared<std::packaged_task<CommonResponseOutcome()>>(
93 [this, request]() { return this->commonResponse(request); });
94
95 asyncExecute(new Runnable([task]() { (*task)(); }));
96 return task->get_future();
97 }
98
buildHttpRequest(const std::string & endpoint,const ServiceRequest & msg,HttpRequest::Method method) const99 HttpRequest CommonClient::buildHttpRequest(const std::string &endpoint,
100 const ServiceRequest &msg,
101 HttpRequest::Method method) const {
102 return buildHttpRequest(endpoint, static_cast<const CommonRequest &>(msg), //lk change dynamic_cast to static_cast
103 method);
104 }
105
buildHttpRequest(const std::string & endpoint,const CommonRequest & msg,HttpRequest::Method method) const106 HttpRequest CommonClient::buildHttpRequest(const std::string &endpoint,
107 const CommonRequest &msg,
108 HttpRequest::Method method) const {
109 if (msg.requestPattern() == CommonRequest::RpcPattern)
110 return buildRpcHttpRequest(endpoint, msg, method);
111 else
112 return buildRoaHttpRequest(endpoint, msg, method);
113 }
114
115 HttpRequest
buildRoaHttpRequest(const std::string & endpoint,const CommonRequest & msg,HttpRequest::Method method) const116 CommonClient::buildRoaHttpRequest(const std::string &endpoint,
117 const CommonRequest &msg,
118 HttpRequest::Method method) const {
119 const Credentials credentials = credentialsProvider_->getCredentials();
120
121 Url url;
122 if (msg.scheme().empty()) {
123 url.setScheme("https");
124 } else {
125 url.setScheme(msg.scheme());
126 }
127 url.setHost(endpoint);
128 url.setPath(msg.resourcePath());
129
130 auto params = msg.headerParameters();
131 std::map<std::string, std::string> queryParams;
132 for (const auto &p : params) {
133 if (!p.second.empty())
134 queryParams[p.first] = p.second;
135 }
136
137 if (!queryParams.empty()) {
138 std::stringstream queryString;
139 for (const auto &p : queryParams) {
140 if (p.second.empty())
141 queryString << "&" << p.first;
142 else
143 queryString << "&" << p.first << "=" << p.second;
144 }
145 url.setQuery(queryString.str().substr(1));
146 }
147
148 HttpRequest request(url);
149 request.setMethod(method);
150
151 if (msg.connectTimeout() != kInvalidTimeout) {
152 request.setConnectTimeout(msg.connectTimeout());
153 } else {
154 request.setConnectTimeout(configuration().connectTimeout());
155 }
156
157 if (msg.readTimeout() != kInvalidTimeout) {
158 request.setReadTimeout(msg.readTimeout());
159 } else {
160 request.setReadTimeout(configuration().readTimeout());
161 }
162
163 if (msg.headerParameter("Accept").empty()) {
164 request.setHeader("Accept", "application/json");
165 } else {
166 request.setHeader("Accept", msg.headerParameter("Accept"));
167 }
168
169 std::stringstream ss;
170 ss << msg.contentSize();
171 request.setHeader("Content-Length", ss.str());
172 if (msg.headerParameter("Content-Type").empty()) {
173 request.setHeader("Content-Type", "application/octet-stream");
174 } else {
175 request.setHeader("Content-Type", msg.headerParameter("Content-Type"));
176 }
177 request.setHeader("Content-MD5",
178 ComputeContentMD5(msg.content(), msg.contentSize()));
179 request.setBody(msg.content(), msg.contentSize());
180
181 #ifdef USE_AOS_TIME_POSIX_API
182 struct timespec currentTime;
183 time_t t;
184 clock_gettime(CLOCK_REALTIME, ¤tTime);
185 t = currentTime.tv_nsec/1000000000 + currentTime.tv_sec;
186 #else
187 std::time_t t = std::time(nullptr);
188 #endif
189 std::stringstream date;
190 #if defined(__GNUG__) && __GNUC__ < 5
191 char tmbuff[26];
192 strftime(tmbuff, 26, "%a, %d %b %Y %T", std::gmtime(&t));
193 date << tmbuff << " GMT";
194 #else
195 date << std::put_time(std::gmtime(&t), "%a, %d %b %Y %T GMT");
196 #endif
197 request.setHeader("Date", date.str());
198 request.setHeader("Host", url.host());
199 request.setHeader("x-sdk-client",
200 std::string("CPP/").append(ALIBABACLOUD_VERSION_STR));
201 request.setHeader("x-acs-region-id", configuration().regionId());
202 if (!credentials.sessionToken().empty())
203 request.setHeader("x-acs-security-token", credentials.sessionToken());
204 request.setHeader("x-acs-signature-method", signer_->name());
205 request.setHeader("x-acs-signature-nonce", GenerateUuid());
206 request.setHeader("x-acs-signature-version", signer_->version());
207 request.setHeader("x-acs-version", msg.version());
208
209 std::stringstream plaintext;
210 plaintext << HttpMethodToString(method) << "\n"
211 << request.header("Accept") << "\n"
212 << request.header("Content-MD5") << "\n"
213 << request.header("Content-Type") << "\n"
214 << request.header("Date") << "\n"
215 << canonicalizedHeaders(request.headers());
216 if (!url.hasQuery())
217 plaintext << url.path();
218 else
219 plaintext << url.path() << "?" << url.query();
220
221 std::stringstream sign;
222 sign << "acs " << credentials.accessKeyId() << ":"
223 << signer_->generate(plaintext.str(), credentials.accessKeySecret());
224 request.setHeader("Authorization", sign.str());
225 return request;
226 }
227
228 HttpRequest
buildRpcHttpRequest(const std::string & endpoint,const CommonRequest & msg,HttpRequest::Method method) const229 CommonClient::buildRpcHttpRequest(const std::string &endpoint,
230 const CommonRequest &msg,
231 HttpRequest::Method method) const {
232 const Credentials credentials = credentialsProvider_->getCredentials();
233
234 Url url;
235 if (msg.scheme().empty()) {
236 url.setScheme("https");
237 } else {
238 url.setScheme(msg.scheme());
239 }
240 url.setHost(endpoint);
241 url.setPath(msg.resourcePath());
242
243 auto params = msg.queryParameters();
244 std::map<std::string, std::string> queryParams;
245 for (const auto &p : params) {
246 if (!p.second.empty())
247 queryParams[p.first] = p.second;
248 }
249
250 queryParams["AccessKeyId"] = credentials.accessKeyId();
251 queryParams["Format"] = "JSON";
252 queryParams["RegionId"] = configuration().regionId();
253 queryParams["SecurityToken"] = credentials.sessionToken();
254 queryParams["SignatureMethod"] = signer_->name();
255 queryParams["SignatureNonce"] = GenerateUuid();
256 queryParams["SignatureVersion"] = signer_->version();
257 #ifdef USE_AOS_TIME_POSIX_API
258 struct timespec currentTime;
259 time_t t;
260 clock_gettime(CLOCK_REALTIME, ¤tTime);
261 t = currentTime.tv_nsec/1000000000 + currentTime.tv_sec;
262 #else
263 std::time_t t = std::time(nullptr);
264 #endif
265 std::stringstream ss;
266 #if defined(__GNUG__) && __GNUC__ < 5
267 char tmbuff[26];
268 strftime(tmbuff, 26, "%FT%TZ", std::gmtime(&t));
269 ss << tmbuff;
270 #else
271 ss << std::put_time(std::gmtime(&t), "%FT%TZ");
272 #endif
273 queryParams["Timestamp"] = ss.str();
274 queryParams["Version"] = msg.version();
275
276 std::string bodyParamString;
277 auto signParams = queryParams;
278 auto bodyParams = msg.bodyParameters();
279 for (const auto &p : bodyParams) {
280 bodyParamString += "&";
281 bodyParamString += (p.first + "=" + UrlEncode(p.second));
282 signParams[p.first] = p.second;
283 }
284
285 std::stringstream plaintext;
286 plaintext << HttpMethodToString(method) << "&" << UrlEncode(url.path()) << "&"
287 << UrlEncode(canonicalizedQuery(signParams));
288 queryParams["Signature"] =
289 signer_->generate(plaintext.str(), credentials.accessKeySecret() + "&");
290
291 std::stringstream queryString;
292 for (const auto &p : queryParams)
293 queryString << "&" << p.first << "=" << UrlEncode(p.second);
294 url.setQuery(queryString.str().substr(1));
295
296 HttpRequest request(url);
297 if (msg.connectTimeout() != kInvalidTimeout) {
298 request.setConnectTimeout(msg.connectTimeout());
299 } else {
300 request.setConnectTimeout(configuration().connectTimeout());
301 }
302
303 if (msg.readTimeout() != kInvalidTimeout) {
304 request.setReadTimeout(msg.readTimeout());
305 } else {
306 request.setReadTimeout(configuration().readTimeout());
307 }
308
309 request.setMethod(method);
310 request.setHeader("Host", url.host());
311 request.setHeader("x-sdk-client",
312 std::string("CPP/").append(ALIBABACLOUD_VERSION_STR));
313
314 if (!bodyParamString.empty()) {
315 request.setBody(bodyParamString.c_str() + 1, bodyParamString.size() - 1);
316 }
317 return request;
318 }
319
320 } // namespace AlibabaCloud
321