Initial community commit
This commit is contained in:
84
Src/external_dependencies/cpr/cpr/CMakeLists.txt
Normal file
84
Src/external_dependencies/cpr/cpr/CMakeLists.txt
Normal file
@@ -0,0 +1,84 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
add_library(cpr
|
||||
accept_encoding.cpp
|
||||
async.cpp
|
||||
auth.cpp
|
||||
bearer.cpp
|
||||
cert_info.cpp
|
||||
cookies.cpp
|
||||
cprtypes.cpp
|
||||
curl_container.cpp
|
||||
curlholder.cpp
|
||||
error.cpp
|
||||
file.cpp
|
||||
multipart.cpp
|
||||
parameters.cpp
|
||||
payload.cpp
|
||||
proxies.cpp
|
||||
proxyauth.cpp
|
||||
session.cpp
|
||||
threadpool.cpp
|
||||
timeout.cpp
|
||||
unix_socket.cpp
|
||||
util.cpp
|
||||
response.cpp
|
||||
redirect.cpp
|
||||
interceptor.cpp
|
||||
ssl_ctx.cpp
|
||||
curlmultiholder.cpp
|
||||
multiperform.cpp)
|
||||
|
||||
add_library(cpr::cpr ALIAS cpr)
|
||||
|
||||
target_link_libraries(cpr PUBLIC CURL::libcurl) # todo should be private, but first dependencys in ssl_options need to be removed
|
||||
|
||||
# Fix missing OpenSSL includes for Windows since in 'ssl_ctx.cpp' we include OpenSSL directly
|
||||
if(SSL_BACKEND_USED STREQUAL "OpenSSL")
|
||||
target_link_libraries(cpr PRIVATE OpenSSL::SSL)
|
||||
target_include_directories(cpr PRIVATE ${OPENSSL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# Set version for shared libraries.
|
||||
set_target_properties(cpr
|
||||
PROPERTIES
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR})
|
||||
|
||||
# Import GNU common install directory variables
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(CPR_USE_SYSTEM_CURL)
|
||||
install(TARGETS cpr
|
||||
EXPORT cprTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
# Include CMake helpers for package config files
|
||||
# Follow this installation guideline: https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${PROJECT_BINARY_DIR}/cpr/cprConfigVersion.cmake"
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
COMPATIBILITY ExactVersion)
|
||||
|
||||
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig.cmake.in
|
||||
"${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
|
||||
|
||||
install(EXPORT cprTargets
|
||||
FILE cprTargets.cmake
|
||||
NAMESPACE cpr::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
|
||||
|
||||
install(FILES ${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/cpr/cprConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
|
||||
|
||||
else()
|
||||
install(TARGETS cpr
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
25
Src/external_dependencies/cpr/cpr/accept_encoding.cpp
Normal file
25
Src/external_dependencies/cpr/cpr/accept_encoding.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "cpr/accept_encoding.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
AcceptEncoding::AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods) {
|
||||
methods_.clear();
|
||||
std::transform(methods.begin(), methods.end(), std::back_inserter(methods_), [&](cpr::AcceptEncodingMethods method) { return cpr::AcceptEncodingMethodsStringMap.at(method); });
|
||||
}
|
||||
|
||||
AcceptEncoding::AcceptEncoding(const std::initializer_list<std::string>& string_methods) : methods_{string_methods} {}
|
||||
|
||||
bool AcceptEncoding::empty() const noexcept {
|
||||
return methods_.empty();
|
||||
}
|
||||
|
||||
const std::string AcceptEncoding::getString() const {
|
||||
std::string methodsString = std::accumulate(std::next(methods_.begin()), methods_.end(), methods_[0], [](std::string a, std::string b) { return std::move(a) + ", " + std::move(b); });
|
||||
return methodsString;
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
8
Src/external_dependencies/cpr/cpr/async.cpp
Normal file
8
Src/external_dependencies/cpr/cpr/async.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "cpr/async.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
|
||||
CPR_SINGLETON_IMPL(GlobalThreadPool)
|
||||
|
||||
} // namespace cpr
|
||||
16
Src/external_dependencies/cpr/cpr/auth.cpp
Normal file
16
Src/external_dependencies/cpr/cpr/auth.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "cpr/auth.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
Authentication::~Authentication() noexcept {
|
||||
util::secureStringClear(auth_string_);
|
||||
}
|
||||
|
||||
const char* Authentication::GetAuthString() const noexcept {
|
||||
return auth_string_.c_str();
|
||||
}
|
||||
|
||||
AuthMode Authentication::GetAuthMode() const noexcept {
|
||||
return auth_mode_;
|
||||
}
|
||||
} // namespace cpr
|
||||
16
Src/external_dependencies/cpr/cpr/bearer.cpp
Normal file
16
Src/external_dependencies/cpr/cpr/bearer.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "cpr/bearer.h"
|
||||
#include "cpr/util.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
|
||||
Bearer::~Bearer() noexcept {
|
||||
util::secureStringClear(token_string_);
|
||||
}
|
||||
|
||||
const char* Bearer::GetToken() const noexcept {
|
||||
return token_string_.c_str();
|
||||
}
|
||||
#endif
|
||||
} // namespace cpr
|
||||
43
Src/external_dependencies/cpr/cpr/cert_info.cpp
Normal file
43
Src/external_dependencies/cpr/cpr/cert_info.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "cpr/cert_info.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
std::string& CertInfo::operator[](const size_t& pos) {
|
||||
return cert_info_[pos];
|
||||
}
|
||||
|
||||
CertInfo::iterator CertInfo::begin() {
|
||||
return cert_info_.begin();
|
||||
}
|
||||
CertInfo::iterator CertInfo::end() {
|
||||
return cert_info_.end();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::begin() const {
|
||||
return cert_info_.begin();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::end() const {
|
||||
return cert_info_.end();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::cbegin() const {
|
||||
return cert_info_.cbegin();
|
||||
}
|
||||
|
||||
CertInfo::const_iterator CertInfo::cend() const {
|
||||
return cert_info_.cend();
|
||||
}
|
||||
|
||||
void CertInfo::emplace_back(const std::string& str) {
|
||||
cert_info_.emplace_back(str);
|
||||
}
|
||||
|
||||
void CertInfo::push_back(const std::string& str) {
|
||||
cert_info_.push_back(str);
|
||||
}
|
||||
|
||||
void CertInfo::pop_back() {
|
||||
cert_info_.pop_back();
|
||||
}
|
||||
} // namespace cpr
|
||||
106
Src/external_dependencies/cpr/cpr/cookies.cpp
Normal file
106
Src/external_dependencies/cpr/cpr/cookies.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "cpr/cookies.h"
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
namespace cpr {
|
||||
const std::string Cookie::GetDomain() const {
|
||||
return domain_;
|
||||
}
|
||||
|
||||
bool Cookie::IsIncludingSubdomains() const {
|
||||
return includeSubdomains_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetPath() const {
|
||||
return path_;
|
||||
}
|
||||
|
||||
bool Cookie::IsHttpsOnly() const {
|
||||
return httpsOnly_;
|
||||
}
|
||||
|
||||
const std::chrono::system_clock::time_point Cookie::GetExpires() const {
|
||||
return expires_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetExpiresString() const {
|
||||
std::stringstream ss;
|
||||
std::tm tm{};
|
||||
std::time_t tt = std::chrono::system_clock::to_time_t(expires_);
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&tm, &tt);
|
||||
#else
|
||||
gmtime_r(&tt, &tm);
|
||||
#endif
|
||||
ss << std::put_time(&tm, "%a, %d %b %Y %H:%M:%S GMT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
const std::string Cookie::GetName() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string Cookie::GetValue() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
const std::string Cookies::GetEncoded(const CurlHolder& holder) const {
|
||||
std::stringstream stream;
|
||||
for (const cpr::Cookie& item : cookies_) {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.GetName()) : item.GetName()) << "=";
|
||||
|
||||
// special case version 1 cookies, which can be distinguished by
|
||||
// beginning and trailing quotes
|
||||
if (!item.GetValue().empty() && item.GetValue().front() == '"' && item.GetValue().back() == '"') {
|
||||
stream << item.GetValue();
|
||||
} else {
|
||||
// Depending on if encoding is set to "true", we will URL-encode cookies
|
||||
stream << (encode ? holder.urlEncode(item.GetValue()) : item.GetValue());
|
||||
}
|
||||
stream << "; ";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
cpr::Cookie& Cookies::operator[](size_t pos) {
|
||||
return cookies_[pos];
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::begin() {
|
||||
return cookies_.begin();
|
||||
}
|
||||
|
||||
Cookies::iterator Cookies::end() {
|
||||
return cookies_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::begin() const {
|
||||
return cookies_.begin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::end() const {
|
||||
return cookies_.end();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cbegin() const {
|
||||
return cookies_.cbegin();
|
||||
}
|
||||
|
||||
Cookies::const_iterator Cookies::cend() const {
|
||||
return cookies_.cend();
|
||||
}
|
||||
|
||||
void Cookies::emplace_back(const Cookie& str) {
|
||||
cookies_.emplace_back(str);
|
||||
}
|
||||
|
||||
void Cookies::push_back(const Cookie& str) {
|
||||
cookies_.push_back(str);
|
||||
}
|
||||
|
||||
void Cookies::pop_back() {
|
||||
cookies_.pop_back();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
10
Src/external_dependencies/cpr/cpr/cprtypes.cpp
Normal file
10
Src/external_dependencies/cpr/cpr/cprtypes.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#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
|
||||
58
Src/external_dependencies/cpr/cpr/curl_container.cpp
Normal file
58
Src/external_dependencies/cpr/cpr/curl_container.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "cpr/curl_container.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
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) {
|
||||
std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); });
|
||||
}
|
||||
|
||||
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
|
||||
49
Src/external_dependencies/cpr/cpr/curlholder.cpp
Normal file
49
Src/external_dependencies/cpr/cpr/curlholder.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "cpr/curlholder.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace cpr {
|
||||
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();
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-prefer-member-initializer) since we need it to happen inside the lock
|
||||
handle = curl_easy_init();
|
||||
curl_easy_init_mutex_().unlock();
|
||||
|
||||
assert(handle);
|
||||
} // namespace cpr
|
||||
|
||||
CurlHolder::~CurlHolder() {
|
||||
curl_slist_free_all(chunk);
|
||||
curl_slist_free_all(resolveCurlList);
|
||||
curl_formfree(formpost);
|
||||
curl_easy_cleanup(handle);
|
||||
}
|
||||
|
||||
std::string CurlHolder::urlEncode(const std::string& s) const {
|
||||
assert(handle);
|
||||
char* output = curl_easy_escape(handle, s.c_str(), static_cast<int>(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(), static_cast<int>(s.length()), nullptr);
|
||||
if (output) {
|
||||
std::string result = output;
|
||||
curl_free(output);
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
} // namespace cpr
|
||||
15
Src/external_dependencies/cpr/cpr/curlmultiholder.cpp
Normal file
15
Src/external_dependencies/cpr/cpr/curlmultiholder.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "cpr/curlmultiholder.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
CurlMultiHolder::CurlMultiHolder() : handle{curl_multi_init()} {
|
||||
assert(handle);
|
||||
}
|
||||
|
||||
CurlMultiHolder::~CurlMultiHolder() {
|
||||
curl_multi_cleanup(handle);
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
68
Src/external_dependencies/cpr/cpr/error.cpp
Normal file
68
Src/external_dependencies/cpr/cpr/error.cpp
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::TOO_MANY_REDIRECTS;
|
||||
default:
|
||||
return ErrorCode::INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
40
Src/external_dependencies/cpr/cpr/file.cpp
Normal file
40
Src/external_dependencies/cpr/cpr/file.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "cpr/file.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Files::iterator Files::begin() {
|
||||
return files.begin();
|
||||
}
|
||||
|
||||
Files::iterator Files::end() {
|
||||
return files.end();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::begin() const {
|
||||
return files.begin();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::end() const {
|
||||
return files.end();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::cbegin() const {
|
||||
return files.cbegin();
|
||||
}
|
||||
|
||||
Files::const_iterator Files::cend() const {
|
||||
return files.cend();
|
||||
}
|
||||
|
||||
void Files::emplace_back(const File& file) {
|
||||
files.emplace_back(file);
|
||||
}
|
||||
|
||||
void Files::push_back(const File& file) {
|
||||
files.push_back(file);
|
||||
}
|
||||
|
||||
void Files::pop_back() {
|
||||
files.pop_back();
|
||||
}
|
||||
} // namespace cpr
|
||||
46
Src/external_dependencies/cpr/cpr/interceptor.cpp
Normal file
46
Src/external_dependencies/cpr/cpr/interceptor.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "cpr/interceptor.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
Response Interceptor::proceed(Session& session) {
|
||||
return session.proceed();
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod) {
|
||||
switch (httpMethod) {
|
||||
case ProceedHttpMethod::DELETE_REQUEST:
|
||||
return session.Delete();
|
||||
case ProceedHttpMethod::GET_REQUEST:
|
||||
return session.Get();
|
||||
case ProceedHttpMethod::HEAD_REQUEST:
|
||||
return session.Head();
|
||||
case ProceedHttpMethod::OPTIONS_REQUEST:
|
||||
return session.Options();
|
||||
case ProceedHttpMethod::PATCH_REQUEST:
|
||||
return session.Patch();
|
||||
case ProceedHttpMethod::POST_REQUEST:
|
||||
return session.Post();
|
||||
case ProceedHttpMethod::PUT_REQUEST:
|
||||
return session.Put();
|
||||
default:
|
||||
throw std::invalid_argument{"Can't procceed the session with the provided http method!"};
|
||||
}
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file) {
|
||||
if (httpMethod == ProceedHttpMethod::DOWNLOAD_FILE_REQUEST) {
|
||||
return session.Download(file);
|
||||
}
|
||||
throw std::invalid_argument{"std::ofstream argument is only valid for ProceedHttpMethod::DOWNLOAD_FILE!"};
|
||||
}
|
||||
|
||||
Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write) {
|
||||
if (httpMethod == ProceedHttpMethod::DOWNLOAD_CALLBACK_REQUEST) {
|
||||
return session.Download(write);
|
||||
}
|
||||
throw std::invalid_argument{"WriteCallback argument is only valid for ProceedHttpMethod::DOWNLOAD_CALLBACK!"};
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
5
Src/external_dependencies/cpr/cpr/multipart.cpp
Normal file
5
Src/external_dependencies/cpr/cpr/multipart.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "cpr/multipart.h"
|
||||
|
||||
namespace cpr {
|
||||
Multipart::Multipart(const std::initializer_list<Part>& p_parts) : parts{p_parts} {}
|
||||
} // namespace cpr
|
||||
273
Src/external_dependencies/cpr/cpr/multiperform.cpp
Normal file
273
Src/external_dependencies/cpr/cpr/multiperform.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
#include "cpr/multiperform.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
MultiPerform::MultiPerform() : multicurl_(new CurlMultiHolder()) {}
|
||||
|
||||
MultiPerform::~MultiPerform() {
|
||||
// Unock all sessions
|
||||
for (std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
pair.first->isUsedInMultiPerform = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::AddSession(std::shared_ptr<Session>& session, HttpMethod method) {
|
||||
// Check if this multiperform is download only
|
||||
if (((method != HttpMethod::DOWNLOAD_REQUEST && is_download_multi_perform) && method != HttpMethod::UNDEFINED) || (method == HttpMethod::DOWNLOAD_REQUEST && !is_download_multi_perform && !sessions_.empty())) {
|
||||
// Currently it is not possible to mix download and non-download methods, as download needs additional parameters
|
||||
throw std::invalid_argument("Failed to add session: Cannot mix download and non-download methods!");
|
||||
}
|
||||
|
||||
// Set download only if neccessary
|
||||
if (method == HttpMethod::DOWNLOAD_REQUEST) {
|
||||
is_download_multi_perform = true;
|
||||
}
|
||||
|
||||
// Add easy handle to multi handle
|
||||
CURLMcode error_code = curl_multi_add_handle(multicurl_->handle, session->curl_->handle);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_add_handle() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Lock session to the multihandle
|
||||
session->isUsedInMultiPerform = true;
|
||||
|
||||
// Add session to sessions_
|
||||
sessions_.emplace_back(session, method);
|
||||
}
|
||||
|
||||
void MultiPerform::RemoveSession(const std::shared_ptr<Session>& session) {
|
||||
// Remove easy handle from multihandle
|
||||
CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_remove_handle() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Unock session
|
||||
session->isUsedInMultiPerform = false;
|
||||
|
||||
// Remove session from sessions_
|
||||
auto it = std::find_if(sessions_.begin(), sessions_.end(), [&session](const std::pair<std::shared_ptr<Session>, HttpMethod>& pair) { return session->curl_->handle == pair.first->curl_->handle; });
|
||||
if (it == sessions_.end()) {
|
||||
throw std::invalid_argument("Failed to find session!");
|
||||
}
|
||||
sessions_.erase(it);
|
||||
|
||||
// Reset download only if empty
|
||||
if (sessions_.empty()) {
|
||||
is_download_multi_perform = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::DoMultiPerform() {
|
||||
// Do multi perform until every handle has finished
|
||||
int still_running{0};
|
||||
do {
|
||||
CURLMcode error_code = curl_multi_perform(multicurl_->handle, &still_running);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_perform() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (still_running) {
|
||||
const int timeout_ms{250};
|
||||
error_code = curl_multi_poll(multicurl_->handle, nullptr, 0, timeout_ms, nullptr);
|
||||
if (error_code) {
|
||||
std::cerr << "curl_multi_poll() failed, code " << static_cast<int>(error_code) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (still_running);
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function) {
|
||||
// Get infos and create Response objects
|
||||
std::vector<Response> responses;
|
||||
struct CURLMsg* info{nullptr};
|
||||
do {
|
||||
int msgq = 0;
|
||||
|
||||
// Read info from multihandle
|
||||
info = curl_multi_info_read(multicurl_->handle, &msgq);
|
||||
|
||||
if (info) {
|
||||
// Find current session
|
||||
auto it = std::find_if(sessions_.begin(), sessions_.end(), [&info](const std::pair<std::shared_ptr<Session>, HttpMethod>& pair) { return pair.first->curl_->handle == info->easy_handle; });
|
||||
if (it == sessions_.end()) {
|
||||
std::cerr << "Failed to find current session!" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::shared_ptr<Session> current_session = (*it).first;
|
||||
|
||||
// Add response object
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-union-access)
|
||||
responses.push_back(complete_function(*current_session, info->data.result));
|
||||
}
|
||||
} while (info);
|
||||
|
||||
// Sort response objects to match order of added sessions
|
||||
std::vector<Response> sorted_responses;
|
||||
for (std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
Session& current_session = *(pair.first);
|
||||
auto it = std::find_if(responses.begin(), responses.end(), [¤t_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; });
|
||||
Response current_response = *it;
|
||||
// Erase response from original vector to increase future search speed
|
||||
responses.erase(it);
|
||||
sorted_responses.push_back(current_response);
|
||||
}
|
||||
|
||||
return sorted_responses;
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::MakeRequest() {
|
||||
DoMultiPerform();
|
||||
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.Complete(curl_error); });
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::MakeDownloadRequest() {
|
||||
DoMultiPerform();
|
||||
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.CompleteDownload(curl_error); });
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareSessions() {
|
||||
for (std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
switch (pair.second) {
|
||||
case HttpMethod::GET_REQUEST:
|
||||
pair.first->PrepareGet();
|
||||
break;
|
||||
case HttpMethod::POST_REQUEST:
|
||||
pair.first->PreparePost();
|
||||
break;
|
||||
case HttpMethod::PUT_REQUEST:
|
||||
pair.first->PreparePut();
|
||||
break;
|
||||
case HttpMethod::DELETE_REQUEST:
|
||||
pair.first->PrepareDelete();
|
||||
break;
|
||||
case HttpMethod::PATCH_REQUEST:
|
||||
pair.first->PreparePatch();
|
||||
break;
|
||||
case HttpMethod::HEAD_REQUEST:
|
||||
pair.first->PrepareHead();
|
||||
break;
|
||||
case HttpMethod::OPTIONS_REQUEST:
|
||||
pair.first->PrepareOptions();
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or download without arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDownloadSession(size_t sessions_index, const WriteCallback& write) {
|
||||
std::pair<std::shared_ptr<Session>, HttpMethod>& pair = sessions_[sessions_index];
|
||||
switch (pair.second) {
|
||||
case HttpMethod::DOWNLOAD_REQUEST:
|
||||
pair.first->PrepareDownload(write);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDownloadSession(size_t sessions_index, std::ofstream& file) {
|
||||
std::pair<std::shared_ptr<Session>, HttpMethod>& pair = sessions_[sessions_index];
|
||||
switch (pair.second) {
|
||||
case HttpMethod::DOWNLOAD_REQUEST:
|
||||
pair.first->PrepareDownload(file);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::SetHttpMethod(HttpMethod method) {
|
||||
for (std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
|
||||
pair.second = method;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareGet() {
|
||||
SetHttpMethod(HttpMethod::GET_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareDelete() {
|
||||
SetHttpMethod(HttpMethod::DELETE_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePut() {
|
||||
SetHttpMethod(HttpMethod::PUT_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePatch() {
|
||||
SetHttpMethod(HttpMethod::PATCH_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareHead() {
|
||||
SetHttpMethod(HttpMethod::HEAD_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PrepareOptions() {
|
||||
SetHttpMethod(HttpMethod::OPTIONS_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
void MultiPerform::PreparePost() {
|
||||
SetHttpMethod(HttpMethod::POST_REQUEST);
|
||||
PrepareSessions();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Get() {
|
||||
PrepareGet();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Delete() {
|
||||
PrepareDelete();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Put() {
|
||||
PreparePut();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Head() {
|
||||
PrepareHead();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Options() {
|
||||
PrepareOptions();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Patch() {
|
||||
PreparePatch();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Post() {
|
||||
PreparePost();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
std::vector<Response> MultiPerform::Perform() {
|
||||
PrepareSessions();
|
||||
return MakeRequest();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
10
Src/external_dependencies/cpr/cpr/parameters.cpp
Normal file
10
Src/external_dependencies/cpr/cpr/parameters.cpp
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
Src/external_dependencies/cpr/cpr/payload.cpp
Normal file
10
Src/external_dependencies/cpr/cpr/payload.cpp
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
Src/external_dependencies/cpr/cpr/proxies.cpp
Normal file
21
Src/external_dependencies/cpr/cpr/proxies.cpp
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} {}
|
||||
Proxies::Proxies(const std::map<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
|
||||
21
Src/external_dependencies/cpr/cpr/proxyauth.cpp
Normal file
21
Src/external_dependencies/cpr/cpr/proxyauth.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "cpr/proxyauth.h"
|
||||
#include "cpr/util.h"
|
||||
|
||||
namespace cpr {
|
||||
EncodedAuthentication::~EncodedAuthentication() noexcept {
|
||||
util::secureStringClear(auth_string_);
|
||||
}
|
||||
|
||||
const char* EncodedAuthentication::GetAuthString() const noexcept {
|
||||
return auth_string_.c_str();
|
||||
}
|
||||
|
||||
bool ProxyAuthentication::has(const std::string& protocol) const {
|
||||
return proxyAuth_.count(protocol) > 0;
|
||||
}
|
||||
|
||||
const char* ProxyAuthentication::operator[](const std::string& protocol) {
|
||||
return proxyAuth_[protocol].GetAuthString();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
40
Src/external_dependencies/cpr/cpr/redirect.cpp
Normal file
40
Src/external_dependencies/cpr/cpr/redirect.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "cpr/redirect.h"
|
||||
|
||||
namespace cpr {
|
||||
PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs) {
|
||||
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
||||
}
|
||||
|
||||
PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs) {
|
||||
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
|
||||
}
|
||||
|
||||
PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs) {
|
||||
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs));
|
||||
}
|
||||
|
||||
PostRedirectFlags operator~(PostRedirectFlags flag) {
|
||||
return static_cast<PostRedirectFlags>(~static_cast<uint8_t>(flag));
|
||||
}
|
||||
|
||||
PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
|
||||
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
||||
uint8_t tmp = static_cast<uint8_t>(lhs);
|
||||
lhs = static_cast<PostRedirectFlags>(tmp);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
|
||||
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
|
||||
return lhs;
|
||||
}
|
||||
|
||||
PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
|
||||
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs));
|
||||
return lhs;
|
||||
}
|
||||
|
||||
bool any(PostRedirectFlags flag) {
|
||||
return flag != PostRedirectFlags::NONE;
|
||||
}
|
||||
} // namespace cpr
|
||||
44
Src/external_dependencies/cpr/cpr/response.cpp
Normal file
44
Src/external_dependencies/cpr/cpr/response.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#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)), raw_header(std::move(p_header_string)) {
|
||||
header = cpr::util::parseHeader(raw_header, &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<CertInfo> Response::GetCertInfos() {
|
||||
assert(curl_);
|
||||
assert(curl_->handle);
|
||||
curl_certinfo* ci{nullptr};
|
||||
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
|
||||
|
||||
std::vector<CertInfo> cert_infos;
|
||||
for (int i = 0; i < ci->num_of_certs; i++) {
|
||||
CertInfo cert_info;
|
||||
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for (curl_slist* slist = ci->certinfo[i]; slist; slist = slist->next) {
|
||||
cert_info.emplace_back(std::string{slist->data});
|
||||
}
|
||||
cert_infos.emplace_back(cert_info);
|
||||
}
|
||||
return cert_infos;
|
||||
}
|
||||
} // namespace cpr
|
||||
964
Src/external_dependencies/cpr/cpr/session.cpp
Normal file
964
Src/external_dependencies/cpr/cpr/session.cpp
Normal file
@@ -0,0 +1,964 @@
|
||||
#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);
|
||||
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()) {
|
||||
std::shared_ptr<Interceptor> interceptor = interceptors_.front();
|
||||
interceptors_.pop();
|
||||
return interceptor->intercept(*this);
|
||||
}
|
||||
|
||||
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()) {
|
||||
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());
|
||||
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_MAJOR >= 7
|
||||
#if LIBCURL_VERSION_MINOR >= 21
|
||||
if (acceptEncoding_.empty()) {
|
||||
/* enable all supported built-in compressions */
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
|
||||
} else {
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str());
|
||||
}
|
||||
#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';
|
||||
|
||||
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()) {
|
||||
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());
|
||||
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()) {
|
||||
// At least one interceptor exists -> Execute its intercept function
|
||||
std::shared_ptr<Interceptor> interceptor = interceptors_.front();
|
||||
interceptors_.pop();
|
||||
return interceptor->intercept(*this);
|
||||
}
|
||||
|
||||
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 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::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) {
|
||||
curl_httppost* formpost = nullptr;
|
||||
curl_httppost* lastptr = nullptr;
|
||||
|
||||
for (const Part& part : multipart.parts) {
|
||||
std::vector<curl_forms> formdata;
|
||||
if (!part.content_type.empty()) {
|
||||
formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
|
||||
}
|
||||
if (part.is_file) {
|
||||
for (const File& file : part.files) {
|
||||
formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
|
||||
formdata.push_back({CURLFORM_FILE, file.filepath.c_str()});
|
||||
if (file.hasOverridedFilename()) {
|
||||
formdata.push_back({CURLFORM_FILENAME, file.overrided_filename.c_str()});
|
||||
}
|
||||
formdata.push_back({CURLFORM_END, nullptr});
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
|
||||
formdata.clear();
|
||||
}
|
||||
} else 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()});
|
||||
formdata.push_back({CURLFORM_COPYCONTENTS, part.value.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::SetMultipart(Multipart&& multipart) {
|
||||
curl_httppost* formpost = nullptr;
|
||||
curl_httppost* lastptr = nullptr;
|
||||
|
||||
for (const Part& part : multipart.parts) {
|
||||
std::vector<curl_forms> formdata;
|
||||
if (!part.content_type.empty()) {
|
||||
formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
|
||||
}
|
||||
if (part.is_file) {
|
||||
for (const File& file : part.files) {
|
||||
formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
|
||||
formdata.push_back({CURLFORM_FILE, file.filepath.c_str()});
|
||||
if (file.hasOverridedFilename()) {
|
||||
formdata.push_back({CURLFORM_FILENAME, file.overrided_filename.c_str()});
|
||||
}
|
||||
formdata.push_back({CURLFORM_END, nullptr});
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
|
||||
formdata.clear();
|
||||
}
|
||||
} else 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()});
|
||||
formdata.push_back({CURLFORM_COPYCONTENTS, part.value.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::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) {
|
||||
std::string range_str = range.str();
|
||||
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str());
|
||||
}
|
||||
|
||||
void Session::SetMultiRange(const MultiRange& multi_range) {
|
||||
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());
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
// 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
|
||||
} // namespace cpr
|
||||
70
Src/external_dependencies/cpr/cpr/ssl_ctx.cpp
Normal file
70
Src/external_dependencies/cpr/cpr/ssl_ctx.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#include "cpr/ssl_ctx.h"
|
||||
|
||||
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
|
||||
#ifdef OPENSSL_BACKEND_USED
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace cpr {
|
||||
|
||||
/**
|
||||
* The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL.
|
||||
* If an error is returned from the callback no attempt to establish a connection is made and
|
||||
* the perform operation will return the callback's error code.
|
||||
*
|
||||
* Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html
|
||||
* https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html
|
||||
*/
|
||||
CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) {
|
||||
// Check arguments
|
||||
if (raw_cert_buf == nullptr || sslctx == nullptr) {
|
||||
printf("Invalid callback arguments\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Setup pointer
|
||||
X509_STORE* store = nullptr;
|
||||
X509* cert = nullptr;
|
||||
BIO* bio = nullptr;
|
||||
char* cert_buf = static_cast<char*>(raw_cert_buf);
|
||||
|
||||
// Create a memory BIO using the data of cert_buf.
|
||||
// Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen.
|
||||
bio = BIO_new_mem_buf(cert_buf, -1);
|
||||
|
||||
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
|
||||
PEM_read_bio_X509(bio, &cert, nullptr, nullptr);
|
||||
if (cert == nullptr) {
|
||||
printf("PEM_read_bio_X509 failed\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Get a pointer to the current certificate verification storage
|
||||
store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
|
||||
|
||||
// Add the loaded certificate to the verification storage
|
||||
int status = X509_STORE_add_cert(store, cert);
|
||||
if (status == 0) {
|
||||
printf("Error adding certificate\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
|
||||
// Decrement the reference count of the X509 structure cert and frees it up
|
||||
X509_free(cert);
|
||||
|
||||
// Free the entire bio chain
|
||||
BIO_free(bio);
|
||||
|
||||
// The CA certificate was loaded successfully into the verification storage
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
|
||||
#endif // OPENSSL_BACKEND_USED
|
||||
|
||||
#endif // SUPPORT_CURLOPT_SSL_CTX_FUNCTION
|
||||
148
Src/external_dependencies/cpr/cpr/threadpool.cpp
Normal file
148
Src/external_dependencies/cpr/cpr/threadpool.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "cpr/threadpool.h"
|
||||
|
||||
namespace cpr {
|
||||
|
||||
ThreadPool::ThreadPool(size_t min_threads, size_t max_threads, std::chrono::milliseconds max_idle_ms) : min_thread_num(min_threads), max_thread_num(max_threads), max_idle_time(max_idle_ms), status(STOP), cur_thread_num(0), idle_thread_num(0) {}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
int ThreadPool::Start(size_t start_threads) {
|
||||
if (status != STOP) {
|
||||
return -1;
|
||||
}
|
||||
status = RUNNING;
|
||||
if (start_threads < min_thread_num) {
|
||||
start_threads = min_thread_num;
|
||||
}
|
||||
if (start_threads > max_thread_num) {
|
||||
start_threads = max_thread_num;
|
||||
}
|
||||
for (size_t i = 0; i < start_threads; ++i) {
|
||||
CreateThread();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Stop() {
|
||||
if (status == STOP) {
|
||||
return -1;
|
||||
}
|
||||
status = STOP;
|
||||
task_cond.notify_all();
|
||||
for (auto& i : threads) {
|
||||
if (i.thread->joinable()) {
|
||||
i.thread->join();
|
||||
}
|
||||
}
|
||||
threads.clear();
|
||||
cur_thread_num = 0;
|
||||
idle_thread_num = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Pause() {
|
||||
if (status == RUNNING) {
|
||||
status = PAUSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Resume() {
|
||||
if (status == PAUSE) {
|
||||
status = RUNNING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ThreadPool::Wait() {
|
||||
while (true) {
|
||||
if (status == STOP || (tasks.empty() && idle_thread_num == cur_thread_num)) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ThreadPool::CreateThread() {
|
||||
if (cur_thread_num >= max_thread_num) {
|
||||
return false;
|
||||
}
|
||||
std::thread* thread = new std::thread([this] {
|
||||
bool initialRun = true;
|
||||
while (status != STOP) {
|
||||
while (status == PAUSE) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
Task task;
|
||||
{
|
||||
std::unique_lock<std::mutex> locker(task_mutex);
|
||||
task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() { return status == STOP || !tasks.empty(); });
|
||||
if (status == STOP) {
|
||||
return;
|
||||
}
|
||||
if (tasks.empty()) {
|
||||
if (cur_thread_num > min_thread_num) {
|
||||
DelThread(std::this_thread::get_id());
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!initialRun) {
|
||||
--idle_thread_num;
|
||||
}
|
||||
task = std::move(tasks.front());
|
||||
tasks.pop();
|
||||
}
|
||||
if (task) {
|
||||
task();
|
||||
++idle_thread_num;
|
||||
} else if (initialRun) {
|
||||
++idle_thread_num;
|
||||
initialRun = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
AddThread(thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThreadPool::AddThread(std::thread* thread) {
|
||||
thread_mutex.lock();
|
||||
++cur_thread_num;
|
||||
ThreadData data;
|
||||
data.thread = std::shared_ptr<std::thread>(thread);
|
||||
data.id = thread->get_id();
|
||||
data.status = RUNNING;
|
||||
data.start_time = time(nullptr);
|
||||
data.stop_time = 0;
|
||||
threads.emplace_back(data);
|
||||
thread_mutex.unlock();
|
||||
}
|
||||
|
||||
void ThreadPool::DelThread(std::thread::id id) {
|
||||
time_t now = time(nullptr);
|
||||
thread_mutex.lock();
|
||||
--cur_thread_num;
|
||||
--idle_thread_num;
|
||||
auto iter = threads.begin();
|
||||
while (iter != threads.end()) {
|
||||
if (iter->status == STOP && now > iter->stop_time) {
|
||||
if (iter->thread->joinable()) {
|
||||
iter->thread->join();
|
||||
iter = threads.erase(iter);
|
||||
continue;
|
||||
}
|
||||
} else if (iter->id == id) {
|
||||
iter->status = STOP;
|
||||
iter->stop_time = time(nullptr);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
thread_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace cpr
|
||||
31
Src/external_dependencies/cpr/cpr/timeout.cpp
Normal file
31
Src/external_dependencies/cpr/cpr/timeout.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "cpr/timeout.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
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() > static_cast<std::chrono::milliseconds::rep>(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() < static_cast<std::chrono::milliseconds::rep>(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
Src/external_dependencies/cpr/cpr/unix_socket.cpp
Normal file
8
Src/external_dependencies/cpr/cpr/unix_socket.cpp
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
|
||||
236
Src/external_dependencies/cpr/cpr/util.cpp
Normal file
236
Src/external_dependencies/cpr/cpr/util.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "cpr/util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_Win32)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
// https://en.cppreference.com/w/c/string/byte/memset
|
||||
// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp, cppcoreguidelines-macro-usage)
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace cpr::util {
|
||||
|
||||
enum class CurlHTTPCookieField : size_t {
|
||||
Domain = 0,
|
||||
IncludeSubdomains,
|
||||
Path,
|
||||
HttpsOnly,
|
||||
Expires,
|
||||
Name,
|
||||
Value,
|
||||
};
|
||||
|
||||
Cookies parseCookies(curl_slist* raw_cookies) {
|
||||
const int CURL_HTTP_COOKIE_SIZE = static_cast<int>(CurlHTTPCookieField::Value) + 1;
|
||||
Cookies cookies;
|
||||
for (curl_slist* nc = raw_cookies; nc; nc = nc->next) {
|
||||
std::vector<std::string> tokens = cpr::util::split(nc->data, '\t');
|
||||
while (tokens.size() < CURL_HTTP_COOKIE_SIZE) {
|
||||
tokens.emplace_back("");
|
||||
}
|
||||
std::time_t expires = static_cast<time_t>(std::stoul(tokens.at(static_cast<size_t>(CurlHTTPCookieField::Expires))));
|
||||
cookies.emplace_back(Cookie{
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Name)),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Value)),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Domain)),
|
||||
isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::IncludeSubdomains))),
|
||||
tokens.at(static_cast<size_t>(CurlHTTPCookieField::Path)),
|
||||
isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::HttpsOnly))),
|
||||
std::chrono::system_clock::from_time_t(expires),
|
||||
});
|
||||
}
|
||||
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) {
|
||||
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)(ptr, size) ? size : CURL_READFUNC_ABORT;
|
||||
}
|
||||
|
||||
size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header) {
|
||||
size *= nmemb;
|
||||
return (*header)({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, static_cast<std::streamsize>(size));
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write) {
|
||||
size *= nmemb;
|
||||
return (*write)({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)(dltotal, dlnow, ultotal, ulnow) ? 0 : 1;
|
||||
} // namespace cpr::util
|
||||
|
||||
int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, const DebugCallback* debug) {
|
||||
(*debug)(static_cast<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);
|
||||
}
|
||||
|
||||
#if defined(__STDC_LIB_EXT1__)
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
memset_s(&s.front(), s.length(), 0, s.length());
|
||||
s.clear();
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
SecureZeroMemory(&s.front(), s.length());
|
||||
s.clear();
|
||||
}
|
||||
#else
|
||||
#if defined(__clang__)
|
||||
#pragma clang optimize off // clang
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma GCC push_options // g++
|
||||
#pragma GCC optimize("O0") // g++
|
||||
#endif
|
||||
void secureStringClear(std::string& s) {
|
||||
if (s.empty()) {
|
||||
return;
|
||||
}
|
||||
// NOLINTNEXTLINE (readability-container-data-pointer)
|
||||
char* ptr = &(s[0]);
|
||||
memset(ptr, '\0', s.length());
|
||||
s.clear();
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang optimize on // clang
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma GCC pop_options // g++
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool isTrue(const std::string& s) {
|
||||
std::string temp_string{s};
|
||||
std::transform(temp_string.begin(), temp_string.end(), temp_string.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
return temp_string == "true";
|
||||
}
|
||||
|
||||
} // namespace cpr::util
|
||||
Reference in New Issue
Block a user