mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-06-16 15:17:13 +02:00
Reinstate CPR using system library.
This commit is contained in:
7
vendor/CPR/cpr/auth.cpp
vendored
Normal file
7
vendor/CPR/cpr/auth.cpp
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
#include "cpr/auth.h"
|
||||
|
||||
namespace cpr {
|
||||
const char* Authentication::GetAuthString() const noexcept {
|
||||
return auth_string_.c_str();
|
||||
}
|
||||
} // namespace cpr
|
11
vendor/CPR/cpr/bearer.cpp
vendored
Normal file
11
vendor/CPR/cpr/bearer.cpp
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include "cpr/bearer.h"
|
||||
|
||||
namespace cpr {
|
||||
// Only supported with libcurl >= 7.61.0.
|
||||
// As an alternative use SetHeader and add the token manually.
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
const char* Bearer::GetToken() const noexcept {
|
||||
return token_string_.c_str();
|
||||
}
|
||||
#endif
|
||||
} // namespace cpr
|
51
vendor/CPR/cpr/cookies.cpp
vendored
Normal file
51
vendor/CPR/cpr/cookies.cpp
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#include "cpr/cookies.h"
|
||||
|
||||
namespace cpr {
|
||||
std::string Cookies::GetEncoded(const CurlHolder& holder) const {
|
||||
std::stringstream stream;
|
||||
for (const std::pair<const std::string, std::string>& item : map_) {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.first) : item.first) << "=";
|
||||
|
||||
// special case version 1 cookies, which can be distinguished by
|
||||
// beginning and trailing quotes
|
||||
if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') {
|
||||
stream << item.second;
|
||||
} else {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.second) : item.second);
|
||||
}
|
||||
stream << "; ";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string& Cookies::operator[](const std::string& key) {
|
||||
return map_[key];
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::begin() {
|
||||
return map_.begin();
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::end() {
|
||||
return map_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::begin() const {
|
||||
return map_.begin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::end() const {
|
||||
return map_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cbegin() const {
|
||||
return map_.cbegin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cend() const {
|
||||
return map_.cend();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
12
vendor/CPR/cpr/cprtypes.cpp
vendored
Normal file
12
vendor/CPR/cpr/cprtypes.cpp
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#include "cpr/cprtypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace cpr {
|
||||
bool CaseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept {
|
||||
return std::lexicographical_compare(
|
||||
a.begin(), a.end(), b.begin(), b.end(),
|
||||
[](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); });
|
||||
}
|
||||
} // namespace cpr
|
59
vendor/CPR/cpr/curl_container.cpp
vendored
Normal file
59
vendor/CPR/cpr/curl_container.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#include "cpr/curl_container.h"
|
||||
|
||||
|
||||
namespace cpr {
|
||||
template <class T>
|
||||
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList)
|
||||
: containerList_(containerList) {}
|
||||
|
||||
template <class T>
|
||||
void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) {
|
||||
for (const T& element : containerList) {
|
||||
containerList_.push_back(std::move(element));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void CurlContainer<T>::Add(const T& element) {
|
||||
containerList_.push_back(std::move(element));
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::string CurlContainer<Parameter>::GetContent(const CurlHolder& holder) const {
|
||||
std::string content{};
|
||||
for (const Parameter& parameter : containerList_) {
|
||||
if (!content.empty()) {
|
||||
content += "&";
|
||||
}
|
||||
|
||||
std::string escapedKey = encode ? holder.urlEncode(parameter.key) : parameter.key;
|
||||
if (parameter.value.empty()) {
|
||||
content += escapedKey;
|
||||
} else {
|
||||
std::string escapedValue = encode ? holder.urlEncode(parameter.value) : parameter.value;
|
||||
content += escapedKey + "=";
|
||||
content += escapedValue;
|
||||
}
|
||||
};
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
template <>
|
||||
const std::string CurlContainer<Pair>::GetContent(const CurlHolder& holder) const {
|
||||
std::string content{};
|
||||
for (const cpr::Pair& element : containerList_) {
|
||||
if (!content.empty()) {
|
||||
content += "&";
|
||||
}
|
||||
std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
|
||||
content += element.key + "=" + escaped;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
template class CurlContainer<Pair>;
|
||||
template class CurlContainer<Parameter>;
|
||||
|
||||
} // namespace cpr
|
54
vendor/CPR/cpr/curlholder.cpp
vendored
Normal file
54
vendor/CPR/cpr/curlholder.cpp
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
#include "cpr/curlholder.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace cpr {
|
||||
// It does not make sense to make a std::mutex const.
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::mutex CurlHolder::curl_easy_init_mutex_{};
|
||||
|
||||
#ifndef _WIN32 // There is no thread sanitizer on windows
|
||||
__attribute__((no_sanitize("thread")))
|
||||
#endif
|
||||
CurlHolder::CurlHolder() {
|
||||
/**
|
||||
* Allow multithreaded access to CPR by locking curl_easy_init().
|
||||
* curl_easy_init() is not thread safe.
|
||||
* References:
|
||||
* https://curl.haxx.se/libcurl/c/curl_easy_init.html
|
||||
* https://curl.haxx.se/libcurl/c/threadsafe.html
|
||||
**/
|
||||
curl_easy_init_mutex_.lock();
|
||||
handle = curl_easy_init();
|
||||
curl_easy_init_mutex_.unlock();
|
||||
|
||||
assert(handle);
|
||||
} // namespace cpr
|
||||
|
||||
CurlHolder::~CurlHolder() {
|
||||
curl_easy_cleanup(handle);
|
||||
curl_slist_free_all(chunk);
|
||||
curl_formfree(formpost);
|
||||
}
|
||||
|
||||
std::string CurlHolder::urlEncode(const std::string& s) const {
|
||||
assert(handle);
|
||||
char* output = curl_easy_escape(handle, s.c_str(), s.length());
|
||||
if (output) {
|
||||
std::string result = output;
|
||||
curl_free(output);
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CurlHolder::urlDecode(const std::string& s) const {
|
||||
assert(handle);
|
||||
char* output = curl_easy_unescape(handle, s.c_str(), s.length(), nullptr);
|
||||
if (output) {
|
||||
std::string result = output;
|
||||
curl_free(output);
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
} // namespace cpr
|
68
vendor/CPR/cpr/error.cpp
vendored
Normal file
68
vendor/CPR/cpr/error.cpp
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
#include "cpr/error.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace cpr {
|
||||
ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
|
||||
switch (curl_code) {
|
||||
case CURLE_OK:
|
||||
return ErrorCode::OK;
|
||||
case CURLE_UNSUPPORTED_PROTOCOL:
|
||||
return ErrorCode::UNSUPPORTED_PROTOCOL;
|
||||
case CURLE_URL_MALFORMAT:
|
||||
return ErrorCode::INVALID_URL_FORMAT;
|
||||
case CURLE_COULDNT_RESOLVE_PROXY:
|
||||
return ErrorCode::PROXY_RESOLUTION_FAILURE;
|
||||
case CURLE_COULDNT_RESOLVE_HOST:
|
||||
return ErrorCode::HOST_RESOLUTION_FAILURE;
|
||||
case CURLE_COULDNT_CONNECT:
|
||||
return ErrorCode::CONNECTION_FAILURE;
|
||||
case CURLE_OPERATION_TIMEDOUT:
|
||||
return ErrorCode::OPERATION_TIMEDOUT;
|
||||
case CURLE_SSL_CONNECT_ERROR:
|
||||
return ErrorCode::SSL_CONNECT_ERROR;
|
||||
#if LIBCURL_VERSION_NUM < 0x073e00
|
||||
case CURLE_PEER_FAILED_VERIFICATION:
|
||||
return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR;
|
||||
#endif
|
||||
case CURLE_ABORTED_BY_CALLBACK:
|
||||
case CURLE_WRITE_ERROR:
|
||||
return ErrorCode::REQUEST_CANCELLED;
|
||||
case CURLE_GOT_NOTHING:
|
||||
return ErrorCode::EMPTY_RESPONSE;
|
||||
case CURLE_SSL_ENGINE_NOTFOUND:
|
||||
case CURLE_SSL_ENGINE_SETFAILED:
|
||||
return ErrorCode::GENERIC_SSL_ERROR;
|
||||
case CURLE_SEND_ERROR:
|
||||
return ErrorCode::NETWORK_SEND_FAILURE;
|
||||
case CURLE_RECV_ERROR:
|
||||
return ErrorCode::NETWORK_RECEIVE_ERROR;
|
||||
case CURLE_SSL_CERTPROBLEM:
|
||||
return ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR;
|
||||
case CURLE_SSL_CIPHER:
|
||||
return ErrorCode::GENERIC_SSL_ERROR;
|
||||
#if LIBCURL_VERSION_NUM >= 0x073e00
|
||||
case CURLE_PEER_FAILED_VERIFICATION:
|
||||
return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR;
|
||||
#else
|
||||
case CURLE_SSL_CACERT:
|
||||
return ErrorCode::SSL_CACERT_ERROR;
|
||||
#endif
|
||||
case CURLE_USE_SSL_FAILED:
|
||||
case CURLE_SSL_ENGINE_INITFAILED:
|
||||
return ErrorCode::GENERIC_SSL_ERROR;
|
||||
case CURLE_SSL_CACERT_BADFILE:
|
||||
return ErrorCode::SSL_CACERT_ERROR;
|
||||
case CURLE_SSL_SHUTDOWN_FAILED:
|
||||
return ErrorCode::GENERIC_SSL_ERROR;
|
||||
case CURLE_SSL_CRL_BADFILE:
|
||||
case CURLE_SSL_ISSUER_ERROR:
|
||||
return ErrorCode::SSL_CACERT_ERROR;
|
||||
case CURLE_TOO_MANY_REDIRECTS:
|
||||
return ErrorCode::OK;
|
||||
default:
|
||||
return ErrorCode::INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpr
|
5
vendor/CPR/cpr/multipart.cpp
vendored
Normal file
5
vendor/CPR/cpr/multipart.cpp
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#include "cpr/multipart.h"
|
||||
|
||||
namespace cpr {
|
||||
Multipart::Multipart(const std::initializer_list<Part>& parts) : parts{parts} {}
|
||||
} // namespace cpr
|
10
vendor/CPR/cpr/parameters.cpp
vendored
Normal file
10
vendor/CPR/cpr/parameters.cpp
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include "cpr/parameters.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Parameters::Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
|
||||
} // namespace cpr
|
10
vendor/CPR/cpr/payload.cpp
vendored
Normal file
10
vendor/CPR/cpr/payload.cpp
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include "cpr/payload.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Payload::Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
|
||||
} // namespace cpr
|
21
vendor/CPR/cpr/proxies.cpp
vendored
Normal file
21
vendor/CPR/cpr/proxies.cpp
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
#include "cpr/proxies.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts)
|
||||
: hosts_{hosts} {}
|
||||
|
||||
bool Proxies::has(const std::string& protocol) const {
|
||||
return hosts_.count(protocol) > 0;
|
||||
}
|
||||
|
||||
const std::string& Proxies::operator[](const std::string& protocol) {
|
||||
return hosts_[protocol];
|
||||
}
|
||||
|
||||
} // namespace cpr
|
46
vendor/CPR/cpr/response.cpp
vendored
Normal file
46
vendor/CPR/cpr/response.cpp
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
#include "cpr/response.h"
|
||||
|
||||
namespace cpr {
|
||||
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
|
||||
std::string&& p_header_string, Cookies&& p_cookies = Cookies{},
|
||||
Error&& p_error = Error{})
|
||||
: curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)),
|
||||
error(std::move(p_error)) {
|
||||
header = cpr::util::parseHeader(p_header_string, &status_line, &reason);
|
||||
assert(curl_);
|
||||
assert(curl_->handle);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_TOTAL_TIME, &elapsed);
|
||||
char* url_string{nullptr};
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string);
|
||||
url = Url(url_string);
|
||||
#if LIBCURL_VERSION_NUM >= 0x073700
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes);
|
||||
#else
|
||||
double downloaded_bytes_double, uploaded_bytes_double;
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD, &downloaded_bytes_double);
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD, &uploaded_bytes_double);
|
||||
downloaded_bytes = downloaded_bytes_double;
|
||||
uploaded_bytes = uploaded_bytes_double;
|
||||
#endif
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_REDIRECT_COUNT, &redirect_count);
|
||||
}
|
||||
|
||||
std::vector<std::string> Response::GetCertInfo() {
|
||||
assert(curl_);
|
||||
assert(curl_->handle);
|
||||
curl_certinfo* ci{nullptr};
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
|
||||
|
||||
std::vector<std::string> info;
|
||||
info.resize(ci->num_of_certs);
|
||||
for (size_t i = 0; i < ci->num_of_certs; i++) {
|
||||
// No way around here.
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
info[i] = std::string{ci->certinfo[i]->data};
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
} // namespace cpr
|
740
vendor/CPR/cpr/session.cpp
vendored
Normal file
740
vendor/CPR/cpr/session.cpp
vendored
Normal file
@ -0,0 +1,740 @@
|
||||
#include "cpr/session.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "cpr/cprtypes.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
|
||||
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;
|
||||
|
||||
class Session::Impl {
|
||||
public:
|
||||
Impl();
|
||||
|
||||
void SetUrl(const Url& url);
|
||||
void SetParameters(const Parameters& parameters);
|
||||
void SetParameters(Parameters&& parameters);
|
||||
void SetHeader(const Header& header);
|
||||
void UpdateHeader(const Header& header);
|
||||
void SetTimeout(const Timeout& timeout);
|
||||
void SetConnectTimeout(const ConnectTimeout& timeout);
|
||||
void SetAuth(const Authentication& auth);
|
||||
// Only supported with libcurl >= 7.61.0.
|
||||
// As an alternative use SetHeader and add the token manually.
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
void SetBearer(const Bearer& token);
|
||||
#endif
|
||||
void SetDigest(const Digest& auth);
|
||||
void SetUserAgent(const UserAgent& ua);
|
||||
void SetPayload(Payload&& payload);
|
||||
void SetPayload(const Payload& payload);
|
||||
void SetProxies(Proxies&& proxies);
|
||||
void SetProxies(const Proxies& proxies);
|
||||
void SetMultipart(Multipart&& multipart);
|
||||
void SetMultipart(const Multipart& multipart);
|
||||
void SetNTLM(const NTLM& auth);
|
||||
void SetRedirect(const bool& redirect);
|
||||
void SetMaxRedirects(const MaxRedirects& max_redirects);
|
||||
void SetCookies(const Cookies& cookies);
|
||||
void SetBody(Body&& body);
|
||||
void SetBody(const Body& body);
|
||||
void SetReadCallback(const ReadCallback& read);
|
||||
void SetHeaderCallback(const HeaderCallback& header);
|
||||
void SetWriteCallback(const WriteCallback& write);
|
||||
void SetProgressCallback(const ProgressCallback& progress);
|
||||
void SetDebugCallback(const DebugCallback& debug);
|
||||
void SetLowSpeed(const LowSpeed& low_speed);
|
||||
void SetVerifySsl(const VerifySsl& verify);
|
||||
void SetLimitRate(const LimitRate& limit_rate);
|
||||
void SetUnixSocket(const UnixSocket& unix_socket);
|
||||
void SetVerbose(const Verbose& verbose);
|
||||
void SetSslOptions(const SslOptions& options);
|
||||
|
||||
Response Delete();
|
||||
Response Download(const WriteCallback& write);
|
||||
Response Download(std::ofstream& file);
|
||||
Response Get();
|
||||
Response Head();
|
||||
Response Options();
|
||||
Response Patch();
|
||||
Response Post();
|
||||
Response Put();
|
||||
|
||||
std::shared_ptr<CurlHolder> GetCurlHolder();
|
||||
|
||||
private:
|
||||
void SetHeaderInternal();
|
||||
bool hasBodyOrPayload_{false};
|
||||
|
||||
std::shared_ptr<CurlHolder> curl_;
|
||||
Url url_;
|
||||
Parameters parameters_;
|
||||
Proxies proxies_;
|
||||
Header header_;
|
||||
/**
|
||||
* Will be set by the read callback.
|
||||
* Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_.
|
||||
**/
|
||||
bool chunkedTransferEncoding{false};
|
||||
|
||||
ReadCallback readcb_;
|
||||
HeaderCallback headercb_;
|
||||
WriteCallback writecb_;
|
||||
ProgressCallback progresscb_;
|
||||
DebugCallback debugcb_;
|
||||
|
||||
Response makeDownloadRequest();
|
||||
Response makeRequest();
|
||||
static void freeHolder(CurlHolder* holder);
|
||||
};
|
||||
|
||||
Session::Impl::Impl() : curl_(new CurlHolder()) {
|
||||
// Set up some sensible defaults
|
||||
curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW);
|
||||
std::string version = "curl/" + std::string{version_info->version};
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str());
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, 50L);
|
||||
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_MAJOR >= 7
|
||||
#if LIBCURL_VERSION_MINOR >= 25
|
||||
#if LIBCURL_VERSION_PATCH >= 0
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void Session::Impl::SetUrl(const Url& url) {
|
||||
url_ = url;
|
||||
}
|
||||
|
||||
void Session::Impl::SetParameters(const Parameters& parameters) {
|
||||
parameters_ = parameters;
|
||||
}
|
||||
|
||||
void Session::Impl::SetParameters(Parameters&& parameters) {
|
||||
parameters_ = std::move(parameters);
|
||||
}
|
||||
|
||||
void Session::Impl::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;
|
||||
}
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk);
|
||||
|
||||
curl_slist_free_all(curl_->chunk);
|
||||
curl_->chunk = chunk;
|
||||
}
|
||||
|
||||
void Session::Impl::SetHeader(const Header& header) {
|
||||
header_ = header;
|
||||
}
|
||||
|
||||
void Session::Impl::UpdateHeader(const Header& header) {
|
||||
for (const std::pair<const std::string, std::string>& item : header) {
|
||||
header_[item.first] = item.second;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::Impl::SetTimeout(const Timeout& timeout) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds());
|
||||
}
|
||||
|
||||
void Session::Impl::SetConnectTimeout(const ConnectTimeout& timeout) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds());
|
||||
}
|
||||
|
||||
void Session::Impl::SetVerbose(const Verbose& verbose) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF);
|
||||
}
|
||||
|
||||
void Session::Impl::SetAuth(const Authentication& auth) {
|
||||
// Ignore here since this has been defined by libcurl.
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||||
}
|
||||
|
||||
// Only supported with libcurl >= 7.61.0.
|
||||
// As an alternative use SetHeader and add the token manually.
|
||||
#if LIBCURL_VERSION_NUM >= 0x073D00
|
||||
void Session::Impl::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
|
||||
|
||||
void Session::Impl::SetDigest(const Digest& auth) {
|
||||
// Ignore here since this has been defined by libcurl.
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||||
}
|
||||
|
||||
void Session::Impl::SetUserAgent(const UserAgent& ua) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str());
|
||||
}
|
||||
|
||||
void Session::Impl::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::Impl::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::Impl::SetProxies(const Proxies& proxies) {
|
||||
proxies_ = proxies;
|
||||
}
|
||||
|
||||
void Session::Impl::SetProxies(Proxies&& proxies) {
|
||||
proxies_ = std::move(proxies);
|
||||
}
|
||||
|
||||
void Session::Impl::SetMultipart(Multipart&& multipart) {
|
||||
curl_httppost* formpost = nullptr;
|
||||
curl_httppost* lastptr = nullptr;
|
||||
|
||||
for (const Part& part : multipart.parts) {
|
||||
std::vector<curl_forms> formdata;
|
||||
if (part.is_buffer) {
|
||||
// Do not use formdata, to prevent having to use reinterpreter_cast:
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, part.name.c_str(), CURLFORM_BUFFER,
|
||||
part.value.c_str(), CURLFORM_BUFFERPTR, part.data, CURLFORM_BUFFERLENGTH,
|
||||
part.datalen, CURLFORM_END);
|
||||
} else {
|
||||
formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
|
||||
if (part.is_file) {
|
||||
formdata.push_back({CURLFORM_FILE, part.value.c_str()});
|
||||
} else {
|
||||
formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()});
|
||||
}
|
||||
}
|
||||
if (!part.content_type.empty()) {
|
||||
formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
|
||||
}
|
||||
|
||||
formdata.push_back({CURLFORM_END, nullptr});
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
|
||||
}
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost);
|
||||
hasBodyOrPayload_ = true;
|
||||
|
||||
curl_formfree(curl_->formpost);
|
||||
curl_->formpost = formpost;
|
||||
}
|
||||
|
||||
void Session::Impl::SetMultipart(const Multipart& multipart) {
|
||||
curl_httppost* formpost = nullptr;
|
||||
curl_httppost* lastptr = nullptr;
|
||||
|
||||
for (const Part& part : multipart.parts) {
|
||||
std::vector<curl_forms> formdata;
|
||||
if (part.is_buffer) {
|
||||
// Do not use formdata, to prevent having to use reinterpreter_cast:
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, part.name.c_str(), CURLFORM_BUFFER,
|
||||
part.value.c_str(), CURLFORM_BUFFERPTR, part.data, CURLFORM_BUFFERLENGTH,
|
||||
part.datalen, CURLFORM_END);
|
||||
} else {
|
||||
formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
|
||||
if (part.is_file) {
|
||||
formdata.push_back({CURLFORM_FILE, part.value.c_str()});
|
||||
} else {
|
||||
formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()});
|
||||
}
|
||||
}
|
||||
if (!part.content_type.empty()) {
|
||||
formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
|
||||
}
|
||||
|
||||
formdata.push_back({CURLFORM_END, nullptr});
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
|
||||
}
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost);
|
||||
hasBodyOrPayload_ = true;
|
||||
|
||||
curl_formfree(curl_->formpost);
|
||||
curl_->formpost = formpost;
|
||||
}
|
||||
|
||||
void Session::Impl::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::Impl::SetNTLM(const NTLM& auth) {
|
||||
// Ignore here since this has been defined by libcurl.
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
|
||||
}
|
||||
|
||||
void Session::Impl::SetRedirect(const bool& redirect) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, std::int32_t(redirect));
|
||||
}
|
||||
|
||||
void Session::Impl::SetMaxRedirects(const MaxRedirects& max_redirects) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, max_redirects.number_of_redirects);
|
||||
}
|
||||
|
||||
void Session::Impl::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::Impl::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::Impl::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::Impl::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::Impl::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::Impl::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::Impl::SetProgressCallback(const ProgressCallback& progress) {
|
||||
progresscb_ = progress;
|
||||
#if LIBCURL_VERSION_NUM < 0x072000
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_);
|
||||
#else
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_);
|
||||
#endif
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
void Session::Impl::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::Impl::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::Impl::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::Impl::SetUnixSocket(const UnixSocket& unix_socket) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString());
|
||||
}
|
||||
|
||||
void Session::Impl::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_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
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION,
|
||||
// Ignore here since this has been defined by libcurl.
|
||||
options.ssl_version
|
||||
#if SUPPORT_MAX_TLS_VERSION
|
||||
| options.max_version
|
||||
#endif
|
||||
);
|
||||
#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 (!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
|
||||
}
|
||||
|
||||
Response Session::Impl::Delete() {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Download(const WriteCallback& write) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET");
|
||||
|
||||
SetWriteCallback(write);
|
||||
|
||||
return makeDownloadRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Download(std::ofstream& file) {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET");
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file);
|
||||
|
||||
return makeDownloadRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Get() {
|
||||
// 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);
|
||||
}
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Head() {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Options() {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Patch() {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Post() {
|
||||
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");
|
||||
}
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
Response Session::Impl::Put() {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT");
|
||||
|
||||
return makeRequest();
|
||||
}
|
||||
|
||||
std::shared_ptr<CurlHolder> Session::Impl::GetCurlHolder() {
|
||||
return curl_;
|
||||
}
|
||||
|
||||
Response Session::Impl::makeDownloadRequest() {
|
||||
assert(curl_->handle);
|
||||
const std::string parametersContent = parameters_.GetContent(*curl_);
|
||||
if (!parametersContent.empty()) {
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
} else {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, "");
|
||||
}
|
||||
|
||||
curl_->error[0] = '\0';
|
||||
|
||||
std::string header_string;
|
||||
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);
|
||||
}
|
||||
|
||||
CURLcode curl_error = curl_easy_perform(curl_->handle);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
Response Session::Impl::makeRequest() {
|
||||
assert(curl_->handle);
|
||||
|
||||
// Set Header:
|
||||
SetHeaderInternal();
|
||||
|
||||
const std::string parametersContent = parameters_.GetContent(*curl_);
|
||||
if (!parametersContent.empty()) {
|
||||
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:
|
||||
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());
|
||||
} else {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, nullptr);
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_MAJOR >= 7
|
||||
#if LIBCURL_VERSION_MINOR >= 21
|
||||
/* enable all supported built-in compressions */
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if LIBCURL_VERSION_MAJOR >= 7
|
||||
#if LIBCURL_VERSION_MINOR >= 71
|
||||
// Fix loading certs from Windows cert store when using OpenSSL:
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
curl_->error[0] = '\0';
|
||||
|
||||
std::string response_string;
|
||||
std::string header_string;
|
||||
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);
|
||||
|
||||
CURLcode curl_error = curl_easy_perform(curl_->handle);
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
Session::Session() : pimpl_(new Impl()) {}
|
||||
Session::~Session() = default;
|
||||
void Session::SetReadCallback(const ReadCallback& read) { pimpl_->SetReadCallback(read); }
|
||||
void Session::SetHeaderCallback(const HeaderCallback& header) { pimpl_->SetHeaderCallback(header); }
|
||||
void Session::SetWriteCallback(const WriteCallback& write) { pimpl_->SetWriteCallback(write); }
|
||||
void Session::SetProgressCallback(const ProgressCallback& progress) { pimpl_->SetProgressCallback(progress); }
|
||||
void Session::SetUrl(const Url& url) { pimpl_->SetUrl(url); }
|
||||
void Session::SetParameters(const Parameters& parameters) { pimpl_->SetParameters(parameters); }
|
||||
void Session::SetParameters(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); }
|
||||
void Session::SetHeader(const Header& header) { pimpl_->SetHeader(header); }
|
||||
void Session::UpdateHeader(const Header& header) { pimpl_->UpdateHeader(header); }
|
||||
void Session::SetTimeout(const Timeout& timeout) { pimpl_->SetTimeout(timeout); }
|
||||
void Session::SetConnectTimeout(const ConnectTimeout& timeout) { pimpl_->SetConnectTimeout(timeout); }
|
||||
void Session::SetAuth(const Authentication& auth) { pimpl_->SetAuth(auth); }
|
||||
void Session::SetDigest(const Digest& auth) { pimpl_->SetDigest(auth); }
|
||||
void Session::SetUserAgent(const UserAgent& ua) { pimpl_->SetUserAgent(ua); }
|
||||
void Session::SetPayload(const Payload& payload) { pimpl_->SetPayload(payload); }
|
||||
void Session::SetPayload(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); }
|
||||
void Session::SetProxies(const Proxies& proxies) { pimpl_->SetProxies(proxies); }
|
||||
void Session::SetProxies(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); }
|
||||
void Session::SetMultipart(const Multipart& multipart) { pimpl_->SetMultipart(multipart); }
|
||||
void Session::SetMultipart(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); }
|
||||
void Session::SetNTLM(const NTLM& auth) { pimpl_->SetNTLM(auth); }
|
||||
void Session::SetRedirect(const bool& redirect) { pimpl_->SetRedirect(redirect); }
|
||||
void Session::SetMaxRedirects(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); }
|
||||
void Session::SetCookies(const Cookies& cookies) { pimpl_->SetCookies(cookies); }
|
||||
void Session::SetBody(const Body& body) { pimpl_->SetBody(body); }
|
||||
void Session::SetBody(Body&& body) { pimpl_->SetBody(std::move(body)); }
|
||||
void Session::SetLowSpeed(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); }
|
||||
void Session::SetVerifySsl(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); }
|
||||
void Session::SetUnixSocket(const UnixSocket& unix_socket) { pimpl_->SetUnixSocket(unix_socket); }
|
||||
void Session::SetSslOptions(const SslOptions& options) { pimpl_->SetSslOptions(options); }
|
||||
void Session::SetVerbose(const Verbose& verbose) { pimpl_->SetVerbose(verbose); }
|
||||
void Session::SetOption(const ReadCallback& read) { pimpl_->SetReadCallback(read); }
|
||||
void Session::SetOption(const HeaderCallback& header) { pimpl_->SetHeaderCallback(header); }
|
||||
void Session::SetOption(const WriteCallback& write) { pimpl_->SetWriteCallback(write); }
|
||||
void Session::SetOption(const ProgressCallback& progress) { pimpl_->SetProgressCallback(progress); }
|
||||
void Session::SetOption(const DebugCallback& debug) { pimpl_->SetDebugCallback(debug); }
|
||||
void Session::SetOption(const Url& url) { pimpl_->SetUrl(url); }
|
||||
void Session::SetOption(const Parameters& parameters) { pimpl_->SetParameters(parameters); }
|
||||
void Session::SetOption(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); }
|
||||
void Session::SetOption(const Header& header) { pimpl_->SetHeader(header); }
|
||||
void Session::SetOption(const Timeout& timeout) { pimpl_->SetTimeout(timeout); }
|
||||
void Session::SetOption(const ConnectTimeout& timeout) { pimpl_->SetConnectTimeout(timeout); }
|
||||
void Session::SetOption(const Authentication& auth) { pimpl_->SetAuth(auth); }
|
||||
void Session::SetOption(const LimitRate& limit_rate) { pimpl_->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) { pimpl_->SetBearer(auth); }
|
||||
#endif
|
||||
void Session::SetOption(const Digest& auth) { pimpl_->SetDigest(auth); }
|
||||
void Session::SetOption(const UserAgent& ua) { pimpl_->SetUserAgent(ua); }
|
||||
void Session::SetOption(const Payload& payload) { pimpl_->SetPayload(payload); }
|
||||
void Session::SetOption(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); }
|
||||
void Session::SetOption(const Proxies& proxies) { pimpl_->SetProxies(proxies); }
|
||||
void Session::SetOption(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); }
|
||||
void Session::SetOption(const Multipart& multipart) { pimpl_->SetMultipart(multipart); }
|
||||
void Session::SetOption(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); }
|
||||
void Session::SetOption(const NTLM& auth) { pimpl_->SetNTLM(auth); }
|
||||
void Session::SetOption(const bool& redirect) { pimpl_->SetRedirect(redirect); }
|
||||
void Session::SetOption(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); }
|
||||
void Session::SetOption(const Cookies& cookies) { pimpl_->SetCookies(cookies); }
|
||||
void Session::SetOption(const Body& body) { pimpl_->SetBody(body); }
|
||||
void Session::SetOption(Body&& body) { pimpl_->SetBody(std::move(body)); }
|
||||
void Session::SetOption(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); }
|
||||
void Session::SetOption(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); }
|
||||
void Session::SetOption(const Verbose& verbose) { pimpl_->SetVerbose(verbose); }
|
||||
void Session::SetOption(const UnixSocket& unix_socket) { pimpl_->SetUnixSocket(unix_socket); }
|
||||
void Session::SetOption(const SslOptions& options) { pimpl_->SetSslOptions(options); }
|
||||
|
||||
Response Session::Delete() { return pimpl_->Delete(); }
|
||||
Response Session::Download(const WriteCallback& write) { return pimpl_->Download(write); }
|
||||
Response Session::Download(std::ofstream& file) { return pimpl_->Download(file); }
|
||||
Response Session::Get() { return pimpl_->Get(); }
|
||||
Response Session::Head() { return pimpl_->Head(); }
|
||||
Response Session::Options() { return pimpl_->Options(); }
|
||||
Response Session::Patch() { return pimpl_->Patch(); }
|
||||
Response Session::Post() { return pimpl_->Post(); }
|
||||
Response Session::Put() { return pimpl_->Put(); }
|
||||
|
||||
std::shared_ptr<CurlHolder> Session::GetCurlHolder() { return pimpl_->GetCurlHolder(); }
|
||||
// clang-format on
|
||||
} // namespace cpr
|
34
vendor/CPR/cpr/timeout.cpp
vendored
Normal file
34
vendor/CPR/cpr/timeout.cpp
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
#include "cpr/timeout.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
long Timeout::Milliseconds() const {
|
||||
static_assert(std::is_same<std::chrono::milliseconds, decltype(ms)>::value,
|
||||
"Following casting expects milliseconds.");
|
||||
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
if (ms.count() > std::numeric_limits<long>::max()) {
|
||||
throw std::overflow_error(
|
||||
"cpr::Timeout: timeout value overflow: " + std::to_string(ms.count()) + " ms.");
|
||||
}
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
if (ms.count() < std::numeric_limits<long>::min()) {
|
||||
throw std::underflow_error(
|
||||
"cpr::Timeout: timeout value underflow: " + std::to_string(ms.count()) + " ms.");
|
||||
}
|
||||
|
||||
// No way around since curl uses a long here.
|
||||
// NOLINTNEXTLINE(google-runtime-int)
|
||||
return static_cast<long>(ms.count());
|
||||
}
|
||||
|
||||
} // namespace cpr
|
8
vendor/CPR/cpr/unix_socket.cpp
vendored
Normal file
8
vendor/CPR/cpr/unix_socket.cpp
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#include "cpr/unix_socket.h"
|
||||
|
||||
namespace cpr {
|
||||
const char* UnixSocket::GetUnixSocketString() const noexcept {
|
||||
return unix_socket_.data();
|
||||
}
|
||||
} // namespace cpr
|
164
vendor/CPR/cpr/util.cpp
vendored
Normal file
164
vendor/CPR/cpr/util.cpp
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
#include "cpr/util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cpr {
|
||||
namespace util {
|
||||
|
||||
Cookies parseCookies(curl_slist* raw_cookies) {
|
||||
Cookies cookies;
|
||||
for (curl_slist* nc = raw_cookies; nc; nc = nc->next) {
|
||||
std::vector<std::string> tokens = cpr::util::split(nc->data, '\t');
|
||||
std::string value = tokens.back();
|
||||
tokens.pop_back();
|
||||
cookies[tokens.back()] = value;
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
|
||||
Header parseHeader(const std::string& headers, std::string* status_line, std::string* reason) {
|
||||
Header header;
|
||||
std::vector<std::string> lines;
|
||||
std::istringstream stream(headers);
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(stream, line, '\n')) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::string& line : lines) {
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
|
||||
if (line.substr(0, 5) == "HTTP/") {
|
||||
// set the status_line if it was given
|
||||
if ((status_line != nullptr) || (reason != nullptr)) {
|
||||
line.resize(std::min<size_t>(line.size(), line.find_last_not_of("\t\n\r ") + 1));
|
||||
if (status_line != nullptr) {
|
||||
*status_line = line;
|
||||
}
|
||||
|
||||
// set the reason if it was given
|
||||
if (reason != nullptr) {
|
||||
size_t pos1 = line.find_first_of("\t ");
|
||||
size_t pos2 = std::string::npos;
|
||||
if (pos1 != std::string::npos) {
|
||||
pos2 = line.find_first_of("\t ", pos1 + 1);
|
||||
}
|
||||
if (pos2 != std::string::npos) {
|
||||
line.erase(0, pos2 + 1);
|
||||
*reason = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
header.clear();
|
||||
}
|
||||
|
||||
if (line.length() > 0) {
|
||||
size_t found = line.find(':');
|
||||
if (found != std::string::npos) {
|
||||
std::string value = line.substr(found + 1);
|
||||
value.erase(0, value.find_first_not_of("\t "));
|
||||
value.resize(std::min<size_t>(value.size(), value.find_last_not_of("\t\n\r ") + 1));
|
||||
header[line.substr(0, found)] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& to_split, char delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
std::stringstream stream(to_split);
|
||||
std::string item;
|
||||
while (std::getline(stream, item, delimiter)) {
|
||||
tokens.push_back(item);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read) {
|
||||
size *= nitems;
|
||||
return read->callback(ptr, size) ? size : CURL_READFUNC_ABORT;
|
||||
}
|
||||
|
||||
size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header) {
|
||||
size *= nmemb;
|
||||
return header->callback({ptr, size}) ? size : 0;
|
||||
}
|
||||
|
||||
size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data) {
|
||||
size *= nmemb;
|
||||
data->append(ptr, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) {
|
||||
size *= nmemb;
|
||||
file->write(ptr, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write) {
|
||||
size *= nmemb;
|
||||
return write->callback({ptr, size}) ? size : 0;
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_NUM < 0x072000
|
||||
int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow,
|
||||
double ultotal, double ulnow) {
|
||||
#else
|
||||
int progressUserFunction(const ProgressCallback* progress, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow) {
|
||||
#endif
|
||||
return progress->callback(dltotal, dlnow, ultotal, ulnow) ? 0 : 1;
|
||||
}
|
||||
|
||||
int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size,
|
||||
const DebugCallback* debug) {
|
||||
debug->callback(DebugCallback::InfoType(type), std::string(data, size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary CurlHolder object and uses it to escape the given string.
|
||||
* If you plan to use this methode on a regular basis think about creating a CurlHolder
|
||||
* object and calling urlEncode(std::string) on it.
|
||||
*
|
||||
* Example:
|
||||
* CurlHolder holder;
|
||||
* std::string input = "Hello World!";
|
||||
* std::string result = holder.urlEncode(input);
|
||||
**/
|
||||
std::string urlEncode(const std::string& s) {
|
||||
CurlHolder holder; // Create a temporary new holder for URL encoding
|
||||
return holder.urlEncode(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary CurlHolder object and uses it to unescape the given string.
|
||||
* If you plan to use this methode on a regular basis think about creating a CurlHolder
|
||||
* object and calling urlDecode(std::string) on it.
|
||||
*
|
||||
* Example:
|
||||
* CurlHolder holder;
|
||||
* std::string input = "Hello%20World%21";
|
||||
* std::string result = holder.urlDecode(input);
|
||||
**/
|
||||
std::string urlDecode(const std::string& s) {
|
||||
CurlHolder holder; // Create a temporary new holder for URL decoding
|
||||
return holder.urlDecode(s);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace cpr
|
Reference in New Issue
Block a user