1
+ #ifdef _WIN32
2
+ #define NOMINMAX
3
+ #define WIN32_LEAN_AND_MEAN
4
+ #endif
5
+
1
6
#include " CurlClient.h"
2
7
3
8
#ifdef HTTPS_BACKEND_CURL
4
9
5
10
#include < algorithm>
6
- #include < dlfcn.h>
7
11
#include < stdexcept>
8
12
#include < sstream>
9
13
#include < vector>
10
14
15
+ // Dynamic library loader
16
+ #ifdef _WIN32
17
+ #include < windows.h>
18
+ #else
19
+ #include < dlfcn.h>
20
+ #endif
21
+
11
22
typedef struct StringReader
12
23
{
13
24
const std::string *str;
14
25
size_t pos;
15
26
} StringReader;
16
27
17
- template <typename T> bool loadSymbol (void *handle, const char *name, T &out)
28
+ template <class T >
29
+ static inline bool loadSymbol (T &var, void *handle, const char *name)
18
30
{
19
- out = (T) dlsym (handle, name);
20
- return out != nullptr ;
31
+ #ifdef _WIN32
32
+ var = (T) GetProcAddress ((HMODULE) handle, name);
33
+ #else
34
+ var = (T) dlsym (handle, name);
35
+ #endif
36
+ return var != nullptr ;
21
37
}
22
38
23
39
CurlClient::Curl::Curl ()
24
- : loaded(false )
40
+ : handle(nullptr )
41
+ , loaded(false )
42
+ , global_cleanup(nullptr )
43
+ , easy_init(nullptr )
44
+ , easy_cleanup(nullptr )
45
+ , easy_setopt(nullptr )
46
+ , easy_perform(nullptr )
47
+ , easy_getinfo(nullptr )
48
+ , slist_append(nullptr )
49
+ , slist_free_all(nullptr )
25
50
{
26
- void *handle = dlopen (" libcurl.so" , RTLD_LAZY);
51
+ #ifdef _WIN32
52
+ handle = (void *) LoadLibraryA (" libcurl.dll" );
53
+ #else
54
+ handle = dlopen (" libcurl.so.4" , RTLD_LAZY);
55
+ #endif
27
56
if (!handle)
28
57
return ;
29
58
30
59
// Load symbols
31
- void (*global_init)( long ) = nullptr ;
32
- if (!loadSymbol (handle, " curl_global_init" , global_init ))
60
+ decltype (&curl_global_init) global_init = nullptr ;
61
+ if (!loadSymbol (global_init, handle, " curl_global_init" ))
33
62
return ;
34
- if (!loadSymbol (handle, " curl_global_cleanup" , global_cleanup ))
63
+ if (!loadSymbol (global_cleanup, handle, " curl_global_cleanup" ))
35
64
return ;
36
- if (!loadSymbol (handle, " curl_easy_init" , easy_init ))
65
+ if (!loadSymbol (easy_init, handle, " curl_easy_init" ))
37
66
return ;
38
- if (!loadSymbol (handle, " curl_easy_cleanup" , easy_cleanup ))
67
+ if (!loadSymbol (easy_cleanup, handle, " curl_easy_cleanup" ))
39
68
return ;
40
- if (!loadSymbol (handle, " curl_easy_setopt" , easy_setopt ))
69
+ if (!loadSymbol (easy_setopt, handle, " curl_easy_setopt" ))
41
70
return ;
42
- if (!loadSymbol (handle, " curl_easy_perform" , easy_perform ))
71
+ if (!loadSymbol (easy_perform, handle, " curl_easy_perform" ))
43
72
return ;
44
- if (!loadSymbol (handle, " curl_easy_getinfo" , easy_getinfo ))
73
+ if (!loadSymbol (easy_getinfo, handle, " curl_easy_getinfo" ))
45
74
return ;
46
- if (!loadSymbol (handle, " curl_slist_append" , slist_append ))
75
+ if (!loadSymbol (slist_append, handle, " curl_slist_append" ))
47
76
return ;
48
- if (!loadSymbol (handle, " curl_slist_free_all" , slist_free_all ))
77
+ if (!loadSymbol (slist_free_all, handle, " curl_slist_free_all" ))
49
78
return ;
50
79
51
80
global_init (CURL_GLOBAL_DEFAULT);
@@ -56,6 +85,13 @@ CurlClient::Curl::~Curl()
56
85
{
57
86
if (loaded)
58
87
global_cleanup ();
88
+
89
+ if (handle)
90
+ #ifdef _WIN32
91
+ FreeLibrary ((HMODULE) handle);
92
+ #else
93
+ dlclose (handle);
94
+ #endif
59
95
}
60
96
61
97
static char toUppercase (char c)
@@ -69,12 +105,13 @@ static size_t stringReader(char *ptr, size_t size, size_t nmemb, StringReader *r
69
105
const char *data = reader->str ->data ();
70
106
size_t len = reader->str ->length ();
71
107
size_t maxCount = (len - reader->pos ) / size;
72
- size_t desiredBytes = std::min (maxCount, nmemb) * size;
108
+ size_t desiredCount = std::min (maxCount, nmemb);
109
+ size_t desiredBytes = desiredCount * size;
73
110
74
111
std::copy (data + reader->pos , data + desiredBytes, ptr);
75
112
reader->pos += desiredBytes;
76
113
77
- return desiredBytes ;
114
+ return desiredCount ;
78
115
}
79
116
80
117
static size_t stringstreamWriter (char *ptr, size_t size, size_t nmemb, std::stringstream *ss)
@@ -109,6 +146,9 @@ HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
109
146
Reply reply;
110
147
reply.responseCode = 0 ;
111
148
149
+ // Use sensible default header for later
150
+ HTTPSClient::header_map newHeaders = req.headers ;
151
+
112
152
CURL *handle = curl.easy_init ();
113
153
if (!handle)
114
154
throw std::runtime_error (" Could not create curl request" );
@@ -117,13 +157,13 @@ HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
117
157
curl.easy_setopt (handle, CURLOPT_FOLLOWLOCATION, 1L );
118
158
119
159
std::string method = req.method ;
120
- if (method == " " )
121
- method = " GET" ;
160
+ if (method. empty () )
161
+ method = req. postdata . size () > 0 ? " POST " : " GET" ;
122
162
else
123
163
std::transform (method.begin (), method.end (), method.begin (), toUppercase);
124
164
curl.easy_setopt (handle, CURLOPT_CUSTOMREQUEST, method.c_str ());
125
165
126
- StringReader reader;
166
+ StringReader reader {} ;
127
167
128
168
if (req.postdata .size () > 0 && (method != " GET" && method != " HEAD" ))
129
169
{
@@ -133,11 +173,14 @@ HTTPSClient::Reply CurlClient::request(const HTTPSClient::Request &req)
133
173
curl.easy_setopt (handle, CURLOPT_READFUNCTION, stringReader);
134
174
curl.easy_setopt (handle, CURLOPT_READDATA, &reader);
135
175
curl.easy_setopt (handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t ) req.postdata .length ());
176
+
177
+ if (newHeaders.count (" Content-Type" ) == 0 )
178
+ newHeaders[" Content-Type" ] = " application/x-www-form-urlencoded" ;
136
179
}
137
180
138
181
// Curl doesn't copy memory, keep the strings around
139
182
std::vector<std::string> lines;
140
- for (auto &header : req. headers )
183
+ for (auto &header : newHeaders )
141
184
{
142
185
std::stringstream line;
143
186
line << header.first << " : " << header.second ;
0 commit comments