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/Utils.h>
19 #include <sstream>
20 #include <stdlib.h>
21 
22 #ifdef _WIN32
23 #include <Windows.h>
24 #elif defined(USE_CRYPTO_MBEDTLS)
25 #include "mbedtls/md.h"
26 #include "mbedtls/compat-1.3.h"
27 #include "mbedtls/sha1.h"
28 #include "mbedtls/base64.h"
29 #include "mbedtls/md5.h"
30 #else
31 #include <openssl/hmac.h>
32 #include <openssl/md5.h>
33 #include <uuid/uuid.h>
34 #endif
35 #include <curl/curl.h>
36 #include <json/json.h>
37 #include <time.h>
38 
GenerateUuid()39 std::string AlibabaCloud::GenerateUuid() {
40 #ifdef _WIN32
41   char *data;
42   UUID uuidhandle;
43   UuidCreate(&uuidhandle);
44   UuidToString(&uuidhandle, reinterpret_cast<RPC_CSTR *>(&data));
45   std::string uuid(data);
46   RpcStringFree(reinterpret_cast<RPC_CSTR *>(&data));
47   return uuid;
48 #else
49 #if 0
50   uuid_t uu;
51   uuid_generate(uu);
52   char buf[36];
53   uuid_unparse(uu, buf);
54   return buf;
55 #else
56   char buf[36];
57   unsigned int seed = (unsigned int)aos_now();
58 
59   srand(seed);
60   sprintf(buf,"680c83c1-fa94-4b90-a364-%d",rand());
61   std::string uuid(buf);
62   return uuid;
63 #endif
64 #endif
65 }
66 
UrlEncode(const std::string & src)67 std::string AlibabaCloud::UrlEncode(const std::string &src) {
68   CURL *curl = curl_easy_init();
69   char *output = curl_easy_escape(curl, src.c_str(), src.size());
70   std::string result(output);
71   curl_free(output);
72   curl_easy_cleanup(curl);
73   return result;
74 }
75 
UrlDecode(const std::string & src)76 std::string AlibabaCloud::UrlDecode(const std::string &src) {
77   CURL *curl = curl_easy_init();
78   int outlength = 0;
79   char *output = curl_easy_unescape(curl, src.c_str(), src.size(), &outlength);
80   std::string result(output, outlength);
81   curl_free(output);
82   curl_easy_cleanup(curl);
83   return result;
84 }
85 
ComputeContentMD5(const char * data,size_t size)86 std::string AlibabaCloud::ComputeContentMD5(const char *data, size_t size) {
87 #ifdef _WIN32
88   HCRYPTPROV hProv = 0;
89   HCRYPTHASH hHash = 0;
90   BYTE pbHash[16];
91   DWORD dwDataLen = 16;
92 
93   CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
94   CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
95   CryptHashData(hHash, (BYTE *)(data), size, 0);
96   CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwDataLen, 0);
97 
98   CryptDestroyHash(hHash);
99   CryptReleaseContext(hProv, 0);
100 
101   DWORD dlen = 0;
102   CryptBinaryToString(pbHash, dwDataLen,
103                       CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &dlen);
104   char *dest = new char[dlen];
105   CryptBinaryToString(pbHash, dwDataLen,
106                       CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, dest, &dlen);
107   std::string ret = std::string(dest, dlen);
108   delete dest;
109   return ret;
110 
111 #elif defined(USE_CRYPTO_MBEDTLS)
112   unsigned char md_data[16];
113   unsigned int mdLen = 16;
114   mbedtls_md5_context ctx;
115 	unsigned int olen = 0;
116 
117 	mbedtls_md5_ret((const unsigned char*)data, size, md_data);
118 
119   char encodedData[100];
120 
121   mbedtls_base64_encode((unsigned char*)encodedData, sizeof(encodedData), &olen, md_data, mdLen);
122 
123   return encodedData;
124 #else
125   unsigned char md[MD5_DIGEST_LENGTH];
126   MD5(reinterpret_cast<const unsigned char *>(data), size,
127       (unsigned char *)&md);
128 
129   char encodedData[100];
130   EVP_EncodeBlock(reinterpret_cast<unsigned char *>(encodedData), md,
131                   MD5_DIGEST_LENGTH);
132   return encodedData;
133 #endif
134 }
135 
StringReplace(std::string & src,const std::string & s1,const std::string & s2)136 void AlibabaCloud::StringReplace(std::string &src, const std::string &s1,
137                                  const std::string &s2) {
138   std::string::size_type pos = 0;
139   while ((pos = src.find(s1, pos)) != std::string::npos) {
140     src.replace(pos, s1.length(), s2);
141     pos += s2.length();
142   }
143 }
144 
HttpMethodToString(HttpRequest::Method method)145 std::string AlibabaCloud::HttpMethodToString(HttpRequest::Method method) {
146   switch (method) {
147   case HttpRequest::Method::Head:
148     return "HEAD";
149     break;
150   case HttpRequest::Method::Post:
151     return "POST";
152     break;
153   case HttpRequest::Method::Put:
154     return "PUT";
155     break;
156   case HttpRequest::Method::Delete:
157     return "DELETE";
158     break;
159   case HttpRequest::Method::Connect:
160     return "CONNECT";
161     break;
162   case HttpRequest::Method::Options:
163     return "OPTIONS";
164     break;
165   case HttpRequest::Method::Patch:
166     return "PATCH";
167     break;
168   case HttpRequest::Method::Trace:
169     return "TRACE";
170     break;
171   case HttpRequest::Method::Get:
172   default:
173     return "GET";
174     break;
175   }
176 }
177 
canonicalizedQuery(const std::map<std::string,std::string> & params)178 std::string AlibabaCloud::canonicalizedQuery(
179     const std::map<std::string, std::string> &params) {
180   if (params.empty())
181     return std::string();
182 
183   std::stringstream ss;
184   for (const auto &p : params) {
185     std::string key = UrlEncode(p.first);
186     StringReplace(key, "+", "%20");
187     StringReplace(key, "*", "%2A");
188     StringReplace(key, "%7E", "~");
189     std::string value = UrlEncode(p.second);
190     StringReplace(value, "+", "%20");
191     StringReplace(value, "*", "%2A");
192     StringReplace(value, "%7E", "~");
193     ss << "&" << key << "=" << value;
194   }
195   return ss.str().substr(1);
196 }
197 
canonicalizedHeaders(const HttpMessage::HeaderCollection & headers)198 std::string AlibabaCloud::canonicalizedHeaders(
199     const HttpMessage::HeaderCollection &headers) {
200   std::map<std::string, std::string> materials;
201   for (const auto &p : headers) {
202     std::string key = p.first;
203     std::transform(key.begin(), key.end(), key.begin(), ::tolower);
204     if (key.find("x-acs-") != 0)
205       continue;
206 
207     std::string value = p.second;
208     StringReplace(value, "\t", " ");
209     StringReplace(value, "\n", " ");
210     StringReplace(value, "\r", " ");
211     StringReplace(value, "\f", " ");
212     materials[key] = value;
213   }
214 
215   if (materials.empty())
216     return std::string();
217   std::stringstream ss;
218   for (const auto &p : materials)
219     ss << p.first << ":" << p.second << "\n";
220 
221   return ss.str();
222 }
223 
GetEnv(const std::string env)224 std::string AlibabaCloud::GetEnv(const std::string env) {
225 #ifdef _WIN32
226   char *buf = nullptr;
227   size_t sz = 0;
228   if (_dupenv_s(&buf, &sz, env.c_str()) == 0 && buf != nullptr) {
229     std::string var(buf);
230     free(buf);
231     return var;
232   } else {
233     if (buf) {
234       free(buf);
235     }
236     return std::string();
237   }
238 #else
239   char *var = getenv(env.c_str());
240   if (var) {
241     return std::string(var);
242   }
243   return std::string();
244 #endif
245 }
246 
247 std::string
MapToJson(const std::map<std::string,std::string> & maps)248 AlibabaCloud::MapToJson(const std::map<std::string, std::string> &maps) {
249   Json::Value jsonObject;
250   Json::FastWriter writer;
251   for (std::map<std::string, std::string>::const_iterator iter = maps.begin();
252        iter != maps.end(); ++iter) {
253     jsonObject[iter->first] = iter->second;
254   }
255   std::string unformat_str = writer.write(jsonObject);
256   return unformat_str.substr(0, unformat_str.length() - 1);
257 }
258 
259 std::map<std::string, std::string>
JsonToMap(const std::string & json)260 AlibabaCloud::JsonToMap(const std::string &json) {
261   Json::Reader reader;
262   Json::Value value;
263   std::map<std::string, std::string> maps;
264 
265   if (json.length() > 0) {
266     if (reader.parse(json, value)) {
267       Json::Value::Members members = value.getMemberNames();
268       for (Json::Value::Members::iterator it = members.begin();
269            it != members.end(); ++it) {
270         Json::ValueType vt = value[*it].type();
271         switch (vt) {
272         case Json::stringValue: {
273           maps.insert(
274               std::pair<std::string, std::string>(*it, value[*it].asString()));
275           break;
276         }
277         case Json::intValue: {
278           int inttmp = value[*it].asInt();
279           maps.insert(
280               std::pair<std::string, std::string>(*it, std::to_string(inttmp)));
281           break;
282         }
283         case Json::arrayValue: {
284           std::string strid;
285           for (unsigned int i = 0; i < value[*it].size(); i++) {
286             strid += value[*it][i].asString();
287             strid += ",";
288           }
289           if (!strid.empty()) {
290             strid = strid.substr(0, strid.size() - 1);
291           }
292           maps.insert(std::pair<std::string, std::string>(*it, strid));
293           break;
294         }
295         default: {
296           break;
297         }
298         }
299       }
300     }
301   }
302 
303   return maps;
304 }