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
|
#include "tgbot/net/CurlHttpClient.h"
#include <cstddef>
#include <string>
namespace TgBot {
CurlHttpClient::CurlHttpClient() : _httpParser() {
curlSettings = curl_easy_init();
curl_easy_setopt(curlSettings, CURLOPT_CONNECTTIMEOUT, 20);
curl_easy_setopt(curlSettings, CURLOPT_TIMEOUT, _timeout);
}
CurlHttpClient::~CurlHttpClient() {
curl_easy_cleanup(curlSettings);
}
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 {
// Copy settings for each call because we change CURLOPT_URL and other stuff.
// This also protects multithreaded case.
auto curl = curl_easy_duphandle(curlSettings);
std::string u = url.protocol + "://" + url.host + url.path;
curl_easy_setopt(curl, CURLOPT_URL, u.c_str());
// disable keep-alive
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Connection: close");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
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_slist_free_all(headers);
curl_easy_cleanup(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);
}
}
|