-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathcurl_http.hpp
178 lines (135 loc) · 4.26 KB
/
curl_http.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#ifndef CURL_HTTP_HPP
#define CURL_HTTP_HPP
#include <cassert>
#include <curl/curl.h>
#include "api2captcha.hpp"
namespace api2captcha
{
class curl_http_t : public http_client_i
{
CURL * curl_ = nullptr;
std::string result_;
bool verbose_ = false;
static size_t
on_data (void * contents,
const size_t size, const size_t nmemb,
void * userp)
{
assert (userp);
// get curl
auto * self = reinterpret_cast<curl_http_t *> (userp);
assert (self);
// push data
const size_t total = size * nmemb;
self->result_.append ((char *)contents, total);
// always confirm receival
return total;
}
public:
curl_http_t ()
{
if (curl_global_init (CURL_GLOBAL_ALL))
throw std::runtime_error ("Failed to global init curl");
curl_ = curl_easy_init ();
if (!curl_)
{
curl_global_cleanup ();
throw std::runtime_error ("Failed to init curl");
}
}
~curl_http_t ()
{
if (curl_)
curl_easy_cleanup (curl_);
curl_global_cleanup ();
}
void set_verbose (const bool v) { verbose_ = v; }
virtual int status () const
{
long status = 0;
curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &status);
return status;
}
virtual std::string get (
const std::string & url, const int timeout, const params_t & params)
{
result_.clear ();
curl_easy_reset (curl_);
// format url
std::string full_url = url + "?";
for (const auto & i: params)
{
auto * v = curl_easy_escape (curl_, i.second.c_str (), i.second.size ());
assert (v);
full_url += "&" + i.first + "=" + v;
curl_free (v);
}
// set url
curl_easy_setopt (curl_, CURLOPT_URL, full_url.c_str ());
// timeouts
curl_easy_setopt (curl_, CURLOPT_TIMEOUT, timeout);
// set self as on_data context
curl_easy_setopt (curl_, CURLOPT_WRITEDATA, this);
// data callback
curl_easy_setopt (curl_, CURLOPT_WRITEFUNCTION, on_data);
if (verbose_)
curl_easy_setopt (curl_, CURLOPT_VERBOSE, 1L);
/* Perform the request, res will get the return code */
const auto res = curl_easy_perform (curl_);
if (res)
throw network_exception_t (
std::string ("Failed to curl get: ") + curl_easy_strerror (res));
return result_;
}
virtual std::string post (
const std::string & url, const int timeout,
const params_t & params, const files_t & files)
{
result_.clear ();
curl_easy_reset (curl_);
// Create the form
auto * form = curl_mime_init (curl_);
if (!form)
throw std::runtime_error ("Failed to create curl mime");
// params
for (const auto & i: params)
{
auto * field = curl_mime_addpart (form);
curl_mime_name (field, i.first.c_str ());
curl_mime_data (field, i.second.c_str (), CURL_ZERO_TERMINATED);
}
// files
for (const auto & i: files)
{
auto * field = curl_mime_addpart (form);
curl_mime_name (field, i.first.c_str ());
if (curl_mime_filedata (field, i.second.c_str ()))
throw std::runtime_error ("Failed to set uploaded file in curl");
}
// set url
curl_easy_setopt (curl_, CURLOPT_URL, url.c_str ());
// initialize custom header list (stating that Expect: 100-continue is not wanted
// FIXME???
auto * headerlist = curl_slist_append (NULL, "Expect:");
curl_easy_setopt (curl_, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt (curl_, CURLOPT_MIMEPOST, form);
// timeouts
curl_easy_setopt (curl_, CURLOPT_TIMEOUT, timeout);
// set self as on_data context
curl_easy_setopt (curl_, CURLOPT_WRITEDATA, this);
// data callback
curl_easy_setopt (curl_, CURLOPT_WRITEFUNCTION, on_data);
if (verbose_)
curl_easy_setopt (curl_, CURLOPT_VERBOSE, 1L);
/* Perform the request, res will get the return code */
const auto res = curl_easy_perform (curl_);
curl_mime_free (form);
curl_slist_free_all (headerlist);
if (res)
throw network_exception_t (
std::string ("Failed to curl post: ") + curl_easy_strerror (res));
return result_;
}
};
};
#endif /* CURL_HTTP_HPP */