22namespace network_manager
27static const std::map<CURLcode, NetworkError>
errorsMap = {
76 const char* start = stream->Buffer + stream->Offset;
79 std::copy (start,
end, ptr);
81 stream->Offset +=
size;
88 int64_t offset = offs;
93 offset += stream->Offset;
96 offset += stream->Size;
100 if (offset < 0 || offset >= stream->Size)
101 return CURL_SEEKFUNC_FAIL;
103 stream->Offset = offset;
105 return CURL_SEEKFUNC_OK;
115 return stream->Seek(offs, origin) ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_FAIL;
123 mHandleManager (handleManager)
129 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
135 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
141 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
147 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
153 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
159 std::lock_guard<std::mutex> lock (mHeadersMutex);
160 return mResponseHeaders.hasHeader (headerName);
193 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
213 std::lock_guard<std::recursive_mutex> statusLock (
mStatusMutex);
239 if (buffer ==
nullptr || maxBytesCount == 0)
247 maxBytesCount = std::min<uint64_t> (maxBytesCount,
mDataBuffer.size ());
250 const auto end =
begin + maxBytesCount;
252 std::copy (
begin,
end,
static_cast<uint8_t*
> (buffer));
256 return maxBytesCount;
267 mForm = std::move(form);
275 handle.
setOption (CURLOPT_WRITEDATA,
this);
278 handle.
setOption (CURLOPT_HEADERDATA,
this);
281 handle.
setOption (CURLOPT_XFERINFODATA,
this);
286 handle.
setOption (CURLOPT_NOPROGRESS, 0L);
288 handle.
setOption (CURLOPT_CONNECTTIMEOUT_MS,
289 std::chrono::duration_cast<std::chrono::milliseconds> (
mRequest.
getTimeout()).count ()
295 curl_mime* mimeList =
nullptr;
297 if (
mForm !=
nullptr)
301 for (
size_t i = 0; i <
mForm->GetPartsCount(); ++i)
303 auto part =
mForm->GetPart(i);
305 curl_mimepart* curlPart = curl_mime_addpart(mimeList);
307 const auto& headers = part->GetHeaders();
309 if (headers.getHeadersCount() > 0)
311 curl_slist* partHeaders =
nullptr;
313 for (
auto header : headers)
315 partHeaders = curl_slist_append(
316 partHeaders, (header.Name +
": " + header.Value).c_str());
319 curl_mime_headers(curlPart, partHeaders, 1);
323 curlPart, part->GetSize(), curl_read_callback(
MimePartRead),
327 curl_easy_setopt(handle.
getCurlHandle(), CURLOPT_MIMEPOST, mimeList);
331 handle.
appendHeader ({
"Transfer-Encoding", std::string () });
340 handle.
setOption (CURLOPT_READDATA, &ds);
343 handle.
setOption (CURLOPT_SEEKDATA, &ds);
347 handle.
setOption (CURLOPT_POSTFIELDS,
"");
348 handle.
setOption (CURLOPT_POSTFIELDSIZE, 0);
351 auto cleanupMime =
finally(
353 if (mimeList !=
nullptr)
354 curl_mime_free(mimeList);
360 const auto result = handle.
perform ();
364 std::lock_guard<std::recursive_mutex> lock (
mStatusMutex);
366 if (result.Code != CURLE_OK)
368 const auto it =
errorsMap.find (result.Code);
397 std::lock_guard<std::recursive_mutex> lock (request->mStatusMutex);
399 if (request->mAbortRequested)
402 if (!request->mHeadersReceived)
404 request->mHeadersReceived =
true;
407 assert (request->mCurrentHandle !=
nullptr);
409 if (request->mCurrentHandle !=
nullptr)
410 request->mHttpCode = request->mCurrentHandle->getHTTPCode ();
417 std::lock_guard<std::mutex> lock (request->mDataBufferMutex);
418 request->mDataBuffer.insert (request->mDataBuffer.end (), ptr, ptr +
size);
421 std::lock_guard<std::mutex> lock (request->mCallbackMutex);
423 if (request->mOnDataReceivedCallback)
424 request->mOnDataReceivedCallback (request);
432 std::lock_guard<std::recursive_mutex> lock (request->mStatusMutex);
434 if (request->mAbortRequested)
438 assert (request->mCurrentHandle !=
nullptr);
440 if (request->mCurrentHandle !=
nullptr)
441 request->mHttpCode = request->mCurrentHandle->getHTTPCode ();
451 std::lock_guard<std::mutex> lock (request->mHeadersMutex);
460 request->mCurrentHandle->markKeepAlive ();
462 request->mResponseHeaders.addHeader (header);
469 CurlResponse* clientp, curl_off_t dltotal, curl_off_t dlnow,
470 curl_off_t ultotal, curl_off_t ulnow)
noexcept
473 std::lock_guard<std::recursive_mutex> lock(clientp->mStatusMutex);
475 if (clientp->mAbortRequested)
479 std::lock_guard<std::mutex> callbackLock(clientp->mCallbackMutex);
481 if (dltotal > 0 && clientp->mDownloadProgressCallback)
482 clientp->mDownloadProgressCallback(dlnow, dltotal);
484 if (ultotal > 0 && clientp->mUploadProgressCallback)
485 clientp->mUploadProgressCallback(ulnow, ultotal);
Declare an implementation of IResponse using libcurl.
CURL * getCurlHandle() const noexcept
CURLcode appendCookies(const CookiesList &cookie) noexcept
unsigned getHTTPCode() const noexcept
CURLcode setOption(CURLoption option, Args... value) noexcept
void appendHeader(const Header &header)
void appendHeaders(const HeadersList &headers)
Handle getHandle(RequestVerb verb, const std::string &url)
std::deque< uint8_t > mDataBuffer
virtual void setUploadProgressCallback(ProgressCallback callback) override
Set the upload progress callback.
void setForm(std::unique_ptr< MultipartData > form)
HeadersList mResponseHeaders
virtual void setDownloadProgressCallback(ProgressCallback callback) override
Set the download progress callback.
void setPayload(const void *ptr, size_t size)
static size_t WriteCallback(const uint8_t *ptr, size_t size, size_t nmemb, CurlResponse *userdata) noexcept
uint64_t getBytesAvailable() const noexcept override
const CookiesList & getCookies() const noexcept override
std::unique_ptr< MultipartData > mForm
NetworkError getError() const noexcept override
const Request & getRequest() const noexcept override
static int CurlProgressCallback(CurlResponse *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) noexcept
bool isFinished() const noexcept override
CurlHandleManager * mHandleManager
void setOnDataReceivedCallback(RequestCallback callback) override
std::mutex mDataBufferMutex
NetworkError mNetworkError
unsigned getHTTPCode() const noexcept override
CurlResponse(RequestVerb verb, const Request &request, CurlHandleManager *handleManager) noexcept
ProgressCallback mUploadProgressCallback
std::recursive_mutex mStatusMutex
std::mutex mCallbackMutex
std::string getErrorString() const override
bool hasHeader(const std::string &headerName) const noexcept override
std::string getHeader(const std::string &headerName) const override
const HeadersList & getHeaders() const noexcept override
static size_t HeaderCallback(const char *buffer, size_t size, size_t nitems, CurlResponse *userdata) noexcept
CurlHandleManager::Handle * mCurrentHandle
RequestCallback mRequestFinishedCallback
ProgressCallback mDownloadProgressCallback
void setRequestFinishedCallback(RequestCallback callback) override
void abort() noexcept override
uint64_t readData(void *buffer, uint64_t maxBytesCount) override
RequestCallback mOnDataReceivedCallback
CookiesList mResponseCookies
bool headersReceived() const noexcept override
std::string getURL() const override
std::function< void(int64_t current, int64_t expected)> ProgressCallback
std::function< void(IResponse *)> RequestCallback
virtual size_t Read(void *buffer, size_t maxBytes)=0
Timeout getTimeout() const noexcept
const HeadersList & getHeaders() const noexcept
const CookiesList & getCookies() noexcept
size_t getMaxRedirects() const noexcept
const std::string & getURL() const noexcept
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
size_t MimePartRead(char *ptr, size_t size, size_t nmemb, MultipartData::Part *stream)
int MimePartSeek(MultipartData::Part *stream, curl_off_t offs, int origin) noexcept
int DataStreamSeek(DataStream *stream, curl_off_t offs, int origin) noexcept
size_t DataStreamRead(char *ptr, size_t size, size_t nmemb, DataStream *stream) noexcept
static const std::map< CURLcode, NetworkError > errorsMap
static Cookie Parse(const std::string &cookieString)