cmCTestCurl.cxx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2015 Kitware, Inc.
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmCTestCurl.h"
  11. #include "cmCTest.h"
  12. #include "cmSystemTools.h"
  13. cmCTestCurl::cmCTestCurl(cmCTest* ctest)
  14. {
  15. this->CTest = ctest;
  16. this->SetProxyType();
  17. this->UseHttp10 = false;
  18. // In windows, this will init the winsock stuff
  19. ::curl_global_init(CURL_GLOBAL_ALL);
  20. // default is to verify https
  21. this->VerifyPeerOff = false;
  22. this->VerifyHostOff = false;
  23. this->TimeOutSeconds = 0;
  24. this->Curl = curl_easy_init();
  25. }
  26. cmCTestCurl::~cmCTestCurl()
  27. {
  28. ::curl_easy_cleanup(this->Curl);
  29. ::curl_global_cleanup();
  30. }
  31. std::string cmCTestCurl::Escape(std::string const& source)
  32. {
  33. char* data1 = curl_easy_escape(this->Curl, source.c_str(), 0);
  34. std::string ret = data1;
  35. curl_free(data1);
  36. return ret;
  37. }
  38. namespace {
  39. static size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,
  40. void* data)
  41. {
  42. int realsize = (int)(size * nmemb);
  43. std::vector<char>* vec = static_cast<std::vector<char>*>(data);
  44. const char* chPtr = static_cast<char*>(ptr);
  45. vec->insert(vec->end(), chPtr, chPtr + realsize);
  46. return realsize;
  47. }
  48. static size_t curlDebugCallback(CURL*, curl_infotype, char* chPtr, size_t size,
  49. void* data)
  50. {
  51. std::vector<char>* vec = static_cast<std::vector<char>*>(data);
  52. vec->insert(vec->end(), chPtr, chPtr + size);
  53. return size;
  54. }
  55. }
  56. void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
  57. {
  58. for (std::vector<std::string>::const_iterator i = args.begin();
  59. i != args.end(); ++i) {
  60. if (*i == "CURLOPT_SSL_VERIFYPEER_OFF") {
  61. this->VerifyPeerOff = true;
  62. }
  63. if (*i == "CURLOPT_SSL_VERIFYHOST_OFF") {
  64. this->VerifyHostOff = true;
  65. }
  66. }
  67. }
  68. bool cmCTestCurl::InitCurl()
  69. {
  70. if (!this->Curl) {
  71. return false;
  72. }
  73. if (this->VerifyPeerOff) {
  74. curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
  75. }
  76. if (this->VerifyHostOff) {
  77. curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
  78. }
  79. if (!this->HTTPProxy.empty()) {
  80. curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
  81. curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
  82. if (!this->HTTPProxyAuth.empty()) {
  83. curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
  84. this->HTTPProxyAuth.c_str());
  85. }
  86. }
  87. if (this->UseHttp10) {
  88. curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  89. }
  90. // enable HTTP ERROR parsing
  91. curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  92. return true;
  93. }
  94. bool cmCTestCurl::UploadFile(std::string const& local_file,
  95. std::string const& url, std::string const& fields,
  96. std::string& response)
  97. {
  98. response = "";
  99. if (!this->InitCurl()) {
  100. cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
  101. return false;
  102. }
  103. /* enable uploading */
  104. curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
  105. // if there is little to no activity for too long stop submitting
  106. if (this->TimeOutSeconds) {
  107. ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
  108. ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME,
  109. this->TimeOutSeconds);
  110. }
  111. /* HTTP PUT please */
  112. ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
  113. ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
  114. FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
  115. if (!ftpfile) {
  116. cmCTestLog(this->CTest, ERROR_MESSAGE,
  117. "Could not open file for upload: " << local_file << "\n");
  118. return false;
  119. }
  120. // set the url
  121. std::string upload_url = url;
  122. upload_url += "?";
  123. upload_url += fields;
  124. ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
  125. // now specify which file to upload
  126. ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
  127. unsigned long filelen = cmSystemTools::FileLength(local_file);
  128. // and give the size of the upload (optional)
  129. ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
  130. static_cast<long>(filelen));
  131. ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
  132. curlWriteMemoryCallback);
  133. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
  134. // Be sure to set Content-Type to satisfy fussy modsecurity rules
  135. struct curl_slist* headers =
  136. ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml");
  137. ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
  138. std::vector<char> responseData;
  139. std::vector<char> debugData;
  140. ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
  141. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
  142. ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  143. // Now run off and do what you've been told!
  144. ::curl_easy_perform(this->Curl);
  145. ::fclose(ftpfile);
  146. ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);
  147. ::curl_slist_free_all(headers);
  148. if (!responseData.empty()) {
  149. response = std::string(responseData.begin(), responseData.end());
  150. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Curl response: ["
  151. << response << "]\n");
  152. }
  153. std::string curlDebug;
  154. if (!debugData.empty()) {
  155. curlDebug = std::string(debugData.begin(), debugData.end());
  156. cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
  157. }
  158. if (response.empty()) {
  159. cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n"
  160. << curlDebug);
  161. return false;
  162. }
  163. return true;
  164. }
  165. bool cmCTestCurl::HttpRequest(std::string const& url,
  166. std::string const& fields, std::string& response)
  167. {
  168. response = "";
  169. cmCTestLog(this->CTest, DEBUG, "HttpRequest\n"
  170. << "url: " << url << "\n"
  171. << "fields " << fields << "\n");
  172. if (!this->InitCurl()) {
  173. cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
  174. return false;
  175. }
  176. curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
  177. curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
  178. ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
  179. ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
  180. // set response options
  181. ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
  182. curlWriteMemoryCallback);
  183. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);
  184. std::vector<char> responseData;
  185. std::vector<char> debugData;
  186. ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void*)&responseData);
  187. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData);
  188. ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  189. CURLcode res = ::curl_easy_perform(this->Curl);
  190. if (!responseData.empty()) {
  191. response = std::string(responseData.begin(), responseData.end());
  192. cmCTestLog(this->CTest, DEBUG, "Curl response: [" << response << "]\n");
  193. }
  194. if (!debugData.empty()) {
  195. std::string curlDebug = std::string(debugData.begin(), debugData.end());
  196. cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
  197. }
  198. cmCTestLog(this->CTest, DEBUG, "Curl res: " << res << "\n");
  199. return (res == 0);
  200. }
  201. void cmCTestCurl::SetProxyType()
  202. {
  203. if (cmSystemTools::GetEnv("HTTP_PROXY")) {
  204. this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY");
  205. if (cmSystemTools::GetEnv("HTTP_PROXY_PORT")) {
  206. this->HTTPProxy += ":";
  207. this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT");
  208. }
  209. if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE")) {
  210. // this is the default
  211. this->HTTPProxyType = CURLPROXY_HTTP;
  212. std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE");
  213. // HTTP/SOCKS4/SOCKS5
  214. if (type == "HTTP") {
  215. this->HTTPProxyType = CURLPROXY_HTTP;
  216. } else if (type == "SOCKS4") {
  217. this->HTTPProxyType = CURLPROXY_SOCKS4;
  218. } else if (type == "SOCKS5") {
  219. this->HTTPProxyType = CURLPROXY_SOCKS5;
  220. }
  221. }
  222. if (cmSystemTools::GetEnv("HTTP_PROXY_USER")) {
  223. this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER");
  224. }
  225. if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD")) {
  226. this->HTTPProxyAuth += ":";
  227. this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD");
  228. }
  229. }
  230. }