diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b0a43de..917dc243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/vendor/POCO/cmake) # Several plugin options option(ENABLE_API21 "Build for 2.1 API." OFF) -option(ENABLE_OFFICIAL "Enable compatibility with official legacy plug-in" OFF) +option(ENABLE_OFFICIAL "Enable compatibility with official legacy plug-in" ON) option(FORCE_32BIT_BIN "Create a 32-bit executable binary if the compiler defaults to 64-bit." OFF) # This option should only be available in certain conditions if(WIN32 AND MINGW) diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index 63e0592b..45ff5f4f 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -64,6 +64,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp Library/Chrono/Time.cpp Library/Chrono/Time.hpp Library/Chrono/Timer.cpp Library/Chrono/Timer.hpp Library/Chrono/Timestamp.cpp Library/Chrono/Timestamp.hpp + Library/CURL.cpp Library/CURL.hpp Library/IO.cpp Library/IO.hpp Library/IO/Buffer.cpp Library/IO/Buffer.hpp Library/IO/File.cpp Library/IO/File.hpp @@ -126,7 +127,7 @@ if(WIN32 OR MINGW) target_link_libraries(SqModule wsock32 ws2_32 shlwapi) endif() # Link to base libraries -target_link_libraries(SqModule Squirrel FmtLib SimpleINI TinyDir ConcurrentQueue maxminddb libzmq-static) +target_link_libraries(SqModule Squirrel FmtLib SimpleINI TinyDir ConcurrentQueue CPR maxminddb libzmq-static) # Link to POCO libraries target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML) # Does POCO have SQLite support? diff --git a/module/Library/CURL.cpp b/module/Library/CURL.cpp new file mode 100644 index 00000000..d7a38ff7 --- /dev/null +++ b/module/Library/CURL.cpp @@ -0,0 +1,376 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/CURL.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQMOD_DECL_TYPENAME(SqCpSslOptions, _SC("SqCprSslOptions")) +SQMOD_DECL_TYPENAME(SqCpError, _SC("SqCprError")) +SQMOD_DECL_TYPENAME(SqCpCookies, _SC("SqCprCookies")) +SQMOD_DECL_TYPENAME(SqCpHeader, _SC("SqCprHeader")) +SQMOD_DECL_TYPENAME(SqCpResponse, _SC("SqCprResponse")) +SQMOD_DECL_TYPENAME(SqCpParameters, _SC("SqCprParameters")) +SQMOD_DECL_TYPENAME(SqCpPayload, _SC("SqCprPayload")) +SQMOD_DECL_TYPENAME(SqCpProxies, _SC("SqCprProxies")) +SQMOD_DECL_TYPENAME(SqCpSession, _SC("SqCprSession")) + +// ------------------------------------------------------------------------------------------------ +static const EnumElement g_ErrorCodes[] = { + {_SC("OK"), SQInteger(cpr::ErrorCode::OK)}, + {_SC("CONNECTION_FAILURE"), SQInteger(cpr::ErrorCode::CONNECTION_FAILURE)}, + {_SC("EMPTY_RESPONSE"), SQInteger(cpr::ErrorCode::EMPTY_RESPONSE)}, + {_SC("HOST_RESOLUTION_FAILURE"), SQInteger(cpr::ErrorCode::HOST_RESOLUTION_FAILURE)}, + {_SC("INTERNAL_ERROR"), SQInteger(cpr::ErrorCode::INTERNAL_ERROR)}, + {_SC("INVALID_URL_FORMAT"), SQInteger(cpr::ErrorCode::INVALID_URL_FORMAT)}, + {_SC("NETWORK_RECEIVE_ERROR"), SQInteger(cpr::ErrorCode::NETWORK_RECEIVE_ERROR)}, + {_SC("NETWORK_SEND_FAILURE"), SQInteger(cpr::ErrorCode::NETWORK_SEND_FAILURE)}, + {_SC("OPERATION_TIMEDOUT"), SQInteger(cpr::ErrorCode::OPERATION_TIMEDOUT)}, + {_SC("PROXY_RESOLUTION_FAILURE"), SQInteger(cpr::ErrorCode::PROXY_RESOLUTION_FAILURE)}, + {_SC("SSL_CONNECT_ERROR"), SQInteger(cpr::ErrorCode::SSL_CONNECT_ERROR)}, + {_SC("SSL_LOCAL_CERTIFICATE_ERROR"), SQInteger(cpr::ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR)}, + {_SC("SSL_REMOTE_CERTIFICATE_ERROR"), SQInteger(cpr::ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR)}, + {_SC("SSL_CACERT_ERROR"), SQInteger(cpr::ErrorCode::SSL_CACERT_ERROR)}, + {_SC("GENERIC_SSL_ERROR"), SQInteger(cpr::ErrorCode::GENERIC_SSL_ERROR)}, + {_SC("UNSUPPORTED_PROTOCOL"), SQInteger(cpr::ErrorCode::UNSUPPORTED_PROTOCOL)}, + {_SC("REQUEST_CANCELLED"), SQInteger(cpr::ErrorCode::REQUEST_CANCELLED)}, + {_SC("UNKNOWN_ERROR"), SQInteger(cpr::ErrorCode::UNKNOWN_ERROR)} +}; + +// ------------------------------------------------------------------------------------------------ +static const EnumElement g_StatusCodes[] = { + // Information responses + {_SC("HTTP_CONTINUE"), cpr::status::HTTP_CONTINUE}, + {_SC("HTTP_SWITCHING_PROTOCOL"), cpr::status::HTTP_SWITCHING_PROTOCOL}, + {_SC("HTTP_PROCESSING"), cpr::status::HTTP_PROCESSING}, + {_SC("HTTP_EARLY_HINTS"), cpr::status::HTTP_EARLY_HINTS}, + // Successful responses + {_SC("HTTP_OK"), cpr::status::HTTP_OK}, + {_SC("HTTP_CREATED"), cpr::status::HTTP_CREATED}, + {_SC("HTTP_ACCEPTED"), cpr::status::HTTP_ACCEPTED}, + {_SC("HTTP_NON_AUTHORITATIVE_INFORMATION"), cpr::status::HTTP_NON_AUTHORITATIVE_INFORMATION}, + {_SC("HTTP_NO_CONTENT"), cpr::status::HTTP_NO_CONTENT}, + {_SC("HTTP_RESET_CONTENT"), cpr::status::HTTP_RESET_CONTENT}, + {_SC("HTTP_PARTIAL_CONTENT"), cpr::status::HTTP_PARTIAL_CONTENT}, + {_SC("HTTP_MULTI_STATUS"), cpr::status::HTTP_MULTI_STATUS}, + {_SC("HTTP_ALREADY_REPORTED"), cpr::status::HTTP_ALREADY_REPORTED}, + {_SC("HTTP_IM_USED"), cpr::status::HTTP_IM_USED}, + // Redirection messages + {_SC("HTTP_MULTIPLE_CHOICE"), cpr::status::HTTP_MULTIPLE_CHOICE}, + {_SC("HTTP_MOVED_PERMANENTLY"), cpr::status::HTTP_MOVED_PERMANENTLY}, + {_SC("HTTP_FOUND"), cpr::status::HTTP_FOUND}, + {_SC("HTTP_SEE_OTHER"), cpr::status::HTTP_SEE_OTHER}, + {_SC("HTTP_NOT_MODIFIED"), cpr::status::HTTP_NOT_MODIFIED}, + {_SC("HTTP_USE_PROXY"), cpr::status::HTTP_USE_PROXY}, + {_SC("HTTP_UNUSED"), cpr::status::HTTP_UNUSED}, + {_SC("HTTP_TEMPORARY_REDIRECT"), cpr::status::HTTP_TEMPORARY_REDIRECT}, + {_SC("HTTP_PERMANENT_REDIRECT"), cpr::status::HTTP_PERMANENT_REDIRECT}, + // Client error responses + {_SC("HTTP_BAD_REQUEST"), cpr::status::HTTP_BAD_REQUEST}, + {_SC("HTTP_UNAUTHORIZED"), cpr::status::HTTP_UNAUTHORIZED}, + {_SC("HTTP_PAYMENT_REQUIRED"), cpr::status::HTTP_PAYMENT_REQUIRED}, + {_SC("HTTP_FORBIDDEN"), cpr::status::HTTP_FORBIDDEN}, + {_SC("HTTP_NOT_FOUND"), cpr::status::HTTP_NOT_FOUND}, + {_SC("HTTP_METHOD_NOT_ALLOWED"), cpr::status::HTTP_METHOD_NOT_ALLOWED}, + {_SC("HTTP_NOT_ACCEPTABLE"), cpr::status::HTTP_NOT_ACCEPTABLE}, + {_SC("HTTP_PROXY_AUTHENTICATION_REQUIRED"), cpr::status::HTTP_PROXY_AUTHENTICATION_REQUIRED}, + {_SC("HTTP_REQUEST_TIMEOUT"), cpr::status::HTTP_REQUEST_TIMEOUT}, + {_SC("HTTP_CONFLICT"), cpr::status::HTTP_CONFLICT}, + {_SC("HTTP_GONE"), cpr::status::HTTP_GONE}, + {_SC("HTTP_LENGTH_REQUIRED"), cpr::status::HTTP_LENGTH_REQUIRED}, + {_SC("HTTP_PRECONDITION_FAILED"), cpr::status::HTTP_PRECONDITION_FAILED}, + {_SC("HTTP_PAYLOAD_TOO_LARGE"), cpr::status::HTTP_PAYLOAD_TOO_LARGE}, + {_SC("HTTP_URI_TOO_LONG"), cpr::status::HTTP_URI_TOO_LONG}, + {_SC("HTTP_UNSUPPORTED_MEDIA_TYPE"), cpr::status::HTTP_UNSUPPORTED_MEDIA_TYPE}, + {_SC("HTTP_REQUESTED_RANGE_NOT_SATISFIABLE"), cpr::status::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE}, + {_SC("HTTP_EXPECTATION_FAILED"), cpr::status::HTTP_EXPECTATION_FAILED}, + {_SC("HTTP_IM_A_TEAPOT"), cpr::status::HTTP_IM_A_TEAPOT}, + {_SC("HTTP_MISDIRECTED_REQUEST"), cpr::status::HTTP_MISDIRECTED_REQUEST}, + {_SC("HTTP_UNPROCESSABLE_ENTITY"), cpr::status::HTTP_UNPROCESSABLE_ENTITY}, + {_SC("HTTP_LOCKED"), cpr::status::HTTP_LOCKED}, + {_SC("HTTP_FAILED_DEPENDENCY"), cpr::status::HTTP_FAILED_DEPENDENCY}, + {_SC("HTTP_TOO_EARLY"), cpr::status::HTTP_TOO_EARLY}, + {_SC("HTTP_UPGRADE_REQUIRED"), cpr::status::HTTP_UPGRADE_REQUIRED}, + {_SC("HTTP_PRECONDITION_REQUIRED"), cpr::status::HTTP_PRECONDITION_REQUIRED}, + {_SC("HTTP_TOO_MANY_REQUESTS"), cpr::status::HTTP_TOO_MANY_REQUESTS}, + {_SC("HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE"), cpr::status::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE}, + {_SC("HTTP_UNAVAILABLE_FOR_LEGAL_REASONS"), cpr::status::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS}, + // Server response errors + {_SC("HTTP_INTERNAL_SERVER_ERROR"), cpr::status::HTTP_INTERNAL_SERVER_ERROR}, + {_SC("HTTP_NOT_IMPLEMENTED"), cpr::status::HTTP_NOT_IMPLEMENTED}, + {_SC("HTTP_BAD_GATEWAY"), cpr::status::HTTP_BAD_GATEWAY}, + {_SC("HTTP_SERVICE_UNAVAILABLE"), cpr::status::HTTP_SERVICE_UNAVAILABLE}, + {_SC("HTTP_GATEWAY_TIMEOUT"), cpr::status::HTTP_GATEWAY_TIMEOUT}, + {_SC("HTTP_HTTP_VERSION_NOT_SUPPORTED"), cpr::status::HTTP_HTTP_VERSION_NOT_SUPPORTED}, + {_SC("HTTP_VARIANT_ALSO_NEGOTIATES"), cpr::status::HTTP_VARIANT_ALSO_NEGOTIATES}, + {_SC("HTTP_INSUFFICIENT_STORAGE"), cpr::status::HTTP_INSUFFICIENT_STORAGE}, + {_SC("HTTP_LOOP_DETECTED"), cpr::status::HTTP_LOOP_DETECTED}, + {_SC("HTTP_NOT_EXTENDED"), cpr::status::HTTP_NOT_EXTENDED}, + {_SC("HTTP_NETWORK_AUTHENTICATION_REQUIRED"), cpr::status::HTTP_NETWORK_AUTHENTICATION_REQUIRED}, + + {_SC("INFO_CODE_OFFSET"), cpr::status::INFO_CODE_OFFSET}, + {_SC("SUCCESS_CODE_OFFSET"), cpr::status::SUCCESS_CODE_OFFSET}, + {_SC("REDIRECT_CODE_OFFSET"), cpr::status::REDIRECT_CODE_OFFSET}, + {_SC("CLIENT_ERROR_CODE_OFFSET"), cpr::status::CLIENT_ERROR_CODE_OFFSET}, + {_SC("SERVER_ERROR_CODE_OFFSET"), cpr::status::SERVER_ERROR_CODE_OFFSET}, + {_SC("MISC_CODE_OFFSET"), cpr::status::MISC_CODE_OFFSET} +}; + +// ------------------------------------------------------------------------------------------------ +static const EnumElements g_EnumList[] = { + {_SC("SqCprErrorCode"), g_ErrorCodes}, + {_SC("SqCprStatusCode"), g_StatusCodes} +}; + +// ================================================================================================ +void Register_CURL(HSQUIRRELVM vm) +{ + Table cpns(vm); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("SslOptions"), + Class< CpSslOptions >(vm, SqCpSslOptions::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpSslOptions::Fn) + // Properties + .Prop(_SC("CertFile"), &CpSslOptions::GetCertFile) + .Prop(_SC("CertType"), &CpSslOptions::GetCertType, &CpSslOptions::SetCertType) + .Prop(_SC("KeyFile"), &CpSslOptions::GetKeyFile) + .Prop(_SC("KeyType"), &CpSslOptions::GetKeyType, &CpSslOptions::SetKeyType) + .Prop(_SC("KeyPass"), &CpSslOptions::GetKeyPass, &CpSslOptions::SetKeyPass) + .Prop(_SC("ALPN"), &CpSslOptions::GetALPN, &CpSslOptions::SetALPN) + .Prop(_SC("NPM"), &CpSslOptions::GetNPM, &CpSslOptions::SetNPM) + .Prop(_SC("VerifyHost"), &CpSslOptions::GetVerifyHost, &CpSslOptions::SetVerifyHost) + .Prop(_SC("VerifyPeer"), &CpSslOptions::GetVerifyPeer, &CpSslOptions::SetVerifyPeer) + .Prop(_SC("VerifyStatus"), &CpSslOptions::GetVerifyStatus, &CpSslOptions::SetVerifyStatus) + .Prop(_SC("SslVersion"), &CpSslOptions::GetSslVersion) + .Prop(_SC("MaxVersion"), &CpSslOptions::GetMaxVersion) + .Prop(_SC("CaInfo"), &CpSslOptions::GetCaInfo, &CpSslOptions::SetCaInfo) + .Prop(_SC("CaPath"), &CpSslOptions::GetCaPath, &CpSslOptions::SetCaPath) + .Prop(_SC("CrlFile"), &CpSslOptions::GetCrlFile, &CpSslOptions::SetCrlFile) + .Prop(_SC("Ciphers"), &CpSslOptions::GetCiphers, &CpSslOptions::SetCiphers) + .Prop(_SC("TLS13Ciphers"), &CpSslOptions::GetTLS13Ciphers, &CpSslOptions::SetTLS13Ciphers) + .Prop(_SC("SessionIdCache"), &CpSslOptions::GetSessionIdCache, &CpSslOptions::SetSessionIdCache) + // Member Methods + .Func(_SC("SetCertFile"), &CpSslOptions::SetCertFile) + .Func(_SC("SetPemCertFile"), &CpSslOptions::SetPemCertFile) + .Func(_SC("SetDerCertFile"), &CpSslOptions::SetDerCertFile) + .Func(_SC("SetKeyFile"), &CpSslOptions::SetKeyFile) + .Func(_SC("SetPemKeyFile"), &CpSslOptions::SetPemKeyFile) + .Func(_SC("SetDerKeyFile"), &CpSslOptions::SetDerKeyFile) + .Func(_SC("SetTLSv1"), &CpSslOptions::SetTLSv1) + .Func(_SC("SetSSLv2"), &CpSslOptions::SetSSLv2) + .Func(_SC("SetSSLv3"), &CpSslOptions::SetSSLv3) + .Func(_SC("SetTLSv1_0"), &CpSslOptions::SetTLSv1_0) + .Func(_SC("SetTLSv1_1"), &CpSslOptions::SetTLSv1_1) + .Func(_SC("SetTLSv1_2"), &CpSslOptions::SetTLSv1_2) + .Func(_SC("SetTLSv1_3"), &CpSslOptions::SetTLSv1_3) + .Func(_SC("SetMaxTLSVersion"), &CpSslOptions::SetMaxTLSVersion) + .Func(_SC("SetMaxTLSv1_0"), &CpSslOptions::SetMaxTLSv1_0) + .Func(_SC("SetMaxTLSv1_1"), &CpSslOptions::SetMaxTLSv1_1) + .Func(_SC("SetMaxTLSv1_2"), &CpSslOptions::SetMaxTLSv1_2) + .Func(_SC("SetMaxTLSv1_3"), &CpSslOptions::SetMaxTLSv1_3) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Error"), + Class< CpError >(vm, SqCpError::Str) + // Constructors + .Ctor() + .Ctor< SQInteger, StackStrF & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpError::Fn) + // Properties + .Prop(_SC("Code"), &CpError::GetCode, &CpError::SetCode) + .Prop(_SC("Message"), &CpError::GetMessage, &CpError::SetMessage) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Cookies"), + Class< CpCookies >(vm, SqCpCookies::Str) + // Constructors + .Ctor() + .Ctor< bool >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpCookies::Fn) + // Properties + .Prop(_SC("Size"), &CpCookies::Size) + .Prop(_SC("Empty"), &CpCookies::Empty) + // Member Methods + .FmtFunc(_SC("Count"), &CpCookies::Count) + .FmtFunc(_SC("Erase"), &CpCookies::Erase) + .FmtFunc(_SC("Has"), &CpCookies::Has) + .FmtFunc(_SC("Get"), &CpCookies::Get) + .FmtFunc(_SC("Set"), &CpCookies::Set) + .CbFunc(_SC("Each"), &CpCookies::Each) + .CbFunc(_SC("While"), &CpCookies::While) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Header"), + Class< CpHeader >(vm, SqCpHeader::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpHeader::Fn) + // Properties + .Prop(_SC("Size"), &CpHeader::Size) + .Prop(_SC("Empty"), &CpHeader::Empty) + // Member Methods + .FmtFunc(_SC("Count"), &CpHeader::Count) + .FmtFunc(_SC("Erase"), &CpHeader::Erase) + .FmtFunc(_SC("Has"), &CpHeader::Has) + .FmtFunc(_SC("Get"), &CpHeader::Get) + .FmtFunc(_SC("Set"), &CpHeader::Set) + .CbFunc(_SC("Each"), &CpHeader::Each) + .CbFunc(_SC("While"), &CpHeader::While) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Response"), + Class< CpResponse >(vm, SqCpResponse::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpResponse::Fn) + // Properties + .Prop(_SC("CertInfo"), &CpResponse::GetCertInfoArray) + .Prop(_SC("StatusCode"), &CpResponse::GetStatusCode, &CpResponse::SetStatusCode) + .Prop(_SC("Text"), &CpResponse::GetText, &CpResponse::SetText) + .Prop(_SC("Header"), &CpResponse::GetHeader, &CpResponse::SetHeader) + .Prop(_SC("URL"), &CpResponse::GetURL, &CpResponse::SetURL) + .Prop(_SC("Cookies"), &CpResponse::GetCookies, &CpResponse::SetCookies) + .Prop(_SC("Error"), &CpResponse::GetError, &CpResponse::SetError) + .Prop(_SC("RawHeader"), &CpResponse::GetRawHeader, &CpResponse::SetRawHeader) + .Prop(_SC("StatusLine"), &CpResponse::GetStatusLine, &CpResponse::SetStatusLine) + .Prop(_SC("Reason"), &CpResponse::GetReason, &CpResponse::SetReason) + .Prop(_SC("UploadedBytes"), &CpResponse::GetUploadedBytes, &CpResponse::SetUploadedBytes) + .Prop(_SC("DownloadedBytes"), &CpResponse::GetDownloadedBytes, &CpResponse::SetDownloadedBytes) + .Prop(_SC("RedirectCount"), &CpResponse::GetRedirectCount, &CpResponse::SetRedirectCount) + // Member Methods + .FmtFunc(_SC("StealHeader"), &CpResponse::StealHeader) + .FmtFunc(_SC("YieldHeader"), &CpResponse::YieldHeader) + .FmtFunc(_SC("StealCookies"), &CpResponse::StealCookies) + .FmtFunc(_SC("YieldCookies"), &CpResponse::YieldCookies) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Parameters"), + Class< CpParameters >(vm, SqCpParameters::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpParameters::Fn) + // Properties + .Prop(_SC("Size"), &CpParameters::Size) + .Prop(_SC("Empty"), &CpParameters::Empty) + // Member Methods + .FmtFunc(_SC("Count"), &CpParameters::Count) + .FmtFunc(_SC("Erase"), &CpParameters::Erase) + .FmtFunc(_SC("Has"), &CpParameters::Has) + .FmtFunc(_SC("Get"), &CpParameters::Get) + .FmtFunc(_SC("Set"), &CpParameters::Set) + .CbFunc(_SC("Each"), &CpParameters::Each) + .CbFunc(_SC("While"), &CpParameters::While) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Payload"), + Class< CpPayload >(vm, SqCpPayload::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpPayload::Fn) + // Properties + .Prop(_SC("Size"), &CpPayload::Size) + .Prop(_SC("Empty"), &CpPayload::Empty) + // Member Methods + .FmtFunc(_SC("Count"), &CpPayload::Count) + .FmtFunc(_SC("Erase"), &CpPayload::Erase) + .FmtFunc(_SC("Has"), &CpPayload::Has) + .FmtFunc(_SC("Get"), &CpPayload::Get) + .FmtFunc(_SC("Set"), &CpPayload::Set) + .FmtFunc(_SC("Add"), &CpPayload::Add) + .CbFunc(_SC("Each"), &CpPayload::Each) + .CbFunc(_SC("While"), &CpPayload::While) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Proxies"), + Class< CpProxies >(vm, SqCpProxies::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpProxies::Fn) + // Properties + .Prop(_SC("Size"), &CpProxies::Size) + .Prop(_SC("Empty"), &CpProxies::Empty) + // Member Methods + .FmtFunc(_SC("Count"), &CpProxies::Count) + .FmtFunc(_SC("Erase"), &CpProxies::Erase) + .FmtFunc(_SC("Has"), &CpProxies::Has) + .FmtFunc(_SC("Get"), &CpProxies::Get) + .FmtFunc(_SC("Set"), &CpProxies::Set) + .CbFunc(_SC("Each"), &CpProxies::Each) + .CbFunc(_SC("While"), &CpProxies::While) + ); + + // -------------------------------------------------------------------------------------------- + cpns.Bind(_SC("Session"), + Class< CpSession, NoCopy< CpSession > >(vm, SqCpSession::Str) + // Constructors + .Ctor() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqCpSession::Fn) + // Member Methods + .FmtFunc(_SC("SetURL"), &CpSession::SetURL_) + .Func(_SC("SetParameters"), &CpSession::SetParameters_) + .Func(_SC("YieldParameters"), &CpSession::YieldParameters) + .Func(_SC("SetHeader"), &CpSession::SetHeader_) + .Func(_SC("SetTimeout"), &CpSession::SetTimeout_) + .Func(_SC("SetConnectTimeout"), &CpSession::SetConnectTimeout_) + .FmtFunc(_SC("SetAuth"), &CpSession::SetAuth_) + .FmtFunc(_SC("SetDigest"), &CpSession::SetDigest_) + .FmtFunc(_SC("SetUserAgent"), &CpSession::SetUserAgent_) + .Func(_SC("SetPayload"), &CpSession::SetPayload_) + .Func(_SC("YieldPayload"), &CpSession::YieldPayload) + .Func(_SC("SetProxies"), &CpSession::SetProxies_) + .Func(_SC("YieldProxies"), &CpSession::YieldProxies) + .FmtFunc(_SC("SetNTLM"), &CpSession::SetNTLM_) + .Func(_SC("SetRedirect"), &CpSession::SetRedirect_) + .Func(_SC("SetMaxRedirects"), &CpSession::SetMaxRedirects_) + .Func(_SC("SetCookies"), &CpSession::SetCookies_) + .FmtFunc(_SC("SetBody"), &CpSession::SetBody_) + .Func(_SC("SetLowSpeed"), &CpSession::SetLowSpeed_) + .Func(_SC("SetVerifySsl"), &CpSession::SetVerifySsl_) + .Func(_SC("SetUnixSocket"), &CpSession::SetUnixSocket_) + .Func(_SC("SetSslOptions"), &CpSession::SetSslOptions_) + .FmtFunc(_SC("SetVerbose"), &CpSession::SetVerbose_) + .Func(_SC("Delete"), &CpSession::DoDelete) + .Func(_SC("Get"), &CpSession::DoGet) + .Func(_SC("Head"), &CpSession::DoHead) + .Func(_SC("Options"), &CpSession::DoOptions) + .Func(_SC("Patch"), &CpSession::DoPatch) + .Func(_SC("Post"), &CpSession::DoPost) + .Func(_SC("Put"), &CpSession::DoPut) + ); + + RootTable(vm).Bind(_SC("SqCPR"), cpns); + + // -------------------------------------------------------------------------------------------- + RegisterEnumerations(vm, g_EnumList); + + RootTable(vm) + .Func(_SC("IsInformationalStatus"), cpr::status::is_informational) + .Func(_SC("IsSuccessStatus"), cpr::status::is_success) + .Func(_SC("IsRedirectStatus"), cpr::status::is_redirect) + .Func(_SC("IsClientErrorStatus"), cpr::status::is_client_error) + .Func(_SC("IsServerErrorStatus"), cpr::status::is_server_error); +} + +} // Namespace:: SqMod diff --git a/module/Library/CURL.hpp b/module/Library/CURL.hpp new file mode 100644 index 00000000..9c6edac7 --- /dev/null +++ b/module/Library/CURL.hpp @@ -0,0 +1,1958 @@ +#pragma once + +// ------------------------------------------------------------------------------------------------ +#include "Core/Common.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Options that can be bound to the script engine. +*/ +struct CpSslOptions : public cpr::SslOptions +{ + using Base = cpr::SslOptions; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpSslOptions() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpSslOptions(const CpSslOptions &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpSslOptions(CpSslOptions &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpSslOptions() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpSslOptions & operator = (const CpSslOptions &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpSslOptions & operator = (CpSslOptions &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::cert_file value. + */ + SQMOD_NODISCARD const std::string & GetCertFile() const { return Base::cert_file; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file and cpr::SslOptions::cert_type values. + */ + void SetCertFile(StackStrF & type, StackStrF & file) + { + cert_file.assign(file.mPtr, file.GetSize()); + cert_type.assign(type.mPtr, type.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file values. + */ + void SetPemCertFile(StackStrF & file) + { + cert_file.assign(file.mPtr, file.GetSize()); + cert_type.assign("PEM"); + } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file values. + */ + void SetDerCertFile(StackStrF & file) + { + cert_file.assign(file.mPtr, file.GetSize()); + cert_type.assign("DER"); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::cert_type value. + */ + SQMOD_NODISCARD const std::string & GetCertType() const { return Base::cert_type; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_type values. + */ + void SetCertType(StackStrF & type) { cert_type.assign(type.mPtr, type.GetSize()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::key_file value. + */ + SQMOD_NODISCARD const std::string & GetKeyFile() const { return Base::key_file; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file, cpr::SslOptions::key_pass and cpr::SslOptions::cert_type values. + */ + void SetKeyFile(StackStrF & type, StackStrF & pass, StackStrF & file) + { + key_file.assign(file.mPtr, file.GetSize()); + key_type.assign(type.mPtr, type.GetSize()); + key_pass.assign(pass.mPtr, pass.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file, cpr::SslOptions::key_pass values. + */ + void SetPemKeyFile(StackStrF & type, StackStrF & pass, StackStrF & file) + { + key_file.assign(file.mPtr, file.GetSize()); + key_type.assign("PEM"); + key_pass.assign(pass.mPtr, pass.GetSize()); + } + + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::cert_file, cpr::SslOptions::key_pass values. + */ + void SetDerKeyFile(StackStrF & type, StackStrF & pass, StackStrF & file) + { + key_file.assign(file.mPtr, file.GetSize()); + key_type.assign("DER"); + key_pass.assign(pass.mPtr, pass.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::key_type value. + */ + SQMOD_NODISCARD const std::string & GetKeyType() const { return Base::key_type; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::key_type values. + */ + void SetKeyType(StackStrF & type) { key_type.assign(type.mPtr, type.GetSize()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::key_pass value. + */ + SQMOD_NODISCARD const std::string & GetKeyPass() const { return Base::key_pass; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::key_pass values. + */ + void SetKeyPass(StackStrF & pass) { key_pass.assign(pass.mPtr, pass.GetSize()); } + +#if SUPPORT_ALPN + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::enable_alpn value. + */ + SQMOD_NODISCARD bool GetALPN() const { return Base::enable_alpn; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::enable_alpn value. + */ + void SetALPN(bool value) { Base::enable_alpn = value; } +#else + void GetALPN() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) + void SetALPN(bool) { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif // SUPPORT_ALPN + +#if SUPPORT_NPN + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::enable_npn value. + */ + SQMOD_NODISCARD bool GetNPM() const { return Base::enable_npn; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::enable_npn value. + */ + void SetNPM(bool value) { Base::enable_npn = value; } +#else + void GetNPM() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) + void SetNPM(bool) { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif // SUPPORT_NPN + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::verify_host value. + */ + SQMOD_NODISCARD bool GetVerifyHost() const { return Base::verify_host; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::verify_host value. + */ + void SetVerifyHost(bool value) { Base::verify_host = value; } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::verify_peer value. + */ + SQMOD_NODISCARD bool GetVerifyPeer() const { return Base::verify_peer; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::verify_peer value. + */ + void SetVerifyPeer(bool value) { Base::verify_peer = value; } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::verify_status value. + */ + SQMOD_NODISCARD bool GetVerifyStatus() const { return Base::verify_status; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::verify_status value. + */ + void SetVerifyStatus(bool value) { Base::verify_status = value; } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::ssl_version value. + */ + SQMOD_NODISCARD int GetSslVersion() const { return Base::ssl_version; } + +#if SUPPORT_MAX_TLS_VERSION + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::max_version value. + */ + SQMOD_NODISCARD int GetMaxVersion() const { return Base::max_version; } +#else + void GetMaxVersion() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif // SUPPORT_MAX_TLS_VERSION + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::ca_info value. + */ + SQMOD_NODISCARD const std::string & GetCaInfo() const { return Base::ca_info; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::ca_info values. + */ + void SetCaInfo(StackStrF & info) { ca_info.assign(info.mPtr, info.GetSize()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::ca_path value. + */ + SQMOD_NODISCARD const std::string & GetCaPath() const { return Base::ca_path; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::ca_path values. + */ + void SetCaPath(StackStrF & path) { ca_path.assign(path.mPtr, path.GetSize()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::crl_file value. + */ + SQMOD_NODISCARD const std::string & GetCrlFile() const { return Base::crl_file; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::crl_file values. + */ + void SetCrlFile(StackStrF & file) { crl_file.assign(file.mPtr, file.GetSize()); } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::ciphers value. + */ + SQMOD_NODISCARD const std::string & GetCiphers() const { return Base::ciphers; } + + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::ciphers values. + */ + void SetCiphers(StackStrF & cph) { ciphers.assign(cph.mPtr, cph.GetSize()); } + +#if SUPPORT_TLSv13_CIPHERS + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::tls13_ciphers value. + */ + SQMOD_NODISCARD const std::string & GetTLS13Ciphers() const { return Base::tls13_ciphers; } + /* -------------------------------------------------------------------------------------------- + * Assign cpr::SslOptions::tls13_ciphers values. + */ + void SetTLS13Ciphers(StackStrF & cph) { tls13_ciphers.assign(cph.mPtr, cph.GetSize()); } + +#else + void GetTLS13Ciphers() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) + void SetTLS13Ciphers(StackStrF &) const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif // SUPPORT_TLSv13_CIPHERS + +#if SUPPORT_SESSIONID_CACHE + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::SslOptions::session_id_cache value. + */ + SQMOD_NODISCARD bool GetSessionIdCache() const { return Base::session_id_cache; } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::session_id_cache value. + */ + void SetSessionIdCache(bool value) { Base::session_id_cache = value; } +#else + void GetSessionIdCache() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) + void SetSessionIdCache(bool) const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif // SUPPORT_SESSIONID_CACHE + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ + void SetTLSv1() { ssl_version = CURL_SSLVERSION_TLSv1; } + +#if SUPPORT_SSLv2 + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ + void SetSSLv2() { ssl_version = CURL_SSLVERSION_SSLv2; } +#else + void SetSSLv2() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ +#if SUPPORT_SSLv3 + void SetSSLv3() { ssl_version = CURL_SSLVERSION_SSLv3; } +#else + void SetSSLv3() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ +#if SUPPORT_TLSv1_0 + void SetTLSv1_0() { ssl_version = CURL_SSLVERSION_TLSv1_0; } +#else + void SetTLSv1_0() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ +#if SUPPORT_TLSv1_1 + void SetTLSv1_1() { ssl_version = CURL_SSLVERSION_TLSv1_1; } +#else + void SetTLSv1_1() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ +#if SUPPORT_TLSv1_2 + void SetTLSv1_2() { ssl_version = CURL_SSLVERSION_TLSv1_2; } +#else + void SetTLSv1_2() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::ssl_version value. + */ +#if SUPPORT_TLSv1_3 + void SetTLSv1_3() { ssl_version = CURL_SSLVERSION_TLSv1_3; } +#else + void SetTLSv1_3() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::max_version value. + */ +#if SUPPORT_MAX_TLS_VERSION + void SetMaxTLSVersion() { max_version = CURL_SSLVERSION_DEFAULT; } +#else + void SetMaxTLSVersion() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::max_version value. + */ +#if SUPPORT_MAX_TLSv1_0 + void SetMaxTLSv1_0() { max_version = CURL_SSLVERSION_MAX_TLSv1_0; } +#else + void SetMaxTLSv1_0() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::max_version value. + */ +#if SUPPORT_MAX_TLSv1_1 + void SetMaxTLSv1_1() { max_version = CURL_SSLVERSION_MAX_TLSv1_1; } +#else + void SetMaxTLSv1_1() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::max_version value. + */ +#if SUPPORT_MAX_TLSv1_2 + void SetMaxTLSv1_2() { max_version = CURL_SSLVERSION_MAX_TLSv1_2; } +#else + void SetMaxTLSv1_2() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::SslOptions::max_version value. + */ +#if SUPPORT_MAX_TLSv1_3 + void SetMaxTLSv1_3() { max_version = CURL_SSLVERSION_MAX_TLSv1_3; } +#else + void SetMaxTLSv1_3() const { STHROWF("Unsupported"); } // NOLINT(readability-convert-member-functions-to-static) +#endif +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Error that can be bound to the script engine. +*/ +struct CpError : public cpr::Error +{ + using cpr::Error::Error; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpError() = default; + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpError(SQInteger code, StackStrF & msg) + : cpr::Error(static_cast< int32_t >(code), msg.ToStr()) + { + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpError(const cpr::Error & e) : cpr::Error(e) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpError(cpr::Error && e) : cpr::Error(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpError(const CpError &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpError(CpError &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpError() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpError & operator = (const CpError &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpError & operator = (CpError &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Error::code. + */ + SQMOD_NODISCARD SQInteger GetCode() const + { + return static_cast< SQInteger >(cpr::Error::code); + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Error::code. + */ + void SetCode(SQInteger value) + { + cpr::Error::code = static_cast< cpr::ErrorCode >(value); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Error::text. + */ + SQMOD_NODISCARD const std::string & GetMessage() const + { + return cpr::Error::message; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Error::message. + */ + void SetMessage(StackStrF & str) + { + cpr::Error::message.assign(str.mPtr, str.GetSize()); + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Cookies that can be bound to the script engine. +*/ +struct CpCookies : public cpr::Cookies +{ + using cpr::Cookies::Cookies; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpCookies() = default; + + /* -------------------------------------------------------------------------------------------- + * Encode constructor. + */ + explicit CpCookies(bool enc) : cpr::Cookies(enc) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpCookies(const cpr::Cookies & e) : cpr::Cookies(e) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpCookies(cpr::Cookies && e) : cpr::Cookies(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpCookies(const CpCookies &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpCookies(CpCookies &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpCookies() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpCookies & operator = (const CpCookies &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpCookies & operator = (CpCookies &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of values. + */ + SQMOD_NODISCARD SQInteger Size() const + { + return static_cast< SQInteger >(cpr::Cookies::map_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if no value is stored. + */ + SQMOD_NODISCARD bool Empty() const + { + return cpr::Cookies::map_.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * Clear all values. + */ + void Clear() + { + cpr::Cookies::map_.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of matching values. + */ + SQMOD_NODISCARD SQInteger Count(StackStrF & key) const + { + return static_cast< SQInteger >(cpr::Cookies::map_.count(key.ToStr())); + } + + /* -------------------------------------------------------------------------------------------- + * Remove a value. + */ + bool Erase(StackStrF & key) + { + auto itr = cpr::Cookies::map_.find(key.ToStr()); + // Does it exist? + if (itr == cpr::Cookies::map_.end()) + { + return false; // Nope + } + // Erase it + cpr::Cookies::map_.erase(itr); + // Erased + return true; + } + + /* -------------------------------------------------------------------------------------------- + * Check if value exists. + */ + SQMOD_NODISCARD bool Has(StackStrF & key) const + { + return cpr::Cookies::map_.find(key.ToStr()) != cpr::Cookies::map_.end(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve value. + */ + SQMOD_NODISCARD std::string & Get(StackStrF & key) + { + auto itr = cpr::Cookies::map_.find(key.ToStr()); + // Does it exist? + if (itr == cpr::Cookies::map_.end()) + { + STHROWF("No cookie named: %s", key.mPtr); + } + // Return it + return itr->second; + } + + /* -------------------------------------------------------------------------------------------- + * Assign value. + */ + void Set(StackStrF & key, StackStrF & val) + { + cpr::Cookies::map_[key.ToStr()] = val.ToStr(); + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + for (const auto & p : cpr::Cookies::map_) + { + fn.Execute(p.first, p.second); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + for (const auto & p : cpr::Cookies::map_) + { + auto ret = fn.Eval(p.first, p.second); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.Cast< bool >()) + { + break; + } + } + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Header that can be bound to the script engine. +*/ +struct CpHeader +{ + /* -------------------------------------------------------------------------------------------- + * Value container. + */ + cpr::Header mMap{}; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpHeader() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpHeader(const cpr::Header & e) : mMap(e) { } // NOLINT(modernize-pass-by-value) + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpHeader(cpr::Header && e) : mMap(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpHeader(const CpHeader &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpHeader(CpHeader &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpHeader() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpHeader & operator = (const CpHeader &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpHeader & operator = (CpHeader &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion operator. + */ + operator cpr::Header & () { return mMap; } // NOLINT(google-explicit-constructor) + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion operator. + */ + operator const cpr::Header & () const { return mMap; } // NOLINT(google-explicit-constructor) + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of values. + */ + SQMOD_NODISCARD SQInteger Size() const + { + return static_cast< SQInteger >(mMap.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if no value is stored. + */ + SQMOD_NODISCARD bool Empty() const + { + return mMap.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * Clear all values. + */ + void Clear() + { + mMap.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of matching values. + */ + SQMOD_NODISCARD SQInteger Count(StackStrF & key) const + { + return static_cast< SQInteger >(mMap.count(key.ToStr())); + } + + /* -------------------------------------------------------------------------------------------- + * Remove a value. + */ + bool Erase(StackStrF & key) + { + auto itr = mMap.find(key.ToStr()); + // Does it exist? + if (itr == mMap.end()) + { + return false; // Nope + } + // Erase it + mMap.erase(itr); + // Erased + return true; + } + + /* -------------------------------------------------------------------------------------------- + * Check if value exists. + */ + SQMOD_NODISCARD bool Has(StackStrF & key) const + { + return mMap.find(key.ToStr()) != mMap.end(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve value. + */ + SQMOD_NODISCARD std::string & Get(StackStrF & key) + { + auto itr = mMap.find(key.ToStr()); + // Does it exist? + if (itr == mMap.end()) + { + STHROWF("No cookie named: %s", key.mPtr); + } + // Return it + return itr->second; + } + + /* -------------------------------------------------------------------------------------------- + * Assign value. + */ + void Set(StackStrF & key, StackStrF & val) + { + mMap[key.ToStr()] = val.ToStr(); + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + for (const auto & p : mMap) + { + fn.Execute(p.first, p.second); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + for (const auto & p : mMap) + { + auto ret = fn.Eval(p.first, p.second); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.Cast< bool >()) + { + break; + } + } + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Response that can be bound to the script engine. +*/ +struct CpResponse : public cpr::Response +{ + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpResponse() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpResponse(const cpr::Response & r) : cpr::Response(r) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpResponse(cpr::Response && r) : cpr::Response(std::move(r)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpResponse(const CpResponse &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpResponse(CpResponse &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpResponse() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpResponse & operator = (const CpResponse &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpResponse & operator = (CpResponse &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve certificate information. + */ + SQMOD_NODISCARD Array GetCertInfoArray() + { + if (!cpr::Response::curl_) + { + STHROWF("Invalid response instance"); + } + // Retrieve the info vector + auto vec = cpr::Response::GetCertInfo(); + // Create a script array + Array arr(SqVM(), static_cast< SQInteger >(vec.size())); + // Populate the array with vector elements + for (size_t i = 0; i < vec.size(); ++i) + { + arr.SetValue(static_cast< SQInteger >(i), vec[i]); + } + // Return the array + return arr; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::status_code. + */ + SQMOD_NODISCARD SQInteger GetStatusCode() const + { + return cpr::Response::status_code; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::status_code. + */ + void SetStatusCode(SQInteger value) + { + cpr::Response::status_code = value; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::text. + */ + SQMOD_NODISCARD const std::string & GetText() const + { + return cpr::Response::text; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::text. + */ + void SetText(StackStrF & str) + { + cpr::Response::text.assign(str.mPtr, str.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Steal values from cpr::Response::header. + */ + SQMOD_NODISCARD CpHeader StealHeader() + { + return CpHeader(std::move(cpr::Response::header)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::header. + */ + SQMOD_NODISCARD CpHeader GetHeader() const + { + return CpHeader(cpr::Response::header); + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::header. + */ + void SetHeader(const CpHeader & value) + { + cpr::Response::header = value; + } + + /* -------------------------------------------------------------------------------------------- + * Yield values to cpr::Response::header. + */ + void YieldHeader(CpHeader & value) + { + cpr::Response::header = std::move(static_cast< cpr::Header & >(value)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::url. + */ + SQMOD_NODISCARD const std::string & GetURL() const + { + return cpr::Response::url.str(); + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::url. + */ + void SetURL(StackStrF & str) + { + cpr::Response::url = cpr::Url(str.mPtr, str.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Steal values from cpr::Response::cookies. + */ + SQMOD_NODISCARD CpCookies StealCookies() + { + return CpCookies(std::move(cpr::Response::cookies)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::cookies. + */ + SQMOD_NODISCARD CpCookies GetCookies() const + { + return CpCookies(cpr::Response::cookies); + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::cookies. + */ + void SetCookies(const CpCookies & value) + { + cpr::Response::cookies = value; + } + + /* -------------------------------------------------------------------------------------------- + * Yield values to cpr::Response::cookies. + */ + void YieldCookies(CpCookies & value) + { + cpr::Response::cookies = std::move(static_cast< cpr::Cookies & >(value)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::url. + */ + SQMOD_NODISCARD CpError GetError() const + { + return CpError(cpr::Response::error); + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::url. + */ + void SetError(const CpError & e) + { + cpr::Response::error = e; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::raw_header. + */ + SQMOD_NODISCARD const std::string & GetRawHeader() const + { + return cpr::Response::raw_header; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::raw_header. + */ + void SetRawHeader(StackStrF & str) + { + cpr::Response::raw_header.assign(str.mPtr, str.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::status_line. + */ + SQMOD_NODISCARD const std::string & GetStatusLine() const + { + return cpr::Response::status_line; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::status_line. + */ + void SetStatusLine(StackStrF & str) + { + cpr::Response::status_line.assign(str.mPtr, str.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::reason. + */ + SQMOD_NODISCARD const std::string & GetReason() const + { + return cpr::Response::reason; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::reason. + */ + void SetReason(StackStrF & str) + { + cpr::Response::reason.assign(str.mPtr, str.GetSize()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::uploaded_bytes. + */ + SQMOD_NODISCARD SQInteger GetUploadedBytes() const + { + return static_cast< SQInteger >(cpr::Response::uploaded_bytes); // possible precision loss! + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::uploaded_bytes. + */ + void SetUploadedBytes(SQInteger value) + { + cpr::Response::uploaded_bytes = static_cast< cpr::cpr_off_t >(value); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::downloaded_bytes. + */ + SQMOD_NODISCARD SQInteger GetDownloadedBytes() const + { + return static_cast< SQInteger >(cpr::Response::downloaded_bytes); // possible precision loss! + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::downloaded_bytes. + */ + void SetDownloadedBytes(SQInteger value) + { + cpr::Response::downloaded_bytes = static_cast< cpr::cpr_off_t >(value); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve cpr::Response::redirect_count. + */ + SQMOD_NODISCARD SQInteger GetRedirectCount() const + { + return cpr::Response::redirect_count; + } + + /* -------------------------------------------------------------------------------------------- + * Modify cpr::Response::redirect_count. + */ + void SetRedirectCount(SQInteger value) + { + cpr::Response::redirect_count = static_cast< long >(value); + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Parameters that can be bound to the script engine. +*/ +struct CpParameters : public cpr::Parameters +{ + using cpr::Parameters::Parameters; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpParameters() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpParameters(const cpr::Parameters & e) : cpr::Parameters(e) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpParameters(cpr::Parameters && e) : cpr::Parameters(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpParameters(const CpParameters &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpParameters(CpParameters &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpParameters() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpParameters & operator = (const CpParameters &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpParameters & operator = (CpParameters &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of values. + */ + SQMOD_NODISCARD SQInteger Size() const + { + return static_cast< SQInteger >(cpr::Parameters::containerList_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if no value is stored. + */ + SQMOD_NODISCARD bool Empty() const + { + return cpr::Parameters::containerList_.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * Clear all values. + */ + void Clear() + { + cpr::Parameters::containerList_.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of matching values. + */ + SQInteger Count(StackStrF & key) const + { + return static_cast< SQInteger >(std::count_if( + cpr::Parameters::containerList_.begin(), cpr::Parameters::containerList_.end(), + [key = key.ToStr()](const cpr::Parameter & p) { return p.key == key; } + )); + } + + /* -------------------------------------------------------------------------------------------- + * Remove a value. + */ + SQInteger Erase(StackStrF & key) + { + const size_t n = cpr::Parameters::containerList_.size(); + cpr::Parameters::containerList_.erase(std::remove_if( + cpr::Parameters::containerList_.begin(), cpr::Parameters::containerList_.end(), + [key = key.ToStr()](cpr::Parameter & p) { return p.key == key; }), cpr::Parameters::containerList_.end() + ); + return static_cast< SQInteger >(n - cpr::Parameters::containerList_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if value exists. + */ + bool Has(StackStrF & key) const + { + return std::find_if( + cpr::Parameters::containerList_.begin(), cpr::Parameters::containerList_.end(), + [key = key.ToStr()](const cpr::Parameter & p) { return p.key == key; } + ) != cpr::Parameters::containerList_.end(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve value. + */ + std::string & Get(StackStrF & key) + { + auto itr = std::find_if( + cpr::Parameters::containerList_.begin(), cpr::Parameters::containerList_.end(), + [key = key.ToStr()](cpr::Parameter & p) { return p.key == key; } + ); + // Does it exist? + if (itr == cpr::Parameters::containerList_.end()) + { + STHROWF("No parameter named: %s", key.mPtr); + } + // Return it + return itr->value; + } + + /* -------------------------------------------------------------------------------------------- + * Assign value. + */ + void Set(StackStrF & key, StackStrF & val) + { + auto itr = std::find_if( + cpr::Parameters::containerList_.begin(), cpr::Parameters::containerList_.end(), + [key = key.ToStr()](cpr::Parameter & p) { return p.key == key; } + ); + // Does it exist? + if (itr == cpr::Parameters::containerList_.end()) + { + cpr::Parameters::containerList_.emplace_back(key.ToStr(), val.ToStr()); + } + else + { + itr->value.assign(val.mPtr, val.GetSize()); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + for (const auto & p : cpr::Parameters::containerList_) + { + fn.Execute(p.key, p.value); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + for (const auto & p : cpr::Parameters::containerList_) + { + auto ret = fn.Eval(p.key, p.value); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.Cast< bool >()) + { + break; + } + } + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Payload that can be bound to the script engine. +*/ +struct CpPayload : public cpr::Payload +{ + using cpr::Payload::Payload; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpPayload() : cpr::Payload({}) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpPayload(const cpr::Payload & e) : cpr::Payload(e) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpPayload(cpr::Payload && e) : cpr::Payload(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpPayload(const CpPayload &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpPayload(CpPayload &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpPayload() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpPayload & operator = (const CpPayload &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpPayload & operator = (CpPayload &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of values. + */ + SQMOD_NODISCARD SQInteger Size() const + { + return static_cast< SQInteger >(cpr::Payload::containerList_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if no value is stored. + */ + SQMOD_NODISCARD bool Empty() const + { + return cpr::Payload::containerList_.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * Clear all values. + */ + void Clear() + { + cpr::Payload::containerList_.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of matching values. + */ + SQMOD_NODISCARD SQInteger Count(StackStrF & key) const + { + return static_cast< SQInteger >(std::count_if( + cpr::Payload::containerList_.begin(), cpr::Payload::containerList_.end(), + [key = key.ToStr()](const cpr::Pair & p) { return p.key == key; } + )); + } + + /* -------------------------------------------------------------------------------------------- + * Remove a value. + */ + SQInteger Erase(StackStrF & key) + { + const size_t n = cpr::Payload::containerList_.size(); + cpr::Payload::containerList_.erase(std::remove_if( + cpr::Payload::containerList_.begin(), cpr::Payload::containerList_.end(), + [key = key.ToStr()](cpr::Pair & p) { return p.key == key; }), cpr::Payload::containerList_.end() + ); + return static_cast< SQInteger >(n - cpr::Payload::containerList_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if value exists. + */ + SQMOD_NODISCARD bool Has(StackStrF & key) const + { + return std::find_if( + cpr::Payload::containerList_.begin(), cpr::Payload::containerList_.end(), + [key = key.ToStr()](const cpr::Pair & p) { return p.key == key; } + ) != cpr::Payload::containerList_.end(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve value. + */ + SQMOD_NODISCARD std::string & Get(StackStrF & key) + { + auto itr = std::find_if( + cpr::Payload::containerList_.begin(), cpr::Payload::containerList_.end(), + [key = key.ToStr()](cpr::Pair & p) { return p.key == key; } + ); + // Does it exist? + if (itr == cpr::Payload::containerList_.end()) + { + STHROWF("No Pair named: %s", key.mPtr); + } + // Return it + return itr->value; + } + + /* -------------------------------------------------------------------------------------------- + * Assign value. + */ + void Set(StackStrF & key, StackStrF & val) + { + auto itr = std::find_if( + cpr::Payload::containerList_.begin(), cpr::Payload::containerList_.end(), + [key = key.ToStr()](cpr::Pair & p) { return p.key == key; } + ); + // Does it exist? + if (itr == cpr::Payload::containerList_.end()) + { + cpr::Payload::containerList_.emplace_back(key.ToStr(), val.ToStr()); + } + else + { + itr->value.assign(val.mPtr, val.GetSize()); + } + } + + /* -------------------------------------------------------------------------------------------- + * Add value. + */ + void Add(StackStrF & key, StackStrF & val) + { + cpr::Payload::containerList_.emplace_back(key.ToStr(), val.ToStr()); + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + for (const auto & p : cpr::Payload::containerList_) + { + fn.Execute(p.key, p.value); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + for (const auto & p : cpr::Payload::containerList_) + { + auto ret = fn.Eval(p.key, p.value); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.Cast< bool >()) + { + break; + } + } + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Proxies that can be bound to the script engine. +*/ +struct CpProxies : public cpr::Proxies +{ + using cpr::Proxies::Proxies; + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpProxies() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + explicit CpProxies(const cpr::Proxies & e) : cpr::Proxies(e) { } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + explicit CpProxies(cpr::Proxies && e) : cpr::Proxies(std::move(e)) { } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + CpProxies(const CpProxies &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpProxies(CpProxies &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CpProxies() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + CpProxies & operator = (const CpProxies &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpProxies & operator = (CpProxies &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of values. + */ + SQMOD_NODISCARD SQInteger Size() const + { + return static_cast< SQInteger >(cpr::Proxies::hosts_.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Check if no value is stored. + */ + SQMOD_NODISCARD bool Empty() const + { + return cpr::Proxies::hosts_.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * Clear all values. + */ + void Clear() + { + cpr::Proxies::hosts_.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of matching values. + */ + SQMOD_NODISCARD SQInteger Count(StackStrF & key) const + { + return static_cast< SQInteger >(cpr::Proxies::hosts_.count(key.ToStr())); + } + + /* -------------------------------------------------------------------------------------------- + * Remove a value. + */ + bool Erase(StackStrF & key) + { + auto itr = cpr::Proxies::hosts_.find(key.ToStr()); + // Does it exist? + if (itr == cpr::Proxies::hosts_.end()) + { + return false; // Nope + } + // Erase it + cpr::Proxies::hosts_.erase(itr); + // Erased + return true; + } + + /* -------------------------------------------------------------------------------------------- + * Check if value exists. + */ + SQMOD_NODISCARD bool Has(StackStrF & key) const + { + return cpr::Proxies::hosts_.find(key.ToStr()) != cpr::Proxies::hosts_.end(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve value. + */ + SQMOD_NODISCARD std::string & Get(StackStrF & key) + { + auto itr = cpr::Proxies::hosts_.find(key.ToStr()); + // Does it exist? + if (itr == cpr::Proxies::hosts_.end()) + { + STHROWF("No cookie named: %s", key.mPtr); + } + // Return it + return itr->second; + } + + /* -------------------------------------------------------------------------------------------- + * Assign value. + */ + void Set(StackStrF & key, StackStrF & val) + { + cpr::Proxies::hosts_[key.ToStr()] = val.ToStr(); + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values. + */ + void Each(Function & fn) const + { + for (const auto & p : cpr::Proxies::hosts_) + { + fn.Execute(p.first, p.second); + } + } + + /* -------------------------------------------------------------------------------------------- + * Iterate all values until stopped. + */ + void While(Function & fn) const + { + for (const auto & p : cpr::Proxies::hosts_) + { + auto ret = fn.Eval(p.first, p.second); + // (null || true) == continue & false == break + if (!ret.IsNull() || !ret.Cast< bool >()) + { + break; + } + } + } +}; + +/* ------------------------------------------------------------------------------------------------ + * Wrapper for cpr::Session that can be bound to the script engine. +*/ +struct CpSession : public cpr::Session +{ + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CpSession() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + CpSession(const CpSession &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + CpSession(CpSession &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + virtual ~CpSession() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator (disabled). + */ + CpSession & operator = (const CpSession &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + CpSession & operator = (CpSession &&) noexcept = default; + + /* -------------------------------------------------------------------------------------------- + * Modify URL option. + */ + CpSession & SetURL_(StackStrF & url) + { + cpr::Session::SetUrl(cpr::Url(url.mPtr, url.GetSize())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify parameters option. + */ + CpSession & SetParameters_(const CpParameters & parameters) + { + cpr::Session::SetParameters(parameters); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify parameters option. + */ + CpSession & YieldParameters(CpParameters & parameters) + { + cpr::Session::SetParameters(std::move(static_cast< cpr::Parameters & >(parameters))); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify header option. + */ + CpSession & SetHeader_(const CpHeader & header) + { + cpr::Session::SetHeader(header.mMap); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify timeout option. + */ + CpSession & SetTimeout_(SQInteger ms) + { + cpr::Session::SetTimeout(cpr::Timeout(std::chrono::milliseconds{ms})); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify connect timeout option. + */ + CpSession & SetConnectTimeout_(SQInteger ms) + { + cpr::Session::SetConnectTimeout(cpr::ConnectTimeout(std::chrono::milliseconds{ms})); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify auth option. + */ + CpSession & SetAuth_(StackStrF & username, StackStrF & password) + { + cpr::Session::SetAuth(cpr::Authentication(username.ToStr(), password.ToStr())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify digest option. + */ + CpSession & SetDigest_(StackStrF & username, StackStrF & password) + { + cpr::Session::SetAuth(cpr::Digest(username.ToStr(), password.ToStr())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify user agent option. + */ + CpSession & SetUserAgent_(StackStrF & agent) + { + cpr::Session::SetUserAgent(cpr::UserAgent(agent.mPtr, agent.GetSize())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify payload option. + */ + CpSession & SetPayload_(const CpPayload & payload) + { + cpr::Session::SetPayload(payload); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify payload option. + */ + CpSession & YieldPayload(CpPayload & payload) + { + cpr::Session::SetPayload(std::move(static_cast< cpr::Payload & >(payload))); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify proxies option. + */ + CpSession & SetProxies_(const CpProxies & proxies) + { + cpr::Session::SetProxies(proxies); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify proxies option. + */ + CpSession & YieldProxies(CpProxies & proxies) + { + cpr::Session::SetProxies(std::move(static_cast< cpr::Proxies & >(proxies))); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify multipart option. + */ + //CpSession & SetMultipart_(const cpr::Multipart & multipart) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify multipart option. + */ + //CpSession & YieldMultipart(cpr::Multipart && multipart) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify NTLM option. + */ + CpSession & SetNTLM_(StackStrF & username, StackStrF & password) + { + cpr::Session::SetNTLM(cpr::NTLM(username.ToStr(), password.ToStr())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify redirect option. + */ + CpSession & SetRedirect_(bool redirect) + { + cpr::Session::SetRedirect(redirect); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify max-redirects option. + */ + CpSession & SetMaxRedirects_(SQInteger max_redirects) + { + cpr::Session::SetMaxRedirects(cpr::MaxRedirects(static_cast< int32_t >(max_redirects))); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify cookies option. + */ + CpSession & SetCookies_(const CpCookies & cookies) + { + cpr::Session::SetCookies(cookies); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify body option. + */ + CpSession & SetBody_(StackStrF & body) + { + cpr::Session::SetBody(cpr::Body(body.mPtr, body.GetSize())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify low-speed option. + */ + CpSession & SetLowSpeed_(SQInteger limit, SQInteger time) + { + cpr::Session::SetLowSpeed(cpr::LowSpeed(static_cast< int32_t >(limit), static_cast< int32_t >(time))); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify verify SSL option. + */ + CpSession & SetVerifySsl_(bool verify) + { + cpr::Session::SetVerifySsl(cpr::VerifySsl(verify)); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify unix socket option. + */ + CpSession & SetUnixSocket_(StackStrF & socket) + { + cpr::Session::SetUnixSocket(cpr::UnixSocket(socket.ToStr())); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify SSL option. + */ + CpSession & SetSslOptions_(const CpSslOptions & options) + { + cpr::Session::SetSslOptions(options); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Modify read option. + */ + //CpSession & SetReadCallback_(const cpr::ReadCallback & read) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify header option. + */ + //CpSession & SetHeaderCallback_(const cpr::HeaderCallback & header) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify write option. + */ + //CpSession & SetWriteCallback_(const cpr::WriteCallback & write) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify progress option. + */ + //CpSession & SetProgressCallback_(const cpr::ProgressCallback & progress) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify debug callback option. + */ + //CpSession & SetDebugCallback_(const cpr::DebugCallback & debug) + //{ + //} + + /* -------------------------------------------------------------------------------------------- + * Modify verbose option. + */ + CpSession & SetVerbose_(bool verbose) + { + cpr::Session::SetVerbose(cpr::Verbose(verbose)); + return *this; // Allow chaining + } + + /* -------------------------------------------------------------------------------------------- + * Delete request. + */ + CpResponse DoDelete() + { + return CpResponse(cpr::Session::Delete()); + } + + /* -------------------------------------------------------------------------------------------- + * Get request. + */ + CpResponse DoGet() + { + return CpResponse(cpr::Session::Get()); + } + + /* -------------------------------------------------------------------------------------------- + * Head request. + */ + CpResponse DoHead() + { + return CpResponse(cpr::Session::Head()); + } + + /* -------------------------------------------------------------------------------------------- + * Options request. + */ + CpResponse DoOptions() + { + return CpResponse(cpr::Session::Options()); + } + + /* -------------------------------------------------------------------------------------------- + * Patch request. + */ + CpResponse DoPatch() + { + return CpResponse(cpr::Session::Patch()); + } + + /* -------------------------------------------------------------------------------------------- + * Post request. + */ + CpResponse DoPost() + { + return CpResponse(cpr::Session::Post()); + } + + /* -------------------------------------------------------------------------------------------- + * Put request. + */ + CpResponse DoPut() + { + return CpResponse(cpr::Session::Put()); + } + + //CpResponse Download(const WriteCallback& write); + //CpResponse Download(std::ofstream& file); + +}; + +} // Namespace:: SqMod diff --git a/module/Register.cpp b/module/Register.cpp index 5ed371fa..859d334c 100644 --- a/module/Register.cpp +++ b/module/Register.cpp @@ -32,6 +32,7 @@ extern void Register_CVehicle(HSQUIRRELVM vm); // ------------------------------------------------------------------------------------------------ extern void Register_Chrono(HSQUIRRELVM vm); +extern void Register_CURL(HSQUIRRELVM vm); extern void Register_IO(HSQUIRRELVM vm); extern void Register_MMDB(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm); @@ -85,6 +86,7 @@ bool RegisterAPI(HSQUIRRELVM vm) Register_CVehicle(vm); Register_Chrono(vm); + Register_CURL(vm); Register_IO(vm); Register_MMDB(vm); Register_Numeric(vm); diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index a43b7ded..572a145f 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(Squirrel) add_subdirectory(SimpleIni) add_subdirectory(TinyDir) add_subdirectory(JSMN) +add_subdirectory(CPR) set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) add_subdirectory(MaxmindDB) diff --git a/vendor/CPR/CMakeLists.txt b/vendor/CPR/CMakeLists.txt new file mode 100644 index 00000000..fae79d4d --- /dev/null +++ b/vendor/CPR/CMakeLists.txt @@ -0,0 +1,61 @@ +# Create the CPR library +add_library(CPR STATIC + # Source files + cpr/auth.cpp + cpr/bearer.cpp + cpr/cookies.cpp + cpr/cprtypes.cpp + cpr/curl_container.cpp + cpr/curlholder.cpp + cpr/error.cpp + cpr/multipart.cpp + cpr/parameters.cpp + cpr/payload.cpp + cpr/proxies.cpp + cpr/session.cpp + cpr/timeout.cpp + cpr/unix_socket.cpp + cpr/util.cpp + cpr/response.cpp + # Header files + include/cpr/api.h + include/cpr/auth.h + include/cpr/bearer.h + include/cpr/body.h + include/cpr/cookies.h + include/cpr/cpr.h + include/cpr/cprtypes.h + include/cpr/curlholder.h + include/cpr/curlholder.h + include/cpr/digest.h + include/cpr/error.h + include/cpr/limit_rate.h + include/cpr/max_redirects.h + include/cpr/multipart.h + include/cpr/ntlm.h + include/cpr/parameters.h + include/cpr/payload.h + include/cpr/proxies.h + include/cpr/response.h + include/cpr/session.h + include/cpr/ssl_options.h + include/cpr/timeout.h + include/cpr/unix_socket.h + include/cpr/util.h + include/cpr/verbose.h +) +# Library includes +target_include_directories(CPR PRIVATE ${CMAKE_CURRENT_LIST_DIR}/cpr) +target_include_directories(CPR PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) +# Find CURK +find_package(CURL REQUIRED COMPONENTS HTTP HTTPS SSL) +if (CURL_FOUND) + set(SSL_ENABLED ON CACHE INTERNAL "" FORCE) +else() + find_package(CURL REQUIRED COMPONENTS HTTP) + if(CURL_FOUND) + set(SSL_ENABLED OFF CACHE INTERNAL "" FORCE) + endif() +endif() +# Link to CURL +target_link_libraries(CPR PUBLIC curl) diff --git a/vendor/CPR/CONTRIBUTING.md b/vendor/CPR/CONTRIBUTING.md new file mode 100644 index 00000000..abfb97c3 --- /dev/null +++ b/vendor/CPR/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing to C++ Requests + +Please fork this repository and contribute back using [pull requests](https://github.com/whoshuu/cpr/pulls). Features can be requested using [issues](https://github.com/whoshuu/cpr/issues). All code, comments, and critiques are greatly appreciated. + +## Formatting + +To avoid unproductive debates on formatting, this project uses `clang-format` to ensure a consistent style across all source files. Currently, `clang-format` 3.8 is the version of `clang-format` we use. The format file can be found [here](https://github.com/whoshuu/cpr/blob/master/.clang-format). To install `clang-format` on Ubuntu, run this: + +``` +apt-get install clang-format-3.8 +``` + +To install `clang-format` on OS X, run this: + +``` +brew install clang-format +``` + +Note that `brew` might install a later version of `clang-format`, but it should be mostly compatible with what's run on the Travis servers. + +To run `clang-format` on every source file, run this in the root directory: + +``` +./format-check.sh +``` + +This should indicate which files need formatting and also show a diff of the requested changes. More specific usage instructions can be found on the official [LLVM website](http://releases.llvm.org/3.8.0/tools/clang/docs/ClangFormat.html). diff --git a/vendor/CPR/LICENSE b/vendor/CPR/LICENSE new file mode 100644 index 00000000..d173854d --- /dev/null +++ b/vendor/CPR/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Huu Nguyen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/CPR/README.md b/vendor/CPR/README.md new file mode 100644 index 00000000..157d86af --- /dev/null +++ b/vendor/CPR/README.md @@ -0,0 +1,141 @@ +# C++ Requests: Curl for People + +[![Documentation](https://img.shields.io/badge/docs-online-informational?style=flat&link=https://whoshuu.github.io/cpr/)](https://whoshuu.github.io/cpr/) +![CI](https://github.com/whoshuu/cpr/workflows/CI/badge.svg) + +## Announcements + +The cpr project has new maintainers: [Fabian Sauter](https://github.com/com8) and [Tim Stack](https://github.com/tstack). + +## TLDR + +C++ Requests is a simple wrapper around [libcurl](http://curl.haxx.se/libcurl) inspired by the excellent [Python Requests](https://github.com/kennethreitz/requests) project. + +Despite its name, libcurl's easy interface is anything but, and making mistakes misusing it is a common source of error and frustration. Using the more expressive language facilities of C++11, this library captures the essence of making network calls into a few concise idioms. + +Here's a quick GET request: + +```c++ +#include + +int main(int argc, char** argv) { + cpr::Response r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"}, + cpr::Authentication{"user", "pass"}, + cpr::Parameters{{"anon", "true"}, {"key", "value"}}); + r.status_code; // 200 + r.header["content-type"]; // application/json; charset=utf-8 + r.text; // JSON text string +} +``` + +And here's [less functional, more complicated code, without cpr](https://gist.github.com/whoshuu/2dc858b8730079602044). + +## Documentation + +[![Documentation](https://img.shields.io/badge/docs-online-informational?style=for-the-badge&link=https://whoshuu.github.io/cpr/)](https://whoshuu.github.io/cpr/) +You can find the latest documentation [here](https://whoshuu.github.io/cpr). It's a work in progress, but it should give you a better idea of how to use the library than the [tests](https://github.com/whoshuu/cpr/tree/master/test) currently do. + +## Features + +C++ Requests currently supports: + +* Custom headers +* Url encoded parameters +* Url encoded POST values +* Multipart form POST upload +* File POST upload +* Basic authentication +* Bearer authentication +* Digest authentication +* NTLM authentication +* Connection and request timeout specification +* Timeout for low speed connection +* Asynchronous requests +* :cookie: support! +* Proxy support +* Callback interfaces +* PUT methods +* DELETE methods +* HEAD methods +* OPTIONS methods +* PATCH methods +* Thread Safe access to [libCurl](https://curl.haxx.se/libcurl/c/threadsafe.html) +* OpenSSL and WinSSL support for HTTPS requests + +## Planned + +For a quick overview about the planed features, have a look at the next [Milestones](https://github.com/whoshuu/cpr/milestones). + +## Usage + +If you already have a project you need to integrate C++ Requests with, the primary way is to use CMake `fetch_content`. +Add the following to your `CMakeLists.txt`. + + +```cmake +include(FetchContent) +FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/whoshuu/cpr.git GIT_TAG c8d33915dbd88ad6c92b258869b03aba06587ff9) # the commit hash for 1.5.0 +FetchContent_MakeAvailable(cpr) +``` + +This will produce the target `cpr::cpr` which you can link against the typical way: + +```cmake +target_link_libraries(your_target_name PRIVATE cpr::cpr) +``` + +That should do it! +There's no need to handle `libcurl` yourself. All dependencies are taken care of for you. + +## Requirements + +The only explicit requirements are: + +* a `C++11` compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let me know +* If you would like to perform https requests `OpenSSL` and its development libraries are required. + +## Building cpr - Using vcpkg + +You can download and install cpr using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: +```Bash +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +./vcpkg install cpr +``` +The `cpr` port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + +## Building cpr - Using Conan + +You can download and install `cpr` using the [Conan](https://conan.io/) package manager. Setup your CMakeLists.txt (see [Conan documentation](https://docs.conan.io/en/latest/integrations/build_system.html) on how to use MSBuild, Meson and others) like this: + +```CMake +project(myproject CXX) + +add_executable(${PROJECT_NAME} main.cpp) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) # Include Conan-generated file +conan_basic_setup(TARGETS) # Introduce Conan-generated targets + +target_link_libraries(${PROJECT_NAME} CONAN_PKG::cpr) +``` +Create `conanfile.txt` in your source dir: +``` +[requires] +cpr/1.5.0 + +[generators] +cmake +``` +Install and run Conan, then build your project as always: + +```Bash +pip install conan +mkdir build +cd build +conan install ../ --build=missing +cmake ../ +cmake --build . +``` +The `cpr` package in Conan is kept up to date by Conan contributors. If the version is out of date, please [create an issue or pull request](https://github.com/conan-io/conan-center-index) on the `conan-center-index` repository. diff --git a/vendor/CPR/cpr/auth.cpp b/vendor/CPR/cpr/auth.cpp new file mode 100644 index 00000000..7d55d4b9 --- /dev/null +++ b/vendor/CPR/cpr/auth.cpp @@ -0,0 +1,7 @@ +#include "cpr/auth.h" + +namespace cpr { +const char* Authentication::GetAuthString() const noexcept { + return auth_string_.c_str(); +} +} // namespace cpr diff --git a/vendor/CPR/cpr/bearer.cpp b/vendor/CPR/cpr/bearer.cpp new file mode 100644 index 00000000..5b7eb930 --- /dev/null +++ b/vendor/CPR/cpr/bearer.cpp @@ -0,0 +1,11 @@ +#include "cpr/bearer.h" + +namespace cpr { +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 +const char* Bearer::GetToken() const noexcept { + return token_string_.c_str(); +} +#endif +} // namespace cpr diff --git a/vendor/CPR/cpr/cookies.cpp b/vendor/CPR/cpr/cookies.cpp new file mode 100644 index 00000000..4bd58555 --- /dev/null +++ b/vendor/CPR/cpr/cookies.cpp @@ -0,0 +1,51 @@ +#include "cpr/cookies.h" + +namespace cpr { +std::string Cookies::GetEncoded(const CurlHolder& holder) const { + std::stringstream stream; + for (const std::pair& item : map_) { + // Depending on if encoding is set to "true", we will URL-encode cookies + stream << (encode ? holder.urlEncode(item.first) : item.first) << "="; + + // special case version 1 cookies, which can be distinguished by + // beginning and trailing quotes + if (!item.second.empty() && item.second.front() == '"' && item.second.back() == '"') { + stream << item.second; + } else { + // Depending on if encoding is set to "true", we will URL-encode cookies + stream << (encode ? holder.urlEncode(item.second) : item.second); + } + stream << "; "; + } + return stream.str(); +} + +std::string& Cookies::operator[](const std::string& key) { + return map_[key]; +} + +Cookies::iterator Cookies::begin() { + return map_.begin(); +} + +Cookies::iterator Cookies::end() { + return map_.end(); +} + +Cookies::const_iterator Cookies::begin() const { + return map_.begin(); +} + +Cookies::const_iterator Cookies::end() const { + return map_.end(); +} + +Cookies::const_iterator Cookies::cbegin() const { + return map_.cbegin(); +} + +Cookies::const_iterator Cookies::cend() const { + return map_.cend(); +} + +} // namespace cpr diff --git a/vendor/CPR/cpr/cprtypes.cpp b/vendor/CPR/cpr/cprtypes.cpp new file mode 100644 index 00000000..c618b3f1 --- /dev/null +++ b/vendor/CPR/cpr/cprtypes.cpp @@ -0,0 +1,12 @@ +#include "cpr/cprtypes.h" + +#include +#include + +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 diff --git a/vendor/CPR/cpr/curl_container.cpp b/vendor/CPR/cpr/curl_container.cpp new file mode 100644 index 00000000..12764110 --- /dev/null +++ b/vendor/CPR/cpr/curl_container.cpp @@ -0,0 +1,59 @@ +#include "cpr/curl_container.h" + + +namespace cpr { +template +CurlContainer::CurlContainer(const std::initializer_list& containerList) + : containerList_(containerList) {} + +template +void CurlContainer::Add(const std::initializer_list& containerList) { + for (const T& element : containerList) { + containerList_.push_back(std::move(element)); + } +} + +template +void CurlContainer::Add(const T& element) { + containerList_.push_back(std::move(element)); +} + +template <> +const std::string CurlContainer::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::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; +template class CurlContainer; + +} // namespace cpr diff --git a/vendor/CPR/cpr/curlholder.cpp b/vendor/CPR/cpr/curlholder.cpp new file mode 100644 index 00000000..95ef08eb --- /dev/null +++ b/vendor/CPR/cpr/curlholder.cpp @@ -0,0 +1,54 @@ +#include "cpr/curlholder.h" +#include + +namespace cpr { +// It does not make sense to make a std::mutex const. +// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) +std::mutex CurlHolder::curl_easy_init_mutex_{}; + +#ifndef _WIN32 // There is no thread sanitizer on windows +__attribute__((no_sanitize("thread"))) +#endif +CurlHolder::CurlHolder() { + /** + * Allow multithreaded access to CPR by locking curl_easy_init(). + * curl_easy_init() is not thread safe. + * References: + * https://curl.haxx.se/libcurl/c/curl_easy_init.html + * https://curl.haxx.se/libcurl/c/threadsafe.html + **/ + curl_easy_init_mutex_.lock(); + handle = curl_easy_init(); + curl_easy_init_mutex_.unlock(); + + assert(handle); +} // namespace cpr + +CurlHolder::~CurlHolder() { + curl_easy_cleanup(handle); + curl_slist_free_all(chunk); + curl_formfree(formpost); +} + +std::string CurlHolder::urlEncode(const std::string& s) const { + assert(handle); + char* output = curl_easy_escape(handle, s.c_str(), s.length()); + if (output) { + std::string result = output; + curl_free(output); + return result; + } + return ""; +} + +std::string CurlHolder::urlDecode(const std::string& s) const { + assert(handle); + char* output = curl_easy_unescape(handle, s.c_str(), s.length(), nullptr); + if (output) { + std::string result = output; + curl_free(output); + return result; + } + return ""; +} +} // namespace cpr diff --git a/vendor/CPR/cpr/error.cpp b/vendor/CPR/cpr/error.cpp new file mode 100644 index 00000000..7e713fd1 --- /dev/null +++ b/vendor/CPR/cpr/error.cpp @@ -0,0 +1,68 @@ +#include "cpr/error.h" + +#include + +namespace cpr { +ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) { + switch (curl_code) { + case CURLE_OK: + return ErrorCode::OK; + case CURLE_UNSUPPORTED_PROTOCOL: + return ErrorCode::UNSUPPORTED_PROTOCOL; + case CURLE_URL_MALFORMAT: + return ErrorCode::INVALID_URL_FORMAT; + case CURLE_COULDNT_RESOLVE_PROXY: + return ErrorCode::PROXY_RESOLUTION_FAILURE; + case CURLE_COULDNT_RESOLVE_HOST: + return ErrorCode::HOST_RESOLUTION_FAILURE; + case CURLE_COULDNT_CONNECT: + return ErrorCode::CONNECTION_FAILURE; + case CURLE_OPERATION_TIMEDOUT: + return ErrorCode::OPERATION_TIMEDOUT; + case CURLE_SSL_CONNECT_ERROR: + return ErrorCode::SSL_CONNECT_ERROR; +#if LIBCURL_VERSION_NUM < 0x073e00 + case CURLE_PEER_FAILED_VERIFICATION: + return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR; +#endif + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_WRITE_ERROR: + return ErrorCode::REQUEST_CANCELLED; + case CURLE_GOT_NOTHING: + return ErrorCode::EMPTY_RESPONSE; + case CURLE_SSL_ENGINE_NOTFOUND: + case CURLE_SSL_ENGINE_SETFAILED: + return ErrorCode::GENERIC_SSL_ERROR; + case CURLE_SEND_ERROR: + return ErrorCode::NETWORK_SEND_FAILURE; + case CURLE_RECV_ERROR: + return ErrorCode::NETWORK_RECEIVE_ERROR; + case CURLE_SSL_CERTPROBLEM: + return ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR; + case CURLE_SSL_CIPHER: + return ErrorCode::GENERIC_SSL_ERROR; +#if LIBCURL_VERSION_NUM >= 0x073e00 + case CURLE_PEER_FAILED_VERIFICATION: + return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR; +#else + case CURLE_SSL_CACERT: + return ErrorCode::SSL_CACERT_ERROR; +#endif + case CURLE_USE_SSL_FAILED: + case CURLE_SSL_ENGINE_INITFAILED: + return ErrorCode::GENERIC_SSL_ERROR; + case CURLE_SSL_CACERT_BADFILE: + return ErrorCode::SSL_CACERT_ERROR; + case CURLE_SSL_SHUTDOWN_FAILED: + return ErrorCode::GENERIC_SSL_ERROR; + case CURLE_SSL_CRL_BADFILE: + case CURLE_SSL_ISSUER_ERROR: + return ErrorCode::SSL_CACERT_ERROR; + case CURLE_TOO_MANY_REDIRECTS: + return ErrorCode::OK; + default: + return ErrorCode::INTERNAL_ERROR; + } +} + +} // namespace cpr diff --git a/vendor/CPR/cpr/multipart.cpp b/vendor/CPR/cpr/multipart.cpp new file mode 100644 index 00000000..adbba99b --- /dev/null +++ b/vendor/CPR/cpr/multipart.cpp @@ -0,0 +1,5 @@ +#include "cpr/multipart.h" + +namespace cpr { +Multipart::Multipart(const std::initializer_list& parts) : parts{parts} {} +} // namespace cpr diff --git a/vendor/CPR/cpr/parameters.cpp b/vendor/CPR/cpr/parameters.cpp new file mode 100644 index 00000000..a24c3936 --- /dev/null +++ b/vendor/CPR/cpr/parameters.cpp @@ -0,0 +1,10 @@ +#include "cpr/parameters.h" + +#include +#include + +#include "cpr/util.h" + +namespace cpr { +Parameters::Parameters(const std::initializer_list& parameters) : CurlContainer(parameters) {} +} // namespace cpr diff --git a/vendor/CPR/cpr/payload.cpp b/vendor/CPR/cpr/payload.cpp new file mode 100644 index 00000000..78373fa3 --- /dev/null +++ b/vendor/CPR/cpr/payload.cpp @@ -0,0 +1,10 @@ +#include "cpr/payload.h" + +#include +#include + +#include "cpr/util.h" + +namespace cpr { +Payload::Payload(const std::initializer_list& pairs) : CurlContainer(pairs) {} +} // namespace cpr diff --git a/vendor/CPR/cpr/proxies.cpp b/vendor/CPR/cpr/proxies.cpp new file mode 100644 index 00000000..446f7d76 --- /dev/null +++ b/vendor/CPR/cpr/proxies.cpp @@ -0,0 +1,21 @@ +#include "cpr/proxies.h" + +#include +#include +#include +#include + +namespace cpr { + +Proxies::Proxies(const std::initializer_list>& 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 diff --git a/vendor/CPR/cpr/response.cpp b/vendor/CPR/cpr/response.cpp new file mode 100644 index 00000000..52c653b1 --- /dev/null +++ b/vendor/CPR/cpr/response.cpp @@ -0,0 +1,46 @@ +#include "cpr/response.h" + +namespace cpr { +Response::Response(std::shared_ptr curl, std::string&& p_text, + std::string&& p_header_string, Cookies&& p_cookies = Cookies{}, + Error&& p_error = Error{}) + : curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)), + error(std::move(p_error)) { + header = cpr::util::parseHeader(p_header_string, &status_line, &reason); + assert(curl_); + assert(curl_->handle); + curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code); + curl_easy_getinfo(curl_->handle, CURLINFO_TOTAL_TIME, &elapsed); + char* url_string{nullptr}; + curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string); + url = Url(url_string); +#if LIBCURL_VERSION_NUM >= 0x073700 + curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes); + curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes); +#else + double downloaded_bytes_double, uploaded_bytes_double; + curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD, &downloaded_bytes_double); + curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD, &uploaded_bytes_double); + downloaded_bytes = downloaded_bytes_double; + uploaded_bytes = uploaded_bytes_double; +#endif + curl_easy_getinfo(curl_->handle, CURLINFO_REDIRECT_COUNT, &redirect_count); +} + +std::vector Response::GetCertInfo() { + assert(curl_); + assert(curl_->handle); + curl_certinfo* ci{nullptr}; + curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci); + + std::vector info; + info.resize(ci->num_of_certs); + for (size_t i = 0; i < ci->num_of_certs; i++) { + // No way around here. + // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) + info[i] = std::string{ci->certinfo[i]->data}; + } + + return info; +} +} // namespace cpr diff --git a/vendor/CPR/cpr/session.cpp b/vendor/CPR/cpr/session.cpp new file mode 100644 index 00000000..f17bc499 --- /dev/null +++ b/vendor/CPR/cpr/session.cpp @@ -0,0 +1,740 @@ +#include "cpr/session.h" + +#include +#include +#include +#include +#include + +#include + +#include "cpr/cprtypes.h" +#include "cpr/util.h" + + +namespace cpr { + +// Ignored here since libcurl reqires a long: +// NOLINTNEXTLINE(google-runtime-int) +constexpr long ON = 1L; +// Ignored here since libcurl reqires a long: +// NOLINTNEXTLINE(google-runtime-int) +constexpr long OFF = 0L; + +class Session::Impl { + public: + Impl(); + + void SetUrl(const Url& url); + void SetParameters(const Parameters& parameters); + void SetParameters(Parameters&& parameters); + void SetHeader(const Header& header); + void UpdateHeader(const Header& header); + void SetTimeout(const Timeout& timeout); + void SetConnectTimeout(const ConnectTimeout& timeout); + void SetAuth(const Authentication& auth); +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 + void SetBearer(const Bearer& token); +#endif + void SetDigest(const Digest& auth); + void SetUserAgent(const UserAgent& ua); + void SetPayload(Payload&& payload); + void SetPayload(const Payload& payload); + void SetProxies(Proxies&& proxies); + void SetProxies(const Proxies& proxies); + void SetMultipart(Multipart&& multipart); + void SetMultipart(const Multipart& multipart); + void SetNTLM(const NTLM& auth); + void SetRedirect(const bool& redirect); + void SetMaxRedirects(const MaxRedirects& max_redirects); + void SetCookies(const Cookies& cookies); + void SetBody(Body&& body); + void SetBody(const Body& body); + void SetReadCallback(const ReadCallback& read); + void SetHeaderCallback(const HeaderCallback& header); + void SetWriteCallback(const WriteCallback& write); + void SetProgressCallback(const ProgressCallback& progress); + void SetDebugCallback(const DebugCallback& debug); + void SetLowSpeed(const LowSpeed& low_speed); + void SetVerifySsl(const VerifySsl& verify); + void SetLimitRate(const LimitRate& limit_rate); + void SetUnixSocket(const UnixSocket& unix_socket); + void SetVerbose(const Verbose& verbose); + void SetSslOptions(const SslOptions& options); + + Response Delete(); + Response Download(const WriteCallback& write); + Response Download(std::ofstream& file); + Response Get(); + Response Head(); + Response Options(); + Response Patch(); + Response Post(); + Response Put(); + + std::shared_ptr GetCurlHolder(); + + private: + void SetHeaderInternal(); + bool hasBodyOrPayload_{false}; + + std::shared_ptr curl_; + Url url_; + Parameters parameters_; + Proxies proxies_; + Header header_; + /** + * Will be set by the read callback. + * Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_. + **/ + bool chunkedTransferEncoding{false}; + + ReadCallback readcb_; + HeaderCallback headercb_; + WriteCallback writecb_; + ProgressCallback progresscb_; + DebugCallback debugcb_; + + Response makeDownloadRequest(); + Response makeRequest(); + static void freeHolder(CurlHolder* holder); +}; + +Session::Impl::Impl() : curl_(new CurlHolder()) { + // Set up some sensible defaults + curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW); + std::string version = "curl/" + std::string{version_info->version}; + curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str()); + curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, 50L); + curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data()); + curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, ""); +#ifdef CPR_CURL_NOSIGNAL + curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L); +#endif + +#if LIBCURL_VERSION_MAJOR >= 7 +#if LIBCURL_VERSION_MINOR >= 25 +#if LIBCURL_VERSION_PATCH >= 0 + curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L); +#endif +#endif +#endif +} + +void Session::Impl::SetUrl(const Url& url) { + url_ = url; +} + +void Session::Impl::SetParameters(const Parameters& parameters) { + parameters_ = parameters; +} + +void Session::Impl::SetParameters(Parameters&& parameters) { + parameters_ = std::move(parameters); +} + +void Session::Impl::SetHeaderInternal() { + curl_slist* chunk = nullptr; + for (const std::pair& item : header_) { + std::string header_string = item.first; + if (item.second.empty()) { + header_string += ";"; + } else { + header_string += ": " + item.second; + } + + curl_slist* temp = curl_slist_append(chunk, header_string.c_str()); + if (temp) { + chunk = temp; + } + } + + // Set the chunked transfer encoding in case it does not already exist: + if (chunkedTransferEncoding && header_.find("Transfer-Encoding") == header_.end()) { + curl_slist* temp = curl_slist_append(chunk, "Transfer-Encoding:chunked"); + if (temp) { + chunk = temp; + } + } + + curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk); + + curl_slist_free_all(curl_->chunk); + curl_->chunk = chunk; +} + +void Session::Impl::SetHeader(const Header& header) { + header_ = header; +} + +void Session::Impl::UpdateHeader(const Header& header) { + for (const std::pair& item : header) { + header_[item.first] = item.second; + } +} + +void Session::Impl::SetTimeout(const Timeout& timeout) { + curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds()); +} + +void Session::Impl::SetConnectTimeout(const ConnectTimeout& timeout) { + curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds()); +} + +void Session::Impl::SetVerbose(const Verbose& verbose) { + curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF); +} + +void Session::Impl::SetAuth(const Authentication& auth) { + // Ignore here since this has been defined by libcurl. + curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); +} + +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 +void Session::Impl::SetBearer(const Bearer& token) { + // Ignore here since this has been defined by libcurl. + curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER); + curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken()); +} +#endif + +void Session::Impl::SetDigest(const Digest& auth) { + // Ignore here since this has been defined by libcurl. + curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); +} + +void Session::Impl::SetUserAgent(const UserAgent& ua) { + curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str()); +} + +void Session::Impl::SetPayload(Payload&& payload) { + hasBodyOrPayload_ = true; + const std::string content = payload.GetContent(*curl_); + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(content.length())); + curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str()); +} + +void Session::Impl::SetPayload(const Payload& payload) { + hasBodyOrPayload_ = true; + const std::string content = payload.GetContent(*curl_); + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(content.length())); + curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str()); +} + +void Session::Impl::SetProxies(const Proxies& proxies) { + proxies_ = proxies; +} + +void Session::Impl::SetProxies(Proxies&& proxies) { + proxies_ = std::move(proxies); +} + +void Session::Impl::SetMultipart(Multipart&& multipart) { + curl_httppost* formpost = nullptr; + curl_httppost* lastptr = nullptr; + + for (const Part& part : multipart.parts) { + std::vector formdata; + if (part.is_buffer) { + // Do not use formdata, to prevent having to use reinterpreter_cast: + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, part.name.c_str(), CURLFORM_BUFFER, + part.value.c_str(), CURLFORM_BUFFERPTR, part.data, CURLFORM_BUFFERLENGTH, + part.datalen, CURLFORM_END); + } else { + formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()}); + if (part.is_file) { + formdata.push_back({CURLFORM_FILE, part.value.c_str()}); + } else { + formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()}); + } + } + if (!part.content_type.empty()) { + formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()}); + } + + formdata.push_back({CURLFORM_END, nullptr}); + curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END); + } + curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost); + hasBodyOrPayload_ = true; + + curl_formfree(curl_->formpost); + curl_->formpost = formpost; +} + +void Session::Impl::SetMultipart(const Multipart& multipart) { + curl_httppost* formpost = nullptr; + curl_httppost* lastptr = nullptr; + + for (const Part& part : multipart.parts) { + std::vector formdata; + if (part.is_buffer) { + // Do not use formdata, to prevent having to use reinterpreter_cast: + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, part.name.c_str(), CURLFORM_BUFFER, + part.value.c_str(), CURLFORM_BUFFERPTR, part.data, CURLFORM_BUFFERLENGTH, + part.datalen, CURLFORM_END); + } else { + formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()}); + if (part.is_file) { + formdata.push_back({CURLFORM_FILE, part.value.c_str()}); + } else { + formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()}); + } + } + if (!part.content_type.empty()) { + formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()}); + } + + formdata.push_back({CURLFORM_END, nullptr}); + curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END); + } + curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost); + hasBodyOrPayload_ = true; + + curl_formfree(curl_->formpost); + curl_->formpost = formpost; +} + +void Session::Impl::SetLimitRate(const LimitRate& limit_rate) { + curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate); + curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate); +} + +void Session::Impl::SetNTLM(const NTLM& auth) { + // Ignore here since this has been defined by libcurl. + curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); + curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); +} + +void Session::Impl::SetRedirect(const bool& redirect) { + curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, std::int32_t(redirect)); +} + +void Session::Impl::SetMaxRedirects(const MaxRedirects& max_redirects) { + curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, max_redirects.number_of_redirects); +} + +void Session::Impl::SetCookies(const Cookies& cookies) { + curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL"); + curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str()); +} + +void Session::Impl::SetBody(Body&& body) { + hasBodyOrPayload_ = true; + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(body.str().length())); + curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str()); +} + +void Session::Impl::SetBody(const Body& body) { + hasBodyOrPayload_ = true; + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(body.str().length())); + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.c_str()); +} + +void Session::Impl::SetReadCallback(const ReadCallback& read) { + readcb_ = read; + curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size); + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, read.size); + curl_easy_setopt(curl_->handle, CURLOPT_READFUNCTION, cpr::util::readUserFunction); + curl_easy_setopt(curl_->handle, CURLOPT_READDATA, &readcb_); + chunkedTransferEncoding = read.size == -1; +} + +void Session::Impl::SetHeaderCallback(const HeaderCallback& header) { + curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); + headercb_ = header; + curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_); +} + +void Session::Impl::SetWriteCallback(const WriteCallback& write) { + curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction); + writecb_ = write; + curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &writecb_); +} + +void Session::Impl::SetProgressCallback(const ProgressCallback& progress) { + progresscb_ = progress; +#if LIBCURL_VERSION_NUM < 0x072000 + curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction); + curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_); +#else + curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction); + curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_); +#endif + curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L); +} + +void Session::Impl::SetDebugCallback(const DebugCallback& debug) { + curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction); + debugcb_ = debug; + curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &debugcb_); + curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); +} + +void Session::Impl::SetLowSpeed(const LowSpeed& low_speed) { + curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit); + curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, low_speed.time); +} + +void Session::Impl::SetVerifySsl(const VerifySsl& verify) { + curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF); + curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L); +} + +void Session::Impl::SetUnixSocket(const UnixSocket& unix_socket) { + curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString()); +} + +void Session::Impl::SetSslOptions(const SslOptions& options) { + if (!options.cert_file.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str()); + if (!options.cert_type.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str()); + } + } + if (!options.key_file.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str()); + if (!options.key_type.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str()); + } + if (!options.key_pass.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str()); + } + } +#if SUPPORT_ALPN + curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF); +#endif +#if SUPPORT_NPN + curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF); +#endif + curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF); + curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L); +#if LIBCURL_VERSION_NUM >= 0x072900 + curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF); +#endif + curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION, + // Ignore here since this has been defined by libcurl. + options.ssl_version +#if SUPPORT_MAX_TLS_VERSION + | options.max_version +#endif + ); +#if SUPPORT_SSL_NO_REVOKE + if (options.ssl_no_revoke) { + curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); + } +#endif + if (!options.ca_info.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str()); + } + if (!options.ca_path.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str()); + } + if (!options.crl_file.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str()); + } + if (!options.ciphers.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str()); + } +#if SUPPORT_TLSv13_CIPHERS + if (!options.tls13_ciphers.empty()) { + curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.ciphers.c_str()); + } +#endif +#if SUPPORT_SESSIONID_CACHE + curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, + options.session_id_cache ? ON : OFF); +#endif +} + +Response Session::Impl::Delete() { + curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE"); + + return makeRequest(); +} + +Response Session::Impl::Download(const WriteCallback& write) { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET"); + + SetWriteCallback(write); + + return makeDownloadRequest(); +} + +Response Session::Impl::Download(std::ofstream& file) { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET"); + curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction); + curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file); + + return makeDownloadRequest(); +} + +Response Session::Impl::Get() { + // In case there is a body or payload for this request, we create a custom GET-Request since a + // GET-Request with body is based on the HTTP RFC **not** a leagal request. + if (hasBodyOrPayload_) { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET"); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); + curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L); + } + + return makeRequest(); +} + +Response Session::Impl::Head() { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); + + return makeRequest(); +} + +Response Session::Impl::Options() { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS"); + + return makeRequest(); +} + +Response Session::Impl::Patch() { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH"); + + return makeRequest(); +} + +Response Session::Impl::Post() { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + + // In case there is no body or payload set it to an empty post: + if (hasBodyOrPayload_) { + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, readcb_.callback ? nullptr : ""); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST"); + } + + return makeRequest(); +} + +Response Session::Impl::Put() { + curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT"); + + return makeRequest(); +} + +std::shared_ptr Session::Impl::GetCurlHolder() { + return curl_; +} + +Response Session::Impl::makeDownloadRequest() { + assert(curl_->handle); + const std::string parametersContent = parameters_.GetContent(*curl_); + if (!parametersContent.empty()) { + Url new_url{url_ + "?" + parametersContent}; + curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str()); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); + } + + std::string protocol = url_.str().substr(0, url_.str().find(':')); + if (proxies_.has(protocol)) { + curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_PROXY, ""); + } + + curl_->error[0] = '\0'; + + std::string header_string; + if (headercb_.callback) { + curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); + curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); + curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string); + } + + CURLcode curl_error = curl_easy_perform(curl_->handle); + + curl_slist* raw_cookies{nullptr}; + curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); + Cookies cookies = util::parseCookies(raw_cookies); + curl_slist_free_all(raw_cookies); + std::string errorMsg = curl_->error.data(); + + return Response(curl_, "", std::move(header_string), std::move(cookies), + Error(curl_error, std::move(errorMsg))); +} + +Response Session::Impl::makeRequest() { + assert(curl_->handle); + + // Set Header: + SetHeaderInternal(); + + const std::string parametersContent = parameters_.GetContent(*curl_); + if (!parametersContent.empty()) { + Url new_url{url_ + "?" + parametersContent}; + curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str()); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); + } + + // Proxy: + std::string protocol = url_.str().substr(0, url_.str().find(':')); + if (proxies_.has(protocol)) { + curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); + } else { + curl_easy_setopt(curl_->handle, CURLOPT_PROXY, nullptr); + } + +#if LIBCURL_VERSION_MAJOR >= 7 +#if LIBCURL_VERSION_MINOR >= 21 + /* enable all supported built-in compressions */ + curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, ""); +#endif +#endif + +#if LIBCURL_VERSION_MAJOR >= 7 +#if LIBCURL_VERSION_MINOR >= 71 + // Fix loading certs from Windows cert store when using OpenSSL: + curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA); +#endif +#endif + + curl_->error[0] = '\0'; + + std::string response_string; + std::string header_string; + if (!this->writecb_.callback) { + curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction); + curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string); + } + if (!this->headercb_.callback) { + curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); + curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string); + } + + // Enable so we are able to retrive certificate information: + curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L); + + CURLcode curl_error = curl_easy_perform(curl_->handle); + + curl_slist* raw_cookies{nullptr}; + curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); + Cookies cookies = util::parseCookies(raw_cookies); + curl_slist_free_all(raw_cookies); + + // Reset the has no body property: + hasBodyOrPayload_ = false; + + std::string errorMsg = curl_->error.data(); + return Response(curl_, std::move(response_string), std::move(header_string), std::move(cookies), + Error(curl_error, std::move(errorMsg))); +} + +// clang-format off +Session::Session() : pimpl_(new Impl()) {} +Session::~Session() = default; +void Session::SetReadCallback(const ReadCallback& read) { pimpl_->SetReadCallback(read); } +void Session::SetHeaderCallback(const HeaderCallback& header) { pimpl_->SetHeaderCallback(header); } +void Session::SetWriteCallback(const WriteCallback& write) { pimpl_->SetWriteCallback(write); } +void Session::SetProgressCallback(const ProgressCallback& progress) { pimpl_->SetProgressCallback(progress); } +void Session::SetUrl(const Url& url) { pimpl_->SetUrl(url); } +void Session::SetParameters(const Parameters& parameters) { pimpl_->SetParameters(parameters); } +void Session::SetParameters(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); } +void Session::SetHeader(const Header& header) { pimpl_->SetHeader(header); } +void Session::UpdateHeader(const Header& header) { pimpl_->UpdateHeader(header); } +void Session::SetTimeout(const Timeout& timeout) { pimpl_->SetTimeout(timeout); } +void Session::SetConnectTimeout(const ConnectTimeout& timeout) { pimpl_->SetConnectTimeout(timeout); } +void Session::SetAuth(const Authentication& auth) { pimpl_->SetAuth(auth); } +void Session::SetDigest(const Digest& auth) { pimpl_->SetDigest(auth); } +void Session::SetUserAgent(const UserAgent& ua) { pimpl_->SetUserAgent(ua); } +void Session::SetPayload(const Payload& payload) { pimpl_->SetPayload(payload); } +void Session::SetPayload(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); } +void Session::SetProxies(const Proxies& proxies) { pimpl_->SetProxies(proxies); } +void Session::SetProxies(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); } +void Session::SetMultipart(const Multipart& multipart) { pimpl_->SetMultipart(multipart); } +void Session::SetMultipart(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); } +void Session::SetNTLM(const NTLM& auth) { pimpl_->SetNTLM(auth); } +void Session::SetRedirect(const bool& redirect) { pimpl_->SetRedirect(redirect); } +void Session::SetMaxRedirects(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); } +void Session::SetCookies(const Cookies& cookies) { pimpl_->SetCookies(cookies); } +void Session::SetBody(const Body& body) { pimpl_->SetBody(body); } +void Session::SetBody(Body&& body) { pimpl_->SetBody(std::move(body)); } +void Session::SetLowSpeed(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); } +void Session::SetVerifySsl(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); } +void Session::SetUnixSocket(const UnixSocket& unix_socket) { pimpl_->SetUnixSocket(unix_socket); } +void Session::SetSslOptions(const SslOptions& options) { pimpl_->SetSslOptions(options); } +void Session::SetVerbose(const Verbose& verbose) { pimpl_->SetVerbose(verbose); } +void Session::SetOption(const ReadCallback& read) { pimpl_->SetReadCallback(read); } +void Session::SetOption(const HeaderCallback& header) { pimpl_->SetHeaderCallback(header); } +void Session::SetOption(const WriteCallback& write) { pimpl_->SetWriteCallback(write); } +void Session::SetOption(const ProgressCallback& progress) { pimpl_->SetProgressCallback(progress); } +void Session::SetOption(const DebugCallback& debug) { pimpl_->SetDebugCallback(debug); } +void Session::SetOption(const Url& url) { pimpl_->SetUrl(url); } +void Session::SetOption(const Parameters& parameters) { pimpl_->SetParameters(parameters); } +void Session::SetOption(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); } +void Session::SetOption(const Header& header) { pimpl_->SetHeader(header); } +void Session::SetOption(const Timeout& timeout) { pimpl_->SetTimeout(timeout); } +void Session::SetOption(const ConnectTimeout& timeout) { pimpl_->SetConnectTimeout(timeout); } +void Session::SetOption(const Authentication& auth) { pimpl_->SetAuth(auth); } +void Session::SetOption(const LimitRate& limit_rate) { pimpl_->SetLimitRate(limit_rate); } +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 +void Session::SetOption(const Bearer& auth) { pimpl_->SetBearer(auth); } +#endif +void Session::SetOption(const Digest& auth) { pimpl_->SetDigest(auth); } +void Session::SetOption(const UserAgent& ua) { pimpl_->SetUserAgent(ua); } +void Session::SetOption(const Payload& payload) { pimpl_->SetPayload(payload); } +void Session::SetOption(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); } +void Session::SetOption(const Proxies& proxies) { pimpl_->SetProxies(proxies); } +void Session::SetOption(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); } +void Session::SetOption(const Multipart& multipart) { pimpl_->SetMultipart(multipart); } +void Session::SetOption(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); } +void Session::SetOption(const NTLM& auth) { pimpl_->SetNTLM(auth); } +void Session::SetOption(const bool& redirect) { pimpl_->SetRedirect(redirect); } +void Session::SetOption(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); } +void Session::SetOption(const Cookies& cookies) { pimpl_->SetCookies(cookies); } +void Session::SetOption(const Body& body) { pimpl_->SetBody(body); } +void Session::SetOption(Body&& body) { pimpl_->SetBody(std::move(body)); } +void Session::SetOption(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); } +void Session::SetOption(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); } +void Session::SetOption(const Verbose& verbose) { pimpl_->SetVerbose(verbose); } +void Session::SetOption(const UnixSocket& unix_socket) { pimpl_->SetUnixSocket(unix_socket); } +void Session::SetOption(const SslOptions& options) { pimpl_->SetSslOptions(options); } + +Response Session::Delete() { return pimpl_->Delete(); } +Response Session::Download(const WriteCallback& write) { return pimpl_->Download(write); } +Response Session::Download(std::ofstream& file) { return pimpl_->Download(file); } +Response Session::Get() { return pimpl_->Get(); } +Response Session::Head() { return pimpl_->Head(); } +Response Session::Options() { return pimpl_->Options(); } +Response Session::Patch() { return pimpl_->Patch(); } +Response Session::Post() { return pimpl_->Post(); } +Response Session::Put() { return pimpl_->Put(); } + +std::shared_ptr Session::GetCurlHolder() { return pimpl_->GetCurlHolder(); } +// clang-format on +} // namespace cpr diff --git a/vendor/CPR/cpr/timeout.cpp b/vendor/CPR/cpr/timeout.cpp new file mode 100644 index 00000000..431b7406 --- /dev/null +++ b/vendor/CPR/cpr/timeout.cpp @@ -0,0 +1,34 @@ +#include "cpr/timeout.h" + +#include +#include +#include +#include + +namespace cpr { + +// No way around since curl uses a long here. +// NOLINTNEXTLINE(google-runtime-int) +long Timeout::Milliseconds() const { + static_assert(std::is_same::value, + "Following casting expects milliseconds."); + + // No way around since curl uses a long here. + // NOLINTNEXTLINE(google-runtime-int) + if (ms.count() > std::numeric_limits::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::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(ms.count()); +} + +} // namespace cpr diff --git a/vendor/CPR/cpr/unix_socket.cpp b/vendor/CPR/cpr/unix_socket.cpp new file mode 100644 index 00000000..3171dbc8 --- /dev/null +++ b/vendor/CPR/cpr/unix_socket.cpp @@ -0,0 +1,8 @@ + +#include "cpr/unix_socket.h" + +namespace cpr { +const char* UnixSocket::GetUnixSocketString() const noexcept { + return unix_socket_.data(); +} +} // namespace cpr diff --git a/vendor/CPR/cpr/util.cpp b/vendor/CPR/cpr/util.cpp new file mode 100644 index 00000000..26e9336d --- /dev/null +++ b/vendor/CPR/cpr/util.cpp @@ -0,0 +1,164 @@ +#include "cpr/util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cpr { +namespace util { + +Cookies parseCookies(curl_slist* raw_cookies) { + Cookies cookies; + for (curl_slist* nc = raw_cookies; nc; nc = nc->next) { + std::vector tokens = cpr::util::split(nc->data, '\t'); + std::string value = tokens.back(); + tokens.pop_back(); + cookies[tokens.back()] = value; + } + return cookies; +} + +Header parseHeader(const std::string& headers, std::string* status_line, std::string* reason) { + Header header; + std::vector lines; + std::istringstream stream(headers); + { + std::string line; + while (std::getline(stream, line, '\n')) { + lines.push_back(line); + } + } + + for (std::string& line : lines) { + // NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers) + if (line.substr(0, 5) == "HTTP/") { + // set the status_line if it was given + if ((status_line != nullptr) || (reason != nullptr)) { + line.resize(std::min(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(value.size(), value.find_last_not_of("\t\n\r ") + 1)); + header[line.substr(0, found)] = value; + } + } + } + + return header; +} + +std::vector split(const std::string& to_split, char delimiter) { + std::vector tokens; + + std::stringstream stream(to_split); + std::string item; + while (std::getline(stream, item, delimiter)) { + tokens.push_back(item); + } + + return tokens; +} + +size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read) { + size *= nitems; + return read->callback(ptr, size) ? size : CURL_READFUNC_ABORT; +} + +size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header) { + size *= nmemb; + return header->callback({ptr, size}) ? size : 0; +} + +size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data) { + size *= nmemb; + data->append(ptr, size); + return size; +} + +size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) { + size *= nmemb; + file->write(ptr, size); + return size; +} + +size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write) { + size *= nmemb; + return write->callback({ptr, size}) ? size : 0; +} + +#if LIBCURL_VERSION_NUM < 0x072000 +int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow, + double ultotal, double ulnow) { +#else +int progressUserFunction(const ProgressCallback* progress, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) { +#endif + return progress->callback(dltotal, dlnow, ultotal, ulnow) ? 0 : 1; +} + +int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, + const DebugCallback* debug) { + debug->callback(DebugCallback::InfoType(type), std::string(data, size)); + return 0; +} + +/** + * Creates a temporary CurlHolder object and uses it to escape the given string. + * If you plan to use this methode on a regular basis think about creating a CurlHolder + * object and calling urlEncode(std::string) on it. + * + * Example: + * CurlHolder holder; + * std::string input = "Hello World!"; + * std::string result = holder.urlEncode(input); + **/ +std::string urlEncode(const std::string& s) { + CurlHolder holder; // Create a temporary new holder for URL encoding + return holder.urlEncode(s); +} + +/** + * Creates a temporary CurlHolder object and uses it to unescape the given string. + * If you plan to use this methode on a regular basis think about creating a CurlHolder + * object and calling urlDecode(std::string) on it. + * + * Example: + * CurlHolder holder; + * std::string input = "Hello%20World%21"; + * std::string result = holder.urlDecode(input); + **/ +std::string urlDecode(const std::string& s) { + CurlHolder holder; // Create a temporary new holder for URL decoding + return holder.urlDecode(s); +} + +} // namespace util +} // namespace cpr diff --git a/vendor/CPR/include/cpr/api.h b/vendor/CPR/include/cpr/api.h new file mode 100644 index 00000000..7d8237a3 --- /dev/null +++ b/vendor/CPR/include/cpr/api.h @@ -0,0 +1,229 @@ +#ifndef CPR_API_H +#define CPR_API_H + +#include +#include +#include +#include +#include + +#include "cpr/auth.h" +#include "cpr/bearer.h" +#include "cpr/cprtypes.h" +#include "cpr/digest.h" +#include "cpr/multipart.h" +#include "cpr/ntlm.h" +#include "cpr/payload.h" +#include "cpr/response.h" +#include "cpr/session.h" +#include + +namespace cpr { + +using AsyncResponse = std::future; + +namespace priv { + +template +void set_option(Session& session, T&& t) { + session.SetOption(std::forward(t)); +} + +template +void set_option(Session& session, T&& t, Ts&&... ts) { + set_option(session, std::forward(t)); + set_option(session, std::forward(ts)...); +} + +} // namespace priv + +// Get methods +template +Response Get(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Get(); +} + +// Get async methods +template +AsyncResponse GetAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Get(std::move(ts)...); }, std::move(ts)...); +} + +// Get callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto GetCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Get(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Post methods +template +Response Post(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Post(); +} + +// Post async methods +template +AsyncResponse PostAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Post(std::move(ts)...); }, std::move(ts)...); +} + +// Post callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto PostCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Post(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Put methods +template +Response Put(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Put(); +} + +// Put async methods +template +AsyncResponse PutAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Put(std::move(ts)...); }, std::move(ts)...); +} + +// Put callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto PutCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Put(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Head methods +template +Response Head(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Head(); +} + +// Head async methods +template +AsyncResponse HeadAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Head(std::move(ts)...); }, std::move(ts)...); +} + +// Head callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto HeadCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Head(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Delete methods +template +Response Delete(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Delete(); +} + +// Delete async methods +template +AsyncResponse DeleteAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Delete(std::move(ts)...); }, + std::move(ts)...); +} + +// Delete callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto DeleteCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Delete(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Options methods +template +Response Options(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Options(); +} + +// Options async methods +template +AsyncResponse OptionsAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Options(std::move(ts)...); }, + std::move(ts)...); +} + +// Options callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto OptionsCallback(Then then, Ts... ts) + -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Options(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Patch methods +template +Response Patch(Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Patch(); +} + +// Patch async methods +template +AsyncResponse PatchAsync(Ts... ts) { + return std::async( + std::launch::async, [](Ts... ts) { return Patch(std::move(ts)...); }, std::move(ts)...); +} + +// Patch callback methods +template +// NOLINTNEXTLINE(fuchsia-trailing-return) +auto PatchCallback(Then then, Ts... ts) -> std::future { + return std::async( + std::launch::async, [](Then then, Ts... ts) { return then(Patch(std::move(ts)...)); }, + std::move(then), std::move(ts)...); +} + +// Download methods +template +Response Download(std::ofstream& file, Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Download(file); +} + +// Download with user callback +template +Response Download(const WriteCallback& write, Ts&&... ts) { + Session session; + priv::set_option(session, std::forward(ts)...); + return session.Download(write); +} + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/auth.h b/vendor/CPR/include/cpr/auth.h new file mode 100644 index 00000000..0da65e39 --- /dev/null +++ b/vendor/CPR/include/cpr/auth.h @@ -0,0 +1,31 @@ +#ifndef CPR_AUTH_H +#define CPR_AUTH_H + +#include + +#include + +namespace cpr { + +class Authentication { + public: + Authentication(const std::string& username, const std::string& password) + : auth_string_{username + ":" + password} {} + Authentication(std::string&& username, std::string&& password) + : auth_string_{std::move(username) + ":" + std::move(password)} {} + Authentication(const Authentication& other) = default; + Authentication(Authentication&& old) noexcept = default; + virtual ~Authentication() noexcept = default; + + Authentication& operator=(Authentication&& old) noexcept = default; + Authentication& operator=(const Authentication& other) = default; + + virtual const char* GetAuthString() const noexcept; + + protected: + std::string auth_string_; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/bearer.h b/vendor/CPR/include/cpr/bearer.h new file mode 100644 index 00000000..c7e5d35a --- /dev/null +++ b/vendor/CPR/include/cpr/bearer.h @@ -0,0 +1,36 @@ +#ifndef CPR_BEARER_H +#define CPR_BEARER_H + +#include +#include + +#include + +namespace cpr { + +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 +class Bearer { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Bearer(const std::string& token) : token_string_{token} {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Bearer(std::string&& token) : token_string_{std::move(token)} {} + Bearer(const Bearer& other) = default; + Bearer(Bearer&& old) noexcept = default; + virtual ~Bearer() noexcept = default; + + Bearer& operator=(Bearer&& old) noexcept = default; + Bearer& operator=(const Bearer& other) = default; + + virtual const char* GetToken() const noexcept; + + protected: + std::string token_string_; +}; +#endif + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/body.h b/vendor/CPR/include/cpr/body.h new file mode 100644 index 00000000..bafc89f9 --- /dev/null +++ b/vendor/CPR/include/cpr/body.h @@ -0,0 +1,32 @@ +#ifndef CPR_BODY_H +#define CPR_BODY_H + +#include +#include + +#include "cpr/cprtypes.h" + +namespace cpr { + +class Body : public StringHolder { + public: + Body() : StringHolder() {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Body(const std::string& body) : StringHolder(body) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Body(std::string&& body) : StringHolder(std::move(body)) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Body(const char* body) : StringHolder(body) {} + Body(const char* str, size_t len) : StringHolder(str, len) {} + Body(const std::initializer_list args) : StringHolder(args) {} + Body(const Body& other) = default; + Body(Body&& old) noexcept = default; + ~Body() override = default; + + Body& operator=(Body&& old) noexcept = default; + Body& operator=(const Body& other) = default; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/callback.h b/vendor/CPR/include/cpr/callback.h new file mode 100644 index 00000000..5b2fae21 --- /dev/null +++ b/vendor/CPR/include/cpr/callback.h @@ -0,0 +1,78 @@ +#ifndef CPR_CALLBACK_H +#define CPR_CALLBACK_H + +#include "cprtypes.h" + +#include +#include + +namespace cpr { + +class ReadCallback { + public: + ReadCallback() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + ReadCallback(std::function callback) + : size{-1}, callback{std::move(callback)} {} + ReadCallback(cpr_off_t size, std::function callback) + : size{size}, callback{std::move(callback)} {} + + cpr_off_t size{}; + std::function callback; +}; + +class HeaderCallback { + public: + HeaderCallback() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + HeaderCallback(std::function callback) + : callback(std::move(callback)) {} + + std::function callback; +}; + +class WriteCallback { + public: + WriteCallback() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + WriteCallback(std::function callback) : callback(std::move(callback)) {} + + std::function callback; +}; + +class ProgressCallback { + public: + ProgressCallback() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + ProgressCallback(std::function + callback) + : callback(std::move(callback)) {} + + std::function + callback; +}; + +class DebugCallback { + public: + enum class InfoType { + TEXT = 0, + HEADER_IN = 1, + HEADER_OUT = 2, + DATA_IN = 3, + DATA_OUT = 4, + SSL_DATA_IN = 5, + SSL_DATA_OUT = 6, + }; + DebugCallback() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + DebugCallback(std::function callback) + : callback(std::move(callback)) {} + + std::function callback; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/connect_timeout.h b/vendor/CPR/include/cpr/connect_timeout.h new file mode 100644 index 00000000..546e8a58 --- /dev/null +++ b/vendor/CPR/include/cpr/connect_timeout.h @@ -0,0 +1,18 @@ +#ifndef CPR_CONNECT_TIMEOUT_H +#define CPR_CONNECT_TIMEOUT_H + +#include "cpr/timeout.h" + +namespace cpr { + +class ConnectTimeout : public Timeout { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + ConnectTimeout(const std::chrono::milliseconds& duration) : Timeout{duration} {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + ConnectTimeout(const std::int32_t& milliseconds) : Timeout{milliseconds} {} +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/cookies.h b/vendor/CPR/include/cpr/cookies.h new file mode 100644 index 00000000..2c32035c --- /dev/null +++ b/vendor/CPR/include/cpr/cookies.h @@ -0,0 +1,55 @@ +#ifndef CPR_COOKIES_H +#define CPR_COOKIES_H + +#include "cpr/curlholder.h" +#include +#include +#include +#include + +namespace cpr { + +class Cookies { + public: + /** + * Should we URL-encode cookies when making a request. + * Based on RFC6265, it is recommended but not mandatory to encode cookies. + * + * ------- + * To maximize compatibility with user agents, servers that wish to + * store arbitrary data in a cookie-value SHOULD encode that data, for + * example, using Base64 [RFC4648]. + * ------- + * Source: RFC6265 (https://www.ietf.org/rfc/rfc6265.txt) + **/ + bool encode{true}; + + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Cookies(bool encode = true) : encode(encode) {} + Cookies(const std::initializer_list>& pairs, + bool encode = true) + : encode(encode), map_{pairs} {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Cookies(const std::map& map, bool encode = true) + : encode(encode), map_{map} {} + + std::string& operator[](const std::string& key); + std::string GetEncoded(const CurlHolder& holder) const; + + using iterator = std::map::iterator; + using const_iterator = std::map::const_iterator; + + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + protected: + std::map map_; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/cpr.h b/vendor/CPR/include/cpr/cpr.h new file mode 100644 index 00000000..9b7bb199 --- /dev/null +++ b/vendor/CPR/include/cpr/cpr.h @@ -0,0 +1,13 @@ +#ifndef CPR_CPR_H +#define CPR_CPR_H + +#include "cpr/api.h" +#include "cpr/auth.h" +#include "cpr/cprtypes.h" +#include "cpr/response.h" +#include "cpr/session.h" +#include "cpr/status_codes.h" + +#define CPR_LIBCURL_VERSION_NUM LIBCURL_VERSION_NUM + +#endif diff --git a/vendor/CPR/include/cpr/cprtypes.h b/vendor/CPR/include/cpr/cprtypes.h new file mode 100644 index 00000000..abd8dca3 --- /dev/null +++ b/vendor/CPR/include/cpr/cprtypes.h @@ -0,0 +1,133 @@ +#ifndef CPR_CPR_TYPES_H +#define CPR_CPR_TYPES_H + +#include +#include +#include +#include +#include +#include + +namespace cpr { + +/** + * Wrapper around "curl_off_t" to prevent applications from having to link against libcurl. + **/ +using cpr_off_t = curl_off_t; + +template +class StringHolder { + public: + StringHolder() = default; + explicit StringHolder(const std::string& str) : str_(str) {} + explicit StringHolder(std::string&& str) : str_(std::move(str)) {} + explicit StringHolder(const char* str) : str_(str) {} + StringHolder(const char* str, size_t len) : str_(str, len) {} + StringHolder(const std::initializer_list args) { + str_ = std::accumulate(args.begin(), args.end(), str_); + } + StringHolder(const StringHolder& other) = default; + StringHolder(StringHolder&& old) noexcept = default; + virtual ~StringHolder() = default; + + StringHolder& operator=(StringHolder&& old) noexcept = default; + + StringHolder& operator=(const StringHolder& other) = default; + + explicit operator std::string() const { + return str_; + } + + T operator+(const char* rhs) const { + return T(str_ + rhs); + } + + T operator+(const std::string& rhs) const { + return T(str_ + rhs); + } + + T operator+(const StringHolder& rhs) const { + return T(str_ + rhs.str_); + } + + void operator+=(const char* rhs) { + str_ += rhs; + } + void operator+=(const std::string& rhs) { + str_ += rhs; + } + void operator+=(const StringHolder& rhs) { + str_ += rhs; + } + + bool operator==(const char* rhs) const { + return str_ == rhs; + } + bool operator==(const std::string& rhs) const { + return str_ == rhs; + } + bool operator==(const StringHolder& rhs) const { + return str_ == rhs.str_; + } + + bool operator!=(const char* rhs) const { + return str_.c_str() != rhs; + } + bool operator!=(const std::string& rhs) const { + return str_ != rhs; + } + bool operator!=(const StringHolder& rhs) const { + return str_ != rhs.str_; + } + + const std::string& str() { + return str_; + } + const std::string& str() const { + return str_; + } + const char* c_str() const { + return str_.c_str(); + } + const char* data() const { + return str_.data(); + } + + protected: + std::string str_{}; +}; + +template +std::ostream& operator<<(std::ostream& os, const StringHolder& s) { + os << s.str(); + return os; +} + +class Url : public StringHolder { + public: + Url() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Url(const std::string& url) : StringHolder(url) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Url(std::string&& url) : StringHolder(std::move(url)) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Url(const char* url) : StringHolder(url) {} + Url(const char* str, size_t len) : StringHolder(std::string(str, len)) {} + Url(const std::initializer_list args) : StringHolder(args) {} + Url(const Url& other) = default; + Url(Url&& old) noexcept = default; + ~Url() override = default; + + Url& operator=(Url&& old) noexcept = default; + Url& operator=(const Url& other) = default; +}; + +struct CaseInsensitiveCompare { + bool operator()(const std::string& a, const std::string& b) const noexcept; +}; + +using Header = std::map; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/curl_container.h b/vendor/CPR/include/cpr/curl_container.h new file mode 100644 index 00000000..ac67e944 --- /dev/null +++ b/vendor/CPR/include/cpr/curl_container.h @@ -0,0 +1,55 @@ +#ifndef CURL_CONTAINER_H +#define CURL_CONTAINER_H + +#include +#include +#include +#include + +#include "cpr/curlholder.h" + + +namespace cpr { + +struct Parameter { + Parameter(const std::string& key, const std::string& value) : key{key}, value{value} {} + Parameter(std::string&& key, std::string&& value) + : key{std::move(key)}, value{std::move(value)} {} + + std::string key; + std::string value; +}; + +struct Pair { + Pair(const std::string& p_key, const std::string& p_value) : key(p_key), value(p_value) {} + Pair(std::string&& p_key, std::string&& p_value) + : key(std::move(p_key)), value(std::move(p_value)) {} + + std::string key; + std::string value; +}; + + +template +class CurlContainer { + public: + /** + * Enables or disables URL encoding for keys and values when calling GetContent(...). + **/ + bool encode = true; + + CurlContainer() = default; + CurlContainer(const std::initializer_list&); + + void Add(const std::initializer_list&); + void Add(const T&); + + const std::string GetContent(const CurlHolder&) const; + + protected: + std::vector containerList_; +}; + +} // namespace cpr + +#endif // diff --git a/vendor/CPR/include/cpr/curlholder.h b/vendor/CPR/include/cpr/curlholder.h new file mode 100644 index 00000000..a8a6e07e --- /dev/null +++ b/vendor/CPR/include/cpr/curlholder.h @@ -0,0 +1,50 @@ +#ifndef CPR_CURL_HOLDER_H +#define CPR_CURL_HOLDER_H + +#include +#include +#include + +#include + +namespace cpr { +struct CurlHolder { + private: + /** + * Mutex for curl_easy_init(). + * curl_easy_init() is not thread save. + * References: + * https://curl.haxx.se/libcurl/c/curl_easy_init.html + * https://curl.haxx.se/libcurl/c/threadsafe.html + **/ + // It does not make sense to make a std::mutex const. + // NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) + static std::mutex curl_easy_init_mutex_; + + public: + CURL* handle{nullptr}; + struct curl_slist* chunk{nullptr}; + struct curl_httppost* formpost{nullptr}; + std::array error{}; + + CurlHolder(); + CurlHolder(const CurlHolder& other) = default; + CurlHolder(CurlHolder&& old) noexcept = default; + ~CurlHolder(); + + CurlHolder& operator=(CurlHolder&& old) noexcept = default; + CurlHolder& operator=(const CurlHolder& other) = default; + + /** + * Uses curl_easy_escape(...) for escaping the given string. + **/ + std::string urlEncode(const std::string& s) const; + + /** + * Uses curl_easy_unescape(...) for unescaping the given string. + **/ + std::string urlDecode(const std::string& s) const; +}; +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/digest.h b/vendor/CPR/include/cpr/digest.h new file mode 100644 index 00000000..2a7ff38d --- /dev/null +++ b/vendor/CPR/include/cpr/digest.h @@ -0,0 +1,15 @@ +#ifndef CPR_DIGEST_H +#define CPR_DIGEST_H + +#include "cpr/auth.h" + +namespace cpr { +class Digest : public Authentication { + public: + Digest(const std::string& username, const std::string& password) + : Authentication{username, password} {} +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/error.h b/vendor/CPR/include/cpr/error.h new file mode 100644 index 00000000..6a2be06e --- /dev/null +++ b/vendor/CPR/include/cpr/error.h @@ -0,0 +1,54 @@ +#ifndef CPR_ERROR_H +#define CPR_ERROR_H + +#include +#include + +#include "cpr/cprtypes.h" +#include + +namespace cpr { + +enum class ErrorCode { + OK = 0, + CONNECTION_FAILURE, + EMPTY_RESPONSE, + HOST_RESOLUTION_FAILURE, + INTERNAL_ERROR, + INVALID_URL_FORMAT, + NETWORK_RECEIVE_ERROR, + NETWORK_SEND_FAILURE, + OPERATION_TIMEDOUT, + PROXY_RESOLUTION_FAILURE, + SSL_CONNECT_ERROR, + SSL_LOCAL_CERTIFICATE_ERROR, + SSL_REMOTE_CERTIFICATE_ERROR, + SSL_CACERT_ERROR, + GENERIC_SSL_ERROR, + UNSUPPORTED_PROTOCOL, + REQUEST_CANCELLED, + UNKNOWN_ERROR = 1000, +}; + +class Error { + public: + ErrorCode code = ErrorCode::OK; + std::string message{}; + + Error() = default; + + Error(const std::int32_t& curl_code, std::string&& p_error_message) + : code{getErrorCodeForCurlError(curl_code)}, + message(std::move(p_error_message)) {} + + explicit operator bool() const { + return code != ErrorCode::OK; + } + + private: + static ErrorCode getErrorCodeForCurlError(std::int32_t curl_code); +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/limit_rate.h b/vendor/CPR/include/cpr/limit_rate.h new file mode 100644 index 00000000..d258e63d --- /dev/null +++ b/vendor/CPR/include/cpr/limit_rate.h @@ -0,0 +1,19 @@ +#ifndef CPR_SPEED_LIMIT_H +#define CPR_SPEED_LIMIT_H + +#include + +namespace cpr { + +class LimitRate { + public: + LimitRate(const std::int64_t downrate, const std::int64_t uprate) + : downrate(downrate), uprate(uprate) {} + + std::int64_t downrate = 0; + std::int64_t uprate = 0; +}; + +} // namespace cpr + +#endif \ No newline at end of file diff --git a/vendor/CPR/include/cpr/low_speed.h b/vendor/CPR/include/cpr/low_speed.h new file mode 100644 index 00000000..394a4382 --- /dev/null +++ b/vendor/CPR/include/cpr/low_speed.h @@ -0,0 +1,18 @@ +#ifndef CPR_LOW_SPEED_H +#define CPR_LOW_SPEED_H + +#include + +namespace cpr { + +class LowSpeed { + public: + LowSpeed(const std::int32_t limit, const std::int32_t time) : limit(limit), time(time) {} + + std::int32_t limit; + std::int32_t time; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/max_redirects.h b/vendor/CPR/include/cpr/max_redirects.h new file mode 100644 index 00000000..4d3dea4d --- /dev/null +++ b/vendor/CPR/include/cpr/max_redirects.h @@ -0,0 +1,18 @@ +#ifndef CPR_MAX_REDIRECTS_H +#define CPR_MAX_REDIRECTS_H + +#include + +namespace cpr { + +class MaxRedirects { + public: + explicit MaxRedirects(const std::int32_t number_of_redirects) + : number_of_redirects(number_of_redirects) {} + + std::int32_t number_of_redirects; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/multipart.h b/vendor/CPR/include/cpr/multipart.h new file mode 100644 index 00000000..4e0fb2fa --- /dev/null +++ b/vendor/CPR/include/cpr/multipart.h @@ -0,0 +1,79 @@ +#ifndef CPR_MULTIPART_H +#define CPR_MULTIPART_H + +#include +#include +#include +#include +#include + +namespace cpr { + +struct File { + explicit File(std::string&& filepath) : filepath(std::move(filepath)) {} + explicit File(const std::string& filepath) : filepath(filepath) {} + const std::string filepath; +}; + +struct Buffer { + using data_t = const unsigned char*; + + template + Buffer(Iterator begin, Iterator end, std::string&& filename) + // Ignored here since libcurl reqires a long. + // There is also no way around the reinterpret_cast. + // NOLINTNEXTLINE(google-runtime-int, cppcoreguidelines-pro-type-reinterpret-cast) + : data{reinterpret_cast(&(*begin))}, datalen{static_cast( + std::distance(begin, end))}, + filename(std::move(filename)) { + is_random_access_iterator(begin, end); + static_assert(sizeof(*begin) == 1, "only byte buffers can be used"); + } + + template + typename std::enable_if::iterator_category, + std::random_access_iterator_tag>::value>::type + is_random_access_iterator(Iterator /* begin */, Iterator /* end */) {} + + data_t data; + // Ignored here since libcurl reqires a long: + // NOLINTNEXTLINE(google-runtime-int) + long datalen; + const std::string filename; +}; + +struct Part { + Part(const std::string& name, const std::string& value, const std::string& content_type = {}) + : name{name}, value{value}, + content_type{content_type}, is_file{false}, is_buffer{false} {} + Part(const std::string& name, const std::int32_t& value, const std::string& content_type = {}) + : name{name}, value{std::to_string(value)}, + content_type{content_type}, is_file{false}, is_buffer{false} {} + Part(const std::string& name, const File& file, const std::string& content_type = {}) + : name{name}, value{file.filepath}, + content_type{content_type}, is_file{true}, is_buffer{false} {} + Part(const std::string& name, const Buffer& buffer, const std::string& content_type = {}) + : name{name}, value{buffer.filename}, content_type{content_type}, data{buffer.data}, + datalen{buffer.datalen}, is_file{false}, is_buffer{true} {} + + std::string name; + std::string value; + std::string content_type; + Buffer::data_t data{nullptr}; + // Ignored here since libcurl reqires a long: + // NOLINTNEXTLINE(google-runtime-int) + long datalen{0}; + bool is_file; + bool is_buffer; +}; + +class Multipart { + public: + Multipart(const std::initializer_list& parts); + + std::vector parts; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/ntlm.h b/vendor/CPR/include/cpr/ntlm.h new file mode 100644 index 00000000..e15833d8 --- /dev/null +++ b/vendor/CPR/include/cpr/ntlm.h @@ -0,0 +1,15 @@ +#ifndef CPR_NTLM_H +#define CPR_NTLM_H + +#include "cpr/auth.h" + +namespace cpr { +class NTLM : public Authentication { + public: + NTLM(const std::string& username, const std::string& password) + : Authentication{username, password} {} +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/parameters.h b/vendor/CPR/include/cpr/parameters.h new file mode 100644 index 00000000..0e34d4d7 --- /dev/null +++ b/vendor/CPR/include/cpr/parameters.h @@ -0,0 +1,18 @@ +#ifndef CPR_PARAMETERS_H +#define CPR_PARAMETERS_H + +#include + +#include "cpr/curl_container.h" + +namespace cpr { + +class Parameters : public CurlContainer { + public: + Parameters() = default; + Parameters(const std::initializer_list& parameters); +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/payload.h b/vendor/CPR/include/cpr/payload.h new file mode 100644 index 00000000..686b540e --- /dev/null +++ b/vendor/CPR/include/cpr/payload.h @@ -0,0 +1,23 @@ +#ifndef CPR_PAYLOAD_H +#define CPR_PAYLOAD_H + +#include + +#include "cpr/curl_container.h" + + +namespace cpr { +class Payload : public CurlContainer { + public: + template + Payload(const It begin, const It end) { + for (It pair = begin; pair != end; ++pair) { + Add(*pair); + } + } + Payload(const std::initializer_list& pairs); +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/proxies.h b/vendor/CPR/include/cpr/proxies.h new file mode 100644 index 00000000..565a63ef --- /dev/null +++ b/vendor/CPR/include/cpr/proxies.h @@ -0,0 +1,22 @@ +#ifndef CPR_PROXIES_H +#define CPR_PROXIES_H + +#include +#include +#include + +namespace cpr { +class Proxies { + public: + Proxies() = default; + Proxies(const std::initializer_list>& hosts); + + bool has(const std::string& protocol) const; + const std::string& operator[](const std::string& protocol); + + protected: + std::map hosts_; +}; +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/response.h b/vendor/CPR/include/cpr/response.h new file mode 100644 index 00000000..bd3f25d4 --- /dev/null +++ b/vendor/CPR/include/cpr/response.h @@ -0,0 +1,56 @@ +#ifndef CPR_RESPONSE_H +#define CPR_RESPONSE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "cpr/cookies.h" +#include "cpr/cprtypes.h" +#include "cpr/error.h" +#include "cpr/ssl_options.h" +#include "cpr/util.h" + +namespace cpr { + +class Response { + protected: + std::shared_ptr curl_{nullptr}; + + public: + // Ignored here since libcurl uses a long for this. + // NOLINTNEXTLINE(google-runtime-int) + long status_code{}; + std::string text{}; + Header header{}; + Url url{}; + double elapsed{}; + Cookies cookies{}; + Error error{}; + std::string raw_header{}; + std::string status_line{}; + std::string reason{}; + cpr_off_t uploaded_bytes{}; + cpr_off_t downloaded_bytes{}; + // Ignored here since libcurl uses a long for this. + // NOLINTNEXTLINE(google-runtime-int) + long redirect_count{}; + + Response() = default; + Response(std::shared_ptr curl, std::string&& p_text, std::string&& p_header_string, + Cookies&& p_cookies, Error&& p_error); + std::vector GetCertInfo(); + Response(const Response& other) = default; + Response(Response&& old) noexcept = default; + ~Response() noexcept = default; + + Response& operator=(Response&& old) noexcept = default; + Response& operator=(const Response& other) = default; +}; +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/session.h b/vendor/CPR/include/cpr/session.h new file mode 100644 index 00000000..cccffc76 --- /dev/null +++ b/vendor/CPR/include/cpr/session.h @@ -0,0 +1,136 @@ +#ifndef CPR_SESSION_H +#define CPR_SESSION_H + +#include +#include +#include + +#include "cpr/auth.h" +#include "cpr/bearer.h" +#include "cpr/body.h" +#include "cpr/callback.h" +#include "cpr/connect_timeout.h" +#include "cpr/cookies.h" +#include "cpr/cprtypes.h" +#include "cpr/curlholder.h" +#include "cpr/digest.h" +#include "cpr/limit_rate.h" +#include "cpr/low_speed.h" +#include "cpr/max_redirects.h" +#include "cpr/multipart.h" +#include "cpr/ntlm.h" +#include "cpr/parameters.h" +#include "cpr/payload.h" +#include "cpr/proxies.h" +#include "cpr/response.h" +#include "cpr/ssl_options.h" +#include "cpr/timeout.h" +#include "cpr/unix_socket.h" +#include "cpr/user_agent.h" +#include "cpr/verbose.h" + +namespace cpr { + +class Session { + public: + Session(); + Session(Session&& old) noexcept = default; + Session(const Session& other) = delete; + + ~Session(); + + Session& operator=(Session&& old) noexcept = default; + Session& operator=(const Session& other) = delete; + + void SetUrl(const Url& url); + void SetParameters(const Parameters& parameters); + void SetParameters(Parameters&& parameters); + void SetHeader(const Header& header); + void UpdateHeader(const Header& header); + void SetTimeout(const Timeout& timeout); + void SetConnectTimeout(const ConnectTimeout& timeout); + void SetAuth(const Authentication& auth); + void SetDigest(const Digest& auth); + void SetUserAgent(const UserAgent& ua); + void SetPayload(Payload&& payload); + void SetPayload(const Payload& payload); + void SetProxies(Proxies&& proxies); + void SetProxies(const Proxies& proxies); + void SetMultipart(Multipart&& multipart); + void SetMultipart(const Multipart& multipart); + void SetNTLM(const NTLM& auth); + void SetRedirect(const bool& redirect); + void SetMaxRedirects(const MaxRedirects& max_redirects); + void SetCookies(const Cookies& cookies); + void SetBody(Body&& body); + void SetBody(const Body& body); + void SetLowSpeed(const LowSpeed& low_speed); + void SetVerifySsl(const VerifySsl& verify); + void SetUnixSocket(const UnixSocket& unix_socket); + void SetSslOptions(const SslOptions& options); + void SetReadCallback(const ReadCallback& read); + void SetHeaderCallback(const HeaderCallback& header); + void SetWriteCallback(const WriteCallback& write); + void SetProgressCallback(const ProgressCallback& progress); + void SetDebugCallback(const DebugCallback& debug); + void SetVerbose(const Verbose& verbose); + + // Used in templated functions + void SetOption(const Url& url); + void SetOption(const Parameters& parameters); + void SetOption(Parameters&& parameters); + void SetOption(const Header& header); + void SetOption(const Timeout& timeout); + void SetOption(const ConnectTimeout& timeout); + void SetOption(const Authentication& auth); +// Only supported with libcurl >= 7.61.0. +// As an alternative use SetHeader and add the token manually. +#if LIBCURL_VERSION_NUM >= 0x073D00 + void SetOption(const Bearer& auth); +#endif + void SetOption(const Digest& auth); + void SetOption(const UserAgent& ua); + void SetOption(Payload&& payload); + void SetOption(const Payload& payload); + void SetOption(const LimitRate& limit_rate); + void SetOption(Proxies&& proxies); + void SetOption(const Proxies& proxies); + void SetOption(Multipart&& multipart); + void SetOption(const Multipart& multipart); + void SetOption(const NTLM& auth); + void SetOption(const bool& redirect); + void SetOption(const MaxRedirects& max_redirects); + void SetOption(const Cookies& cookies); + void SetOption(Body&& body); + void SetOption(const Body& body); + void SetOption(const ReadCallback& read); + void SetOption(const HeaderCallback& header); + void SetOption(const WriteCallback& write); + void SetOption(const ProgressCallback& progress); + void SetOption(const DebugCallback& debug); + void SetOption(const LowSpeed& low_speed); + void SetOption(const VerifySsl& verify); + void SetOption(const Verbose& verbose); + void SetOption(const UnixSocket& unix_socket); + void SetOption(const SslOptions& options); + + Response Delete(); + Response Download(const WriteCallback& write); + Response Download(std::ofstream& file); + Response Get(); + Response Head(); + Response Options(); + Response Patch(); + Response Post(); + Response Put(); + + std::shared_ptr GetCurlHolder(); + + private: + class Impl; + std::unique_ptr pimpl_; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/ssl_options.h b/vendor/CPR/include/cpr/ssl_options.h new file mode 100644 index 00000000..ea805254 --- /dev/null +++ b/vendor/CPR/include/cpr/ssl_options.h @@ -0,0 +1,533 @@ +#ifndef CPR_SSLOPTIONS_H +#define CPR_SSLOPTIONS_H + +#include + +#include + +#include + +#define __LIBCURL_VERSION_GTE(major, minor) \ + ((LIBCURL_VERSION_MAJOR > (major)) || \ + ((LIBCURL_VERSION_MAJOR == (major)) && (LIBCURL_VERSION_MINOR >= (minor)))) +#define __LIBCURL_VERSION_LT(major, minor) \ + ((LIBCURL_VERSION_MAJOR < (major)) || \ + ((LIBCURL_VERSION_MAJOR == (major)) && (LIBCURL_VERSION_MINOR < (minor)))) + +#ifndef SUPPORT_ALPN +#define SUPPORT_ALPN __LIBCURL_VERSION_GTE(7, 36) +#endif +#ifndef SUPPORT_NPN +#define SUPPORT_NPN __LIBCURL_VERSION_GTE(7, 36) +#endif + +#ifndef SUPPORT_SSLv2 +#define SUPPORT_SSLv2 __LIBCURL_VERSION_LT(7, 19) +#endif +#ifndef SUPPORT_SSLv3 +#define SUPPORT_SSLv3 __LIBCURL_VERSION_LT(7, 39) +#endif +#ifndef SUPPORT_TLSv1_0 +#define SUPPORT_TLSv1_0 __LIBCURL_VERSION_GTE(7, 34) +#endif +#ifndef SUPPORT_TLSv1_1 +#define SUPPORT_TLSv1_1 __LIBCURL_VERSION_GTE(7, 34) +#endif +#ifndef SUPPORT_TLSv1_2 +#define SUPPORT_TLSv1_2 __LIBCURL_VERSION_GTE(7, 34) +#endif +#ifndef SUPPORT_TLSv1_3 +#define SUPPORT_TLSv1_3 __LIBCURL_VERSION_GTE(7, 52) +#endif +#ifndef SUPPORT_MAX_TLS_VERSION +#define SUPPORT_MAX_TLS_VERSION __LIBCURL_VERSION_GTE(7, 54) +#endif +#ifndef SUPPORT_MAX_TLSv1_1 +#define SUPPORT_MAX_TLSv1_1 __LIBCURL_VERSION_GTE(7, 54) +#endif +#ifndef SUPPORT_MAX_TLSv1_2 +#define SUPPORT_MAX_TLSv1_2 __LIBCURL_VERSION_GTE(7, 54) +#endif +#ifndef SUPPORT_MAX_TLSv1_3 +#define SUPPORT_MAX_TLSv1_3 __LIBCURL_VERSION_GTE(7, 54) +#endif +#ifndef SUPPORT_TLSv13_CIPHERS +#define SUPPORT_TLSv13_CIPHERS __LIBCURL_VERSION_GTE(7, 61) +#endif +#ifndef SUPPORT_SESSIONID_CACHE +#define SUPPORT_SESSIONID_CACHE __LIBCURL_VERSION_GTE(7, 16) +#endif +#ifndef SUPPORT_SSL_FALSESTART +#define SUPPORT_SSL_FALSESTART __LIBCURL_VERSION_GTE(7, 42) +#endif +#ifndef SUPPORT_SSL_NO_REVOKE +#define SUPPORT_SSL_NO_REVOKE __LIBCURL_VERSION_GTE(7, 44) +#endif + +namespace cpr { + +class VerifySsl { + public: + VerifySsl() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + VerifySsl(bool verify) : verify(verify) {} + + explicit operator bool() const { + return verify; + } + + bool verify = true; +}; + +namespace ssl { + +// set SSL client certificate +class CertFile { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + CertFile(std::string&& p_filename) : filename(std::move(p_filename)) {} + + const std::string filename; + + virtual const char* GetCertType() const { + return "PEM"; + } +}; + +using PemCert = CertFile; + +class DerCert : public CertFile { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + DerCert(std::string&& p_filename) : CertFile(std::move(p_filename)) {} + + const char* GetCertType() const override { + return "DER"; + } +}; + +// specify private keyfile for TLS and SSL client cert +class KeyFile { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + KeyFile(std::string&& p_filename) : filename(std::move(p_filename)) {} + + template + KeyFile(FileType&& p_filename, PassType p_password) + : filename(std::forward(p_filename)), password(std::move(p_password)) {} + + std::string filename; + std::string password; + + virtual const char* GetKeyType() const { + return "PEM"; + } +}; + +using PemKey = KeyFile; + +class DerKey : public KeyFile { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + DerKey(std::string&& p_filename) : KeyFile(std::move(p_filename)) {} + + template + DerKey(FileType&& p_filename, PassType p_password) + : KeyFile(std::forward(p_filename), std::move(p_password)) {} + + const char* GetKeyType() const override { + return "DER"; + } +}; + +#if SUPPORT_ALPN +// This option enables/disables ALPN in the SSL handshake (if the SSL backend libcurl is built to +// use supports it), which can be used to negotiate http2. +class ALPN { + public: + ALPN() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + ALPN(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = true; +}; +#endif // SUPPORT_ALPN + +#if SUPPORT_NPN +// This option enables/disables NPN in the SSL handshake (if the SSL backend libcurl is built to +// use supports it), which can be used to negotiate http2. +class NPN { + public: + NPN() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + NPN(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = true; +}; +#endif // SUPPORT_NPN + +// This option determines whether libcurl verifies that the server cert is for the server it is +// known as. +class VerifyHost { + public: + VerifyHost() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + VerifyHost(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = true; +}; + +// This option determines whether libcurl verifies the authenticity of the peer's certificate. +class VerifyPeer { + public: + VerifyPeer() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + VerifyPeer(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = true; +}; + +// This option determines whether libcurl verifies the status of the server cert using the +// "Certificate Status Request" TLS extension (aka. OCSP stapling). +class VerifyStatus { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + VerifyStatus(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = false; +}; + +// TLS v1.0 or later +struct TLSv1 {}; +#if SUPPORT_SSLv2 +// SSL v2 (but not SSLv3) +struct SSLv2 {}; +#endif +#if SUPPORT_SSLv3 +// SSL v3 (but not SSLv2) +struct SSLv3 {}; +#endif +#if SUPPORT_TLSv1_0 +// TLS v1.0 or later (Added in 7.34.0) +struct TLSv1_0 {}; +#endif +#if SUPPORT_TLSv1_1 +// TLS v1.1 or later (Added in 7.34.0) +struct TLSv1_1 {}; +#endif +#if SUPPORT_TLSv1_2 +// TLS v1.2 or later (Added in 7.34.0) +struct TLSv1_2 {}; +#endif +#if SUPPORT_TLSv1_3 +// TLS v1.3 or later (Added in 7.52.0) +struct TLSv1_3 {}; +#endif +#if SUPPORT_MAX_TLS_VERSION +// The flag defines the maximum supported TLS version by libcurl, or the default value from the SSL +// library is used. +struct MaxTLSVersion {}; +#endif +#if SUPPORT_MAX_TLSv1_0 +// The flag defines maximum supported TLS version as TLSv1.0. (Added in 7.54.0) +struct MaxTLSv1_0 {}; +#endif +#if SUPPORT_MAX_TLSv1_1 +// The flag defines maximum supported TLS version as TLSv1.1. (Added in 7.54.0) +struct MaxTLSv1_1 {}; +#endif +#if SUPPORT_MAX_TLSv1_2 +// The flag defines maximum supported TLS version as TLSv1.2. (Added in 7.54.0) +struct MaxTLSv1_2 {}; +#endif +#if SUPPORT_MAX_TLSv1_3 +// The flag defines maximum supported TLS version as TLSv1.3. (Added in 7.54.0) +struct MaxTLSv1_3 {}; +#endif + +// path to Certificate Authority (CA) bundle +class CaInfo { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + CaInfo(std::string&& p_filename) : filename(std::move(p_filename)) {} + + std::string filename; +}; + +// specify directory holding CA certificates +class CaPath { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + CaPath(std::string&& p_filename) : filename(std::move(p_filename)) {} + + std::string filename; +}; + +// specify a Certificate Revocation List file +class Crl { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Crl(std::string&& p_filename) : filename(std::move(p_filename)) {} + + std::string filename; +}; + +// specify ciphers to use for TLS +class Ciphers { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Ciphers(std::string&& p_ciphers) : ciphers(std::move(p_ciphers)) {} + + std::string ciphers; +}; + +#if SUPPORT_TLSv13_CIPHERS +// specify ciphers suites to use for TLS 1.3 +class TLS13_Ciphers { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + TLS13_Ciphers(std::string&& p_ciphers) : ciphers(std::move(p_ciphers)) {} + + std::string ciphers; +}; +#endif + +#if SUPPORT_SESSIONID_CACHE +// enable/disable use of the SSL session-ID cache +class SessionIdCache { + public: + SessionIdCache() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + SessionIdCache(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = true; +}; +#endif + +#if SUPPORT_SSL_FALSESTART +class SslFastStart { + public: + SslFastStart() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + SslFastStart(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = false; +}; +#endif + +class NoRevoke { +public: + NoRevoke() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + NoRevoke(bool enabled) : enabled(enabled) {} + + explicit operator bool() const { + return enabled; + } + + bool enabled = false; +}; + +} // namespace ssl + +struct SslOptions { + std::string cert_file; + std::string cert_type; + std::string key_file; + std::string key_type; + std::string key_pass; +#if SUPPORT_ALPN + bool enable_alpn = true; +#endif // SUPPORT_ALPN +#if SUPPORT_NPN + bool enable_npn = true; +#endif // SUPPORT_ALPN + bool verify_host = true; + bool verify_peer = true; + bool verify_status = false; + int ssl_version = CURL_SSLVERSION_DEFAULT; +#if SUPPORT_SSL_NO_REVOKE + bool ssl_no_revoke = false; +#endif +#if SUPPORT_MAX_TLS_VERSION + int max_version = CURL_SSLVERSION_MAX_DEFAULT; +#endif + std::string ca_info; + std::string ca_path; + std::string crl_file; + std::string ciphers; +#if SUPPORT_TLSv13_CIPHERS + std::string tls13_ciphers; +#endif +#if SUPPORT_SESSIONID_CACHE + bool session_id_cache = true; +#endif + + void SetOption(const ssl::CertFile& opt) { + cert_file = opt.filename; + cert_type = opt.GetCertType(); + } + void SetOption(const ssl::KeyFile& opt) { + key_file = opt.filename; + key_type = opt.GetKeyType(); + key_pass = opt.password; + } +#if SUPPORT_ALPN + void SetOption(const ssl::ALPN& opt) { + enable_alpn = opt.enabled; + } +#endif // SUPPORT_ALPN +#if SUPPORT_NPN + void SetOption(const ssl::NPN& opt) { + enable_npn = opt.enabled; + } +#endif // SUPPORT_NPN + void SetOption(const ssl::VerifyHost& opt) { + verify_host = opt.enabled; + } + void SetOption(const ssl::VerifyPeer& opt) { + verify_peer = opt.enabled; + } + void SetOption(const ssl::VerifyStatus& opt) { + verify_status = opt.enabled; + } + void SetOption(const ssl::TLSv1& /*opt*/) { + ssl_version = CURL_SSLVERSION_TLSv1; + } +#if SUPPORT_SSL_NO_REVOKE + void SetOption(const ssl::NoRevoke& opt) { + ssl_no_revoke = opt.enabled; + } +#endif +#if SUPPORT_SSLv2 + void SetOption(const ssl::SSLv2& /*opt*/) { + ssl_version = CURL_SSLVERSION_SSLv2; + } +#endif +#if SUPPORT_SSLv3 + void SetOption(const ssl::SSLv3& /*opt*/) { + ssl_version = CURL_SSLVERSION_SSLv3; + } +#endif +#if SUPPORT_TLSv1_0 + void SetOption(const ssl::TLSv1_0& /*opt*/) { + ssl_version = CURL_SSLVERSION_TLSv1_0; + } +#endif +#if SUPPORT_TLSv1_1 + void SetOption(const ssl::TLSv1_1& /*opt*/) { + ssl_version = CURL_SSLVERSION_TLSv1_1; + } +#endif +#if SUPPORT_TLSv1_2 + void SetOption(const ssl::TLSv1_2& /*opt*/) { + ssl_version = CURL_SSLVERSION_TLSv1_2; + } +#endif +#if SUPPORT_TLSv1_3 + void SetOption(const ssl::TLSv1_3& /*opt*/) { + ssl_version = CURL_SSLVERSION_TLSv1_3; + } +#endif +#if SUPPORT_MAX_TLS_VERSION + void SetOption(const ssl::MaxTLSVersion& /*opt*/) { + max_version = CURL_SSLVERSION_DEFAULT; + } +#endif +#if SUPPORT_MAX_TLSv1_0 + void SetOption(const ssl::MaxTLSv1_0& opt) { + max_version = CURL_SSLVERSION_MAX_TLSv1_0; + } +#endif +#if SUPPORT_MAX_TLSv1_1 + void SetOption(const ssl::MaxTLSv1_1& /*opt*/) { + max_version = CURL_SSLVERSION_MAX_TLSv1_1; + } +#endif +#if SUPPORT_MAX_TLSv1_2 + void SetOption(const ssl::MaxTLSv1_2& /*opt*/) { + max_version = CURL_SSLVERSION_MAX_TLSv1_2; + } +#endif +#if SUPPORT_MAX_TLSv1_3 + void SetOption(const ssl::MaxTLSv1_3& /*opt*/) { + max_version = CURL_SSLVERSION_MAX_TLSv1_3; + } +#endif + void SetOption(const ssl::CaInfo& opt) { + ca_info = opt.filename; + } + void SetOption(const ssl::CaPath& opt) { + ca_path = opt.filename; + } + void SetOption(const ssl::Crl& opt) { + crl_file = opt.filename; + } + void SetOption(const ssl::Ciphers& opt) { + ciphers = opt.ciphers; + } +#if SUPPORT_TLSv13_CIPHERS + void SetOption(const ssl::TLS13_Ciphers& opt) { + tls13_ciphers = opt.ciphers; + } +#endif +#if SUPPORT_SESSIONID_CACHE + void SetOption(const ssl::SessionIdCache& opt) { + session_id_cache = opt.enabled; + } +#endif +}; + +namespace priv { + +template +void set_ssl_option(SslOptions& opts, T&& t) { + opts.SetOption(std::forward(t)); +} + +template +void set_ssl_option(SslOptions& opts, T&& t, Ts&&... ts) { + set_ssl_option(opts, std::forward(t)); + set_ssl_option(opts, std::move(ts)...); +} + +} // namespace priv + +template +SslOptions Ssl(Ts&&... ts) { + SslOptions opts; + priv::set_ssl_option(opts, std::move(ts)...); + return opts; +} + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/status_codes.h b/vendor/CPR/include/cpr/status_codes.h new file mode 100644 index 00000000..6c7acd6b --- /dev/null +++ b/vendor/CPR/include/cpr/status_codes.h @@ -0,0 +1,100 @@ +#ifndef _CPR_STATUS_CODES +#define _CPR_STATUS_CODES +#include +namespace cpr { +namespace status { +// Information responses +constexpr std::int32_t HTTP_CONTINUE = 100; +constexpr std::int32_t HTTP_SWITCHING_PROTOCOL = 101; +constexpr std::int32_t HTTP_PROCESSING = 102; +constexpr std::int32_t HTTP_EARLY_HINTS = 103; +// Successful responses +constexpr std::int32_t HTTP_OK = 200; +constexpr std::int32_t HTTP_CREATED = 201; +constexpr std::int32_t HTTP_ACCEPTED = 202; +constexpr std::int32_t HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +constexpr std::int32_t HTTP_NO_CONTENT = 204; +constexpr std::int32_t HTTP_RESET_CONTENT = 205; +constexpr std::int32_t HTTP_PARTIAL_CONTENT = 206; +constexpr std::int32_t HTTP_MULTI_STATUS = 207; +constexpr std::int32_t HTTP_ALREADY_REPORTED = 208; +constexpr std::int32_t HTTP_IM_USED = 226; +// Redirection messages +constexpr std::int32_t HTTP_MULTIPLE_CHOICE = 300; +constexpr std::int32_t HTTP_MOVED_PERMANENTLY = 301; +constexpr std::int32_t HTTP_FOUND = 302; +constexpr std::int32_t HTTP_SEE_OTHER = 303; +constexpr std::int32_t HTTP_NOT_MODIFIED = 304; +constexpr std::int32_t HTTP_USE_PROXY = 305; +constexpr std::int32_t HTTP_UNUSED = 306; +constexpr std::int32_t HTTP_TEMPORARY_REDIRECT = 307; +constexpr std::int32_t HTTP_PERMANENT_REDIRECT = 308; +// Client error responses +constexpr std::int32_t HTTP_BAD_REQUEST = 400; +constexpr std::int32_t HTTP_UNAUTHORIZED = 401; +constexpr std::int32_t HTTP_PAYMENT_REQUIRED = 402; +constexpr std::int32_t HTTP_FORBIDDEN = 403; +constexpr std::int32_t HTTP_NOT_FOUND = 404; +constexpr std::int32_t HTTP_METHOD_NOT_ALLOWED = 405; +constexpr std::int32_t HTTP_NOT_ACCEPTABLE = 406; +constexpr std::int32_t HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +constexpr std::int32_t HTTP_REQUEST_TIMEOUT = 408; +constexpr std::int32_t HTTP_CONFLICT = 409; +constexpr std::int32_t HTTP_GONE = 410; +constexpr std::int32_t HTTP_LENGTH_REQUIRED = 411; +constexpr std::int32_t HTTP_PRECONDITION_FAILED = 412; +constexpr std::int32_t HTTP_PAYLOAD_TOO_LARGE = 413; +constexpr std::int32_t HTTP_URI_TOO_LONG = 414; +constexpr std::int32_t HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +constexpr std::int32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +constexpr std::int32_t HTTP_EXPECTATION_FAILED = 417; +constexpr std::int32_t HTTP_IM_A_TEAPOT = 418; +constexpr std::int32_t HTTP_MISDIRECTED_REQUEST = 421; +constexpr std::int32_t HTTP_UNPROCESSABLE_ENTITY = 422; +constexpr std::int32_t HTTP_LOCKED = 423; +constexpr std::int32_t HTTP_FAILED_DEPENDENCY = 424; +constexpr std::int32_t HTTP_TOO_EARLY = 425; +constexpr std::int32_t HTTP_UPGRADE_REQUIRED = 426; +constexpr std::int32_t HTTP_PRECONDITION_REQUIRED = 428; +constexpr std::int32_t HTTP_TOO_MANY_REQUESTS = 429; +constexpr std::int32_t HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; +constexpr std::int32_t HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; +// Server response errors +constexpr std::int32_t HTTP_INTERNAL_SERVER_ERROR = 500; +constexpr std::int32_t HTTP_NOT_IMPLEMENTED = 501; +constexpr std::int32_t HTTP_BAD_GATEWAY = 502; +constexpr std::int32_t HTTP_SERVICE_UNAVAILABLE = 503; +constexpr std::int32_t HTTP_GATEWAY_TIMEOUT = 504; +constexpr std::int32_t HTTP_HTTP_VERSION_NOT_SUPPORTED = 505; +constexpr std::int32_t HTTP_VARIANT_ALSO_NEGOTIATES = 506; +constexpr std::int32_t HTTP_INSUFFICIENT_STORAGE = 507; +constexpr std::int32_t HTTP_LOOP_DETECTED = 508; +constexpr std::int32_t HTTP_NOT_EXTENDED = 510; +constexpr std::int32_t HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; + +constexpr std::int32_t INFO_CODE_OFFSET = 100; +constexpr std::int32_t SUCCESS_CODE_OFFSET = 200; +constexpr std::int32_t REDIRECT_CODE_OFFSET = 300; +constexpr std::int32_t CLIENT_ERROR_CODE_OFFSET = 400; +constexpr std::int32_t SERVER_ERROR_CODE_OFFSET = 500; +constexpr std::int32_t MISC_CODE_OFFSET = 600; + +constexpr bool is_informational(const std::int32_t code) { + return (code >= INFO_CODE_OFFSET && code < SUCCESS_CODE_OFFSET); +} +constexpr bool is_success(const std::int32_t code) { + return (code >= SUCCESS_CODE_OFFSET && code < REDIRECT_CODE_OFFSET); +} +constexpr bool is_redirect(const std::int32_t code) { + return (code >= REDIRECT_CODE_OFFSET && code < CLIENT_ERROR_CODE_OFFSET); +} +constexpr bool is_client_error(const std::int32_t code) { + return (code >= CLIENT_ERROR_CODE_OFFSET && code < SERVER_ERROR_CODE_OFFSET); +} +constexpr bool is_server_error(const std::int32_t code) { + return (code >= SERVER_ERROR_CODE_OFFSET && code < MISC_CODE_OFFSET); +} + +} // namespace status +} // namespace cpr +#endif \ No newline at end of file diff --git a/vendor/CPR/include/cpr/timeout.h b/vendor/CPR/include/cpr/timeout.h new file mode 100644 index 00000000..a01da439 --- /dev/null +++ b/vendor/CPR/include/cpr/timeout.h @@ -0,0 +1,25 @@ +#ifndef CPR_TIMEOUT_H +#define CPR_TIMEOUT_H + +#include +#include + +namespace cpr { + +class Timeout { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Timeout(const std::chrono::milliseconds& duration) : ms{duration} {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Timeout(const std::int32_t& milliseconds) : Timeout{std::chrono::milliseconds(milliseconds)} {} + + // No way around since curl uses a long here. + // NOLINTNEXTLINE(google-runtime-int) + long Milliseconds() const; + + std::chrono::milliseconds ms; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/unix_socket.h b/vendor/CPR/include/cpr/unix_socket.h new file mode 100644 index 00000000..9d4d77c0 --- /dev/null +++ b/vendor/CPR/include/cpr/unix_socket.h @@ -0,0 +1,21 @@ +#ifndef CPR_UNIX_SOCKET_H +#define CPR_UNIX_SOCKET_H + +#include + +namespace cpr { + +class UnixSocket { + public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + UnixSocket(std::string&& unix_socket) : unix_socket_(std::move(unix_socket)) {} + + const char* GetUnixSocketString() const noexcept; + + private: + const std::string unix_socket_; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/user_agent.h b/vendor/CPR/include/cpr/user_agent.h new file mode 100644 index 00000000..71787c5f --- /dev/null +++ b/vendor/CPR/include/cpr/user_agent.h @@ -0,0 +1,31 @@ +#ifndef CPR_USERAGENT_H +#define CPR_USERAGENT_H + +#include +#include + +#include "cpr/cprtypes.h" + +namespace cpr { +class UserAgent : public StringHolder { + public: + UserAgent() : StringHolder() {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + UserAgent(const std::string& useragent) : StringHolder(useragent) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + UserAgent(std::string&& useragent) : StringHolder(std::move(useragent)) {} + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + UserAgent(const char* useragent) : StringHolder(useragent) {} + UserAgent(const char* str, size_t len) : StringHolder(str, len) {} + UserAgent(const std::initializer_list args) : StringHolder(args) {} + UserAgent(const UserAgent& other) = default; + UserAgent(UserAgent&& old) noexcept = default; + ~UserAgent() override = default; + + UserAgent& operator=(UserAgent&& old) noexcept = default; + UserAgent& operator=(const UserAgent& other) = default; +}; + +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/util.h b/vendor/CPR/include/cpr/util.h new file mode 100644 index 00000000..1c2e1610 --- /dev/null +++ b/vendor/CPR/include/cpr/util.h @@ -0,0 +1,40 @@ +#ifndef CPR_UTIL_H +#define CPR_UTIL_H + +#include +#include +#include + +#include "cpr/callback.h" +#include "cpr/cookies.h" +#include "cpr/cprtypes.h" +#include "cpr/curlholder.h" + +namespace cpr { +namespace util { + +Header parseHeader(const std::string& headers, std::string* status_line = nullptr, + std::string* reason = nullptr); +Cookies parseCookies(curl_slist* raw_cookies); +size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read); +size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header); +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_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write); +#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 +int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size, + const DebugCallback* debug); +std::vector split(const std::string& to_split, char delimiter); +std::string urlEncode(const std::string& s); +std::string urlDecode(const std::string& s); + +} // namespace util +} // namespace cpr + +#endif diff --git a/vendor/CPR/include/cpr/verbose.h b/vendor/CPR/include/cpr/verbose.h new file mode 100644 index 00000000..49bf0298 --- /dev/null +++ b/vendor/CPR/include/cpr/verbose.h @@ -0,0 +1,18 @@ +#ifndef CPR_VERBOSE_H_ +#define CPR_VERBOSE_H_ + +namespace cpr { + +class Verbose { + public: + Verbose() = default; + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + Verbose(const bool verbose) : verbose{verbose} {} + + bool verbose = true; +}; + +} // namespace cpr + + +#endif /* CPR_VERBOSE_H_ */