cmCTestCurl.cxx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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 "cmSystemTools.h"
  12. #include "cmCTest.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. {
  40. static size_t
  41. curlWriteMemoryCallback(void *ptr, size_t size, size_t nmemb,
  42. void *data)
  43. {
  44. int realsize = (int)(size * nmemb);
  45. std::vector<char> *vec
  46. = static_cast<std::vector<char>* >(data);
  47. const char* chPtr = static_cast<char*>(ptr);
  48. vec->insert(vec->end(), chPtr, chPtr + realsize);
  49. return realsize;
  50. }
  51. static size_t
  52. curlDebugCallback(CURL *, curl_infotype, char *chPtr,
  53. size_t size, void *data)
  54. {
  55. std::vector<char> *vec
  56. = static_cast<std::vector<char>* >(data);
  57. vec->insert(vec->end(), chPtr, chPtr + size);
  58. return size;
  59. }
  60. }
  61. void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args)
  62. {
  63. for( std::vector<std::string>::const_iterator i = args.begin();
  64. i != args.end(); ++i)
  65. {
  66. if(*i == "CURLOPT_SSL_VERIFYPEER_OFF")
  67. {
  68. this->VerifyPeerOff = true;
  69. }
  70. if(*i == "CURLOPT_SSL_VERIFYHOST_OFF")
  71. {
  72. this->VerifyHostOff = true;
  73. }
  74. }
  75. }
  76. bool cmCTestCurl::InitCurl()
  77. {
  78. if(!this->Curl)
  79. {
  80. return false;
  81. }
  82. if(this->VerifyPeerOff)
  83. {
  84. curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);
  85. }
  86. if(this->VerifyHostOff)
  87. {
  88. curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);
  89. }
  90. if(this->HTTPProxy.size())
  91. {
  92. curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());
  93. curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);
  94. if (this->HTTPProxyAuth.size() > 0)
  95. {
  96. curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,
  97. this->HTTPProxyAuth.c_str());
  98. }
  99. }
  100. if(this->UseHttp10)
  101. {
  102. curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  103. }
  104. // enable HTTP ERROR parsing
  105. curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  106. return true;
  107. }
  108. bool cmCTestCurl::UploadFile(std::string const& local_file,
  109. std::string const& url,
  110. std::string const& fields,
  111. std::string& response)
  112. {
  113. response = "";
  114. if(!this->InitCurl())
  115. {
  116. cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
  117. return false;
  118. }
  119. /* enable uploading */
  120. curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);
  121. // if there is little to no activity for too long stop submitting
  122. if(this->TimeOutSeconds)
  123. {
  124. ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);
  125. ::curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME,
  126. this->TimeOutSeconds);
  127. }
  128. /* HTTP PUT please */
  129. ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);
  130. ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);
  131. FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");
  132. if(!ftpfile)
  133. {
  134. cmCTestLog(this->CTest, ERROR_MESSAGE,
  135. "Could not open file for upload: " << local_file << "\n");
  136. return false;
  137. }
  138. // set the url
  139. std::string upload_url = url;
  140. upload_url += "?";
  141. upload_url += fields;
  142. ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());
  143. // now specify which file to upload
  144. ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);
  145. unsigned long filelen = cmSystemTools::FileLength(local_file);
  146. // and give the size of the upload (optional)
  147. ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,
  148. static_cast<long>(filelen));
  149. ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
  150. curlWriteMemoryCallback);
  151. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
  152. curlDebugCallback);
  153. // Be sure to set Content-Type to satisfy fussy modsecurity rules
  154. struct curl_slist *headers = ::curl_slist_append(NULL,
  155. "Content-Type: text/xml");
  156. ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);
  157. std::vector<char> responseData;
  158. std::vector<char> debugData;
  159. ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
  160. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
  161. ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  162. // Now run off and do what you've been told!
  163. ::curl_easy_perform(this->Curl);
  164. ::fclose(ftpfile);
  165. ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);
  166. ::curl_slist_free_all(headers);
  167. if ( responseData.size() > 0 )
  168. {
  169. response = std::string(responseData.begin(), responseData.end());
  170. cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
  171. "Curl response: [" << response << "]\n");
  172. }
  173. std::string curlDebug;
  174. if ( debugData.size() > 0 )
  175. {
  176. curlDebug = std::string(debugData.begin(), debugData.end());
  177. cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
  178. }
  179. if(response.size() == 0)
  180. {
  181. cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n" <<
  182. curlDebug);
  183. return false;
  184. }
  185. return true;
  186. }
  187. bool cmCTestCurl::HttpRequest(std::string const& url,
  188. std::string const& fields,
  189. std::string& response)
  190. {
  191. response = "";
  192. cmCTestLog(this->CTest, DEBUG, "HttpRequest\n"
  193. << "url: " << url << "\n"
  194. << "fields " << fields << "\n");
  195. if(!this->InitCurl())
  196. {
  197. cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
  198. return false;
  199. }
  200. curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
  201. curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());
  202. ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());
  203. ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);
  204. //set response options
  205. ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,
  206. curlWriteMemoryCallback);
  207. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION,
  208. curlDebugCallback);
  209. std::vector<char> responseData;
  210. std::vector<char> debugData;
  211. ::curl_easy_setopt(this->Curl, CURLOPT_FILE, (void *)&responseData);
  212. ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void *)&debugData);
  213. ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);
  214. CURLcode res = ::curl_easy_perform(this->Curl);
  215. if ( responseData.size() > 0 )
  216. {
  217. response = std::string(responseData.begin(), responseData.end());
  218. cmCTestLog(this->CTest, DEBUG, "Curl response: [" << response << "]\n");
  219. }
  220. if ( debugData.size() > 0 )
  221. {
  222. std::string curlDebug = std::string(debugData.begin(), debugData.end());
  223. cmCTestLog(this->CTest, DEBUG, "Curl debug: [" << curlDebug << "]\n");
  224. }
  225. cmCTestLog(this->CTest, DEBUG, "Curl res: " << res << "\n");
  226. return (res == 0);
  227. }
  228. void cmCTestCurl::SetProxyType()
  229. {
  230. if ( cmSystemTools::GetEnv("HTTP_PROXY") )
  231. {
  232. this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY");
  233. if ( cmSystemTools::GetEnv("HTTP_PROXY_PORT") )
  234. {
  235. this->HTTPProxy += ":";
  236. this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT");
  237. }
  238. if ( cmSystemTools::GetEnv("HTTP_PROXY_TYPE") )
  239. {
  240. // this is the default
  241. this->HTTPProxyType = CURLPROXY_HTTP;
  242. std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE");
  243. // HTTP/SOCKS4/SOCKS5
  244. if ( type == "HTTP" )
  245. {
  246. this->HTTPProxyType = CURLPROXY_HTTP;
  247. }
  248. else if ( type == "SOCKS4" )
  249. {
  250. this->HTTPProxyType = CURLPROXY_SOCKS4;
  251. }
  252. else if ( type == "SOCKS5" )
  253. {
  254. this->HTTPProxyType = CURLPROXY_SOCKS5;
  255. }
  256. }
  257. if ( cmSystemTools::GetEnv("HTTP_PROXY_USER") )
  258. {
  259. this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER");
  260. }
  261. if ( cmSystemTools::GetEnv("HTTP_PROXY_PASSWD") )
  262. {
  263. this->HTTPProxyAuth += ":";
  264. this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD");
  265. }
  266. }
  267. }