diff --git a/CMakeLists.txt b/CMakeLists.txt index 58c629b3d..acf5a42ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.16) file(READ "${CMAKE_CURRENT_LIST_DIR}/VERSION" JSONSCHEMA_VERSION) string(STRIP "${JSONSCHEMA_VERSION}" JSONSCHEMA_VERSION) project(jsonschema VERSION "${JSONSCHEMA_VERSION}" LANGUAGES C CXX) +if(APPLE) + enable_language(OBJCXX) +endif() list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # Options @@ -26,30 +29,11 @@ endif() find_package(Blaze REQUIRED) find_package(JSONBinPack REQUIRED) -if(JSONSCHEMA_USE_SYSTEM_CURL) - list(REMOVE_ITEM CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") - find_package(CURL REQUIRED) - list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") - find_package(CPR REQUIRED) -else() - if(NOT WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "MSYS") - find_package(MbedTLS REQUIRED) - endif() - find_package(Nghttp2 REQUIRED) - if(NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "MSYS") - find_package(CAres REQUIRED) - endif() - find_package(PSL REQUIRED) - find_package(ZLIB REQUIRED) - find_package(CURL REQUIRED) - find_package(CPR REQUIRED) -endif() - add_subdirectory(src) if(JSONSCHEMA_DEVELOPMENT) sourcemeta_target_clang_format(SOURCES - src/*.h src/*.cc) + src/*.h src/*.cc src/*.mm) sourcemeta_target_shellcheck(SOURCES test/*.sh install *.sh completion/*) endif() diff --git a/DEPENDENCIES b/DEPENDENCIES index ec359fd7b..0f2baecac 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,11 +1,10 @@ vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02 -core https://github.com/sourcemeta/core df8f2970ccf85a3a3f01e004ac436ff916f8c52a +core https://github.com/sourcemeta/core eb361a9f3a01f7cffb5da7946a9516ee11dc9ede jsonbinpack https://github.com/sourcemeta/jsonbinpack ac8e1af733a781fc4c94a14157f80970ea569479 blaze https://github.com/sourcemeta/blaze 7b214cff6d575831c16a2ce33f55d97c02eb6338 mbedtls https://github.com/Mbed-TLS/mbedtls v3.6.6 curl https://github.com/curl/curl curl-8_20_0 nghttp2 https://github.com/nghttp2/nghttp2 v1.67.1 -cpr https://github.com/libcpr/cpr 1.14.2 c-ares https://github.com/c-ares/c-ares v1.34.5 libpsl https://github.com/rockdaboot/libpsl 0.21.5 zlib https://github.com/madler/zlib v1.3.2 diff --git a/cmake/FindCPR.cmake b/cmake/FindCPR.cmake deleted file mode 100644 index 3f7074962..000000000 --- a/cmake/FindCPR.cmake +++ /dev/null @@ -1,158 +0,0 @@ -if(NOT CPR_FOUND) - set(CPR_DIR "${PROJECT_SOURCE_DIR}/vendor/cpr") - - set(CPR_PUBLIC_HEADER "${CPR_DIR}/include/cpr/cpr.h") - set(CPR_PRIVATE_HEADERS - "${CPR_DIR}/include/cpr/accept_encoding.h" - "${CPR_DIR}/include/cpr/api.h" - "${CPR_DIR}/include/cpr/async_wrapper.h" - "${CPR_DIR}/include/cpr/async.h" - "${CPR_DIR}/include/cpr/auth.h" - "${CPR_DIR}/include/cpr/bearer.h" - "${CPR_DIR}/include/cpr/body_view.h" - "${CPR_DIR}/include/cpr/body.h" - "${CPR_DIR}/include/cpr/buffer.h" - "${CPR_DIR}/include/cpr/callback.h" - "${CPR_DIR}/include/cpr/cert_info.h" - "${CPR_DIR}/include/cpr/connect_timeout.h" - "${CPR_DIR}/include/cpr/connection_pool.h" - "${CPR_DIR}/include/cpr/cookies.h" - "${CPR_DIR}/include/cpr/cprtypes.h" - "${CPR_DIR}/include/cpr/curl_container.h" - "${CPR_DIR}/include/cpr/curlholder.h" - "${CPR_DIR}/include/cpr/curlmultiholder.h" - "${CPR_DIR}/include/cpr/error.h" - "${CPR_DIR}/include/cpr/file.h" - "${CPR_DIR}/include/cpr/filesystem.h" - "${CPR_DIR}/include/cpr/http_version.h" - "${CPR_DIR}/include/cpr/interceptor.h" - "${CPR_DIR}/include/cpr/interface.h" - "${CPR_DIR}/include/cpr/limit_rate.h" - "${CPR_DIR}/include/cpr/local_port_range.h" - "${CPR_DIR}/include/cpr/local_port.h" - "${CPR_DIR}/include/cpr/low_speed.h" - "${CPR_DIR}/include/cpr/multipart.h" - "${CPR_DIR}/include/cpr/multiperform.h" - "${CPR_DIR}/include/cpr/parameters.h" - "${CPR_DIR}/include/cpr/payload.h" - "${CPR_DIR}/include/cpr/proxies.h" - "${CPR_DIR}/include/cpr/proxyauth.h" - "${CPR_DIR}/include/cpr/range.h" - "${CPR_DIR}/include/cpr/redirect.h" - "${CPR_DIR}/include/cpr/reserve_size.h" - "${CPR_DIR}/include/cpr/resolve.h" - "${CPR_DIR}/include/cpr/response.h" - "${CPR_DIR}/include/cpr/secure_string.h" - "${CPR_DIR}/include/cpr/session.h" - "${CPR_DIR}/include/cpr/singleton.h" - "${CPR_DIR}/include/cpr/sse.h" - "${CPR_DIR}/include/cpr/ssl_ctx.h" - "${CPR_DIR}/include/cpr/ssl_options.h" - "${CPR_DIR}/include/cpr/status_codes.h" - "${CPR_DIR}/include/cpr/threadpool.h" - "${CPR_DIR}/include/cpr/timeout.h" - "${CPR_DIR}/include/cpr/unix_socket.h" - "${CPR_DIR}/include/cpr/user_agent.h" - "${CPR_DIR}/include/cpr/util.h" - "${CPR_DIR}/include/cpr/verbose.h") - - add_library(cpr - "${CPR_PUBLIC_HEADER}" ${CPR_PRIVATE_HEADERS} - - "${CPR_DIR}/cpr/accept_encoding.cpp" - "${CPR_DIR}/cpr/async.cpp" - "${CPR_DIR}/cpr/auth.cpp" - "${CPR_DIR}/cpr/callback.cpp" - "${CPR_DIR}/cpr/cert_info.cpp" - "${CPR_DIR}/cpr/cookies.cpp" - "${CPR_DIR}/cpr/connection_pool.cpp" - "${CPR_DIR}/cpr/cprtypes.cpp" - "${CPR_DIR}/cpr/curl_container.cpp" - "${CPR_DIR}/cpr/curlholder.cpp" - "${CPR_DIR}/cpr/curlmultiholder.cpp" - "${CPR_DIR}/cpr/error.cpp" - "${CPR_DIR}/cpr/file.cpp" - "${CPR_DIR}/cpr/interceptor.cpp" - "${CPR_DIR}/cpr/multipart.cpp" - "${CPR_DIR}/cpr/multiperform.cpp" - "${CPR_DIR}/cpr/parameters.cpp" - "${CPR_DIR}/cpr/payload.cpp" - "${CPR_DIR}/cpr/proxies.cpp" - "${CPR_DIR}/cpr/proxyauth.cpp" - "${CPR_DIR}/cpr/redirect.cpp" - "${CPR_DIR}/cpr/response.cpp" - "${CPR_DIR}/cpr/session.cpp" - "${CPR_DIR}/cpr/sse.cpp" - "${CPR_DIR}/cpr/ssl_ctx.cpp" - "${CPR_DIR}/cpr/threadpool.cpp" - "${CPR_DIR}/cpr/timeout.cpp" - "${CPR_DIR}/cpr/unix_socket.cpp" - "${CPR_DIR}/cpr/util.cpp") - - if(SOURCEMETA_COMPILER_MSVC) - target_compile_options(cpr PRIVATE /W3 /MP /EHsc /wd4996 /wd4244 /GS-) - target_compile_definitions(cpr PRIVATE _CRT_SECURE_NO_WARNINGS) - else() - target_compile_options(cpr PRIVATE - -Wall - -Wextra - -Wpedantic - -Werror - -Wdouble-promotion - -Wfloat-equal - -Wformat=2 - -Wmissing-declarations - -Wnon-virtual-dtor - -Woverloaded-virtual - -Wshadow - -Wwrite-strings - -Wno-cast-align - -Wno-cast-qual - -Wno-newline-eof - -Wno-implicit-int-conversion - -Wno-conversion - -Wno-strict-overflow - -Wno-odr) - - if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - target_compile_options(cpr PRIVATE - -funroll-loops - -fstrict-aliasing - -ftree-vectorize - -fno-math-errno - -fwrapv) - endif() - endif() - - # We don't need to know the actual version - set(cpr_VERSION "0.0.0") - set(cpr_VERSION_MAJOR 0) - set(cpr_VERSION_MINOR 0) - set(cpr_VERSION_PATCH 0) - set(cpr_VERSION_NUM 0x000000) - configure_file("${CPR_DIR}/cmake/cprver.h.in" - "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated/cpr/cprver.h") - - target_include_directories(cpr PUBLIC - "$" - "$" - "$") - - target_link_libraries(cpr PUBLIC CURL::libcurl) - - add_library(CPR::cpr ALIAS cpr) - - set_target_properties(cpr - PROPERTIES - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON - CXX_EXTENSIONS OFF - POSITION_INDEPENDENT_CODE ON - OUTPUT_NAME cpr - CXX_VISIBILITY_PRESET "default" - CXX_VISIBILITY_INLINES_HIDDEN FALSE - WINDOWS_EXPORT_ALL_SYMBOLS TRUE - EXPORT_NAME cpr) - - set(CPR_FOUND ON) -endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f3f06c3a4..2f6ffaa75 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(http) + sourcemeta_executable( PROJECT jsonschema NAME cli @@ -25,6 +27,7 @@ target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::uri) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::json) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::jsonl) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::gzip) +target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::http) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::jsonpointer) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::yaml) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::core::regex) @@ -43,7 +46,7 @@ target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::output) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::test) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::alterschema) target_link_libraries(jsonschema_cli PRIVATE sourcemeta::blaze::codegen) -target_link_libraries(jsonschema_cli PRIVATE CPR::cpr) +target_link_libraries(jsonschema_cli PRIVATE jsonschema_http) configure_file(configure.h.in configure.h @ONLY) target_include_directories(jsonschema_cli PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/src/error.h b/src/error.h index de93b599f..91e5a4712 100644 --- a/src/error.h +++ b/src/error.h @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include +#include // std::same_as, std::convertible_to #include // std::uint64_t #include // std::filesystem #include // std::function @@ -566,6 +568,54 @@ inline auto print_exception(const bool is_json, const Exception &exception) } } + if constexpr (requires(const Exception ¤t) { + { + current.status() + } -> std::same_as; + }) { + const auto status{exception.status()}; + if (is_json) { + error_json.assign("status", sourcemeta::core::JSON{ + static_cast(status.code)}); + } else { + std::cerr << " with status "; + if (status.wire.empty()) { + std::cerr << status.code; + } else { + std::cerr << status.wire; + } + std::cerr << "\n"; + } + } + + if constexpr (requires(const Exception ¤t) { + { + current.method() + } -> std::same_as; + }) { + if (is_json) { + error_json.assign( + "method", + sourcemeta::core::JSON{std::string{ + sourcemeta::core::http_method_string(exception.method())}}); + } else { + std::cerr << " with method " + << sourcemeta::core::http_method_string(exception.method()) + << "\n"; + } + } + + if constexpr (requires(const Exception ¤t) { + { current.url() } -> std::convertible_to; + }) { + if (is_json) { + error_json.assign("url", + sourcemeta::core::JSON{std::string{exception.url()}}); + } else { + std::cerr << " at url " << exception.url() << "\n"; + } + } + if constexpr (requires(const Exception ¤t) { current.base().recompose(); }) { @@ -1007,6 +1057,14 @@ inline auto try_catch(const sourcemeta::core::Options &options, const auto is_json{options.contains("json")}; print_exception(is_json, error); return EXIT_OTHER_INPUT_ERROR; + } catch (const sourcemeta::core::HTTPStatusError &error) { + const auto is_json{options.contains("json")}; + print_exception(is_json, error); + return EXIT_UNEXPECTED_ERROR; + } catch (const sourcemeta::core::HTTPError &error) { + const auto is_json{options.contains("json")}; + print_exception(is_json, error); + return EXIT_UNEXPECTED_ERROR; // Standard library handlers } catch (const sourcemeta::core::IOFileNotFoundError &error) { diff --git a/src/http/CMakeLists.txt b/src/http/CMakeLists.txt new file mode 100644 index 000000000..00482c829 --- /dev/null +++ b/src/http/CMakeLists.txt @@ -0,0 +1,37 @@ +# On Apple and Windows platforms, HTTP requests are served by the +# operating system networking stack. Everywhere else, they go through +# cURL (by default vendored alongside its dependencies) +if(APPLE) + add_library(jsonschema_http STATIC http.h http_darwin.mm) + set_source_files_properties(http_darwin.mm + PROPERTIES COMPILE_OPTIONS "-fobjc-arc") + target_link_libraries(jsonschema_http PRIVATE "-framework Foundation") + target_link_libraries(jsonschema_http PRIVATE sourcemeta::core::text) +elseif(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "MSYS") + add_library(jsonschema_http STATIC http.h http_windows.cc) + target_link_libraries(jsonschema_http PRIVATE winhttp) + target_link_libraries(jsonschema_http PRIVATE sourcemeta::core::unicode) +else() + if(JSONSCHEMA_USE_SYSTEM_CURL) + list(REMOVE_ITEM CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + find_package(CURL REQUIRED) + list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + else() + find_package(MbedTLS REQUIRED) + find_package(Nghttp2 REQUIRED) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "MSYS") + find_package(CAres REQUIRED) + endif() + find_package(PSL REQUIRED) + find_package(ZLIB REQUIRED) + find_package(CURL REQUIRED) + endif() + + add_library(jsonschema_http STATIC http.h http_curl.cc) + target_link_libraries(jsonschema_http PRIVATE CURL::libcurl) +endif() + +sourcemeta_add_default_options(PRIVATE jsonschema_http) +target_link_libraries(jsonschema_http PUBLIC sourcemeta::core::http) +target_include_directories(jsonschema_http PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") +set_target_properties(jsonschema_http PROPERTIES FOLDER "jsonschema/http") diff --git a/src/http/http.h b/src/http/http.h new file mode 100644 index 000000000..929298c63 --- /dev/null +++ b/src/http/http.h @@ -0,0 +1,59 @@ +#ifndef SOURCEMETA_JSONSCHEMA_CLI_HTTP_H_ +#define SOURCEMETA_JSONSCHEMA_CLI_HTTP_H_ + +#include + +#include // std::size_t +#include // std::optional +#include // std::string +#include // std::string_view +#include // std::pair, std::move +#include // std::vector + +namespace sourcemeta::jsonschema { + +inline constexpr std::string_view HTTP_RESPONSE_TOO_LARGE_MESSAGE{ + "The response exceeds the maximum allowed size"}; + +struct HTTPRequestBody { + // Sent as the `Content-Type` header of the request, so do not also + // set that header by hand + std::string_view content_type; + std::string_view data; +}; + +struct HTTPRequest { + sourcemeta::core::HTTPMethod method{sourcemeta::core::HTTPMethod::GET}; + // All request fields are views: the caller must keep the data they + // refer to alive until `http_request` returns + std::string_view url; + // Repeated header names are permitted. Note that some platform HTTP + // stacks fold them into a single comma-separated field line, which is + // semantically equivalent per RFC 9110 + std::vector> headers; + std::optional body; + // When set, abort with an `HTTPError` if the response body exceeds + // this number of bytes + std::optional maximum_response_size; +}; + +struct HTTPResponse { + sourcemeta::core::HTTPStatus status{}; + // Header names are normalised to lowercase and repeated headers are + // preserved as separate entries, except on platform HTTP stacks like + // NSURLSession that fold them into a single comma-separated entry. The + // response owns its data, as the backend buffers it was read from do + // not outlive the request + std::vector> headers; + std::string body; +}; + +// Perform an HTTP request, following redirects. This function is +// implemented on top of NSURLSession on Apple platforms, WinHTTP on +// Windows, and cURL everywhere else. Failures to obtain a response are +// reported as `sourcemeta::core::HTTPError` exceptions +auto http_request(const HTTPRequest &request) -> HTTPResponse; + +} // namespace sourcemeta::jsonschema + +#endif diff --git a/src/http/http_curl.cc b/src/http/http_curl.cc new file mode 100644 index 000000000..4d173659e --- /dev/null +++ b/src/http/http_curl.cc @@ -0,0 +1,183 @@ +#include "http.h" + +#include // curl_easy_*, curl_slist_*, curl_global_init + +#include // std::size_t +#include // std::uint16_t +#include // std::optional +#include // std::string +#include // std::string_view + +namespace { + +class CurlHandle { +public: + CurlHandle() : handle_{curl_easy_init()} {} + ~CurlHandle() { + if (this->handle_) { + curl_easy_cleanup(this->handle_); + } + } + + CurlHandle(const CurlHandle &) = delete; + auto operator=(const CurlHandle &) -> CurlHandle & = delete; + CurlHandle(CurlHandle &&) = delete; + auto operator=(CurlHandle &&) -> CurlHandle & = delete; + + auto get() const -> CURL * { return this->handle_; } + explicit operator bool() const { return this->handle_ != nullptr; } + +private: + CURL *handle_; +}; + +class CurlHeaderList { +public: + CurlHeaderList() = default; + ~CurlHeaderList() { + if (this->list_) { + curl_slist_free_all(this->list_); + } + } + + CurlHeaderList(const CurlHeaderList &) = delete; + auto operator=(const CurlHeaderList &) -> CurlHeaderList & = delete; + CurlHeaderList(CurlHeaderList &&) = delete; + auto operator=(CurlHeaderList &&) -> CurlHeaderList & = delete; + + auto append(const std::string &line) -> void { + auto *result{curl_slist_append(this->list_, line.c_str())}; + if (result) { + this->list_ = result; + } + } + + auto get() const -> curl_slist * { return this->list_; } + +private: + curl_slist *list_{nullptr}; +}; + +struct BodyContext { + std::string *output; + std::optional maximum_size; + bool maximum_size_exceeded{false}; +}; + +auto body_callback(char *data, std::size_t size, std::size_t count, + void *user_data) -> std::size_t { + auto *context{static_cast(user_data)}; + if (context->maximum_size.has_value() && + context->output->size() + (size * count) > + context->maximum_size.value()) { + context->maximum_size_exceeded = true; + // Returning a smaller count than given aborts the transfer + return 0; + } + + context->output->append(data, size * count); + return size * count; +} + +auto header_callback(char *data, std::size_t size, std::size_t count, + void *output) -> std::size_t { + sourcemeta::core::http_accumulate_header_line( + *static_cast(output), + std::string_view{data, size * count}); + return size * count; +} + +} // namespace + +namespace sourcemeta::jsonschema { + +auto http_request(const HTTPRequest &request) -> HTTPResponse { + static const CURLcode global_initialization{ + curl_global_init(CURL_GLOBAL_ALL)}; + if (global_initialization != CURLE_OK) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + curl_easy_strerror(global_initialization)}; + } + + const CurlHandle handle; + if (!handle) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to initialise the HTTP client"}; + } + + HTTPResponse response; + const std::string url{request.url}; + curl_easy_setopt(handle.get(), CURLOPT_URL, url.c_str()); + curl_easy_setopt(handle.get(), CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(handle.get(), CURLOPT_NOSIGNAL, 1L); + // Advertise and transparently decode all supported content encodings, + // matching what the NSURLSession and WinHTTP backends do + curl_easy_setopt(handle.get(), CURLOPT_ACCEPT_ENCODING, ""); + + std::string raw_headers; + BodyContext body_context{&response.body, request.maximum_response_size}; + curl_easy_setopt(handle.get(), CURLOPT_WRITEFUNCTION, body_callback); + curl_easy_setopt(handle.get(), CURLOPT_WRITEDATA, &body_context); + curl_easy_setopt(handle.get(), CURLOPT_HEADERFUNCTION, header_callback); + curl_easy_setopt(handle.get(), CURLOPT_HEADERDATA, &raw_headers); + + CurlHeaderList header_list; + for (const auto &[name, value] : request.headers) { + std::string line{name}; + // The semicolon form is how cURL distinguishes a header with an + // empty value from a header to suppress + if (value.empty()) { + line += ";"; + } else { + line += ": "; + line += value; + } + + header_list.append(line); + } + + if (request.body.has_value()) { + std::string content_type_line{"Content-Type: "}; + content_type_line += request.body.value().content_type; + header_list.append(content_type_line); + curl_easy_setopt(handle.get(), CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(request.body.value().data.size())); + curl_easy_setopt(handle.get(), CURLOPT_POSTFIELDS, + request.body.value().data.data()); + } + + if (header_list.get()) { + curl_easy_setopt(handle.get(), CURLOPT_HTTPHEADER, header_list.get()); + } + + const std::string method{ + sourcemeta::core::http_method_string(request.method)}; + if (request.method == sourcemeta::core::HTTPMethod::HEAD) { + curl_easy_setopt(handle.get(), CURLOPT_NOBODY, 1L); + } else if (request.method != sourcemeta::core::HTTPMethod::GET || + request.body.has_value()) { + curl_easy_setopt(handle.get(), CURLOPT_CUSTOMREQUEST, method.c_str()); + } + + const auto code{curl_easy_perform(handle.get())}; + if (code != CURLE_OK) { + if (body_context.maximum_size_exceeded) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + std::string{HTTP_RESPONSE_TOO_LARGE_MESSAGE}}; + } + + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + curl_easy_strerror(code)}; + } + + long status_code{0}; + curl_easy_getinfo(handle.get(), CURLINFO_RESPONSE_CODE, &status_code); + sourcemeta::core::http_parse_headers(raw_headers, response.headers); + response.status = sourcemeta::core::http_status_from_code( + static_cast(status_code)); + return response; +} + +} // namespace sourcemeta::jsonschema diff --git a/src/http/http_darwin.mm b/src/http/http_darwin.mm new file mode 100644 index 000000000..43d639498 --- /dev/null +++ b/src/http/http_darwin.mm @@ -0,0 +1,150 @@ +#include "http.h" + +// NSURL, NSMutableURLRequest, NSURLSession, NSHTTPURLResponse, dispatch_* +#import + +#include + +#include // std::size_t +#include // std::uint16_t +#include // std::string +#include // std::string_view +#include // std::move + +namespace { + +auto to_nsstring(const std::string_view input) -> NSString * { + return [[NSString alloc] initWithBytes:input.data() + length:input.size() + encoding:NSUTF8StringEncoding]; +} + +} // namespace + +// The delegate-based API streams the response body in chunks, allowing +// the maximum response size to be enforced without first buffering the +// entire response in memory +@interface SourcemetaJSONSchemaHTTPDelegate + : NSObject +@property(nonatomic, assign) sourcemeta::jsonschema::HTTPResponse *response; +@property(nonatomic, assign) std::string *failure; +@property(nonatomic, strong) dispatch_semaphore_t semaphore; +@property(nonatomic, assign) BOOL hasMaximumResponseSize; +@property(nonatomic, assign) std::size_t maximumResponseSize; +@end + +@implementation SourcemetaJSONSchemaHTTPDelegate + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + auto *body{&self.response->body}; + if (self.hasMaximumResponseSize && + body->size() + data.length > self.maximumResponseSize) { + self.failure->assign( + sourcemeta::jsonschema::HTTP_RESPONSE_TOO_LARGE_MESSAGE); + [dataTask cancel]; + return; + } + + [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange range, + BOOL *) { + body->append(static_cast(bytes), range.length); + }]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + // A failure recorded while streaming, such as exceeding the maximum + // response size, takes precedence over the resulting cancellation error + if (self.failure->empty()) { + if (error != nil) { + self.failure->assign([error.localizedDescription UTF8String]); + } else if (![task.response isKindOfClass:[NSHTTPURLResponse class]]) { + self.failure->assign("The response is not an HTTP response"); + } else { + const auto *http_response{(NSHTTPURLResponse *)task.response}; + self.response->status = sourcemeta::core::http_status_from_code( + static_cast(http_response.statusCode)); + auto *headers{&self.response->headers}; + [http_response.allHeaderFields + enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, + BOOL *) { + std::string header_name{[name UTF8String]}; + sourcemeta::core::to_lowercase(header_name); + headers->emplace_back(std::move(header_name), [value UTF8String]); + }]; + } + } + + dispatch_semaphore_signal(self.semaphore); +} + +@end + +namespace sourcemeta::jsonschema { + +auto http_request(const HTTPRequest &request) -> HTTPResponse { + HTTPResponse response; + // The delegate runs on a background queue, where throwing would + // terminate the process, so failures are recorded here and thrown + // from the calling thread once the request settles + std::string failure; + + @autoreleasepool { + NSURL *target{[NSURL URLWithString:to_nsstring(request.url)]}; + if (target == nil) { + failure = "Invalid URL"; + } else { + NSMutableURLRequest *url_request{ + [NSMutableURLRequest requestWithURL:target]}; + url_request.HTTPMethod = + to_nsstring(sourcemeta::core::http_method_string(request.method)); + for (const auto &[name, value] : request.headers) { + // Repeated headers are folded into a single comma-separated field + // line, which is semantically equivalent per RFC 9110 + [url_request addValue:to_nsstring(value) + forHTTPHeaderField:to_nsstring(name)]; + } + + if (request.body.has_value()) { + [url_request setValue:to_nsstring(request.body.value().content_type) + forHTTPHeaderField:@"Content-Type"]; + url_request.HTTPBody = + [NSData dataWithBytes:request.body.value().data.data() + length:request.body.value().data.size()]; + } + + // The delegate completes before the semaphore is signalled, so + // pointing to the stack-allocated locals from it is safe + SourcemetaJSONSchemaHTTPDelegate *delegate{ + [[SourcemetaJSONSchemaHTTPDelegate alloc] init]}; + delegate.response = &response; + delegate.failure = &failure; + delegate.semaphore = dispatch_semaphore_create(0); + delegate.hasMaximumResponseSize = + request.maximum_response_size.has_value() ? YES : NO; + delegate.maximumResponseSize = request.maximum_response_size.value_or(0); + + NSURLSession *session{[NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration + ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]}; + NSURLSessionDataTask *task{[session dataTaskWithRequest:url_request]}; + [task resume]; + dispatch_semaphore_wait(delegate.semaphore, DISPATCH_TIME_FOREVER); + [session finishTasksAndInvalidate]; + } + } + + if (!failure.empty()) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + failure}; + } + + return response; +} + +} // namespace sourcemeta::jsonschema diff --git a/src/http/http_windows.cc b/src/http/http_windows.cc new file mode 100644 index 000000000..586f61747 --- /dev/null +++ b/src/http/http_windows.cc @@ -0,0 +1,220 @@ +#include "http.h" + +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include // DWORD, GetLastError, LPVOID +#include // WinHttp* + +// `windows.h` defines a `DELETE` macro that conflicts with +// `sourcemeta::core::HTTPMethod::DELETE` +#ifdef DELETE +#undef DELETE +#endif + +#include + +#include // std::uint16_t +#include // std::numeric_limits +#include // std::string +#include // std::wstring_view +#include // std::pair +#include // std::vector + +namespace { + +class WinHTTPHandle { +public: + WinHTTPHandle(const HINTERNET handle) : handle_{handle} {} + ~WinHTTPHandle() { + if (this->handle_) { + WinHttpCloseHandle(this->handle_); + } + } + + WinHTTPHandle(const WinHTTPHandle &) = delete; + auto operator=(const WinHTTPHandle &) -> WinHTTPHandle & = delete; + WinHTTPHandle(WinHTTPHandle &&) = delete; + auto operator=(WinHTTPHandle &&) -> WinHTTPHandle & = delete; + + auto get() const -> HINTERNET { return this->handle_; } + explicit operator bool() const { return this->handle_ != nullptr; } + +private: + HINTERNET handle_; +}; + +auto parse_response_headers( + const HINTERNET request, + std::vector> &headers) -> void { + DWORD size{0}; + WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, WINHTTP_NO_OUTPUT_BUFFER, + &size, WINHTTP_NO_HEADER_INDEX); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return; + } + + std::wstring buffer(size / sizeof(wchar_t), L'\0'); + if (!WinHttpQueryHeaders(request, WINHTTP_QUERY_RAW_HEADERS_CRLF, + WINHTTP_HEADER_NAME_BY_INDEX, buffer.data(), &size, + WINHTTP_NO_HEADER_INDEX)) { + return; + } + + sourcemeta::core::http_parse_headers(sourcemeta::core::wide_to_utf8(buffer), + headers); +} + +} // namespace + +namespace sourcemeta::jsonschema { + +auto http_request(const HTTPRequest &request) -> HTTPResponse { + HTTPResponse response; + + const auto wide_url{sourcemeta::core::utf8_to_wide(request.url)}; + URL_COMPONENTS components{}; + components.dwStructSize = sizeof(components); + components.dwHostNameLength = static_cast(-1); + components.dwUrlPathLength = static_cast(-1); + components.dwExtraInfoLength = static_cast(-1); + if (!WinHttpCrackUrl(wide_url.c_str(), 0, 0, &components)) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Invalid URL"}; + } + + const std::wstring host{components.lpszHostName, components.dwHostNameLength}; + std::wstring path{components.lpszUrlPath, components.dwUrlPathLength}; + if (components.lpszExtraInfo) { + // The fragment, if any, must never be sent to the server + const std::wstring_view extra_information{components.lpszExtraInfo, + components.dwExtraInfoLength}; + path.append(extra_information.substr(0, extra_information.find(L'#'))); + } + + const WinHTTPHandle session{ + WinHttpOpen(nullptr, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0)}; + if (!session) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to initialise the HTTP client"}; + } + + const WinHTTPHandle connection{ + WinHttpConnect(session.get(), host.c_str(), components.nPort, 0)}; + if (!connection) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to connect to the host"}; + } + + const auto secure{components.nScheme == INTERNET_SCHEME_HTTPS}; + const auto method{sourcemeta::core::utf8_to_wide( + sourcemeta::core::http_method_string(request.method))}; + const WinHTTPHandle request_handle{WinHttpOpenRequest( + connection.get(), method.c_str(), path.c_str(), nullptr, + WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, + secure ? WINHTTP_FLAG_SECURE : 0)}; + if (!request_handle) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to create the HTTP request"}; + } + + DWORD decompression{WINHTTP_DECOMPRESSION_FLAG_ALL}; + WinHttpSetOption(request_handle.get(), WINHTTP_OPTION_DECOMPRESSION, + &decompression, sizeof(decompression)); + + auto serialized_headers{ + sourcemeta::core::http_serialize_headers(request.headers)}; + LPVOID body_data{WINHTTP_NO_REQUEST_DATA}; + DWORD body_size{0}; + if (request.body.has_value()) { + if (request.body.value().data.size() > std::numeric_limits::max()) { + throw sourcemeta::core::HTTPError{request.method, + std::string{request.url}, + "The request body is too large"}; + } + + serialized_headers += "Content-Type: "; + serialized_headers += request.body.value().content_type; + serialized_headers += "\r\n"; + body_data = const_cast(request.body.value().data.data()); + body_size = static_cast(request.body.value().data.size()); + } + + const auto request_headers{ + sourcemeta::core::utf8_to_wide(serialized_headers)}; + + if (!WinHttpSendRequest( + request_handle.get(), + request_headers.empty() ? WINHTTP_NO_ADDITIONAL_HEADERS + : request_headers.c_str(), + request_headers.empty() ? 0 + : static_cast(request_headers.size()), + body_data, body_size, body_size, 0)) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to send the HTTP request"}; + } + + if (!WinHttpReceiveResponse(request_handle.get(), nullptr)) { + throw sourcemeta::core::HTTPError{request.method, std::string{request.url}, + "Failed to receive the HTTP response"}; + } + + DWORD status_code{0}; + DWORD status_code_size{sizeof(status_code)}; + if (!WinHttpQueryHeaders(request_handle.get(), + WINHTTP_QUERY_STATUS_CODE | + WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, &status_code, + &status_code_size, WINHTTP_NO_HEADER_INDEX)) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + "Failed to read the HTTP response status"}; + } + + parse_response_headers(request_handle.get(), response.headers); + + while (true) { + DWORD available{0}; + if (!WinHttpQueryDataAvailable(request_handle.get(), &available)) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + "Failed to read the HTTP response body"}; + } + + if (available == 0) { + break; + } + + if (request.maximum_response_size.has_value() && + response.body.size() + available > + request.maximum_response_size.value()) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + std::string{HTTP_RESPONSE_TOO_LARGE_MESSAGE}}; + } + + const auto offset{response.body.size()}; + response.body.resize(offset + available); + DWORD read{0}; + if (!WinHttpReadData(request_handle.get(), response.body.data() + offset, + available, &read)) { + throw sourcemeta::core::HTTPError{ + request.method, std::string{request.url}, + "Failed to read the HTTP response body"}; + } + + response.body.resize(offset + read); + } + + response.status = sourcemeta::core::http_status_from_code( + static_cast(status_code)); + return response; +} + +} // namespace sourcemeta::jsonschema diff --git a/src/resolver.h b/src/resolver.h index 8065c20d1..46ddd1658 100644 --- a/src/resolver.h +++ b/src/resolver.h @@ -1,22 +1,10 @@ #ifndef SOURCEMETA_JSONSCHEMA_CLI_RESOLVER_H_ #define SOURCEMETA_JSONSCHEMA_CLI_RESOLVER_H_ -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnewline-eof" -#endif -#include -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - #include #include #include +#include #include #include #include @@ -24,6 +12,7 @@ #include #include "error.h" +#include "http.h" #include "input.h" #include "logger.h" #include "utils.h" @@ -36,12 +25,11 @@ #include // std::cerr #include // std::map #include // std::optional -#include // std::ostringstream -#include // std::runtime_error #include // std::string #include // std::string_view #include // std::this_thread::sleep_for #include // std::pair, std::piecewise_construct, std::forward_as_tuple +#include // std::vector namespace sourcemeta::jsonschema { @@ -76,7 +64,7 @@ static constexpr std::string_view HTTP_HEADER_EXAMPLE{ "--header \"Authorization: Bearer ${TOKEN}\""}; static inline auto parse_http_header(const std::string_view input) - -> std::pair { + -> std::pair { const auto colon{input.find(':')}; if (colon == std::string_view::npos) { throw PositionalArgumentError{ @@ -118,7 +106,7 @@ static inline auto parse_http_header(const std::string_view input) } } - return {std::string{raw_name}, std::string{raw_value}}; + return {raw_name, raw_value}; } static inline auto @@ -132,14 +120,14 @@ validate_http_headers(const sourcemeta::core::Options &options) -> void { } static inline auto -collect_http_headers(const sourcemeta::core::Options &options) -> cpr::Header { - cpr::Header headers; +collect_http_headers(const sourcemeta::core::Options &options) + -> std::vector> { + std::vector> headers; if (!options.contains("header")) { return headers; } for (const auto &raw : options.at("header")) { - auto [name, value]{parse_http_header(raw)}; - headers[std::move(name)] = std::move(value); + headers.emplace_back(parse_http_header(raw)); } return headers; } @@ -147,39 +135,54 @@ collect_http_headers(const sourcemeta::core::Options &options) -> cpr::Header { static inline auto http_fetch(const std::string &url, const sourcemeta::core::Options &options) -> sourcemeta::core::JSON { - const auto headers{collect_http_headers(options)}; - cpr::Response response; + const HTTPRequest request{.method = sourcemeta::core::HTTPMethod::GET, + .url = url, + .headers = collect_http_headers(options), + .body = std::nullopt, + .maximum_response_size = std::nullopt}; + HTTPResponse response; for (std::uint8_t attempt{1}; attempt <= HTTP_MAXIMUM_RETRIES; ++attempt) { LOG_VERBOSE(options) << "Resolving over HTTP (attempt " << static_cast(attempt) << "/" << static_cast(HTTP_MAXIMUM_RETRIES) << "): " << url << "\n"; - response = cpr::Get(cpr::Url{url}, cpr::Redirect{true}, headers); + try { + response = http_request(request); + } catch (const sourcemeta::core::HTTPError &error) { + if (attempt == HTTP_MAXIMUM_RETRIES) { + throw; + } + + LOG_VERBOSE(options) << "Request failed (" << error.what() + << "), retrying...\n"; + std::this_thread::sleep_for(std::chrono::seconds(1)); + continue; + } - if (response.status_code == 200) { + if (response.status == sourcemeta::core::HTTP_STATUS_OK) { break; } if (attempt < HTTP_MAXIMUM_RETRIES) { LOG_VERBOSE(options) << "Request failed with HTTP " - << response.status_code << ", retrying...\n"; + << response.status.code << ", retrying...\n"; std::this_thread::sleep_for(std::chrono::seconds(1)); } } - if (response.status_code != 200) { - std::ostringstream error; - error << "HTTP " << response.status_code << "\n at " << url; - throw std::runtime_error(error.str()); + if (response.status != sourcemeta::core::HTTP_STATUS_OK) { + throw sourcemeta::core::HTTPStatusError{request.method, url, + response.status}; } - const auto content_type_iterator{response.header.find("content-type")}; - if (content_type_iterator != response.header.end() && - content_type_iterator->second.starts_with("text/yaml")) { - return sourcemeta::core::parse_yaml(response.text); + const auto content_type{ + sourcemeta::core::http_header_find(response.headers, "content-type")}; + if (content_type.has_value() && sourcemeta::core::http_content_type_matches( + content_type.value(), "text/yaml")) { + return sourcemeta::core::parse_yaml(response.body); } - return sourcemeta::core::parse_json(response.text); + return sourcemeta::core::parse_json(response.body); } static inline auto fetch_schema(const sourcemeta::core::Options &options, diff --git a/vendor/core/config.cmake.in b/vendor/core/config.cmake.in index e6a48152e..31e34d56f 100644 --- a/vendor/core/config.cmake.in +++ b/vendor/core/config.cmake.in @@ -157,6 +157,7 @@ foreach(component ${SOURCEMETA_CORE_COMPONENTS}) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_numeric.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_io.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_unicode.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_text.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_json.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_time.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_core_http.cmake") diff --git a/vendor/core/src/core/http/CMakeLists.txt b/vendor/core/src/core/http/CMakeLists.txt index 60034a76c..8203b1cef 100644 --- a/vendor/core/src/core/http/CMakeLists.txt +++ b/vendor/core/src/core/http/CMakeLists.txt @@ -1,5 +1,5 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME http - PRIVATE_HEADERS problem.h status.h + PRIVATE_HEADERS problem.h status.h method.h message.h error.h SOURCES helpers.h problem.cc match_accept.cc match_accept_language.cc negotiate_encoding.cc from_date.cc format_link.cc field_list.cc accept_includes_all.cc content_type_matches.cc) @@ -9,4 +9,5 @@ if(SOURCEMETA_CORE_INSTALL) endif() target_link_libraries(sourcemeta_core_http PUBLIC sourcemeta::core::json) +target_link_libraries(sourcemeta_core_http PUBLIC sourcemeta::core::text) target_link_libraries(sourcemeta_core_http PRIVATE sourcemeta::core::time) diff --git a/vendor/core/src/core/http/include/sourcemeta/core/http.h b/vendor/core/src/core/http/include/sourcemeta/core/http.h index deb428740..53c22d1cf 100644 --- a/vendor/core/src/core/http/include/sourcemeta/core/http.h +++ b/vendor/core/src/core/http/include/sourcemeta/core/http.h @@ -6,6 +6,9 @@ #endif // NOLINTBEGIN(misc-include-cleaner) +#include +#include +#include #include #include // NOLINTEND(misc-include-cleaner) diff --git a/vendor/core/src/core/http/include/sourcemeta/core/http_error.h b/vendor/core/src/core/http/include/sourcemeta/core/http_error.h new file mode 100644 index 000000000..45975ee01 --- /dev/null +++ b/vendor/core/src/core/http/include/sourcemeta/core/http_error.h @@ -0,0 +1,98 @@ +#ifndef SOURCEMETA_CORE_HTTP_ERROR_H_ +#define SOURCEMETA_CORE_HTTP_ERROR_H_ + +#ifndef SOURCEMETA_CORE_HTTP_EXPORT +#include +#endif + +#include +#include + +#include // std::uint16_t +#include // std::runtime_error +#include // std::string +#include // std::move + +namespace sourcemeta::core { + +// Exporting symbols that depends on the standard C++ library is considered +// safe. +// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN +#if defined(_MSC_VER) +#pragma warning(disable : 4251 4275) +#endif + +/// @ingroup http +/// An error that prevented obtaining a response, such as a connection +/// failure, a name resolution failure, or a TLS failure. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// const sourcemeta::core::HTTPError error{ +/// sourcemeta::core::HTTPMethod::GET, +/// "https://example.com", "Connection refused"}; +/// assert(error.method() == sourcemeta::core::HTTPMethod::GET); +/// assert(error.url() == "https://example.com"); +/// ``` +class SOURCEMETA_CORE_HTTP_EXPORT HTTPError : public std::runtime_error { +public: + HTTPError(const HTTPMethod method, std::string url, + const std::string &message) + : std::runtime_error{message}, method_{method}, url_{std::move(url)} {} + + /// Get the request method that triggered the failure + [[nodiscard]] auto method() const noexcept -> HTTPMethod { + return this->method_; + } + + /// Get the request URL that triggered the failure + [[nodiscard]] auto url() const noexcept -> const std::string & { + return this->url_; + } + +private: + HTTPMethod method_; + std::string url_; +}; + +/// @ingroup http +/// An error for a response with an unsuccessful status code, owning a copy +/// of the status data. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// const sourcemeta::core::HTTPStatusError error{ +/// sourcemeta::core::HTTPMethod::GET, +/// "https://example.com", sourcemeta::core::HTTP_STATUS_NOT_FOUND}; +/// assert(error.status() == sourcemeta::core::HTTP_STATUS_NOT_FOUND); +/// ``` +class SOURCEMETA_CORE_HTTP_EXPORT HTTPStatusError : public HTTPError { +public: + HTTPStatusError(const HTTPMethod method, std::string url, + const HTTPStatus &status) + : HTTPError{method, std::move(url), "Unsuccessful HTTP response"}, + code_{status.code}, phrase_{status.phrase}, wire_{status.wire} {} + + /// Get the response status that triggered the failure. The contained + /// views borrow from this error and stay valid for its lifetime + [[nodiscard]] auto status() const noexcept -> HTTPStatus { + return {.code = this->code_, .phrase = this->phrase_, .wire = this->wire_}; + } + +private: + std::uint16_t code_; + std::string phrase_; + std::string wire_; +}; + +#if defined(_MSC_VER) +#pragma warning(default : 4251 4275) +#endif + +} // namespace sourcemeta::core + +#endif diff --git a/vendor/core/src/core/http/include/sourcemeta/core/http_message.h b/vendor/core/src/core/http/include/sourcemeta/core/http_message.h new file mode 100644 index 000000000..29f8763a8 --- /dev/null +++ b/vendor/core/src/core/http/include/sourcemeta/core/http_message.h @@ -0,0 +1,280 @@ +#ifndef SOURCEMETA_CORE_HTTP_MESSAGE_H_ +#define SOURCEMETA_CORE_HTTP_MESSAGE_H_ + +#include + +#include // std::convertible_to, std::invocable +#include // std::size_t +#include // std::nullopt, std::optional +#include // std::string +#include // std::string_view +#include // std::move + +namespace sourcemeta::core { + +/// @ingroup http +/// Test whether a raw line opens a message header block per RFC 9112 §4. +/// For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::http_is_status_line("HTTP/1.1 200 OK")); +/// assert(!sourcemeta::core::http_is_status_line("Content-Type: text/html")); +/// ``` +inline constexpr auto http_is_status_line(const std::string_view line) noexcept + -> bool { + // The prefix cannot open a field line, as RFC 9110 §5.6.2 defines tchar + // as "any VCHAR, except delimiters" where delimiters include the slash, + // and the protocol name is case-sensitive per RFC 9112 §2.3 + return line.starts_with("HTTP/"); +} + +/// @ingroup http +/// Accumulate raw header lines into a buffer, retaining only the block of +/// the most recent message, given that transparently following redirects or +/// receiving interim responses produces one header block per message. For +/// example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// +/// std::string buffer; +/// sourcemeta::core::http_accumulate_header_line(buffer, +/// "HTTP/1.1 301 Moved Permanently\r\n"); +/// sourcemeta::core::http_accumulate_header_line(buffer, +/// "HTTP/1.1 200 OK\r\n"); +/// assert(buffer == "HTTP/1.1 200 OK\r\n"); +/// ``` +template + requires requires(Buffer buffer, std::string_view line) { + buffer.clear(); + buffer.append(line); + } +inline auto http_accumulate_header_line(Buffer &buffer, + const std::string_view line) -> void { + if (http_is_status_line(line)) { + buffer.clear(); + } + + buffer.append(line); +} + +/// @ingroup http +/// Parse the field lines of a raw message header block per RFC 9112 §5, +/// skipping the start line and invoking the callback with each raw field +/// name and its value with optional whitespace excluded. A continuation of +/// the previous value through deprecated line folding is reported with an +/// empty name. Malformed field lines are discarded. Neither argument +/// allocates, as both are views into the input. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// +/// sourcemeta::core::http_parse_headers( +/// "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n", +/// [](const std::string_view name, const std::string_view value) { +/// assert(name == "Server"); +/// assert(value == "test"); +/// }); +/// ``` +template + requires std::invocable +inline auto http_parse_headers(const std::string_view input, Callback callback) + -> void { + std::size_t cursor{input.find("\r\n")}; + while (cursor != std::string_view::npos) { + cursor += 2; + const auto end{input.find("\r\n", cursor)}; + if (end == std::string_view::npos || end == cursor) { + break; + } + + auto line{input.substr(cursor, end - cursor)}; + cursor = end; + + // RFC 9112 §5.2 deprecates obs-fold, defined as "OWS CRLF RWS", and + // mandates that a user agent "MUST replace each received obs-fold + // with one or more SP octets prior to interpreting the field value", + // so a line opening with whitespace continues the previous field + // line value and is reported with an empty name for the caller to join + if (line.front() == ' ' || line.front() == '\t') { + while (!line.empty() && (line.front() == ' ' || line.front() == '\t')) { + line.remove_prefix(1); + } + + while (!line.empty() && (line.back() == ' ' || line.back() == '\t')) { + line.remove_suffix(1); + } + + callback(std::string_view{}, line); + continue; + } + + const auto parts{split_once(line, ':')}; + if (!parts.has_value() || parts->first.empty()) { + continue; + } + + const auto name{parts->first}; + // RFC 9112 §5.1 mandates that "no whitespace is allowed between the + // field name and colon" because in the past such whitespace has "led + // to security vulnerabilities", so the field line is discarded + if (name.back() == ' ' || name.back() == '\t') { + continue; + } + + auto value{parts->second}; + // RFC 9112 §5 defines a field line as + // `field-name ":" OWS field-value OWS` where RFC 9110 §5.6.3 defines + // optional whitespace as `*( SP / HTAB )` + while (!value.empty() && (value.front() == ' ' || value.front() == '\t')) { + value.remove_prefix(1); + } + + while (!value.empty() && (value.back() == ' ' || value.back() == '\t')) { + value.remove_suffix(1); + } + + callback(name, value); + } +} + +/// @ingroup http +/// Parse the field lines of a raw message header block, skipping the start +/// line, into any container of name and value pairs, normalising names to +/// lowercase given that RFC 9110 §5.1 mandates that "field names are +/// case-insensitive", preserving repeated fields as separate entries, and +/// joining deprecated line folding per RFC 9112 §5.2. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// #include +/// +/// std::vector> headers; +/// sourcemeta::core::http_parse_headers( +/// "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n", headers); +/// assert(headers.size() == 1); +/// assert(headers.at(0).first == "server"); +/// assert(headers.at(0).second == "test"); +/// ``` +template + requires requires(Container container, std::string name, std::string value, + const char character) { + container.emplace_back(std::move(name), std::move(value)); + { container.empty() } -> std::convertible_to; + container.back().second += character; + } +inline auto http_parse_headers(const std::string_view input, Container &headers) + -> void { + http_parse_headers(input, [&headers](const std::string_view name, + const std::string_view value) { + if (name.empty()) { + // RFC 9112 §5.2 mandates replacing "each received obs-fold with + // one or more SP octets prior to interpreting the field value" + if (!headers.empty()) { + auto &previous_value{headers.back().second}; + previous_value += ' '; + previous_value += value; + } + + return; + } + + std::string header_name{name}; + to_lowercase(header_name); + headers.emplace_back(std::move(header_name), std::string{value}); + }); +} + +/// @ingroup http +/// Serialise headers, given as any range of name and value pairs, into +/// CRLF-delimited field lines per RFC 9112 §5. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// #include +/// +/// const std::vector> headers{ +/// {"Accept", "application/json"}}; +/// assert(sourcemeta::core::http_serialize_headers(headers) == +/// "Accept: application/json\r\n"); +/// ``` +template +inline auto http_serialize_headers(const Headers &headers) -> std::string { + std::size_t total_size{0}; + for (const auto &[name, value] : headers) { + // Account for the colon, the space, and the trailing CRLF + total_size += name.size() + value.size() + 4; + } + + std::string result; + result.reserve(total_size); + for (const auto &[name, value] : headers) { + // RFC 9112 §5.1 notes that "a single SP preceding the field line + // value is preferred for consistent readability by humans" + result += name; + result += ": "; + result += value; + result += "\r\n"; + } + + return result; +} + +/// @ingroup http +/// Find the value of the first header with the given lowercase name in any +/// range of name and value pairs, returning no result when absent. For +/// example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// #include +/// +/// const std::vector> headers{ +/// {"server", "test"}}; +/// assert(sourcemeta::core::http_header_find(headers, "server").has_value()); +/// assert(!sourcemeta::core::http_header_find(headers, "date").has_value()); +/// ``` +template +inline auto http_header_find(const Headers &headers, + const std::string_view name) + -> std::optional { + // Prefer the container's own lookup when it supports searching by the + // given name without converting it, as associative containers do it in + // logarithmic or constant time instead of a linear scan + if constexpr (requires { headers.find(name) != headers.end(); }) { + const auto match{headers.find(name)}; + if (match != headers.end()) { + return std::string_view{match->second}; + } + + return std::nullopt; + } else { + for (const auto &[header_name, header_value] : headers) { + if (header_name == name) { + return std::string_view{header_value}; + } + } + + return std::nullopt; + } +} + +} // namespace sourcemeta::core + +#endif diff --git a/vendor/core/src/core/http/include/sourcemeta/core/http_method.h b/vendor/core/src/core/http/include/sourcemeta/core/http_method.h new file mode 100644 index 000000000..767a1c11c --- /dev/null +++ b/vendor/core/src/core/http/include/sourcemeta/core/http_method.h @@ -0,0 +1,63 @@ +#ifndef SOURCEMETA_CORE_HTTP_METHOD_H_ +#define SOURCEMETA_CORE_HTTP_METHOD_H_ + +#include // std::uint8_t +#include // std::string_view +#include // std::unreachable + +namespace sourcemeta::core { + +/// @ingroup http +/// A request method per RFC 9110 §9.3 and RFC 5789 §2. +enum class HTTPMethod : std::uint8_t { + GET, + HEAD, + POST, + PUT, + DELETE, + CONNECT, + OPTIONS, + TRACE, + PATCH +}; + +/// @ingroup http +/// Convert a request method into its case-sensitive token per RFC 9110 §9.1. +/// For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::http_method_string( +/// sourcemeta::core::HTTPMethod::GET) == "GET"); +/// ``` +inline constexpr auto http_method_string(const HTTPMethod method) noexcept + -> std::string_view { + switch (method) { + case HTTPMethod::GET: + return "GET"; + case HTTPMethod::HEAD: + return "HEAD"; + case HTTPMethod::POST: + return "POST"; + case HTTPMethod::PUT: + return "PUT"; + case HTTPMethod::DELETE: + return "DELETE"; + case HTTPMethod::CONNECT: + return "CONNECT"; + case HTTPMethod::OPTIONS: + return "OPTIONS"; + case HTTPMethod::TRACE: + return "TRACE"; + case HTTPMethod::PATCH: + return "PATCH"; + } + + std::unreachable(); +} + +} // namespace sourcemeta::core + +#endif diff --git a/vendor/core/src/core/http/include/sourcemeta/core/http_status.h b/vendor/core/src/core/http/include/sourcemeta/core/http_status.h index 3a82995c4..c95c6235e 100644 --- a/vendor/core/src/core/http/include/sourcemeta/core/http_status.h +++ b/vendor/core/src/core/http/include/sourcemeta/core/http_status.h @@ -10,7 +10,7 @@ namespace sourcemeta::core { /// A typed HTTP status code per RFC 9110 §15. For example: /// /// ```cpp -/// #include +/// #include /// #include /// /// assert(sourcemeta::core::HTTP_STATUS_OK.code == 200); @@ -386,6 +386,150 @@ inline constexpr HTTPStatus HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED{ .phrase = "Network Authentication Required", .wire = "511 Network Authentication Required"}; +/// @ingroup http +/// Resolve a numeric status code into its registered status, with unknown +/// codes resolving to an empty reason phrase. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::http_status_from_code(200) == +/// sourcemeta::core::HTTP_STATUS_OK); +/// assert(sourcemeta::core::http_status_from_code(599).phrase.empty()); +/// ``` +inline constexpr auto http_status_from_code(const std::uint16_t code) noexcept + -> HTTPStatus { + switch (code) { + case 100: + return HTTP_STATUS_CONTINUE; + case 101: + return HTTP_STATUS_SWITCHING_PROTOCOLS; + case 102: + return HTTP_STATUS_PROCESSING; + case 103: + return HTTP_STATUS_EARLY_HINTS; + case 200: + return HTTP_STATUS_OK; + case 201: + return HTTP_STATUS_CREATED; + case 202: + return HTTP_STATUS_ACCEPTED; + case 203: + return HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION; + case 204: + return HTTP_STATUS_NO_CONTENT; + case 205: + return HTTP_STATUS_RESET_CONTENT; + case 206: + return HTTP_STATUS_PARTIAL_CONTENT; + case 207: + return HTTP_STATUS_MULTI_STATUS; + case 208: + return HTTP_STATUS_ALREADY_REPORTED; + case 226: + return HTTP_STATUS_IM_USED; + case 300: + return HTTP_STATUS_MULTIPLE_CHOICES; + case 301: + return HTTP_STATUS_MOVED_PERMANENTLY; + case 302: + return HTTP_STATUS_FOUND; + case 303: + return HTTP_STATUS_SEE_OTHER; + case 304: + return HTTP_STATUS_NOT_MODIFIED; + case 305: + return HTTP_STATUS_USE_PROXY; + case 307: + return HTTP_STATUS_TEMPORARY_REDIRECT; + case 308: + return HTTP_STATUS_PERMANENT_REDIRECT; + case 400: + return HTTP_STATUS_BAD_REQUEST; + case 401: + return HTTP_STATUS_UNAUTHORIZED; + case 402: + return HTTP_STATUS_PAYMENT_REQUIRED; + case 403: + return HTTP_STATUS_FORBIDDEN; + case 404: + return HTTP_STATUS_NOT_FOUND; + case 405: + return HTTP_STATUS_METHOD_NOT_ALLOWED; + case 406: + return HTTP_STATUS_NOT_ACCEPTABLE; + case 407: + return HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED; + case 408: + return HTTP_STATUS_REQUEST_TIMEOUT; + case 409: + return HTTP_STATUS_CONFLICT; + case 410: + return HTTP_STATUS_GONE; + case 411: + return HTTP_STATUS_LENGTH_REQUIRED; + case 412: + return HTTP_STATUS_PRECONDITION_FAILED; + case 413: + return HTTP_STATUS_CONTENT_TOO_LARGE; + case 414: + return HTTP_STATUS_URI_TOO_LONG; + case 415: + return HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE; + case 416: + return HTTP_STATUS_RANGE_NOT_SATISFIABLE; + case 417: + return HTTP_STATUS_EXPECTATION_FAILED; + case 418: + return HTTP_STATUS_IM_A_TEAPOT; + case 421: + return HTTP_STATUS_MISDIRECTED_REQUEST; + case 422: + return HTTP_STATUS_UNPROCESSABLE_CONTENT; + case 423: + return HTTP_STATUS_LOCKED; + case 424: + return HTTP_STATUS_FAILED_DEPENDENCY; + case 425: + return HTTP_STATUS_TOO_EARLY; + case 426: + return HTTP_STATUS_UPGRADE_REQUIRED; + case 428: + return HTTP_STATUS_PRECONDITION_REQUIRED; + case 429: + return HTTP_STATUS_TOO_MANY_REQUESTS; + case 431: + return HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; + case 451: + return HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS; + case 500: + return HTTP_STATUS_INTERNAL_SERVER_ERROR; + case 501: + return HTTP_STATUS_NOT_IMPLEMENTED; + case 502: + return HTTP_STATUS_BAD_GATEWAY; + case 503: + return HTTP_STATUS_SERVICE_UNAVAILABLE; + case 504: + return HTTP_STATUS_GATEWAY_TIMEOUT; + case 505: + return HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED; + case 506: + return HTTP_STATUS_VARIANT_ALSO_NEGOTIATES; + case 507: + return HTTP_STATUS_INSUFFICIENT_STORAGE; + case 508: + return HTTP_STATUS_LOOP_DETECTED; + case 510: + return HTTP_STATUS_NOT_EXTENDED; + case 511: + return HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED; + default: + return HTTPStatus{.code = code, .phrase = {}, .wire = {}}; + } +} + } // namespace sourcemeta::core #endif diff --git a/vendor/core/src/core/unicode/include/sourcemeta/core/unicode.h b/vendor/core/src/core/unicode/include/sourcemeta/core/unicode.h index e84387f64..a2f4f689c 100644 --- a/vendor/core/src/core/unicode/include/sourcemeta/core/unicode.h +++ b/vendor/core/src/core/unicode/include/sourcemeta/core/unicode.h @@ -12,8 +12,8 @@ #include // std::istream #include // std::optional #include // std::ostream -#include // std::string, std::u32string -#include // std::string_view +#include // std::string, std::u32string, std::wstring +#include // std::string_view, std::wstring_view /// @defgroup unicode Unicode /// @brief Unicode encoding utilities. @@ -106,6 +106,33 @@ SOURCEMETA_CORE_UNICODE_EXPORT auto utf8_to_utf32(const std::string_view input) -> std::optional; +/// @ingroup unicode +/// Convert a UTF-8 string into its wide character form without validation. +/// The input must be valid UTF-8, otherwise the result is undefined. +/// For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::utf8_to_wide("hello") == L"hello"); +/// ``` +SOURCEMETA_CORE_UNICODE_EXPORT +auto utf8_to_wide(const std::string_view input) -> std::wstring; + +/// @ingroup unicode +/// Convert a wide string into its UTF-8 form without validation. The input +/// must be valid, otherwise the result is undefined. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::wide_to_utf8(L"hello") == "hello"); +/// ``` +SOURCEMETA_CORE_UNICODE_EXPORT +auto wide_to_utf8(const std::wstring_view input) -> std::string; + /// @ingroup unicode /// Determine the byte length encoded by a UTF-8 lead byte. Returns 1 for an /// ASCII byte (%x00-7F), 2 for a 2-byte lead (%xC2-DF), 3 for a 3-byte lead diff --git a/vendor/core/src/core/unicode/unicode.cc b/vendor/core/src/core/unicode/unicode.cc index f3d9463ac..0cba16c1c 100644 --- a/vendor/core/src/core/unicode/unicode.cc +++ b/vendor/core/src/core/unicode/unicode.cc @@ -1,10 +1,19 @@ #include -#include // std::array -#include // assert -#include // std::size_t -#include // std::uint8_t -#include // std::optional, std::nullopt +#include // std::array +#include // assert +#include // std::size_t +#include // std::uint8_t +#include // std::optional, std::nullopt +#include // std::string, std::wstring +#include // std::string_view, std::wstring_view + +#if defined(_WIN32) || defined(__CYGWIN__) +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include // std::numeric_limits +#include // MultiByteToWideChar, WideCharToMultiByte, CP_UTF8 +#endif #include "unicode_data.h" @@ -166,6 +175,92 @@ auto utf8_to_utf32(const std::string_view input) return result; } +auto utf8_to_wide(const std::string_view input) -> std::wstring { + if (input.empty()) { + return L""; + } + +#if defined(_WIN32) || defined(__CYGWIN__) + assert(input.size() <= + static_cast(std::numeric_limits::max())); + const auto size{MultiByteToWideChar( + CP_UTF8, 0, input.data(), static_cast(input.size()), nullptr, 0)}; + std::wstring result(static_cast(size), L'\0'); + MultiByteToWideChar(CP_UTF8, 0, input.data(), static_cast(input.size()), + result.data(), size); + return result; +#else + // Outside of Windows, a wide character holds an entire codepoint, so the + // result never has more characters than the input has bytes + static_assert(sizeof(wchar_t) >= 4, + "a wide character must hold an entire codepoint"); + std::wstring result(input.size(), L'\0'); + std::size_t write{0}; + std::size_t read{0}; + while (read < input.size()) { + const auto lead{static_cast(input[read])}; + if (lead < 0x80) { + result[write++] = static_cast(lead); + read += 1; + } else if (lead < 0xE0) { + result[write++] = static_cast( + ((lead & 0x1FU) << 6U) | + (static_cast(input[read + 1]) & 0x3FU)); + read += 2; + } else if (lead < 0xF0) { + result[write++] = static_cast( + ((lead & 0x0FU) << 12U) | + ((static_cast(input[read + 1]) & 0x3FU) << 6U) | + (static_cast(input[read + 2]) & 0x3FU)); + read += 3; + } else { + result[write++] = static_cast( + ((lead & 0x07U) << 18U) | + ((static_cast(input[read + 1]) & 0x3FU) << 12U) | + ((static_cast(input[read + 2]) & 0x3FU) << 6U) | + (static_cast(input[read + 3]) & 0x3FU)); + read += 4; + } + } + + result.resize(write); + return result; +#endif +} + +auto wide_to_utf8(const std::wstring_view input) -> std::string { + if (input.empty()) { + return ""; + } + +#if defined(_WIN32) || defined(__CYGWIN__) + assert(input.size() <= + static_cast(std::numeric_limits::max())); + const auto size{WideCharToMultiByte(CP_UTF8, 0, input.data(), + static_cast(input.size()), nullptr, + 0, nullptr, nullptr)}; + std::string result(static_cast(size), '\0'); + WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), + result.data(), size, nullptr, nullptr); + return result; +#else + static_assert(sizeof(wchar_t) >= 4, + "a wide character must hold an entire codepoint"); + std::size_t size{0}; + for (const auto character : input) { + size += utf8_codepoint_byte_count(static_cast(character)); + } + + std::string result; + result.reserve(size); + for (const auto character : input) { + codepoint_to_utf8(static_cast(character), result); + } + + return result; +#endif +} + auto combining_class(const char32_t codepoint) noexcept -> std::uint8_t { if (codepoint > 0x10FFFF) { return 0; diff --git a/vendor/cpr.mask b/vendor/cpr.mask deleted file mode 100644 index 526021f1a..000000000 --- a/vendor/cpr.mask +++ /dev/null @@ -1,27 +0,0 @@ -.clang-format -.clang-tidy -.vscode -CMakeLists.txt -CODE_OF_CONDUCT.md -CONTRIBUTING.md -cppcheck-suppressions.xml -cmake/clang-tidy.cmake -cmake/clear_variable.cmake -cmake/code_coverage.cmake -cmake/cppcheck.cmake -cmake/cprConfig.cmake.in -cmake/cprConfig-ssl.cmake.in -cmake/FindMbedTLS.cmake -cmake/libpsl.cmake -cmake/mongoose.CMakeLists.txt -cmake/sanitizer.cmake -cmake/std_fs_support_test.cpp -cmake/zlib_external.cmake -cpr/CMakeLists.txt -cpr-config.cmake -include/CMakeLists.txt -nuget -package-build -README.md -scripts -test diff --git a/vendor/cpr/LICENSE b/vendor/cpr/LICENSE deleted file mode 100644 index c63edeb39..000000000 --- a/vendor/cpr/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -This license applies to everything except the contents of the "test" -directory and its subdirectories. - -MIT License - -Copyright (c) 2017-2021 Huu Nguyen -Copyright (c) 2022 libcpr and many other contributors - -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. \ No newline at end of file diff --git a/vendor/cpr/cmake/cprver.h.in b/vendor/cpr/cmake/cprver.h.in deleted file mode 100644 index e35332497..000000000 --- a/vendor/cpr/cmake/cprver.h.in +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CPR_CPRVER_H -#define CPR_CPRVER_H - -/** - * CPR version as a string. - **/ -#define CPR_VERSION "${cpr_VERSION}" - -/** - * CPR version split up into parts. - **/ -#define CPR_VERSION_MAJOR ${cpr_VERSION_MAJOR} -#define CPR_VERSION_MINOR ${cpr_VERSION_MINOR} -#define CPR_VERSION_PATCH ${cpr_VERSION_PATCH} - -/** - * CPR version as a single hex digit. - * it can be split up into three parts: - * 0xAABBCC - * AA: The current CPR major version number in a hex format. - * BB: The current CPR minor version number in a hex format. - * CC: The current CPR patch version number in a hex format. - * - * Examples: - * '0x010702' -> 01.07.02 -> CPR_VERSION: 1.7.2 - * '0xA13722' -> A1.37.22 -> CPR_VERSION: 161.55.34 - **/ -#define CPR_VERSION_NUM ${cpr_VERSION_NUM} - -#endif diff --git a/vendor/cpr/cpr/accept_encoding.cpp b/vendor/cpr/cpr/accept_encoding.cpp deleted file mode 100644 index 0427b31f5..000000000 --- a/vendor/cpr/cpr/accept_encoding.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "cpr/accept_encoding.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace cpr { - -AcceptEncoding::AcceptEncoding(const std::initializer_list& methods) { - methods_.clear(); - std::transform(methods.begin(), methods.end(), std::inserter(methods_, methods_.begin()), [&](cpr::AcceptEncodingMethods method) { return cpr::AcceptEncodingMethodsStringMap.at(method); }); -} - -AcceptEncoding::AcceptEncoding(const std::initializer_list& string_methods) : methods_{string_methods} {} - -bool AcceptEncoding::empty() const noexcept { - return methods_.empty(); -} - -const std::string AcceptEncoding::getString() const { - return std::accumulate(std::next(methods_.begin()), methods_.end(), *methods_.begin(), [](std::string a, std::string b) { return std::move(a) + ", " + std::move(b); }); -} - -[[nodiscard]] bool AcceptEncoding::disabled() const { - if (methods_.find(cpr::AcceptEncodingMethodsStringMap.at(AcceptEncodingMethods::disabled)) != methods_.end()) { - if (methods_.size() != 1) { - throw std::invalid_argument("AcceptEncoding does not accept any other values if 'disabled' is present. You set the following encodings: " + getString()); - } - return true; - } - return false; -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/async.cpp b/vendor/cpr/cpr/async.cpp deleted file mode 100644 index e10d09e1f..000000000 --- a/vendor/cpr/cpr/async.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "cpr/async.h" - -namespace cpr { - -// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) -CPR_SINGLETON_IMPL(GlobalThreadPool) - -} // namespace cpr diff --git a/vendor/cpr/cpr/auth.cpp b/vendor/cpr/cpr/auth.cpp deleted file mode 100644 index 16f61e88a..000000000 --- a/vendor/cpr/cpr/auth.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "cpr/auth.h" - -#include - -namespace cpr { - -Authentication::Authentication(std::string_view username, std::string_view password, AuthMode auth_mode) : auth_mode_{auth_mode} { - auth_string_.reserve(username.size() + 1 + password.size()); - auth_string_ += username; - auth_string_ += ':'; - auth_string_ += password; -} - -const char* Authentication::GetAuthString() const noexcept { - return auth_string_.c_str(); -} - -AuthMode Authentication::GetAuthMode() const noexcept { - return auth_mode_; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/callback.cpp b/vendor/cpr/cpr/callback.cpp deleted file mode 100644 index f2d257a2c..000000000 --- a/vendor/cpr/cpr/callback.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "cpr/callback.h" -#include "cpr/cprtypes.h" -#include - -namespace cpr { - -void CancellationCallback::SetProgressCallback(ProgressCallback& u_cb) { - user_cb.emplace(std::reference_wrapper{u_cb}); -} -bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const { - const bool cont_operation{!cancellation_state->load()}; - return user_cb ? (cont_operation && (*user_cb)(dltotal, dlnow, ultotal, ulnow)) : cont_operation; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/cert_info.cpp b/vendor/cpr/cpr/cert_info.cpp deleted file mode 100644 index 410648c04..000000000 --- a/vendor/cpr/cpr/cert_info.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "cpr/cert_info.h" -#include -#include - -namespace cpr { - -std::string& CertInfo::operator[](const size_t& pos) { - return cert_info_[pos]; -} - -CertInfo::iterator CertInfo::begin() { - return cert_info_.begin(); -} -CertInfo::iterator CertInfo::end() { - return cert_info_.end(); -} - -CertInfo::const_iterator CertInfo::begin() const { - return cert_info_.begin(); -} - -CertInfo::const_iterator CertInfo::end() const { - return cert_info_.end(); -} - -CertInfo::const_iterator CertInfo::cbegin() const { - return cert_info_.cbegin(); -} - -CertInfo::const_iterator CertInfo::cend() const { - return cert_info_.cend(); -} - -void CertInfo::emplace_back(const std::string& str) { - cert_info_.emplace_back(str); -} - -void CertInfo::push_back(const std::string& str) { - cert_info_.push_back(str); -} - -void CertInfo::pop_back() { - cert_info_.pop_back(); -} -} // namespace cpr diff --git a/vendor/cpr/cpr/connection_pool.cpp b/vendor/cpr/cpr/connection_pool.cpp deleted file mode 100644 index 6afb8643e..000000000 --- a/vendor/cpr/cpr/connection_pool.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "cpr/connection_pool.h" -#include -#include -#include - -namespace cpr { -ConnectionPool::ConnectionPool() { - CURLSH* curl_share = curl_share_init(); - this->connection_mutex_ = std::make_shared(); - - auto lock_f = +[](CURL* /*handle*/, curl_lock_data /*data*/, curl_lock_access /*access*/, void* userptr) { - std::mutex* lock = static_cast(userptr); - lock->lock(); // cppcheck-suppress localMutex // False positive: mutex is used as callback for libcurl, not local scope - }; - - auto unlock_f = +[](CURL* /*handle*/, curl_lock_data /*data*/, void* userptr) { - std::mutex* lock = static_cast(userptr); - lock->unlock(); - }; - - curl_share_setopt(curl_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); - curl_share_setopt(curl_share, CURLSHOPT_USERDATA, this->connection_mutex_.get()); - curl_share_setopt(curl_share, CURLSHOPT_LOCKFUNC, lock_f); - curl_share_setopt(curl_share, CURLSHOPT_UNLOCKFUNC, unlock_f); - - this->curl_sh_ = std::shared_ptr(curl_share, - [](CURLSH* ptr) { - // Make sure to reset callbacks before cleanup to avoid deadlocks - curl_share_setopt(ptr, CURLSHOPT_LOCKFUNC, nullptr); - curl_share_setopt(ptr, CURLSHOPT_UNLOCKFUNC, nullptr); - curl_share_cleanup(ptr); - }); -} - -void ConnectionPool::SetupHandler(CURL* easy_handler) const { - curl_easy_setopt(easy_handler, CURLOPT_SHARE, this->curl_sh_.get()); -} - -} // namespace cpr \ No newline at end of file diff --git a/vendor/cpr/cpr/cookies.cpp b/vendor/cpr/cpr/cookies.cpp deleted file mode 100644 index a79d8c7d7..000000000 --- a/vendor/cpr/cpr/cookies.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "cpr/cookies.h" -#include "cpr/curlholder.h" -#include -#include -#include -#include -#include -#include - -namespace cpr { -const std::string& Cookie::GetDomain() const { - return domain_; -} - -bool Cookie::IsIncludingSubdomains() const { - return includeSubdomains_; -} - -const std::string& Cookie::GetPath() const { - return path_; -} - -bool Cookie::IsHttpsOnly() const { - return httpsOnly_; -} - -std::chrono::system_clock::time_point Cookie::GetExpires() const { - return expires_; -} - -std::string Cookie::GetExpiresString() const { - std::stringstream ss; - std::tm tm{}; - const std::time_t tt = std::chrono::system_clock::to_time_t(expires_); -#ifdef _WIN32 - gmtime_s(&tm, &tt); -#else - // NOLINTNEXTLINE(misc-include-cleaner,cert-err33-c) False positive since is included. Also ignore the ret value here. - gmtime_r(&tt, &tm); -#endif - ss << std::put_time(&tm, "%a, %d %b %Y %H:%M:%S GMT"); - return ss.str(); -} - -const std::string& Cookie::GetName() const { - return name_; -} - -const std::string& Cookie::GetValue() const { - return value_; -} - -std::string Cookies::GetEncoded(const CurlHolder& holder) const { - std::stringstream stream; - for (const cpr::Cookie& item : cookies_) { - // Depending on if encoding is set to "true", we will URL-encode cookies - stream << (encode ? std::string_view{holder.urlEncode(item.GetName())} : std::string_view{item.GetName()}) << "="; - - // special case version 1 cookies, which can be distinguished by - // beginning and trailing quotes - if (!item.GetValue().empty() && item.GetValue().front() == '"' && item.GetValue().back() == '"') { - stream << item.GetValue(); - } else { - // Depending on if encoding is set to "true", we will URL-encode cookies - stream << (encode ? std::string_view{holder.urlEncode(item.GetValue())} : std::string_view{item.GetValue()}); - } - stream << "; "; - } - return stream.str(); -} - -cpr::Cookie& Cookies::operator[](size_t pos) { - return cookies_[pos]; -} - -Cookies::iterator Cookies::begin() { - return cookies_.begin(); -} - -Cookies::iterator Cookies::end() { - return cookies_.end(); -} - -Cookies::const_iterator Cookies::begin() const { - return cookies_.begin(); -} - -Cookies::const_iterator Cookies::end() const { - return cookies_.end(); -} - -Cookies::const_iterator Cookies::cbegin() const { - return cookies_.cbegin(); -} - -Cookies::const_iterator Cookies::cend() const { - return cookies_.cend(); -} - -void Cookies::emplace_back(const Cookie& str) { - cookies_.emplace_back(str); -} - -bool Cookies::empty() const { - return cookies_.empty(); -} - -void Cookies::push_back(const Cookie& str) { - cookies_.push_back(str); -} - -void Cookies::pop_back() { - cookies_.pop_back(); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/cprtypes.cpp b/vendor/cpr/cpr/cprtypes.cpp deleted file mode 100644 index 43df13491..000000000 --- a/vendor/cpr/cpr/cprtypes.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "cpr/cprtypes.h" - -#include -#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 deleted file mode 100644 index 7576d3e22..000000000 --- a/vendor/cpr/cpr/curl_container.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "cpr/curl_container.h" -#include "cpr/curlholder.h" -#include -#include -#include -#include - -namespace cpr { -template -CurlContainer::CurlContainer(const std::initializer_list& containerList) : containerList_(containerList) {} - -template -void CurlContainer::Add(const std::initializer_list& containerList) { - std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); }); -} - -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 += "&"; - } - - const std::string escapedKey = encode ? std::string{holder.urlEncode(parameter.key)} : parameter.key; - if (parameter.value.empty()) { - content += escapedKey; - } else { - const std::string escapedValue = encode ? std::string{holder.urlEncode(parameter.value)} : parameter.value; - content += escapedKey + "="; - content += escapedValue; - } - } - - return content; -} - -template <> -const std::string CurlContainer::GetContent() const { - std::string content{}; - for (const Parameter& parameter : containerList_) { - if (!content.empty()) { - content += "&"; - } - - if (parameter.value.empty()) { - content += parameter.key; - } else { - content += parameter.key + "="; - content += parameter.value; - } - } - - 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 += "&"; - } - const std::string escaped = encode ? std::string{holder.urlEncode(element.value)} : element.value; - content += element.key + "=" + escaped; - } - - return content; -} - -template <> -const std::string CurlContainer::GetContent() const { - std::string content{}; - for (const cpr::Pair& element : containerList_) { - if (!content.empty()) { - content += "&"; - } - content += element.key + "=" + element.value; - } - - return content; -} - -template class CurlContainer; -template class CurlContainer; - -} // namespace cpr diff --git a/vendor/cpr/cpr/curlholder.cpp b/vendor/cpr/cpr/curlholder.cpp deleted file mode 100644 index 4c8084634..000000000 --- a/vendor/cpr/cpr/curlholder.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "cpr/curlholder.h" -#include "cpr/secure_string.h" -#include -#include -#include -#include - -namespace cpr { -CurlHolder::CurlHolder() { - /** - * Allow multithreaded access to CPR by locking curl_easy_init(). - * curl_easy_init() is not thread safe. - * References: - * https://curl.haxx.se/libcurl/c/curl_easy_init.html - * https://curl.haxx.se/libcurl/c/threadsafe.html - **/ - curl_easy_init_mutex_().lock(); - // NOLINTNEXTLINE (cppcoreguidelines-prefer-member-initializer) since we need it to happen inside the lock - handle = curl_easy_init(); - curl_easy_init_mutex_().unlock(); - - assert(handle); -} - -CurlHolder::CurlHolder(CurlHolder&& old) noexcept : handle(old.handle), chunk(old.chunk), resolveCurlList(old.resolveCurlList), multipart(old.multipart), error(std::move(old.error)) { - // Avoid double free - old.handle = nullptr; - old.chunk = nullptr; - old.resolveCurlList = nullptr; - old.multipart = nullptr; -} - -CurlHolder::~CurlHolder() { - curl_slist_free_all(chunk); - curl_slist_free_all(resolveCurlList); - curl_mime_free(multipart); - curl_easy_cleanup(handle); -} - -CurlHolder& CurlHolder::operator=(CurlHolder&& old) noexcept { - // Free the previous stuff - curl_slist_free_all(chunk); - curl_slist_free_all(resolveCurlList); - curl_mime_free(multipart); - curl_easy_cleanup(handle); - - // Move - handle = old.handle; - chunk = old.chunk; - resolveCurlList = old.resolveCurlList; - multipart = old.multipart; - error = std::move(old.error); - - // Avoid double free - old.handle = nullptr; - old.chunk = nullptr; - old.resolveCurlList = nullptr; - old.multipart = nullptr; - return *this; -} - -util::SecureString CurlHolder::urlEncode(std::string_view s) const { - assert(handle); - char* output = curl_easy_escape(handle, s.data(), static_cast(s.length())); - if (output) { - util::SecureString result = output; - curl_free(output); - return result; - } - return ""; -} - -util::SecureString CurlHolder::urlDecode(std::string_view s) const { - assert(handle); - char* output = curl_easy_unescape(handle, s.data(), static_cast(s.length()), nullptr); - if (output) { - util::SecureString result = output; - curl_free(output); - return result; - } - return ""; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/curlmultiholder.cpp b/vendor/cpr/cpr/curlmultiholder.cpp deleted file mode 100644 index 972fefe91..000000000 --- a/vendor/cpr/cpr/curlmultiholder.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "cpr/curlmultiholder.h" -#include -#include - -namespace cpr { - -CurlMultiHolder::CurlMultiHolder() : handle{curl_multi_init()} { - assert(handle); -} - -CurlMultiHolder::~CurlMultiHolder() { - curl_multi_cleanup(handle); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/error.cpp b/vendor/cpr/cpr/error.cpp deleted file mode 100644 index 4c533a670..000000000 --- a/vendor/cpr/cpr/error.cpp +++ /dev/null @@ -1,223 +0,0 @@ -#include "cpr/error.h" -#include -#include -#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_FAILED_INIT: - return ErrorCode::FAILED_INIT; - case CURLE_URL_MALFORMAT: - return ErrorCode::URL_MALFORMAT; - case CURLE_NOT_BUILT_IN: - return ErrorCode::NOT_BUILT_IN; - case CURLE_COULDNT_RESOLVE_PROXY: - return ErrorCode::COULDNT_RESOLVE_PROXY; - case CURLE_COULDNT_RESOLVE_HOST: - return ErrorCode::COULDNT_RESOLVE_HOST; - case CURLE_COULDNT_CONNECT: - return ErrorCode::COULDNT_CONNECT; - -// Name changed in curl >= 7.51.0. -#if LIBCURL_VERSION_NUM >= 0x073300 - case CURLE_WEIRD_SERVER_REPLY: - return ErrorCode::WEIRD_SERVER_REPLY; -#else - case CURLE_FTP_WEIRD_SERVER_REPLY: - return ErrorCode::WEIRD_SERVER_REPLY; -#endif - case CURLE_REMOTE_ACCESS_DENIED: - return ErrorCode::REMOTE_ACCESS_DENIED; - case CURLE_HTTP2: - return ErrorCode::HTTP2; - case CURLE_QUOTE_ERROR: - return ErrorCode::QUOTE_ERROR; - case CURLE_HTTP_RETURNED_ERROR: - return ErrorCode::HTTP_RETURNED_ERROR; - case CURLE_WRITE_ERROR: - return ErrorCode::WRITE_ERROR; - case CURLE_UPLOAD_FAILED: - return ErrorCode::UPLOAD_FAILED; - case CURLE_READ_ERROR: - return ErrorCode::READ_ERROR; - case CURLE_OUT_OF_MEMORY: - return ErrorCode::OUT_OF_MEMORY; - case CURLE_OPERATION_TIMEDOUT: - return ErrorCode::OPERATION_TIMEDOUT; - case CURLE_RANGE_ERROR: - return ErrorCode::RANGE_ERROR; - case CURLE_HTTP_POST_ERROR: - return ErrorCode::HTTP_POST_ERROR; - case CURLE_SSL_CONNECT_ERROR: - return ErrorCode::SSL_CONNECT_ERROR; - case CURLE_BAD_DOWNLOAD_RESUME: - return ErrorCode::BAD_DOWNLOAD_RESUME; - case CURLE_FILE_COULDNT_READ_FILE: - return ErrorCode::FILE_COULDNT_READ_FILE; - case CURLE_FUNCTION_NOT_FOUND: - return ErrorCode::FUNCTION_NOT_FOUND; - case CURLE_ABORTED_BY_CALLBACK: - return ErrorCode::ABORTED_BY_CALLBACK; - case CURLE_BAD_FUNCTION_ARGUMENT: - return ErrorCode::BAD_FUNCTION_ARGUMENT; - case CURLE_INTERFACE_FAILED: - return ErrorCode::INTERFACE_FAILED; - case CURLE_TOO_MANY_REDIRECTS: - return ErrorCode::TOO_MANY_REDIRECTS; - case CURLE_UNKNOWN_OPTION: - return ErrorCode::UNKNOWN_OPTION; -// Added in curl 7.78.0. -#if LIBCURL_VERSION_NUM >= 0x074E00 - case CURLE_SETOPT_OPTION_SYNTAX: - return ErrorCode::SETOPT_OPTION_SYNTAX; -#endif - case CURLE_GOT_NOTHING: - return ErrorCode::GOT_NOTHING; - case CURLE_SSL_ENGINE_NOTFOUND: - return ErrorCode::SSL_ENGINE_NOTFOUND; - case CURLE_SSL_ENGINE_SETFAILED: - return ErrorCode::SSL_ENGINE_SETFAILED; - case CURLE_SEND_ERROR: - return ErrorCode::SEND_ERROR; - case CURLE_RECV_ERROR: - return ErrorCode::RECV_ERROR; - case CURLE_SSL_CERTPROBLEM: - return ErrorCode::SSL_CERTPROBLEM; - case CURLE_SSL_CIPHER: - return ErrorCode::SSL_CIPHER; - case CURLE_PEER_FAILED_VERIFICATION: - return ErrorCode::PEER_FAILED_VERIFICATION; - case CURLE_BAD_CONTENT_ENCODING: - return ErrorCode::BAD_CONTENT_ENCODING; - case CURLE_FILESIZE_EXCEEDED: - return ErrorCode::FILESIZE_EXCEEDED; - case CURLE_USE_SSL_FAILED: - return ErrorCode::USE_SSL_FAILED; - case CURLE_SEND_FAIL_REWIND: - return ErrorCode::SEND_FAIL_REWIND; - case CURLE_SSL_ENGINE_INITFAILED: - return ErrorCode::SSL_ENGINE_INITFAILED; - -// Added in curl 7.13.1. -#if LIBCURL_VERSION_NUM >= 0x070D01 - case CURLE_LOGIN_DENIED: - return ErrorCode::LOGIN_DENIED; -#endif - -// Added in curl 7.16.0. -#if LIBCURL_VERSION_NUM >= 0x071000 - case CURLE_SSL_CACERT_BADFILE: - return ErrorCode::SSL_CACERT_BADFILE; -#endif - -// Added in curl 7.16.1. -#if LIBCURL_VERSION_NUM >= 0x071001 - case CURLE_SSL_SHUTDOWN_FAILED: - return ErrorCode::SSL_SHUTDOWN_FAILED; -#endif - -// Added in curl 7.18.2. -#if LIBCURL_VERSION_NUM >= 0x071202 - case CURLE_AGAIN: - return ErrorCode::AGAIN; -#endif - -// Added in curl 7.19.0. -#if LIBCURL_VERSION_NUM >= 0x071300 - case CURLE_SSL_CRL_BADFILE: - return ErrorCode::SSL_CRL_BADFILE; - case CURLE_SSL_ISSUER_ERROR: - return ErrorCode::SSL_ISSUER_ERROR; -#endif - -// Added in curl 7.21.0. -#if LIBCURL_VERSION_NUM >= 0x071500 - case CURLE_CHUNK_FAILED: - return ErrorCode::CHUNK_FAILED; -#endif - -// Added in curl 7.30.0. -#if LIBCURL_VERSION_NUM >= 0x071E00 - case CURLE_NO_CONNECTION_AVAILABLE: - return ErrorCode::NO_CONNECTION_AVAILABLE; -#endif - -// Added in curl 7.39.0. -#if LIBCURL_VERSION_NUM >= 0x072700 - case CURLE_SSL_PINNEDPUBKEYNOTMATCH: - return ErrorCode::SSL_PINNEDPUBKEYNOTMATCH; -#endif - -// Added in curl 7.41.0. -#if LIBCURL_VERSION_NUM >= 0x072900 - case CURLE_SSL_INVALIDCERTSTATUS: - return ErrorCode::SSL_INVALIDCERTSTATUS; -#endif - -// Added in curl 7.49.0. -#if LIBCURL_VERSION_NUM >= 0x073100 - case CURLE_HTTP2_STREAM: - return ErrorCode::HTTP2_STREAM; -#endif - case CURLE_PARTIAL_FILE: - return ErrorCode::PARTIAL_FILE; - -// Added in curl 7.59.0. -#if LIBCURL_VERSION_NUM >= 0x073B00 - case CURLE_RECURSIVE_API_CALL: - return ErrorCode::RECURSIVE_API_CALL; -#endif - -// Added in curl 7.66.0. -#if LIBCURL_VERSION_NUM >= 0x074200 - case CURLE_AUTH_ERROR: - return ErrorCode::AUTH_ERROR; -#endif - -// Added in curl 7.68.0. -#if LIBCURL_VERSION_NUM >= 0x074400 - case CURLE_HTTP3: - return ErrorCode::HTTP3; -#endif - -// Added in curl 7.69.0. -#if LIBCURL_VERSION_NUM >= 0x074500 - case CURLE_QUIC_CONNECT_ERROR: - return ErrorCode::QUIC_CONNECT_ERROR; -#endif - -// Added in curl 7.73.0. -#if LIBCURL_VERSION_NUM >= 0x074900 - case CURLE_PROXY: - return ErrorCode::PROXY; -#endif - -// Added in curl 7.77.0. -#if LIBCURL_VERSION_NUM >= 0x074D00 - case CURLE_SSL_CLIENTCERT: - return ErrorCode::SSL_CLIENTCERT; -#endif - -// Added in curl 7.84.0. -#if LIBCURL_VERSION_NUM >= 0x075400 - case CURLE_UNRECOVERABLE_POLL: - return ErrorCode::UNRECOVERABLE_POLL; -#endif - -// Added in curl 7.6.0. -#if LIBCURL_VERSION_NUM >= 0x080600 - case CURLE_TOO_LARGE: - return ErrorCode::TOO_LARGE; -#endif - default: - return ErrorCode::UNKNOWN_ERROR; - } -} - -} // namespace cpr \ No newline at end of file diff --git a/vendor/cpr/cpr/file.cpp b/vendor/cpr/cpr/file.cpp deleted file mode 100644 index f0336b9ea..000000000 --- a/vendor/cpr/cpr/file.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "cpr/file.h" -#include -#include -#include - -namespace cpr { - -Files::Files(const std::initializer_list& p_filepaths) : files(p_filepaths.begin(), p_filepaths.end()) {} - -Files::iterator Files::begin() { - return files.begin(); -} - -Files::iterator Files::end() { - return files.end(); -} - -Files::const_iterator Files::begin() const { - return files.begin(); -} - -Files::const_iterator Files::end() const { - return files.end(); -} - -Files::const_iterator Files::cbegin() const { - return files.cbegin(); -} - -Files::const_iterator Files::cend() const { - return files.cend(); -} - -void Files::emplace_back(const File& file) { - files.emplace_back(file); -} - -void Files::push_back(const File& file) { - files.push_back(file); -} - -void Files::pop_back() { - files.pop_back(); -} - -Files& Files::operator=(const Files& other) { - if (&other != this) { - files = other.files; - } - return *this; -} - -Files& Files::operator=(Files&& old) noexcept { - if (&old != this) { - files = std::move(old.files); - } - return *this; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/interceptor.cpp b/vendor/cpr/cpr/interceptor.cpp deleted file mode 100644 index 6af915aa0..000000000 --- a/vendor/cpr/cpr/interceptor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "cpr/interceptor.h" -#include "cpr/callback.h" -#include "cpr/multiperform.h" -#include "cpr/response.h" -#include "cpr/session.h" -#include -#include -#include -#include - -namespace cpr { - -Response Interceptor::proceed(Session& session) { - return session.proceed(); -} - -Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod) { - switch (httpMethod) { - case ProceedHttpMethod::DELETE_REQUEST: - return session.Delete(); - case ProceedHttpMethod::GET_REQUEST: - return session.Get(); - case ProceedHttpMethod::HEAD_REQUEST: - return session.Head(); - case ProceedHttpMethod::OPTIONS_REQUEST: - return session.Options(); - case ProceedHttpMethod::PATCH_REQUEST: - return session.Patch(); - case ProceedHttpMethod::POST_REQUEST: - return session.Post(); - case ProceedHttpMethod::PUT_REQUEST: - return session.Put(); - default: - throw std::invalid_argument{"Can't proceed the session with the provided http method!"}; - } -} - -Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file) { - if (httpMethod == ProceedHttpMethod::DOWNLOAD_FILE_REQUEST) { - return session.Download(file); - } - throw std::invalid_argument{"std::ofstream argument is only valid for ProceedHttpMethod::DOWNLOAD_FILE!"}; -} - -Response Interceptor::proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write) { - if (httpMethod == ProceedHttpMethod::DOWNLOAD_CALLBACK_REQUEST) { - return session.Download(write); - } - throw std::invalid_argument{"WriteCallback argument is only valid for ProceedHttpMethod::DOWNLOAD_CALLBACK!"}; -} - -std::vector InterceptorMulti::proceed(MultiPerform& multi) { - return multi.proceed(); -} - -void InterceptorMulti::PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write) { - multi.PrepareDownloadSessions(sessions_index, write); -} -} // namespace cpr diff --git a/vendor/cpr/cpr/multipart.cpp b/vendor/cpr/cpr/multipart.cpp deleted file mode 100644 index 21251d531..000000000 --- a/vendor/cpr/cpr/multipart.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "cpr/multipart.h" -#include -#include - -namespace cpr { -Multipart::Multipart(const std::initializer_list& p_parts) : parts{p_parts} {} -Multipart::Multipart(const std::vector& p_parts) : parts{p_parts} {} -Multipart::Multipart(const std::vector&& p_parts) : parts{p_parts} {} -} // namespace cpr diff --git a/vendor/cpr/cpr/multiperform.cpp b/vendor/cpr/cpr/multiperform.cpp deleted file mode 100644 index 272d6c09f..000000000 --- a/vendor/cpr/cpr/multiperform.cpp +++ /dev/null @@ -1,385 +0,0 @@ -#include "cpr/multiperform.h" - -#include "cpr/callback.h" -#include "cpr/curlmultiholder.h" -#include "cpr/interceptor.h" -#include "cpr/response.h" -#include "cpr/session.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cpr { - -MultiPerform::MultiPerform() : multicurl_(new CurlMultiHolder()) { - current_interceptor_ = interceptors_.end(); - first_interceptor_ = interceptors_.end(); -} - -MultiPerform::MultiPerform(MultiPerform&& old) noexcept { - *this = std::move(old); -} - -MultiPerform& MultiPerform::operator=(MultiPerform&& old) noexcept { - sessions_ = std::move(old.sessions_); - multicurl_ = std::move(old.multicurl_); - interceptors_ = std::move(old.interceptors_); - current_interceptor_ = interceptors_.end(); - first_interceptor_ = interceptors_.end(); - return *this; -} - -MultiPerform::~MultiPerform() { - // Unlock all sessions - for (const auto& [session, method] : sessions_) { - session->isUsedInMultiPerform = false; - - // Remove easy handle from multi handle - const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle); - if (error_code) { - std::cerr << "curl_multi_remove_handle() failed, code " << static_cast(error_code) << '\n'; - } - } -} - -void MultiPerform::AddSession(std::shared_ptr& session, HttpMethod method) { - // Check if this multiperform is download only - if (((method != HttpMethod::DOWNLOAD_REQUEST && is_download_multi_perform) && method != HttpMethod::UNDEFINED) || (method == HttpMethod::DOWNLOAD_REQUEST && !is_download_multi_perform && !sessions_.empty())) { - // Currently it is not possible to mix download and non-download methods, as download needs additional parameters - throw std::invalid_argument("Failed to add session: Cannot mix download and non-download methods!"); - } - - // Set download only if neccessary - if (method == HttpMethod::DOWNLOAD_REQUEST) { - is_download_multi_perform = true; - } - - // Lock session to the multihandle - session->isUsedInMultiPerform = true; - - // Add session to sessions_ - sessions_.emplace_back(session, method); -} - -void MultiPerform::RemoveSession(const std::shared_ptr& session) { - if (sessions_.empty()) { - throw std::invalid_argument("Failed to find session!"); - } - - // Unlock session - session->isUsedInMultiPerform = false; - - // Remove session from sessions_ - auto it = std::find_if(sessions_.begin(), sessions_.end(), [&session](const std::pair, HttpMethod>& pair) { return session->curl_->handle == pair.first->curl_->handle; }); - if (it == sessions_.end()) { - throw std::invalid_argument("Failed to find session!"); - } - sessions_.erase(it); - - // Reset download only if empty - if (sessions_.empty()) { - is_download_multi_perform = false; - } -} - -std::vector, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() { - return sessions_; -} - -const std::vector, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() const { - return sessions_; -} - -void MultiPerform::DoMultiPerform() { - // Do multi perform until every handle has finished - int still_running{0}; - for (const auto& [session, _] : sessions_) { - const CURLMcode error_code = curl_multi_add_handle(multicurl_->handle, session->curl_->handle); - if (error_code && error_code != CURLM_ADDED_ALREADY) { - std::cerr << "curl_multi_add_handle() failed, code " << static_cast(error_code) << '\n'; - } - } - do { - CURLMcode error_code = curl_multi_perform(multicurl_->handle, &still_running); - if (error_code) { - std::cerr << "curl_multi_perform() failed, code " << static_cast(error_code) << '\n'; - break; - } - - if (still_running) { - const int timeout_ms{250}; -#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0 - error_code = curl_multi_poll(multicurl_->handle, nullptr, 0, timeout_ms, nullptr); - if (error_code) { - std::cerr << "curl_multi_poll() failed, code " << static_cast(error_code) << '\n'; -#else - error_code = curl_multi_wait(multicurl_->handle, nullptr, 0, timeout_ms, nullptr); - if (error_code) { - std::cerr << "curl_multi_wait() failed, code " << static_cast(error_code) << '\n'; - -#endif - break; - } - } - } while (still_running); -} - -std::vector MultiPerform::ReadMultiInfo(const std::function& complete_function) { - // Get infos and create Response objects - std::vector responses; - struct CURLMsg* info{nullptr}; - do { - int msgq = 0; - - // Read info from multihandle - info = curl_multi_info_read(multicurl_->handle, &msgq); - - if (info) { - // Find current session - auto it = std::find_if(sessions_.begin(), sessions_.end(), [&info](const std::pair, HttpMethod>& pair) { return pair.first->curl_->handle == info->easy_handle; }); - if (it == sessions_.end()) { - std::cerr << "Failed to find current session!" << '\n'; - break; - } - const std::shared_ptr current_session = (*it).first; - - // Add response object - // NOLINTNEXTLINE (cppcoreguidelines-pro-type-union-access) - responses.push_back(complete_function(*current_session, info->data.result)); - } - } while (info); - - for (const auto& [session, _] : sessions_) { - const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle); - if (error_code) { - std::cerr << "curl_multi_remove_handle() failed, code " << static_cast(error_code) << '\n'; - } - } - - // Sort response objects to match order of added sessions - std::vector sorted_responses; - for (const auto& [session, _] : sessions_) { - Session& current_session = *session; - auto it = std::find_if(responses.begin(), responses.end(), [¤t_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; }); - const Response current_response = *it; // NOLINT (performance-unnecessary-copy-initialization) False positive - // Erase response from original vector to increase future search speed - responses.erase(it); - sorted_responses.push_back(current_response); - } - return sorted_responses; -} - -std::vector MultiPerform::MakeRequest() { - const std::optional> r = intercept(); - if (r.has_value()) { - return r.value(); - } - - DoMultiPerform(); - return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.Complete(curl_error); }); -} - -std::vector MultiPerform::MakeDownloadRequest() { - const std::optional> r = intercept(); - if (r.has_value()) { - return r.value(); - } - - DoMultiPerform(); - return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.CompleteDownload(curl_error); }); -} - -void MultiPerform::PrepareSessions() { - for (const auto& [session, method] : sessions_) { - switch (method) { - case HttpMethod::GET_REQUEST: - session->PrepareGet(); - break; - case HttpMethod::POST_REQUEST: - session->PreparePost(); - break; - case HttpMethod::PUT_REQUEST: - session->PreparePut(); - break; - case HttpMethod::DELETE_REQUEST: - session->PrepareDelete(); - break; - case HttpMethod::PATCH_REQUEST: - session->PreparePatch(); - break; - case HttpMethod::HEAD_REQUEST: - session->PrepareHead(); - break; - case HttpMethod::OPTIONS_REQUEST: - session->PrepareOptions(); - break; - default: - std::cerr << "PrepareSessions failed: Undefined HttpMethod or download without arguments!" << '\n'; - return; - } - } -} - -void MultiPerform::PrepareDownloadSession(size_t sessions_index, const WriteCallback& write) { - const auto& [session, method] = sessions_[sessions_index]; - switch (method) { - case HttpMethod::DOWNLOAD_REQUEST: - session->PrepareDownload(write); - break; - default: - std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << '\n'; - return; - } -} - -void MultiPerform::PrepareDownloadSession(size_t sessions_index, std::ofstream& file) { - const auto& [session, method] = sessions_[sessions_index]; - switch (method) { - case HttpMethod::DOWNLOAD_REQUEST: - session->PrepareDownload(file); - break; - default: - std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << '\n'; - return; - } -} - -void MultiPerform::SetHttpMethod(HttpMethod method) { - for (auto& [_, session_method] : sessions_) { - session_method = method; - } -} - -void MultiPerform::PrepareGet() { - SetHttpMethod(HttpMethod::GET_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PrepareDelete() { - SetHttpMethod(HttpMethod::DELETE_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PreparePut() { - SetHttpMethod(HttpMethod::PUT_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PreparePatch() { - SetHttpMethod(HttpMethod::PATCH_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PrepareHead() { - SetHttpMethod(HttpMethod::HEAD_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PrepareOptions() { - SetHttpMethod(HttpMethod::OPTIONS_REQUEST); - PrepareSessions(); -} - -void MultiPerform::PreparePost() { - SetHttpMethod(HttpMethod::POST_REQUEST); - PrepareSessions(); -} - -std::vector MultiPerform::Get() { - PrepareGet(); - return MakeRequest(); -} - -std::vector MultiPerform::Delete() { - PrepareDelete(); - return MakeRequest(); -} - -std::vector MultiPerform::Put() { - PreparePut(); - return MakeRequest(); -} - -std::vector MultiPerform::Head() { - PrepareHead(); - return MakeRequest(); -} - -std::vector MultiPerform::Options() { - PrepareOptions(); - return MakeRequest(); -} - -std::vector MultiPerform::Patch() { - PreparePatch(); - return MakeRequest(); -} - -std::vector MultiPerform::Post() { - PreparePost(); - return MakeRequest(); -} - -std::vector MultiPerform::Perform() { - PrepareSessions(); - return MakeRequest(); -} - -std::vector MultiPerform::proceed() { - // Check if this multiperform mixes download and non download requests - if (!sessions_.empty()) { - const bool new_is_download_multi_perform = sessions_.front().second == HttpMethod::DOWNLOAD_REQUEST; - - for (const auto& [_, method] : sessions_) { - if ((new_is_download_multi_perform && method != HttpMethod::DOWNLOAD_REQUEST) || (!new_is_download_multi_perform && method == HttpMethod::DOWNLOAD_REQUEST)) { - throw std::invalid_argument("Failed to proceed with session: Cannot mix download and non-download methods!"); - } - } - is_download_multi_perform = new_is_download_multi_perform; - } - - PrepareSessions(); - return MakeRequest(); -} - -const std::optional> MultiPerform::intercept() { - if (current_interceptor_ == interceptors_.end()) { - current_interceptor_ = first_interceptor_; - } else { - current_interceptor_++; - } - - if (current_interceptor_ != interceptors_.end()) { - auto icpt = current_interceptor_; - // Nested makeRequest() start at first_interceptor_, thus excluding previous interceptors. - first_interceptor_ = current_interceptor_; - ++first_interceptor_; - - const std::optional> r = (*current_interceptor_)->intercept(*this); - - first_interceptor_ = icpt; - - return r; - } - return std::nullopt; -} - -void MultiPerform::AddInterceptor(const std::shared_ptr& pinterceptor) { - // Shall only add before first interceptor run - assert(current_interceptor_ == interceptors_.end()); - interceptors_.push_back(pinterceptor); - first_interceptor_ = interceptors_.begin(); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/parameters.cpp b/vendor/cpr/cpr/parameters.cpp deleted file mode 100644 index 51cdd1830..000000000 --- a/vendor/cpr/cpr/parameters.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// NOLINTNEXTLINE(misc-include-cleaner) Ignored since it's for the future -#include "cpr/parameters.h" - -namespace cpr {} // namespace cpr diff --git a/vendor/cpr/cpr/payload.cpp b/vendor/cpr/cpr/payload.cpp deleted file mode 100644 index 2a23b0dd3..000000000 --- a/vendor/cpr/cpr/payload.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// NOLINTNEXTLINE(misc-include-cleaner) Ignored since it's for the future -#include "cpr/payload.h" - -namespace cpr {} // namespace cpr diff --git a/vendor/cpr/cpr/proxies.cpp b/vendor/cpr/cpr/proxies.cpp deleted file mode 100644 index 0d3fe9893..000000000 --- a/vendor/cpr/cpr/proxies.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "cpr/proxies.h" - -#include -#include -#include -#include - -namespace cpr { - -Proxies::Proxies(const std::initializer_list>& hosts) : hosts_{hosts} {} -Proxies::Proxies(const std::map& 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/proxyauth.cpp b/vendor/cpr/cpr/proxyauth.cpp deleted file mode 100644 index 78d82919d..000000000 --- a/vendor/cpr/cpr/proxyauth.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "cpr/proxyauth.h" -#include "cpr/secure_string.h" -#include -#include - -namespace cpr { - -std::string_view EncodedAuthentication::GetUsername() const { - return username; -} - -std::string_view EncodedAuthentication::GetPassword() const { - return password; -} - -const util::SecureString& EncodedAuthentication::GetUsernameUnderlying() const { - return username; -} - -const util::SecureString& EncodedAuthentication::GetPasswordUnderlying() const { - return password; -} - -bool ProxyAuthentication::has(const std::string& protocol) const { - return proxyAuth_.count(protocol) > 0; -} - -std::string_view ProxyAuthentication::GetUsername(const std::string& protocol) { - return proxyAuth_[protocol].GetUsername(); -} - -std::string_view ProxyAuthentication::GetPassword(const std::string& protocol) { - return proxyAuth_[protocol].GetPassword(); -} - -const util::SecureString& ProxyAuthentication::GetUsernameUnderlying(const std::string& protocol) const { - return proxyAuth_.at(protocol).GetUsernameUnderlying(); -} - -const util::SecureString& ProxyAuthentication::GetPasswordUnderlying(const std::string& protocol) const { - return proxyAuth_.at(protocol).GetPasswordUnderlying(); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/redirect.cpp b/vendor/cpr/cpr/redirect.cpp deleted file mode 100644 index 3be96960b..000000000 --- a/vendor/cpr/cpr/redirect.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "cpr/redirect.h" -#include - -namespace cpr { -PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs) { - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs) { - return static_cast(static_cast(lhs) & static_cast(rhs)); -} - -PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs) { - return static_cast(static_cast(lhs) ^ static_cast(rhs)); -} - -PostRedirectFlags operator~(PostRedirectFlags flag) { - return static_cast(~static_cast(flag)); -} - -PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) { - lhs = static_cast(static_cast(lhs) | static_cast(rhs)); - const uint8_t tmp = static_cast(lhs); - lhs = static_cast(tmp); - return lhs; -} - -PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs) { - lhs = static_cast(static_cast(lhs) & static_cast(rhs)); - return lhs; -} - -PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs) { - lhs = static_cast(static_cast(lhs) ^ static_cast(rhs)); - return lhs; -} - -bool any(PostRedirectFlags flag) { - return flag != PostRedirectFlags::NONE; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/response.cpp b/vendor/cpr/cpr/response.cpp deleted file mode 100644 index 4bfa3d5ed..000000000 --- a/vendor/cpr/cpr/response.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "cpr/response.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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)), raw_header(std::move(p_header_string)) { - header = cpr::util::parseHeader(raw_header, &status_line, &reason); - assert(curl_); - assert(curl_->handle); - curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code); - curl_easy_getinfo(curl_->handle, CURLINFO_TOTAL_TIME, &elapsed); - char* url_string{nullptr}; - curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string); - url = Url(url_string); -#if LIBCURL_VERSION_NUM >= 0x073700 // 7.55.0 - curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes); - curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes); -#else - 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); -#if LIBCURL_VERSION_NUM >= 0x071300 // 7.19.0 - char* ip_ptr{nullptr}; - if (curl_easy_getinfo(curl_->handle, CURLINFO_PRIMARY_IP, &ip_ptr) == CURLE_OK && ip_ptr) { - primary_ip = ip_ptr; - } -#endif -#if LIBCURL_VERSION_NUM >= 0x071500 // 7.21.0 - // Ignored here since libcurl uses a long for this. - // NOLINTNEXTLINE(google-runtime-int) - long port = 0; - if (curl_easy_getinfo(curl_->handle, CURLINFO_PRIMARY_PORT, &port) == CURLE_OK) { - primary_port = port; - } -#endif -} - -std::vector Response::GetCertInfos() const { - assert(curl_); - assert(curl_->handle); - curl_certinfo* ci{nullptr}; - curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci); - - std::vector cert_infos; - for (int i = 0; i < ci->num_of_certs; i++) { - CertInfo cert_info; - // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) - for (curl_slist* slist = ci->certinfo[i]; slist; slist = slist->next) { - cert_info.emplace_back(std::string{slist->data}); - } - cert_infos.emplace_back(cert_info); - } - return cert_infos; -} -} // namespace cpr diff --git a/vendor/cpr/cpr/session.cpp b/vendor/cpr/cpr/session.cpp deleted file mode 100644 index a62c8dd53..000000000 --- a/vendor/cpr/cpr/session.cpp +++ /dev/null @@ -1,1146 +0,0 @@ -#include "cpr/session.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cpr/accept_encoding.h" -#include "cpr/async.h" -#include "cpr/auth.h" -#include "cpr/bearer.h" -#include "cpr/body.h" -#include "cpr/body_view.h" -#include "cpr/callback.h" -#include "cpr/connect_timeout.h" -#include "cpr/connection_pool.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/curlholder.h" -#include "cpr/error.h" -#include "cpr/file.h" -#include "cpr/filesystem.h" // IWYU pragma: keep -#include "cpr/http_version.h" -#include "cpr/interceptor.h" -#include "cpr/interface.h" -#include "cpr/limit_rate.h" -#include "cpr/local_port.h" -#include "cpr/local_port_range.h" -#include "cpr/low_speed.h" -#include "cpr/multipart.h" -#include "cpr/parameters.h" -#include "cpr/payload.h" -#include "cpr/proxies.h" -#include "cpr/proxyauth.h" -#include "cpr/range.h" -#include "cpr/redirect.h" -#include "cpr/reserve_size.h" -#include "cpr/resolve.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/util.h" -#include "cpr/verbose.h" - -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION -#include "cpr/ssl_ctx.h" -#endif - - -namespace cpr { -// Ignored here since libcurl reqires a long: -// NOLINTNEXTLINE(google-runtime-int) -constexpr long ON = 1L; -// Ignored here since libcurl reqires a long: -// NOLINTNEXTLINE(google-runtime-int) -constexpr long OFF = 0L; - -CURLcode Session::DoEasyPerform() { - if (isUsedInMultiPerform) { - std::cerr << "curl_easy_perform cannot be executed if the CURL handle is used in a MultiPerform.\n"; - return CURLcode::CURLE_FAILED_INIT; - } - return curl_easy_perform(curl_->handle); -} - -void Session::prepareHeader() { - 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; - } - } - - // libcurl would prepare the header "Expect: 100-continue" by default when uploading files larger than 1 MB. - // Here we would like to disable this feature: - curl_slist* temp = curl_slist_append(chunk, "Expect:"); - if (temp) { - chunk = temp; - } - - curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk); - - curl_slist_free_all(curl_->chunk); - curl_->chunk = chunk; -} - -void Session::prepareProxy() { - const std::string protocol = url_.str().substr(0, url_.str().find(':')); - if (proxies_.has(protocol)) { - curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); - if (proxyAuth_.has(protocol)) { - curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERNAME, proxyAuth_.GetUsernameUnderlying(protocol).c_str()); - curl_easy_setopt(curl_->handle, CURLOPT_PROXYPASSWORD, proxyAuth_.GetPasswordUnderlying(protocol).c_str()); - } - } -} - -// Only supported with libcurl >= 7.61.0. -// As an alternative use SetHeader and add the token manually. -#if LIBCURL_VERSION_NUM >= 0x073D00 -void Session::SetBearer(const Bearer& token) { - // Ignore here since this has been defined by libcurl. - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER); - curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken()); -} -#endif - -Session::Session() : curl_(new CurlHolder()) { - // Set up some sensible defaults - curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW); - const std::string version = "curl/" + std::string{version_info->version}; - curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str()); - SetRedirect(Redirect()); - curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data()); - curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, ""); -#ifdef CPR_CURL_NOSIGNAL - curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L); -#endif - -#if LIBCURL_VERSION_NUM >= 0x071900 // 7.25.0 - curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L); -#endif - current_interceptor_ = interceptors_.end(); - first_interceptor_ = interceptors_.end(); -} - -Response Session::makeDownloadRequest() { - const std::optional r = intercept(); - if (r.has_value()) { - return r.value(); - } - - const CURLcode curl_error = DoEasyPerform(); - - return CompleteDownload(curl_error); -} - -void Session::prepareCommonShared() { - assert(curl_->handle); - - // Set Header: - prepareHeader(); - - // URL parameter: - const std::string parametersContent = parameters_.GetContent(*curl_); - if (!parametersContent.empty()) { - const 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: - prepareProxy(); - - // handle NO_PROXY override passed through Proxies object - // Example: Proxies{"no_proxy": ""} will override environment variable definition with an empty list - const std::array no_proxy{"no_proxy", "NO_PROXY"}; - for (const auto& item : no_proxy) { // cppcheck-suppress useStlAlgorithm - if (proxies_.has(item)) { // cppcheck-suppress useStlAlgorithm - curl_easy_setopt(curl_->handle, CURLOPT_NOPROXY, proxies_[item].c_str()); - break; - } - } - -#if LIBCURL_VERSION_NUM >= 0x071506 // 7.21.6 - if (acceptEncoding_.empty()) { - // Enable all supported built-in compressions - curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, ""); - } else if (acceptEncoding_.disabled()) { - // Disable curl adding the 'Accept-Encoding' header - curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, nullptr); - } else { - curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str()); - } -#endif - - curl_->error[0] = '\0'; - - // Clear the response - response_string_.clear(); - if (response_string_reserve_size_ > 0) { - response_string_.reserve(response_string_reserve_size_); - } - - // Enable so we are able to retrieve certificate information: - curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L); -} - -void Session::prepareCommon() { - assert(curl_->handle); - - // Everything else: - prepareCommonShared(); - - // Set Content: - prepareBodyPayloadOrMultipart(); - - if (!cbs_->writecb_.callback && !cbs_->ssecb_.callback) { - curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction); - curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string_); - } - - header_string_.clear(); - if (!cbs_->headercb_.callback) { - curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); - curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_); - } -} - -void Session::prepareCommonDownload() { - assert(curl_->handle); - - // Everything else: - prepareCommonShared(); - - header_string_.clear(); - if (cbs_->headercb_.callback) { - curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); - curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &cbs_->headercb_); - } else { - curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); - curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_); - } -} - -Response Session::makeRequest() { - const std::optional r = intercept(); - if (r.has_value()) { - return r.value(); - } - - const CURLcode curl_error = DoEasyPerform(); - - return Complete(curl_error); -} - -void Session::SetLimitRate(const LimitRate& limit_rate) { - curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate); - curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate); -} - -const Content& Session::GetContent() const { - return content_; -} - -void Session::RemoveContent() { - // inverse function to prepareBodyPayloadOrMultipart() - if (std::holds_alternative(content_) || std::holds_alternative(content_)) { - // set default values, so curl does not send a body in subsequent requests - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, -1); - curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, nullptr); - } else if (std::holds_alternative(content_)) { - if (curl_->multipart) { - // remove multipart data - curl_mime_free(curl_->multipart); - curl_->multipart = nullptr; - } - } else if (std::holds_alternative(content_)) { - // set default values, so curl does not send a body in subsequent requests - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, -1); - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr); - } - content_ = std::monostate{}; -} - -void Session::SetReadCallback(const ReadCallback& read) { - cbs_->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, &cbs_->readcb_); - chunkedTransferEncoding_ = read.size == -1; -} - -void Session::SetHeaderCallback(const HeaderCallback& header) { - curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); - cbs_->headercb_ = header; - curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &cbs_->headercb_); -} - -void Session::SetWriteCallback(const WriteCallback& write) { - curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction); - cbs_->writecb_ = write; - curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &cbs_->writecb_); -} - -void Session::SetServerSentEventCallback(const ServerSentEventCallback& sse) { - curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeSSEFunction); - cbs_->ssecb_ = sse; - curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &cbs_->ssecb_); -} - -void Session::SetProgressCallback(const ProgressCallback& progress) { - cbs_->progresscb_ = progress; - if (isCancellable) { - cbs_->cancellationcb_.SetProgressCallback(cbs_->progresscb_); - return; - } -#if LIBCURL_VERSION_NUM < 0x072000 // 7.32.0 - curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction); - curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &cbs_->progresscb_); -#else - curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction); - curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &cbs_->progresscb_); -#endif - curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L); -} - -void Session::SetDebugCallback(const DebugCallback& debug) { - curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction); - cbs_->debugcb_ = debug; - curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &cbs_->debugcb_); - curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); -} - -void Session::SetUrl(const Url& url) { - url_ = url; -} - -void Session::SetResolve(const Resolve& resolve) { - SetResolves({resolve}); -} - -void Session::SetResolves(const std::vector& resolves) { - curl_slist_free_all(curl_->resolveCurlList); - curl_->resolveCurlList = nullptr; - for (const Resolve& resolve : resolves) { - for (const uint16_t port : resolve.ports) { - curl_->resolveCurlList = curl_slist_append(curl_->resolveCurlList, (resolve.host + ":" + std::to_string(port) + ":" + resolve.addr).c_str()); - } - } - curl_easy_setopt(curl_->handle, CURLOPT_RESOLVE, curl_->resolveCurlList); -} - -void Session::SetParameters(const Parameters& parameters) { - parameters_ = parameters; -} - -void Session::SetParameters(Parameters&& parameters) { - parameters_ = std::move(parameters); -} - -void Session::SetHeader(const Header& header) { - header_ = header; -} - -void Session::UpdateHeader(const Header& header) { - for (const std::pair& item : header) { - header_[item.first] = item.second; - } -} - -Header& Session::GetHeader() { - return header_; -} - -const Header& Session::GetHeader() const { - return header_; -} - -void Session::SetTimeout(const Timeout& timeout) { - curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds()); -} - -void Session::SetConnectTimeout(const ConnectTimeout& timeout) { - curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds()); -} - -void Session::SetConnectionPool(const ConnectionPool& pool) { - CURL* curl = curl_->handle; - pool.SetupHandler(curl); -} - -void Session::SetAuth(const Authentication& auth) { - // Ignore here since this has been defined by libcurl. - switch (auth.GetAuthMode()) { - case AuthMode::BASIC: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - case AuthMode::DIGEST: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - case AuthMode::NTLM: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - case AuthMode::NEGOTIATE: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - case AuthMode::ANY: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - case AuthMode::ANYSAFE: - curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); - curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); - break; - } -} - -void Session::SetUserAgent(const UserAgent& ua) { - curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str()); -} - -void Session::SetPayload(const Payload& payload) { - content_ = payload; -} - -void Session::SetPayload(Payload&& payload) { - content_ = std::move(payload); -} - -void Session::SetProxies(const Proxies& proxies) { - proxies_ = proxies; -} - -void Session::SetProxies(Proxies&& proxies) { - proxies_ = std::move(proxies); -} - -void Session::SetProxyAuth(ProxyAuthentication&& proxy_auth) { - proxyAuth_ = std::move(proxy_auth); -} - -void Session::SetProxyAuth(const ProxyAuthentication& proxy_auth) { - proxyAuth_ = proxy_auth; -} - -void Session::SetMultipart(const Multipart& multipart) { - content_ = multipart; -} - -void Session::SetMultipart(Multipart&& multipart) { - content_ = std::move(multipart); -} - -void Session::SetRedirect(const Redirect& redirect) { - curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, redirect.follow ? 1L : 0L); - curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, redirect.maximum); - curl_easy_setopt(curl_->handle, CURLOPT_UNRESTRICTED_AUTH, redirect.cont_send_cred ? 1L : 0L); - - // NOLINTNEXTLINE (google-runtime-int) - long mask = 0; - if (any(redirect.post_flags & PostRedirectFlags::POST_301)) { - mask |= CURL_REDIR_POST_301; - } - if (any(redirect.post_flags & PostRedirectFlags::POST_302)) { - mask |= CURL_REDIR_POST_302; - } - if (any(redirect.post_flags & PostRedirectFlags::POST_303)) { - mask |= CURL_REDIR_POST_303; - } - curl_easy_setopt(curl_->handle, CURLOPT_POSTREDIR, mask); -} - -void Session::SetCookies(const Cookies& cookies) { - curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL"); - curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str()); -} - -void Session::SetBody(const Body& body) { - content_ = body; -} - -void Session::SetBody(Body&& body) { - content_ = std::move(body); -} - -// cppcheck-suppress passedByValue -void Session::SetBodyView(BodyView body) { - static_assert(std::is_trivially_copyable_v, "BodyView expected to be trivially copyable otherwise will need some std::move across codebase"); - content_ = body; -} - -void Session::SetLowSpeed(const LowSpeed& low_speed) { - curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, static_cast(low_speed.limit)); - curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, static_cast(low_speed.time.count())); // cppcheck-suppress y2038-unsafe-call -} - -void Session::SetVerifySsl(const VerifySsl& verify) { - curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF); - curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L); -} - -void Session::SetUnixSocket(const UnixSocket& unix_socket) { - curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString()); -} - -void Session::SetSslOptions(const SslOptions& options) { - if (!options.cert_file.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str()); - if (!options.cert_type.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str()); - } - } -#if SUPPORT_CURLOPT_SSLCERT_BLOB - else if (!options.cert_blob.empty()) { - std::string cert_blob(options.cert_blob); - curl_blob blob{}; - // NOLINTNEXTLINE (readability-container-data-pointer) - blob.data = &cert_blob[0]; - blob.len = cert_blob.length(); - blob.flags = CURL_BLOB_COPY; - curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT_BLOB, &blob); - if (!options.cert_type.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str()); - } - } -#endif - if (!options.key_file.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str()); - if (!options.key_type.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str()); - } - if (!options.key_pass.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str()); - } -#if SUPPORT_CURLOPT_SSLKEY_BLOB - } else if (!options.key_blob.empty()) { - std::string key_blob(options.key_blob); - curl_blob blob{}; - // NOLINTNEXTLINE (readability-container-data-pointer) - blob.data = &key_blob[0]; - blob.len = key_blob.length(); - blob.flags = CURL_BLOB_COPY; - curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY_BLOB, &blob); - if (!options.key_type.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str()); - } - if (!options.key_pass.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str()); - } -#endif - } - if (!options.pinned_public_key.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_PINNEDPUBLICKEY, options.pinned_public_key.c_str()); - } -#if SUPPORT_ALPN - curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF); -#endif -#if SUPPORT_NPN - curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF); -#endif - curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF); - curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L); -#if LIBCURL_VERSION_NUM >= 0x072900 // 7.41.0 - curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF); -#endif - - int maxTlsVersion = options.ssl_version; -#if SUPPORT_MAX_TLS_VERSION - maxTlsVersion |= options.max_version; -#endif - - curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION, - // Ignore here since this has been defined by libcurl. - maxTlsVersion); - - // NOLINTNEXTLINE (google-runtime-int) - long curlSslOptions = 0; -#if SUPPORT_SSL_NO_REVOKE - sslNoRevoke_ = options.ssl_no_revoke; - if (options.ssl_no_revoke) { - curlSslOptions |= CURLSSLOPT_NO_REVOKE; - } -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 // 7.71.0 - // Fix loading certs from Windows cert store when using OpenSSL: - curlSslOptions |= CURLSSLOPT_NATIVE_CA; -#endif - curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, curlSslOptions); - - if (!options.ca_info.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str()); - } -#if SUPPORT_CURLOPT_CAINFO_BLOB - if (!options.ca_info_blob.empty()) { - std::string cainfo_blob(options.ca_info_blob); - curl_blob blob{}; - blob.data = cainfo_blob.data(); - blob.len = cainfo_blob.length(); - blob.flags = CURL_BLOB_COPY; - curl_easy_setopt(curl_->handle, CURLOPT_CAINFO_BLOB, &blob); - } -#endif - if (!options.ca_path.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str()); - } -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION -#ifdef OPENSSL_BACKEND_USED - if (!options.ca_buffer.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function_load_ca_cert_from_buffer); - curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, options.ca_buffer.c_str()); - } -#endif -#endif - if (!options.crl_file.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str()); - } - if (!options.ciphers.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str()); - } -#if SUPPORT_TLSv13_CIPHERS - if (!options.tls13_ciphers.empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.tls13_ciphers.c_str()); - } -#endif -#if SUPPORT_SESSIONID_CACHE - curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, options.session_id_cache ? ON : OFF); -#endif -} - -void Session::SetVerbose(const Verbose& verbose) { - curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF); -} - -void Session::SetInterface(const Interface& iface) { - if (iface.str().empty()) { - curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, nullptr); - } else { - curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, iface.c_str()); - } -} - -void Session::SetLocalPort(const LocalPort& local_port) { - curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORT, static_cast(static_cast(local_port))); -} - -void Session::SetLocalPortRange(const LocalPortRange& local_port_range) { - curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORTRANGE, static_cast(static_cast(local_port_range))); -} - -void Session::SetHttpVersion(const HttpVersion& version) { - switch (version.code) { - case HttpVersionCode::VERSION_NONE: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE); - break; - - case HttpVersionCode::VERSION_1_0: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); - break; - - case HttpVersionCode::VERSION_1_1: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - break; - -#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0 - case HttpVersionCode::VERSION_2_0: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); - break; -#endif - -#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0 - case HttpVersionCode::VERSION_2_0_TLS: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); - break; -#endif - -#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0 - case HttpVersionCode::VERSION_2_0_PRIOR_KNOWLEDGE: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); - break; -#endif - -#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0 - case HttpVersionCode::VERSION_3_0: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3); - break; -#endif -#if LIBCURL_VERSION_NUM >= 0x075701 // 7.87.1, but corresponds to 7.88.0 tag - case HttpVersionCode::VERSION_3_0_ONLY: - curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY); - break; -#endif - - default: // Should not happen - throw std::invalid_argument("Invalid/Unknown HTTP version type."); - } -} - -void Session::SetRange(const Range& range) { - const std::string range_str = range.str(); - curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str()); -} - -void Session::SetMultiRange(const MultiRange& multi_range) { - const std::string multi_range_str = multi_range.str(); - curl_easy_setopt(curl_->handle, CURLOPT_RANGE, multi_range_str.c_str()); -} - -void Session::SetReserveSize(const ReserveSize& reserve_size) { - ResponseStringReserve(reserve_size.size); -} - -void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) { - acceptEncoding_ = accept_encoding; -} - -void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) { - acceptEncoding_ = std::move(accept_encoding); -} - -cpr_off_t Session::GetDownloadFileLength() { - cpr_off_t downloadFileLength = -1; - curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); - - prepareProxy(); - - curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1); - if (DoEasyPerform() == CURLE_OK) { - // NOLINTNEXTLINE (google-runtime-int) - long status_code{}; - curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code); - if (200 == status_code) { - curl_easy_getinfo(curl_->handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &downloadFileLength); - } - } - return downloadFileLength; -} - -void Session::ResponseStringReserve(size_t size) { - response_string_reserve_size_ = size; -} - -Response Session::Delete() { - PrepareDelete(); - return makeRequest(); -} - -Response Session::Download(const WriteCallback& write) { - PrepareDownload(write); - return makeDownloadRequest(); -} - -Response Session::Download(std::ofstream& file) { - PrepareDownload(file); - return makeDownloadRequest(); -} - -Response Session::Get() { - PrepareGet(); - return makeRequest(); -} - -Response Session::Head() { - PrepareHead(); - return makeRequest(); -} - -Response Session::Options() { - PrepareOptions(); - return makeRequest(); -} - -Response Session::Patch() { - PreparePatch(); - return makeRequest(); -} - -Response Session::Post() { - PreparePost(); - return makeRequest(); -} - -Response Session::Put() { - PreparePut(); - return makeRequest(); -} - -std::shared_ptr Session::GetSharedPtrFromThis() { - try { - return shared_from_this(); - } catch (std::bad_weak_ptr&) { - throw std::runtime_error("Failed to get a shared pointer from this. The reason is probably that the session object is not managed by a shared pointer, which is required to use this functionality."); - } -} - -AsyncResponse Session::GetAsync() { - auto shared_this = shared_from_this(); - return async([shared_this]() { return shared_this->Get(); }); -} - -AsyncResponse Session::DeleteAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Delete(); }); -} - -AsyncResponse Session::DownloadAsync(const WriteCallback& write) { - return async([shared_this = GetSharedPtrFromThis(), write]() { return shared_this->Download(write); }); -} - -AsyncResponse Session::DownloadAsync(std::ofstream& file) { - return async([shared_this = GetSharedPtrFromThis(), &file]() { return shared_this->Download(file); }); -} - -AsyncResponse Session::HeadAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Head(); }); -} - -AsyncResponse Session::OptionsAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Options(); }); -} - -AsyncResponse Session::PatchAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Patch(); }); -} - -AsyncResponse Session::PostAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Post(); }); -} - -AsyncResponse Session::PutAsync() { - return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Put(); }); -} - -std::shared_ptr Session::GetCurlHolder() { - return curl_; -} - -std::string Session::GetFullRequestUrl() { - const std::string parametersContent = parameters_.GetContent(*curl_); - return url_.str() + (parametersContent.empty() ? "" : "?") + parametersContent; -} - -void Session::PrepareDelete() { - curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE"); - prepareCommon(); -} - -void Session::PrepareGet() { - // In case there is a body or payload for this request, we create a custom GET-Request since a - // GET-Request with body is based on the HTTP RFC **not** a leagal request. - if (hasBodyOrPayload()) { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET"); - } else { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); - curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L); - } - prepareCommon(); -} - -void Session::PrepareHead() { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); - prepareCommon(); -} - -void Session::PrepareOptions() { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS"); - prepareCommon(); -} - -void Session::PreparePatch() { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH"); - prepareCommon(); -} - -void Session::PreparePost() { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - - // In case there is no body or payload set it to an empty post: - if (hasBodyOrPayload()) { - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); - } else { - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, cbs_->readcb_.callback ? nullptr : ""); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST"); - } - prepareCommon(); -} - -void Session::PreparePut() { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - if (!hasBodyOrPayload() && cbs_->readcb_.callback) { - /** - * Yes, this one has to be CURLOPT_POSTFIELDS even if we are performing a PUT request. - * In case we don't set this one, performing a POST-request with PUT won't work. - * It in theory this only enforces the usage of the readcallback for POST requests, but works here as well. - **/ - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr); - } - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(curl_->handle, CURLOPT_RANGE, nullptr); - prepareCommon(); -} - -void Session::PrepareDownload(std::ofstream& file) { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); - curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction); - curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); - - prepareCommonDownload(); -} - -void Session::PrepareDownload(const WriteCallback& write) { - curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); - curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); - curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); - - SetWriteCallback(write); - - prepareCommonDownload(); -} - -Response Session::Complete(CURLcode curl_error) { - curl_slist* raw_cookies{nullptr}; - curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); - Cookies cookies = util::parseCookies(raw_cookies); - curl_slist_free_all(raw_cookies); - - std::string errorMsg = curl_->error.data(); - return Response(curl_, std::move(response_string_), std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg))); -} - -Response Session::CompleteDownload(CURLcode curl_error) { - if (!cbs_->headercb_.callback) { - curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, nullptr); - curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, 0); - } - - curl_slist* raw_cookies{nullptr}; - curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); - Cookies cookies = util::parseCookies(raw_cookies); - curl_slist_free_all(raw_cookies); - std::string errorMsg = curl_->error.data(); - - return Response(curl_, "", std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg))); -} - -void Session::AddInterceptor(const std::shared_ptr& pinterceptor) { - // Shall only add before first interceptor run - assert(current_interceptor_ == interceptors_.end()); - interceptors_.push_back(pinterceptor); - first_interceptor_ = interceptors_.begin(); -} - -Response Session::proceed() { - prepareCommon(); - return makeRequest(); -} - -const std::optional Session::intercept() { - if (current_interceptor_ == interceptors_.end()) { - current_interceptor_ = first_interceptor_; - } else { - ++current_interceptor_; - } - - if (current_interceptor_ != interceptors_.end()) { - auto icpt = current_interceptor_; - // Nested makeRequest() start at first_interceptor_, thus excluding previous interceptors. - first_interceptor_ = current_interceptor_; - ++first_interceptor_; - - const std::optional r = (*current_interceptor_)->intercept(*this); - - first_interceptor_ = icpt; - - return r; - } - return std::nullopt; -} - -void Session::prepareBodyPayloadOrMultipart() const { - // Either a body, multipart or a payload is allowed. Inverse function to RemoveContent() - - if (std::holds_alternative(content_)) { - const std::string payload = std::get(content_).GetContent(*curl_); - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast(payload.length())); - curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, payload.c_str()); - } else if (std::holds_alternative(content_)) { - const std::string& body = std::get(content_).str(); - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast(body.length())); - curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str()); - } else if (std::holds_alternative(content_)) { - const std::string_view body = std::get(content_).str(); - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast(body.length())); - // NOLINTNEXTLINE (bugprone-suspicious-stringview-data-usage) - curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.data()); - } else if (std::holds_alternative(content_)) { - // Make sure, we have a empty multipart to start with: - if (curl_->multipart) { - curl_mime_free(curl_->multipart); - } - curl_->multipart = curl_mime_init(curl_->handle); - - // Add all multipart pieces: - const cpr::Multipart& multipart = std::get(content_); - for (const Part& part : multipart.parts) { - if (part.is_file) { - for (const File& file : part.files) { - curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart); - if (!part.content_type.empty()) { - curl_mime_type(mimePart, part.content_type.c_str()); - } - - curl_mime_filedata(mimePart, file.filepath.c_str()); - curl_mime_name(mimePart, part.name.c_str()); - - if (file.hasOverridenFilename()) { - curl_mime_filename(mimePart, file.overriden_filename.c_str()); - } else { - // NOLINTNEXTLINE (misc-include-cleaner) - curl_mime_filename(mimePart, fs::path(file.filepath).filename().string().c_str()); - } - } - } else { - curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart); - if (!part.content_type.empty()) { - curl_mime_type(mimePart, part.content_type.c_str()); - } - if (part.is_buffer) { - // Do not use formdata, to prevent having to use reinterpreter_cast: - curl_mime_name(mimePart, part.name.c_str()); - curl_mime_data(mimePart, part.data, part.datalen); - curl_mime_filename(mimePart, part.value.c_str()); - } else { - curl_mime_name(mimePart, part.name.c_str()); - curl_mime_data(mimePart, part.value.c_str(), CURL_ZERO_TERMINATED); - } - } - } - - curl_easy_setopt(curl_->handle, CURLOPT_MIMEPOST, curl_->multipart); - } -} - -[[nodiscard]] bool Session::hasBodyOrPayload() const { - return std::holds_alternative(content_) || std::holds_alternative(content_) || std::holds_alternative(content_); -} - -// clang-format off -void Session::SetOption(const Resolve& resolve) { SetResolve(resolve); } -void Session::SetOption(const std::vector& resolves) { SetResolves(resolves); } -void Session::SetOption(const ReadCallback& read) { SetReadCallback(read); } -void Session::SetOption(const HeaderCallback& header) { SetHeaderCallback(header); } -void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); } -void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); } -void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); } -void Session::SetOption(const ServerSentEventCallback& sse) { SetServerSentEventCallback(sse); } -void Session::SetOption(const Url& url) { SetUrl(url); } -void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); } -void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); } -void Session::SetOption(const Header& header) { SetHeader(header); } -void Session::SetOption(const Timeout& timeout) { SetTimeout(timeout); } -void Session::SetOption(const ConnectTimeout& timeout) { SetConnectTimeout(timeout); } -void Session::SetOption(const Authentication& auth) { SetAuth(auth); } -void Session::SetOption(const LimitRate& limit_rate) { SetLimitRate(limit_rate); } -// Only supported with libcurl >= 7.61.0. -// As an alternative use SetHeader and add the token manually. -#if LIBCURL_VERSION_NUM >= 0x073D00 -void Session::SetOption(const Bearer& auth) { SetBearer(auth); } -#endif -void Session::SetOption(const UserAgent& ua) { SetUserAgent(ua); } -void Session::SetOption(const Payload& payload) { SetPayload(payload); } -void Session::SetOption(Payload&& payload) { SetPayload(std::move(payload)); } -void Session::SetOption(const Proxies& proxies) { SetProxies(proxies); } -void Session::SetOption(Proxies&& proxies) { SetProxies(std::move(proxies)); } -void Session::SetOption(ProxyAuthentication&& proxy_auth) { SetProxyAuth(std::move(proxy_auth)); } -void Session::SetOption(const ProxyAuthentication& proxy_auth) { SetProxyAuth(proxy_auth); } -void Session::SetOption(const Multipart& multipart) { SetMultipart(multipart); } -void Session::SetOption(Multipart&& multipart) { SetMultipart(std::move(multipart)); } -void Session::SetOption(const Redirect& redirect) { SetRedirect(redirect); } -void Session::SetOption(const Cookies& cookies) { SetCookies(cookies); } -void Session::SetOption(const Body& body) { SetBody(body); } -void Session::SetOption(Body&& body) { SetBody(std::move(body)); } -// cppcheck-suppress passedByValue -void Session::SetOption(BodyView body) { SetBodyView(body); } -void Session::SetOption(const LowSpeed& low_speed) { SetLowSpeed(low_speed); } -void Session::SetOption(const VerifySsl& verify) { SetVerifySsl(verify); } -void Session::SetOption(const Verbose& verbose) { SetVerbose(verbose); } -void Session::SetOption(const UnixSocket& unix_socket) { SetUnixSocket(unix_socket); } -void Session::SetOption(const SslOptions& options) { SetSslOptions(options); } -void Session::SetOption(const Interface& iface) { SetInterface(iface); } -void Session::SetOption(const LocalPort& local_port) { SetLocalPort(local_port); } -void Session::SetOption(const LocalPortRange& local_port_range) { SetLocalPortRange(local_port_range); } -void Session::SetOption(const HttpVersion& version) { SetHttpVersion(version); } -void Session::SetOption(const Range& range) { SetRange(range); } -void Session::SetOption(const MultiRange& multi_range) { SetMultiRange(multi_range); } -void Session::SetOption(const ReserveSize& reserve_size) { SetReserveSize(reserve_size.size); } -void Session::SetOption(const AcceptEncoding& accept_encoding) { SetAcceptEncoding(accept_encoding); } -void Session::SetOption(AcceptEncoding&& accept_encoding) { SetAcceptEncoding(std::move(accept_encoding)); } -void Session::SetOption(const ConnectionPool& pool) { SetConnectionPool(pool); } -// clang-format on - -void Session::SetCancellationParam(std::shared_ptr param) { - cbs_->cancellationcb_ = CancellationCallback{std::move(param)}; - isCancellable = true; -#if LIBCURL_VERSION_NUM < 0x072000 // 7.32.0 - curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction); - curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &cbs_->cancellationcb_); -#else - curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction); - curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &cbs_->cancellationcb_); -#endif - curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L); -} -} // namespace cpr diff --git a/vendor/cpr/cpr/sse.cpp b/vendor/cpr/cpr/sse.cpp deleted file mode 100644 index 05ab06fe8..000000000 --- a/vendor/cpr/cpr/sse.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "cpr/sse.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace cpr { - -bool ServerSentEventParser::parse(std::string_view data, const std::function& callback) { - // Append incoming data to buffer - buffer_.append(data); - - // Process complete lines - size_t pos = 0; - while ((pos = buffer_.find('\n')) != std::string::npos) { - std::string line = buffer_.substr(0, pos); - buffer_.erase(0, pos + 1); - - // Remove trailing \r if present (handles both \n and \r\n) - if (!line.empty() && line.back() == '\r') { - line.pop_back(); - } - - if (!processLine(line, callback)) { - return false; - } - } - - return true; -} - -void ServerSentEventParser::reset() { - buffer_.clear(); - current_event_ = ServerSentEvent(); -} - -bool ServerSentEventParser::processLine(const std::string& line, const std::function& callback) { - // Empty line means end of event - if (line.empty()) { - return dispatchEvent(callback); - } - - // Lines starting with ':' are comments, ignore them - if (line[0] == ':') { - return true; - } - - // Find the colon separator - const size_t colon_pos = line.find(':'); - - std::string field; - std::string value; - - if (colon_pos == std::string::npos) { - // No colon, entire line is the field name - field = line; - value = ""; - } else { - field = line.substr(0, colon_pos); - // Skip the colon and optional leading space - size_t value_start = colon_pos + 1; - if (value_start < line.size() && line[value_start] == ' ') { - value_start++; - } - value = line.substr(value_start); - } - - // Process the field - if (field == "event") { - current_event_.event = value; - } else if (field == "data") { - // Multiple data fields are concatenated with newlines - if (!current_event_.data.empty()) { - current_event_.data += '\n'; - } - current_event_.data += value; - } else if (field == "id") { - // Only set id if the value doesn't contain null character - if (value.find('\0') == std::string::npos) { - current_event_.id = value; - } - } else if (field == "retry") { - // Parse retry value as integer - size_t retry_value = 0; - const std::string_view sv(value); - const char* begin = sv.data(); - const char* end = begin + sv.size(); // NOLINT (cppcoreguidelines-pro-bounds-pointer-arithmetic) Required here since Windows and Clang/GCC have different std::string_view iterator implementations - auto [ptr, ec] = std::from_chars(begin, end, retry_value); - if (ec == std::errc()) { - current_event_.retry = retry_value; - } - } - // Unknown fields are ignored per spec - - return true; -} - -bool ServerSentEventParser::dispatchEvent(const std::function& callback) { - // Don't dispatch if data is empty - if (current_event_.data.empty()) { - current_event_ = ServerSentEvent(); - return true; - } - - // Invoke callback with the current event - const bool continue_parsing = callback(std::move(current_event_)); - - // Reset for next event (but keep event type as "message") - current_event_ = ServerSentEvent(); - - return continue_parsing; -} - -bool ServerSentEventCallback::handleData(std::string_view data) { - return parser_.parse(data, [this](ServerSentEvent&& event) { return (*this)(std::move(event)); }); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/ssl_ctx.cpp b/vendor/cpr/cpr/ssl_ctx.cpp deleted file mode 100644 index da5949270..000000000 --- a/vendor/cpr/cpr/ssl_ctx.cpp +++ /dev/null @@ -1,143 +0,0 @@ - -#include "cpr/ssl_ctx.h" -#include "cpr/ssl_options.h" -#include -#include -#include -#include - -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION - -#ifdef OPENSSL_BACKEND_USED - -#include -#include -#include -#include -#include -#include -#include - -// openssl/types.h was added in later version of openssl (starting from 3.0.0) and is therefore not always available. -// This is for example the case on Ubuntu 20.04 or Centos 7. -// We try to include it if available to satisfy clang-tidy. -// Ref: https://github.com/openssl/openssl/commit/50cd4768c6b89c757645f28519236bb989216f8d -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -#include -#else -#include -#endif - -// openssl/pemerr.h was added in 1.1.1a, but not in BoringSSL -// Ref https://github.com/libcpr/cpr/issues/333#issuecomment-2425104338 -#if OPENSSL_VERSION_NUMBER >= 0x1010101fL && !defined(OPENSSL_IS_BORINGSSL) -#include -#endif - -namespace cpr { - -/** - * The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL. - * If an error is returned from the callback no attempt to establish a connection is made and - * the perform operation will return the callback's error code. - * - * Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html - * https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html - */ - -template -struct deleter_from_fn { - template - constexpr void operator()(T* arg) const { - fn(arg); - } -}; - -template -using custom_unique_ptr = std::unique_ptr>; -using x509_ptr = custom_unique_ptr; -using bio_ptr = custom_unique_ptr; - -CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) { - // Check arguments - if (raw_cert_buf == nullptr || sslctx == nullptr) { - std::cerr << "Invalid callback arguments!\n"; - return CURLE_ABORTED_BY_CALLBACK; - } - - // Create a memory BIO using the data of cert_buf - // Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen - char* cert_buf = static_cast(raw_cert_buf); - BIO* bio = BIO_new_mem_buf(cert_buf, -1); - - // Get a pointer to the current certificate verification storage - X509_STORE* store = SSL_CTX_get_cert_store(static_cast(sslctx)); - if (store == nullptr) { - std::cerr << "SSL_CTX_get_cert_store failed!\n"; - ERR_print_errors_fp(stderr); - BIO_free(bio); - return CURLE_ABORTED_BY_CALLBACK; - } - - // Load the PEM formatted certicifate into an X509 structure which OpenSSL can use - // PEM_read_bio_X509 can read multiple certificates from the same buffer in a loop. - // The buffer should be in PEM format, which is a base64 encoded format - // with header and footer lines like - // - // CA 1 - // ============ - // -----BEGIN CERTIFICATE----- - // ... base64 data ... - // -----END CERTIFICATE----- - // - // CA 2 - // ============ - // -----BEGIN CERTIFICATE----- - // ... base64 data ... - // -----END CERTIFICATE----- - // - size_t certs_loaded = 0; - X509* cert = nullptr; - while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr) { - const int status = X509_STORE_add_cert(store, cert); - // Fail if any loaded cert is invalid - if (status == 0) { - std::cerr << "[CPR] while adding certificate to store\n"; - ERR_print_errors_fp(stderr); - BIO_free(bio); - return CURLE_ABORTED_BY_CALLBACK; - } - certs_loaded++; - // Free cert so we can load another one - X509_free(cert); - cert = nullptr; - } - - // NOLINTNEXTLINE(google-runtime-int) Ignored here since it is an API return value - const unsigned long err = ERR_peek_last_error(); - if (certs_loaded == 0 && err != 0) { - // Check if the error is just EOF or an actual parsing error - if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { - // This is expected if the buffer was empty or contains no valid - // PEM certs - std::cerr << "No PEM certificates found or end of stream\n"; - } else { - std::cerr << "PEM_read_bio_X509 failed after loading " << certs_loaded << " certificates\n"; - ERR_print_errors_fp(stderr); - BIO_free(bio); - return CURLE_ABORTED_BY_CALLBACK; - } - } - - // Free the entire bio chain - BIO_free(bio); - - // The CA certificate was loaded successfully into the verification storage - return CURLE_OK; -} - -} // namespace cpr - -#endif // OPENSSL_BACKEND_USED - -#endif // SUPPORT_CURLOPT_SSL_CTX_FUNCTION diff --git a/vendor/cpr/cpr/threadpool.cpp b/vendor/cpr/cpr/threadpool.cpp deleted file mode 100644 index 105c02039..000000000 --- a/vendor/cpr/cpr/threadpool.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "cpr/threadpool.h" -#include -#include -#include -#include -#include -#include -#include - -namespace cpr { - -ThreadPool::ThreadPool(size_t min_threads, size_t max_threads, std::chrono::milliseconds max_idle_ms) : min_thread_num(min_threads), max_thread_num(max_threads), max_idle_time(max_idle_ms) {} - -ThreadPool::~ThreadPool() { - Stop(); -} - -int ThreadPool::Start(size_t start_threads) { - if (status != STOP) { - return -1; - } - status = RUNNING; - start_threads = std::clamp(start_threads, min_thread_num, max_thread_num); - for (size_t i = 0; i < start_threads; ++i) { - CreateThread(); - } - return 0; -} - -int ThreadPool::Stop() { - const std::unique_lock status_lock(status_wait_mutex); - if (status == STOP) { - return -1; - } - - status = STOP; - status_wait_cond.notify_all(); - task_cond.notify_all(); - - for (auto& i : threads) { - if (i.thread->joinable()) { - i.thread->join(); - } - } - - threads.clear(); - cur_thread_num = 0; - idle_thread_num = 0; - return 0; -} - -int ThreadPool::Pause() { - if (status == RUNNING) { - status = PAUSE; - } - return 0; -} - -int ThreadPool::Resume() { - const std::unique_lock status_lock(status_wait_mutex); - if (status == PAUSE) { - status = RUNNING; - status_wait_cond.notify_all(); - } - return 0; -} - -int ThreadPool::Wait() const { - while (true) { - if (status == STOP || (tasks.empty() && idle_thread_num == cur_thread_num)) { - break; - } - std::this_thread::yield(); - } - return 0; -} - -bool ThreadPool::CreateThread() { - if (cur_thread_num >= max_thread_num) { - return false; - } - auto thread = std::make_shared([this] { - bool initialRun = true; - while (status != STOP) { - { - std::unique_lock status_lock(status_wait_mutex); - status_wait_cond.wait(status_lock, [this]() { return status != Status::PAUSE; }); - } - - Task task; - { - std::unique_lock locker(task_mutex); - task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() { return status == STOP || !tasks.empty(); }); - if (status == STOP) { - return; - } - if (tasks.empty()) { - if (cur_thread_num > min_thread_num) { - DelThread(std::this_thread::get_id()); - return; - } - continue; - } - if (!initialRun) { - --idle_thread_num; - } - task = std::move(tasks.front()); - tasks.pop(); - } - if (task) { - task(); - ++idle_thread_num; - initialRun = false; - } - } - }); - AddThread(thread); - return true; -} - -void ThreadPool::AddThread(const std::shared_ptr& thread) { - thread_mutex.lock(); - ++cur_thread_num; - ThreadData data; - data.thread = thread; - data.id = thread->get_id(); - data.status = RUNNING; - data.start_time = std::chrono::steady_clock::now(); - data.stop_time = std::chrono::steady_clock::time_point::max(); - threads.emplace_back(data); - thread_mutex.unlock(); -} - -void ThreadPool::DelThread(std::thread::id id) { - const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - - thread_mutex.lock(); - --cur_thread_num; - --idle_thread_num; - auto iter = threads.begin(); - while (iter != threads.end()) { - if (iter->status == STOP && now > iter->stop_time) { - if (iter->thread->joinable()) { - iter->thread->join(); - iter = threads.erase(iter); - continue; - } - } else if (iter->id == id) { - iter->status = STOP; - iter->stop_time = std::chrono::steady_clock::now(); - } - ++iter; - } - thread_mutex.unlock(); -} - -} // namespace cpr diff --git a/vendor/cpr/cpr/timeout.cpp b/vendor/cpr/cpr/timeout.cpp deleted file mode 100644 index a2a7c90fb..000000000 --- a/vendor/cpr/cpr/timeout.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "cpr/timeout.h" - -#include -#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_v, "Following casting expects milliseconds."); - - // No way around since curl uses a long here. - // NOLINTNEXTLINE(google-runtime-int) - if (ms.count() > static_cast(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() < static_cast(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 deleted file mode 100644 index 3171dbc8f..000000000 --- a/vendor/cpr/cpr/unix_socket.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -#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 deleted file mode 100644 index 8bf5426a2..000000000 --- a/vendor/cpr/cpr/util.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "cpr/util.h" -#include "cpr/callback.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/curlholder.h" -#include "cpr/secure_string.h" -#include "cpr/sse.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_Win32) -#include -#else -#ifdef __clang__ -#pragma clang diagnostic push -#if __has_warning("-Wreserved-macro-identifier") // Not all versions of clang support this flag like the one used on Ubuntu 18.04 -#pragma clang diagnostic ignored "-Wreserved-macro-identifier" -#endif -#pragma clang diagnostic ignored "-Wunused-macros" -#endif -// https://en.cppreference.com/w/c/string/byte/memset -// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp, cppcoreguidelines-macro-usage) -#define __STDC_WANT_LIB_EXT1__ 1 -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -#include -#endif - -namespace cpr::util { - -enum class CurlHTTPCookieField : uint8_t { - Domain = 0, - IncludeSubdomains, - Path, - HttpsOnly, - Expires, - Name, - Value, -}; - -Cookies parseCookies(curl_slist* raw_cookies) { - const int CURL_HTTP_COOKIE_SIZE = static_cast(CurlHTTPCookieField::Value) + 1; - Cookies cookies; - for (curl_slist* nc = raw_cookies; nc; nc = nc->next) { - std::vector tokens = cpr::util::split(nc->data, '\t'); - while (tokens.size() < CURL_HTTP_COOKIE_SIZE) { - tokens.emplace_back(""); - } - const std::time_t expires = sTimestampToT(tokens.at(static_cast(CurlHTTPCookieField::Expires))); - cookies.emplace_back(Cookie{ - tokens.at(static_cast(CurlHTTPCookieField::Name)), - tokens.at(static_cast(CurlHTTPCookieField::Value)), - tokens.at(static_cast(CurlHTTPCookieField::Domain)), - isTrue(tokens.at(static_cast(CurlHTTPCookieField::IncludeSubdomains))), - tokens.at(static_cast(CurlHTTPCookieField::Path)), - isTrue(tokens.at(static_cast(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::istringstream stream(headers); - std::string line; - while (std::getline(stream, line, '\n')) { - 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) { - const size_t pos1 = line.find_first_of("\t "); - size_t pos2 = std::string::npos; - if (pos1 != std::string::npos) { - pos2 = line.find_first_of("\t ", pos1 + 1); - } - if (pos2 != std::string::npos) { - line.erase(0, pos2 + 1); - *reason = line; - } - } - } - header.clear(); - } - - if (!line.empty()) { - const size_t found = line.find(':'); - if (found != std::string::npos) { - std::string value = line.substr(found + 1); - value.erase(0, value.find_first_not_of("\t ")); - 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)(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, void* data) { - size *= nmemb; - static_cast(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(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; -} - -size_t writeSSEFunction(char* ptr, size_t size, size_t nmemb, ServerSentEventCallback* sse) { - size *= nmemb; - return sse->handleData({ptr, size}) ? size : 0; -} - -int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t size, const DebugCallback* debug) { - (*debug)(static_cast(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); - **/ -util::SecureString urlEncode(std::string_view s) { - const 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); - **/ -util::SecureString urlDecode(std::string_view s) { - const CurlHolder holder; // Create a temporary new holder for URL decoding - return holder.urlDecode(s); -} - -bool isTrue(const std::string& s) { - constexpr std::string_view tmp = "true"; - auto [s_it, tmp_it] = std::mismatch(s.begin(), s.end(), tmp.begin(), tmp.end(), [](auto s_c, auto t_c) { return std::tolower(s_c) == t_c; }); - return s_it == s.end() && tmp_it == tmp.end(); -} - -time_t sTimestampToT(const std::string& st) { - // NOLINTNEXTLINE(google-runtime-int) - if (std::is_same_v) { - return static_cast(std::stoul(st)); - } - // NOLINTNEXTLINE(google-runtime-int) - if (std::is_same_v) { - return static_cast(std::stoull(st)); - } - if (std::is_same_v) { - return static_cast(std::stoi(st)); - } - // NOLINTNEXTLINE(google-runtime-int) - if (std::is_same_v) { - return static_cast(std::stol(st)); - } - return static_cast(std::stoll(st)); -} - -} // namespace cpr::util diff --git a/vendor/cpr/include/cpr/accept_encoding.h b/vendor/cpr/include/cpr/accept_encoding.h deleted file mode 100644 index 167d7c2cf..000000000 --- a/vendor/cpr/include/cpr/accept_encoding.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CPR_ACCEPT_ENCODING_H -#define CPR_ACCEPT_ENCODING_H - -#include -#include -#include -#include -#include - -namespace cpr { - -enum class AcceptEncodingMethods { - identity, - deflate, - zlib, - gzip, - disabled, -}; - -// NOLINTNEXTLINE(cert-err58-cpp) -static const std::map AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}}; - -class AcceptEncoding { - public: - AcceptEncoding() = default; - // NOLINTNEXTLINE(google-explicit-constructor) - AcceptEncoding(const std::initializer_list& methods); - // NOLINTNEXTLINE(google-explicit-constructor) - AcceptEncoding(const std::initializer_list& methods); - - [[nodiscard]] bool empty() const noexcept; - [[nodiscard]] const std::string getString() const; - [[nodiscard]] bool disabled() const; - - private: - std::unordered_set methods_; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/api.h b/vendor/cpr/include/cpr/api.h deleted file mode 100644 index fa700bed1..000000000 --- a/vendor/cpr/include/cpr/api.h +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef CPR_API_H -#define CPR_API_H - -#include -#include -#include -#include -#include - -#include "cpr/async.h" -#include "cpr/async_wrapper.h" -#include "cpr/auth.h" -#include "cpr/bearer.h" -#include "cpr/cprtypes.h" -#include "cpr/filesystem.h" -#include "cpr/multipart.h" -#include "cpr/multiperform.h" -#include "cpr/payload.h" -#include "cpr/response.h" -#include "cpr/session.h" - -namespace cpr { - -using AsyncResponse = AsyncWrapper; - -namespace priv { - -template -void set_option_internal(Session& session, CurrentType&& current_option) { - session.SetOption(std::forward(current_option)); -} - -template <> -inline void set_option_internal(Session& session, Header&& current_option) { - // Header option was already provided -> Update previous header - session.UpdateHeader(std::forward
(current_option)); -} - -template -void set_option_internal(Session& session, CurrentType&& current_option, Ts&&... ts) { - set_option_internal(session, std::forward(current_option)); - - if constexpr (std::is_same_v) { - set_option_internal(session, std::forward(ts)...); - } else { - set_option_internal(session, std::forward(ts)...); - } -} - -template -void set_option(Session& session, Ts&&... ts) { - set_option_internal(session, std::forward(ts)...); -} - -// Idea: https://stackoverflow.com/a/19060157 -template -void apply_set_option_internal(Session& session, Tuple&& t, std::index_sequence) { - set_option(session, std::get(std::forward(t))...); -} - -// Idea: https://stackoverflow.com/a/19060157 -template -void apply_set_option(Session& session, Tuple&& t) { - using Indices = std::make_index_sequence>::value>; - apply_set_option_internal(session, std::forward(t), Indices()); -} - -template -void setup_multiperform_internal(MultiPerform& multiperform, T&& t) { - std::shared_ptr session = std::make_shared(); - apply_set_option(*session, t); - multiperform.AddSession(session); -} - -template -void setup_multiperform_internal(MultiPerform& multiperform, T&& t, Ts&&... ts) { - std::shared_ptr session = std::make_shared(); - apply_set_option(*session, t); - multiperform.AddSession(session); - setup_multiperform_internal(multiperform, std::forward(ts)...); -} - -template -void setup_multiperform(MultiPerform& multiperform, Ts&&... ts) { - setup_multiperform_internal(multiperform, std::forward(ts)...); -} - -using session_action_t = cpr::Response (cpr::Session::*)(); - -template -void setup_multiasync(std::vector>& responses, T&& parameters) { - std::shared_ptr cancellation_state = std::make_shared(false); - - std::function execFn{[cancellation_state](T params) { - if (cancellation_state->load()) { - return Response{}; - } - cpr::Session s{}; - s.SetCancellationParam(cancellation_state); - apply_set_option(s, std::forward(params)); - return std::invoke(SessionAction, s); - }}; - responses.emplace_back(GlobalThreadPool::GetInstance()->Submit(std::move(execFn), std::forward(parameters)), std::move(cancellation_state)); -} - -template -void setup_multiasync(std::vector>& responses, T&& head, Ts&&... tail) { - setup_multiasync(responses, std::forward(head)); - if constexpr (sizeof...(Ts) > 0) { - setup_multiasync(responses, std::forward(tail)...); - } -} - -} // 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 cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Get callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto GetCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Post callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto PostCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Put callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto PutCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Head callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto HeadCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Delete callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto DeleteCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Options callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto OptionsCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, 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 cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...); -} - -// Patch callback methods -template -// NOLINTNEXTLINE(fuchsia-trailing-return) -auto PatchCallback(Then then, Ts... ts) { - return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, 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 async method -template -AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) { - return AsyncWrapper{std::async( - std::launch::async, - [](fs::path local_path_, Ts... ts_) { - std::ofstream f(local_path_.c_str()); - return Download(f, std::move(ts_)...); - }, - std::move(local_path), std::move(ts)...)}; -} - -// 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); -} - -// Multi requests -template -std::vector MultiGet(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Get(); -} - -template -std::vector MultiDelete(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Delete(); -} - -template -std::vector MultiPut(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Put(); -} - -template -std::vector MultiHead(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Head(); -} - -template -std::vector MultiOptions(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Options(); -} - -template -std::vector MultiPatch(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Patch(); -} - -template -std::vector MultiPost(Ts&&... ts) { - MultiPerform multiperform; - priv::setup_multiperform(multiperform, std::forward(ts)...); - return multiperform.Post(); -} - -template -std::vector> MultiGetAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward(ts)...); - return ret; -} - -template -std::vector> MultiDeleteAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward(ts)...); - return ret; -} - -template -std::vector> MultiHeadAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward(ts)...); - return ret; -} -template -std::vector> MultiOptionsAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward(ts)...); - return ret; -} - -template -std::vector> MultiPatchAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward(ts)...); - return ret; -} - -template -std::vector> MultiPostAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward(ts)...); - return ret; -} - -template -std::vector> MultiPutAsync(Ts&&... ts) { - std::vector> ret{}; - priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward(ts)...); - return ret; -} - - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/async.h b/vendor/cpr/include/cpr/async.h deleted file mode 100644 index 03a35354b..000000000 --- a/vendor/cpr/include/cpr/async.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef CPR_ASYNC_H -#define CPR_ASYNC_H - -#include "async_wrapper.h" -#include "singleton.h" -#include "threadpool.h" - -namespace cpr { - -class GlobalThreadPool : public ThreadPool { - CPR_SINGLETON_DECL(GlobalThreadPool) - protected: - GlobalThreadPool() = default; - - public: - ~GlobalThreadPool() override = default; -}; - -/** - * Return a wrapper for a future, calling future.get() will wait until the task is done and return RetType. - * async(fn, args...) - * async(std::bind(&Class::mem_fn, &obj)) - * async(std::mem_fn(&Class::mem_fn, &obj)) - **/ -template -auto async(Fn&& fn, Args&&... args) { - std::future future = GlobalThreadPool::GetInstance()->Submit(std::forward(fn), std::forward(args)...); - using async_wrapper_t = AsyncWrapper; - if constexpr (isCancellable) { - return async_wrapper_t{std::move(future), std::make_shared(false)}; - } else { - return async_wrapper_t{std::move(future)}; - } -} - -class async { - public: - static void startup(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME) { - GlobalThreadPool* gtp = GlobalThreadPool::GetInstance(); - if (gtp->IsStarted()) { - return; - } - gtp->SetMinThreadNum(min_threads); - gtp->SetMaxThreadNum(max_threads); - gtp->SetMaxIdleTime(max_idle_ms); - gtp->Start(); - } - - static void cleanup() { - GlobalThreadPool::ExitInstance(); - } -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/async_wrapper.h b/vendor/cpr/include/cpr/async_wrapper.h deleted file mode 100644 index c90ea06c6..000000000 --- a/vendor/cpr/include/cpr/async_wrapper.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef CPR_ASYNC_WRAPPER_H -#define CPR_ASYNC_WRAPPER_H - -#include -#include -#include - -namespace cpr { -enum class [[nodiscard]] CancellationResult : uint8_t { failure, success, invalid_operation }; - -/** - * A class template intended to wrap results of async operations (instances of std::future) - * and also provide extended capablilities relaed to these requests, for example cancellation. - * - * The RAII semantics are the same as std::future - moveable, not copyable. - */ -template -class AsyncWrapper; - -template -class AsyncWrapper { - private: - friend class AsyncWrapper; - std::future future; - - void throw_if_invalid(const char* error) const { - if (!future.valid()) { - throw std::logic_error{error}; - } - } - - public: - // Constructors - AsyncWrapper() = default; - explicit AsyncWrapper(std::future&& f) : future{std::move(f)} {} - - // Copy Semantics - AsyncWrapper(const AsyncWrapper&) = delete; - AsyncWrapper& operator=(const AsyncWrapper&) = delete; - - // Move Semantics - AsyncWrapper(AsyncWrapper&&) noexcept = default; - AsyncWrapper& operator=(AsyncWrapper&&) noexcept = default; - - // Destructor - ~AsyncWrapper() = default; - - // These methods replicate the behaviour of std::future - [[nodiscard]] T get() { - throw_if_invalid("Calling AsyncWrapper::get when the associated future instance is invalid!"); - return future.get(); - } - - [[nodiscard]] bool valid() const noexcept { - return future.valid(); - } - - void wait() const { - throw_if_invalid("Calling AsyncWrapper::wait when the associated future is invalid!"); - future.wait(); - } - - template - std::future_status wait_for(const std::chrono::duration& timeout_duration) const { - throw_if_invalid("Calling AsyncWrapper::wait_for when the associated future is invalid!"); - return future.wait_for(timeout_duration); - } - - template - std::future_status wait_until(const std::chrono::time_point& timeout_time) const { - throw_if_invalid("Calling AsyncWrapper::wait_until when the associated future is invalid!"); - return future.wait_until(timeout_time); - } - - std::shared_future share() noexcept { - return future.share(); - } -}; - -template -class AsyncWrapper : public AsyncWrapper { - private: - using base = AsyncWrapper; - std::shared_ptr is_cancelled; - - void throw_if_cancelled(const char* error) const { - if (is_cancelled->load()) { - throw std::logic_error{error}; - } - } - - public: - // Constructors - AsyncWrapper(std::future&& f, std::shared_ptr&& cancelledState) : base{std::move(f)}, is_cancelled{std::move(cancelledState)} {} - - // Copy Semantics - AsyncWrapper(const AsyncWrapper&) = delete; - AsyncWrapper& operator=(const AsyncWrapper&) = delete; - - // Move Semantics - AsyncWrapper(AsyncWrapper&&) noexcept = default; - AsyncWrapper& operator=(AsyncWrapper&&) noexcept = default; - - // Destructor - ~AsyncWrapper() { - if (is_cancelled) { - is_cancelled->store(true); - } - } - - [[nodiscard]] T get() { - throw_if_cancelled("Calling AsyncWrapper::get on a cancelled request!"); - return base::get(); - } - - [[nodiscard]] bool valid() const noexcept { - return !is_cancelled->load() && base::future.valid(); - } - - void wait() const { - throw_if_cancelled("Calling AsyncWrapper::wait when the associated future is invalid or cancelled!"); - base::wait(); - } - - template - std::future_status wait_for(const std::chrono::duration& timeout_duration) const { - throw_if_cancelled("Calling AsyncWrapper::wait_for when the associated future is cancelled!"); - return base::wait_for(timeout_duration); - } - - template - std::future_status wait_until(const std::chrono::time_point& timeout_time) const { - throw_if_cancelled("Calling AsyncWrapper::wait_until when the associated future is cancelled!"); - return base::wait_until(timeout_time); - } - - // Cancellation-related methods - CancellationResult Cancel() { - if (!base::future.valid() || is_cancelled->load()) { - return CancellationResult::invalid_operation; - } - is_cancelled->store(true); - return CancellationResult::success; - } - - [[nodiscard]] bool IsCancelled() const { - return is_cancelled->load(); - } -}; - -// Deduction guides -template -AsyncWrapper(std::future&&) -> AsyncWrapper; - -template -AsyncWrapper(std::future&&, std::shared_ptr&&) -> AsyncWrapper; - -} // namespace cpr - - -#endif diff --git a/vendor/cpr/include/cpr/auth.h b/vendor/cpr/include/cpr/auth.h deleted file mode 100644 index 830b964a9..000000000 --- a/vendor/cpr/include/cpr/auth.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CPR_AUTH_H -#define CPR_AUTH_H - -#include -#include - -#include "cpr/util.h" - -namespace cpr { - -enum class AuthMode { BASIC, DIGEST, NTLM, NEGOTIATE, ANY, ANYSAFE }; - -class Authentication { - public: - Authentication(std::string_view username, std::string_view password, AuthMode auth_mode); - - const char* GetAuthString() const noexcept; - AuthMode GetAuthMode() const noexcept; - - private: - util::SecureString auth_string_; - AuthMode auth_mode_; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/bearer.h b/vendor/cpr/include/cpr/bearer.h deleted file mode 100644 index 7792dc704..000000000 --- a/vendor/cpr/include/cpr/bearer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CPR_BEARER_H -#define CPR_BEARER_H - -#include -#include - -#include - -#include "cpr/util.h" - -namespace cpr { - -// Only supported with libcurl >= 7.61.0. -// As an alternative use SetHeader and add the token manually. -#if LIBCURL_VERSION_NUM >= 0x073D00 -class Bearer { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Bearer(std::string_view token) : token_string_{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 { - return token_string_.c_str(); - } - - protected: - util::SecureString token_string_; -}; -#endif - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/body.h b/vendor/cpr/include/cpr/body.h deleted file mode 100644 index cea7cdff6..000000000 --- a/vendor/cpr/include/cpr/body.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef CPR_BODY_H -#define CPR_BODY_H - -#include -#include -#include -#include - -#include "cpr/buffer.h" -#include "cpr/cprtypes.h" -#include "cpr/file.h" - -namespace cpr { - -class Body : public StringHolder { - public: - Body() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Body(std::string body) : StringHolder(std::move(body)) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Body(std::string_view body) : StringHolder(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) {} - // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-reinterpret-cast) - Body(const Buffer& buffer) : StringHolder(reinterpret_cast(buffer.data), static_cast(buffer.datalen)) {} - // NOLINTNEXTLINE(google-explicit-constructor) - Body(const File& file) { - std::ifstream is(file.filepath, std::ifstream::binary); - if (!is) { - throw std::invalid_argument("Can't open the file for HTTP request body!"); - } - - is.seekg(0, std::ios::end); - const std::streampos length = is.tellg(); - is.seekg(0, std::ios::beg); - std::string buffer; - buffer.resize(static_cast(length)); - is.read(buffer.data(), length); - str_ = std::move(buffer); - } - 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/body_view.h b/vendor/cpr/include/cpr/body_view.h deleted file mode 100644 index 3bbf73da0..000000000 --- a/vendor/cpr/include/cpr/body_view.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef CPR_BODY_VIEW_H -#define CPR_BODY_VIEW_H - -#include - -#include "cpr/buffer.h" - -namespace cpr { - -class BodyView final { - public: - BodyView() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - BodyView(std::string_view body) : m_body(body) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - BodyView(const char* body) : m_body(body) {} - BodyView(const char* str, size_t len) : m_body(str, len) {} - // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-reinterpret-cast) - BodyView(const Buffer& buffer) : m_body(reinterpret_cast(buffer.data), static_cast(buffer.datalen)) {} - - BodyView(const BodyView& other) = default; - BodyView(BodyView&& old) noexcept = default; - ~BodyView() = default; - - BodyView& operator=(BodyView&& old) noexcept = default; - BodyView& operator=(const BodyView& other) = default; - - [[nodiscard]] std::string_view str() const { return m_body; } - - private: - std::string_view m_body; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/buffer.h b/vendor/cpr/include/cpr/buffer.h deleted file mode 100644 index 7b4ccfcf0..000000000 --- a/vendor/cpr/include/cpr/buffer.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CPR_BUFFER_H -#define CPR_BUFFER_H - -#include - -#include "cpr/filesystem.h" - -namespace cpr { - -struct Buffer { - using data_t = const char*; - - template - Buffer(Iterator begin, Iterator end, fs::path&& p_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(p_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; - size_t datalen; - const fs::path filename; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/callback.h b/vendor/cpr/include/cpr/callback.h deleted file mode 100644 index ababb87f7..000000000 --- a/vendor/cpr/include/cpr/callback.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef CPR_CALLBACK_H -#define CPR_CALLBACK_H - -#include "cprtypes.h" - -#include -#include -#include -#include -#include - -namespace cpr { - -class ReadCallback { - public: - ReadCallback() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - ReadCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{-1}, callback{std::move(p_callback)} {} - ReadCallback(cpr_off_t p_size, std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{p_size}, callback{std::move(p_callback)} {} - bool operator()(char* buffer, size_t& buffer_size) const { - if(!callback) - { - return true; - } - return callback(buffer, buffer_size, userdata); - } - - intptr_t userdata{}; - cpr_off_t size{}; - std::function callback; -}; - -class HeaderCallback { - public: - HeaderCallback() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - HeaderCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - bool operator()(std::string_view header) const { - if(!callback) - { - return true; - } - return callback(header, userdata); - } - - intptr_t userdata{}; - std::function callback; -}; - -class WriteCallback { - public: - WriteCallback() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - WriteCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - bool operator()(std::string_view data) const { - if(!callback) - { - return true; - } - return callback(data, userdata); - } - - intptr_t userdata{}; - std::function callback; -}; - -class ProgressCallback { - public: - ProgressCallback() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - ProgressCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - bool operator()(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow) const { - if(!callback) - { - return true; - } - return callback(downloadTotal, downloadNow, uploadTotal, uploadNow, userdata); - } - - intptr_t userdata{}; - 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 p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - void operator()(InfoType type, std::string_view data) const { - if(!callback) - { - return; - } - callback(type, data, userdata); - } - - intptr_t userdata{}; - std::function callback; -}; - -/** - * Functor class for progress functions that will be used in cancellable requests. - */ -class CancellationCallback { - public: - CancellationCallback() = default; - explicit CancellationCallback(std::shared_ptr&& cs) : cancellation_state{std::move(cs)} {} - - CancellationCallback(std::shared_ptr&& cs, ProgressCallback& u_cb) : cancellation_state{std::move(cs)}, user_cb{std::reference_wrapper{u_cb}} {} - - bool operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const; - - void SetProgressCallback(ProgressCallback& u_cb); - - private: - std::shared_ptr cancellation_state; - std::optional> user_cb; -}; - - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/cert_info.h b/vendor/cpr/include/cpr/cert_info.h deleted file mode 100644 index 4d957b026..000000000 --- a/vendor/cpr/include/cpr/cert_info.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CPR_CERT_INFO_H -#define CPR_CERT_INFO_H - -#include -#include -#include - -namespace cpr { - -class CertInfo { - private: - std::vector cert_info_; - - public: - CertInfo() = default; - CertInfo(const CertInfo& other) = default; - CertInfo(CertInfo&& old) = default; - CertInfo(const std::initializer_list& entry) : cert_info_{entry} {} - ~CertInfo() noexcept = default; - - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - std::string& operator[](const size_t& pos); - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - void emplace_back(const std::string& str); - void push_back(const std::string& str); - void pop_back(); -}; -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/connect_timeout.h b/vendor/cpr/include/cpr/connect_timeout.h deleted file mode 100644 index 546e8a585..000000000 --- a/vendor/cpr/include/cpr/connect_timeout.h +++ /dev/null @@ -1,18 +0,0 @@ -#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/connection_pool.h b/vendor/cpr/include/cpr/connection_pool.h deleted file mode 100644 index b4a758b4f..000000000 --- a/vendor/cpr/include/cpr/connection_pool.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef CPR_CONNECTION_POOL_H -#define CPR_CONNECTION_POOL_H - -#include -#include -#include - -namespace cpr { -/** - * cpr connection pool implementation for sharing connections between HTTP requests. - * - * The ConnectionPool enables connection reuse across multiple HTTP requests to the same host, - * which can significantly improve performance by avoiding the overhead of establishing new - * connections for each request. It uses libcurl's CURLSH (share) interface to manage - * connection sharing in a thread-safe manner. - * - * Example: - * ```cpp - * // Create a connection pool - * cpr::ConnectionPool pool; - * - * // Use the pool with requests to reuse connections - * cpr::Response r1 = cpr::Get(cpr::Url{"http://example.com/api/data"}, pool); - * cpr::Response r2 = cpr::Get(cpr::Url{"http://example.com/api/more"}, pool); - * - * // Or with async requests - * auto future1 = cpr::GetAsync(cpr::Url{"http://example.com/api/data"}, pool); - * auto future2 = cpr::GetAsync(cpr::Url{"http://example.com/api/more"}, pool); - * ``` - **/ -class ConnectionPool { - public: - /** - * Creates a new connection pool with shared connection state. - * Initializes the underlying CURLSH handle and sets up thread-safe locking mechanisms. - **/ - ConnectionPool(); - - /** - * Copy constructor - creates a new connection pool sharing the same connection state. - * Multiple ConnectionPool instances can share the same underlying connection pool. - **/ - ConnectionPool(const ConnectionPool&) = default; - - /** - * Copy assignment operator is deleted to prevent accidental copying. - * Use the copy constructor if you need to share the connection pool. - **/ - ConnectionPool& operator=(const ConnectionPool&) = delete; - - /** - * Configures a CURL easy handle to use this connection pool. - * This method sets up the easy handle to participate in connection sharing - * managed by this pool. - * - * @param easy_handler The CURL easy handle to configure for connection sharing. - **/ - void SetupHandler(CURL* easy_handler) const; - - private: - /** - * Thread-safe mutex used for synchronizing access to shared connections. - * This mutex is passed to libcurl's locking callbacks to ensure thread safety - * when multiple threads access the same connection pool. It's declared first - * to ensure it's destroyed last, after the CURLSH handle that references it. - **/ - std::shared_ptr connection_mutex_; - - /** - * Shared CURL handle (CURLSH) that manages the actual connection sharing. - * This handle maintains the pool of reusable connections and is configured - * with appropriate locking callbacks for thread safety. The shared_ptr uses - * a custom deleter that safely resets the lock/unlock callbacks before - * calling curl_share_cleanup() to prevent use-after-free issues during destruction. - * Declared last to ensure it's destroyed first, before the mutex it references. - **/ - std::shared_ptr curl_sh_; -}; -} // namespace cpr -#endif \ No newline at end of file diff --git a/vendor/cpr/include/cpr/cookies.h b/vendor/cpr/include/cpr/cookies.h deleted file mode 100644 index 052d9a8c0..000000000 --- a/vendor/cpr/include/cpr/cookies.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef CPR_COOKIES_H -#define CPR_COOKIES_H - -#include "cpr/curlholder.h" -#include -#include -#include -#include - -namespace cpr { -/** - * EXPIRES_STRING_SIZE is an explicitly static and const variable that could be only accessed within the same namespace and is immutable. - * To be used for "std::array", the expression must have a constant value, so EXPIRES_STRING_SIZE must be a const value. - **/ -static const std::size_t EXPIRES_STRING_SIZE = 100; - -class Cookie { - public: - Cookie() = default; - /** - * Some notes for the default value used by expires: - * std::chrono::system_clock::time_point::min() won't work on Windows due to the min, max clash there. - * So we fall back to std::chrono::system_clock::from_time_t(0) for the minimum value here. - **/ - Cookie(const std::string& name, const std::string& value, const std::string& domain = "", bool p_isIncludingSubdomains = false, const std::string& path = "/", bool p_isHttpsOnly = false, std::chrono::system_clock::time_point expires = std::chrono::system_clock::from_time_t(0)) : name_{name}, value_{value}, domain_{domain}, includeSubdomains_{p_isIncludingSubdomains}, path_{path}, httpsOnly_{p_isHttpsOnly}, expires_{expires} {} - [[nodiscard]] const std::string& GetDomain() const; - [[nodiscard]] bool IsIncludingSubdomains() const; - [[nodiscard]] const std::string& GetPath() const; - [[nodiscard]] bool IsHttpsOnly() const; - [[nodiscard]] std::chrono::system_clock::time_point GetExpires() const; - [[nodiscard]] std::string GetExpiresString() const; - [[nodiscard]] const std::string& GetName() const; - [[nodiscard]] const std::string& GetValue() const; - - private: - std::string name_; - std::string value_; - std::string domain_; - bool includeSubdomains_{}; - std::string path_; - bool httpsOnly_{}; - /** - * TODO: Update the implementation using `std::chrono::utc_clock` of C++20 - **/ - std::chrono::system_clock::time_point expires_{}; -}; - -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 p_encode = true) : encode{p_encode} {} - Cookies(const std::initializer_list& cookies, bool p_encode = true) : encode{p_encode}, cookies_{cookies} {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Cookies(const cpr::Cookie& cookie, bool p_encode = true) : encode{p_encode}, cookies_{cookie} {} - - cpr::Cookie& operator[](size_t pos); - [[nodiscard]] std::string GetEncoded(const CurlHolder& holder) const; - - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - iterator begin(); - iterator end(); - [[nodiscard]] const_iterator begin() const; - [[nodiscard]] const_iterator end() const; - [[nodiscard]] const_iterator cbegin() const; - [[nodiscard]] const_iterator cend() const; - void emplace_back(const Cookie& str); - [[nodiscard]] bool empty() const; - void push_back(const Cookie& str); - void pop_back(); - - private: - std::vector cookies_; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/cpr.h b/vendor/cpr/include/cpr/cpr.h deleted file mode 100644 index a42058fbd..000000000 --- a/vendor/cpr/include/cpr/cpr.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef CPR_CPR_H -#define CPR_CPR_H - -#include "cpr/api.h" -#include "cpr/auth.h" -#include "cpr/bearer.h" -#include "cpr/callback.h" -#include "cpr/cert_info.h" -#include "cpr/connect_timeout.h" -#include "cpr/connection_pool.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/cprver.h" -#include "cpr/curl_container.h" -#include "cpr/curlholder.h" -#include "cpr/error.h" -#include "cpr/http_version.h" -#include "cpr/interceptor.h" -#include "cpr/interface.h" -#include "cpr/limit_rate.h" -#include "cpr/local_port.h" -#include "cpr/local_port_range.h" -#include "cpr/low_speed.h" -#include "cpr/multipart.h" -#include "cpr/multiperform.h" -#include "cpr/parameters.h" -#include "cpr/payload.h" -#include "cpr/proxies.h" -#include "cpr/proxyauth.h" -#include "cpr/range.h" -#include "cpr/redirect.h" -#include "cpr/reserve_size.h" -#include "cpr/resolve.h" -#include "cpr/response.h" -#include "cpr/session.h" -#include "cpr/sse.h" -#include "cpr/ssl_ctx.h" -#include "cpr/ssl_options.h" -#include "cpr/status_codes.h" -#include "cpr/timeout.h" -#include "cpr/unix_socket.h" -#include "cpr/user_agent.h" -#include "cpr/util.h" -#include "cpr/verbose.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 deleted file mode 100644 index 6692ffd7b..000000000 --- a/vendor/cpr/include/cpr/cprtypes.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef CPR_CPR_TYPES_H -#define CPR_CPR_TYPES_H - -#include -#include -#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; - -/** - * The argument type for progress functions, dependent on libcurl version - **/ -#if LIBCURL_VERSION_NUM < 0x072000 -using cpr_pf_arg_t = double; -#else -using cpr_pf_arg_t = cpr_off_t; -#endif - -template -class StringHolder { - public: - StringHolder() = default; - explicit StringHolder(std::string str) : str_(std::move(str)) {} - explicit StringHolder(std::string_view str) : str_(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_; - } - [[nodiscard]] const std::string& str() const { - return str_; - } - [[nodiscard]] const char* c_str() const { - return str_.c_str(); - } - [[nodiscard]] 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(std::string url) : StringHolder(std::move(url)) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Url(std::string_view url) : StringHolder(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 deleted file mode 100644 index 3f80586a4..000000000 --- a/vendor/cpr/include/cpr/curl_container.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef CURL_CONTAINER_H -#define CURL_CONTAINER_H - -#include -#include -#include -#include - -#include "cpr/curlholder.h" - - -namespace cpr { - -struct Parameter { - Parameter(std::string p_key, std::string p_value) : key{std::move(p_key)}, value{std::move(p_value)} {} - - std::string key; - std::string value; -}; - -struct Pair { - 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&); - - /** - * Returns the URL using curl_easy_escape(...) for escaping the given parameters. - * Requires `CurlHolder`. - **/ - const std::string GetContent(const CurlHolder&) const; - - /** - * Returns the URL while ignoring `encode`. This allows calling without - * active `CurlHolder`. - **/ - const std::string GetContent() const; - - protected: - std::vector containerList_; -}; - -} // namespace cpr - -#endif // diff --git a/vendor/cpr/include/cpr/curlholder.h b/vendor/cpr/include/cpr/curlholder.h deleted file mode 100644 index 75aff10cd..000000000 --- a/vendor/cpr/include/cpr/curlholder.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef CPR_CURL_HOLDER_H -#define CPR_CURL_HOLDER_H - -#include -#include -#include - -#include "cpr/secure_string.h" - -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 - **/ - - // Avoids initalization order problems in a static build - static std::mutex& curl_easy_init_mutex_() { - static std::mutex curl_easy_init_mutex_; - return curl_easy_init_mutex_; - } - - public: - CURL* handle{nullptr}; - struct curl_slist* chunk{nullptr}; - struct curl_slist* resolveCurlList{nullptr}; - curl_mime* multipart{nullptr}; - std::array error{}; - - CurlHolder(); - CurlHolder(const CurlHolder& other) = delete; - CurlHolder(CurlHolder&& old) noexcept; - ~CurlHolder(); - - CurlHolder& operator=(const CurlHolder& other) = delete; - CurlHolder& operator=(CurlHolder&& old) noexcept; - - /** - * Uses curl_easy_escape(...) for escaping the given string. - **/ - [[nodiscard]] util::SecureString urlEncode(std::string_view s) const; - - /** - * Uses curl_easy_unescape(...) for unescaping the given string. - **/ - [[nodiscard]] util::SecureString urlDecode(std::string_view s) const; -}; -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/curlmultiholder.h b/vendor/cpr/include/cpr/curlmultiholder.h deleted file mode 100644 index 401df0eb6..000000000 --- a/vendor/cpr/include/cpr/curlmultiholder.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CPR_CURLMULTIHOLDER_H -#define CPR_CURLMULTIHOLDER_H - -#include - -namespace cpr { - -class CurlMultiHolder { - public: - CurlMultiHolder(); - ~CurlMultiHolder(); - - CURLM* handle{nullptr}; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/error.h b/vendor/cpr/include/cpr/error.h deleted file mode 100644 index 0548ba9e4..000000000 --- a/vendor/cpr/include/cpr/error.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef CPR_ERROR_H -#define CPR_ERROR_H - -#include -#include -#include - -#include "cpr/cprtypes.h" -#include - -namespace cpr { - -/** - * cpr error codes that match the ones found inside 'curl.h'. - * These error codes only include relevant error codes meaning no support for e.g. FTP errors since cpr does only support HTTP. - **/ -enum class ErrorCode { - /** - * Everything is good and no error occurred. - **/ - OK = 0, - UNSUPPORTED_PROTOCOL, - FAILED_INIT, - URL_MALFORMAT, - NOT_BUILT_IN, - COULDNT_RESOLVE_PROXY, - COULDNT_RESOLVE_HOST, - COULDNT_CONNECT, - WEIRD_SERVER_REPLY, - REMOTE_ACCESS_DENIED, - HTTP2, - PARTIAL_FILE, - QUOTE_ERROR, - HTTP_RETURNED_ERROR, - WRITE_ERROR, - UPLOAD_FAILED, - READ_ERROR, - OUT_OF_MEMORY, - OPERATION_TIMEDOUT, - RANGE_ERROR, - HTTP_POST_ERROR, - SSL_CONNECT_ERROR, - BAD_DOWNLOAD_RESUME, - FILE_COULDNT_READ_FILE, - FUNCTION_NOT_FOUND, - ABORTED_BY_CALLBACK, - BAD_FUNCTION_ARGUMENT, - INTERFACE_FAILED, - TOO_MANY_REDIRECTS, - UNKNOWN_OPTION, - SETOPT_OPTION_SYNTAX, - GOT_NOTHING, - SSL_ENGINE_NOTFOUND, - SSL_ENGINE_SETFAILED, - SEND_ERROR, - RECV_ERROR, - SSL_CERTPROBLEM, - SSL_CIPHER, - PEER_FAILED_VERIFICATION, - BAD_CONTENT_ENCODING, - FILESIZE_EXCEEDED, - USE_SSL_FAILED, - SEND_FAIL_REWIND, - SSL_ENGINE_INITFAILED, - LOGIN_DENIED, - SSL_CACERT_BADFILE, - SSL_SHUTDOWN_FAILED, - AGAIN, - SSL_CRL_BADFILE, - SSL_ISSUER_ERROR, - CHUNK_FAILED, - NO_CONNECTION_AVAILABLE, - SSL_PINNEDPUBKEYNOTMATCH, - SSL_INVALIDCERTSTATUS, - HTTP2_STREAM, - RECURSIVE_API_CALL, - AUTH_ERROR, - HTTP3, - QUIC_CONNECT_ERROR, - PROXY, - SSL_CLIENTCERT, - UNRECOVERABLE_POLL, - TOO_LARGE, - /** - * An unknown error inside curl occurred. - * Please try to reproduce it and then report it to us. - * It might be that there is a new curl error code we are not aware yet. - * Reporting bugs: https://github.com/libcpr/cpr - **/ - UNKNOWN_ERROR = 1000, -}; - -inline const std::unordered_map& get_error_code_to_string_mapping() { - // Use a function-local static rather than inline global objects to avoid the 'double-destructor' problem in MSVC when using /MT flags. - static const std::unordered_map mapping = {{ErrorCode::OK, "OK"}, - {ErrorCode::UNSUPPORTED_PROTOCOL, "UNSUPPORTED_PROTOCOL"}, - {ErrorCode::FAILED_INIT, "FAILED_INIT"}, - {ErrorCode::URL_MALFORMAT, "URL_MALFORMAT"}, - {ErrorCode::NOT_BUILT_IN, "NOT_BUILT_IN"}, - {ErrorCode::COULDNT_RESOLVE_PROXY, "COULDNT_RESOLVE_PROXY"}, - {ErrorCode::COULDNT_RESOLVE_HOST, "COULDNT_RESOLVE_HOST"}, - {ErrorCode::COULDNT_CONNECT, "COULDNT_CONNECT"}, - {ErrorCode::WEIRD_SERVER_REPLY, "WEIRD_SERVER_REPLY"}, - {ErrorCode::REMOTE_ACCESS_DENIED, "REMOTE_ACCESS_DENIED"}, - {ErrorCode::HTTP2, "HTTP2"}, - {ErrorCode::PARTIAL_FILE, "PARTIAL_FILE"}, - {ErrorCode::QUOTE_ERROR, "QUOTE_ERROR"}, - {ErrorCode::HTTP_RETURNED_ERROR, "HTTP_RETURNED_ERROR"}, - {ErrorCode::WRITE_ERROR, "WRITE_ERROR"}, - {ErrorCode::UPLOAD_FAILED, "UPLOAD_FAILED"}, - {ErrorCode::READ_ERROR, "READ_ERROR"}, - {ErrorCode::OUT_OF_MEMORY, "OUT_OF_MEMORY"}, - {ErrorCode::OPERATION_TIMEDOUT, "OPERATION_TIMEDOUT"}, - {ErrorCode::RANGE_ERROR, "RANGE_ERROR"}, - {ErrorCode::HTTP_POST_ERROR, "HTTP_POST_ERROR"}, - {ErrorCode::SSL_CONNECT_ERROR, "SSL_CONNECT_ERROR"}, - {ErrorCode::BAD_DOWNLOAD_RESUME, "BAD_DOWNLOAD_RESUME"}, - {ErrorCode::FILE_COULDNT_READ_FILE, "FILE_COULDNT_READ_FILE"}, - {ErrorCode::FUNCTION_NOT_FOUND, "FUNCTION_NOT_FOUND"}, - {ErrorCode::ABORTED_BY_CALLBACK, "ABORTED_BY_CALLBACK"}, - {ErrorCode::BAD_FUNCTION_ARGUMENT, "BAD_FUNCTION_ARGUMENT"}, - {ErrorCode::INTERFACE_FAILED, "INTERFACE_FAILED"}, - {ErrorCode::TOO_MANY_REDIRECTS, "TOO_MANY_REDIRECTS"}, - {ErrorCode::UNKNOWN_OPTION, "UNKNOWN_OPTION"}, - {ErrorCode::SETOPT_OPTION_SYNTAX, "SETOPT_OPTION_SYNTAX"}, - {ErrorCode::GOT_NOTHING, "GOT_NOTHING"}, - {ErrorCode::SSL_ENGINE_NOTFOUND, "SSL_ENGINE_NOTFOUND"}, - {ErrorCode::SSL_ENGINE_SETFAILED, "SSL_ENGINE_SETFAILED"}, - {ErrorCode::SEND_ERROR, "SEND_ERROR"}, - {ErrorCode::RECV_ERROR, "RECV_ERROR"}, - {ErrorCode::SSL_CERTPROBLEM, "SSL_CERTPROBLEM"}, - {ErrorCode::SSL_CIPHER, "SSL_CIPHER"}, - {ErrorCode::PEER_FAILED_VERIFICATION, "PEER_FAILED_VERIFICATION"}, - {ErrorCode::BAD_CONTENT_ENCODING, "BAD_CONTENT_ENCODING"}, - {ErrorCode::FILESIZE_EXCEEDED, "FILESIZE_EXCEEDED"}, - {ErrorCode::USE_SSL_FAILED, "USE_SSL_FAILED"}, - {ErrorCode::SEND_FAIL_REWIND, "SEND_FAIL_REWIND"}, - {ErrorCode::SSL_ENGINE_INITFAILED, "SSL_ENGINE_INITFAILED"}, - {ErrorCode::LOGIN_DENIED, "LOGIN_DENIED"}, - {ErrorCode::SSL_CACERT_BADFILE, "SSL_CACERT_BADFILE"}, - {ErrorCode::SSL_SHUTDOWN_FAILED, "SSL_SHUTDOWN_FAILED"}, - {ErrorCode::AGAIN, "AGAIN"}, - {ErrorCode::SSL_CRL_BADFILE, "SSL_CRL_BADFILE"}, - {ErrorCode::SSL_ISSUER_ERROR, "SSL_ISSUER_ERROR"}, - {ErrorCode::CHUNK_FAILED, "CHUNK_FAILED"}, - {ErrorCode::NO_CONNECTION_AVAILABLE, "NO_CONNECTION_AVAILABLE"}, - {ErrorCode::SSL_PINNEDPUBKEYNOTMATCH, "SSL_PINNEDPUBKEYNOTMATCH"}, - {ErrorCode::SSL_INVALIDCERTSTATUS, "SSL_INVALIDCERTSTATUS"}, - {ErrorCode::HTTP2_STREAM, "HTTP2_STREAM"}, - {ErrorCode::RECURSIVE_API_CALL, "RECURSIVE_API_CALL"}, - {ErrorCode::AUTH_ERROR, "AUTH_ERROR"}, - {ErrorCode::HTTP3, "HTTP3"}, - {ErrorCode::QUIC_CONNECT_ERROR, "QUIC_CONNECT_ERROR"}, - {ErrorCode::PROXY, "PROXY"}, - {ErrorCode::SSL_CLIENTCERT, "SSL_CLIENTCERT"}, - {ErrorCode::UNRECOVERABLE_POLL, "UNRECOVERABLE_POLL"}, - {ErrorCode::TOO_LARGE, "TOO_LARGE"}, - {ErrorCode::UNKNOWN_ERROR, "UNKNOWN_ERROR"}}; - return mapping; -} - -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 - -namespace std { -inline std::string to_string(const cpr::ErrorCode& code) { - return cpr::get_error_code_to_string_mapping().at(code); -} -} // namespace std - - -#endif diff --git a/vendor/cpr/include/cpr/file.h b/vendor/cpr/include/cpr/file.h deleted file mode 100644 index 9f1f18cf3..000000000 --- a/vendor/cpr/include/cpr/file.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef CPR_FILE_H -#define CPR_FILE_H - -#include -#include -#include - -#include "cpr/filesystem.h" - -namespace cpr { - -struct File { - explicit File(std::string p_filepath, const std::string& p_overriden_filename = {}) : filepath(std::move(p_filepath)), overriden_filename(p_overriden_filename) {} - - std::string filepath; - std::string overriden_filename; - - [[nodiscard]] bool hasOverridenFilename() const noexcept { - return !overriden_filename.empty(); - } -}; - -class Files { - public: - Files() = default; - // NOLINTNEXTLINE(google-explicit-constructor) - Files(const File& p_file) : files{p_file} {} - - Files(const Files& other) = default; - Files(Files&& old) noexcept = default; - - Files(const std::initializer_list& p_files) : files{p_files} {} - Files(const std::initializer_list& p_filepaths); - - ~Files() noexcept = default; - - Files& operator=(const Files& other); - Files& operator=(Files&& old) noexcept; - - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - iterator begin(); - iterator end(); - [[nodiscard]] const_iterator begin() const; - [[nodiscard]] const_iterator end() const; - [[nodiscard]] const_iterator cbegin() const; - [[nodiscard]] const_iterator cend() const; - void emplace_back(const File& file); - void push_back(const File& file); - void pop_back(); - - private: - std::vector files; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/filesystem.h b/vendor/cpr/include/cpr/filesystem.h deleted file mode 100644 index f296770cf..000000000 --- a/vendor/cpr/include/cpr/filesystem.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CPR_FILESYSTEM_H -#define CPR_FILESYSTEM_H - -// Include filesystem into the namespace "fs" from either "filesystem" or "experimental/filesystem" or "boost/filesystem" -#ifdef CPR_USE_BOOST_FILESYSTEM -#define BOOST_FILESYSTEM_VERSION 4 // Use the latest, with the closest behavior to std::filesystem. -#include -namespace cpr { -namespace fs = boost::filesystem; -} -// cppcheck-suppress preprocessorErrorDirective -#elif __has_include() -#include -namespace cpr { -namespace fs = std::filesystem; -} -#elif __has_include("experimental/filesystem") -#include -namespace cpr { -namespace fs = std::experimental::filesystem; -} -#else -#error "Failed to include header!" -#endif - -#endif diff --git a/vendor/cpr/include/cpr/http_version.h b/vendor/cpr/include/cpr/http_version.h deleted file mode 100644 index 3d4d58c6c..000000000 --- a/vendor/cpr/include/cpr/http_version.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef CPR_HTTP_VERSION_H -#define CPR_HTTP_VERSION_H - -#include - -namespace cpr { -enum class HttpVersionCode { - /** - * Let libcurl decide which version is the best. - **/ - VERSION_NONE, - /** - * Enforce HTTP 1.0 requests. - **/ - VERSION_1_0, - /** - * Enforce HTTP 1.1 requests. - **/ - VERSION_1_1, -#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0 - /** - * Attempt HTTP 2.0 requests. - * Fallback to HTTP 1.1 if negotiation fails. - **/ - VERSION_2_0, -#endif -#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0 - /** - * Attempt HTTP 2.0 for HTTPS requests only. - * Fallback to HTTP 1.1 if negotiation fails. - * HTTP 1.1 will be used for HTTP connections. - **/ - VERSION_2_0_TLS, -#endif -#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0 - /** - * Start HTTP 2.0 for HTTP requests. - * Requires prior knowledge that the server supports HTTP 2.0. - * For HTTPS requests we will negotiate the protocol version in the TLS handshake. - **/ - VERSION_2_0_PRIOR_KNOWLEDGE, -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0 - /** - * Attempt HTTP 3.0 requests. - * Requires prior knowledge that the server supports HTTP 3.0 since there is no gracefully downgrade. - * Fallback to HTTP 1.1 if negotiation fails. - **/ - VERSION_3_0, -#endif -#if LIBCURL_VERSION_NUM >= 0x075701 // 7.87.1, but corresponds to 7.88.0 tag - /** - * Enforce HTTP 3.0 requests without fallback. - * Requires prior knowledge that the server supports HTTP 3.0 since there is no gracefully downgrade. - **/ - VERSION_3_0_ONLY -#endif -}; - -class HttpVersion { - public: - /** - * The HTTP version that should be used by libcurl when initiating a HTTP(S) connection. - * Default: HttpVersionCode::VERSION_NONE - **/ - HttpVersionCode code = HttpVersionCode::VERSION_NONE; - - HttpVersion() = default; - explicit HttpVersion(HttpVersionCode _code) : code(_code) {} -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/interceptor.h b/vendor/cpr/include/cpr/interceptor.h deleted file mode 100644 index d05f4c9c2..000000000 --- a/vendor/cpr/include/cpr/interceptor.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef CPR_INTERCEPTOR_H -#define CPR_INTERCEPTOR_H - -#include "cpr/multiperform.h" -#include "cpr/response.h" -#include "cpr/session.h" -#include - -namespace cpr { -class Interceptor { - public: - enum class ProceedHttpMethod { - GET_REQUEST = 0, - POST_REQUEST, - PUT_REQUEST, - DELETE_REQUEST, - PATCH_REQUEST, - HEAD_REQUEST, - OPTIONS_REQUEST, - DOWNLOAD_CALLBACK_REQUEST, - DOWNLOAD_FILE_REQUEST, - }; - - Interceptor() = default; - Interceptor(const Interceptor& other) = default; - Interceptor(Interceptor&& old) = default; - virtual ~Interceptor() = default; - - Interceptor& operator=(const Interceptor& other) = default; - Interceptor& operator=(Interceptor&& old) = default; - - virtual Response intercept(Session& session) = 0; - - protected: - static Response proceed(Session& session); - static Response proceed(Session& session, ProceedHttpMethod httpMethod); - static Response proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file); - static Response proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write); -}; - -class InterceptorMulti { - public: - enum class ProceedHttpMethod { - GET_REQUEST = 0, - POST_REQUEST, - PUT_REQUEST, - DELETE_REQUEST, - PATCH_REQUEST, - HEAD_REQUEST, - OPTIONS_REQUEST, - DOWNLOAD_CALLBACK_REQUEST, - DOWNLOAD_FILE_REQUEST, - }; - - InterceptorMulti() = default; - InterceptorMulti(const InterceptorMulti& other) = default; - InterceptorMulti(InterceptorMulti&& old) = default; - virtual ~InterceptorMulti() = default; - - InterceptorMulti& operator=(const InterceptorMulti& other) = default; - InterceptorMulti& operator=(InterceptorMulti&& old) = default; - - virtual std::vector intercept(MultiPerform& multi) = 0; - - protected: - static std::vector proceed(MultiPerform& multi); - - static void PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write); -}; - -} // namespace cpr - - -#endif diff --git a/vendor/cpr/include/cpr/interface.h b/vendor/cpr/include/cpr/interface.h deleted file mode 100644 index b98940ec2..000000000 --- a/vendor/cpr/include/cpr/interface.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CPR_INTERFACE_H -#define CPR_INTERFACE_H - -#include -#include - -#include "cpr/cprtypes.h" - -namespace cpr { - -class Interface : public StringHolder { - public: - Interface() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Interface(std::string iface) : StringHolder(std::move(iface)) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Interface(std::string_view iface) : StringHolder(iface) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Interface(const char* iface) : StringHolder(iface) {} - Interface(const char* str, size_t len) : StringHolder(str, len) {} - Interface(const std::initializer_list args) : StringHolder(args) {} - Interface(const Interface& other) = default; - Interface(Interface&& old) noexcept = default; - ~Interface() override = default; - - Interface& operator=(Interface&& old) noexcept = default; - Interface& operator=(const Interface& other) = default; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/limit_rate.h b/vendor/cpr/include/cpr/limit_rate.h deleted file mode 100644 index f25c09e5b..000000000 --- a/vendor/cpr/include/cpr/limit_rate.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CPR_SPEED_LIMIT_H -#define CPR_SPEED_LIMIT_H - -#include - -namespace cpr { - -class LimitRate { - public: - LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) : downrate(p_downrate), uprate(p_uprate) {} - - std::int64_t downrate = 0; - std::int64_t uprate = 0; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/local_port.h b/vendor/cpr/include/cpr/local_port.h deleted file mode 100644 index a6efe7ecf..000000000 --- a/vendor/cpr/include/cpr/local_port.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPR_LOCAL_PORT_H -#define CPR_LOCAL_PORT_H - -#include - -namespace cpr { - -class LocalPort { - public: - // NOLINTNEXTLINE(google-explicit-constructor) - LocalPort(const std::uint16_t p_localport) : localport_(p_localport) {} - - operator std::uint16_t() const { - return localport_; - } - - private: - std::uint16_t localport_ = 0; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/local_port_range.h b/vendor/cpr/include/cpr/local_port_range.h deleted file mode 100644 index e048b6e97..000000000 --- a/vendor/cpr/include/cpr/local_port_range.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPR_LOCAL_PORT_RANGE_H -#define CPR_LOCAL_PORT_RANGE_H - -#include - -namespace cpr { - -class LocalPortRange { - public: - // NOLINTNEXTLINE(google-explicit-constructor) - LocalPortRange(const std::uint16_t p_localportrange) : localportrange_(p_localportrange) {} - - operator std::uint16_t() const { - return localportrange_; - } - - private: - std::uint16_t localportrange_ = 0; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/low_speed.h b/vendor/cpr/include/cpr/low_speed.h deleted file mode 100644 index 8f9eb86ab..000000000 --- a/vendor/cpr/include/cpr/low_speed.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPR_LOW_SPEED_H -#define CPR_LOW_SPEED_H - -#include -#include - -namespace cpr { - -class LowSpeed { - public: - - [[deprecated("Will be removed in CPR 2.x - Use the constructor with std::chrono::seconds instead of std::int32_t")]] - LowSpeed(const std::int32_t p_limit, const std::int32_t p_time) : limit(p_limit), time(std::chrono::seconds(p_time)) {} - - LowSpeed(const std::int32_t p_limit, const std::chrono::seconds p_time) : limit(p_limit), time(p_time) {} - - std::int32_t limit; - std::chrono::seconds time; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/multipart.h b/vendor/cpr/include/cpr/multipart.h deleted file mode 100644 index 9ee62d5ab..000000000 --- a/vendor/cpr/include/cpr/multipart.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CPR_MULTIPART_H -#define CPR_MULTIPART_H - -#include -#include -#include -#include -#include - -#include "buffer.h" -#include "file.h" - -namespace cpr { - -struct Part { - Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {}) : name{p_name}, value{p_value}, content_type{p_content_type}, is_file{false}, is_buffer{false} {} - Part(const std::string& p_name, const std::int32_t& p_value, const std::string& p_content_type = {}) : name{p_name}, value{std::to_string(p_value)}, content_type{p_content_type}, is_file{false}, is_buffer{false} {} - Part(const std::string& p_name, const Files& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {} - Part(const std::string& p_name, Files&& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {} - Part(const std::string& p_name, const Buffer& buffer, const std::string& p_content_type = {}) : name{p_name}, value{buffer.filename.string()}, content_type{p_content_type}, data{buffer.data}, datalen{buffer.datalen}, is_file{false}, is_buffer{true} {} - - std::string name; - // We don't use fs::path here, as this leads to problems using windows - std::string value; - std::string content_type; - Buffer::data_t data{nullptr}; - size_t datalen{0}; - bool is_file; - bool is_buffer; - - Files files; -}; - -class Multipart { - public: - Multipart(const std::initializer_list& parts); - Multipart(const std::vector& parts); - Multipart(const std::vector&& parts); - - std::vector parts; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/multiperform.h b/vendor/cpr/include/cpr/multiperform.h deleted file mode 100644 index a48123792..000000000 --- a/vendor/cpr/include/cpr/multiperform.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef CPR_MULTIPERFORM_H -#define CPR_MULTIPERFORM_H - -#include "cpr/curlmultiholder.h" -#include "cpr/response.h" -#include "cpr/session.h" -#include -#include -#include -#include -#include - -namespace cpr { - -class InterceptorMulti; - -class MultiPerform { - public: - enum class HttpMethod { - UNDEFINED = 0, - GET_REQUEST, - POST_REQUEST, - PUT_REQUEST, - DELETE_REQUEST, - PATCH_REQUEST, - HEAD_REQUEST, - OPTIONS_REQUEST, - DOWNLOAD_REQUEST, - }; - - MultiPerform(); - MultiPerform(const MultiPerform& other) = delete; - MultiPerform(MultiPerform&& old) noexcept; - ~MultiPerform(); - - MultiPerform& operator=(const MultiPerform& other) = delete; - MultiPerform& operator=(MultiPerform&& old) noexcept; - - std::vector Get(); - std::vector Delete(); - template - std::vector Download(DownloadArgTypes... args); - std::vector Put(); - std::vector Head(); - std::vector Options(); - std::vector Patch(); - std::vector Post(); - - std::vector Perform(); - template - std::vector PerformDownload(DownloadArgTypes... args); - - void AddSession(std::shared_ptr& session, HttpMethod method = HttpMethod::UNDEFINED); - void RemoveSession(const std::shared_ptr& session); - std::vector, HttpMethod>>& GetSessions(); - [[nodiscard]] const std::vector, HttpMethod>>& GetSessions() const; - - void AddInterceptor(const std::shared_ptr& pinterceptor); - - private: - // Interceptors should be able to call the private proceed() and PrepareDownloadSessions() functions - friend InterceptorMulti; - - void SetHttpMethod(HttpMethod method); - - void PrepareSessions(); - template - void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args); - template - void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg); - void PrepareDownloadSession(size_t sessions_index, std::ofstream& file); - void PrepareDownloadSession(size_t sessions_index, const WriteCallback& write); - - void PrepareGet(); - void PrepareDelete(); - void PreparePut(); - void PreparePatch(); - void PrepareHead(); - void PrepareOptions(); - void PreparePost(); - template - void PrepareDownload(DownloadArgTypes... args); - - const std::optional> intercept(); - std::vector proceed(); - std::vector MakeRequest(); - std::vector MakeDownloadRequest(); - - void DoMultiPerform(); - std::vector ReadMultiInfo(const std::function& complete_function); - - std::vector, HttpMethod>> sessions_; - std::unique_ptr multicurl_; - bool is_download_multi_perform{false}; - - using InterceptorsContainer = std::list>; - InterceptorsContainer interceptors_; - // Currently running interceptor - InterceptorsContainer::iterator current_interceptor_; - // Interceptor within the chain where to start with each repeated request - InterceptorsContainer::iterator first_interceptor_; -}; - -template -void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg) { - PrepareDownloadSession(sessions_index, current_arg); -} - -template -void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args) { - PrepareDownloadSession(sessions_index, current_arg); - PrepareDownloadSessions(sessions_index + 1, args...); -} - - -template -void MultiPerform::PrepareDownload(DownloadArgTypes... args) { - SetHttpMethod(HttpMethod::DOWNLOAD_REQUEST); - PrepareDownloadSessions(0, args...); -} - -template -std::vector MultiPerform::Download(DownloadArgTypes... args) { - if (sizeof...(args) != sessions_.size()) { - throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!"); - } - PrepareDownload(args...); - return MakeDownloadRequest(); -} - -template -std::vector MultiPerform::PerformDownload(DownloadArgTypes... args) { - if (sizeof...(args) != sessions_.size()) { - throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!"); - } - PrepareDownloadSessions(0, args...); - return MakeDownloadRequest(); -} - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/parameters.h b/vendor/cpr/include/cpr/parameters.h deleted file mode 100644 index 620962778..000000000 --- a/vendor/cpr/include/cpr/parameters.h +++ /dev/null @@ -1,18 +0,0 @@ -#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) : CurlContainer(parameters) {} -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/payload.h b/vendor/cpr/include/cpr/payload.h deleted file mode 100644 index 0741a88fa..000000000 --- a/vendor/cpr/include/cpr/payload.h +++ /dev/null @@ -1,23 +0,0 @@ -#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) : CurlContainer(pairs) {} -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/proxies.h b/vendor/cpr/include/cpr/proxies.h deleted file mode 100644 index 6970442de..000000000 --- a/vendor/cpr/include/cpr/proxies.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPR_PROXIES_H -#define CPR_PROXIES_H - -#include -#include -#include - -namespace cpr { -class Proxies { - public: - Proxies() = default; - Proxies(const std::initializer_list>& hosts); - Proxies(const std::map& hosts); - - bool has(const std::string& protocol) const; - const std::string& operator[](const std::string& protocol); - - private: - std::map hosts_; -}; -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/proxyauth.h b/vendor/cpr/include/cpr/proxyauth.h deleted file mode 100644 index 6a00c920e..000000000 --- a/vendor/cpr/include/cpr/proxyauth.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef CPR_PROXYAUTH_H -#define CPR_PROXYAUTH_H - -#include -#include -#include -#include - -#include "cpr/auth.h" -#include "cpr/util.h" - -namespace cpr { -class ProxyAuthentication; - -class EncodedAuthentication { - friend ProxyAuthentication; - - public: - EncodedAuthentication() = default; - EncodedAuthentication(std::string_view p_username, std::string_view p_password) : username(util::urlEncode(p_username)), password(util::urlEncode(p_password)) {} - EncodedAuthentication(const EncodedAuthentication& other) = default; - EncodedAuthentication(EncodedAuthentication&& old) noexcept = default; - virtual ~EncodedAuthentication() noexcept = default; - - EncodedAuthentication& operator=(EncodedAuthentication&& old) noexcept = default; - EncodedAuthentication& operator=(const EncodedAuthentication& other) = default; - - [[nodiscard]] std::string_view GetUsername() const; - [[nodiscard]] std::string_view GetPassword() const; - [[nodiscard]] const util::SecureString& GetUsernameUnderlying() const; - [[nodiscard]] const util::SecureString& GetPasswordUnderlying() const; - - private: - util::SecureString username; - util::SecureString password; -}; - -class ProxyAuthentication { - public: - ProxyAuthentication() = default; - ProxyAuthentication(const std::initializer_list>& auths) : proxyAuth_{auths} {} - explicit ProxyAuthentication(const std::map& auths) : proxyAuth_{auths} {} - - [[nodiscard]] bool has(const std::string& protocol) const; - [[nodiscard]] std::string_view GetUsername(const std::string& protocol); - [[nodiscard]] std::string_view GetPassword(const std::string& protocol); - [[nodiscard]] const util::SecureString& GetUsernameUnderlying(const std::string& protocol) const; - [[nodiscard]] const util::SecureString& GetPasswordUnderlying(const std::string& protocol) const; - - private: - std::map proxyAuth_; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/range.h b/vendor/cpr/include/cpr/range.h deleted file mode 100644 index 2c5a145d5..000000000 --- a/vendor/cpr/include/cpr/range.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef CPR_RANGE_H -#define CPR_RANGE_H - -#include -#include - -namespace cpr { - -class Range { - public: - Range(const std::optional p_resume_from = std::nullopt, const std::optional p_finish_at = std::nullopt) { - resume_from = p_resume_from.value_or(0); - finish_at = p_finish_at.value_or(-1); - } - - std::int64_t resume_from; - std::int64_t finish_at; - - const std::string str() const { - std::string from_str = (resume_from < 0U) ? "" : std::to_string(resume_from); - std::string to_str = (finish_at < 0U) ? "" : std::to_string(finish_at); - return from_str + "-" + to_str; - } -}; - -class MultiRange { - public: - MultiRange(std::initializer_list rs) : ranges{rs} {} - - const std::string str() const { - std::string multi_range_string{}; - for (Range range : ranges) { - multi_range_string += ((multi_range_string.empty()) ? "" : ", ") + range.str(); - } - return multi_range_string; - } - - private: - std::vector ranges; -}; // namespace cpr - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/redirect.h b/vendor/cpr/include/cpr/redirect.h deleted file mode 100644 index d4c8e576b..000000000 --- a/vendor/cpr/include/cpr/redirect.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef CPR_REDIRECT_H -#define CPR_REDIRECT_H - -#include - -namespace cpr { -enum class PostRedirectFlags : uint8_t { - /** - * Respect RFC 7231 (section 6.4.2 to 6.4.4). - * Same as CURL_REDIR_POST_301 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html). - **/ - POST_301 = 0x1 << 0, - /** - * Maintain the request method after a 302 redirect. - * Same as CURL_REDIR_POST_302 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html). - **/ - POST_302 = 0x1 << 1, - /** - * Maintain the request method after a 303 redirect. - * Same as CURL_REDIR_POST_303 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html). - **/ - POST_303 = 0x1 << 2, - /** - * Default value. - * Convenience option to enable all flags. - * Same as CURL_REDIR_POST_ALL (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html). - **/ - POST_ALL = POST_301 | POST_302 | POST_303, - /** - * * Convenience option to disable all flags. - **/ - NONE = 0x0 -}; - -PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator~(PostRedirectFlags flag); -PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -bool any(PostRedirectFlags flag); - -class Redirect { - public: - /** - * The maximum number of redirects to follow. - * 0: Refuse any redirects. - * -1: Infinite number of redirects. - * Default: 50 - * https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html - **/ - // NOLINTNEXTLINE (google-runtime-int) - long maximum{50L}; - /** - * Follow 3xx redirects. - * Default: true - * https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html - **/ - bool follow{true}; - /** - * Continue to send authentication (user+password) credentials when following locations, even when hostname changed. - * Default: false - * https://curl.se/libcurl/c/CURLOPT_UNRESTRICTED_AUTH.html - **/ - bool cont_send_cred{false}; - /** - * Flags to control how to act after a redirect for a post request. - * Default: POST_ALL - **/ - PostRedirectFlags post_flags{PostRedirectFlags::POST_ALL}; - - Redirect() = default; - // NOLINTNEXTLINE (google-runtime-int) - Redirect(long p_maximum, bool p_follow, bool p_cont_send_cred, PostRedirectFlags p_post_flags) : maximum(p_maximum), follow(p_follow), cont_send_cred(p_cont_send_cred), post_flags(p_post_flags) {} - // NOLINTNEXTLINE (google-runtime-int) - explicit Redirect(long p_maximum) : maximum(p_maximum) {} - explicit Redirect(bool p_follow) : follow(p_follow) {} - Redirect(bool p_follow, bool p_cont_send_cred) : follow(p_follow), cont_send_cred(p_cont_send_cred) {} - explicit Redirect(PostRedirectFlags p_post_flags) : post_flags(p_post_flags) {} -}; -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/reserve_size.h b/vendor/cpr/include/cpr/reserve_size.h deleted file mode 100644 index 5eae4c80a..000000000 --- a/vendor/cpr/include/cpr/reserve_size.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CPR_RESERVE_SIZE_H -#define CPR_RESERVE_SIZE_H - -#include - -namespace cpr { - -class ReserveSize { - public: - ReserveSize(const size_t _size) : size(_size) {} - - size_t size = 0; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/resolve.h b/vendor/cpr/include/cpr/resolve.h deleted file mode 100644 index 6f0e52c16..000000000 --- a/vendor/cpr/include/cpr/resolve.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CPR_RESOLVE_H -#define CPR_RESOLVE_H - -#include -#include - -namespace cpr { -class Resolve { - public: - std::string host; - std::string addr; - std::set ports; - - Resolve(const std::string& host_param, const std::string& addr_param, const std::set& ports_param = std::set{80U, 443U}) : host(host_param), addr(addr_param), ports(ports_param) { - if (this->ports.empty()) { - this->ports.insert(80U); - this->ports.insert(443U); - } - } -}; -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/response.h b/vendor/cpr/include/cpr/response.h deleted file mode 100644 index 5606253b9..000000000 --- a/vendor/cpr/include/cpr/response.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef CPR_RESPONSE_H -#define CPR_RESPONSE_H - -#include -#include -#include -#include -#include -#include - -#include "cpr/cert_info.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/error.h" -#include "cpr/ssl_options.h" -#include "cpr/util.h" - -namespace cpr { - -class MultiPerform; - -class Response { - private: - friend MultiPerform; - 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{}; - std::string primary_ip{}; - std::uint16_t primary_port{}; - - Response() = default; - Response(std::shared_ptr curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies, Error&& p_error); - [[nodiscard]] std::vector GetCertInfos() const; - 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/secure_string.h b/vendor/cpr/include/cpr/secure_string.h deleted file mode 100644 index 86c38c6b4..000000000 --- a/vendor/cpr/include/cpr/secure_string.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef CPR_SECURE_STRING_H -#define CPR_SECURE_STRING_H - -#include -#include -#include - -namespace cpr::util { - -// This is an allocator that overwrites memory with zero values before -// deallocating the memory, so as to not leave secrets in unallocated memory -// sections. -template -struct SecureAllocator : private std::allocator { - template - friend struct SecureAllocator; - SecureAllocator() = default; - template - // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) - SecureAllocator(const SecureAllocator& rhs) noexcept : std::allocator(static_cast&>(rhs)) {} - template - // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) - SecureAllocator(SecureAllocator&& rhs) noexcept : std::allocator(static_cast&&>(rhs)) {} - template - SecureAllocator& operator=(const SecureAllocator& rhs) noexcept { - static_cast&>(*this) = static_cast&>(rhs); - return *this; - } - template - SecureAllocator& operator=(SecureAllocator&& rhs) noexcept { - static_cast&>(*this) = static_cast&&>(rhs); - return *this; - } - - using value_type = T; - - // NOLINTNEXTLINE(readability-identifier-naming) - T* allocate(std::size_t n) { - return static_cast&>(*this).allocate(n); - } - - // NOLINTNEXTLINE(readability-identifier-naming) - void deallocate(T* p, std::size_t n) { - std::fill_n(p, n, T{}); - static_cast&>(*this).deallocate(p, n); - } - - template - [[nodiscard]] bool IsEqual(const SecureAllocator& rhs) const noexcept { - return static_cast&>(*this) == static_cast&>(rhs); - } -}; -template -bool operator==(const SecureAllocator& lhs, const SecureAllocator& rhs) noexcept { - return lhs.IsEqual(rhs); -} -template -bool operator!=(const SecureAllocator& lhs, const SecureAllocator& rhs) noexcept { - return !lhs.IsEqual(rhs); -} - -using SecureString = std::basic_string, SecureAllocator>; - -} // namespace cpr::util - -#endif // CPR_SECURE_STRING_H diff --git a/vendor/cpr/include/cpr/session.h b/vendor/cpr/include/cpr/session.h deleted file mode 100644 index 0781559f9..000000000 --- a/vendor/cpr/include/cpr/session.h +++ /dev/null @@ -1,367 +0,0 @@ -#ifndef CPR_SESSION_H -#define CPR_SESSION_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpr/accept_encoding.h" -#include "cpr/async_wrapper.h" -#include "cpr/auth.h" -#include "cpr/bearer.h" -#include "cpr/body.h" -#include "cpr/body_view.h" -#include "cpr/callback.h" -#include "cpr/connect_timeout.h" -#include "cpr/connection_pool.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/curlholder.h" -#include "cpr/http_version.h" -#include "cpr/interface.h" -#include "cpr/limit_rate.h" -#include "cpr/local_port.h" -#include "cpr/local_port_range.h" -#include "cpr/low_speed.h" -#include "cpr/multipart.h" -#include "cpr/parameters.h" -#include "cpr/payload.h" -#include "cpr/proxies.h" -#include "cpr/proxyauth.h" -#include "cpr/range.h" -#include "cpr/redirect.h" -#include "cpr/reserve_size.h" -#include "cpr/resolve.h" -#include "cpr/response.h" -#include "cpr/sse.h" -#include "cpr/ssl_options.h" -#include "cpr/timeout.h" -#include "cpr/unix_socket.h" -#include "cpr/user_agent.h" -#include "cpr/util.h" -#include "cpr/verbose.h" - -namespace cpr { - -using AsyncResponse = AsyncWrapper; -using Content = std::variant; - -class Interceptor; -class MultiPerform; - -class Session : public std::enable_shared_from_this { - public: - Session(); - Session(const Session& other) = delete; - Session(Session&& old) = delete; - - ~Session() = default; - - Session& operator=(Session&& old) noexcept = delete; - 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); - [[nodiscard]] Header& GetHeader(); - [[nodiscard]] const Header& GetHeader() const; - void SetTimeout(const Timeout& timeout); - void SetConnectTimeout(const ConnectTimeout& timeout); - void SetConnectionPool(const ConnectionPool& pool); - 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 SetUserAgent(const UserAgent& ua); - void SetPayload(Payload&& payload); - void SetPayload(const Payload& payload); - void SetProxies(Proxies&& proxies); - void SetProxies(const Proxies& proxies); - void SetProxyAuth(ProxyAuthentication&& proxy_auth); - void SetProxyAuth(const ProxyAuthentication& proxy_auth); - void SetMultipart(Multipart&& multipart); - void SetMultipart(const Multipart& multipart); - void SetRedirect(const Redirect& redirect); - void SetCookies(const Cookies& cookies); - void SetBody(Body&& body); - void SetBody(const Body& body); - void SetBodyView(BodyView 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 SetServerSentEventCallback(const ServerSentEventCallback& sse); - void SetVerbose(const Verbose& verbose); - void SetInterface(const Interface& iface); - void SetLocalPort(const LocalPort& local_port); - void SetLocalPortRange(const LocalPortRange& local_port_range); - void SetHttpVersion(const HttpVersion& version); - void SetRange(const Range& range); - void SetResolve(const Resolve& resolve); - void SetResolves(const std::vector& resolves); - void SetMultiRange(const MultiRange& multi_range); - void SetReserveSize(const ReserveSize& reserve_size); - void SetAcceptEncoding(const AcceptEncoding& accept_encoding); - void SetAcceptEncoding(AcceptEncoding&& accept_encoding); - void SetLimitRate(const LimitRate& limit_rate); - - /** - * Returns a reference to the content sent in previous request. - **/ - [[nodiscard]] const Content& GetContent() const; - - /** - * Removes the content sent in previous request from internal state, so it will not be sent with the next request. - * Call this before doing a request that is specified not to send a body, e.g. GET. - **/ - void RemoveContent(); - - // For cancellable requests - void SetCancellationParam(std::shared_ptr param); - - // 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); - void SetOption(const ConnectionPool& pool); -// 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 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(ProxyAuthentication&& proxy_auth); - void SetOption(const ProxyAuthentication& proxy_auth); - void SetOption(Multipart&& multipart); - void SetOption(const Multipart& multipart); - void SetOption(const Redirect& redirect); - void SetOption(const Cookies& cookies); - void SetOption(Body&& body); - void SetOption(const Body& body); - void SetOption(BodyView 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 ServerSentEventCallback& sse); - 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); - void SetOption(const Interface& iface); - void SetOption(const LocalPort& local_port); - void SetOption(const LocalPortRange& local_port_range); - void SetOption(const HttpVersion& version); - void SetOption(const Range& range); - void SetOption(const MultiRange& multi_range); - void SetOption(const ReserveSize& reserve_size); - void SetOption(const AcceptEncoding& accept_encoding); - void SetOption(AcceptEncoding&& accept_encoding); - void SetOption(const Resolve& resolve); - void SetOption(const std::vector& resolves); - - cpr_off_t GetDownloadFileLength(); - /** - * Attempt to preallocate enough memory for specified number of characters in the response string. - * Pass 0 to disable this behavior and let the response string be allocated dynamically on demand. - * - * Example: - * cpr::Session session; - * session.SetUrl(cpr::Url{"http://xxx/file"}); - * session.ResponseStringReserve(1024 * 512); // Reserve space for at least 1024 * 512 characters - * cpr::Response r = session.Get(); - **/ - void ResponseStringReserve(size_t size); - Response Delete(); - Response Download(const WriteCallback& write); - Response Download(std::ofstream& file); - Response Get(); - Response Head(); - Response Options(); - Response Patch(); - Response Post(); - Response Put(); - - AsyncResponse GetAsync(); - AsyncResponse DeleteAsync(); - AsyncResponse DownloadAsync(const WriteCallback& write); - AsyncResponse DownloadAsync(std::ofstream& file); - AsyncResponse HeadAsync(); - AsyncResponse OptionsAsync(); - AsyncResponse PatchAsync(); - AsyncResponse PostAsync(); - AsyncResponse PutAsync(); - - template - auto GetCallback(Then then); - template - auto PostCallback(Then then); - template - auto PutCallback(Then then); - template - auto HeadCallback(Then then); - template - auto DeleteCallback(Then then); - template - auto OptionsCallback(Then then); - template - auto PatchCallback(Then then); - - std::shared_ptr GetCurlHolder(); - std::string GetFullRequestUrl(); - - void PrepareDelete(); - void PrepareGet(); - void PrepareHead(); - void PrepareOptions(); - void PreparePatch(); - void PreparePost(); - void PreparePut(); - void PrepareDownload(const WriteCallback& write); - void PrepareDownload(std::ofstream& file); - Response Complete(CURLcode curl_error); - Response CompleteDownload(CURLcode curl_error); - - void AddInterceptor(const std::shared_ptr& pinterceptor); - - std::shared_ptr GetSharedPtrFromThis(); - - private: - // Interceptors should be able to call the private proceed() function - friend Interceptor; - friend MultiPerform; - - - bool chunkedTransferEncoding_{false}; - Content content_{std::monostate{}}; - std::shared_ptr curl_; - Url url_; - Parameters parameters_; - Proxies proxies_; - ProxyAuthentication proxyAuth_; - Header header_; - AcceptEncoding acceptEncoding_; - - - struct Callbacks { - /** - * Will be set by the read callback. - * Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_. - **/ - ReadCallback readcb_; - HeaderCallback headercb_; - WriteCallback writecb_; - ProgressCallback progresscb_; - DebugCallback debugcb_; - CancellationCallback cancellationcb_; - ServerSentEventCallback ssecb_; - }; - - std::unique_ptr cbs_{std::make_unique()}; - - size_t response_string_reserve_size_{0}; - std::string response_string_; - std::string header_string_; - // Container type is required to keep iterator valid on elem insertion. E.g. list but not vector. - using InterceptorsContainer = std::list>; - InterceptorsContainer interceptors_; - // Currently running interceptor - InterceptorsContainer::const_iterator current_interceptor_; - // Interceptor within the chain where to start with each repeated request - InterceptorsContainer::const_iterator first_interceptor_; - bool isUsedInMultiPerform{false}; - bool isCancellable{false}; - -#if SUPPORT_SSL_NO_REVOKE - bool sslNoRevoke_{false}; -#endif - - Response makeDownloadRequest(); - Response makeRequest(); - Response proceed(); - const std::optional intercept(); - /** - * Prepares the curl object for a request with everything used by all requests. - **/ - void prepareCommonShared(); - /** - * Prepares the curl object for a request with everything used by all non download related requests. - **/ - void prepareCommon(); - /** - * Prepares the curl object for a request with everything used by the download request. - **/ - void prepareCommonDownload(); - void prepareHeader(); - void prepareProxy(); - CURLcode DoEasyPerform(); - void prepareBodyPayloadOrMultipart() const; - /** - * Returns true in case content_ is of type cpr::Body or cpr::Payload. - **/ - [[nodiscard]] bool hasBodyOrPayload() const; -}; - -template -auto Session::GetCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Get()); }, std::move(then)); -} - -template -auto Session::PostCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Post()); }, std::move(then)); -} - -template -auto Session::PutCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Put()); }, std::move(then)); -} - -template -auto Session::HeadCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Head()); }, std::move(then)); -} - -template -auto Session::DeleteCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Delete()); }, std::move(then)); -} - -template -auto Session::OptionsCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Options()); }, std::move(then)); -} - -template -auto Session::PatchCallback(Then then) { - return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Patch()); }, std::move(then)); -} - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/singleton.h b/vendor/cpr/include/cpr/singleton.h deleted file mode 100644 index e52439bf1..000000000 --- a/vendor/cpr/include/cpr/singleton.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef CPR_SINGLETON_H -#define CPR_SINGLETON_H - -#include -#include - -#ifndef CPR_DISABLE_COPY -#define CPR_DISABLE_COPY(Class) \ - Class(const Class&) = delete; \ - Class& operator=(const Class&) = delete; -#endif - -#ifndef CPR_SINGLETON_DECL -#define CPR_SINGLETON_DECL(Class) \ - public: \ - static Class* GetInstance(); \ - static void ExitInstance(); \ - \ - private: \ - CPR_DISABLE_COPY(Class) \ - static Class* s_pInstance; \ - static std::once_flag s_getFlag; \ - static std::once_flag s_exitFlag; -#endif - -#ifndef CPR_SINGLETON_IMPL -#define CPR_SINGLETON_IMPL(Class) \ - Class* Class::s_pInstance = nullptr; \ - std::once_flag Class::s_getFlag{}; \ - std::once_flag Class::s_exitFlag{}; \ - Class* Class::GetInstance() { \ - std::call_once(Class::s_getFlag, []() { s_pInstance = new Class; }); \ - return s_pInstance; \ - } \ - void Class::ExitInstance() { \ - std::call_once(Class::s_exitFlag, []() { \ - assert(s_pInstance); \ - delete s_pInstance; \ - s_pInstance = nullptr; \ - }); \ - } -#endif - -#endif diff --git a/vendor/cpr/include/cpr/sse.h b/vendor/cpr/include/cpr/sse.h deleted file mode 100644 index 2a137b361..000000000 --- a/vendor/cpr/include/cpr/sse.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef CPR_SSE_H -#define CPR_SSE_H - -#include -#include -#include -#include -#include -#include - -namespace cpr { - -/** - * Represents a Server-Sent Event (SSE) as defined in the HTML5 specification. - * https://html.spec.whatwg.org/multipage/server-sent-events.html - */ -struct ServerSentEvent { - /** - * The event ID. Can be used to track the last received event and resume from there. - */ - std::optional id; - - /** - * The event type. If not specified, defaults to "message". - */ - std::string event{"message"}; - - /** - * The event data. Multiple data fields are concatenated with newlines. - */ - std::string data; - - /** - * The retry time in milliseconds. Used to set the reconnection time. - */ - std::optional retry; - - ServerSentEvent() = default; -}; - -/** - * Parser for Server-Sent Events (SSE) streams. - * This parser handles incoming SSE data according to the HTML5 specification. - */ -class ServerSentEventParser { - public: - ServerSentEventParser() = default; - - /** - * Parse incoming SSE data and invoke the callback for each complete event. - * @param data The incoming data chunk - * @param callback The callback to invoke for each parsed event - * @return true to continue receiving data, false to abort - */ - bool parse(std::string_view data, const std::function& callback); - - /** - * Reset the parser state. - */ - void reset(); - - private: - std::string buffer_; - ServerSentEvent current_event_; - - bool processLine(const std::string& line, const std::function& callback); - bool dispatchEvent(const std::function& callback); -}; - -/** - * Callback for handling Server-Sent Events. - * The callback receives each parsed SSE event and can return false to abort the connection. - */ -class ServerSentEventCallback { - public: - ServerSentEventCallback() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - ServerSentEventCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - - bool operator()(ServerSentEvent&& event) const { - if (!callback) { - return true; - } - return callback(std::move(event), userdata); - } - - /** - * Internal function used to handle raw data chunks and parse them into SSE events. - * This is called by the underlying write callback mechanism. - */ - bool handleData(std::string_view data); - - intptr_t userdata{}; - std::function callback; - - private: - ServerSentEventParser parser_; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/ssl_ctx.h b/vendor/cpr/include/cpr/ssl_ctx.h deleted file mode 100644 index b6bc81190..000000000 --- a/vendor/cpr/include/cpr/ssl_ctx.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CPR_SSL_CTX_H -#define CPR_SSL_CTX_H - -#include "cpr/ssl_options.h" -#include - -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION - -namespace cpr { - -/** - * This callback function loads a CA certificate from raw_cert_buf and gets called by libcurl - * just before the initialization of an SSL connection. - * The raw_cert_buf argument is set with the CURLOPT_SSL_CTX_DATA option and has to be a nul - * terminated buffer. - * - * Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html - * https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html - */ -CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* curl, void* sslctx, void* raw_cert_buf); - -} // Namespace cpr - -#endif - -#endif diff --git a/vendor/cpr/include/cpr/ssl_options.h b/vendor/cpr/include/cpr/ssl_options.h deleted file mode 100644 index d7d43d60c..000000000 --- a/vendor/cpr/include/cpr/ssl_options.h +++ /dev/null @@ -1,675 +0,0 @@ -#ifndef CPR_SSLOPTIONS_H -#define CPR_SSLOPTIONS_H - -#include -#include -#include - -#include "cpr/filesystem.h" -#include - -#include "cpr/util.h" -#include "util.h" -#include - -#ifndef SUPPORT_ALPN -#define SUPPORT_ALPN LIBCURL_VERSION_NUM >= 0x072400 // 7.36.0 -#endif -#ifndef SUPPORT_NPN -#define SUPPORT_NPN LIBCURL_VERSION_NUM >= 0x072400 && LIBCURL_VERSION_NUM < 0x075600 // 7.36.0 - 7.85.0 -#endif - -#ifndef SUPPORT_SSLv2 -#define SUPPORT_SSLv2 LIBCURL_VERSION_NUM <= 0x071300 // 7.19.0 -#endif -#ifndef SUPPORT_SSLv3 -#define SUPPORT_SSLv3 LIBCURL_VERSION_NUM <= 0x072700 // 7.39.0 -#endif -#ifndef SUPPORT_TLSv1_0 -#define SUPPORT_TLSv1_0 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0 -#endif -#ifndef SUPPORT_TLSv1_1 -#define SUPPORT_TLSv1_1 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0 -#endif -#ifndef SUPPORT_TLSv1_2 -#define SUPPORT_TLSv1_2 LIBCURL_VERSION_NUM >= 0x072200 // 7.34.0 -#endif -#ifndef SUPPORT_TLSv1_3 -#define SUPPORT_TLSv1_3 LIBCURL_VERSION_NUM >= 0x073400 // 7.52.0 -#endif -#ifndef SUPPORT_MAX_TLS_VERSION -#define SUPPORT_MAX_TLS_VERSION LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0 -#endif -#ifndef SUPPORT_MAX_TLSv1_1 -#define SUPPORT_MAX_TLSv1_1 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0 -#endif -#ifndef SUPPORT_MAX_TLSv1_2 -#define SUPPORT_MAX_TLSv1_2 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0 -#endif -#ifndef SUPPORT_MAX_TLSv1_3 -#define SUPPORT_MAX_TLSv1_3 LIBCURL_VERSION_NUM >= 0x073600 // 7.54.0 -#endif -#ifndef SUPPORT_TLSv13_CIPHERS -#define SUPPORT_TLSv13_CIPHERS LIBCURL_VERSION_NUM >= 0x073D00 // 7.61.0 -#endif -#ifndef SUPPORT_SESSIONID_CACHE -#define SUPPORT_SESSIONID_CACHE LIBCURL_VERSION_NUM >= 0x071000 // 7.16.0 -#endif -#ifndef SUPPORT_SSL_FALSESTART -#define SUPPORT_SSL_FALSESTART LIBCURL_VERSION_NUM >= 0x072A00 // 7.42.0 -#endif -#ifndef SUPPORT_SSL_NO_REVOKE -#define SUPPORT_SSL_NO_REVOKE LIBCURL_VERSION_NUM >= 0x072C00 // 7.44.0 -#endif -#ifndef SUPPORT_CURLOPT_SSLKEY_BLOB -#define SUPPORT_CURLOPT_SSLKEY_BLOB LIBCURL_VERSION_NUM >= 0x074700 // 7.71.0 -#endif -#ifndef SUPPORT_CURLOPT_SSL_CTX_FUNCTION -#define SUPPORT_CURLOPT_SSL_CTX_FUNCTION LIBCURL_VERSION_NUM >= 0x070B00 // 7.11.0 -#endif -#ifndef SUPPORT_CURLOPT_CAINFO_BLOB -#define SUPPORT_CURLOPT_CAINFO_BLOB LIBCURL_VERSION_NUM >= 0x074D00 // 7.77.0 -#endif -#ifndef SUPPORT_CURLOPT_SSLCERT_BLOB -#define SUPPORT_CURLOPT_SSLCERT_BLOB LIBCURL_VERSION_NUM >= 0x074700 // 7.71.0 -#endif - -namespace cpr { - -class VerifySsl { - public: - VerifySsl() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - VerifySsl(bool p_verify) : verify(p_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(fs::path&& p_filename) : filename(std::move(p_filename)) {} - - virtual ~CertFile() = default; - - const fs::path filename; - - virtual const char* GetCertType() const { - return "PEM"; - } -}; - -using PemCert = CertFile; - -class DerCert : public CertFile { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - DerCert(fs::path&& p_filename) : CertFile(std::move(p_filename)) {} - - ~DerCert() override = default; - - const char* GetCertType() const override { - return "DER"; - } -}; - - -#if SUPPORT_CURLOPT_SSLCERT_BLOB -class CertBlob { -public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - CertBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} - - virtual ~CertBlob() = default; - - std::string blob; - - virtual const char* GetCertType() const { - return "PEM"; - } -}; - -using PemBlob = CertBlob; - -class DerBlob : public CertBlob { -public: - template - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - DerBlob(BlobType&& p_blob) : CertBlob(std::move(p_blob)) {} - - ~DerBlob() override = default; - - const char* GetCertType() const override { - return "DER"; - } -}; -#endif - -// specify private keyfile for TLS and SSL client cert -class KeyFile { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - KeyFile(fs::path&& 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)) {} - - virtual ~KeyFile() = default; - - fs::path filename; - util::SecureString password; - - virtual const char* GetKeyType() const { - return "PEM"; - } -}; - -#if SUPPORT_CURLOPT_SSLKEY_BLOB -class KeyBlob { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - KeyBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} - - template - KeyBlob(BlobType&& p_blob, PassType p_password) : blob(std::forward(p_blob)), password(std::move(p_password)) {} - - virtual ~KeyBlob() = default; - - std::string blob; - util::SecureString password; - - virtual const char* GetKeyType() const { - return "PEM"; - } -}; -#endif - -using PemKey = KeyFile; - -class DerKey : public KeyFile { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - DerKey(fs::path&& p_filename) : KeyFile(std::move(p_filename)) {} - - template - DerKey(FileType&& p_filename, PassType p_password) : KeyFile(std::forward(p_filename), std::move(p_password)) {} - - ~DerKey() override = default; - - const char* GetKeyType() const override { - return "DER"; - } -}; - -class PinnedPublicKey { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - PinnedPublicKey(std::string&& p_pinned_public_key) : pinned_public_key(std::move(p_pinned_public_key)) {} - - const std::string pinned_public_key; -}; - -#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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_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(fs::path&& p_filename) : filename(std::move(p_filename)) {} - - fs::path filename; -}; - -#if SUPPORT_CURLOPT_CAINFO_BLOB -// Certificate Authority (CA) bundle as blob -class CaInfoBlob { -public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - CaInfoBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} - - std::string blob; -}; -#endif - -// specify directory holding CA certificates -class CaPath { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - CaPath(fs::path&& p_filename) : filename(std::move(p_filename)) {} - - fs::path filename; -}; - -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION -class CaBuffer { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - CaBuffer(std::string&& p_buffer) : buffer(std::move(p_buffer)) {} - - const std::string buffer; -}; -#endif - -// specify a Certificate Revocation List file -class Crl { - public: - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - Crl(fs::path&& p_filename) : filename(std::move(p_filename)) {} - - fs::path 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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_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 p_enabled) : enabled(p_enabled) {} - - explicit operator bool() const { - return enabled; - } - - bool enabled = false; -}; - -} // namespace ssl - -struct SslOptions { - // We don't use fs::path here, as this leads to problems using windows - std::string cert_file; -#if SUPPORT_CURLOPT_SSLCERT_BLOB - util::SecureString cert_blob; -#endif - std::string cert_type; - // We don't use fs::path here, as this leads to problems using windows - std::string key_file; -#if SUPPORT_CURLOPT_SSLKEY_BLOB - util::SecureString key_blob; -#endif - std::string key_type; - util::SecureString key_pass; - std::string pinned_public_key; -#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 - // We don't use fs::path here, as this leads to problems using windows - std::string ca_info; -#if SUPPORT_CURLOPT_CAINFO_BLOB - std::string ca_info_blob; -#endif - // We don't use fs::path here, as this leads to problems using windows - std::string ca_path; -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION - std::string ca_buffer; -#endif - // We don't use fs::path here, as this leads to problems using windows - 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.string(); - cert_type = opt.GetCertType(); - } -#if SUPPORT_CURLOPT_SSLCERT_BLOB - void SetOption(const ssl::CertBlob& opt) { - cert_blob = opt.blob; - cert_type = opt.GetCertType(); - } -#endif - void SetOption(const ssl::KeyFile& opt) { - key_file = opt.filename.string(); - key_type = opt.GetKeyType(); - key_pass = opt.password; - } -#if SUPPORT_CURLOPT_SSLKEY_BLOB - void SetOption(const ssl::KeyBlob& opt) { - key_blob = opt.blob; - key_type = opt.GetKeyType(); - key_pass = opt.password; - } -#endif - void SetOption(const ssl::PinnedPublicKey& opt) { - pinned_public_key = opt.pinned_public_key; - } - -#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.string(); - } -#if SUPPORT_CURLOPT_CAINFO_BLOB - void SetOption(const ssl::CaInfoBlob& opt) { - ca_info_blob = opt.blob; - } -#endif - void SetOption(const ssl::CaPath& opt) { - ca_path = opt.filename.string(); - } -#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION - void SetOption(const ssl::CaBuffer& opt) { - ca_buffer = opt.buffer; - } -#endif - void SetOption(const ssl::Crl& opt) { - crl_file = opt.filename.string(); - } - 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 deleted file mode 100644 index 53e0d251d..000000000 --- a/vendor/cpr/include/cpr/status_codes.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef CPR_STATUS_CODES -#define CPR_STATUS_CODES -namespace cpr { -namespace status { -// Information responses -constexpr long HTTP_CONTINUE = 100; -constexpr long HTTP_SWITCHING_PROTOCOL = 101; -constexpr long HTTP_PROCESSING = 102; -constexpr long HTTP_EARLY_HINTS = 103; -// Successful responses -constexpr long HTTP_OK = 200; -constexpr long HTTP_CREATED = 201; -constexpr long HTTP_ACCEPTED = 202; -constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203; -constexpr long HTTP_NO_CONTENT = 204; -constexpr long HTTP_RESET_CONTENT = 205; -constexpr long HTTP_PARTIAL_CONTENT = 206; -constexpr long HTTP_MULTI_STATUS = 207; -constexpr long HTTP_ALREADY_REPORTED = 208; -constexpr long HTTP_IM_USED = 226; -// Redirection messages -constexpr long HTTP_MULTIPLE_CHOICE = 300; -constexpr long HTTP_MOVED_PERMANENTLY = 301; -constexpr long HTTP_FOUND = 302; -constexpr long HTTP_SEE_OTHER = 303; -constexpr long HTTP_NOT_MODIFIED = 304; -constexpr long HTTP_USE_PROXY = 305; -constexpr long HTTP_UNUSED = 306; -constexpr long HTTP_TEMPORARY_REDIRECT = 307; -constexpr long HTTP_PERMANENT_REDIRECT = 308; -// Client error responses -constexpr long HTTP_BAD_REQUEST = 400; -constexpr long HTTP_UNAUTHORIZED = 401; -constexpr long HTTP_PAYMENT_REQUIRED = 402; -constexpr long HTTP_FORBIDDEN = 403; -constexpr long HTTP_NOT_FOUND = 404; -constexpr long HTTP_METHOD_NOT_ALLOWED = 405; -constexpr long HTTP_NOT_ACCEPTABLE = 406; -constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; -constexpr long HTTP_REQUEST_TIMEOUT = 408; -constexpr long HTTP_CONFLICT = 409; -constexpr long HTTP_GONE = 410; -constexpr long HTTP_LENGTH_REQUIRED = 411; -constexpr long HTTP_PRECONDITION_FAILED = 412; -constexpr long HTTP_PAYLOAD_TOO_LARGE = 413; -constexpr long HTTP_URI_TOO_LONG = 414; -constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415; -constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; -constexpr long HTTP_EXPECTATION_FAILED = 417; -constexpr long HTTP_IM_A_TEAPOT = 418; -constexpr long HTTP_MISDIRECTED_REQUEST = 421; -constexpr long HTTP_UNPROCESSABLE_ENTITY = 422; -constexpr long HTTP_LOCKED = 423; -constexpr long HTTP_FAILED_DEPENDENCY = 424; -constexpr long HTTP_TOO_EARLY = 425; -constexpr long HTTP_UPGRADE_REQUIRED = 426; -constexpr long HTTP_PRECONDITION_REQUIRED = 428; -constexpr long HTTP_TOO_MANY_REQUESTS = 429; -constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; -constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; -// Server response errors -constexpr long HTTP_INTERNAL_SERVER_ERROR = 500; -constexpr long HTTP_NOT_IMPLEMENTED = 501; -constexpr long HTTP_BAD_GATEWAY = 502; -constexpr long HTTP_SERVICE_UNAVAILABLE = 503; -constexpr long HTTP_GATEWAY_TIMEOUT = 504; -constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505; -constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506; -constexpr long HTTP_INSUFFICIENT_STORAGE = 507; -constexpr long HTTP_LOOP_DETECTED = 508; -constexpr long HTTP_NOT_EXTENDED = 510; -constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; - -constexpr long INFO_CODE_OFFSET = 100; -constexpr long SUCCESS_CODE_OFFSET = 200; -constexpr long REDIRECT_CODE_OFFSET = 300; -constexpr long CLIENT_ERROR_CODE_OFFSET = 400; -constexpr long SERVER_ERROR_CODE_OFFSET = 500; -constexpr long MISC_CODE_OFFSET = 600; - -constexpr bool is_informational(const long code) { - return (code >= INFO_CODE_OFFSET && code < SUCCESS_CODE_OFFSET); -} -constexpr bool is_success(const long code) { - return (code >= SUCCESS_CODE_OFFSET && code < REDIRECT_CODE_OFFSET); -} -constexpr bool is_redirect(const long code) { - return (code >= REDIRECT_CODE_OFFSET && code < CLIENT_ERROR_CODE_OFFSET); -} -constexpr bool is_client_error(const long code) { - return (code >= CLIENT_ERROR_CODE_OFFSET && code < SERVER_ERROR_CODE_OFFSET); -} -constexpr bool is_server_error(const long code) { - return (code >= SERVER_ERROR_CODE_OFFSET && code < MISC_CODE_OFFSET); -} - -} // namespace status -} // namespace cpr -#endif diff --git a/vendor/cpr/include/cpr/threadpool.h b/vendor/cpr/include/cpr/threadpool.h deleted file mode 100644 index 346ff025c..000000000 --- a/vendor/cpr/include/cpr/threadpool.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef CPR_THREAD_POOL_H -#define CPR_THREAD_POOL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency() - -constexpr size_t CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM = 1; -constexpr std::chrono::milliseconds CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME{250}; - -namespace cpr { - -class ThreadPool { - public: - using Task = std::function; - - explicit ThreadPool(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME); - ThreadPool(const ThreadPool& other) = delete; - ThreadPool(ThreadPool&& old) = delete; - - virtual ~ThreadPool(); - - ThreadPool& operator=(const ThreadPool& other) = delete; - ThreadPool& operator=(ThreadPool&& old) = delete; - - void SetMinThreadNum(size_t min_threads) { - min_thread_num = min_threads; - } - - void SetMaxThreadNum(size_t max_threads) { - max_thread_num = max_threads; - } - - void SetMaxIdleTime(std::chrono::milliseconds ms) { - max_idle_time = ms; - } - - size_t GetCurrentThreadNum() { - return cur_thread_num; - } - - size_t GetIdleThreadNum() { - return idle_thread_num; - } - - bool IsStarted() const { - return status != STOP; - } - - bool IsStopped() const { - return status == STOP; - } - - int Start(size_t start_threads = 0); - int Stop(); - int Pause(); - int Resume(); - int Wait() const; - - /** - * Return a future, calling future.get() will wait task done and return RetType. - * Submit(fn, args...) - * Submit(std::bind(&Class::mem_fn, &obj)) - * Submit(std::mem_fn(&Class::mem_fn, &obj)) - **/ - template - auto Submit(Fn&& fn, Args&&... args) { - if (status == STOP) { - Start(); - } - if (idle_thread_num <= 0 && cur_thread_num < max_thread_num) { - CreateThread(); - } - using RetType = decltype(fn(args...)); - auto task = std::make_shared>([fn = std::forward(fn), args...]() mutable { return std::invoke(fn, args...); }); - std::future future = task->get_future(); - { - std::lock_guard locker(task_mutex); - tasks.emplace([task] { (*task)(); }); - } - - task_cond.notify_one(); - return future; - } - - private: - bool CreateThread(); - void AddThread(const std::shared_ptr& thread); - void DelThread(std::thread::id id); - - public: - size_t min_thread_num; - size_t max_thread_num; - std::chrono::milliseconds max_idle_time; - - private: - enum Status { - STOP, - RUNNING, - PAUSE, - }; - - struct ThreadData { - std::shared_ptr thread; - std::thread::id id; - Status status; - std::chrono::steady_clock::time_point start_time; - std::chrono::steady_clock::time_point stop_time; - }; - - std::atomic status{Status::STOP}; - std::condition_variable status_wait_cond{}; - std::mutex status_wait_mutex{}; - - std::atomic cur_thread_num{0}; - std::atomic idle_thread_num{0}; - - std::list threads{}; - std::mutex thread_mutex{}; - - std::queue tasks{}; - std::mutex task_mutex{}; - std::condition_variable task_cond{}; -}; - -} // namespace cpr - -#endif diff --git a/vendor/cpr/include/cpr/timeout.h b/vendor/cpr/include/cpr/timeout.h deleted file mode 100644 index af80a1b7a..000000000 --- a/vendor/cpr/include/cpr/timeout.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CPR_TIMEOUT_H -#define CPR_TIMEOUT_H - -#include -#include - -namespace cpr { - -class Timeout { - public: - // Template constructor to accept any chrono duration type and convert it to milliseconds - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - template - Timeout(const std::chrono::duration& duration) : ms{std::chrono::duration_cast(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 deleted file mode 100644 index 152caf0ca..000000000 --- a/vendor/cpr/include/cpr/unix_socket.h +++ /dev/null @@ -1,21 +0,0 @@ -#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 deleted file mode 100644 index a3cc1293d..000000000 --- a/vendor/cpr/include/cpr/user_agent.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CPR_USERAGENT_H -#define CPR_USERAGENT_H - -#include -#include - -#include "cpr/cprtypes.h" - -namespace cpr { -class UserAgent : public StringHolder { - public: - UserAgent() = default; - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - UserAgent(std::string useragent) : StringHolder(std::move(useragent)) {} - // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) - UserAgent(std::string_view useragent) : StringHolder(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 deleted file mode 100644 index 4ffd02df6..000000000 --- a/vendor/cpr/include/cpr/util.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef CPR_UTIL_H -#define CPR_UTIL_H - -#include -#include -#include -#include - -#include "cpr/callback.h" -#include "cpr/cookies.h" -#include "cpr/cprtypes.h" -#include "cpr/secure_string.h" -#include "cpr/sse.h" - -namespace cpr::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, void* 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); -size_t writeSSEFunction(char* ptr, size_t size, size_t nmemb, ServerSentEventCallback* sse); - -template -int progressUserFunction(const T* progress, cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) { - const int cancel_retval{1}; -#ifdef CURL_PROGRESSFUNC_CONTINUE // Not always defined. Ref: https://github.com/libcpr/cpr/issues/932 - static_assert(cancel_retval != CURL_PROGRESSFUNC_CONTINUE); -#endif // CURL_PROGRESSFUNC_CONTINUE - return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : cancel_retval; -} -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); -util::SecureString urlEncode(std::string_view s); -util::SecureString urlDecode(std::string_view s); - -bool isTrue(const std::string& s); - -/** - * Parses the given std::string into time_t (unix ms). - * This parsing happens time_t size agnostic since time_t does not use the same underlying type on all systems/compilers. - **/ -time_t sTimestampToT(const std::string&); - -} // namespace cpr::util - -#endif diff --git a/vendor/cpr/include/cpr/verbose.h b/vendor/cpr/include/cpr/verbose.h deleted file mode 100644 index 2bf0df8f0..000000000 --- a/vendor/cpr/include/cpr/verbose.h +++ /dev/null @@ -1,18 +0,0 @@ -#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 p_verbose) : verbose{p_verbose} {} - - bool verbose = true; -}; - -} // namespace cpr - - -#endif /* CPR_VERBOSE_H_ */