1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-09-15 16:57:19 +02:00

Update WIP discord and some vendors.

CPR has features disabled and PCRE is fully disabled until updated to new code.
This commit is contained in:
Sandu Liviu Catalin
2023-08-05 21:31:33 +03:00
parent e0761bf3b9
commit 9298065cef
1562 changed files with 55070 additions and 76299 deletions

37
vendor/CPR/cpr/accept_encoding.cpp vendored Normal file
View File

@@ -0,0 +1,37 @@
#include "cpr/accept_encoding.h"
#include <algorithm>
#include <cassert>
#include <initializer_list>
#include <iterator>
#include <numeric>
#include <stdexcept>
namespace cpr {
AcceptEncoding::AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods) {
methods_.clear();
std::transform(methods.begin(), methods.end(), std::inserter(methods_, methods_.begin()), [&](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 {
return std::accumulate(std::next(methods_.begin()), methods_.end(), *methods_.begin(), [](std::string a, std::string b) { return std::move(a) + ", " + std::move(b); });
}
[[nodiscard]] bool AcceptEncoding::disabled() const {
if (methods_.find(cpr::AcceptEncodingMethodsStringMap.at(AcceptEncodingMethods::disabled)) != methods_.end()) {
if (methods_.size() != 1) {
throw std::invalid_argument("AcceptEncoding does not accept any other values if 'disabled' is present. You set the following encodings: " + getString());
}
return true;
}
return false;
}
} // namespace cpr

8
vendor/CPR/cpr/async.cpp vendored Normal file
View File

@@ -0,0 +1,8 @@
#include "cpr/async.h"
namespace cpr {
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
CPR_SINGLETON_IMPL(GlobalThreadPool)
} // namespace cpr

View File

@@ -1,7 +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

View File

@@ -1,9 +1,14 @@
#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();
}

14
vendor/CPR/cpr/callback.cpp vendored Normal file
View File

@@ -0,0 +1,14 @@
#include <cpr/callback.h>
#include <curl/curl.h>
#include <functional>
namespace cpr {
void CancellationCallback::SetProgressCallback(ProgressCallback& u_cb) {
user_cb.emplace(std::reference_wrapper{u_cb});
}
bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const {
const bool cont_operation{!cancellation_state->load()};
return user_cb ? (cont_operation && (*user_cb)(dltotal, dlnow, ultotal, ulnow)) : cont_operation;
}
} // namespace cpr

43
vendor/CPR/cpr/cert_info.cpp vendored Normal file
View 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

View File

@@ -1,51 +1,106 @@
#include "cpr/cookies.h"
#include <ctime>
#include <iomanip>
namespace cpr {
std::string Cookies::GetEncoded(const CurlHolder& holder) const {
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{};
const 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 std::pair<const std::string, std::string>& item : map_) {
for (const cpr::Cookie& item : cookies_) {
// Depending on if encoding is set to "true", we will URL-encode cookies
stream << (encode ? holder.urlEncode(item.first) : item.first) << "=";
stream << (encode ? holder.urlEncode(item.GetName()) : item.GetName()) << "=";
// special case version 1 cookies, which can be distinguished by
// beginning and trailing quotes
if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') {
stream << item.second;
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.second) : item.second);
stream << (encode ? holder.urlEncode(item.GetValue()) : item.GetValue());
}
stream << "; ";
}
return stream.str();
}
std::string& Cookies::operator[](const std::string& key) {
return map_[key];
cpr::Cookie& Cookies::operator[](size_t pos) {
return cookies_[pos];
}
Cookies::iterator Cookies::begin() {
return map_.begin();
return cookies_.begin();
}
Cookies::iterator Cookies::end() {
return map_.end();
return cookies_.end();
}
Cookies::const_iterator Cookies::begin() const {
return map_.begin();
return cookies_.begin();
}
Cookies::const_iterator Cookies::end() const {
return map_.end();
return cookies_.end();
}
Cookies::const_iterator Cookies::cbegin() const {
return map_.cbegin();
return cookies_.cbegin();
}
Cookies::const_iterator Cookies::cend() const {
return map_.cend();
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

View File

@@ -5,8 +5,6 @@
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); });
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

View File

@@ -1,16 +1,15 @@
#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) {}
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList) : containerList_(containerList) {}
template <class T>
void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) {
for (const T& element : containerList) {
containerList_.push_back(std::move(element));
}
std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); });
}
template <class T>
@@ -26,15 +25,15 @@ const std::string CurlContainer<Parameter>::GetContent(const CurlHolder& holder)
content += "&";
}
std::string escapedKey = encode ? holder.urlEncode(parameter.key) : parameter.key;
const 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;
const std::string escapedValue = encode ? holder.urlEncode(parameter.value) : parameter.value;
content += escapedKey + "=";
content += escapedValue;
}
};
}
return content;
}
@@ -46,7 +45,7 @@ const std::string CurlContainer<Pair>::GetContent(const CurlHolder& holder) cons
if (!content.empty()) {
content += "&";
}
std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
const std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
content += element.key + "=" + escaped;
}

View File

@@ -2,10 +2,6 @@
#include <cassert>
namespace cpr {
// It does not make sense to make a std::mutex const.
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
std::mutex CurlHolder::curl_easy_init_mutex_{};
CurlHolder::CurlHolder() {
/**
* Allow multithreaded access to CPR by locking curl_easy_init().
@@ -14,22 +10,24 @@ CurlHolder::CurlHolder() {
* https://curl.haxx.se/libcurl/c/curl_easy_init.html
* https://curl.haxx.se/libcurl/c/threadsafe.html
**/
curl_easy_init_mutex_.lock();
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();
curl_easy_init_mutex_().unlock();
assert(handle);
} // namespace cpr
CurlHolder::~CurlHolder() {
curl_slist_free_all(chunk);
curl_formfree(formpost);
curl_slist_free_all(resolveCurlList);
curl_mime_free(multipart);
curl_easy_cleanup(handle);
}
std::string CurlHolder::urlEncode(const std::string& s) const {
assert(handle);
char* output = curl_easy_escape(handle, s.c_str(), s.length());
char* output = curl_easy_escape(handle, s.c_str(), static_cast<int>(s.length()));
if (output) {
std::string result = output;
curl_free(output);
@@ -40,7 +38,7 @@ std::string CurlHolder::urlEncode(const std::string& s) const {
std::string CurlHolder::urlDecode(const std::string& s) const {
assert(handle);
char* output = curl_easy_unescape(handle, s.c_str(), s.length(), nullptr);
char* output = curl_easy_unescape(handle, s.c_str(), static_cast<int>(s.length()), nullptr);
if (output) {
std::string result = output;
curl_free(output);

15
vendor/CPR/cpr/curlmultiholder.cpp vendored Normal file
View 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

View File

@@ -59,7 +59,7 @@ ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
case CURLE_SSL_ISSUER_ERROR:
return ErrorCode::SSL_CACERT_ERROR;
case CURLE_TOO_MANY_REDIRECTS:
return ErrorCode::OK;
return ErrorCode::TOO_MANY_REDIRECTS;
default:
return ErrorCode::INTERNAL_ERROR;
}

60
vendor/CPR/cpr/file.cpp vendored Normal file
View File

@@ -0,0 +1,60 @@
#include "cpr/file.h"
namespace cpr {
Files::Files(const std::initializer_list<std::string>& p_filepaths) {
for (const std::string& filepath : p_filepaths) {
files.emplace_back(filepath);
}
}
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();
}
Files& Files::operator=(const Files& other) {
if (&other != this) {
files = other.files;
}
return *this;
}
Files& Files::operator=(Files&& old) noexcept {
if (&old != this) {
files = std::move(old.files);
}
return *this;
}
} // namespace cpr

53
vendor/CPR/cpr/interceptor.cpp vendored Normal file
View File

@@ -0,0 +1,53 @@
#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 proceed 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!"};
}
std::vector<Response> InterceptorMulti::proceed(MultiPerform& multi) {
return multi.proceed();
}
void InterceptorMulti::PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write) {
multi.PrepareDownloadSessions(sessions_index, write);
}
} // namespace cpr

View File

@@ -2,4 +2,6 @@
namespace cpr {
Multipart::Multipart(const std::initializer_list<Part>& p_parts) : parts{p_parts} {}
Multipart::Multipart(const std::vector<Part>& p_parts) : parts{p_parts} {}
Multipart::Multipart(const std::vector<Part>&& p_parts) : parts{p_parts} {}
} // namespace cpr

323
vendor/CPR/cpr/multiperform.cpp vendored Normal file
View File

@@ -0,0 +1,323 @@
#include "cpr/multiperform.h"
#include "cpr/interceptor.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
namespace cpr {
MultiPerform::MultiPerform() : multicurl_(new CurlMultiHolder()) {}
MultiPerform::~MultiPerform() {
// Unlock all sessions
for (const 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
const 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
const 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;
}
}
std::vector<std::pair<std::shared_ptr<Session>, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() {
return sessions_;
}
const std::vector<std::pair<std::shared_ptr<Session>, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() const {
return sessions_;
}
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;
}
const 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 (const std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
Session& current_session = *(pair.first);
auto it = std::find_if(responses.begin(), responses.end(), [&current_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; });
const 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() {
if (!interceptors_.empty()) {
return intercept();
}
DoMultiPerform();
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.Complete(curl_error); });
}
std::vector<Response> MultiPerform::MakeDownloadRequest() {
if (!interceptors_.empty()) {
return intercept();
}
DoMultiPerform();
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.CompleteDownload(curl_error); });
}
void MultiPerform::PrepareSessions() {
for (const 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) {
const 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) {
const 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();
}
std::vector<Response> MultiPerform::proceed() {
// Check if this multiperform mixes download and non download requests
if (!sessions_.empty()) {
const bool new_is_download_multi_perform = sessions_.front().second == HttpMethod::DOWNLOAD_REQUEST;
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& s : sessions_) {
const HttpMethod method = s.second;
if ((new_is_download_multi_perform && method != HttpMethod::DOWNLOAD_REQUEST) || (!new_is_download_multi_perform && method == HttpMethod::DOWNLOAD_REQUEST)) {
throw std::invalid_argument("Failed to proceed with session: Cannot mix download and non-download methods!");
}
}
is_download_multi_perform = new_is_download_multi_perform;
}
PrepareSessions();
return MakeRequest();
}
std::vector<Response> MultiPerform::intercept() {
// At least one interceptor exists -> Execute its intercept function
const std::shared_ptr<InterceptorMulti> interceptor = interceptors_.front();
interceptors_.pop();
return interceptor->intercept(*this);
}
void MultiPerform::AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor) {
interceptors_.push(pinterceptor);
}
} // namespace cpr

View File

@@ -1,10 +1,4 @@
#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

View File

@@ -1,10 +1,4 @@
#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

View File

@@ -7,8 +7,8 @@
namespace cpr {
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts)
: hosts_{hosts} {}
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;

View File

@@ -1,16 +1,30 @@
#include "cpr/proxyauth.h"
#include "cpr/util.h"
namespace cpr {
const char* EncodedAuthentication::GetAuthString() const noexcept {
return auth_string_.c_str();
EncodedAuthentication::~EncodedAuthentication() noexcept {
util::secureStringClear(username);
util::secureStringClear(password);
}
const std::string& EncodedAuthentication::GetUsername() const {
return username;
}
const std::string& EncodedAuthentication::GetPassword() const {
return password;
}
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();
const char* ProxyAuthentication::GetUsername(const std::string& protocol) {
return proxyAuth_[protocol].username.c_str();
}
const char* ProxyAuthentication::GetPassword(const std::string& protocol) {
return proxyAuth_[protocol].password.c_str();
}
} // namespace cpr

View File

@@ -19,7 +19,7 @@ PostRedirectFlags operator~(PostRedirectFlags 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);
const uint8_t tmp = static_cast<uint8_t>(lhs);
lhs = static_cast<PostRedirectFlags>(tmp);
return lhs;
}

View File

@@ -1,12 +1,9 @@
#include "cpr/response.h"
namespace cpr {
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
std::string&& p_header_string, Cookies&& p_cookies = Cookies{},
Error&& p_error = Error{})
: curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)),
error(std::move(p_error)) {
header = cpr::util::parseHeader(p_header_string, &status_line, &reason);
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);
@@ -14,7 +11,7 @@ Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
char* url_string{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string);
url = Url(url_string);
#if LIBCURL_VERSION_NUM >= 0x073700
#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes);
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes);
#else
@@ -27,20 +24,21 @@ Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text,
curl_easy_getinfo(curl_->handle, CURLINFO_REDIRECT_COUNT, &redirect_count);
}
std::vector<std::string> Response::GetCertInfo() {
std::vector<CertInfo> Response::GetCertInfos() {
assert(curl_);
assert(curl_->handle);
curl_certinfo* ci{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
std::vector<std::string> info;
info.resize(ci->num_of_certs);
std::vector<CertInfo> cert_infos;
for (int i = 0; i < ci->num_of_certs; i++) {
// No way around here.
CertInfo cert_info;
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic)
info[i] = std::string{ci->certinfo[i]->data};
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 info;
return cert_infos;
}
} // namespace cpr

File diff suppressed because it is too large Load Diff

70
vendor/CPR/cpr/ssl_ctx.cpp vendored Normal file
View 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
const 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
vendor/CPR/cpr/threadpool.cpp vendored Normal file
View 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;
if (initialRun) {
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) {
const 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

View File

@@ -14,12 +14,12 @@ long Timeout::Milliseconds() const {
// No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int)
if (ms.count() > std::numeric_limits<long>::max()) {
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() < std::numeric_limits<long>::min()) {
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.");
}

View File

@@ -3,23 +3,64 @@
#include <algorithm>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <ios>
#include <sstream>
#include <string>
#include <vector>
namespace cpr {
namespace util {
#if defined(_Win32)
#include <Windows.h>
#else
#ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wreserved-macro-identifier") // Not all versions of clang support this flag like the one used on Ubuntu 18.04
#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
#endif
#pragma clang diagnostic ignored "-Wunused-macros"
#endif
// 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
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#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');
std::string value = tokens.back();
tokens.pop_back();
cookies[tokens.back()] = value;
while (tokens.size() < CURL_HTTP_COOKIE_SIZE) {
tokens.emplace_back("");
}
const 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;
}
@@ -36,7 +77,6 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
}
for (std::string& line : lines) {
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
if (line.substr(0, 5) == "HTTP/") {
// set the status_line if it was given
if ((status_line != nullptr) || (reason != nullptr)) {
@@ -47,7 +87,7 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
// set the reason if it was given
if (reason != nullptr) {
size_t pos1 = line.find_first_of("\t ");
const 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);
@@ -62,7 +102,7 @@ Header parseHeader(const std::string& headers, std::string* status_line, std::st
}
if (line.length() > 0) {
size_t found = line.find(':');
const 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 "));
@@ -105,7 +145,7 @@ size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data) {
size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) {
size *= nmemb;
file->write(ptr, size);
file->write(ptr, static_cast<std::streamsize>(size));
return size;
}
@@ -114,19 +154,8 @@ size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallba
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;
}
int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size,
const DebugCallback* debug) {
(*debug)(DebugCallback::InfoType(type), std::string(data, size));
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;
}
@@ -141,7 +170,7 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s
* std::string result = holder.urlEncode(input);
**/
std::string urlEncode(const std::string& s) {
CurlHolder holder; // Create a temporary new holder for URL encoding
const CurlHolder holder; // Create a temporary new holder for URL encoding
return holder.urlEncode(s);
}
@@ -156,9 +185,54 @@ std::string urlEncode(const std::string& s) {
* std::string result = holder.urlDecode(input);
**/
std::string urlDecode(const std::string& s) {
CurlHolder holder; // Create a temporary new holder for URL decoding
const CurlHolder holder; // Create a temporary new holder for URL decoding
return holder.urlDecode(s);
}
} // namespace util
} // namespace cpr
#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