linux版本中间件

utils.h 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /**
  2. * Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  5. * the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  10. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  11. * specific language governing permissions and limitations under the License.
  12. *
  13. * @author baidu aip
  14. */
  15. #ifndef __AIP_UTILS_H__
  16. #define __AIP_UTILS_H__
  17. #include <string>
  18. #include <fstream>
  19. #include <ctype.h>
  20. #include <openssl/evp.h>
  21. #include <openssl/hmac.h>
  22. #include <algorithm>
  23. #include <openssl/md5.h>
  24. const int __BCE_VERSION__ = 1;
  25. const int __BCE_EXPIRE__ = 1800;
  26. namespace aip {
  27. template<class CharT, class Traits, class Allocator>
  28. std::basic_istream<CharT, Traits>& getall(std::basic_istream<CharT, Traits>& input,
  29. std::basic_string<CharT, Traits, Allocator>& str) {
  30. std::ostringstream oss;
  31. oss << input.rdbuf();
  32. str.assign(oss.str());
  33. return input;
  34. }
  35. inline int get_file_content(const char *filename, std::string* out) {
  36. std::ifstream in(filename, std::ios::in | std::ios::binary);
  37. if (in) {
  38. getall(in, *out);
  39. return 0;
  40. } else {
  41. return -1;
  42. }
  43. }
  44. inline std::string to_upper(std::string src)
  45. {
  46. std::transform(src.begin(), src.end(), src.begin(), toupper);
  47. return src;
  48. }
  49. inline std::string to_lower(std::string src)
  50. {
  51. std::transform(src.begin(), src.end(), src.begin(), tolower);
  52. return src;
  53. }
  54. inline std::string to_hex(unsigned char c, bool lower = false)
  55. {
  56. const std::string hex = "0123456789ABCDEF";
  57. std::stringstream ss;
  58. ss << hex[c >> 4] << hex[c & 0xf];
  59. return lower ? to_lower(ss.str()) : ss.str();
  60. }
  61. inline time_t now()
  62. {
  63. return time(NULL);
  64. }
  65. std::string utc_time(time_t timestamp)
  66. {
  67. struct tm result_tm;
  68. char buffer[32];
  69. #ifdef _WIN32
  70. gmtime_s(&result_tm, &timestamp);
  71. #else
  72. gmtime_r(&timestamp, &result_tm);
  73. #endif
  74. size_t size = strftime(buffer, 32, "%Y-%m-%dT%H:%M:%SZ", &result_tm);
  75. return std::string(buffer, size);
  76. }
  77. void url_parse(
  78. const std::string & url,
  79. std::map<std::string, std::string> & params)
  80. {
  81. int pos = (int)url.find("?");
  82. if (pos != -1)
  83. {
  84. int key_start = pos + 1,
  85. key_len = 0,
  86. val_start = 0;
  87. for (int i = key_start; i <= (int)url.size(); ++i)
  88. {
  89. switch (url[i])
  90. {
  91. case '=':
  92. key_len = i - key_start;
  93. val_start = i + 1;
  94. break;
  95. case '\0':
  96. case '&':
  97. if (key_len != 0)
  98. {
  99. params[url.substr(key_start, key_len)] = url.substr(val_start, i - val_start);
  100. key_start = i + 1;
  101. key_len = 0;
  102. }
  103. break;
  104. default:
  105. break;
  106. }
  107. }
  108. }
  109. }
  110. std::string url_encode(const std::string & input, bool encode_slash=true)
  111. {
  112. std::stringstream ss;
  113. const char *str = input.c_str();
  114. for (uint32_t i = 0; i < input.size(); i++)
  115. {
  116. unsigned char c = str[i];
  117. if (isalnum(c) || c == '_' || c == '-' || c == '~' || c == '.' || (!encode_slash && c == '/'))
  118. {
  119. ss << c;
  120. }
  121. else
  122. {
  123. ss << "%" << to_hex(c);
  124. }
  125. }
  126. return ss.str();
  127. }
  128. std::string canonicalize_params(std::map<std::string, std::string> & params)
  129. {
  130. std::vector<std::string> v;
  131. v.reserve(params.size());
  132. for (auto & it : params) {
  133. v.push_back(url_encode(it.first) + "=" + url_encode(it.second));
  134. }
  135. std::sort(v.begin(), v.end());
  136. std::string result;
  137. for (auto & it : v)
  138. {
  139. result.append((result.empty() ? "" : "&") + it);
  140. }
  141. return result;
  142. }
  143. std::string canonicalize_headers(std::map<std::string, std::string> & headers)
  144. {
  145. std::vector<std::string> v;
  146. v.reserve(headers.size());
  147. for (auto & it : headers) {
  148. v.push_back(url_encode(to_lower(it.first)) + ":" + url_encode(it.second));
  149. }
  150. std::sort(v.begin(), v.end());
  151. std::string result;
  152. for (auto & it : v)
  153. {
  154. result.append((result.empty() ? "" : "\n") + it);
  155. }
  156. return result;
  157. }
  158. std::string get_headers_keys(std::map<std::string, std::string> & headers)
  159. {
  160. std::vector<std::string> v;
  161. v.reserve(headers.size());
  162. for (auto & it : headers) {
  163. v.push_back(to_lower(it.first));
  164. }
  165. std::string result;
  166. for (auto & it : v)
  167. {
  168. result.append((result.empty() ? "" : ";") + it);
  169. }
  170. return result;
  171. }
  172. std::string get_host(const std::string & url)
  173. {
  174. int pos = (int)url.find("://") + 3;
  175. return url.substr(
  176. pos,
  177. url.find('/', pos) - pos
  178. );
  179. }
  180. std::string get_path(const std::string & url)
  181. {
  182. int path_start = (int)url.find('/', url.find("://") + 3);
  183. int path_end = (int)url.find('?');
  184. path_end = path_end == -1 ? (int)url.size() : path_end;
  185. return url.substr(path_start, path_end - path_start);
  186. }
  187. std::string hmac_sha256(
  188. const std::string & src,
  189. const std::string & sk)
  190. {
  191. const EVP_MD *evp_md = EVP_sha256();
  192. unsigned char md[EVP_MAX_MD_SIZE];
  193. unsigned int md_len = 0;
  194. if (HMAC(evp_md,
  195. reinterpret_cast<const unsigned char *>(sk.data()), (int)sk.size(),
  196. reinterpret_cast<const unsigned char *>(src.data()), src.size(),
  197. md, &md_len) == NULL)
  198. {
  199. return "";
  200. }
  201. std::stringstream ss;
  202. for (int i = 0; i < (int)md_len; ++i)
  203. {
  204. ss << to_hex(md[i], true);
  205. }
  206. return ss.str();
  207. }
  208. void sign(
  209. std::string method,
  210. std::string & url,
  211. std::map<std::string, std::string> & params,
  212. std::map<std::string, std::string> & headers,
  213. std::string & ak,
  214. std::string & sk)
  215. {
  216. url_parse(url, params);
  217. headers["Host"] = get_host(url);
  218. std::string timestamp = utc_time(now());
  219. headers["x-bce-date"] = timestamp;
  220. std::stringstream ss;
  221. ss << "bce-auth-v" << __BCE_VERSION__ << "/" << ak << "/"
  222. << timestamp << "/" << __BCE_EXPIRE__;
  223. std::string val = ss.str();
  224. std::string sign_key = hmac_sha256(val, sk);
  225. ss.str("");
  226. ss << to_upper(method) << '\n' << url_encode(get_path(url), false)
  227. << '\n' << canonicalize_params(params)
  228. << '\n' << canonicalize_headers(headers);
  229. std::string signature = hmac_sha256(ss.str(), sign_key);
  230. ss.str("");
  231. ss << "bce-auth-v" << __BCE_VERSION__ << "/" << ak << "/"
  232. << timestamp << "/" << __BCE_EXPIRE__ << "/"
  233. << get_headers_keys(headers) << "/" << signature;
  234. headers["authorization"] = ss.str();
  235. }
  236. }
  237. #endif