| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying   file Copyright.txt or https://cmake.org/licensing for details.  */#include "cmCTestCurl.h"#include "cmCTest.h"#include "cmCurl.h"#include "cmSystemTools.h"#include <ostream>#include <stdio.h>cmCTestCurl::cmCTestCurl(cmCTest* ctest){  this->CTest = ctest;  this->SetProxyType();  this->UseHttp10 = false;  // In windows, this will init the winsock stuff  ::curl_global_init(CURL_GLOBAL_ALL);  // default is to verify https  this->VerifyPeerOff = false;  this->VerifyHostOff = false;  this->Quiet = false;  this->TimeOutSeconds = 0;  this->Curl = curl_easy_init();}cmCTestCurl::~cmCTestCurl(){  ::curl_easy_cleanup(this->Curl);  ::curl_global_cleanup();}std::string cmCTestCurl::Escape(std::string const& source){  char* data1 = curl_easy_escape(this->Curl, source.c_str(), 0);  std::string ret = data1;  curl_free(data1);  return ret;}namespace {size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb,                               void* data){  int realsize = static_cast<int>(size * nmemb);  std::vector<char>* vec = static_cast<std::vector<char>*>(data);  const char* chPtr = static_cast<char*>(ptr);  vec->insert(vec->end(), chPtr, chPtr + realsize);  return realsize;}size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,                         char* chPtr, size_t size, void* data){  std::vector<char>* vec = static_cast<std::vector<char>*>(data);  vec->insert(vec->end(), chPtr, chPtr + size);  return size;}}void cmCTestCurl::SetCurlOptions(std::vector<std::string> const& args){  for (std::string const& arg : args) {    if (arg == "CURLOPT_SSL_VERIFYPEER_OFF") {      this->VerifyPeerOff = true;    }    if (arg == "CURLOPT_SSL_VERIFYHOST_OFF") {      this->VerifyHostOff = true;    }  }}bool cmCTestCurl::InitCurl(){  if (!this->Curl) {    return false;  }  cmCurlSetCAInfo(this->Curl);  if (this->VerifyPeerOff) {    curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYPEER, 0);  }  if (this->VerifyHostOff) {    curl_easy_setopt(this->Curl, CURLOPT_SSL_VERIFYHOST, 0);  }  if (!this->HTTPProxy.empty()) {    curl_easy_setopt(this->Curl, CURLOPT_PROXY, this->HTTPProxy.c_str());    curl_easy_setopt(this->Curl, CURLOPT_PROXYTYPE, this->HTTPProxyType);    if (!this->HTTPProxyAuth.empty()) {      curl_easy_setopt(this->Curl, CURLOPT_PROXYUSERPWD,                       this->HTTPProxyAuth.c_str());    }  }  if (this->UseHttp10) {    curl_easy_setopt(this->Curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);  }  // enable HTTP ERROR parsing  curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);  // if there is little to no activity for too long stop submitting  if (this->TimeOutSeconds) {    curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_LIMIT, 1);    curl_easy_setopt(this->Curl, CURLOPT_LOW_SPEED_TIME, this->TimeOutSeconds);  }  return true;}bool cmCTestCurl::UploadFile(std::string const& local_file,                             std::string const& url, std::string const& fields,                             std::string& response){  response.clear();  if (!this->InitCurl()) {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");    return false;  }  /* enable uploading */  curl_easy_setopt(this->Curl, CURLOPT_UPLOAD, 1);  /* HTTP PUT please */  ::curl_easy_setopt(this->Curl, CURLOPT_PUT, 1);  ::curl_easy_setopt(this->Curl, CURLOPT_VERBOSE, 1);  FILE* ftpfile = cmsys::SystemTools::Fopen(local_file, "rb");  if (!ftpfile) {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "Could not open file for upload: " << local_file << "\n");    return false;  }  // set the url  std::string upload_url = url;  upload_url += "?";  upload_url += fields;  ::curl_easy_setopt(this->Curl, CURLOPT_URL, upload_url.c_str());  // now specify which file to upload  ::curl_easy_setopt(this->Curl, CURLOPT_INFILE, ftpfile);  unsigned long filelen = cmSystemTools::FileLength(local_file);  // and give the size of the upload (optional)  ::curl_easy_setopt(this->Curl, CURLOPT_INFILESIZE,                     static_cast<long>(filelen));  ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,                     curlWriteMemoryCallback);  ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);  // Set Content-Type to satisfy fussy modsecurity rules.  struct curl_slist* headers =    ::curl_slist_append(nullptr, "Content-Type: text/xml");  // Add any additional headers that the user specified.  for (std::string const& h : this->HttpHeaders) {    cmCTestOptionalLog(this->CTest, DEBUG,                       "   Add HTTP Header: \"" << h << "\"" << std::endl,                       this->Quiet);    headers = ::curl_slist_append(headers, h.c_str());  }  ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);  std::vector<char> responseData;  std::vector<char> debugData;  ::curl_easy_setopt(this->Curl, CURLOPT_FILE, &responseData);  ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, &debugData);  ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);  // Now run off and do what you've been told!  ::curl_easy_perform(this->Curl);  ::fclose(ftpfile);  ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, NULL);  ::curl_slist_free_all(headers);  if (!responseData.empty()) {    response = std::string(responseData.begin(), responseData.end());    cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,                       "Curl response: [" << response << "]\n", this->Quiet);  }  std::string curlDebug;  if (!debugData.empty()) {    curlDebug = std::string(debugData.begin(), debugData.end());    cmCTestOptionalLog(this->CTest, DEBUG,                       "Curl debug: [" << curlDebug << "]\n", this->Quiet);  }  if (response.empty()) {    cmCTestLog(this->CTest, ERROR_MESSAGE,               "No response from server.\n"                 << curlDebug);    return false;  }  return true;}bool cmCTestCurl::HttpRequest(std::string const& url,                              std::string const& fields, std::string& response){  response.clear();  cmCTestOptionalLog(this->CTest, DEBUG,                     "HttpRequest\n"                       << "url: " << url << "\n"                       << "fields " << fields << "\n",                     this->Quiet);  if (!this->InitCurl()) {    cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");    return false;  }  curl_easy_setopt(this->Curl, CURLOPT_POST, 1);  curl_easy_setopt(this->Curl, CURLOPT_POSTFIELDS, fields.c_str());  ::curl_easy_setopt(this->Curl, CURLOPT_URL, url.c_str());  ::curl_easy_setopt(this->Curl, CURLOPT_FOLLOWLOCATION, 1);  // set response options  ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION,                     curlWriteMemoryCallback);  ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback);  std::vector<char> responseData;  std::vector<char> debugData;  ::curl_easy_setopt(this->Curl, CURLOPT_FILE, &responseData);  ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, &debugData);  ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1);  // Add headers if any were specified.  struct curl_slist* headers = nullptr;  if (!this->HttpHeaders.empty()) {    for (std::string const& h : this->HttpHeaders) {      cmCTestOptionalLog(this->CTest, DEBUG,                         "   Add HTTP Header: \"" << h << "\"" << std::endl,                         this->Quiet);      headers = ::curl_slist_append(headers, h.c_str());    }  }  ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers);  CURLcode res = ::curl_easy_perform(this->Curl);  ::curl_slist_free_all(headers);  if (!responseData.empty()) {    response = std::string(responseData.begin(), responseData.end());    cmCTestOptionalLog(this->CTest, DEBUG,                       "Curl response: [" << response << "]\n", this->Quiet);  }  if (!debugData.empty()) {    std::string curlDebug = std::string(debugData.begin(), debugData.end());    cmCTestOptionalLog(this->CTest, DEBUG,                       "Curl debug: [" << curlDebug << "]\n", this->Quiet);  }  cmCTestOptionalLog(this->CTest, DEBUG, "Curl res: " << res << "\n",                     this->Quiet);  return (res == 0);}void cmCTestCurl::SetProxyType(){  this->HTTPProxy.clear();  // this is the default  this->HTTPProxyType = CURLPROXY_HTTP;  this->HTTPProxyAuth.clear();  if (cmSystemTools::GetEnv("HTTP_PROXY", this->HTTPProxy)) {    std::string port;    if (cmSystemTools::GetEnv("HTTP_PROXY_PORT", port)) {      this->HTTPProxy += ":";      this->HTTPProxy += port;    }    std::string type;    if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE", type)) {      // HTTP/SOCKS4/SOCKS5      if (type == "HTTP") {        this->HTTPProxyType = CURLPROXY_HTTP;      } else if (type == "SOCKS4") {        this->HTTPProxyType = CURLPROXY_SOCKS4;      } else if (type == "SOCKS5") {        this->HTTPProxyType = CURLPROXY_SOCKS5;      }    }    cmSystemTools::GetEnv("HTTP_PROXY_USER", this->HTTPProxyAuth);    std::string passwd;    if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD", passwd)) {      this->HTTPProxyAuth += ":";      this->HTTPProxyAuth += passwd;    }  }}
 |