Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions .github/workflows/modules-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: C++20 Modules CI
on: [push, workflow_dispatch, pull_request]

env:
# Enable verbose output for CMake and tests
VERBOSE: 1
CTEST_OUTPUT_ON_FAILURE: 1

jobs:
ubuntu-clang-modules:
strategy:
matrix:
buildType: [Debug, Release]
runs-on: ubuntu-latest
steps:
- name: Update package list
run: sudo apt update
- name: Install Dependencies
run: |
sudo apt install -y git libssl-dev build-essential libcurl4-openssl-dev libpsl-dev meson libunistring-dev ninja-build wget
# Install Clang 21+
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt install -y libc++-21-dev libc++abi-21-dev
env:
DEBIAN_FRONTEND: noninteractive
- name: Install CMake 3.28+
run: |
wget -O cmake.sh https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh
sudo sh cmake.sh --prefix=/usr/local --skip-license
cmake --version
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=${{ matrix.buildType }} \
-DCMAKE_CXX_COMPILER=clang++-21 \
-DCMAKE_C_COMPILER=clang-21 \
-DCPR_BUILD_MODULES=ON \
-DCPR_BUILD_TESTS=ON \
-DCPR_BUILD_TESTS_SSL=ON \
-DCPR_FORCE_OPENSSL_BACKEND=ON \
-DCPR_USE_SYSTEM_CURL=OFF \
-G Ninja
- name: Build
run: cmake --build build --verbose
- name: Test
run: ctest --test-dir build --output-on-failure --repeat until-pass:5
- name: Verify Module Build
run: |
echo "Contents of build/modules:"
ls -la build/modules/
if [ -f build/modules/libcpr_module.a ] || [ -f build/modules/libcpr_module.so ] || [ -f build/modules/cpr_module.a ] || find build/modules -name "*cpr_module*" -type f | grep -q .; then
echo "Module library built successfully"
else
echo "Error: Module library not found"
exit 1
fi

fedora-gcc-modules:
runs-on: ubuntu-latest
container: "fedora:latest"
steps:
- name: Update package list
run: dnf update -y
- name: Install Dependencies
run: dnf install -y gcc g++ git make openssl-devel libcurl-devel cmake libpsl-devel libunistring-devel meson ninja-build
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCPR_BUILD_MODULES=ON \
-DCPR_BUILD_TESTS=ON \
-DCPR_BUILD_TESTS_SSL=ON \
-DCPR_FORCE_OPENSSL_BACKEND=ON \
-DCPR_USE_SYSTEM_CURL=OFF \
-G Ninja
- name: Build
run: cmake --build build --verbose
- name: Test
run: ctest --test-dir build --output-on-failure --repeat until-pass:5
- name: Verify Module Build
run: |
echo "Searching for module build artifacts:"
find build -name "*cpr_module*" -type f || true
find build -name "cpr.gcm" -type f || true
# GCC stores the compiled module interface (BMI) as cpr.gcm rather than
# a traditional archive when all sources are in FILE_SET CXX_MODULES.
# Also check build/lib/ in case LIBRARY_OUTPUT_PATH redirected the archive.
if find build \( -name "*cpr_module*" -o -name "cpr.gcm" \) -type f | grep -q .; then
echo "Module build artifacts found successfully"
else
echo "Error: No module build artifacts found"
exit 1
fi

windows-msvc-modules:
runs-on: windows-latest
steps:
- uses: actions/setup-python@v6
- name: Install meson
run: pip install meson
- name: Setup MSVC environment
uses: ilammy/msvc-dev-cmd@v1
- name: Checkout
uses: actions/checkout@v5
- name: Install dependencies via vcpkg
run: |
vcpkg install curl zlib openssl --triplet x64-windows
shell: pwsh
- name: Configure
run: |
cmake -S . -B build `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-DVCPKG_TARGET_TRIPLET=x64-windows `
-DCPR_BUILD_MODULES=ON `
-DCPR_BUILD_TESTS=ON `
-DCPR_BUILD_TESTS_SSL=OFF `
-DCPR_USE_SYSTEM_CURL=ON `
-G "Visual Studio 17 2022"
shell: pwsh
- name: Build
run: cmake --build build --config Release --verbose
- name: Test
run: ctest --test-dir build -C Release --output-on-failure --repeat until-pass:5
- name: Verify Module Build
run: |
Write-Host "Contents of build/modules/Release:"
Get-ChildItem -Path build/modules/Release -Force
if (!(Test-Path "build/modules/Release/cpr_module.lib") -and !(Get-ChildItem -Path build/modules -Recurse -Filter "*cpr_module*")) {
throw "Module library not found"
}
Write-Host "Module library built successfully"
shell: pwsh

macos-clang-modules:
runs-on: macos-latest
steps:
- name: Install Dependencies
run: |
brew install llvm libpsl ninja
- name: Checkout
uses: actions/checkout@v5
- name: Configure
run: |
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++ \
-DCMAKE_C_COMPILER=$(brew --prefix llvm)/bin/clang \
-DCPR_BUILD_MODULES=ON \
-DCPR_BUILD_TESTS=ON \
-DCPR_BUILD_TESTS_SSL=OFF \
-DCPR_USE_SYSTEM_LIB_PSL=ON \
-G Ninja
- name: Build
run: cmake --build build --verbose
- name: Test
run: ctest --test-dir build --output-on-failure --repeat until-pass:5
- name: Verify Module Build
run: |
echo "Contents of build/modules:"
ls -la build/modules/
if [ -f build/modules/libcpr_module.a ] || [ -f build/modules/libcpr_module.dylib ] || [ -f build/modules/cpr_module.a ] || find build/modules -name "*cpr_module*" -type f | grep -q .; then
echo "Module library built successfully"
else
echo "Error: Module library not found"
exit 1
fi
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ cpr_option(CPR_FORCE_DARWINSSL_BACKEND "Force to use the DarwinSSL backend. If C
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_MODULES "Set to ON to build cpr as a C++ module." 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)
Expand Down Expand Up @@ -323,6 +324,10 @@ else()
set(CURL_LIB CURL::libcurl)
endif()

if(CPR_BUILD_MODULES)
add_subdirectory(modules)
endif()

# GTest configuration
if(CPR_BUILD_TESTS)
if(CPR_USE_SYSTEM_GTEST)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ 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 use cpr as a C++20 module, you must have CMake 3.28 enabled. Enable `CPR_BUILD_MODULES` to activate the feature.
* 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.71.0`. Lower versions are not supported. This means you need Debian `>= 11` or Ubuntu `>= 22.04 LTS`.
* [`The Meson Build System`](https://mesonbuild.com/) is required build PSL from source ([PSL support for curl](https://everything.curl.dev/build/deps.html#libpsl)). For more information take a look at the `CPR_CURL_USE_LIBPSL` and `CPR_USE_SYSTEM_LIB_PSL` CMake options.
Expand Down
2 changes: 1 addition & 1 deletion include/cpr/accept_encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ enum class AcceptEncodingMethods : uint8_t {
};

// NOLINTNEXTLINE(cert-err58-cpp)
static const std::map<AcceptEncodingMethods, std::string> AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}};
inline const std::map<AcceptEncodingMethods, std::string> AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}};

class AcceptEncoding {
public:
Expand Down
2 changes: 1 addition & 1 deletion include/cpr/cookies.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace cpr {
* EXPIRES_STRING_SIZE is an explicitly static and const variable that could be only accessed within the same namespace and is immutable.
* To be used for "std::array", the expression must have a constant value, so EXPIRES_STRING_SIZE must be a const value.
**/
static const std::size_t EXPIRES_STRING_SIZE = 100;
inline const std::size_t EXPIRES_STRING_SIZE = 100;

class Cookie {
public:
Expand Down
2 changes: 2 additions & 0 deletions include/cpr/cpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include "cpr/connection_pool.h"
#include "cpr/cookies.h"
#include "cpr/cprtypes.h"
#ifndef CPR_AS_MODULE
#include "cpr/cprver.h"
#endif
#include "cpr/curl_container.h"
#include "cpr/curlholder.h"
#include "cpr/error.h"
Expand Down
145 changes: 71 additions & 74 deletions include/cpr/status_codes.h
Original file line number Diff line number Diff line change
@@ -1,82 +1,81 @@
#ifndef CPR_STATUS_CODES
#define CPR_STATUS_CODES
namespace cpr {
namespace status {
namespace cpr::status {
// Information responses
constexpr long HTTP_CONTINUE = 100;
constexpr long HTTP_SWITCHING_PROTOCOL = 101;
constexpr long HTTP_PROCESSING = 102;
constexpr long HTTP_EARLY_HINTS = 103;
inline constexpr long HTTP_CONTINUE = 100;
inline constexpr long HTTP_SWITCHING_PROTOCOL = 101;
inline constexpr long HTTP_PROCESSING = 102;
inline constexpr long HTTP_EARLY_HINTS = 103;
// Successful responses
constexpr long HTTP_OK = 200;
constexpr long HTTP_CREATED = 201;
constexpr long HTTP_ACCEPTED = 202;
constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
constexpr long HTTP_NO_CONTENT = 204;
constexpr long HTTP_RESET_CONTENT = 205;
constexpr long HTTP_PARTIAL_CONTENT = 206;
constexpr long HTTP_MULTI_STATUS = 207;
constexpr long HTTP_ALREADY_REPORTED = 208;
constexpr long HTTP_IM_USED = 226;
inline constexpr long HTTP_OK = 200;
inline constexpr long HTTP_CREATED = 201;
inline constexpr long HTTP_ACCEPTED = 202;
inline constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
inline constexpr long HTTP_NO_CONTENT = 204;
inline constexpr long HTTP_RESET_CONTENT = 205;
inline constexpr long HTTP_PARTIAL_CONTENT = 206;
inline constexpr long HTTP_MULTI_STATUS = 207;
inline constexpr long HTTP_ALREADY_REPORTED = 208;
inline constexpr long HTTP_IM_USED = 226;
// Redirection messages
constexpr long HTTP_MULTIPLE_CHOICE = 300;
constexpr long HTTP_MOVED_PERMANENTLY = 301;
constexpr long HTTP_FOUND = 302;
constexpr long HTTP_SEE_OTHER = 303;
constexpr long HTTP_NOT_MODIFIED = 304;
constexpr long HTTP_USE_PROXY = 305;
constexpr long HTTP_UNUSED = 306;
constexpr long HTTP_TEMPORARY_REDIRECT = 307;
constexpr long HTTP_PERMANENT_REDIRECT = 308;
inline constexpr long HTTP_MULTIPLE_CHOICE = 300;
inline constexpr long HTTP_MOVED_PERMANENTLY = 301;
inline constexpr long HTTP_FOUND = 302;
inline constexpr long HTTP_SEE_OTHER = 303;
inline constexpr long HTTP_NOT_MODIFIED = 304;
inline constexpr long HTTP_USE_PROXY = 305;
inline constexpr long HTTP_UNUSED = 306;
inline constexpr long HTTP_TEMPORARY_REDIRECT = 307;
inline constexpr long HTTP_PERMANENT_REDIRECT = 308;
// Client error responses
constexpr long HTTP_BAD_REQUEST = 400;
constexpr long HTTP_UNAUTHORIZED = 401;
constexpr long HTTP_PAYMENT_REQUIRED = 402;
constexpr long HTTP_FORBIDDEN = 403;
constexpr long HTTP_NOT_FOUND = 404;
constexpr long HTTP_METHOD_NOT_ALLOWED = 405;
constexpr long HTTP_NOT_ACCEPTABLE = 406;
constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
constexpr long HTTP_REQUEST_TIMEOUT = 408;
constexpr long HTTP_CONFLICT = 409;
constexpr long HTTP_GONE = 410;
constexpr long HTTP_LENGTH_REQUIRED = 411;
constexpr long HTTP_PRECONDITION_FAILED = 412;
constexpr long HTTP_PAYLOAD_TOO_LARGE = 413;
constexpr long HTTP_URI_TOO_LONG = 414;
constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
constexpr long HTTP_EXPECTATION_FAILED = 417;
constexpr long HTTP_IM_A_TEAPOT = 418;
constexpr long HTTP_MISDIRECTED_REQUEST = 421;
constexpr long HTTP_UNPROCESSABLE_ENTITY = 422;
constexpr long HTTP_LOCKED = 423;
constexpr long HTTP_FAILED_DEPENDENCY = 424;
constexpr long HTTP_TOO_EARLY = 425;
constexpr long HTTP_UPGRADE_REQUIRED = 426;
constexpr long HTTP_PRECONDITION_REQUIRED = 428;
constexpr long HTTP_TOO_MANY_REQUESTS = 429;
constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
inline constexpr long HTTP_BAD_REQUEST = 400;
inline constexpr long HTTP_UNAUTHORIZED = 401;
inline constexpr long HTTP_PAYMENT_REQUIRED = 402;
inline constexpr long HTTP_FORBIDDEN = 403;
inline constexpr long HTTP_NOT_FOUND = 404;
inline constexpr long HTTP_METHOD_NOT_ALLOWED = 405;
inline constexpr long HTTP_NOT_ACCEPTABLE = 406;
inline constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
inline constexpr long HTTP_REQUEST_TIMEOUT = 408;
inline constexpr long HTTP_CONFLICT = 409;
inline constexpr long HTTP_GONE = 410;
inline constexpr long HTTP_LENGTH_REQUIRED = 411;
inline constexpr long HTTP_PRECONDITION_FAILED = 412;
inline constexpr long HTTP_PAYLOAD_TOO_LARGE = 413;
inline constexpr long HTTP_URI_TOO_LONG = 414;
inline constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
inline constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
inline constexpr long HTTP_EXPECTATION_FAILED = 417;
inline constexpr long HTTP_IM_A_TEAPOT = 418;
inline constexpr long HTTP_MISDIRECTED_REQUEST = 421;
inline constexpr long HTTP_UNPROCESSABLE_ENTITY = 422;
inline constexpr long HTTP_LOCKED = 423;
inline constexpr long HTTP_FAILED_DEPENDENCY = 424;
inline constexpr long HTTP_TOO_EARLY = 425;
inline constexpr long HTTP_UPGRADE_REQUIRED = 426;
inline constexpr long HTTP_PRECONDITION_REQUIRED = 428;
inline constexpr long HTTP_TOO_MANY_REQUESTS = 429;
inline constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
inline constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
// Server response errors
constexpr long HTTP_INTERNAL_SERVER_ERROR = 500;
constexpr long HTTP_NOT_IMPLEMENTED = 501;
constexpr long HTTP_BAD_GATEWAY = 502;
constexpr long HTTP_SERVICE_UNAVAILABLE = 503;
constexpr long HTTP_GATEWAY_TIMEOUT = 504;
constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505;
constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506;
constexpr long HTTP_INSUFFICIENT_STORAGE = 507;
constexpr long HTTP_LOOP_DETECTED = 508;
constexpr long HTTP_NOT_EXTENDED = 510;
constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;
inline constexpr long HTTP_INTERNAL_SERVER_ERROR = 500;
inline constexpr long HTTP_NOT_IMPLEMENTED = 501;
inline constexpr long HTTP_BAD_GATEWAY = 502;
inline constexpr long HTTP_SERVICE_UNAVAILABLE = 503;
inline constexpr long HTTP_GATEWAY_TIMEOUT = 504;
inline constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505;
inline constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506;
inline constexpr long HTTP_INSUFFICIENT_STORAGE = 507;
inline constexpr long HTTP_LOOP_DETECTED = 508;
inline constexpr long HTTP_NOT_EXTENDED = 510;
inline constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;

constexpr long INFO_CODE_OFFSET = 100;
constexpr long SUCCESS_CODE_OFFSET = 200;
constexpr long REDIRECT_CODE_OFFSET = 300;
constexpr long CLIENT_ERROR_CODE_OFFSET = 400;
constexpr long SERVER_ERROR_CODE_OFFSET = 500;
constexpr long MISC_CODE_OFFSET = 600;
inline constexpr long INFO_CODE_OFFSET = 100;
inline constexpr long SUCCESS_CODE_OFFSET = 200;
inline constexpr long REDIRECT_CODE_OFFSET = 300;
inline constexpr long CLIENT_ERROR_CODE_OFFSET = 400;
inline constexpr long SERVER_ERROR_CODE_OFFSET = 500;
inline constexpr long MISC_CODE_OFFSET = 600;

constexpr bool is_informational(const long code) {
return (code >= INFO_CODE_OFFSET && code < SUCCESS_CODE_OFFSET);
Expand All @@ -93,7 +92,5 @@ constexpr bool is_client_error(const long code) {
constexpr bool is_server_error(const long code) {
return (code >= SERVER_ERROR_CODE_OFFSET && code < MISC_CODE_OFFSET);
}

} // namespace status
} // namespace cpr
} // namespace cpr::status
#endif
Loading
Loading