CurlClient.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "CurlClient.h"
  2. #ifdef HTTPS_BACKEND_CURL
  3. #include <dlfcn.h>
  4. #include <stdexcept>
  5. #include <sstream>
  6. #include <vector>
  7. CurlClient::Curl::Curl()
  8. {
  9. void *handle = dlopen("libcurl.so", RTLD_LAZY);
  10. if (!handle)
  11. {
  12. loaded = false;
  13. return;
  14. }
  15. void (*global_init)() = (void(*)()) dlsym(handle, "curl_global_init");
  16. easy_init = (CURL*(*)()) dlsym(handle, "curl_easy_init");
  17. easy_cleanup = (void(*)(CURL*)) dlsym(handle, "curl_easy_cleanup");
  18. easy_setopt = (CURLcode(*)(CURL*,CURLoption,...)) dlsym(handle, "curl_easy_setopt");
  19. easy_perform = (CURLcode(*)(CURL*)) dlsym(handle, "curl_easy_perform");
  20. easy_getinfo = (CURLcode(*)(CURL*,CURLINFO,...)) dlsym(handle, "curl_easy_getinfo");
  21. slist_append = (curl_slist*(*)(curl_slist*,const char*)) dlsym(handle, "curl_slist_append");
  22. slist_free_all = (void(*)(curl_slist*)) dlsym(handle, "curl_slist_free_all");
  23. loaded = (global_init && easy_init && easy_cleanup && easy_setopt && easy_perform && easy_getinfo && slist_append && slist_free_all);
  24. if (!loaded)
  25. return;
  26. global_init();
  27. }
  28. static size_t stringstreamWriter(char *ptr, size_t size, size_t nmemb, void *userdata)
  29. {
  30. std::stringstream *ss = (std::stringstream*) userdata;
  31. size_t count = size*nmemb;
  32. ss->write(ptr, count);
  33. return count;
  34. }
  35. static size_t headerWriter(char *ptr, size_t size, size_t nmemb, void *userdata)
  36. {
  37. std::map<std::string, std::string> &headers = *((std::map<std::string,std::string>*) userdata);
  38. size_t count = size*nmemb;
  39. std::string line(ptr, count);
  40. size_t split = line.find(':');
  41. size_t newline = line.find('\r');
  42. if (newline == std::string::npos)
  43. newline = line.size();
  44. if (split != std::string::npos)
  45. headers[line.substr(0, split)] = line.substr(split+1, newline-split-1);
  46. return count;
  47. }
  48. bool CurlClient::valid() const
  49. {
  50. return curl.loaded;
  51. }
  52. HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
  53. {
  54. Reply reply;
  55. reply.responseCode = 400;
  56. CURL *handle = curl.easy_init();
  57. if (!handle)
  58. throw std::runtime_error("Could not create curl request");
  59. curl.easy_setopt(handle, CURLOPT_URL, req.url.c_str());
  60. curl.easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
  61. if (req.method == "PUT")
  62. curl.easy_setopt(handle, CURLOPT_PUT, 1L);
  63. else if (req.method == "POST")
  64. curl.easy_setopt(handle, CURLOPT_POST, 1L);
  65. else
  66. curl.easy_setopt(handle, CURLOPT_CUSTOMREQUEST, req.method.c_str());
  67. if (req.postdata.size() > 0 && (req.method != "GET" && req.method != "HEAD"))
  68. {
  69. curl.easy_setopt(handle, CURLOPT_POSTFIELDS, req.postdata.c_str());
  70. curl.easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.postdata.size());
  71. }
  72. // Curl doesn't copy memory, keep the strings around
  73. std::vector<std::string> lines;
  74. for (auto &header : req.headers)
  75. {
  76. std::stringstream line;
  77. line << header.first << ": " << header.second;
  78. lines.push_back(line.str());
  79. }
  80. curl_slist *sendHeaders = nullptr;
  81. for (auto &line : lines)
  82. sendHeaders = curl.slist_append(sendHeaders, line.c_str());
  83. if (sendHeaders)
  84. curl.easy_setopt(handle, CURLOPT_HTTPHEADER, sendHeaders);
  85. std::stringstream body;
  86. curl.easy_setopt(handle, CURLOPT_WRITEFUNCTION, stringstreamWriter);
  87. curl.easy_setopt(handle, CURLOPT_WRITEDATA, &body);
  88. curl.easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerWriter);
  89. curl.easy_setopt(handle, CURLOPT_HEADERDATA, &reply.headers);
  90. curl.easy_perform(handle);
  91. if (sendHeaders)
  92. curl.slist_free_all(sendHeaders);
  93. {
  94. long responseCode;
  95. curl.easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode);
  96. reply.responseCode = (int) responseCode;
  97. }
  98. reply.body = body.str();
  99. curl.easy_cleanup(handle);
  100. return reply;
  101. }
  102. CurlClient::Curl CurlClient::curl;
  103. #endif // HTTPS_BACKEND_CURL