update Curl.cpp

This commit is contained in:
MihailRis 2026-09-10 22:29:34 +03:00
parent effa850337
commit 9510e06a26

View file

@ -23,27 +23,27 @@ static size_t write_callback(
return size * nmemb; return size * nmemb;
} }
struct ProcessingRequest {
CURL* curl;
HttpRequest request;
std::vector<char> buffer;
};
class CurlRequests : public Requests { class CurlRequests : public Requests {
CURLM* multiHandle; CURLM* multiHandle;
CURL* curl; std::vector<std::unique_ptr<ProcessingRequest>> requests;
size_t totalUpload = 0; size_t totalUpload = 0;
size_t totalDownload = 0; size_t totalDownload = 0;
OnResponse onResponse;
OnReject onReject;
std::vector<char> buffer;
std::string url;
std::queue<HttpRequest> requests;
public: public:
CurlRequests(CURLM* multiHandle, CURL* curl) CurlRequests(CURLM* multiHandle) : multiHandle(multiHandle) {
: multiHandle(multiHandle), curl(curl) {
} }
virtual ~CurlRequests() { virtual ~CurlRequests() {
curl_multi_remove_handle(multiHandle, curl); for (auto& entry : requests) {
curl_easy_cleanup(curl); curl_multi_remove_handle(multiHandle, entry->curl);
curl_easy_cleanup(entry->curl);
}
curl_multi_cleanup(multiHandle); curl_multi_cleanup(multiHandle);
} }
@ -52,17 +52,12 @@ public:
} }
void processRequest(HttpRequest request) { void processRequest(HttpRequest request) {
if (!url.empty()) { auto curl = curl_easy_init();
requests.push(request);
return;
}
onResponse = request.onResponse;
onReject = request.onReject;
url = request.url;
buffer.clear(); auto entry = std::make_unique<ProcessingRequest>();
entry->curl = curl;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, request.url.c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request.method.c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request.method.c_str());
curl_slist* hs = nullptr; curl_slist* hs = nullptr;
@ -80,7 +75,7 @@ public:
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, request.followLocation); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, request.followLocation);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &entry->buffer);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.81.0"); curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.81.0");
#ifndef NDEBUG #ifndef NDEBUG
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
@ -97,12 +92,13 @@ public:
CURLMcode res = curl_multi_perform(multiHandle, &running); CURLMcode res = curl_multi_perform(multiHandle, &running);
if (res != CURLM_OK) { if (res != CURLM_OK) {
auto message = curl_multi_strerror(res); auto message = curl_multi_strerror(res);
logger.error() << message << " (" << url << ")"; logger.error() << message << " (" << request.url << ")";
if (onReject) { if (request.onReject) {
onReject(HTTP_BAD_GATEWAY, {}); request.onReject(HTTP_BAD_GATEWAY, {});
} }
url = "";
} }
entry->request = std::move(request);
requests.push_back(std::move(entry));
} }
void update() override { void update() override {
@ -112,15 +108,24 @@ public:
CURLMcode res = curl_multi_perform(multiHandle, &running); CURLMcode res = curl_multi_perform(multiHandle, &running);
if (res != CURLM_OK) { if (res != CURLM_OK) {
auto message = curl_multi_strerror(res); auto message = curl_multi_strerror(res);
logger.error() << message << " (" << url << ")"; logger.error() << message;
if (onReject) {
onReject(HTTP_BAD_GATEWAY, {});
}
curl_multi_remove_handle(multiHandle, curl);
url = "";
return; return;
} }
if ((msg = curl_multi_info_read(multiHandle, &messagesLeft)) != nullptr) { if ((msg = curl_multi_info_read(multiHandle, &messagesLeft)) != nullptr) {
auto curl = msg->easy_handle;
auto found = std::find_if(
requests.begin(), requests.end(),
[curl](const std::unique_ptr<ProcessingRequest>& entry) {
return entry->curl == curl;
}
);
if (found == requests.end()) {
logger.error() << "could not find request for cURL handle";
return;
}
auto& entry = *found;
auto& req = entry->request;
if(msg->msg == CURLMSG_DONE) { if(msg->msg == CURLMSG_DONE) {
curl_multi_remove_handle(multiHandle, curl); curl_multi_remove_handle(multiHandle, curl);
} }
@ -135,15 +140,15 @@ public:
if (!curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &size)) { if (!curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &size)) {
totalDownload += size; totalDownload += size;
} }
totalDownload += buffer.size(); totalDownload += entry->buffer.size();
if (onResponse) { if (req.onResponse) {
onResponse(std::move(buffer)); req.onResponse(std::move(entry->buffer));
} }
} else if (response == 0) { } else if (response == 0) {
auto message = std::string(curl_easy_strerror(result)); auto message = std::string(curl_easy_strerror(result));
logger.error() << message << " (" << url << ")"; logger.error() << message << " (" << req.url << ")";
if (onReject) { if (req.onReject) {
onReject( req.onReject(
response, response,
std::vector<char>( std::vector<char>(
message.data(), message.data() + message.size() message.data(), message.data() + message.size()
@ -152,21 +157,15 @@ public:
} }
} else { } else {
logger.error() logger.error()
<< "response code " << response << " (" << url << ")" << "response code " << response << " (" << req.url << ")"
<< (buffer.empty() << (entry->buffer.empty()
? "" ? ""
: std::to_string(buffer.size()) + " byte(s)"); : std::to_string(entry->buffer.size()) + " byte(s)");
totalDownload += buffer.size(); totalDownload += entry->buffer.size();
if (onReject) { if (req.onReject) {
onReject(response, std::move(buffer)); req.onReject(response, std::move(entry->buffer));
} }
} }
url = "";
}
if (url.empty() && !requests.empty()) {
auto request = std::move(requests.front());
requests.pop();
processRequest(std::move(request));
} }
} }
@ -181,14 +180,14 @@ public:
static std::unique_ptr<CurlRequests> create() { static std::unique_ptr<CurlRequests> create() {
auto curl = curl_easy_init(); auto curl = curl_easy_init();
if (curl == nullptr) { if (curl == nullptr) {
throw std::runtime_error("could not initialzie cURL"); throw std::runtime_error("could not initialize cURL");
} }
auto multiHandle = curl_multi_init(); auto multiHandle = curl_multi_init();
if (multiHandle == nullptr) { if (multiHandle == nullptr) {
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
throw std::runtime_error("could not initialzie cURL-multi"); throw std::runtime_error("could not initialize cURL-multi");
} }
return std::make_unique<CurlRequests>(multiHandle, curl); return std::make_unique<CurlRequests>(multiHandle);
} }
}; };