diff options
Diffstat (limited to 'Src/external_dependencies/cpr/cpr/util.cpp')
-rw-r--r-- | Src/external_dependencies/cpr/cpr/util.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/Src/external_dependencies/cpr/cpr/util.cpp b/Src/external_dependencies/cpr/cpr/util.cpp new file mode 100644 index 00000000..81fd3a28 --- /dev/null +++ b/Src/external_dependencies/cpr/cpr/util.cpp @@ -0,0 +1,236 @@ +#include "cpr/util.h" + +#include <algorithm> +#include <cassert> +#include <cctype> +#include <chrono> +#include <cstdint> +#include <fstream> +#include <iomanip> +#include <ios> +#include <sstream> +#include <string> +#include <vector> + +#if defined(_Win32) +#include <Windows.h> +#else +// https://en.cppreference.com/w/c/string/byte/memset +// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp, cppcoreguidelines-macro-usage) +#define __STDC_WANT_LIB_EXT1__ 1 +#include <cstring> +#endif + +namespace cpr::util { + +enum class CurlHTTPCookieField : size_t { + Domain = 0, + IncludeSubdomains, + Path, + HttpsOnly, + Expires, + Name, + Value, +}; + +Cookies parseCookies(curl_slist* raw_cookies) { + const int CURL_HTTP_COOKIE_SIZE = static_cast<int>(CurlHTTPCookieField::Value) + 1; + Cookies cookies; + for (curl_slist* nc = raw_cookies; nc; nc = nc->next) { + std::vector<std::string> tokens = cpr::util::split(nc->data, '\t'); + while (tokens.size() < CURL_HTTP_COOKIE_SIZE) { + tokens.emplace_back(""); + } + std::time_t expires = static_cast<time_t>(std::stoul(tokens.at(static_cast<size_t>(CurlHTTPCookieField::Expires)))); + cookies.emplace_back(Cookie{ + tokens.at(static_cast<size_t>(CurlHTTPCookieField::Name)), + tokens.at(static_cast<size_t>(CurlHTTPCookieField::Value)), + tokens.at(static_cast<size_t>(CurlHTTPCookieField::Domain)), + isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::IncludeSubdomains))), + tokens.at(static_cast<size_t>(CurlHTTPCookieField::Path)), + isTrue(tokens.at(static_cast<size_t>(CurlHTTPCookieField::HttpsOnly))), + std::chrono::system_clock::from_time_t(expires), + }); + } + return cookies; +} + +Header parseHeader(const std::string& headers, std::string* status_line, std::string* reason) { + Header header; + std::vector<std::string> lines; + std::istringstream stream(headers); + { + std::string line; + while (std::getline(stream, line, '\n')) { + lines.push_back(line); + } + } + + for (std::string& line : lines) { + if (line.substr(0, 5) == "HTTP/") { + // set the status_line if it was given + if ((status_line != nullptr) || (reason != nullptr)) { + line.resize(std::min<size_t>(line.size(), line.find_last_not_of("\t\n\r ") + 1)); + if (status_line != nullptr) { + *status_line = line; + } + + // set the reason if it was given + if (reason != nullptr) { + size_t pos1 = line.find_first_of("\t "); + size_t pos2 = std::string::npos; + if (pos1 != std::string::npos) { + pos2 = line.find_first_of("\t ", pos1 + 1); + } + if (pos2 != std::string::npos) { + line.erase(0, pos2 + 1); + *reason = line; + } + } + } + header.clear(); + } + + if (line.length() > 0) { + size_t found = line.find(':'); + if (found != std::string::npos) { + std::string value = line.substr(found + 1); + value.erase(0, value.find_first_not_of("\t ")); + value.resize(std::min<size_t>(value.size(), value.find_last_not_of("\t\n\r ") + 1)); + header[line.substr(0, found)] = value; + } + } + } + + return header; +} + +std::vector<std::string> split(const std::string& to_split, char delimiter) { + std::vector<std::string> tokens; + + std::stringstream stream(to_split); + std::string item; + while (std::getline(stream, item, delimiter)) { + tokens.push_back(item); + } + + return tokens; +} + +size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read) { + size *= nitems; + return (*read)(ptr, size) ? size : CURL_READFUNC_ABORT; +} + +size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header) { + size *= nmemb; + return (*header)({ptr, size}) ? size : 0; +} + +size_t writeFunction(char* ptr, size_t size, size_t nmemb, std::string* data) { + size *= nmemb; + data->append(ptr, size); + return size; +} + +size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file) { + size *= nmemb; + file->write(ptr, static_cast<std::streamsize>(size)); + return size; +} + +size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write) { + size *= nmemb; + return (*write)({ptr, size}) ? size : 0; +} + +#if LIBCURL_VERSION_NUM < 0x072000 +int progressUserFunction(const ProgressCallback* progress, double dltotal, double dlnow, double ultotal, double ulnow) { +#else +int progressUserFunction(const ProgressCallback* progress, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { +#endif + return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : 1; +} // namespace cpr::util + +int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, const DebugCallback* debug) { + (*debug)(static_cast<DebugCallback::InfoType>(type), std::string(data, size)); + return 0; +} + +/** + * Creates a temporary CurlHolder object and uses it to escape the given string. + * If you plan to use this methode on a regular basis think about creating a CurlHolder + * object and calling urlEncode(std::string) on it. + * + * Example: + * CurlHolder holder; + * std::string input = "Hello World!"; + * std::string result = holder.urlEncode(input); + **/ +std::string urlEncode(const std::string& s) { + CurlHolder holder; // Create a temporary new holder for URL encoding + return holder.urlEncode(s); +} + +/** + * Creates a temporary CurlHolder object and uses it to unescape the given string. + * If you plan to use this methode on a regular basis think about creating a CurlHolder + * object and calling urlDecode(std::string) on it. + * + * Example: + * CurlHolder holder; + * std::string input = "Hello%20World%21"; + * std::string result = holder.urlDecode(input); + **/ +std::string urlDecode(const std::string& s) { + CurlHolder holder; // Create a temporary new holder for URL decoding + return holder.urlDecode(s); +} + +#if defined(__STDC_LIB_EXT1__) +void secureStringClear(std::string& s) { + if (s.empty()) { + return; + } + memset_s(&s.front(), s.length(), 0, s.length()); + s.clear(); +} +#elif defined(_WIN32) +void secureStringClear(std::string& s) { + if (s.empty()) { + return; + } + SecureZeroMemory(&s.front(), s.length()); + s.clear(); +} +#else +#if defined(__clang__) +#pragma clang optimize off // clang +#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__) +#pragma GCC push_options // g++ +#pragma GCC optimize("O0") // g++ +#endif +void secureStringClear(std::string& s) { + if (s.empty()) { + return; + } + // NOLINTNEXTLINE (readability-container-data-pointer) + char* ptr = &(s[0]); + memset(ptr, '\0', s.length()); + s.clear(); +} + +#if defined(__clang__) +#pragma clang optimize on // clang +#elif defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW32__) || defined(__MINGW64__) +#pragma GCC pop_options // g++ +#endif +#endif + +bool isTrue(const std::string& s) { + std::string temp_string{s}; + std::transform(temp_string.begin(), temp_string.end(), temp_string.begin(), [](unsigned char c) { return std::tolower(c); }); + return temp_string == "true"; +} + +} // namespace cpr::util |