http.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // MinIO C++ Library for Amazon S3 Compatible Cloud Storage
  2. // Copyright 2022 MinIO, Inc.
  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. #ifndef _MINIO_HTTP_H
  16. #define _MINIO_HTTP_H
  17. #ifdef _MSC_VER
  18. # include <winsock2.h>
  19. # include <ws2tcpip.h>
  20. #else
  21. # include <arpa/inet.h>
  22. #endif
  23. #include "utils.h"
  24. #include <functional>
  25. namespace curlpp {
  26. class Easy;
  27. class Multi;
  28. }
  29. namespace minio {
  30. namespace http {
  31. enum class Method { kGet, kHead, kPost, kPut, kDelete };
  32. // MethodToString converts http Method enum to string.
  33. constexpr const char* MethodToString(Method& method) throw() {
  34. switch (method) {
  35. case Method::kGet:
  36. return "GET";
  37. case Method::kHead:
  38. return "HEAD";
  39. case Method::kPost:
  40. return "POST";
  41. case Method::kPut:
  42. return "PUT";
  43. case Method::kDelete:
  44. return "DELETE";
  45. default: {
  46. std::cerr << "ABORT: Unimplemented HTTP method. This should not happen."
  47. << std::endl;
  48. std::terminate();
  49. }
  50. }
  51. return NULL;
  52. }
  53. /**
  54. * Url represents HTTP URL and it's components.
  55. */
  56. struct Url {
  57. bool https;
  58. std::string host;
  59. unsigned int port = 0;
  60. std::string path;
  61. std::string query_string;
  62. operator bool() const { return !host.empty(); }
  63. std::string String() {
  64. if (host.empty()) return "";
  65. std::string url = (https ? "https://" : "http://") + host;
  66. if (port) url += ":" + std::to_string(port);
  67. if (!path.empty()) {
  68. if (path.front() != '/') url += '/';
  69. url += path;
  70. }
  71. if (!query_string.empty()) url += "?" + query_string;
  72. return url;
  73. }
  74. std::string HostHeaderValue() {
  75. if (!port) return host;
  76. return host + ":" + std::to_string(port);
  77. }
  78. static Url Parse(std::string value) {
  79. std::string scheme;
  80. size_t pos = value.find("://");
  81. if (pos != std::string::npos) {
  82. scheme = value.substr(0, pos);
  83. value.erase(0, pos + 3);
  84. }
  85. scheme = utils::ToLower(scheme);
  86. if (!scheme.empty() && scheme != "http" && scheme != "https") return Url{};
  87. bool https = (scheme.empty() || scheme == "https");
  88. std::string host;
  89. std::string path;
  90. std::string query_string;
  91. pos = value.find("/");
  92. if (pos != std::string::npos) {
  93. host = value.substr(0, pos);
  94. value.erase(0, pos + 1);
  95. pos = value.find("?");
  96. if (pos != std::string::npos) {
  97. path = value.substr(0, pos);
  98. value.erase(0, pos + 1);
  99. query_string = value;
  100. } else {
  101. path = value;
  102. }
  103. } else {
  104. pos = value.find("?");
  105. if (pos != std::string::npos) {
  106. host = value.substr(0, pos);
  107. value.erase(0, pos + 1);
  108. query_string = value;
  109. } else {
  110. host = value;
  111. }
  112. }
  113. if (host.empty()) return Url{};
  114. unsigned int port = 0;
  115. struct sockaddr_in6 dst;
  116. if (inet_pton(AF_INET6, host.c_str(), &(dst.sin6_addr)) <= 0) {
  117. if (host.front() != '[' || host.back() != ']') {
  118. std::stringstream ss(host);
  119. std::string portstr;
  120. while (std::getline(ss, portstr, ':')) {
  121. }
  122. if (!portstr.empty()) {
  123. try {
  124. port = std::stoi(portstr);
  125. host = host.substr(0, host.rfind(":" + portstr));
  126. } catch (std::invalid_argument) {
  127. port = 0;
  128. }
  129. }
  130. }
  131. } else {
  132. host = "[" + host + "]";
  133. }
  134. if (!https && port == 80) port = 0;
  135. if (https && port == 443) port = 0;
  136. return Url{https, host, port, path, query_string};
  137. }
  138. }; // struct Url
  139. struct DataFunctionArgs;
  140. using DataFunction = std::function<bool(DataFunctionArgs)>;
  141. struct ProgressFunctionArgs;
  142. using ProgressFunction = std::function<void(ProgressFunctionArgs)>;
  143. struct Response;
  144. struct DataFunctionArgs {
  145. curlpp::Easy* handle = NULL;
  146. Response* response = NULL;
  147. std::string datachunk;
  148. void* userdata = NULL;
  149. }; // struct DataFunctionArgs
  150. struct ProgressFunctionArgs {
  151. double download_total_bytes = 0;
  152. double downloaded_bytes = 0;
  153. double upload_total_bytes = 0;
  154. double uploaded_bytes = 0;
  155. double download_speed = 0;
  156. double upload_speed = 0;
  157. void* userdata = NULL;
  158. }; // struct ProgressFunctionArgs
  159. struct Request {
  160. Method method;
  161. http::Url url;
  162. utils::Multimap headers;
  163. std::string_view body = "";
  164. DataFunction datafunc = NULL;
  165. void* userdata = NULL;
  166. ProgressFunction progressfunc = NULL;
  167. void* progress_userdata = NULL;
  168. bool debug = false;
  169. bool ignore_cert_check = false;
  170. std::string ssl_cert_file;
  171. std::string key_file;
  172. std::string cert_file;
  173. Request(Method method, Url url);
  174. Response Execute();
  175. operator bool() const {
  176. if (method < Method::kGet || method > Method::kDelete) return false;
  177. return url;
  178. }
  179. private:
  180. Response execute();
  181. }; // struct Request
  182. struct Response {
  183. std::string error;
  184. DataFunction datafunc = NULL;
  185. void* userdata = NULL;
  186. int status_code = 0;
  187. utils::Multimap headers;
  188. std::string body;
  189. size_t ResponseCallback(curlpp::Multi* requests, curlpp::Easy* request,
  190. char* buffer, size_t size, size_t length);
  191. operator bool() const {
  192. return error.empty() && status_code >= 200 && status_code <= 299;
  193. }
  194. error::Error Error() {
  195. if (!error.empty()) return error::Error(error);
  196. if (status_code && (status_code < 200 || status_code > 299)) {
  197. return error::Error("failed with HTTP status code " +
  198. std::to_string(status_code));
  199. }
  200. return error::SUCCESS;
  201. }
  202. private:
  203. std::string response_;
  204. bool continue100_ = false;
  205. bool status_code_read_ = false;
  206. bool headers_read_ = false;
  207. error::Error ReadStatusCode();
  208. error::Error ReadHeaders();
  209. }; // struct Response
  210. } // namespace http
  211. } // namespace minio
  212. #endif // #ifndef _MINIO_HTTP_H