diff --git a/.github/workflows/ci-debian.yml b/.github/workflows/ci-debian.yml
index c705981107f565dd775c389758e444f2da22812f..88b3f2d557c324e2b00aae53bb7d8638cd5e3f0a 100644
--- a/.github/workflows/ci-debian.yml
+++ b/.github/workflows/ci-debian.yml
@@ -51,7 +51,7 @@ jobs:
- uses: xmake-io/github-action-setup-xmake@v1
with:
- xmake-version: v2.8.7
+ xmake-version: v2.9.9
actions-cache-folder: '.xmake-cache'
- name: xmake repo --update
diff --git a/.github/workflows/ci-fedora.yml b/.github/workflows/ci-fedora.yml
index 8216a0bc0bd2254e19bdbb332bcd371129f63660..fda7c09bce5c5630280d8df7ee1ec0d3b553b1ec 100644
--- a/.github/workflows/ci-fedora.yml
+++ b/.github/workflows/ci-fedora.yml
@@ -34,7 +34,7 @@ jobs:
- name: Install dependencies
run: |
sudo dnf update -y
- sudo dnf install -y gcc g++ xmake git unzip curl
+ sudo dnf install -y gcc g++ xmake git unzip curl perl
- uses: actions/checkout@v3
with:
fetch-depth: 1
diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml
index c47c8cce328fbb985260ae5160ce057e053d40e7..61d5ff5f955babb67a31b1a17b1896655e423327 100644
--- a/.github/workflows/ci-macos.yml
+++ b/.github/workflows/ci-macos.yml
@@ -43,7 +43,7 @@ jobs:
- uses: xmake-io/github-action-setup-xmake@v1
with:
- xmake-version: v2.8.7
+ xmake-version: v2.9.9
actions-cache-folder: '.xmake-cache'
- name: xmake repo --update
diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml
index 23aeeaa8a24907bc905a22bcea90639ddcc1d6db..fb3e8649310e1f36956df366ae913264d0389dfe 100644
--- a/.github/workflows/ci-windows.yml
+++ b/.github/workflows/ci-windows.yml
@@ -32,7 +32,7 @@ jobs:
steps:
- uses: xmake-io/github-action-setup-xmake@v1
with:
- xmake-version: v2.8.9
+ xmake-version: v2.9.9
- name: update repo
run: xmake repo -u
- name: git crlf
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7578bded0c102ac04ba8be8e7a52d8d19336d0b0
--- /dev/null
+++ b/.github/workflows/package.yml
@@ -0,0 +1,89 @@
+name: XPack Build
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: true
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Install Dependencies
+ run: |
+ sudo add-apt-repository ppa:xmake-io/xmake
+ sudo apt update
+ sudo apt install -y git \
+ curl 7zip unzip curl \
+ gcc g++ \
+ devscripts debhelper build-essential \
+ xmake # xmake must be installed by apt (dpkg)
+
+ - name: git add safe directory
+ run: git config --global --add safe.directory '*'
+
+
+ - name: set XMAKE_GLOBALDIR
+ run: echo "XMAKE_GLOBALDIR=${{ runner.workspace }}/xmake-global" >> $GITHUB_ENV
+
+ - name: xmake repo --update
+ run: xmake repo --update
+
+ - name: cache packages from xrepo
+ uses: actions/cache@v3
+ with:
+ path: |
+ ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages
+ key: ${{ runner.os }}-xrepo-${{ hashFiles('**/xmake.lua') }}
+
+ - name: Config and Build
+ run: |
+ sed -i 's|"deb", "rpm", "srpm"|"deb"|g' xmake.lua
+ sed -i 's|set_default(false) -- repl-anchor|set_default(true)|g' xmake.lua
+
+ xmake config -vyD --policies=build.ccache -o tmp/build -m releasedbg --repl=true
+ xmake build goldfish
+
+ - name: Package
+ run: xmake pack -vyD goldfish
+
+ - name: Create summary table
+ run: |
+ echo "## 生成的包文件" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "| 类型 | 文件名 | 大小 | 版本 | 架构 |" >> $GITHUB_STEP_SUMMARY
+ echo "|------|--------|------|------|------|" >> $GITHUB_STEP_SUMMARY
+
+ DIR="tmp/build/xpack/goldfish"
+
+ # Debian 包
+ for deb in "$DIR"/*.deb; do
+ if [ -f "$deb" ]; then
+ size=$(ls -lh "$deb" | awk '{print $5}')
+ info=$(dpkg-deb -f "$deb" 2>/dev/null)
+ pkg=$(echo "$info" | grep "^Package" | cut -d' ' -f2- || echo "")
+ ver=$(echo "$info" | grep "^Version" | cut -d' ' -f2- || echo "")
+ arch=$(echo "$info" | grep "^Architecture" | cut -d' ' -f2- || echo "")
+
+ echo "| Debian | \`$(basename "$deb")\` | $size | $ver | $arch |" >> $GITHUB_STEP_SUMMARY
+ fi
+ done
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "*目录: \`$DIR\`*" >> $GITHUB_STEP_SUMMARY
+
+ - name: Upload all package artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: goldfish-packages
+ path: tmp/build/xpack/goldfish/*.deb
+ retention-days: 30
+ if-no-files-found: error
diff --git a/3rdparty/cpr/CMakeLists.txt b/3rdparty/cpr/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..30208bcd5caa6c4c0910e6c839f5e6ec8cc9cefc
--- /dev/null
+++ b/3rdparty/cpr/CMakeLists.txt
@@ -0,0 +1,400 @@
+cmake_minimum_required(VERSION 3.15)
+project(cpr VERSION 1.11.1 LANGUAGES CXX)
+
+math(EXPR cpr_VERSION_NUM "${cpr_VERSION_MAJOR} * 0x10000 + ${cpr_VERSION_MINOR} * 0x100 + ${cpr_VERSION_PATCH}" OUTPUT_FORMAT HEXADECIMAL)
+configure_file("${cpr_SOURCE_DIR}/cmake/cprver.h.in" "${cpr_BINARY_DIR}/cpr_generated_includes/cpr/cprver.h")
+
+# Only change the folder behaviour if cpr is not a subproject
+if(${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake")
+ set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
+ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
+else()
+ # Check required c++ standard of parent project
+ if(CMAKE_CXX_STANDARD)
+ set(PARENT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
+ message(STATUS "CXX standard of parent project: ${PARENT_CXX_STANDARD}")
+ endif()
+endif()
+
+# Avoid the dll boilerplate code for windows
+set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+
+if (PARENT_CXX_STANDARD)
+ # Don't set CMAKE_CXX_STANDARD if it is already set by parent project
+ if (PARENT_CXX_STANDARD LESS 17)
+ message(FATAL_ERROR "cpr ${cpr_VERSION} does not support ${PARENT_CXX_STANDARD}. Please use cpr <= 1.9.x")
+ endif()
+else()
+ # Set standard version if not already set by potential parent project
+ set(CMAKE_CXX_STANDARD 17)
+endif()
+
+message(STATUS "CXX standard: ${CMAKE_CXX_STANDARD}")
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(CPR_LIBRARIES cpr CACHE INTERNAL "")
+
+macro(cpr_option OPTION_NAME OPTION_TEXT OPTION_DEFAULT)
+ option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT})
+ if(DEFINED ENV{${OPTION_NAME}})
+ # Allow overriding the option through an environment variable
+ set(${OPTION_NAME} $ENV{${OPTION_NAME}})
+ endif()
+ if(${OPTION_NAME})
+ add_definitions(-D${OPTION_NAME})
+ endif()
+ message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}")
+endmacro()
+
+message(STATUS "C++ Requests CMake Options")
+message(STATUS "=======================================================")
+cpr_option(CPR_GENERATE_COVERAGE "Set to ON to generate coverage reports." OFF)
+cpr_option(CPR_CURL_NOSIGNAL "Set to ON to disable use of signals in libcurl." OFF)
+cpr_option(CURL_VERBOSE_LOGGING "Curl verbose logging during building curl" OFF)
+cpr_option(CPR_USE_SYSTEM_GTEST "If ON, this project will look in the system paths for an installed gtest library. If none is found it will use the built-in one." OFF)
+cpr_option(CPR_USE_SYSTEM_CURL "If enabled we will use the curl lib already installed on this system." OFF)
+cpr_option(CPR_ENABLE_CURL_HTTP_ONLY "If enabled we will only use the HTTP/HTTPS protocols from CURL. If disabled, all the CURL protocols are enabled. This is useful if your project uses libcurl and you need support for other CURL features e.g. sending emails." ON)
+cpr_option(CPR_ENABLE_SSL "Enables or disables the SSL backend. Required to perform HTTPS requests." ON)
+cpr_option(CPR_FORCE_OPENSSL_BACKEND "Force to use the OpenSSL backend. If CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, and CPR_FORCE_WINSSL_BACKEND are set to to OFF, cpr will try to automatically detect the best available SSL backend (WinSSL - Windows, OpenSSL - Linux, DarwinSSL - Mac ...)." OFF)
+cpr_option(CPR_FORCE_WINSSL_BACKEND "Force to use the WinSSL backend. If CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, and CPR_FORCE_WINSSL_BACKEND are set to to OFF, cpr will try to automatically detect the best available SSL backend (WinSSL - Windows, OpenSSL - Linux, DarwinSSL - Mac ...)." OFF)
+cpr_option(CPR_FORCE_DARWINSSL_BACKEND "Force to use the DarwinSSL backend. If CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, and CPR_FORCE_WINSSL_BACKEND are set to to OFF, cpr will try to automatically detect the best available SSL backend (WinSSL - Windows, OpenSSL - Linux, DarwinSSL - Mac ...)." OFF)
+cpr_option(CPR_FORCE_MBEDTLS_BACKEND "Force to use the Mbed TLS backend. If CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, and CPR_FORCE_WINSSL_BACKEND are set to to OFF, cpr will try to automatically detect the best available SSL backend (WinSSL - Windows, OpenSSL - Linux, DarwinSSL - Mac ...)." OFF)
+cpr_option(CPR_ENABLE_LINTING "Set to ON to enable clang linting." OFF)
+cpr_option(CPR_ENABLE_CPPCHECK "Set to ON to enable Cppcheck static analysis. Requires CPR_BUILD_TESTS and CPR_BUILD_TESTS_SSL to be OFF to prevent checking google tests source code." OFF)
+cpr_option(CPR_BUILD_TESTS "Set to ON to build cpr tests." OFF)
+cpr_option(CPR_BUILD_TESTS_SSL "Set to ON to build cpr ssl tests" ${CPR_BUILD_TESTS})
+cpr_option(CPR_BUILD_TESTS_PROXY "Set to ON to build proxy tests. They fail in case there is no valid proxy server available in proxy_tests.cpp" OFF)
+cpr_option(CPR_BUILD_VERSION_OUTPUT_ONLY "Set to ON to only export the version into 'build/version.txt' and exit" OFF)
+cpr_option(CPR_SKIP_CA_BUNDLE_SEARCH "Skip searching for Certificate Authority certs. Turn ON for systems like iOS where file access is restricted and prevents https from working." OFF)
+cpr_option(CPR_USE_BOOST_FILESYSTEM "Set to ON to use the Boost.Filesystem library. This is useful, on, e.g., Apple platforms, where std::filesystem may not always be available when targeting older OS versions." OFF)
+cpr_option(CPR_DEBUG_SANITIZER_FLAG_THREAD "Enables the ThreadSanitizer for debug builds." OFF)
+cpr_option(CPR_DEBUG_SANITIZER_FLAG_ADDR "Enables the AddressSanitizer for debug builds." OFF)
+cpr_option(CPR_DEBUG_SANITIZER_FLAG_LEAK "Enables the LeakSanitizer for debug builds." OFF)
+cpr_option(CPR_DEBUG_SANITIZER_FLAG_UB "Enables the UndefinedBehaviorSanitizer for debug builds." OFF)
+cpr_option(CPR_DEBUG_SANITIZER_FLAG_ALL "Enables all sanitizers for debug builds except the ThreadSanitizer since it is incompatible with the other sanitizers." OFF)
+message(STATUS "=======================================================")
+
+# Save the project version as txt file for deb and NuGet builds
+if(CPR_BUILD_VERSION_OUTPUT_ONLY)
+ message(STATUS "Printing version and exiting...")
+ file(WRITE "${CMAKE_BINARY_DIR}/version.txt" "${PROJECT_VERSION}")
+ return()
+endif()
+
+if (CPR_FORCE_USE_SYSTEM_CURL)
+ message(WARNING "The variable CPR_FORCE_USE_SYSTEM_CURL is deprecated, please use CPR_USE_SYSTEM_CURL instead")
+ set(CPR_USE_SYSTEM_CURL ${CPR_FORCE_USE_SYSTEM_CURL})
+endif()
+
+include(GNUInstallDirs)
+include(FetchContent)
+include(cmake/code_coverage.cmake)
+include(cmake/sanitizer.cmake)
+include(cmake/clear_variable.cmake)
+
+# So CMake can find FindMbedTLS.cmake
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
+
+# Linting
+if(CPR_ENABLE_LINTING)
+ include(cmake/clang-tidy.cmake)
+endif()
+
+# Cppcheck
+if(CPR_ENABLE_CPPCHECK)
+ if(CPR_BUILD_TESTS OR CPR_BUILD_TESTS_SSL)
+ message(FATAL_ERROR "Cppcheck is incompatible with building tests. Make sure to disable CPR_ENABLE_CPPCHECK or disable tests by setting CPR_BUILD_TESTS and CPR_BUILD_TESTS_SSL to OFF. This is because Cppcheck would try to check the google tests source code and then fail. ")
+ endif()
+ include(cmake/cppcheck.cmake)
+endif()
+
+# SSL
+if(CPR_ENABLE_SSL)
+ if(CPR_FORCE_OPENSSL_BACKEND OR CPR_FORCE_WINSSL_BACKEND OR CPR_FORCE_DARWINSSL_BACKEND OR CPR_FORCE_MBEDTLS_BACKEND)
+ message(STATUS "Disabled SSL backend auto detect since either CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, or CPR_FORCE_WINSSL_BACKEND is enabled.")
+ set(DETECT_SSL_BACKEND OFF CACHE INTERNAL "" FORCE)
+ else()
+ message(STATUS "Automatically detecting SSL backend.")
+ set(DETECT_SSL_BACKEND ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ if(CPR_FORCE_WINSSL_BACKEND AND (NOT WIN32))
+ message(FATAL_ERROR "WinSSL is only available on Windows! Use either OpenSSL (CPR_FORCE_OPENSSL_BACKEND) or DarwinSSL (CPR_FORCE_DARWINSSL_BACKEND) instead.")
+ endif()
+
+ if(DETECT_SSL_BACKEND)
+ message(STATUS "Detecting SSL backend...")
+ if(WIN32)
+ message(STATUS "SSL auto detect: Using WinSSL.")
+ set(SSL_BACKEND_USED "WinSSL")
+ elseif(APPLE)
+ message(STATUS "SSL auto detect: Using DarwinSSL.")
+ set(CPR_BUILD_TESTS_SSL OFF)
+ set(SSL_BACKEND_USED "DarwinSSL")
+ else()
+ find_package(OpenSSL)
+ if(OPENSSL_FOUND)
+ message(STATUS "SSL auto detect: Using OpenSSL.")
+ set(SSL_BACKEND_USED "OpenSSL")
+ else()
+ find_package(MbedTLS)
+ if(MBEDTLS_FOUND)
+ set(SSL_BACKEND_USED "MbedTLS")
+ else()
+ message(FATAL_ERROR "No valid SSL backend found! Please install OpenSSL, Mbed TLS or disable SSL by setting CPR_ENABLE_SSL to OFF.")
+ endif()
+ endif()
+ endif()
+ else()
+ if(CPR_FORCE_OPENSSL_BACKEND)
+ find_package(OpenSSL)
+ if(OPENSSL_FOUND)
+ message(STATUS "Using OpenSSL.")
+ set(SSL_BACKEND_USED "OpenSSL")
+ else()
+ message(FATAL_ERROR "CPR_FORCE_OPENSSL_BACKEND enabled but we were not able to find OpenSSL!")
+ endif()
+ elseif(CPR_FORCE_WINSSL_BACKEND)
+ message(STATUS "Using WinSSL.")
+ set(SSL_BACKEND_USED "WinSSL")
+ elseif(CPR_FORCE_DARWINSSL_BACKEND)
+ message(STATUS "Using DarwinSSL.")
+ set(CPR_BUILD_TESTS_SSL OFF)
+ set(SSL_BACKEND_USED "DarwinSSL")
+ elseif(CPR_FORCE_MBEDTLS_BACKEND)
+ message(STATUS "Using Mbed TLS.")
+ set(CPR_BUILD_TESTS_SSL OFF)
+ set(SSL_BACKEND_USED "MbedTLS")
+ endif()
+ endif()
+endif()
+
+if(SSL_BACKEND_USED STREQUAL "OpenSSL")
+# Fix missing OpenSSL includes for Windows since in 'ssl_ctx.cpp' we include OpenSSL directly
+find_package(OpenSSL REQUIRED)
+ add_compile_definitions(OPENSSL_BACKEND_USED)
+endif()
+
+# Curl configuration
+if(CPR_USE_SYSTEM_CURL)
+ if(CPR_ENABLE_SSL)
+ find_package(CURL COMPONENTS HTTP HTTPS)
+ if(CURL_FOUND)
+ message(STATUS "Curl ${CURL_VERSION_STRING} found on this system.")
+
+ # To be able to load certificates under Windows when using OpenSSL:
+ if(CMAKE_USE_OPENSSL AND WIN32 AND (NOT (CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.71.0")))
+ message(FATAL_ERROR "Your system curl version (${CURL_VERSION_STRING}) is too old to support OpenSSL on Windows which requires curl >= 7.71.0. Update your curl version, use WinSSL, disable SSL or use the built-in version of curl.")
+ endif()
+ else()
+ find_package(CURL COMPONENTS HTTP)
+ if(CURL_FOUND)
+ message(FATAL_ERROR "Curl found on this system but WITHOUT HTTPS/SSL support. Either disable SSL by setting CPR_ENABLE_SSL to OFF or use the built-in version of curl by setting CPR_USE_SYSTEM_CURL to OFF.")
+ else()
+ message(FATAL_ERROR "Curl not found on this system. To use the built-in version set CPR_USE_SYSTEM_CURL to OFF.")
+ endif()
+ endif()
+ else()
+ find_package(CURL COMPONENTS HTTP)
+ if(CURL_FOUND)
+ message(STATUS "Curl found on this system.")
+ else()
+ message(FATAL_ERROR "Curl not found on this system. To use the built-in version set CPR_USE_SYSTEM_CURL to OFF.")
+ endif()
+ endif()
+
+ # Check for the minimum supported curl version
+ if(NOT (CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.64.0"))
+ message(FATAL_ERROR "Your system curl version (${CURL_VERSION_STRING}) is too old! curl >= 7.64.0 is required. Update your curl version, or use the build in curl version e.g. via `cmake .. -DCPR_USE_SYSTEM_CURL=OFF` during CMake configure.")
+ endif()
+else()
+ message(STATUS "Configuring built-in curl...")
+
+ # ZLIB is optional for curl
+ # to disable it:
+ # * from command line:
+ # -DCURL_ZLIB=OFF
+ # * from CMake script:
+ if (CURL_ZLIB OR CURL_ZLIB STREQUAL AUTO OR NOT DEFINED CACHE{CURL_ZLIB})
+ include(cmake/zlib_external.cmake)
+ endif()
+
+ if (CPR_ENABLE_CURL_HTTP_ONLY)
+ # We only need HTTP (and HTTPS) support:
+ set(HTTP_ONLY ON CACHE INTERNAL "" FORCE)
+ endif()
+ set(BUILD_CURL_EXE OFF CACHE INTERNAL "" FORCE)
+ set(BUILD_TESTING OFF)
+
+ if (CURL_VERBOSE_LOGGING)
+ message(STATUS "Enabled curl debug features")
+ set(ENABLE_DEBUG ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ if (CPR_ENABLE_SSL)
+ set(CURL_ENABLE_SSL ON CACHE INTERNAL "" FORCE)
+ if(ANDROID)
+ set(CURL_CA_PATH "/system/etc/security/cacerts" CACHE INTERNAL "")
+ elseif(CPR_SKIP_CA_BUNDLE_SEARCH)
+ set(CURL_CA_PATH "none" CACHE INTERNAL "")
+ else()
+ set(CURL_CA_PATH "auto" CACHE INTERNAL "")
+ endif()
+
+ if(CPR_SKIP_CA_BUNDLE_SEARCH)
+ set(CURL_CA_BUNDLE "none" CACHE INTERNAL "")
+ elseif(NOT DEFINED CURL_CA_BUNDLE)
+ set(CURL_CA_BUNDLE "auto" CACHE INTERNAL "")
+ endif()
+
+ if(SSL_BACKEND_USED STREQUAL "WinSSL")
+ set(CURL_USE_SCHANNEL ON CACHE INTERNAL "" FORCE)
+ set(CURL_WINDOWS_SSPI ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ if(SSL_BACKEND_USED STREQUAL "OpenSSL")
+ set(CURL_USE_OPENSSL ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ if(SSL_BACKEND_USED STREQUAL "DarwinSSL")
+ set(CURL_USE_SECTRANSP ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ if(SSL_BACKEND_USED STREQUAL "MbedTLS")
+ set(CURL_USE_MBEDTLS ON CACHE INTERNAL "" FORCE)
+ endif()
+
+ message(STATUS "Enabled curl SSL")
+ else()
+ set(CURL_ENABLE_SSL OFF CACHE INTERNAL "" FORCE)
+
+ set(CURL_CA_PATH "none" CACHE INTERNAL "" FORCE)
+ set(CURL_USE_SCHANNEL OFF CACHE INTERNAL "" FORCE)
+ set(CURL_WINDOWS_SSPI OFF CACHE INTERNAL "" FORCE)
+ set(CURL_USE_OPENSSL OFF CACHE INTERNAL "" FORCE)
+ set(CURL_USE_SECTRANSP OFF CACHE INTERNAL "" FORCE)
+ set(CURL_USE_MBEDTLS OFF CACHE INTERNAL "" FORCE)
+ message(STATUS "Disabled curl SSL")
+ endif()
+ # Disable linting for curl
+ clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+
+ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
+ cmake_policy(SET CMP0135 NEW)
+ endif()
+ FetchContent_Declare(curl
+ URL https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.xz
+ URL_HASH SHA256=73a4b0e99596a09fa5924a4fb7e4b995a85fda0d18a2c02ab9cf134bebce04ee # the file hash for curl-8.10.1.tar.xz
+ USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress
+ FetchContent_MakeAvailable(curl)
+
+ restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+endif()
+
+# Depending on which version of libcurl we are using the CMake target is called differently
+if(TARGET libcurl)
+ # Old curl CMake target name
+ set(CURL_LIB libcurl)
+else()
+ # New curl CMake target name
+ set(CURL_LIB CURL::libcurl)
+endif()
+
+# GTest configuration
+if(CPR_BUILD_TESTS)
+ if(CPR_USE_SYSTEM_GTEST)
+ find_package(GTest)
+ endif()
+ if(NOT CPR_USE_SYSTEM_GTEST OR NOT GTEST_FOUND)
+ message(STATUS "Not using system gtest, using built-in googletest project instead.")
+ if(MSVC)
+ # By default, GTest compiles on Windows in CRT static linkage mode. We use this
+ # variable to force it into using the CRT in dynamic linkage (DLL), just as CPR
+ # does.
+ set(gtest_force_shared_crt ON CACHE BOOL "Force gtest to use the shared c runtime")
+ endif()
+
+ # Disable linting for google test
+ clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+
+ FetchContent_Declare(googletest
+ URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz
+ URL_HASH SHA256=8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 # the file hash for release-1.14.0.tar.gz
+ USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress
+ FetchContent_MakeAvailable(googletest)
+
+ restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+
+ add_library(gtest_int INTERFACE)
+ target_link_libraries(gtest_int INTERFACE gtest)
+ target_include_directories(gtest_int INTERFACE ${googletest_SOURCE_DIR}/include)
+
+ add_library(GTest::GTest ALIAS gtest_int)
+
+ # Group under the "tests/gtest" project folder in IDEs such as Visual Studio.
+ set_property(TARGET gtest PROPERTY FOLDER "tests/gtest")
+ set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest")
+ endif()
+endif()
+
+
+# Mongoose configuration
+if(CPR_BUILD_TESTS)
+ message(STATUS "Building mongoose project for test support.")
+
+ if(CPR_BUILD_TESTS_SSL)
+ if(NOT CPR_ENABLE_SSL)
+ message(FATAL_ERROR "OpenSSL is required to build SSL test but CPR_ENABLE_SSL is disabled. Either set CPR_ENABLE_SSL to ON or disable CPR_BUILD_TESTS_SSL.")
+ endif()
+
+ if(NOT(SSL_BACKEND_USED STREQUAL "OpenSSL"))
+ message(FATAL_ERROR "OpenSSL is required for SSL test, but it seams like OpenSSL is not being used as SSL backend. Either set CPR_BUILD_TESTS_SSL to OFF or set CPR_FORCE_OPENSSL_BACKEND to ON and try again.")
+ endif()
+
+ set(ENABLE_SSL_TESTS ON CACHE INTERNAL "")
+ else()
+ set(ENABLE_SSL_TESTS OFF CACHE INTERNAL "")
+ endif()
+
+ # Disable linting for mongoose
+ clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+
+ FetchContent_Declare(mongoose
+ URL https://github.com/cesanta/mongoose/archive/7.7.tar.gz
+ URL_HASH SHA256=4e5733dae31c3a81156af63ca9aa3a6b9b736547f21f23c3ab2f8e3f1ecc16c0 # the hash for 7.7.tar.gz
+ USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress
+ # We can not use FetchContent_MakeAvailable, since we need to patch mongoose to use CMake
+ if (NOT mongoose_POPULATED)
+ FetchContent_POPULATE(mongoose)
+
+ file(INSTALL cmake/mongoose.CMakeLists.txt DESTINATION ${mongoose_SOURCE_DIR})
+ file(RENAME ${mongoose_SOURCE_DIR}/mongoose.CMakeLists.txt ${mongoose_SOURCE_DIR}/CMakeLists.txt)
+ add_subdirectory(${mongoose_SOURCE_DIR} ${mongoose_BINARY_DIR})
+
+ endif()
+ # Group under the "external" project folder in IDEs such as Visual Studio.
+ set_property(TARGET mongoose PROPERTY FOLDER "external")
+ restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+endif()
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ # Disable C++98 compatibility support in clang: https://github.com/libcpr/cpr/issues/927
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-nonportable-system-include-path -Wno-exit-time-destructors -Wno-undef -Wno-global-constructors -Wno-switch-enum -Wno-old-style-cast -Wno-covered-switch-default -Wno-undefined-func-template")
+ endif()
+endif()
+
+add_subdirectory(cpr)
+add_subdirectory(include)
+
+if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND CPR_BUILD_TESTS)
+ # Disable linting for tests since they are currently not up to the standard
+ clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+ enable_testing()
+ add_subdirectory(test)
+ restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
+endif()
diff --git a/3rdparty/cpr/CODE_OF_CONDUCT.md b/3rdparty/cpr/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000000000000000000000000000000000..1c9ee05c9ad36c93bf09dfd510a794802b89edcc
--- /dev/null
+++ b/3rdparty/cpr/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+cc@libcpr.org.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/3rdparty/cpr/CONTRIBUTING.md b/3rdparty/cpr/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..abfb97c346e737b78590e7f9bf64fc5660d8e523
--- /dev/null
+++ b/3rdparty/cpr/CONTRIBUTING.md
@@ -0,0 +1,27 @@
+# Contributing to C++ Requests
+
+Please fork this repository and contribute back using [pull requests](https://github.com/whoshuu/cpr/pulls). Features can be requested using [issues](https://github.com/whoshuu/cpr/issues). All code, comments, and critiques are greatly appreciated.
+
+## Formatting
+
+To avoid unproductive debates on formatting, this project uses `clang-format` to ensure a consistent style across all source files. Currently, `clang-format` 3.8 is the version of `clang-format` we use. The format file can be found [here](https://github.com/whoshuu/cpr/blob/master/.clang-format). To install `clang-format` on Ubuntu, run this:
+
+```
+apt-get install clang-format-3.8
+```
+
+To install `clang-format` on OS X, run this:
+
+```
+brew install clang-format
+```
+
+Note that `brew` might install a later version of `clang-format`, but it should be mostly compatible with what's run on the Travis servers.
+
+To run `clang-format` on every source file, run this in the root directory:
+
+```
+./format-check.sh
+```
+
+This should indicate which files need formatting and also show a diff of the requested changes. More specific usage instructions can be found on the official [LLVM website](http://releases.llvm.org/3.8.0/tools/clang/docs/ClangFormat.html).
diff --git a/3rdparty/cpr/CppCheckSuppressions.txt b/3rdparty/cpr/CppCheckSuppressions.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fec131b1195235c1013eeff27ef0dc372dddf827
--- /dev/null
+++ b/3rdparty/cpr/CppCheckSuppressions.txt
@@ -0,0 +1,3 @@
+noExplicitConstructor
+ConfigurationNotChecked
+passedByValue
diff --git a/3rdparty/cpr/LICENSE b/3rdparty/cpr/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..c63edeb39817d114d10d4b63d36e808bd4490630
--- /dev/null
+++ b/3rdparty/cpr/LICENSE
@@ -0,0 +1,25 @@
+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/3rdparty/cpr/README.md b/3rdparty/cpr/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..dd21f1ab218351ab032577eea69b89718b190189
--- /dev/null
+++ b/3rdparty/cpr/README.md
@@ -0,0 +1,204 @@
+# C++ Requests: Curl for People
+
+[](https://docs.libcpr.org/)
+
+[](https://gitter.im/libcpr/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+## Announcements
+
+* This project is being maintained by [Fabian Sauter](https://github.com/com8) and [Kilian Traub](https://github.com/KingKili).
+* For quick help, and discussion libcpr also offers a [gitter](https://gitter.im/libcpr/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link) chat.
+
+## Supported Releases
+| Release | Min. C++ Standard | Status | Notes |
+|----------|-------------------|--------|-------|
+| master | `cpp17` | ![alt text][preview] | |
+| 1.11.x | `cpp17` | ![alt text][supported] | |
+| 1.10.x | `cpp17` | ![alt text][unsupported] | |
+| 1.9.x | `cpp11` | ![alt text][supported] | Supported until 01.01.2025 |
+| <= 1.8.x | `cpp11` | ![alt text][unsupported] | |
+
+[unsupported]: https://img.shields.io/badge/-unsupported-red "unsupported"
+[supported]: https://img.shields.io/badge/-supported-green "supported"
+[preview]: https://img.shields.io/badge/-preview-orange "preview"
+
+## TLDR
+
+C++ Requests is a simple wrapper around [libcurl](http://curl.haxx.se/libcurl) inspired by the excellent [Python Requests](https://github.com/kennethreitz/requests) project.
+
+Despite its name, libcurl's easy interface is anything but, and making mistakes, misusing it is a common source of error and frustration. Using the more expressive language facilities of `C++17` (or `C++11` in case you use cpr < 1.10.0), this library captures the essence of making network calls into a few concise idioms.
+
+Here's a quick GET request:
+
+```c++
+#include
+
+int main(int argc, char** argv) {
+ cpr::Response r = cpr::Get(cpr::Url{"https://api.github.com/repos/whoshuu/cpr/contributors"},
+ cpr::Authentication{"user", "pass", cpr::AuthMode::BASIC},
+ cpr::Parameters{{"anon", "true"}, {"key", "value"}});
+ r.status_code; // 200
+ r.header["content-type"]; // application/json; charset=utf-8
+ r.text; // JSON text string
+ return 0;
+}
+```
+
+And here's [less functional, more complicated code, without cpr](https://gist.github.com/whoshuu/2dc858b8730079602044).
+
+## Documentation
+
+[](https://docs.libcpr.org/)
+You can find the latest documentation [here](https://docs.libcpr.org/). It's a work in progress, but it should give you a better idea of how to use the library than the [tests](https://github.com/libcpr/cpr/tree/master/test) currently do.
+
+## Features
+
+C++ Requests currently supports:
+
+* Custom headers
+* URL-encoded parameters
+* URL-encoded POST values
+* Multipart form POST upload
+* File POST upload
+* Basic authentication
+* Bearer authentication
+* Digest authentication
+* NTLM authentication
+* Connection and request timeout specification
+* Timeout for low speed connection
+* Asynchronous requests
+* :cookie: support!
+* Proxy support
+* Callback interfaces
+* PUT methods
+* DELETE methods
+* HEAD methods
+* OPTIONS methods
+* PATCH methods
+* Thread Safe access to [libCurl](https://curl.haxx.se/libcurl/c/threadsafe.html)
+* OpenSSL and WinSSL support for HTTPS requests
+
+## Planned
+
+For a quick overview about the planned features, have a look at the next [Milestones](https://github.com/libcpr/cpr/milestones).
+
+## Usage
+
+### CMake
+
+#### fetch_content:
+If you already have a CMake project you need to integrate C++ Requests with, the primary way is to use `fetch_content`.
+Add the following to your `CMakeLists.txt`.
+
+
+```cmake
+include(FetchContent)
+FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git
+ GIT_TAG bb01c8db702fb41e5497aee9c0559ddf4bf13749) # Replace with your desired git commit from: https://github.com/libcpr/cpr/releases
+FetchContent_MakeAvailable(cpr)
+```
+
+This will produce the target `cpr::cpr` which you can link against the typical way:
+
+```cmake
+target_link_libraries(your_target_name PRIVATE cpr::cpr)
+```
+
+That should do it!
+There's no need to handle `libcurl` yourself. All dependencies are taken care of for you.
+All of this can be found in an example [**here**](https://github.com/libcpr/example-cmake-fetch-content).
+
+#### find_package():
+If you prefer not to use `fetch_content`, you can download, build, and install the library and then use CMake `find_package()` function to integrate it into a project.
+
+**Note:** this feature is feasible only if CPR_USE_SYSTEM_CURL is set. (see [#645](https://github.com/libcpr/cpr/pull/645))
+```Bash
+git clone https://github.com/libcpr/cpr.git
+cd cpr && mkdir build && cd build
+cmake .. -DCPR_USE_SYSTEM_CURL=ON
+cmake --build . --parallel
+sudo cmake --install .
+```
+#### Build Static Library
+As an alternative if you want to switch between a static or shared version of cpr use ['-DBUILD_SHARED_LIBS=ON/OFF'](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html).
+```Bash
+git clone https://github.com/libcpr/cpr.git
+cd cpr && mkdir build && cd build
+cmake .. -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF
+cmake --build . --parallel
+sudo cmake --install .
+```
+
+In your `CMakeLists.txt`:
+```cmake
+find_package(cpr REQUIRED)
+add_executable(your_target_name your_target_name.cpp)
+target_link_libraries(your_target_name PRIVATE cpr::cpr)
+```
+
+#### Tests
+`cpr` provides a bunch of tests that can be executed via the following commands.
+```Bash
+git clone https://github.com/libcpr/cpr.git
+cd cpr && mkdir build && cd build
+cmake .. -DCPR_BUILD_TESTS=ON # There are other test related options like 'CPR_BUILD_TESTS_SSL' and 'CPR_BUILD_TESTS_PROXY'
+cmake --build . --parallel
+ctest -VV # -VV is optional since it enables verbose output
+```
+
+### Bazel
+
+Please refer to [hedronvision/bazel-make-cc-https-easy](https://github.com/hedronvision/bazel-make-cc-https-easy).
+
+### Packages for Linux Distributions
+
+Alternatively, you may install a package specific to your Linux distribution. Since so few distributions currently have a package for cpr, most users will not be able to run your program with this approach.
+
+Currently, we are aware of packages for the following distributions:
+
+* [Arch Linux (AUR)](https://aur.archlinux.org/packages/cpr)
+* [Fedora Linux](https://src.fedoraproject.org/rpms/cpr)
+
+If there's no package for your distribution, try making one! If you do, and it is added to your distribution's repositories, please submit a pull request to add it to the list above. However, please only do this if you plan to actively maintain the package.
+
+### NuGet Package
+
+For Windows, there is also a libcpr NuGet package available. Currently, x86 and x64 builds are supported with release and debug configuration.
+
+The package can be found here: [NuGet.org](https://www.nuget.org/packages/libcpr/)
+
+### Port for macOS
+
+On macOS you may install cpr via [MacPorts.org](https://ports.macports.org/port/cpr) (arm64, x86_64, powerpc)
+
+### FreeBSD Port
+
+On FreeBSD, you can issue `pkg install cpr` or use the Ports tree to install it.
+
+## Requirements
+
+The only explicit requirements are:
+
+* a `C++17` compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let us know
+* in case you only have a `C++11` compatible compiler available, all versions below cpr 1.9.x are for you. The 1.10.0 release of cpr switches to `C++17` as a requirement.
+* If you would like to perform https requests `OpenSSL` and its development libraries are required.
+* If you do not use the built-in version of [curl](https://github.com/curl/curl) but instead use your systems version, make sure you use a version `>= 7.64.0`. Lower versions are not supported. This means you need Debian `>= 10` or Ubuntu `>= 20.04 LTS`.
+
+## Building cpr - Using vcpkg
+
+You can download and install cpr using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
+```Bash
+git clone https://github.com/Microsoft/vcpkg.git
+cd vcpkg
+./bootstrap-vcpkg.sh
+./vcpkg integrate install
+./vcpkg install cpr
+```
+The `cpr` port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
+
+## Building cpr - Using Conan
+
+You can download and install `cpr` using the [Conan](https://conan.io/) package manager. Setup your CMakeLists.txt (see [Conan documentation](https://docs.conan.io/en/latest/integrations/build_system.html) on how to use MSBuild, Meson and others).
+An example can be found [**here**](https://github.com/libcpr/example-cmake-conan).
+
+The `cpr` package in Conan is kept up to date by Conan contributors. If the version is out of date, please [create an issue or pull request](https://github.com/conan-io/conan-center-index) on the `conan-center-index` repository.
diff --git a/3rdparty/cpr/cmake/FindMbedTLS.cmake b/3rdparty/cpr/cmake/FindMbedTLS.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..61ec46414f01844277a1f377ce7cf6443e408b4f
--- /dev/null
+++ b/3rdparty/cpr/cmake/FindMbedTLS.cmake
@@ -0,0 +1,14 @@
+# Source: https://github.com/curl/curl/blob/curl-7_82_0/CMake/FindMbedTLS.cmake
+find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
+
+find_library(MBEDTLS_LIBRARY mbedtls)
+find_library(MBEDX509_LIBRARY mbedx509)
+find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
+
+set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MbedTLS DEFAULT_MSG
+ MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+
+mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
diff --git a/3rdparty/cpr/cmake/clang-tidy.cmake b/3rdparty/cpr/cmake/clang-tidy.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..26defad2eaca2a1f12adb3dec3ee6c0159ab799c
--- /dev/null
+++ b/3rdparty/cpr/cmake/clang-tidy.cmake
@@ -0,0 +1,13 @@
+if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+ find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy)
+ mark_as_advanced(CLANG_TIDY_EXECUTABLE)
+
+ if (${CLANG_TIDY_EXECUTABLE})
+ message(FATAL_ERROR "Clang-tidy not found")
+ else()
+ message(STATUS "Enabling clang-tidy")
+ set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE};-warnings-as-errors=*")
+ endif()
+else()
+ message(FATAL_ERROR "Clang-tidy is not supported when building for windows")
+endif()
diff --git a/3rdparty/cpr/cmake/clear_variable.cmake b/3rdparty/cpr/cmake/clear_variable.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..469ac827e8b5bd437f484ce96265fe1a6bcce115
--- /dev/null
+++ b/3rdparty/cpr/cmake/clear_variable.cmake
@@ -0,0 +1,11 @@
+macro(clear_variable)
+ cmake_parse_arguments(CLEAR_VAR "" "DESTINATION;BACKUP;REPLACE" "" ${ARGN})
+ set(${CLEAR_VAR_BACKUP} ${${CLEAR_VAR_DESTINATION}})
+ set(${CLEAR_VAR_DESTINATION} ${CLEAR_VAR_REPLACE})
+endmacro()
+
+macro(restore_variable)
+ cmake_parse_arguments(CLEAR_VAR "" "DESTINATION;BACKUP" "" ${ARGN})
+ set(${CLEAR_VAR_DESTINATION} ${${CLEAR_VAR_BACKUP}})
+ unset(${CLEAR_VAR_BACKUP})
+endmacro()
diff --git a/3rdparty/cpr/cmake/code_coverage.cmake b/3rdparty/cpr/cmake/code_coverage.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..eefc4fb399702fe0248c9ef81b63fad883b32220
--- /dev/null
+++ b/3rdparty/cpr/cmake/code_coverage.cmake
@@ -0,0 +1,29 @@
+# Code coverage
+if(CPR_BUILD_TESTS AND CPR_GENERATE_COVERAGE)
+ set(CMAKE_BUILD_TYPE COVERAGE CACHE INTERNAL "Coverage enabled build")
+ message(STATUS "Enabling gcov support")
+ if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ set(COVERAGE_FLAG "--coverage")
+ endif()
+ set(CMAKE_CXX_FLAGS_COVERAGE
+ "-g -O0 ${COVERAGE_FLAG} -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE)
+ set(CMAKE_C_FLAGS_COVERAGE
+ "-g -O0 ${COVERAGE_FLAG} -fprofile-arcs -ftest-coverage"
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE)
+ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ ""
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE)
+ mark_as_advanced(
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE)
+endif()
diff --git a/3rdparty/cpr/cmake/cppcheck.cmake b/3rdparty/cpr/cmake/cppcheck.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8ef46880650b52298cb915152fdd1346c5fa28b0
--- /dev/null
+++ b/3rdparty/cpr/cmake/cppcheck.cmake
@@ -0,0 +1,10 @@
+find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck)
+if(CMAKE_CXX_CPPCHECK)
+ list(APPEND CMAKE_CXX_CPPCHECK
+ "--error-exitcode=1"
+ "--enable=warning,style"
+ "--force"
+ "--inline-suppr"
+ "--std=c++${CMAKE_CXX_STANDARD}"
+ "--suppressions-list=${CMAKE_SOURCE_DIR}/CppCheckSuppressions.txt")
+endif()
diff --git a/3rdparty/cpr/cmake/cprConfig.cmake.in b/3rdparty/cpr/cmake/cprConfig.cmake.in
new file mode 100644
index 0000000000000000000000000000000000000000..9c0bda5fad2a08297cd182bd2b1e0ccd2071540b
--- /dev/null
+++ b/3rdparty/cpr/cmake/cprConfig.cmake.in
@@ -0,0 +1,8 @@
+include(CMakeFindDependencyMacro)
+@PACKAGE_INIT@
+
+find_dependency(CURL REQUIRED)
+
+include(${CMAKE_CURRENT_LIST_DIR}/cprTargets.cmake)
+
+check_required_components(cpr)
\ No newline at end of file
diff --git a/3rdparty/cpr/cmake/cprver.h.in b/3rdparty/cpr/cmake/cprver.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..e353324976ee2626af0bb12684b0cfc9cdda3dfc
--- /dev/null
+++ b/3rdparty/cpr/cmake/cprver.h.in
@@ -0,0 +1,30 @@
+#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/3rdparty/cpr/cmake/mongoose.CMakeLists.txt b/3rdparty/cpr/cmake/mongoose.CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..397e0c12660a69895c641de920c381f59b40d07b
--- /dev/null
+++ b/3rdparty/cpr/cmake/mongoose.CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.15)
+project(mongoose C)
+
+
+add_library(mongoose STATIC mongoose.c)
+target_include_directories(mongoose PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+
+if(ENABLE_SSL_TESTS)
+ # Enable mongoose SSL
+ target_compile_definitions(mongoose PUBLIC MG_ENABLE_OPENSSL)
+ target_link_libraries(mongoose PUBLIC OpenSSL::SSL)
+
+ # Fix macOS and Windows invalid OpenSSL include path
+ target_include_directories(mongoose PUBLIC "${OPENSSL_INCLUDE_DIR}")
+endif()
diff --git a/3rdparty/cpr/cmake/sanitizer.cmake b/3rdparty/cpr/cmake/sanitizer.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..10cdc46244498ccae96fd6e96232a288457ebab4
--- /dev/null
+++ b/3rdparty/cpr/cmake/sanitizer.cmake
@@ -0,0 +1,69 @@
+include(CheckCXXCompilerFlag)
+include(CheckCXXSourceRuns)
+
+set(ALL_SAN_FLAGS "")
+
+ # No sanitizers when cross compiling to prevent stuff like this: https://github.com/whoshuu/cpr/issues/582
+if(NOT CMAKE_CROSSCOMPILING)
+ # Thread sanitizer
+ set(THREAD_SAN_FLAGS "-fsanitize=thread")
+ set(PREV_FLAG ${CMAKE_REQUIRED_FLAGS})
+ set(CMAKE_REQUIRED_FLAGS "${THREAD_SAN_FLAGS}")
+ check_cxx_source_runs("int main() { return 0; }" THREAD_SANITIZER_AVAILABLE)
+ set(CMAKE_REQUIRED_FLAGS ${PREV_FLAG})
+ # Do not add the ThreadSanitizer for builds with all sanitizers enabled because it is incompatible with other sanitizers.
+
+ # Address sanitizer
+ set(ADDR_SAN_FLAGS "-fsanitize=address")
+ set(PREV_FLAG ${CMAKE_REQUIRED_FLAGS})
+ set(CMAKE_REQUIRED_FLAGS "${ADDR_SAN_FLAGS}")
+ check_cxx_source_runs("int main() { return 0; }" ADDRESS_SANITIZER_AVAILABLE)
+ set(CMAKE_REQUIRED_FLAGS ${PREV_FLAG})
+ if(ADDRESS_SANITIZER_AVAILABLE)
+ set(ALL_SAN_FLAGS "${ALL_SAN_FLAGS} ${ADDR_SAN_FLAGS}")
+ endif()
+
+ # Leak sanitizer
+ set(LEAK_SAN_FLAGS "-fsanitize=leak")
+ check_cxx_compiler_flag(${LEAK_SAN_FLAGS} LEAK_SANITIZER_AVAILABLE)
+ if(LEAK_SANITIZER_AVAILABLE)
+ set(ALL_SAN_FLAGS "${ALL_SAN_FLAGS} ${LEAK_SAN_FLAGS}")
+ endif()
+
+ # Undefined behavior sanitizer
+ set(UDEF_SAN_FLAGS "-fsanitize=undefined")
+ check_cxx_compiler_flag(${UDEF_SAN_FLAGS} UNDEFINED_BEHAVIOUR_SANITIZER_AVAILABLE)
+ if(UNDEFINED_BEHAVIOUR_SANITIZER_AVAILABLE)
+ set(ALL_SAN_FLAGS "${ALL_SAN_FLAGS} ${UDEF_SAN_FLAGS}")
+ endif()
+
+ # All sanitizer (without thread sanitizer)
+ if(NOT ALL_SAN_FLAGS STREQUAL "")
+ set(PREV_FLAG ${CMAKE_REQUIRED_FLAGS})
+ set(CMAKE_REQUIRED_FLAGS "${ALL_SAN_FLAGS}")
+ check_cxx_source_runs("int main() { return 0; }" ALL_SANITIZERS_AVAILABLE)
+ set(CMAKE_REQUIRED_FLAGS ${PREV_FLAG})
+ endif()
+
+ if(CPR_DEBUG_SANITIZER_FLAG_THREAD AND THREAD_SANITIZER_AVAILABLE)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${THREAD_SAN_FLAGS}" CACHE INTERNAL "Flags used by the C compiler during thread sanitizer builds." FORCE)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${THREAD_SAN_FLAGS}" CACHE INTERNAL "Flags used by the C++ compiler during thread sanitizer builds." FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE INTERNAL "Flags used for the linker during thread sanitizer builds" FORCE)
+ elseif(CPR_DEBUG_SANITIZER_FLAG_ADDR AND ADDRESS_SANITIZER_AVAILABLE)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${ADDR_SAN_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE INTERNAL "Flags used by the C compiler during address sanitizer builds." FORCE)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${ADDR_SAN_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE INTERNAL "Flags used by the C++ compiler during address sanitizer builds." FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE INTERNAL "Flags used for the linker during address sanitizer builds" FORCE)
+ elseif(CPR_DEBUG_SANITIZER_FLAG_LEAK AND LEAK_SANITIZER_AVAILABLE)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${LEAK_SAN_FLAGS} -fno-omit-frame-pointer" CACHE INTERNAL "Flags used by the C compiler during leak sanitizer builds." FORCE)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${LEAK_SAN_FLAGS} -fno-omit-frame-pointer" CACHE INTERNAL "Flags used by the C++ compiler during leak sanitizer builds." FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE INTERNAL "Flags used for the linker during leak sanitizer builds" FORCE)
+ elseif(CPR_DEBUG_SANITIZER_FLAG_UB AND UNDEFINED_BEHAVIOUR_SANITIZER_AVAILABLE)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${UDEF_SAN_FLAGS}" CACHE INTERNAL "Flags used by the C compiler during undefined behaviour sanitizer builds." FORCE)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${UDEF_SAN_FLAGS}" CACHE INTERNAL "Flags used by the C++ compiler during undefined behaviour sanitizer builds." FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE INTERNAL "Flags used for the linker during undefined behaviour sanitizer builds" FORCE)
+ elseif(CPR_DEBUG_SANITIZER_FLAG_ALL AND ALL_SANITIZERS_AVAILABLE)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${ALL_SAN_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE INTERNAL "Flags used by the C compiler during most possible sanitizer builds." FORCE)
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${ALL_SAN_FLAGS} -fno-omit-frame-pointer -fno-optimize-sibling-calls" CACHE INTERNAL "Flags used by the C++ compiler during most possible sanitizer builds." FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE INTERNAL "Flags used for the linker during most possible sanitizer builds" FORCE)
+ endif()
+endif()
diff --git a/3rdparty/cpr/cmake/std_fs_support_test.cpp b/3rdparty/cpr/cmake/std_fs_support_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44bac7770d52f901beedaf244edfa6cf6de31a22
--- /dev/null
+++ b/3rdparty/cpr/cmake/std_fs_support_test.cpp
@@ -0,0 +1,11 @@
+#if __has_include()
+#include
+namespace fs = std::filesystem;
+#else
+#include
+namespace fs = std::experimental::filesystem;
+#endif
+
+int main() {
+ auto cwd = fs::current_path();
+}
diff --git a/3rdparty/cpr/cmake/zlib_external.cmake b/3rdparty/cpr/cmake/zlib_external.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..1a8eea066383872eebb4a75fda8fbe408c1545d5
--- /dev/null
+++ b/3rdparty/cpr/cmake/zlib_external.cmake
@@ -0,0 +1,22 @@
+# ZLIB
+
+# Fix Windows missing "zlib.dll":
+if(WIN32 AND (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}))
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/$ CACHE INTERNAL "" FORCE)
+endif()
+
+set(ZLIB_COMPAT ON CACHE INTERNAL "" FORCE)
+set(ZLIB_ENABLE_TESTS OFF CACHE INTERNAL "" FORCE)
+
+FetchContent_Declare(zlib
+ GIT_REPOSITORY https://github.com/zlib-ng/zlib-ng
+ GIT_TAG 2.1.3
+ USES_TERMINAL_DOWNLOAD TRUE)
+FetchContent_MakeAvailable(zlib)
+
+# Fix Windows zlib dll names from "zlibd1.dll" to "zlib.dll":
+if(WIN32 AND BUILD_SHARED_LIBS)
+ set_target_properties(zlib PROPERTIES OUTPUT_NAME "zlib")
+ set_target_properties(zlib PROPERTIES DEBUG_POSTFIX "")
+ set_target_properties(zlib PROPERTIES SUFFIX ".dll")
+endif()
diff --git a/3rdparty/cpr/cpr-config.cmake b/3rdparty/cpr/cpr-config.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..58ab48320bb8f4d7c01a936b585a08327a13bbd6
--- /dev/null
+++ b/3rdparty/cpr/cpr-config.cmake
@@ -0,0 +1,26 @@
+# - C++ Requests, Curl for People
+# This module is a libcurl wrapper written in modern C++.
+# It provides an easy, intuitive, and efficient interface to
+# a host of networking methods.
+#
+# Finding this module will define the following variables:
+# CPR_FOUND - True if the core library has been found
+# CPR_LIBRARIES - Path to the core library archive
+# CPR_INCLUDE_DIRS - Path to the include directories. Gives access
+# to cpr.h, which must be included in every
+# file that uses this interface
+
+find_path(CPR_INCLUDE_DIR
+ NAMES cpr.h)
+
+find_library(CPR_LIBRARY
+ NAMES cpr
+ HINTS ${CPR_LIBRARY_ROOT})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CPR REQUIRED_VARS CPR_LIBRARY CPR_INCLUDE_DIR)
+
+if(CPR_FOUND)
+ set(CPR_LIBRARIES ${CPR_LIBRARY})
+ set(CPR_INCLUDE_DIRS ${CPR_INCLUDE_DIR})
+endif()
diff --git a/3rdparty/cpr/cpr/CMakeLists.txt b/3rdparty/cpr/cpr/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0c7083c4e9286db2e5ef8dfb0131bb52eaf70957
--- /dev/null
+++ b/3rdparty/cpr/cpr/CMakeLists.txt
@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 3.15)
+
+add_library(cpr
+ accept_encoding.cpp
+ async.cpp
+ auth.cpp
+ bearer.cpp
+ callback.cpp
+ cert_info.cpp
+ cookies.cpp
+ cprtypes.cpp
+ curl_container.cpp
+ curlholder.cpp
+ error.cpp
+ file.cpp
+ multipart.cpp
+ parameters.cpp
+ payload.cpp
+ proxies.cpp
+ proxyauth.cpp
+ session.cpp
+ threadpool.cpp
+ timeout.cpp
+ unix_socket.cpp
+ util.cpp
+ response.cpp
+ redirect.cpp
+ interceptor.cpp
+ ssl_ctx.cpp
+ curlmultiholder.cpp
+ multiperform.cpp)
+
+add_library(cpr::cpr ALIAS cpr)
+
+target_link_libraries(cpr PUBLIC ${CURL_LIB}) # todo should be private, but first dependencies in ssl_options need to be removed
+
+# Fix missing OpenSSL includes for Windows since in 'ssl_ctx.cpp' we include OpenSSL directly
+if(SSL_BACKEND_USED STREQUAL "OpenSSL")
+ target_link_libraries(cpr PRIVATE OpenSSL::SSL)
+ target_include_directories(cpr PRIVATE ${OPENSSL_INCLUDE_DIR})
+endif()
+
+# Set version for shared libraries.
+set_target_properties(cpr
+ PROPERTIES
+ VERSION ${${PROJECT_NAME}_VERSION}
+ SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR})
+
+# Import GNU common install directory variables
+include(GNUInstallDirs)
+
+install(TARGETS cpr
+ EXPORT cprTargets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+if(CPR_USE_SYSTEM_CURL)
+ # Include CMake helpers for package config files
+ # Follow this installation guideline: https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html
+ include(CMakePackageConfigHelpers)
+
+ write_basic_package_version_file(
+ "${PROJECT_BINARY_DIR}/cpr/cprConfigVersion.cmake"
+ VERSION ${${PROJECT_NAME}_VERSION}
+ COMPATIBILITY ExactVersion)
+
+ configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig.cmake.in
+ "${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake"
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
+
+ install(FILES ${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake
+ ${PROJECT_BINARY_DIR}/cpr/cprConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
+endif()
+
+install(EXPORT cprTargets
+ FILE cprTargets.cmake
+ NAMESPACE cpr::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr)
diff --git a/3rdparty/cpr/cpr/accept_encoding.cpp b/3rdparty/cpr/cpr/accept_encoding.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0427b31f50e9d6a80b822f3970d47ee7b548672c
--- /dev/null
+++ b/3rdparty/cpr/cpr/accept_encoding.cpp
@@ -0,0 +1,38 @@
+#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/3rdparty/cpr/cpr/async.cpp b/3rdparty/cpr/cpr/async.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e10d09e1fda4521ae442ed4750183077bac297a1
--- /dev/null
+++ b/3rdparty/cpr/cpr/async.cpp
@@ -0,0 +1,8 @@
+#include "cpr/async.h"
+
+namespace cpr {
+
+// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
+CPR_SINGLETON_IMPL(GlobalThreadPool)
+
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/auth.cpp b/3rdparty/cpr/cpr/auth.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfda86263c1d3e126a85b7c9be1cd5f8a53c8125
--- /dev/null
+++ b/3rdparty/cpr/cpr/auth.cpp
@@ -0,0 +1,26 @@
+#include "cpr/auth.h"
+#include "cpr/util.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;
+}
+
+Authentication::~Authentication() noexcept {
+ util::secureStringClear(auth_string_);
+}
+
+const char* Authentication::GetAuthString() const noexcept {
+ return auth_string_.c_str();
+}
+
+AuthMode Authentication::GetAuthMode() const noexcept {
+ return auth_mode_;
+}
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/bearer.cpp b/3rdparty/cpr/cpr/bearer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..041b6c18786def194b3efe3c2dab4ab23bd38c74
--- /dev/null
+++ b/3rdparty/cpr/cpr/bearer.cpp
@@ -0,0 +1,17 @@
+#include "cpr/bearer.h"
+#include "cpr/util.h"
+#include
+
+namespace cpr {
+// Only supported with libcurl >= 7.61.0.
+// As an alternative use SetHeader and add the token manually.
+#if LIBCURL_VERSION_NUM >= 0x073D00
+Bearer::~Bearer() noexcept {
+ util::secureStringClear(token_string_);
+}
+
+const char* Bearer::GetToken() const noexcept {
+ return token_string_.c_str();
+}
+#endif
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/callback.cpp b/3rdparty/cpr/cpr/callback.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2d257a2c55589410476423ff901b9a6ba2c437e
--- /dev/null
+++ b/3rdparty/cpr/cpr/callback.cpp
@@ -0,0 +1,14 @@
+#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/3rdparty/cpr/cpr/cert_info.cpp b/3rdparty/cpr/cpr/cert_info.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..410648c04ded85094f4bc6104f6b0a51889f4db9
--- /dev/null
+++ b/3rdparty/cpr/cpr/cert_info.cpp
@@ -0,0 +1,45 @@
+#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/3rdparty/cpr/cpr/cookies.cpp b/3rdparty/cpr/cpr/cookies.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..37c088b9801448b41e2f750fbdc411394fc65ea3
--- /dev/null
+++ b/3rdparty/cpr/cpr/cookies.cpp
@@ -0,0 +1,115 @@
+#include "cpr/cookies.h"
+#include "cpr/curlholder.h"
+#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_;
+}
+
+const std::chrono::system_clock::time_point Cookie::GetExpires() const {
+ return expires_;
+}
+
+const std::string Cookie::GetExpiresString() const {
+ std::stringstream ss;
+ std::tm tm{};
+ const std::time_t tt = std::chrono::system_clock::to_time_t(expires_);
+#ifdef _WIN32
+ gmtime_s(&tm, &tt);
+#else
+ // 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_;
+}
+
+const std::string Cookies::GetEncoded(const CurlHolder& holder) const {
+ std::stringstream stream;
+ for (const cpr::Cookie& item : cookies_) {
+ // Depending on if encoding is set to "true", we will URL-encode cookies
+ stream << (encode ? holder.urlEncode(item.GetName()) : item.GetName()) << "=";
+
+ // special case version 1 cookies, which can be distinguished by
+ // beginning and trailing quotes
+ if (!item.GetValue().empty() && item.GetValue().front() == '"' && item.GetValue().back() == '"') {
+ stream << item.GetValue();
+ } else {
+ // Depending on if encoding is set to "true", we will URL-encode cookies
+ stream << (encode ? holder.urlEncode(item.GetValue()) : item.GetValue());
+ }
+ stream << "; ";
+ }
+ return stream.str();
+}
+
+cpr::Cookie& Cookies::operator[](size_t pos) {
+ return cookies_[pos];
+}
+
+Cookies::iterator Cookies::begin() {
+ return cookies_.begin();
+}
+
+Cookies::iterator Cookies::end() {
+ return cookies_.end();
+}
+
+Cookies::const_iterator Cookies::begin() const {
+ return cookies_.begin();
+}
+
+Cookies::const_iterator Cookies::end() const {
+ return cookies_.end();
+}
+
+Cookies::const_iterator Cookies::cbegin() const {
+ return cookies_.cbegin();
+}
+
+Cookies::const_iterator Cookies::cend() const {
+ return cookies_.cend();
+}
+
+void Cookies::emplace_back(const Cookie& str) {
+ cookies_.emplace_back(str);
+}
+
+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/3rdparty/cpr/cpr/cprtypes.cpp b/3rdparty/cpr/cpr/cprtypes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..43df134911f30ac6145a8604aeb1d3e18a95512b
--- /dev/null
+++ b/3rdparty/cpr/cpr/cprtypes.cpp
@@ -0,0 +1,11 @@
+#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/3rdparty/cpr/cpr/curl_container.cpp b/3rdparty/cpr/cpr/curl_container.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de0c9c3b5c84ce8a28d61056d5b6158acc943f4e
--- /dev/null
+++ b/3rdparty/cpr/cpr/curl_container.cpp
@@ -0,0 +1,60 @@
+#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 ? holder.urlEncode(parameter.key) : parameter.key;
+ if (parameter.value.empty()) {
+ content += escapedKey;
+ } else {
+ const std::string escapedValue = encode ? holder.urlEncode(parameter.value) : parameter.value;
+ content += escapedKey + "=";
+ content += escapedValue;
+ }
+ }
+
+ return content;
+}
+
+template <>
+const std::string CurlContainer::GetContent(const CurlHolder& holder) const {
+ std::string content{};
+ for (const cpr::Pair& element : containerList_) {
+ if (!content.empty()) {
+ content += "&";
+ }
+ const std::string escaped = encode ? holder.urlEncode(element.value) : element.value;
+ content += element.key + "=" + escaped;
+ }
+
+ return content;
+}
+
+template class CurlContainer;
+template class CurlContainer;
+
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/curlholder.cpp b/3rdparty/cpr/cpr/curlholder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cee8897c07b68e1a1ca61b0a78b78d63cb5c003f
--- /dev/null
+++ b/3rdparty/cpr/cpr/curlholder.cpp
@@ -0,0 +1,52 @@
+#include "cpr/curlholder.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);
+} // namespace cpr
+
+CurlHolder::~CurlHolder() {
+ curl_slist_free_all(chunk);
+ curl_slist_free_all(resolveCurlList);
+ curl_mime_free(multipart);
+ curl_easy_cleanup(handle);
+}
+
+std::string CurlHolder::urlEncode(const std::string& s) const {
+ assert(handle);
+ char* output = curl_easy_escape(handle, s.c_str(), static_cast(s.length()));
+ if (output) {
+ std::string result = output;
+ curl_free(output);
+ return result;
+ }
+ return "";
+}
+
+std::string CurlHolder::urlDecode(const std::string& s) const {
+ assert(handle);
+ char* output = curl_easy_unescape(handle, s.c_str(), static_cast(s.length()), nullptr);
+ if (output) {
+ std::string result = output;
+ curl_free(output);
+ return result;
+ }
+ return "";
+}
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/curlmultiholder.cpp b/3rdparty/cpr/cpr/curlmultiholder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..972fefe91c1af681af73f441a2b7aced37e9b274
--- /dev/null
+++ b/3rdparty/cpr/cpr/curlmultiholder.cpp
@@ -0,0 +1,15 @@
+#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/3rdparty/cpr/cpr/error.cpp b/3rdparty/cpr/cpr/error.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e5f355631f2c7a372aba0d5c56d27e61b7e8ef4
--- /dev/null
+++ b/3rdparty/cpr/cpr/error.cpp
@@ -0,0 +1,167 @@
+#include "cpr/error.h"
+#include
+#include
+#include
+#include
+
+namespace cpr {
+static const std::unordered_map curl_error_map = { // NOLINT - (needed because of static init)
+ {CURLE_OK, ErrorCode::OK},
+ {CURLE_UNSUPPORTED_PROTOCOL, ErrorCode::UNSUPPORTED_PROTOCOL},
+ {CURLE_FAILED_INIT, ErrorCode::FAILED_INIT},
+ {CURLE_URL_MALFORMAT, ErrorCode::URL_MALFORMAT},
+ {CURLE_NOT_BUILT_IN, ErrorCode::NOT_BUILT_IN},
+ {CURLE_COULDNT_RESOLVE_PROXY, ErrorCode::COULDNT_RESOLVE_PROXY},
+ {CURLE_COULDNT_RESOLVE_HOST, ErrorCode::COULDNT_RESOLVE_HOST},
+ {CURLE_COULDNT_CONNECT, ErrorCode::COULDNT_CONNECT},
+
+// Name changed in curl >= 7.51.0.
+#if LIBCURL_VERSION_NUM >= 0x073300
+ {CURLE_WEIRD_SERVER_REPLY, ErrorCode::WEIRD_SERVER_REPLY},
+#else
+ {CURLE_FTP_WEIRD_SERVER_REPLY, ErrorCode::WEIRD_SERVER_REPLY},
+#endif
+
+ {CURLE_REMOTE_ACCESS_DENIED, ErrorCode::REMOTE_ACCESS_DENIED},
+ {CURLE_HTTP2, ErrorCode::HTTP2},
+ {CURLE_QUOTE_ERROR, ErrorCode::QUOTE_ERROR},
+ {CURLE_HTTP_RETURNED_ERROR, ErrorCode::HTTP_RETURNED_ERROR},
+ {CURLE_WRITE_ERROR, ErrorCode::WRITE_ERROR},
+ {CURLE_UPLOAD_FAILED, ErrorCode::UPLOAD_FAILED},
+ {CURLE_READ_ERROR, ErrorCode::READ_ERROR},
+ {CURLE_OUT_OF_MEMORY, ErrorCode::OUT_OF_MEMORY},
+ {CURLE_OPERATION_TIMEDOUT, ErrorCode::OPERATION_TIMEDOUT},
+ {CURLE_RANGE_ERROR, ErrorCode::RANGE_ERROR},
+ {CURLE_HTTP_POST_ERROR, ErrorCode::HTTP_POST_ERROR},
+ {CURLE_SSL_CONNECT_ERROR, ErrorCode::SSL_CONNECT_ERROR},
+ {CURLE_BAD_DOWNLOAD_RESUME, ErrorCode::BAD_DOWNLOAD_RESUME},
+ {CURLE_FILE_COULDNT_READ_FILE, ErrorCode::FILE_COULDNT_READ_FILE},
+ {CURLE_FUNCTION_NOT_FOUND, ErrorCode::FUNCTION_NOT_FOUND},
+ {CURLE_ABORTED_BY_CALLBACK, ErrorCode::ABORTED_BY_CALLBACK},
+ {CURLE_BAD_FUNCTION_ARGUMENT, ErrorCode::BAD_FUNCTION_ARGUMENT},
+ {CURLE_INTERFACE_FAILED, ErrorCode::INTERFACE_FAILED},
+ {CURLE_TOO_MANY_REDIRECTS, ErrorCode::TOO_MANY_REDIRECTS},
+ {CURLE_UNKNOWN_OPTION, ErrorCode::UNKNOWN_OPTION},
+
+// Added in curl 7.78.0.
+#if LIBCURL_VERSION_NUM >= 0x074E00
+ {CURLE_SETOPT_OPTION_SYNTAX, ErrorCode::SETOPT_OPTION_SYNTAX},
+#endif
+
+ {CURLE_GOT_NOTHING, ErrorCode::GOT_NOTHING},
+ {CURLE_SSL_ENGINE_NOTFOUND, ErrorCode::SSL_ENGINE_NOTFOUND},
+ {CURLE_SSL_ENGINE_SETFAILED, ErrorCode::SSL_ENGINE_SETFAILED},
+ {CURLE_SEND_ERROR, ErrorCode::SEND_ERROR},
+ {CURLE_RECV_ERROR, ErrorCode::RECV_ERROR},
+ {CURLE_SSL_CERTPROBLEM, ErrorCode::SSL_CERTPROBLEM},
+ {CURLE_SSL_CIPHER, ErrorCode::SSL_CIPHER},
+ {CURLE_PEER_FAILED_VERIFICATION, ErrorCode::PEER_FAILED_VERIFICATION},
+ {CURLE_BAD_CONTENT_ENCODING, ErrorCode::BAD_CONTENT_ENCODING},
+ {CURLE_FILESIZE_EXCEEDED, ErrorCode::FILESIZE_EXCEEDED},
+ {CURLE_USE_SSL_FAILED, ErrorCode::USE_SSL_FAILED},
+ {CURLE_SEND_FAIL_REWIND, ErrorCode::SEND_FAIL_REWIND},
+ {CURLE_SSL_ENGINE_INITFAILED, ErrorCode::SSL_ENGINE_INITFAILED},
+
+// Added in curl 7.13.1.
+#if LIBCURL_VERSION_NUM >= 0x070D01
+ {CURLE_LOGIN_DENIED, ErrorCode::LOGIN_DENIED},
+#endif
+
+// Added in curl 7.16.0.
+#if LIBCURL_VERSION_NUM >= 0x071000
+ {CURLE_SSL_CACERT_BADFILE, ErrorCode::SSL_CACERT_BADFILE},
+#endif
+
+// Added in curl 7.16.1.
+#if LIBCURL_VERSION_NUM >= 0x071001
+ {CURLE_SSL_SHUTDOWN_FAILED, ErrorCode::SSL_SHUTDOWN_FAILED},
+#endif
+
+// Added in curl 7.18.2.
+#if LIBCURL_VERSION_NUM >= 0x071202
+ {CURLE_AGAIN, ErrorCode::AGAIN},
+#endif
+
+// Added in curl 7.19.0.
+#if LIBCURL_VERSION_NUM >= 0x071300
+ {CURLE_SSL_CRL_BADFILE, ErrorCode::SSL_CRL_BADFILE},
+ {CURLE_SSL_ISSUER_ERROR, ErrorCode::SSL_ISSUER_ERROR},
+#endif
+
+// Added in curl 7.21.0.
+#if LIBCURL_VERSION_NUM >= 0x071500
+ {CURLE_CHUNK_FAILED, ErrorCode::CHUNK_FAILED},
+#endif
+
+// Added in curl 7.30.0.
+#if LIBCURL_VERSION_NUM >= 0x071E00
+ {CURLE_NO_CONNECTION_AVAILABLE, ErrorCode::NO_CONNECTION_AVAILABLE},
+#endif
+
+// Added in curl 7.39.0.
+#if LIBCURL_VERSION_NUM >= 0x072700
+ {CURLE_SSL_PINNEDPUBKEYNOTMATCH, ErrorCode::SSL_PINNEDPUBKEYNOTMATCH},
+#endif
+
+// Added in curl 7.41.0.
+#if LIBCURL_VERSION_NUM >= 0x072900
+ {CURLE_SSL_INVALIDCERTSTATUS, ErrorCode::SSL_INVALIDCERTSTATUS},
+#endif
+
+// Added in curl 7.49.0.
+#if LIBCURL_VERSION_NUM >= 0x073100
+ {CURLE_HTTP2_STREAM, ErrorCode::HTTP2_STREAM},
+#endif
+
+ {CURLE_PARTIAL_FILE, ErrorCode::PARTIAL_FILE},
+
+// Added in curl 7.59.0.
+#if LIBCURL_VERSION_NUM >= 0x073B00
+ {CURLE_RECURSIVE_API_CALL, ErrorCode::RECURSIVE_API_CALL},
+#endif
+
+// Added in curl 7.66.0.
+#if LIBCURL_VERSION_NUM >= 0x074200
+ {CURLE_AUTH_ERROR, ErrorCode::AUTH_ERROR},
+#endif
+
+// Added in curl 7.68.0.
+#if LIBCURL_VERSION_NUM >= 0x074400
+ {CURLE_HTTP3, ErrorCode::HTTP3},
+#endif
+
+// Added in curl 7.69.0.
+#if LIBCURL_VERSION_NUM >= 0x074500
+ {CURLE_QUIC_CONNECT_ERROR, ErrorCode::QUIC_CONNECT_ERROR},
+#endif
+
+// Added in curl 7.73.0.
+#if LIBCURL_VERSION_NUM >= 0x074900
+ {CURLE_PROXY, ErrorCode::PROXY},
+#endif
+
+// Added in curl 7.77.0.
+#if LIBCURL_VERSION_NUM >= 0x074D00
+ {CURLE_SSL_CLIENTCERT, ErrorCode::SSL_CLIENTCERT},
+#endif
+
+// Added in curl 7.84.0.
+#if LIBCURL_VERSION_NUM >= 0x075400
+ {CURLE_UNRECOVERABLE_POLL, ErrorCode::UNRECOVERABLE_POLL},
+#endif
+
+// Added in curl 7.6.0.
+#if LIBCURL_VERSION_NUM >= 0x080600
+ {CURLE_TOO_LARGE, ErrorCode::TOO_LARGE},
+#endif
+};
+
+ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
+ auto it = curl_error_map.find(curl_code);
+ if (it == curl_error_map.end()) {
+ // Default return value when the CURL error code is not recognized
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+ return it->second;
+}
+} // namespace cpr
\ No newline at end of file
diff --git a/3rdparty/cpr/cpr/file.cpp b/3rdparty/cpr/cpr/file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0690198bb190161a4c39f44d8b74178ce220fcc3
--- /dev/null
+++ b/3rdparty/cpr/cpr/file.cpp
@@ -0,0 +1,63 @@
+#include "cpr/file.h"
+#include
+#include
+#include
+
+namespace cpr {
+
+Files::Files(const std::initializer_list& p_filepaths) {
+ for (const std::string& filepath : p_filepaths) {
+ files.emplace_back(filepath);
+ }
+}
+
+Files::iterator Files::begin() {
+ return files.begin();
+}
+
+Files::iterator Files::end() {
+ return files.end();
+}
+
+Files::const_iterator Files::begin() const {
+ return files.begin();
+}
+
+Files::const_iterator Files::end() const {
+ return files.end();
+}
+
+Files::const_iterator Files::cbegin() const {
+ return files.cbegin();
+}
+
+Files::const_iterator Files::cend() const {
+ return files.cend();
+}
+
+void Files::emplace_back(const File& file) {
+ files.emplace_back(file);
+}
+
+void Files::push_back(const File& file) {
+ files.push_back(file);
+}
+
+void Files::pop_back() {
+ files.pop_back();
+}
+
+Files& Files::operator=(const Files& other) {
+ if (&other != this) {
+ files = other.files;
+ }
+ return *this;
+}
+
+Files& Files::operator=(Files&& old) noexcept {
+ if (&old != this) {
+ files = std::move(old.files);
+ }
+ return *this;
+}
+} // namespace cpr
diff --git a/3rdparty/cpr/cpr/interceptor.cpp b/3rdparty/cpr/cpr/interceptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6af915aa01dec417a146d8fd26904300556f1cab
--- /dev/null
+++ b/3rdparty/cpr/cpr/interceptor.cpp
@@ -0,0 +1,59 @@
+#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/3rdparty/cpr/cpr/multipart.cpp b/3rdparty/cpr/cpr/multipart.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..21251d53110c7ae5c05539a0f2d906cbf4909922
--- /dev/null
+++ b/3rdparty/cpr/cpr/multipart.cpp
@@ -0,0 +1,9 @@
+#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/3rdparty/cpr/cpr/multiperform.cpp b/3rdparty/cpr/cpr/multiperform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c6ea0c80bbd2b38d741394856ee446f13f964a9
--- /dev/null
+++ b/3rdparty/cpr/cpr/multiperform.cpp
@@ -0,0 +1,377 @@
+#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() {
+ // Unlock all sessions
+ for (const std::pair, HttpMethod>& pair : sessions_) {
+ pair.first->isUsedInMultiPerform = false;
+
+ // Remove easy handle from multi handle
+ const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, pair.first->curl_->handle);
+ if (error_code) {
+ std::cerr << "curl_multi_remove_handle() failed, code " << static_cast(error_code) << '\n';
+ return;
+ }
+ }
+}
+
+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;
+ }
+
+ // Add easy handle to multi handle
+ const CURLMcode error_code = curl_multi_add_handle(multicurl_->handle, session->curl_->handle);
+ if (error_code) {
+ std::cerr << "curl_multi_add_handle() failed, code " << static_cast(error_code) << '\n';
+ return;
+ }
+
+ // Lock session to the multihandle
+ session->isUsedInMultiPerform = true;
+
+ // Add session to sessions_
+ sessions_.emplace_back(session, method);
+}
+
+void MultiPerform::RemoveSession(const std::shared_ptr& session) {
+ // Has to be handled before calling curl_multi_remove_handle to avoid it returning something != CURLM_OK.
+ if (sessions_.empty()) {
+ throw std::invalid_argument("Failed to find session!");
+ }
+
+ // Remove easy handle from multihandle
+ const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle);
+ if (error_code != CURLM_OK) {
+ std::cerr << "curl_multi_remove_handle() failed, code " << static_cast(error_code) << '\n';
+ return;
+ }
+
+ // 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};
+ 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);
+
+ // Sort response objects to match order of added sessions
+ std::vector sorted_responses;
+ for (const std::pair, HttpMethod>& pair : sessions_) {
+ Session& current_session = *(pair.first);
+ auto it = std::find_if(responses.begin(), responses.end(), [¤t_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; });
+ const Response current_response = *it; // NOLINT (performance-unnecessary-copy-initialization) False possible
+ // 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 std::pair, HttpMethod>& pair : sessions_) {
+ switch (pair.second) {
+ case HttpMethod::GET_REQUEST:
+ pair.first->PrepareGet();
+ break;
+ case HttpMethod::POST_REQUEST:
+ pair.first->PreparePost();
+ break;
+ case HttpMethod::PUT_REQUEST:
+ pair.first->PreparePut();
+ break;
+ case HttpMethod::DELETE_REQUEST:
+ pair.first->PrepareDelete();
+ break;
+ case HttpMethod::PATCH_REQUEST:
+ pair.first->PreparePatch();
+ break;
+ case HttpMethod::HEAD_REQUEST:
+ pair.first->PrepareHead();
+ break;
+ case HttpMethod::OPTIONS_REQUEST:
+ pair.first->PrepareOptions();
+ break;
+ default:
+ std::cerr << "PrepareSessions failed: Undefined HttpMethod or download without arguments!" << '\n';
+ return;
+ }
+ }
+}
+
+void MultiPerform::PrepareDownloadSession(size_t sessions_index, const WriteCallback& write) {
+ const std::pair, HttpMethod>& pair = sessions_[sessions_index];
+ switch (pair.second) {
+ case HttpMethod::DOWNLOAD_REQUEST:
+ pair.first->PrepareDownload(write);
+ break;
+ default:
+ std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << '\n';
+ return;
+ }
+}
+
+void MultiPerform::PrepareDownloadSession(size_t sessions_index, std::ofstream& file) {
+ const std::pair, HttpMethod>& pair = sessions_[sessions_index];
+ switch (pair.second) {
+ case HttpMethod::DOWNLOAD_REQUEST:
+ pair.first->PrepareDownload(file);
+ break;
+ default:
+ std::cerr << "PrepareSessions failed: Undefined HttpMethod or non download method with arguments!" << '\n';
+ return;
+ }
+}
+
+void MultiPerform::SetHttpMethod(HttpMethod method) {
+ for (std::pair, HttpMethod>& pair : sessions_) {
+ pair.second = method;
+ }
+}
+
+void MultiPerform::PrepareGet() {
+ SetHttpMethod(HttpMethod::GET_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PrepareDelete() {
+ SetHttpMethod(HttpMethod::DELETE_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PreparePut() {
+ SetHttpMethod(HttpMethod::PUT_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PreparePatch() {
+ SetHttpMethod(HttpMethod::PATCH_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PrepareHead() {
+ SetHttpMethod(HttpMethod::HEAD_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PrepareOptions() {
+ SetHttpMethod(HttpMethod::OPTIONS_REQUEST);
+ PrepareSessions();
+}
+
+void MultiPerform::PreparePost() {
+ SetHttpMethod(HttpMethod::POST_REQUEST);
+ PrepareSessions();
+}
+
+std::vector 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 std::pair, HttpMethod>& s : sessions_) {
+ const HttpMethod method = s.second;
+ if ((new_is_download_multi_perform && method != HttpMethod::DOWNLOAD_REQUEST) || (!new_is_download_multi_perform && method == HttpMethod::DOWNLOAD_REQUEST)) {
+ throw std::invalid_argument("Failed to proceed with session: Cannot mix download and non-download methods!");
+ }
+ }
+ is_download_multi_perform = new_is_download_multi_perform;
+ }
+
+ PrepareSessions();
+ return MakeRequest();
+}
+
+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/3rdparty/cpr/cpr/parameters.cpp b/3rdparty/cpr/cpr/parameters.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51cdd183070aa8c55ae294fd00e1035ecb3498df
--- /dev/null
+++ b/3rdparty/cpr/cpr/parameters.cpp
@@ -0,0 +1,4 @@
+// NOLINTNEXTLINE(misc-include-cleaner) Ignored since it's for the future
+#include "cpr/parameters.h"
+
+namespace cpr {} // namespace cpr
diff --git a/3rdparty/cpr/cpr/payload.cpp b/3rdparty/cpr/cpr/payload.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a23b0dd30836b0486c537c4e5a741209d7f0d0f
--- /dev/null
+++ b/3rdparty/cpr/cpr/payload.cpp
@@ -0,0 +1,4 @@
+// NOLINTNEXTLINE(misc-include-cleaner) Ignored since it's for the future
+#include "cpr/payload.h"
+
+namespace cpr {} // namespace cpr
diff --git a/3rdparty/cpr/cpr/proxies.cpp b/3rdparty/cpr/cpr/proxies.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d3fe98935d14e8ebed86608c7a175c0f1decf4e
--- /dev/null
+++ b/3rdparty/cpr/cpr/proxies.cpp
@@ -0,0 +1,21 @@
+#include "cpr/proxies.h"
+
+#include
+#include