forked from reo7sp/tgbot-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCurlHttpClient.cpp
More file actions
102 lines (82 loc) · 2.92 KB
/
CurlHttpClient.cpp
File metadata and controls
102 lines (82 loc) · 2.92 KB
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
#ifdef HAVE_CURL
#include "tgbot/net/CurlHttpClient.h"
#include <cstddef>
#include <string>
namespace TgBot {
CurlHttpClient::CurlHttpClient() : _httpParser() {
}
CurlHttpClient::~CurlHttpClient() {
std::lock_guard<std::mutex> lock(curlHandlesMutex);
for (auto& c : curlHandles) {
curl_easy_cleanup(c.second);
}
}
static CURL* getCurlHandle(const CurlHttpClient *c_) {
CurlHttpClient *c = const_cast<CurlHttpClient *>(c_);
std::lock_guard<std::mutex> lock(c->curlHandlesMutex);
auto id = std::this_thread::get_id();
auto it = c->curlHandles.find(id);
if (it == c->curlHandles.end()) {
CURL* curl = curl_easy_init();
if (!curl) {
throw std::runtime_error("curl_easy_init() failed");
}
c->curlHandles[id] = curl;
return curl;
}
return it->second;
}
static std::size_t curlWriteString(char* ptr, std::size_t size, std::size_t nmemb, void* userdata) {
static_cast<std::string*>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
std::string CurlHttpClient::makeRequest(const Url& url, const std::vector<HttpReqArg>& args) const {
CURL* curl = getCurlHandle(this);
curl_easy_reset(curl);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, _timeout);
std::string u = url.protocol + "://" + url.host + url.path;
if (args.empty()) {
u += "?" + url.query;
}
curl_easy_setopt(curl, CURLOPT_URL, u.c_str());
curl_mime* mime;
curl_mimepart* part;
mime = curl_mime_init(curl);
if (!args.empty()) {
for (const HttpReqArg& a : args) {
part = curl_mime_addpart(mime);
curl_mime_data(part, a.value.c_str(), a.value.size());
curl_mime_type(part, a.mimeType.c_str());
curl_mime_name(part, a.name.c_str());
if (a.isFile) {
curl_mime_filename(part, a.fileName.c_str());
}
}
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
}
std::string response;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteString);
char errbuf[CURL_ERROR_SIZE] {};
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
auto res = curl_easy_perform(curl);
curl_mime_free(mime);
// If the request did not complete correctly, show the error
// information. If no detailed error information was written to errbuf
// show the more generic information from curl_easy_strerror instead.
if (res != CURLE_OK) {
size_t len = strlen(errbuf);
std::string errmsg;
if (len) {
errmsg = std::string(errbuf) + ((errbuf[len - 1] != '\n') ? "\n" : "");
}
else {
errmsg = curl_easy_strerror(res);
}
throw std::runtime_error(std::string("curl error: ") + errmsg);
}
return _httpParser.extractBody(response);
}
}
#endif