976 lines
36 KiB
C++
976 lines
36 KiB
C++
|
#include "cpr/session.h"
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cstdlib>
|
||
|
#include <cstring>
|
||
|
#include <fstream>
|
||
|
#include <functional>
|
||
|
#include <iostream>
|
||
|
#include <stdexcept>
|
||
|
#include <string>
|
||
|
|
||
|
#include <curl/curl.h>
|
||
|
|
||
|
#include "cpr/async.h"
|
||
|
#include "cpr/cprtypes.h"
|
||
|
#include "cpr/interceptor.h"
|
||
|
#include "cpr/util.h"
|
||
|
|
||
|
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||
|
#include "cpr/ssl_ctx.h"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
namespace cpr {
|
||
|
// Ignored here since libcurl reqires a long:
|
||
|
// NOLINTNEXTLINE(google-runtime-int)
|
||
|
constexpr long ON = 1L;
|
||
|
// Ignored here since libcurl reqires a long:
|
||
|
// NOLINTNEXTLINE(google-runtime-int)
|
||
|
constexpr long OFF = 0L;
|
||
|
|
||
|
CURLcode Session::DoEasyPerform() {
|
||
|
if (isUsedInMultiPerform) {
|
||
|
std::cerr << "curl_easy_perform cannot be executed if the CURL handle is used in a MultiPerform." << std::endl;
|
||
|
return CURLcode::CURLE_FAILED_INIT;
|
||
|
}
|
||
|
return curl_easy_perform(curl_->handle);
|
||
|
}
|
||
|
|
||
|
void Session::SetHeaderInternal() {
|
||
|
curl_slist* chunk = nullptr;
|
||
|
for (const std::pair<const std::string, std::string>& item : header_) {
|
||
|
std::string header_string = item.first;
|
||
|
if (item.second.empty()) {
|
||
|
header_string += ";";
|
||
|
} else {
|
||
|
header_string += ": " + item.second;
|
||
|
}
|
||
|
|
||
|
curl_slist* temp = curl_slist_append(chunk, header_string.c_str());
|
||
|
if (temp) {
|
||
|
chunk = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the chunked transfer encoding in case it does not already exist:
|
||
|
if (chunkedTransferEncoding_ && header_.find("Transfer-Encoding") == header_.end()) {
|
||
|
curl_slist* temp = curl_slist_append(chunk, "Transfer-Encoding:chunked");
|
||
|
if (temp) {
|
||
|
chunk = temp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// libcurl would prepare the header "Expect: 100-continue" by default when uploading files larger than 1 MB.
|
||
|
// Here we would like to disable this feature:
|
||
|
curl_slist* temp = curl_slist_append(chunk, "Expect:");
|
||
|
if (temp) {
|
||
|
chunk = temp;
|
||
|
}
|
||
|
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk);
|
||
|
|
||
|
curl_slist_free_all(curl_->chunk);
|
||
|
curl_->chunk = chunk;
|
||
|
}
|
||
|
|
||
|
// Only supported with libcurl >= 7.61.0.
|
||
|
// As an alternative use SetHeader and add the token manually.
|
||
|
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||
|
void Session::SetBearer(const Bearer& token) {
|
||
|
// Ignore here since this has been defined by libcurl.
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Session::Session() : curl_(new CurlHolder()) {
|
||
|
// Set up some sensible defaults
|
||
|
curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW);
|
||
|
const std::string version = "curl/" + std::string{version_info->version};
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str());
|
||
|
SetRedirect(Redirect());
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data());
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, "");
|
||
|
#ifdef CPR_CURL_NOSIGNAL
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L);
|
||
|
#endif
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x071900
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
Response Session::makeDownloadRequest() {
|
||
|
if (!interceptors_.empty()) {
|
||
|
return intercept();
|
||
|
}
|
||
|
|
||
|
const CURLcode curl_error = DoEasyPerform();
|
||
|
|
||
|
return CompleteDownload(curl_error);
|
||
|
}
|
||
|
|
||
|
void Session::prepareCommon() {
|
||
|
assert(curl_->handle);
|
||
|
|
||
|
// Set Header:
|
||
|
SetHeaderInternal();
|
||
|
|
||
|
const std::string parametersContent = parameters_.GetContent(*curl_);
|
||
|
if (!parametersContent.empty()) {
|
||
|
const Url new_url{url_ + "?" + parametersContent};
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
|
||
|
}
|
||
|
|
||
|
// Proxy:
|
||
|
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
|
||
|
if (proxies_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
|
||
|
if (proxyAuth_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x072100
|
||
|
if (acceptEncoding_.empty()) {
|
||
|
// Enable all supported built-in compressions
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
|
||
|
} else if (acceptEncoding_.disabled()) {
|
||
|
// Disable curl adding the 'Accept-Encoding' header
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, nullptr);
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x077100
|
||
|
#if SUPPORT_SSL_NO_REVOKE
|
||
|
// NOLINTNEXTLINE (google-runtime-int)
|
||
|
long bitmask{0};
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, &bitmask);
|
||
|
const bool noRevoke = bitmask & CURLSSLOPT_NO_REVOKE;
|
||
|
#endif
|
||
|
|
||
|
// Fix loading certs from Windows cert store when using OpenSSL:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
|
||
|
|
||
|
// Ensure SSL no revoke is still set
|
||
|
#if SUPPORT_SSL_NO_REVOKE
|
||
|
if (noRevoke) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
curl_->error[0] = '\0';
|
||
|
|
||
|
response_string_.clear();
|
||
|
if (response_string_reserve_size_ > 0) {
|
||
|
response_string_.reserve(response_string_reserve_size_);
|
||
|
}
|
||
|
header_string_.clear();
|
||
|
if (!this->writecb_.callback) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string_);
|
||
|
}
|
||
|
if (!this->headercb_.callback) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
|
||
|
}
|
||
|
|
||
|
// Enable so we are able to retrive certificate information:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L);
|
||
|
}
|
||
|
|
||
|
void Session::prepareCommonDownload() {
|
||
|
assert(curl_->handle);
|
||
|
|
||
|
// Set Header:
|
||
|
SetHeaderInternal();
|
||
|
|
||
|
const std::string parametersContent = parameters_.GetContent(*curl_);
|
||
|
if (!parametersContent.empty()) {
|
||
|
const Url new_url{url_ + "?" + parametersContent};
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
|
||
|
}
|
||
|
|
||
|
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
|
||
|
if (proxies_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
|
||
|
if (proxyAuth_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
curl_->error[0] = '\0';
|
||
|
|
||
|
header_string_.clear();
|
||
|
if (headercb_.callback) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Response Session::makeRequest() {
|
||
|
if (!interceptors_.empty()) {
|
||
|
return intercept();
|
||
|
}
|
||
|
|
||
|
const CURLcode curl_error = DoEasyPerform();
|
||
|
return Complete(curl_error);
|
||
|
}
|
||
|
|
||
|
void Session::SetLimitRate(const LimitRate& limit_rate) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate);
|
||
|
}
|
||
|
|
||
|
void Session::SetReadCallback(const ReadCallback& read) {
|
||
|
readcb_ = read;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, read.size);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_READFUNCTION, cpr::util::readUserFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_READDATA, &readcb_);
|
||
|
chunkedTransferEncoding_ = read.size == -1;
|
||
|
}
|
||
|
|
||
|
void Session::SetHeaderCallback(const HeaderCallback& header) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
|
||
|
headercb_ = header;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
|
||
|
}
|
||
|
|
||
|
void Session::SetWriteCallback(const WriteCallback& write) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction);
|
||
|
writecb_ = write;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &writecb_);
|
||
|
}
|
||
|
|
||
|
void Session::SetProgressCallback(const ProgressCallback& progress) {
|
||
|
progresscb_ = progress;
|
||
|
if (isCancellable) {
|
||
|
cancellationcb_.SetProgressCallback(progresscb_);
|
||
|
return;
|
||
|
}
|
||
|
#if LIBCURL_VERSION_NUM < 0x072000
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<ProgressCallback>);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_);
|
||
|
#else
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<ProgressCallback>);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_);
|
||
|
#endif
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
|
||
|
}
|
||
|
|
||
|
void Session::SetDebugCallback(const DebugCallback& debug) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction);
|
||
|
debugcb_ = debug;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &debugcb_);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L);
|
||
|
}
|
||
|
|
||
|
void Session::SetUrl(const Url& url) {
|
||
|
url_ = url;
|
||
|
}
|
||
|
|
||
|
void Session::SetResolve(const Resolve& resolve) {
|
||
|
SetResolves({resolve});
|
||
|
}
|
||
|
|
||
|
void Session::SetResolves(const std::vector<Resolve>& resolves) {
|
||
|
curl_slist_free_all(curl_->resolveCurlList);
|
||
|
curl_->resolveCurlList = nullptr;
|
||
|
for (const Resolve& resolve : resolves) {
|
||
|
for (const uint16_t port : resolve.ports) {
|
||
|
curl_->resolveCurlList = curl_slist_append(curl_->resolveCurlList, (resolve.host + ":" + std::to_string(port) + ":" + resolve.addr).c_str());
|
||
|
}
|
||
|
}
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_RESOLVE, curl_->resolveCurlList);
|
||
|
}
|
||
|
|
||
|
void Session::SetParameters(const Parameters& parameters) {
|
||
|
parameters_ = parameters;
|
||
|
}
|
||
|
|
||
|
void Session::SetParameters(Parameters&& parameters) {
|
||
|
parameters_ = std::move(parameters);
|
||
|
}
|
||
|
|
||
|
void Session::SetHeader(const Header& header) {
|
||
|
header_ = header;
|
||
|
}
|
||
|
|
||
|
void Session::UpdateHeader(const Header& header) {
|
||
|
for (const std::pair<const std::string, std::string>& item : header) {
|
||
|
header_[item.first] = item.second;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Session::SetTimeout(const Timeout& timeout) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds());
|
||
|
}
|
||
|
|
||
|
void Session::SetConnectTimeout(const ConnectTimeout& timeout) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds());
|
||
|
}
|
||
|
|
||
|
void Session::SetAuth(const Authentication& auth) {
|
||
|
// Ignore here since this has been defined by libcurl.
|
||
|
switch (auth.GetAuthMode()) {
|
||
|
case AuthMode::BASIC:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||
|
break;
|
||
|
case AuthMode::DIGEST:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||
|
break;
|
||
|
case AuthMode::NTLM:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Session::SetUserAgent(const UserAgent& ua) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetPayload(const Payload& payload) {
|
||
|
hasBodyOrPayload_ = true;
|
||
|
const std::string content = payload.GetContent(*curl_);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetPayload(Payload&& payload) {
|
||
|
hasBodyOrPayload_ = true;
|
||
|
const std::string content = payload.GetContent(*curl_);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetProxies(const Proxies& proxies) {
|
||
|
proxies_ = proxies;
|
||
|
}
|
||
|
|
||
|
void Session::SetProxies(Proxies&& proxies) {
|
||
|
proxies_ = std::move(proxies);
|
||
|
}
|
||
|
|
||
|
void Session::SetProxyAuth(ProxyAuthentication&& proxy_auth) {
|
||
|
proxyAuth_ = std::move(proxy_auth);
|
||
|
}
|
||
|
|
||
|
void Session::SetProxyAuth(const ProxyAuthentication& proxy_auth) {
|
||
|
proxyAuth_ = proxy_auth;
|
||
|
}
|
||
|
|
||
|
void Session::SetMultipart(const Multipart& multipart) {
|
||
|
// Make sure, we have a empty multipart to start with:
|
||
|
if (curl_->multipart) {
|
||
|
curl_mime_free(curl_->multipart);
|
||
|
}
|
||
|
curl_->multipart = curl_mime_init(curl_->handle);
|
||
|
|
||
|
// Add all multipart pieces:
|
||
|
for (const Part& part : multipart.parts) {
|
||
|
if (part.is_file) {
|
||
|
for (const File& file : part.files) {
|
||
|
curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart);
|
||
|
if (!part.content_type.empty()) {
|
||
|
curl_mime_type(mimePart, part.content_type.c_str());
|
||
|
}
|
||
|
|
||
|
curl_mime_filedata(mimePart, file.filepath.c_str());
|
||
|
curl_mime_name(mimePart, part.name.c_str());
|
||
|
|
||
|
if (file.hasOverridenFilename()) {
|
||
|
curl_mime_filename(mimePart, file.overriden_filename.c_str());
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart);
|
||
|
if (!part.content_type.empty()) {
|
||
|
curl_mime_type(mimePart, part.content_type.c_str());
|
||
|
}
|
||
|
if (part.is_buffer) {
|
||
|
// Do not use formdata, to prevent having to use reinterpreter_cast:
|
||
|
curl_mime_name(mimePart, part.name.c_str());
|
||
|
curl_mime_data(mimePart, part.data, part.datalen);
|
||
|
curl_mime_filename(mimePart, part.value.c_str());
|
||
|
} else {
|
||
|
curl_mime_name(mimePart, part.name.c_str());
|
||
|
curl_mime_data(mimePart, part.value.c_str(), CURL_ZERO_TERMINATED);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_MIMEPOST, curl_->multipart);
|
||
|
hasBodyOrPayload_ = true;
|
||
|
}
|
||
|
|
||
|
void Session::SetMultipart(Multipart&& multipart) {
|
||
|
SetMultipart(multipart);
|
||
|
}
|
||
|
|
||
|
void Session::SetRedirect(const Redirect& redirect) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, redirect.follow ? 1L : 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, redirect.maximum);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_UNRESTRICTED_AUTH, redirect.cont_send_cred ? 1L : 0L);
|
||
|
|
||
|
// NOLINTNEXTLINE (google-runtime-int)
|
||
|
long mask = 0;
|
||
|
if (any(redirect.post_flags & PostRedirectFlags::POST_301)) {
|
||
|
mask |= CURL_REDIR_POST_301;
|
||
|
}
|
||
|
if (any(redirect.post_flags & PostRedirectFlags::POST_302)) {
|
||
|
mask |= CURL_REDIR_POST_302;
|
||
|
}
|
||
|
if (any(redirect.post_flags & PostRedirectFlags::POST_303)) {
|
||
|
mask |= CURL_REDIR_POST_303;
|
||
|
}
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTREDIR, mask);
|
||
|
}
|
||
|
|
||
|
void Session::SetCookies(const Cookies& cookies) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL");
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetBody(const Body& body) {
|
||
|
hasBodyOrPayload_ = true;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetBody(Body&& body) {
|
||
|
hasBodyOrPayload_ = true;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetLowSpeed(const LowSpeed& low_speed) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, low_speed.time);
|
||
|
}
|
||
|
|
||
|
void Session::SetVerifySsl(const VerifySsl& verify) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L);
|
||
|
}
|
||
|
|
||
|
void Session::SetUnixSocket(const UnixSocket& unix_socket) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString());
|
||
|
}
|
||
|
|
||
|
void Session::SetSslOptions(const SslOptions& options) {
|
||
|
if (!options.cert_file.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str());
|
||
|
if (!options.cert_type.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str());
|
||
|
}
|
||
|
}
|
||
|
if (!options.key_file.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str());
|
||
|
if (!options.key_type.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
|
||
|
}
|
||
|
if (!options.key_pass.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
|
||
|
}
|
||
|
#if SUPPORT_CURLOPT_SSLKEY_BLOB
|
||
|
} else if (!options.key_blob.empty()) {
|
||
|
std::string key_blob(options.key_blob);
|
||
|
curl_blob blob{};
|
||
|
// NOLINTNEXTLINE (readability-container-data-pointer)
|
||
|
blob.data = &key_blob[0];
|
||
|
blob.len = key_blob.length();
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY_BLOB, &blob);
|
||
|
if (!options.key_type.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
|
||
|
}
|
||
|
if (!options.key_pass.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
if (!options.pinned_public_key.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PINNEDPUBLICKEY, options.pinned_public_key.c_str());
|
||
|
}
|
||
|
#if SUPPORT_ALPN
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF);
|
||
|
#endif
|
||
|
#if SUPPORT_NPN
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF);
|
||
|
#endif
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L);
|
||
|
#if LIBCURL_VERSION_NUM >= 0x072900
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF);
|
||
|
#endif
|
||
|
|
||
|
int maxTlsVersion = options.ssl_version;
|
||
|
#if SUPPORT_MAX_TLS_VERSION
|
||
|
maxTlsVersion |= options.max_version;
|
||
|
#endif
|
||
|
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION,
|
||
|
// Ignore here since this has been defined by libcurl.
|
||
|
maxTlsVersion);
|
||
|
#if SUPPORT_SSL_NO_REVOKE
|
||
|
if (options.ssl_no_revoke) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
|
||
|
}
|
||
|
#endif
|
||
|
if (!options.ca_info.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str());
|
||
|
}
|
||
|
if (!options.ca_path.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str());
|
||
|
}
|
||
|
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||
|
#ifdef OPENSSL_BACKEND_USED
|
||
|
if (!options.ca_buffer.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function_load_ca_cert_from_buffer);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, options.ca_buffer.c_str());
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
if (!options.crl_file.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str());
|
||
|
}
|
||
|
if (!options.ciphers.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str());
|
||
|
}
|
||
|
#if SUPPORT_TLSv13_CIPHERS
|
||
|
if (!options.tls13_ciphers.empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.ciphers.c_str());
|
||
|
}
|
||
|
#endif
|
||
|
#if SUPPORT_SESSIONID_CACHE
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, options.session_id_cache ? ON : OFF);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Session::SetVerbose(const Verbose& verbose) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF);
|
||
|
}
|
||
|
|
||
|
void Session::SetInterface(const Interface& iface) {
|
||
|
if (iface.str().empty()) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, nullptr);
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, iface.c_str());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Session::SetLocalPort(const LocalPort& local_port) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORT, local_port);
|
||
|
}
|
||
|
|
||
|
void Session::SetLocalPortRange(const LocalPortRange& local_port_range) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORTRANGE, local_port_range);
|
||
|
}
|
||
|
|
||
|
void Session::SetHttpVersion(const HttpVersion& version) {
|
||
|
switch (version.code) {
|
||
|
case HttpVersionCode::VERSION_NONE:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
|
||
|
break;
|
||
|
|
||
|
case HttpVersionCode::VERSION_1_0:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||
|
break;
|
||
|
|
||
|
case HttpVersionCode::VERSION_1_1:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||
|
break;
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0
|
||
|
case HttpVersionCode::VERSION_2_0:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0
|
||
|
case HttpVersionCode::VERSION_2_0_TLS:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0
|
||
|
case HttpVersionCode::VERSION_2_0_PRIOR_KNOWLEDGE:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0
|
||
|
case HttpVersionCode::VERSION_3_0:
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
default: // Should not happen
|
||
|
throw std::invalid_argument("Invalid/Unknown HTTP version type.");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Session::SetRange(const Range& range) {
|
||
|
const std::string range_str = range.str();
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetMultiRange(const MultiRange& multi_range) {
|
||
|
const std::string multi_range_str = multi_range.str();
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, multi_range_str.c_str());
|
||
|
}
|
||
|
|
||
|
void Session::SetReserveSize(const ReserveSize& reserve_size) {
|
||
|
ResponseStringReserve(reserve_size.size);
|
||
|
}
|
||
|
|
||
|
void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) {
|
||
|
acceptEncoding_ = accept_encoding;
|
||
|
}
|
||
|
|
||
|
void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) {
|
||
|
acceptEncoding_ = std::move(accept_encoding);
|
||
|
}
|
||
|
|
||
|
cpr_off_t Session::GetDownloadFileLength() {
|
||
|
cpr_off_t downloadFileLenth = -1;
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
|
||
|
|
||
|
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
|
||
|
if (proxies_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
|
||
|
if (proxyAuth_.has(protocol)) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1);
|
||
|
if (DoEasyPerform() == CURLE_OK) {
|
||
|
// NOLINTNEXTLINE (google-runtime-int)
|
||
|
long status_code{};
|
||
|
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code);
|
||
|
if (200 == status_code) {
|
||
|
curl_easy_getinfo(curl_->handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &downloadFileLenth);
|
||
|
}
|
||
|
}
|
||
|
return downloadFileLenth;
|
||
|
}
|
||
|
|
||
|
void Session::ResponseStringReserve(size_t size) {
|
||
|
response_string_reserve_size_ = size;
|
||
|
}
|
||
|
|
||
|
Response Session::Delete() {
|
||
|
PrepareDelete();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Download(const WriteCallback& write) {
|
||
|
PrepareDownload(write);
|
||
|
return makeDownloadRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Download(std::ofstream& file) {
|
||
|
PrepareDownload(file);
|
||
|
return makeDownloadRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Get() {
|
||
|
PrepareGet();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Head() {
|
||
|
PrepareHead();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Options() {
|
||
|
PrepareOptions();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Patch() {
|
||
|
PreparePatch();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Post() {
|
||
|
PreparePost();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::Put() {
|
||
|
PreparePut();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<Session> Session::GetSharedPtrFromThis() {
|
||
|
try {
|
||
|
return shared_from_this();
|
||
|
} catch (std::bad_weak_ptr&) {
|
||
|
throw std::runtime_error("Failed to get a shared pointer from this. The reason is probably that the session object is not managed by a shared pointer, which is required to use this functionality.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::GetAsync() {
|
||
|
auto shared_this = shared_from_this();
|
||
|
return async([shared_this]() { return shared_this->Get(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::DeleteAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Delete(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::DownloadAsync(const WriteCallback& write) {
|
||
|
return async([shared_this = GetSharedPtrFromThis(), write]() { return shared_this->Download(write); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::DownloadAsync(std::ofstream& file) {
|
||
|
return async([shared_this = GetSharedPtrFromThis(), &file]() { return shared_this->Download(file); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::HeadAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Head(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::OptionsAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Options(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::PatchAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Patch(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::PostAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Post(); });
|
||
|
}
|
||
|
|
||
|
AsyncResponse Session::PutAsync() {
|
||
|
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Put(); });
|
||
|
}
|
||
|
|
||
|
std::shared_ptr<CurlHolder> Session::GetCurlHolder() {
|
||
|
return curl_;
|
||
|
}
|
||
|
|
||
|
std::string Session::GetFullRequestUrl() {
|
||
|
const std::string parametersContent = parameters_.GetContent(*curl_);
|
||
|
return url_.str() + (parametersContent.empty() ? "" : "?") + parametersContent;
|
||
|
}
|
||
|
|
||
|
void Session::PrepareDelete() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PrepareGet() {
|
||
|
// In case there is a body or payload for this request, we create a custom GET-Request since a
|
||
|
// GET-Request with body is based on the HTTP RFC **not** a leagal request.
|
||
|
if (hasBodyOrPayload_) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET");
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L);
|
||
|
}
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PrepareHead() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PrepareOptions() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PreparePatch() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PreparePost() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
|
||
|
// In case there is no body or payload set it to an empty post:
|
||
|
if (hasBodyOrPayload_) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||
|
} else {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, readcb_.callback ? nullptr : "");
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST");
|
||
|
}
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PreparePut() {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
if (!hasBodyOrPayload_ && readcb_.callback) {
|
||
|
/**
|
||
|
* Yes, this one has to be CURLOPT_POSTFIELDS even if we are performing a PUT request.
|
||
|
* In case we don't set this one, performing a POST-request with PUT won't work.
|
||
|
* It in theory this only enforces the usage of the readcallback for POST requests, but works here as well.
|
||
|
**/
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr);
|
||
|
}
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT");
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, nullptr);
|
||
|
prepareCommon();
|
||
|
}
|
||
|
|
||
|
void Session::PrepareDownload(std::ofstream& file) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||
|
|
||
|
prepareCommonDownload();
|
||
|
}
|
||
|
|
||
|
void Session::PrepareDownload(const WriteCallback& write) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||
|
|
||
|
SetWriteCallback(write);
|
||
|
|
||
|
prepareCommonDownload();
|
||
|
}
|
||
|
|
||
|
Response Session::Complete(CURLcode curl_error) {
|
||
|
curl_slist* raw_cookies{nullptr};
|
||
|
curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
|
||
|
Cookies cookies = util::parseCookies(raw_cookies);
|
||
|
curl_slist_free_all(raw_cookies);
|
||
|
|
||
|
// Reset the has no body property:
|
||
|
hasBodyOrPayload_ = false;
|
||
|
|
||
|
std::string errorMsg = curl_->error.data();
|
||
|
return Response(curl_, std::move(response_string_), std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
|
||
|
}
|
||
|
|
||
|
Response Session::CompleteDownload(CURLcode curl_error) {
|
||
|
if (!headercb_.callback) {
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, nullptr);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, 0);
|
||
|
}
|
||
|
|
||
|
curl_slist* raw_cookies{nullptr};
|
||
|
curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
|
||
|
Cookies cookies = util::parseCookies(raw_cookies);
|
||
|
curl_slist_free_all(raw_cookies);
|
||
|
std::string errorMsg = curl_->error.data();
|
||
|
|
||
|
return Response(curl_, "", std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
|
||
|
}
|
||
|
|
||
|
void Session::AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor) {
|
||
|
interceptors_.push(pinterceptor);
|
||
|
}
|
||
|
|
||
|
Response Session::proceed() {
|
||
|
prepareCommon();
|
||
|
return makeRequest();
|
||
|
}
|
||
|
|
||
|
Response Session::intercept() {
|
||
|
// At least one interceptor exists -> Execute its intercept function
|
||
|
const std::shared_ptr<Interceptor> interceptor = interceptors_.front();
|
||
|
interceptors_.pop();
|
||
|
return interceptor->intercept(*this);
|
||
|
}
|
||
|
|
||
|
// clang-format off
|
||
|
void Session::SetOption(const Resolve& resolve) { SetResolve(resolve); }
|
||
|
void Session::SetOption(const std::vector<Resolve>& resolves) { SetResolves(resolves); }
|
||
|
void Session::SetOption(const ReadCallback& read) { SetReadCallback(read); }
|
||
|
void Session::SetOption(const HeaderCallback& header) { SetHeaderCallback(header); }
|
||
|
void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); }
|
||
|
void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); }
|
||
|
void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); }
|
||
|
void Session::SetOption(const Url& url) { SetUrl(url); }
|
||
|
void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); }
|
||
|
void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); }
|
||
|
void Session::SetOption(const Header& header) { SetHeader(header); }
|
||
|
void Session::SetOption(const Timeout& timeout) { SetTimeout(timeout); }
|
||
|
void Session::SetOption(const ConnectTimeout& timeout) { SetConnectTimeout(timeout); }
|
||
|
void Session::SetOption(const Authentication& auth) { SetAuth(auth); }
|
||
|
void Session::SetOption(const LimitRate& limit_rate) { SetLimitRate(limit_rate); }
|
||
|
// Only supported with libcurl >= 7.61.0.
|
||
|
// As an alternative use SetHeader and add the token manually.
|
||
|
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||
|
void Session::SetOption(const Bearer& auth) { SetBearer(auth); }
|
||
|
#endif
|
||
|
void Session::SetOption(const UserAgent& ua) { SetUserAgent(ua); }
|
||
|
void Session::SetOption(const Payload& payload) { SetPayload(payload); }
|
||
|
void Session::SetOption(Payload&& payload) { SetPayload(std::move(payload)); }
|
||
|
void Session::SetOption(const Proxies& proxies) { SetProxies(proxies); }
|
||
|
void Session::SetOption(Proxies&& proxies) { SetProxies(std::move(proxies)); }
|
||
|
void Session::SetOption(ProxyAuthentication&& proxy_auth) { SetProxyAuth(std::move(proxy_auth)); }
|
||
|
void Session::SetOption(const ProxyAuthentication& proxy_auth) { SetProxyAuth(proxy_auth); }
|
||
|
void Session::SetOption(const Multipart& multipart) { SetMultipart(multipart); }
|
||
|
void Session::SetOption(Multipart&& multipart) { SetMultipart(std::move(multipart)); }
|
||
|
void Session::SetOption(const Redirect& redirect) { SetRedirect(redirect); }
|
||
|
void Session::SetOption(const Cookies& cookies) { SetCookies(cookies); }
|
||
|
void Session::SetOption(const Body& body) { SetBody(body); }
|
||
|
void Session::SetOption(Body&& body) { SetBody(std::move(body)); }
|
||
|
void Session::SetOption(const LowSpeed& low_speed) { SetLowSpeed(low_speed); }
|
||
|
void Session::SetOption(const VerifySsl& verify) { SetVerifySsl(verify); }
|
||
|
void Session::SetOption(const Verbose& verbose) { SetVerbose(verbose); }
|
||
|
void Session::SetOption(const UnixSocket& unix_socket) { SetUnixSocket(unix_socket); }
|
||
|
void Session::SetOption(const SslOptions& options) { SetSslOptions(options); }
|
||
|
void Session::SetOption(const Interface& iface) { SetInterface(iface); }
|
||
|
void Session::SetOption(const LocalPort& local_port) { SetLocalPort(local_port); }
|
||
|
void Session::SetOption(const LocalPortRange& local_port_range) { SetLocalPortRange(local_port_range); }
|
||
|
void Session::SetOption(const HttpVersion& version) { SetHttpVersion(version); }
|
||
|
void Session::SetOption(const Range& range) { SetRange(range); }
|
||
|
void Session::SetOption(const MultiRange& multi_range) { SetMultiRange(multi_range); }
|
||
|
void Session::SetOption(const ReserveSize& reserve_size) { SetReserveSize(reserve_size.size); }
|
||
|
void Session::SetOption(const AcceptEncoding& accept_encoding) { SetAcceptEncoding(accept_encoding); }
|
||
|
void Session::SetOption(AcceptEncoding&& accept_encoding) { SetAcceptEncoding(accept_encoding); }
|
||
|
// clang-format on
|
||
|
|
||
|
void Session::SetCancellationParam(std::shared_ptr<std::atomic_bool> param) {
|
||
|
cancellationcb_ = CancellationCallback{std::move(param)};
|
||
|
isCancellable = true;
|
||
|
#if LIBCURL_VERSION_NUM < 0x072000
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<CancellationCallback>);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &cancellationcb_);
|
||
|
#else
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<CancellationCallback>);
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &cancellationcb_);
|
||
|
#endif
|
||
|
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
|
||
|
}
|
||
|
} // namespace cpr
|