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
17 #include <alibabacloud/oss/client/RetryStrategy.h>
18 #include <alibabacloud/oss/utils/Executor.h>
19 #include <external/tinyxml2/tinyxml2.h>
20 #include "Client.h"
21 #include "../http/CurlHttpClient.h"
22 #include "utils/Utils.h"
23 #include "../auth/Signer.h"
24 #include <sstream>
25 #include <ctime>
26 #ifdef USE_AOS_TIME_POSIX_API
27 #include <posix/timer.h>
28 #endif
29
30 using namespace AlibabaCloud::OSS;
31 using namespace tinyxml2;
32
Client(const std::string & servicename,const ClientConfiguration & configuration)33 Client::Client(const std::string & servicename, const ClientConfiguration &configuration) :
34 requestDateOffset_(0),
35 serviceName_(servicename),
36 configuration_(configuration),
37 httpClient_(configuration.httpClient? configuration.httpClient:std::make_shared<CurlHttpClient>(configuration))
38 {
39 }
40
~Client()41 Client::~Client()
42 {
43 }
44
configuration() const45 const ClientConfiguration& Client::configuration()const
46 {
47 return configuration_;
48 }
49
serviceName() const50 std::string Client::serviceName()const
51 {
52 return serviceName_;
53 }
54
AttemptRequest(const std::string & endpoint,const ServiceRequest & request,Http::Method method) const55 Client::ClientOutcome Client::AttemptRequest(const std::string & endpoint, const ServiceRequest & request, Http::Method method) const
56 {
57 for (int retry =0; ;retry++) {
58 auto outcome = AttemptOnceRequest(endpoint, request, method);
59 if (outcome.isSuccess()) {
60 return outcome;
61 }
62 else if (!httpClient_->isEnable()) {
63 return outcome;
64 }
65 else {
66 if (configuration_.enableDateSkewAdjustment &&
67 outcome.error().Status() == 403 &&
68 outcome.error().Message().find("RequestTimeTooSkewed")) {
69 auto serverTimeStr = analyzeServerTime(outcome.error().Message());
70 auto serverTime = UtcToUnixTime(serverTimeStr);
71 if (serverTime != -1) {
72 #ifdef USE_AOS_TIME_POSIX_API
73 struct timespec currentTime;
74 time_t localTime;
75 clock_gettime(CLOCK_REALTIME, ¤tTime);
76 localTime = currentTime.tv_nsec/1000000000 + currentTime.tv_sec;
77 #else
78 std::time_t localTime = std::time(nullptr);
79 #endif
80 setRequestDateOffset(serverTime - localTime);
81 }
82 }
83 RetryStrategy *retryStrategy = configuration().retryStrategy.get();
84 if (retryStrategy == nullptr || !retryStrategy->shouldRetry(outcome.error(), retry)) {
85 return outcome;
86 }
87 long sleepTmeMs = retryStrategy->calcDelayTimeMs(outcome.error(), retry);
88 httpClient_->waitForRetry(sleepTmeMs);
89 }
90 }
91 }
92
AttemptOnceRequest(const std::string & endpoint,const ServiceRequest & request,Http::Method method) const93 Client::ClientOutcome Client::AttemptOnceRequest(const std::string & endpoint, const ServiceRequest & request, Http::Method method) const
94 {
95 if (!httpClient_->isEnable()) {
96 return ClientOutcome(Error("ClientError:100002", "Disable all requests by upper."));
97 }
98
99 auto r = buildHttpRequest(endpoint, request, method);
100 auto response = httpClient_->makeRequest(r);
101
102 if(hasResponseError(response)) {
103 return ClientOutcome(buildError(response));
104 } else {
105 return ClientOutcome(response);
106 }
107 }
108
analyzeServerTime(const std::string & message) const109 std::string Client::analyzeServerTime(const std::string &message) const
110 {
111 XMLDocument doc;
112 if (doc.Parse(message.c_str(), message.size()) == XML_SUCCESS) {
113 XMLElement* root = doc.RootElement();
114 if (root && !std::strncmp("Error", root->Name(), 5)) {
115 XMLElement *node;
116 node = root->FirstChildElement("ServerTime");
117 return (node ? node->GetText() : "");
118 }
119 }
120 return "";
121 }
122
buildError(const std::shared_ptr<HttpResponse> & response) const123 Error Client::buildError(const std::shared_ptr<HttpResponse> &response) const
124 {
125 Error error;
126 if (response == nullptr) {
127 error.setCode("NullptrError");
128 error.setMessage("HttpResponse is nullptr, should not be here.");
129 return error;
130 }
131
132 long responseCode = response->statusCode();
133 error.setStatus(responseCode);
134 std::stringstream ss;
135 if ((responseCode == 203) ||
136 (responseCode > 299 && responseCode < 600)) {
137 ss << "ServerError:" << responseCode;
138 error.setCode(ss.str());
139 if (response->Body() != nullptr) {
140 std::istreambuf_iterator<char> isb(*response->Body().get()), end;
141 error.setMessage(std::string(isb, end));
142 }
143 } else {
144 ss << "ClientError:" << responseCode;
145 error.setCode(ss.str());
146 error.setMessage(response->statusMsg());
147 }
148 error.setHeaders(response->Headers());
149 return error;
150 }
151
hasResponseError(const std::shared_ptr<HttpResponse> & response) const152 bool Client::hasResponseError(const std::shared_ptr<HttpResponse>&response)const
153 {
154 if (!response) {
155 return true;
156 }
157 return (response->statusCode()/100 != 2);
158 }
159
disableRequest()160 void Client::disableRequest()
161 {
162 httpClient_->disable();
163 }
164
enableRequest()165 void Client::enableRequest()
166 {
167 httpClient_->enable();
168 }
169
isEnableRequest() const170 bool Client::isEnableRequest() const
171 {
172 return httpClient_->isEnable();
173 }
174
setRequestDateOffset(uint64_t offset) const175 void Client::setRequestDateOffset(uint64_t offset) const
176 {
177 requestDateOffset_ = offset;
178 }
179
getRequestDateOffset() const180 uint64_t Client::getRequestDateOffset() const
181 {
182 return requestDateOffset_;
183 }