44
55#include < cstddef>
66#include < string>
7+ #include < atomic>
8+ #include < cstdint>
9+ #include < cstring>
710
811namespace TgBot {
912
13+ namespace {
14+
15+ struct RequestCancelState {
16+ RequestCancelState (const std::atomic<bool >* const isEternalCancel, const std::atomic<uint64_t >* const globalCancelEpoch, const uint64_t currentCancelEpoch)
17+ : isEternalCancel(isEternalCancel), globalCancelEpoch(globalCancelEpoch), currentCancelEpoch(currentCancelEpoch) {}
18+
19+ const std::atomic<bool >* const isEternalCancel = nullptr ;
20+ const std::atomic<uint64_t >* const globalCancelEpoch = nullptr ;
21+ const uint64_t currentCancelEpoch = 0 ;
22+ };
23+ }
24+
1025CurlHttpClient::CurlHttpClient () : _httpParser() {
1126}
1227
@@ -35,6 +50,16 @@ static CURL* getCurlHandle(const CurlHttpClient *c_) {
3550 return it->second ;
3651}
3752
53+ static int curlProgressCallback (void * clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
54+ {
55+ const RequestCancelState* const state = static_cast <const RequestCancelState* const >(clientp);
56+ if (state && ((state->isEternalCancel && state->isEternalCancel ->load ()) || (state->globalCancelEpoch && state->currentCancelEpoch < state->globalCancelEpoch ->load ()))) {
57+ return 1 ;
58+ }
59+
60+ return 0 ;
61+ }
62+
3863static std::size_t curlWriteString (char * ptr, std::size_t size, std::size_t nmemb, void * userdata) {
3964 static_cast <std::string*>(userdata)->append (ptr, size * nmemb);
4065 return size * nmemb;
@@ -48,6 +73,12 @@ std::string CurlHttpClient::makeRequest(const Url& url, const std::vector<HttpRe
4873 curl_easy_setopt (curl, CURLOPT_TIMEOUT , _timeout);
4974 curl_easy_setopt (curl, CURLOPT_PROXY , _proxyUrl);
5075
76+ const RequestCancelState state{ &_isEternalCancel, &_cancelEpoch, _cancelEpoch.load () };
77+
78+ curl_easy_setopt (curl, CURLOPT_NOPROGRESS , 0L );
79+ curl_easy_setopt (curl, CURLOPT_XFERINFOFUNCTION , curlProgressCallback);
80+ curl_easy_setopt (curl, CURLOPT_XFERINFODATA , &state);
81+
5182 std::string u = url.protocol + " ://" + url.host + url.path ;
5283 if (args.empty ()) {
5384 u += " ?" + url.query ;
@@ -81,6 +112,12 @@ std::string CurlHttpClient::makeRequest(const Url& url, const std::vector<HttpRe
81112 auto res = curl_easy_perform (curl);
82113 curl_mime_free (mime);
83114
115+ if (res == CURLcode::CURLE_ABORTED_BY_CALLBACK && ((state.isEternalCancel && state.isEternalCancel ->load ()) || (state.globalCancelEpoch && state.currentCancelEpoch < state.globalCancelEpoch ->load ()))) {
116+ const size_t slashPos = url.path .rfind (' /' );
117+
118+ throw std::runtime_error (slashPos == std::string::npos ? getCancelExceptionText () : getCancelExceptionText () + " : " + url.path .substr (slashPos + 1 ));
119+ }
120+
84121 // If the request did not complete correctly, show the error
85122 // information. If no detailed error information was written to errbuf
86123 // show the more generic information from curl_easy_strerror instead.
0 commit comments