22
33#ifdef HTTPS_BACKEND_CURL
44
5+ #include < algorithm>
56#include < dlfcn.h>
67#include < stdexcept>
78#include < sstream>
89#include < vector>
910
11+ typedef struct StringReader
12+ {
13+ const std::string *str;
14+ size_t pos;
15+ } StringReader;
16+
17+ template <typename T> bool loadSymbol (void *handle, const char *name, T &out)
18+ {
19+ out = (T) dlsym (handle, name);
20+ return out != nullptr ;
21+ }
22+
1023CurlClient::Curl::Curl ()
24+ : loaded(false )
1125{
1226 void *handle = dlopen (" libcurl.so" , RTLD_LAZY);
1327 if (!handle)
14- {
15- loaded = false ;
1628 return ;
17- }
1829
19- void (*global_init)() = (void (*)()) dlsym (handle, " curl_global_init" );
20- easy_init = (CURL*(*)()) dlsym (handle, " curl_easy_init" );
21- easy_cleanup = (void (*)(CURL*)) dlsym (handle, " curl_easy_cleanup" );
22- easy_setopt = (CURLcode (*)(CURL*,CURLoption,...)) dlsym (handle, " curl_easy_setopt" );
23- easy_perform = (CURLcode (*)(CURL*)) dlsym (handle, " curl_easy_perform" );
24- easy_getinfo = (CURLcode (*)(CURL*,CURLINFO,...)) dlsym (handle, " curl_easy_getinfo" );
25- slist_append = (curl_slist*(*)(curl_slist*,const char *)) dlsym (handle, " curl_slist_append" );
26- slist_free_all = (void (*)(curl_slist*)) dlsym (handle, " curl_slist_free_all" );
30+ // Load symbols
31+ void (*global_init)(long ) = nullptr ;
32+ if (!loadSymbol (handle, " curl_global_init" , global_init))
33+ return ;
34+ if (!loadSymbol (handle, " curl_global_cleanup" , global_cleanup))
35+ return ;
36+ if (!loadSymbol (handle, " curl_easy_init" , easy_init))
37+ return ;
38+ if (!loadSymbol (handle, " curl_easy_cleanup" , easy_cleanup))
39+ return ;
40+ if (!loadSymbol (handle, " curl_easy_setopt" , easy_setopt))
41+ return ;
42+ if (!loadSymbol (handle, " curl_easy_perform" , easy_perform))
43+ return ;
44+ if (!loadSymbol (handle, " curl_easy_getinfo" , easy_getinfo))
45+ return ;
46+ if (!loadSymbol (handle, " curl_slist_append" , slist_append))
47+ return ;
48+ if (!loadSymbol (handle, " curl_slist_free_all" , slist_free_all))
49+ return ;
2750
28- loaded = (global_init && easy_init && easy_cleanup && easy_setopt && easy_perform && easy_getinfo && slist_append && slist_free_all);
51+ global_init (CURL_GLOBAL_DEFAULT);
52+ loaded = true ;
53+ }
2954
30- if (!loaded)
31- return ;
55+ CurlClient::Curl::~Curl ()
56+ {
57+ if (loaded)
58+ global_cleanup ();
59+ }
3260
33- global_init ();
61+ static char toUppercase (char c)
62+ {
63+ int ch = (unsigned char ) c;
64+ return toupper (ch);
3465}
3566
36- static size_t stringstreamWriter (char *ptr, size_t size, size_t nmemb, void *userdata)
67+ static size_t stringReader (char *ptr, size_t size, size_t nmemb, StringReader *reader)
68+ {
69+ const char *data = reader->str ->data ();
70+ size_t len = reader->str ->length ();
71+ size_t maxCount = (len - reader->pos ) / size;
72+ size_t desiredBytes = std::min (maxCount, nmemb) * size;
73+
74+ std::copy (data + reader->pos , data + desiredBytes, ptr);
75+ reader->pos += desiredBytes;
76+
77+ return desiredBytes;
78+ }
79+
80+ static size_t stringstreamWriter (char *ptr, size_t size, size_t nmemb, std::stringstream *ss)
3781{
38- std::stringstream *ss = (std::stringstream*) userdata;
3982 size_t count = size*nmemb;
4083 ss->write (ptr, count);
4184 return count;
4285}
4386
44- static size_t headerWriter (char *ptr, size_t size, size_t nmemb, void *userdata)
87+ static size_t headerWriter (char *ptr, size_t size, size_t nmemb, std::map<std::string,std::string> *userdata)
4588{
46- std::map<std::string, std::string> &headers = *((std::map<std::string,std::string>*) userdata) ;
89+ std::map<std::string, std::string> &headers = *userdata;
4790 size_t count = size*nmemb;
4891 std::string line (ptr, count);
4992 size_t split = line.find (' :' );
@@ -64,7 +107,7 @@ bool CurlClient::valid() const
64107HTTPSClient::Reply CurlClient::request (const HTTPSClient::Request &req)
65108{
66109 Reply reply;
67- reply.responseCode = 400 ;
110+ reply.responseCode = 0 ;
68111
69112 CURL *handle = curl.easy_init ();
70113 if (!handle)
@@ -73,17 +116,23 @@ HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
73116 curl.easy_setopt (handle, CURLOPT_URL, req.url .c_str ());
74117 curl.easy_setopt (handle, CURLOPT_FOLLOWLOCATION, 1L );
75118
76- if (req.method == " PUT" )
77- curl.easy_setopt (handle, CURLOPT_PUT, 1L );
78- else if (req.method == " POST" )
79- curl.easy_setopt (handle, CURLOPT_POST, 1L );
119+ std::string method = req.method ;
120+ if (method == " " )
121+ method = " GET" ;
80122 else
81- curl.easy_setopt (handle, CURLOPT_CUSTOMREQUEST, req.method .c_str ());
123+ std::transform (method.begin (), method.end (), method.begin (), toUppercase);
124+ curl.easy_setopt (handle, CURLOPT_CUSTOMREQUEST, method.c_str ());
125+
126+ StringReader reader;
82127
83- if (req.postdata .size () > 0 && (req. method != " GET" && req. method != " HEAD" ))
128+ if (req.postdata .size () > 0 && (method != " GET" && method != " HEAD" ))
84129 {
85- curl.easy_setopt (handle, CURLOPT_POSTFIELDS, req.postdata .c_str ());
86- curl.easy_setopt (handle, CURLOPT_POSTFIELDSIZE, req.postdata .size ());
130+ reader.str = &req.postdata ;
131+ reader.pos = 0 ;
132+ curl.easy_setopt (handle, CURLOPT_UPLOAD, 1L );
133+ curl.easy_setopt (handle, CURLOPT_READFUNCTION, stringReader);
134+ curl.easy_setopt (handle, CURLOPT_READDATA, &reader);
135+ curl.easy_setopt (handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t ) req.postdata .length ());
87136 }
88137
89138 // Curl doesn't copy memory, keep the strings around
0 commit comments