18 #include "C4Version.h"
35 curl_multi_cleanup(MultiHandle);
36 #ifdef STDSCHEDULER_USE_EVENTS
44 MultiHandle = curl_multi_init();
45 if (!MultiHandle)
return false;
46 #ifdef STDSCHEDULER_USE_EVENTS
47 if ((Event = WSACreateEvent()) == WSA_INVALID_EVENT)
49 SetError(
"could not create socket event");
50 curl_multi_cleanup(MultiHandle);
54 curl_multi_setopt(MultiHandle, CURLMOPT_SOCKETFUNCTION, &C4HTTPClient::SSocketCallback);
55 curl_multi_setopt(MultiHandle, CURLMOPT_SOCKETDATA,
this);
62 #ifdef STDSCHEDULER_USE_EVENTS
65 if (WaitForSingleObject(Event, 0) == WAIT_OBJECT_0)
68 auto sockets_tmp = sockets;
69 for (
const auto& kv : sockets_tmp)
71 auto socket = kv.first;
72 WSANETWORKEVENTS NetworkEvents;
73 if (WSAEnumNetworkEvents(socket, Event, &NetworkEvents) !=
SOCKET_ERROR)
76 if (NetworkEvents.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE)) ev_bitmask |= CURL_CSELECT_IN;
77 if (NetworkEvents.lNetworkEvents & (FD_WRITE|FD_CONNECT)) ev_bitmask |= CURL_CSELECT_OUT;
78 curl_multi_socket_action(MultiHandle, socket, ev_bitmask, &running);
86 if (readyfd->revents & POLLIN) ev_bitmask |= CURL_CSELECT_IN;
87 if (readyfd->revents & POLLOUT) ev_bitmask |= CURL_CSELECT_OUT;
88 if (readyfd->revents & POLLERR) ev_bitmask |= CURL_CSELECT_ERR;
89 curl_multi_socket_action(MultiHandle, readyfd->fd, ev_bitmask, &running);
94 curl_multi_socket_action(MultiHandle, CURL_SOCKET_TIMEOUT, 0, &running);
100 m = curl_multi_info_read(MultiHandle, &msgq);
101 if(m && (m->msg == CURLMSG_DONE)) {
102 CURL *e = m->easy_handle;
103 assert(e == CurlHandle);
104 CurlHandle =
nullptr;
105 curl_multi_remove_handle(MultiHandle, e);
109 fSuccess = m->data.result == CURLE_OK;
111 Error.
Copy(curl_easy_strerror(m->data.result));
113 curl_easy_getinfo(e, CURLINFO_PRIMARY_IP, &ip);
118 curl_easy_cleanup(e);
128 curl_multi_timeout(MultiHandle, &timeout);
131 return tNow + timeout;
134 #ifndef STDSCHEDULER_USE_EVENTS
137 for (
const auto& kv : sockets)
145 pfd.events = POLLIN;
break;
147 pfd.events = POLLOUT;
break;
148 case CURL_POLL_INOUT:
149 pfd.events = POLLIN | POLLOUT;
break;
153 pollfds.push_back(pfd);
160 if (URL.
isNull())
return false;
167 this->fBinary = fBinary;
169 CURL *curl = curl_easy_init();
170 if (!curl)
return false;
172 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
174 curl_easy_setopt(curl, CURLOPT_URL, URL.
getData());
175 curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING,
"");
176 curl_easy_setopt(curl, CURLOPT_USERAGENT, C4ENGINENAME
"/" C4VERSION );
178 curl_slist *headers =
nullptr;
179 headers = curl_slist_append(headers,
"Accept-Charset: utf-8");
181 if (!headerAcceptedResponseType.empty())
182 headers = curl_slist_append(headers, headerAcceptedResponseType.c_str());
187 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, RequestData.
getData());
188 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, RequestData.
getSize());
191 headers = curl_slist_append(headers,
"Expect:");
192 headers = curl_slist_append(headers,
"Content-Type: text/plain; charset=utf-8");
195 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
196 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &C4HTTPClient::SWriteCallback);
197 curl_easy_setopt(curl, CURLOPT_WRITEDATA,
this);
198 curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &C4HTTPClient::SProgressCallback);
199 curl_easy_setopt(curl, CURLOPT_XFERINFODATA,
this);
203 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER,
Error.
getMData());
205 curl_multi_add_handle(MultiHandle, curl);
207 iDownloadedSize = iTotalSize = 0;
210 curl_multi_socket_action(MultiHandle, CURL_SOCKET_TIMEOUT, 0, &running);
215 size_t C4HTTPClient::SWriteCallback(
char *ptr,
size_t size,
size_t nmemb,
void *userdata)
218 return client->WriteCallback(ptr, size * nmemb);
221 size_t C4HTTPClient::WriteCallback(
char *ptr,
size_t realsize)
230 int C4HTTPClient::SProgressCallback(
void *clientp, int64_t dltotal, int64_t dlnow, int64_t ultotal, int64_t ulnow)
233 return client->ProgressCallback(dltotal, dlnow, ultotal, ulnow);
236 int C4HTTPClient::ProgressCallback(int64_t dltotal, int64_t dlnow, int64_t ultotal, int64_t ulnow)
238 iDownloadedSize = dlnow;
239 iTotalSize = dltotal;
243 int C4HTTPClient::SSocketCallback(CURL *easy, curl_socket_t
s,
int what,
void *userp,
void *socketp)
246 return client->SocketCallback(easy,
s, what, socketp);
249 int C4HTTPClient::SocketCallback(CURL *easy, curl_socket_t
s,
int what,
void *socketp)
251 #ifdef STDSCHEDULER_USE_EVENTS
256 NetworkEvents = FD_READ | FD_ACCEPT | FD_CLOSE;
break;
258 NetworkEvents = FD_WRITE | FD_CONNECT;
break;
259 case CURL_POLL_INOUT:
260 NetworkEvents = FD_READ | FD_ACCEPT | FD_CLOSE | FD_WRITE | FD_CONNECT;
break;
270 if (what == CURL_POLL_REMOVE)
281 curl_multi_remove_handle(MultiHandle, CurlHandle);
282 curl_easy_cleanup(CurlHandle);
283 CurlHandle =
nullptr;
286 iDownloadedSize = iTotalSize = 0;
300 static std::regex HostnameRegex(R
"(^(:?[a-z]+:\/\/)?([^/:]+).*)", std::regex::icase);
302 if (std::regex_match(szServerAddress, match, HostnameRegex))
305 URL.
Copy(szServerAddress);
306 ServerName.
Copy(match[2].str().c_str());
319 case C4HTTPClient::ResponseType::XML:
320 headerAcceptedResponseType =
"Accept: application/xml";
322 case C4HTTPClient::ResponseType::NoPreference:
324 headerAcceptedResponseType =
"";
const int C4HTTPQueryTimeout
StdStrBuf FormatString(const char *szFmt,...)
char LanguageEx[CFG_MaxString+1]
void SetError(const char *strnError)
void SetExpectedResponseType(ResponseType type)
bool Execute(int iMaxTime=-1, pollfd *readyfds=nullptr) override
bool SetServer(const char *szServerAddress)
bool Query(const StdBuf &Data, bool fBinary)
void GetFDs(std::vector< struct pollfd > &) override
C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow) override
StdCopyStrBuf ResultString
void Cancel(const char *szReason)
bool PushEvent(C4InteractiveEventType eEventType, void *pData=nullptr)
const void * getData() const
void Append(const void *pnData, size_t inSize)
void SetLength(size_t iLength)
const char * getData() const
void Append(const char *pnData, size_t iChars)
void SetHost(const sockaddr *addr)