not necessary anymore

This commit is contained in:
千住柱間 2024-04-13 22:54:57 -04:00
parent a44fc99f9a
commit 73276228d6
Signed by: hashirama
GPG key ID: 53E62470A86BC185
170 changed files with 0 additions and 20209 deletions

View file

@ -1,59 +0,0 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -2
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
BinPackArguments: true
ColumnLimit: 500
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 2
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: None
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 4
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterCStyleCast: true
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 8
CommentPragmas: '^ IWYU pragma:'
SpaceBeforeParens: ControlStatements
...

View file

@ -1,41 +0,0 @@
---
Checks: '*,
-cppcoreguidelines-pro-type-static-cast-downcast,
-fuchsia-default-arguments-calls,
-fuchsia-default-arguments,
-fuchsia-default-arguments-declarations,
-fuchsia-overloaded-operator,
-fuchsia-statically-constructed-objects,
-hicpp-use-auto,
-modernize-use-auto,
-modernize-use-trailing-return-type,
-readability-implicit-bool-conversion,
-readability-const-return-type,
-google-runtime-references,
-misc-non-private-member-variables-in-classes,
-llvm-include-order,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-pro-type-vararg,
-hicpp-vararg,
-cppcoreguidelines-owning-memory,
-llvmlibc-callee-namespace,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-hicpp-no-array-decay,
-modernize-pass-by-value,
-cppcoreguidelines-pro-bounds-constant-array-index,
-hicpp-signed-bitwise,
-llvmlibc-implementation-in-namespace,
-llvmlibc-restrict-system-libc-headers,
-readability-function-cognitive-complexity,
-readability-identifier-length,
-altera-unroll-loops,
-altera-id-dependent-backward-branch,
-bugprone-easily-swappable-parameters,
-modernize-return-braced-init-list,
-cppcoreguidelines-avoid-magic-numbers,
-readability-magic-numbers,
-cppcoreguidelines-avoid-do-while
'
WarningsAsErrors: '*'
HeaderFilterRegex: 'src/*.hpp'
FormatStyle: file

View file

@ -1,58 +0,0 @@
name: "🐛 Bug report"
description: Something in cpr is not working as expected? Create a report to help us improve.
labels: ["Needs Investigation :mag:", "Bug :bug:"]
body:
- type: markdown
attributes:
value: |
Provide a general summary of the issue in the Title above.
Use Markdown to highlight and format your code!
[https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf](https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf)
[https://developers.google.com/blockly/guides/modify/contribute/write_a_good_issue](https://developers.google.com/blockly/guides/modify/contribute/write_a_good_issue)
⚠️⚠️ If you do not use this template, we will simply close your issue. There are no exceptions for this! These steps, especially the part at the end, are very important to solve your problem quickly and efficiently. Please remember that we are not paid to solve or even answer your issues, so we do all this work in OUR free time. ⚠️⚠️
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
placeholder: What happened? Also tell us, what did you expect to happen?
validations:
required: true
- type: textarea
attributes:
label: Example/How to Reproduce
description: "Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code to reproduce, if relevant."
value: |
1. Create a `cpr::Session`
2. Set option ...
3. Perform the request
4. See error
validations:
required: true
- type: textarea
attributes:
label: Possible Fix
description: A possible fix for your issue.
placeholder: Not obligatory, but suggest a fix or reason for the bug.
validations:
required: false
- type: dropdown
attributes:
label: Where did you get it from?
multiple: true
options:
- GitHub (branch e.g. master)
- vcpkg
- conan
- NuGet
- Other (specify in "Additional Context/Your Environment")
validations:
required: true
- type: textarea
attributes:
label: Additional Context/Your Environment
description: Provide some additional context for your issue and your environment your are trying to use cpr in.
value: |
- OS:
- Version:
validations:
required: true

View file

@ -1,36 +0,0 @@
name: "✨ Feature request"
description: Suggest an idea for this project.
labels: ["Needs Investigation :mag:", "Feature :sparkles:"]
body:
- type: markdown
attributes:
value: |
Provide a general summary of the feature in the Title above.
Use Markdown to highlight and format your code!
[https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf](https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf)
[https://developers.google.com/blockly/guides/modify/contribute/write_a_good_issue](https://developers.google.com/blockly/guides/modify/contribute/write_a_good_issue)
⚠️⚠️ If you do not use this template, we will simply close your feature request. There are no exceptions for this! These steps are very important to solve your problem quickly and efficiently. Please remember that we are not paid to solve or even answer your feature requests, so we do all this work in OUR free time. ⚠️⚠️
- type: markdown
attributes:
value: |
Thanks for suggesting new features or pointing our missing functionality.
Please describe your request in detail so we can understand your ideas. Feel free to upload additional material such as mockups, diagrams, or sketches.
- type: textarea
attributes:
label: Is your feature request related to a problem?
description: Please describe. A clear and concise description of what the problem is.
placeholder: Ex. I'm always frustrated when ...
- type: textarea
attributes:
label: Possible Solution
description: Describe the solution you'd like.
validations:
required: true
- type: textarea
attributes:
label: Alternatives
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.

View file

@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View file

@ -1,36 +0,0 @@
name: Build Debian Package
on:
push:
tags: [ '[0-9]+.[0-9]+.[0-9]+' ]
pull_request:
jobs:
package-ubuntu-latest-amd64:
runs-on: ubuntu-latest
steps:
- name: "Checkout"
uses: actions/checkout@v3
with:
submodules: true
path: cpr
# Install packages necessary for building libcpr and package
- name: "Update package list"
run: sudo apt update
- name: "Install cpr dependencies"
run: sudo apt install -y libssl-dev libcurl4-openssl-dev
- name: "Install building tools"
run: sudo apt install -y cmake debmake devscripts debhelper
# Build package of runtime library
- name: "Package build of runtime library"
env:
VERSION: ${{ github.ref_name }}
run: bash cpr/package-build/build-package.sh cpr
- name: "Upload deb-packages"
uses: actions/upload-artifact@v3
with:
name: artifact-deb
path: ./*.deb

View file

@ -1,115 +0,0 @@
name: Build NuGet Package
on:
push:
tags: [ '[0-9]+.[0-9]+.[0-9]+' ]
workflow_dispatch:
inputs:
version:
description: 'The optional semantic version number. If not supplied the branch/tag will be used.'
type: string
no_publish:
description: 'Prevent publishing the NuGet package. Just build it and then upload it as an artifact.'
type: boolean
default: false
jobs:
package-windows-latest:
runs-on: windows-latest
steps:
- name: Set version based on input
if: ${{ inputs.version }}
run: echo "RELEASE_VERSION=${{ inputs.version }}" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
- name: Set version based on ref
if: ${{ !inputs.version }}
run: echo "RELEASE_VERSION=$($env:GITHUB_REF -replace 'refs/.*/', '')" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
- name: Print Version
run: echo "NuGet version will be '${{ env.RELEASE_VERSION }}'"
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Setup NuGet.exe
uses: nuget/setup-nuget@v1
- name: "[Release_x86] Build & Install"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: false
configure-options: -DBUILD_SHARED_LIBS=ON -DCURL_ZLIB=OFF -A Win32
install-build: true
install-options: --prefix ${{github.workspace}}\install --config Release
- name: "[Release_x86] Copy install files for Release_x86"
run: xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\x86\Release && xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\Win32\Release
- name: "[Release_x86] Clean build"
run: rm -r -fo ${{github.workspace}}/build
- name: "[Debug_x86] Build & Install"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Debug
target: ALL_BUILD
run-test: false
configure-options: -DBUILD_SHARED_LIBS=ON -DCURL_ZLIB=OFF -A Win32
install-build: true
install-options: --prefix ${{github.workspace}}\install --config Debug
- name: "[Debug_x86] Copy install files for Debug_x86"
run: xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\x86\Debug && xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\Win32\Debug
- name: "[Debug_x86] Clean build"
run: rm -r -fo ${{github.workspace}}/build
- name: "[Release_x64] Build & Install"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: false
configure-options: -DBUILD_SHARED_LIBS=ON -DCURL_ZLIB=OFF -A x64
install-build: true
install-options: --prefix ${{github.workspace}}\install --config Release
- name: "[Release_x64] Copy install files for Release_x64"
run: xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\x64\Release
- name: "[Release_x64] Clean build"
run: rm -r -fo ${{github.workspace}}/build
- name: "[Debug_x64] Build & Install"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Debug
target: ALL_BUILD
run-test: false
configure-options: -DBUILD_SHARED_LIBS=ON -DCURL_ZLIB=OFF -A x64
install-build: true
install-options: --prefix ${{github.workspace}}\install --config Debug
- name: "[Debug_x64] Copy install files for Debug_x64"
run: xcopy /e /i /y ${{github.workspace}}\install ${{github.workspace}}\nuget\build\native\x64\Debug
- name: "Copy Readme.md"
run: xcopy /y ${{github.workspace}}\README.md ${{github.workspace}}\nuget
- name: "Create NuGet package"
env:
VERSION: ${{ env.RELEASE_VERSION }}
COMMIT_HASH: ${{ github.sha }}
run: nuget pack ${{github.workspace}}\nuget\libcpr.nuspec -OutputDirectory ${{github.workspace}} -Properties "VERSION=$ENV:VERSION;COMMIT_HASH=$ENV:COMMIT_HASH"
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: artifact-nuget
path: ${{github.workspace}}\*.nupkg
- name: "Publish package to NuGet.org"
if: ${{ !inputs.no_publish }}
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: nuget push ${{github.workspace}}\*.nupkg $ENV:NUGET_API_KEY -Source https://api.nuget.org/v3/index.json

View file

@ -1,633 +0,0 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
ubuntu-22-04-static-gcc-ssl:
runs-on: ubuntu-latest
container: ubuntu:22.04
steps:
- name: Update package list
run: apt update
- name: Install git
run: apt install -y git
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install libssl-dev
run: apt install -y libssl-dev
- name: Install cmake
run: apt install -y cmake
- name: Install build-essential
run: apt install -y build-essential
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
ubuntu-22-04-clang-static-ssl:
runs-on: ubuntu-latest
container: ubuntu:22.04
steps:
- name: Update package list
run: apt update
- name: Install git
run: apt install -y git
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install libssl-dev
run: apt install -y libssl-dev
- name: Install cmake
run: apt install -y cmake
- name: Install build-essential
run: apt install -y build-essential
- name: Install clang
run: apt install -y clang
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: clang
cxx: clang++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
ubuntu-20-shared-gcc-ssl:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
ubuntu-20-static-gcc-mbedtls:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libmbedtls-dev
run: sudo apt install libmbedtls-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
CPR_FORCE_MBEDTLS_BACKEND: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
ubuntu-20-shared-gcc-mbedtls:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libmbedtls-dev
run: sudo apt install libmbedtls-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
CPR_FORCE_MBEDTLS_BACKEND: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
ubuntu-20-static-gcc-ssl:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
ubuntu-18-gcc-shared-ssl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
ubuntu-18-gcc-static-ssl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
ubuntu-18-gcc-shared-ssl-system-curl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libcurl4-openssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
configure-options: -DUSE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=ON
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
ubuntu-18-gcc-static-ssl-system-curl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libcurl4-openssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
configure-options: -DUSE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF
cc: gcc
cxx: g++
build-type: Release
run-test: true
ctest-options: -V
ubuntu-18-gcc-ssl-address-leak-undefined-behavior-sanitizer:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: Install sanitizer
run: sudo apt install libasan5 libubsan1 liblsan0 libtsan0
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_DEBUG_SANITIZER_FLAG_ALL: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Debug
run-test: true
ctest-options: -V
ubuntu-18-gcc-ssl-thread-sanitizer:
runs-on: ubuntu-18.04
if: ${{ false }} # Disabled for now until all problems are resolved
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: Install sanitizer
run: sudo apt install libasan5 libubsan1 liblsan0 libtsan0
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_DEBUG_SANITIZER_FLAG_THREAD: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Debug
run-test: true
ctest-options: -V
ubuntu-18-clang-shared-ssl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: clang
cxx: clang++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
ubuntu-18-clang-static-ssl:
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install libssl-dev
run: sudo apt install libssl-dev
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: clang
cxx: clang++
build-type: Release
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
windows-msvc-shared-ssl:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: "[Release msvc] Build & Test"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
windows-msvc-shared-winssl:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: "[Release msvc] Build & Test"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
CPR_FORCE_WINSSL_BACKEND: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
windows-msvc-static-ssl:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: "[Release msvc] Build & Test"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
windows-msvc-shared-openssl:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install OpenSSL
run: choco install openssl -y
- name: "[Release msvc] Build & Test"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
CPR_BUILD_TESTS: ON
CPR_FORCE_OPENSSL_BACKEND: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
windows-msvc-static-openssl:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install OpenSSL
run: choco install openssl -y
- name: "[Release msvc] Build & Test"
env:
CMAKE_GENERATOR: "Visual Studio 17 2022"
CPR_BUILD_TESTS: ON
CPR_FORCE_OPENSSL_BACKEND: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
target: ALL_BUILD
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
macos-clang-shared-openssl:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install OpenSSL
run: |
brew install openssl
echo 'export PATH="/usr/local/opt/openssl@3/bin:$PATH"' >> /Users/runner/.bash_profile
source ~/.bash_profile
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
- name: "[Release clang++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: ON
OPENSSL_ROOT_DIR: "/usr/local/opt/openssl@3"
OPENSSL_LIBRARIES: "/usr/local/opt/openssl@3/lib"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
cc: clang
cxx: clang++
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=ON
macos-clang-static-openssl:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install OpenSSL
run: |
brew install openssl
echo 'export PATH="/usr/local/opt/openssl@3/bin:$PATH"' >> /Users/runner/.bash_profile
source ~/.bash_profile
export LDFLAGS="-L/usr/local/opt/openssl@3/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@3/include"
export PKG_CONFIG_PATH="/usr/local/opt/openssl@3/lib/pkgconfig"
- name: "[Release clang++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
OPENSSL_ROOT_DIR: "/usr/local/opt/openssl@3"
OPENSSL_LIBRARIES: "/usr/local/opt/openssl@3/lib"
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
cc: clang
cxx: clang++
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
macos-clang-static-autossl:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: "[Release clang++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
cc: clang
cxx: clang++
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF
macos-clang-static-darwinssl:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: "[Release clang++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
cc: clang
cxx: clang++
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF -DCPR_FORCE_DARWINSSL_BACKEND=ON
macos-clang-static-autossl-boost:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install Boost
run: |
brew install boost
- name: "[Release clang++] Build & Test"
env:
CPR_BUILD_TESTS: ON
CPR_BUILD_TESTS_SSL: OFF
CPR_USE_BOOST_FILESYSTEM: ON
CMAKE_OSX_DEPLOYMENT_TARGET: 10.13
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
build-type: Release
cc: clang
cxx: clang++
run-test: true
ctest-options: -V
configure-options: -DBUILD_SHARED_LIBS=OFF

View file

@ -1,19 +0,0 @@
name: "Test Clang Format"
on: [push, pull_request]
jobs:
clang-format:
runs-on: ubuntu-latest
container: fedora:latest
steps:
- name: Update package list
run: sudo dnf update -y
- name: Install dependencies
run: sudo dnf install -y openssl-devel cmake git gcc clang ninja-build
- name: Install clang-tidy
run: sudo dnf install -y clang-tools-extra
- name: Checkout
uses: actions/checkout@v3
- name: Check format
uses: RafikFarhad/clang-format-github-action@v3.0.0

View file

@ -1,29 +0,0 @@
name: "Test Clang Tidy"
on: [push, pull_request]
jobs:
clang-tidy:
runs-on: ubuntu-latest
container: fedora:latest
steps:
- name: Update package list
run: sudo dnf update -y
- name: Install dependencies
run: sudo dnf install -y openssl-devel cmake git gcc clang ninja-build
- name: Install clang-tidy
run: sudo dnf install -y clang-tools-extra
- name: Checkout
uses: actions/checkout@v3
- name: "[Release g++] Build & Test"
env:
CPR_BUILD_TESTS: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: clang
cxx: clang++
build-type: Release
run-test: false
configure-options: -DCPR_ENABLE_LINTING=ON

View file

@ -1,71 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '25 20 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View file

@ -1,27 +0,0 @@
name: "Test cppcheck"
on: [push, pull_request]
jobs:
cppcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Update package list
run: sudo apt update
- name: Install cppcheck
run: sudo apt install cppcheck
- name: "[Release g++] Build"
env:
CPR_ENABLE_CPPCHECK: ON
uses: ashutoshvarma/action-cmake-build@master
with:
build-dir: ${{github.workspace}}/build
source-dir: ${{github.workspace}}
cc: gcc
cxx: g++
build-type: Release
run-test: false

61
cpr-1.10.5/.gitignore vendored
View file

@ -1,61 +0,0 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# CMake
CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
# Custom
build/
!nuget/build
# Jekyll stuff
_includes/
_site/
# Vim
.ycm_extra_conf.py*
*.swp
# VSCode
.vscode/
.vs/
# clangd
.cache/
# compilation database
# used in various editor configurations, such as vim & YcM
compile_commands.json
# macOS
.DS_Store

View file

@ -1,373 +0,0 @@
cmake_minimum_required(VERSION 3.15)
project(cpr VERSION 1.10.5 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()
option(BUILD_SHARED_LIBS "Build libraries as shared libraries" ON)
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_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 "=======================================================")
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()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror")
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()
else()
message(STATUS "Configuring built-in curl...")
# ZLIB is optional for curl
# to disable it:
# * from command line:
# -DCURL_ZLIB=OFF
# * from CMake script:
# SET(CURL_ZLIB OFF CACHE STRING "" FORCE)
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
restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
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/release-1.11.0.tar.gz
URL_HASH SHA256=b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5 # the file hash for release-1.11.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()
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()

View file

@ -1,128 +0,0 @@
# 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.

View file

@ -1,27 +0,0 @@
# 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).

View file

@ -1,3 +0,0 @@
noExplicitConstructor
ConfigurationNotChecked
passedByValue

View file

@ -1,25 +0,0 @@
This license applies to everything except the contents of the "test"
directory and its subdirectories.
MIT License
Copyright (c) 2017-2021 Huu Nguyen
Copyright (c) 2022 libcpr and many other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,173 +0,0 @@
# C++ Requests: Curl for People <img align="right" height="40" src="http://i.imgur.com/d9Xtyts.png">
[![Documentation](https://img.shields.io/badge/docs-online-informational?style=flat&link=https://docs.libcpr.org/)](https://docs.libcpr.org/)
![CI](https://github.com/libcpr/cpr/workflows/CI/badge.svg)
[![Gitter](https://badges.gitter.im/libcpr/community.svg)](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 offer 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.10.x | `cpp17` | ![alt text][supported] | |
| 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 <cpr/cpr.h>
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
[![Documentation](https://img.shields.io/badge/docs-online-informational?style=for-the-badge&link=https://docs.libcpr.org/)](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 planed 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 0817715923c9705e68994eb52ef9df3f6845beba) # The commit hash for 1.10.x. Replace with the latest 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 .
$ 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)
```
### 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)
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/)
## 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.
## 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.

View file

@ -1,14 +0,0 @@
# 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)

View file

@ -1,13 +0,0 @@
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()

View file

@ -1,11 +0,0 @@
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()

View file

@ -1,29 +0,0 @@
# 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()

View file

@ -1,10 +0,0 @@
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()

View file

@ -1,8 +0,0 @@
include(CMakeFindDependencyMacro)
@PACKAGE_INIT@
find_dependency(CURL REQUIRED)
include(${CMAKE_CURRENT_LIST_DIR}/cprTargets.cmake)
check_required_components(cpr)

View file

@ -1,30 +0,0 @@
#ifndef CPR_CPRVER_H
#define CPR_CPRVER_H
/**
* CPR version as a string.
**/
#define CPR_VERSION "${cpr_VERSION}"
/**
* CPR version split up into parts.
**/
#define CPR_VERSION_MAJOR ${cpr_VERSION_MAJOR}
#define CPR_VERSION_MINOR ${cpr_VERSION_MINOR}
#define CPR_VERSION_PATCH ${cpr_VERSION_PATCH}
/**
* CPR version as a single hex digit.
* it can be split up into three parts:
* 0xAABBCC
* AA: The current CPR major version number in a hex format.
* BB: The current CPR minor version number in a hex format.
* CC: The current CPR patch version number in a hex format.
*
* Examples:
* '0x010702' -> 01.07.02 -> CPR_VERSION: 1.7.2
* '0xA13722' -> A1.37.22 -> CPR_VERSION: 161.55.34
**/
#define CPR_VERSION_NUM ${cpr_VERSION_NUM}
#endif

View file

@ -1,12 +0,0 @@
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 PRIVATE OpenSSL::SSL)
endif()

View file

@ -1,69 +0,0 @@
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()

View file

@ -1,18 +0,0 @@
# ZLIB
# Fix Windows missing "zlib.dll":
if(WIN32 AND (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}))
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/$<CONFIG> CACHE INTERNAL "" FORCE)
endif()
set(ZLIB_COMPAT ON CACHE INTERNAL "" FORCE)
set(ZLIB_ENABLE_TESTS OFF CACHE INTERNAL "" FORCE)
#FetchContent Zlib
# Fix Windows zlib dll names from "zlibd1.dll" to "zlib.dll":
if(WIN32)
set_target_properties(zlib PROPERTIES OUTPUT_NAME "zlib")
set_target_properties(zlib PROPERTIES DEBUG_POSTFIX "")
set_target_properties(zlib PROPERTIES SUFFIX ".dll")
endif()

View file

@ -1,26 +0,0 @@
# - 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()

View file

@ -1,85 +0,0 @@
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 -lcurl) # 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)
if(CPR_USE_SYSTEM_CURL)
install(TARGETS cpr
EXPORT cprTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
# 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(EXPORT cprTargets
FILE cprTargets.cmake
NAMESPACE cpr::
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)
else()
install(TARGETS cpr
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()

View file

@ -1,37 +0,0 @@
#include "cpr/accept_encoding.h"
#include <algorithm>
#include <cassert>
#include <initializer_list>
#include <iterator>
#include <numeric>
#include <stdexcept>
namespace cpr {
AcceptEncoding::AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& 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<std::string>& 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

View file

@ -1,8 +0,0 @@
#include "cpr/async.h"
namespace cpr {
// NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables)
CPR_SINGLETON_IMPL(GlobalThreadPool)
} // namespace cpr

View file

@ -1,16 +0,0 @@
#include "cpr/auth.h"
#include "cpr/util.h"
namespace cpr {
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

View file

@ -1,16 +0,0 @@
#include "cpr/bearer.h"
#include "cpr/util.h"
namespace cpr {
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
Bearer::~Bearer() noexcept {
util::secureStringClear(token_string_);
}
const char* Bearer::GetToken() const noexcept {
return token_string_.c_str();
}
#endif
} // namespace cpr

View file

@ -1,14 +0,0 @@
#include <cpr/callback.h>
#include <curl/curl.h>
#include <functional>
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

View file

@ -1,43 +0,0 @@
#include "cpr/cert_info.h"
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

View file

@ -1,106 +0,0 @@
#include "cpr/cookies.h"
#include <ctime>
#include <iomanip>
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
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);
}
void Cookies::push_back(const Cookie& str) {
cookies_.push_back(str);
}
void Cookies::pop_back() {
cookies_.pop_back();
}
} // namespace cpr

View file

@ -1,10 +0,0 @@
#include "cpr/cprtypes.h"
#include <algorithm>
#include <cctype>
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

View file

@ -1,58 +0,0 @@
#include "cpr/curl_container.h"
#include <algorithm>
#include <iterator>
namespace cpr {
template <class T>
CurlContainer<T>::CurlContainer(const std::initializer_list<T>& containerList) : containerList_(containerList) {}
template <class T>
void CurlContainer<T>::Add(const std::initializer_list<T>& containerList) {
std::transform(containerList.begin(), containerList.end(), std::back_inserter(containerList_), [](const T& elem) { return std::move(elem); });
}
template <class T>
void CurlContainer<T>::Add(const T& element) {
containerList_.push_back(std::move(element));
}
template <>
const std::string CurlContainer<Parameter>::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<Pair>::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<Pair>;
template class CurlContainer<Parameter>;
} // namespace cpr

View file

@ -1,49 +0,0 @@
#include "cpr/curlholder.h"
#include <cassert>
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<int>(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<int>(s.length()), nullptr);
if (output) {
std::string result = output;
curl_free(output);
return result;
}
return "";
}
} // namespace cpr

View file

@ -1,15 +0,0 @@
#include "cpr/curlmultiholder.h"
#include <cassert>
namespace cpr {
CurlMultiHolder::CurlMultiHolder() : handle{curl_multi_init()} {
assert(handle);
}
CurlMultiHolder::~CurlMultiHolder() {
curl_multi_cleanup(handle);
}
} // namespace cpr

View file

@ -1,68 +0,0 @@
#include "cpr/error.h"
#include <curl/curl.h>
namespace cpr {
ErrorCode Error::getErrorCodeForCurlError(std::int32_t curl_code) {
switch (curl_code) {
case CURLE_OK:
return ErrorCode::OK;
case CURLE_UNSUPPORTED_PROTOCOL:
return ErrorCode::UNSUPPORTED_PROTOCOL;
case CURLE_URL_MALFORMAT:
return ErrorCode::INVALID_URL_FORMAT;
case CURLE_COULDNT_RESOLVE_PROXY:
return ErrorCode::PROXY_RESOLUTION_FAILURE;
case CURLE_COULDNT_RESOLVE_HOST:
return ErrorCode::HOST_RESOLUTION_FAILURE;
case CURLE_COULDNT_CONNECT:
return ErrorCode::CONNECTION_FAILURE;
case CURLE_OPERATION_TIMEDOUT:
return ErrorCode::OPERATION_TIMEDOUT;
case CURLE_SSL_CONNECT_ERROR:
return ErrorCode::SSL_CONNECT_ERROR;
#if LIBCURL_VERSION_NUM < 0x073e00
case CURLE_PEER_FAILED_VERIFICATION:
return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR;
#endif
case CURLE_ABORTED_BY_CALLBACK:
case CURLE_WRITE_ERROR:
return ErrorCode::REQUEST_CANCELLED;
case CURLE_GOT_NOTHING:
return ErrorCode::EMPTY_RESPONSE;
case CURLE_SSL_ENGINE_NOTFOUND:
case CURLE_SSL_ENGINE_SETFAILED:
return ErrorCode::GENERIC_SSL_ERROR;
case CURLE_SEND_ERROR:
return ErrorCode::NETWORK_SEND_FAILURE;
case CURLE_RECV_ERROR:
return ErrorCode::NETWORK_RECEIVE_ERROR;
case CURLE_SSL_CERTPROBLEM:
return ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR;
case CURLE_SSL_CIPHER:
return ErrorCode::GENERIC_SSL_ERROR;
#if LIBCURL_VERSION_NUM >= 0x073e00
case CURLE_PEER_FAILED_VERIFICATION:
return ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR;
#else
case CURLE_SSL_CACERT:
return ErrorCode::SSL_CACERT_ERROR;
#endif
case CURLE_USE_SSL_FAILED:
case CURLE_SSL_ENGINE_INITFAILED:
return ErrorCode::GENERIC_SSL_ERROR;
case CURLE_SSL_CACERT_BADFILE:
return ErrorCode::SSL_CACERT_ERROR;
case CURLE_SSL_SHUTDOWN_FAILED:
return ErrorCode::GENERIC_SSL_ERROR;
case CURLE_SSL_CRL_BADFILE:
case CURLE_SSL_ISSUER_ERROR:
return ErrorCode::SSL_CACERT_ERROR;
case CURLE_TOO_MANY_REDIRECTS:
return ErrorCode::TOO_MANY_REDIRECTS;
default:
return ErrorCode::INTERNAL_ERROR;
}
}
} // namespace cpr

View file

@ -1,60 +0,0 @@
#include "cpr/file.h"
namespace cpr {
Files::Files(const std::initializer_list<std::string>& 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

View file

@ -1,53 +0,0 @@
#include "cpr/interceptor.h"
#include <exception>
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<Response> 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

View file

@ -1,5 +0,0 @@
#include "cpr/multipart.h"
namespace cpr {
Multipart::Multipart(const std::initializer_list<Part>& p_parts) : parts{p_parts} {}
} // namespace cpr

View file

@ -1,331 +0,0 @@
#include "cpr/multiperform.h"
#include "cpr/interceptor.h"
#include "cpr/multipart.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
namespace cpr {
MultiPerform::MultiPerform() : multicurl_(new CurlMultiHolder()) {}
MultiPerform::~MultiPerform() {
// Unlock all sessions
for (const std::pair<std::shared_ptr<Session>, 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<int>(error_code) << std::endl;
return;
}
}
}
void MultiPerform::AddSession(std::shared_ptr<Session>& 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<int>(error_code) << std::endl;
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>& session) {
// Remove easy handle from multihandle
const CURLMcode error_code = curl_multi_remove_handle(multicurl_->handle, session->curl_->handle);
if (error_code) {
std::cerr << "curl_multi_remove_handle() failed, code " << static_cast<int>(error_code) << std::endl;
return;
}
// Unock session
session->isUsedInMultiPerform = false;
// Remove session from sessions_
auto it = std::find_if(sessions_.begin(), sessions_.end(), [&session](const std::pair<std::shared_ptr<Session>, 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<std::pair<std::shared_ptr<Session>, MultiPerform::HttpMethod>>& MultiPerform::GetSessions() {
return sessions_;
}
const std::vector<std::pair<std::shared_ptr<Session>, 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<int>(error_code) << std::endl;
break;
}
if (still_running) {
const int timeout_ms{250};
error_code = curl_multi_poll(multicurl_->handle, nullptr, 0, timeout_ms, nullptr);
if (error_code) {
std::cerr << "curl_multi_poll() failed, code " << static_cast<int>(error_code) << std::endl;
break;
}
}
} while (still_running);
}
std::vector<Response> MultiPerform::ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function) {
// Get infos and create Response objects
std::vector<Response> 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<std::shared_ptr<Session>, HttpMethod>& pair) { return pair.first->curl_->handle == info->easy_handle; });
if (it == sessions_.end()) {
std::cerr << "Failed to find current session!" << std::endl;
break;
}
const std::shared_ptr<Session> 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<Response> sorted_responses;
for (const std::pair<std::shared_ptr<Session>, HttpMethod>& pair : sessions_) {
Session& current_session = *(pair.first);
auto it = std::find_if(responses.begin(), responses.end(), [&current_session](const Response& response) { return current_session.curl_->handle == response.curl_->handle; });
const Response current_response = *it;
// Erase response from original vector to increase future search speed
responses.erase(it);
sorted_responses.push_back(current_response);
}
return sorted_responses;
}
std::vector<Response> MultiPerform::MakeRequest() {
if (!interceptors_.empty()) {
return intercept();
}
DoMultiPerform();
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.Complete(curl_error); });
}
std::vector<Response> MultiPerform::MakeDownloadRequest() {
if (!interceptors_.empty()) {
return intercept();
}
DoMultiPerform();
return ReadMultiInfo([](Session& session, CURLcode curl_error) -> Response { return session.CompleteDownload(curl_error); });
}
void MultiPerform::PrepareSessions() {
for (const std::pair<std::shared_ptr<Session>, 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!" << std::endl;
return;
}
}
}
void MultiPerform::PrepareDownloadSession(size_t sessions_index, const WriteCallback& write) {
const std::pair<std::shared_ptr<Session>, 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!" << std::endl;
return;
}
}
void MultiPerform::PrepareDownloadSession(size_t sessions_index, std::ofstream& file) {
const std::pair<std::shared_ptr<Session>, 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!" << std::endl;
return;
}
}
void MultiPerform::SetHttpMethod(HttpMethod method) {
for (std::pair<std::shared_ptr<Session>, 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<Response> MultiPerform::Get() {
PrepareGet();
return MakeRequest();
}
std::vector<Response> MultiPerform::Delete() {
PrepareDelete();
return MakeRequest();
}
std::vector<Response> MultiPerform::Put() {
PreparePut();
return MakeRequest();
}
std::vector<Response> MultiPerform::Head() {
PrepareHead();
return MakeRequest();
}
std::vector<Response> MultiPerform::Options() {
PrepareOptions();
return MakeRequest();
}
std::vector<Response> MultiPerform::Patch() {
PreparePatch();
return MakeRequest();
}
std::vector<Response> MultiPerform::Post() {
PreparePost();
return MakeRequest();
}
std::vector<Response> MultiPerform::Perform() {
PrepareSessions();
return MakeRequest();
}
std::vector<Response> 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<std::shared_ptr<Session>, 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();
}
std::vector<Response> MultiPerform::intercept() {
// At least one interceptor exists -> Execute its intercept function
const std::shared_ptr<InterceptorMulti> interceptor = interceptors_.front();
interceptors_.pop();
return interceptor->intercept(*this);
}
void MultiPerform::AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor) {
interceptors_.push(pinterceptor);
}
} // namespace cpr

View file

@ -1,10 +0,0 @@
#include "cpr/parameters.h"
#include <initializer_list>
#include <string>
#include "cpr/util.h"
namespace cpr {
Parameters::Parameters(const std::initializer_list<Parameter>& parameters) : CurlContainer<Parameter>(parameters) {}
} // namespace cpr

View file

@ -1,10 +0,0 @@
#include "cpr/payload.h"
#include <initializer_list>
#include <string>
#include "cpr/util.h"
namespace cpr {
Payload::Payload(const std::initializer_list<Pair>& pairs) : CurlContainer<Pair>(pairs) {}
} // namespace cpr

View file

@ -1,21 +0,0 @@
#include "cpr/proxies.h"
#include <initializer_list>
#include <map>
#include <string>
#include <utility>
namespace cpr {
Proxies::Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts) : hosts_{hosts} {}
Proxies::Proxies(const std::map<std::string, std::string>& hosts) : hosts_{hosts} {}
bool Proxies::has(const std::string& protocol) const {
return hosts_.count(protocol) > 0;
}
const std::string& Proxies::operator[](const std::string& protocol) {
return hosts_[protocol];
}
} // namespace cpr

View file

@ -1,21 +0,0 @@
#include "cpr/proxyauth.h"
#include "cpr/util.h"
namespace cpr {
EncodedAuthentication::~EncodedAuthentication() noexcept {
util::secureStringClear(auth_string_);
}
const char* EncodedAuthentication::GetAuthString() const noexcept {
return auth_string_.c_str();
}
bool ProxyAuthentication::has(const std::string& protocol) const {
return proxyAuth_.count(protocol) > 0;
}
const char* ProxyAuthentication::operator[](const std::string& protocol) {
return proxyAuth_[protocol].GetAuthString();
}
} // namespace cpr

View file

@ -1,40 +0,0 @@
#include "cpr/redirect.h"
namespace cpr {
PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs) {
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
}
PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs) {
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
}
PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs) {
return static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs));
}
PostRedirectFlags operator~(PostRedirectFlags flag) {
return static_cast<PostRedirectFlags>(~static_cast<uint8_t>(flag));
}
PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
const uint8_t tmp = static_cast<uint8_t>(lhs);
lhs = static_cast<PostRedirectFlags>(tmp);
return lhs;
}
PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
return lhs;
}
PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs) {
lhs = static_cast<PostRedirectFlags>(static_cast<uint8_t>(lhs) ^ static_cast<uint8_t>(rhs));
return lhs;
}
bool any(PostRedirectFlags flag) {
return flag != PostRedirectFlags::NONE;
}
} // namespace cpr

View file

@ -1,44 +0,0 @@
#include "cpr/response.h"
namespace cpr {
Response::Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies = Cookies{}, Error&& p_error = Error{}) : curl_(std::move(curl)), text(std::move(p_text)), cookies(std::move(p_cookies)), error(std::move(p_error)), raw_header(std::move(p_header_string)) {
header = cpr::util::parseHeader(raw_header, &status_line, &reason);
assert(curl_);
assert(curl_->handle);
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code);
curl_easy_getinfo(curl_->handle, CURLINFO_TOTAL_TIME, &elapsed);
char* url_string{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_EFFECTIVE_URL, &url_string);
url = Url(url_string);
#if LIBCURL_VERSION_NUM >= 0x073700
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_bytes);
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes);
#else
double downloaded_bytes_double, uploaded_bytes_double;
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_DOWNLOAD, &downloaded_bytes_double);
curl_easy_getinfo(curl_->handle, CURLINFO_SIZE_UPLOAD, &uploaded_bytes_double);
downloaded_bytes = downloaded_bytes_double;
uploaded_bytes = uploaded_bytes_double;
#endif
curl_easy_getinfo(curl_->handle, CURLINFO_REDIRECT_COUNT, &redirect_count);
}
std::vector<CertInfo> Response::GetCertInfos() {
assert(curl_);
assert(curl_->handle);
curl_certinfo* ci{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_CERTINFO, &ci);
std::vector<CertInfo> cert_infos;
for (int i = 0; i < ci->num_of_certs; i++) {
CertInfo cert_info;
// NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic)
for (curl_slist* slist = ci->certinfo[i]; slist; slist = slist->next) {
cert_info.emplace_back(std::string{slist->data});
}
cert_infos.emplace_back(cert_info);
}
return cert_infos;
}
} // namespace cpr

View file

@ -1,975 +0,0 @@
#include "cpr/session.h"
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <curl/curl.h>
#include "cpr/async.h"
#include "cpr/cprtypes.h"
#include "cpr/interceptor.h"
#include "cpr/util.h"
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
#include "cpr/ssl_ctx.h"
#endif
namespace cpr {
// Ignored here since libcurl reqires a long:
// NOLINTNEXTLINE(google-runtime-int)
constexpr long ON = 1L;
// Ignored here since libcurl reqires a long:
// NOLINTNEXTLINE(google-runtime-int)
constexpr long OFF = 0L;
CURLcode Session::DoEasyPerform() {
if (isUsedInMultiPerform) {
std::cerr << "curl_easy_perform cannot be executed if the CURL handle is used in a MultiPerform." << std::endl;
return CURLcode::CURLE_FAILED_INIT;
}
return curl_easy_perform(curl_->handle);
}
void Session::SetHeaderInternal() {
curl_slist* chunk = nullptr;
for (const std::pair<const std::string, std::string>& item : header_) {
std::string header_string = item.first;
if (item.second.empty()) {
header_string += ";";
} else {
header_string += ": " + item.second;
}
curl_slist* temp = curl_slist_append(chunk, header_string.c_str());
if (temp) {
chunk = temp;
}
}
// Set the chunked transfer encoding in case it does not already exist:
if (chunkedTransferEncoding_ && header_.find("Transfer-Encoding") == header_.end()) {
curl_slist* temp = curl_slist_append(chunk, "Transfer-Encoding:chunked");
if (temp) {
chunk = temp;
}
}
// libcurl would prepare the header "Expect: 100-continue" by default when uploading files larger than 1 MB.
// Here we would like to disable this feature:
curl_slist* temp = curl_slist_append(chunk, "Expect:");
if (temp) {
chunk = temp;
}
curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk);
curl_slist_free_all(curl_->chunk);
curl_->chunk = chunk;
}
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
void Session::SetBearer(const Bearer& token) {
// Ignore here since this has been defined by libcurl.
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken());
}
#endif
Session::Session() : curl_(new CurlHolder()) {
// Set up some sensible defaults
curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW);
const std::string version = "curl/" + std::string{version_info->version};
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str());
SetRedirect(Redirect());
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data());
curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, "");
#ifdef CPR_CURL_NOSIGNAL
curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L);
#endif
#if LIBCURL_VERSION_NUM >= 0x071900
curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L);
#endif
}
Response Session::makeDownloadRequest() {
if (!interceptors_.empty()) {
return intercept();
}
const CURLcode curl_error = DoEasyPerform();
return CompleteDownload(curl_error);
}
void Session::prepareCommon() {
assert(curl_->handle);
// Set Header:
SetHeaderInternal();
const std::string parametersContent = parameters_.GetContent(*curl_);
if (!parametersContent.empty()) {
const Url new_url{url_ + "?" + parametersContent};
curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
} else {
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
}
// Proxy:
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
if (proxies_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
if (proxyAuth_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
}
}
#if LIBCURL_VERSION_NUM >= 0x072100
if (acceptEncoding_.empty()) {
// Enable all supported built-in compressions
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
} else if (acceptEncoding_.disabled()) {
// Disable curl adding the 'Accept-Encoding' header
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, nullptr);
} else {
curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str());
}
#endif
#if LIBCURL_VERSION_NUM >= 0x077100
#if SUPPORT_SSL_NO_REVOKE
// NOLINTNEXTLINE (google-runtime-int)
long bitmask{0};
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, &bitmask);
const bool noRevoke = bitmask & CURLSSLOPT_NO_REVOKE;
#endif
// Fix loading certs from Windows cert store when using OpenSSL:
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
// Ensure SSL no revoke is still set
#if SUPPORT_SSL_NO_REVOKE
if (noRevoke) {
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
}
#endif
#endif
curl_->error[0] = '\0';
response_string_.clear();
if (response_string_reserve_size_ > 0) {
response_string_.reserve(response_string_reserve_size_);
}
header_string_.clear();
if (!this->writecb_.callback) {
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction);
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string_);
}
if (!this->headercb_.callback) {
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
}
// Enable so we are able to retrive certificate information:
curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L);
}
void Session::prepareCommonDownload() {
assert(curl_->handle);
// Set Header:
SetHeaderInternal();
const std::string parametersContent = parameters_.GetContent(*curl_);
if (!parametersContent.empty()) {
const Url new_url{url_ + "?" + parametersContent};
curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
} else {
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
}
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
if (proxies_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
if (proxyAuth_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
}
}
curl_->error[0] = '\0';
header_string_.clear();
if (headercb_.callback) {
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
} else {
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
}
}
Response Session::makeRequest() {
if (!interceptors_.empty()) {
return intercept();
}
const CURLcode curl_error = DoEasyPerform();
return Complete(curl_error);
}
void Session::SetLimitRate(const LimitRate& limit_rate) {
curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate);
curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate);
}
void Session::SetReadCallback(const ReadCallback& read) {
readcb_ = read;
curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size);
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, read.size);
curl_easy_setopt(curl_->handle, CURLOPT_READFUNCTION, cpr::util::readUserFunction);
curl_easy_setopt(curl_->handle, CURLOPT_READDATA, &readcb_);
chunkedTransferEncoding_ = read.size == -1;
}
void Session::SetHeaderCallback(const HeaderCallback& header) {
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
headercb_ = header;
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
}
void Session::SetWriteCallback(const WriteCallback& write) {
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction);
writecb_ = write;
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &writecb_);
}
void Session::SetProgressCallback(const ProgressCallback& progress) {
progresscb_ = progress;
if (isCancellable) {
cancellationcb_.SetProgressCallback(progresscb_);
return;
}
#if LIBCURL_VERSION_NUM < 0x072000
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<ProgressCallback>);
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_);
#else
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<ProgressCallback>);
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_);
#endif
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
}
void Session::SetDebugCallback(const DebugCallback& debug) {
curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction);
debugcb_ = debug;
curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &debugcb_);
curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L);
}
void Session::SetUrl(const Url& url) {
url_ = url;
}
void Session::SetResolve(const Resolve& resolve) {
SetResolves({resolve});
}
void Session::SetResolves(const std::vector<Resolve>& resolves) {
curl_slist_free_all(curl_->resolveCurlList);
curl_->resolveCurlList = nullptr;
for (const Resolve& resolve : resolves) {
for (const uint16_t port : resolve.ports) {
curl_->resolveCurlList = curl_slist_append(curl_->resolveCurlList, (resolve.host + ":" + std::to_string(port) + ":" + resolve.addr).c_str());
}
}
curl_easy_setopt(curl_->handle, CURLOPT_RESOLVE, curl_->resolveCurlList);
}
void Session::SetParameters(const Parameters& parameters) {
parameters_ = parameters;
}
void Session::SetParameters(Parameters&& parameters) {
parameters_ = std::move(parameters);
}
void Session::SetHeader(const Header& header) {
header_ = header;
}
void Session::UpdateHeader(const Header& header) {
for (const std::pair<const std::string, std::string>& item : header) {
header_[item.first] = item.second;
}
}
void Session::SetTimeout(const Timeout& timeout) {
curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds());
}
void Session::SetConnectTimeout(const ConnectTimeout& timeout) {
curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds());
}
void Session::SetAuth(const Authentication& auth) {
// Ignore here since this has been defined by libcurl.
switch (auth.GetAuthMode()) {
case AuthMode::BASIC:
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
break;
case AuthMode::DIGEST:
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
break;
case AuthMode::NTLM:
curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
break;
}
}
void Session::SetUserAgent(const UserAgent& ua) {
curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str());
}
void Session::SetPayload(const Payload& payload) {
hasBodyOrPayload_ = true;
const std::string content = payload.GetContent(*curl_);
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
}
void Session::SetPayload(Payload&& payload) {
hasBodyOrPayload_ = true;
const std::string content = payload.GetContent(*curl_);
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
}
void Session::SetProxies(const Proxies& proxies) {
proxies_ = proxies;
}
void Session::SetProxies(Proxies&& proxies) {
proxies_ = std::move(proxies);
}
void Session::SetProxyAuth(ProxyAuthentication&& proxy_auth) {
proxyAuth_ = std::move(proxy_auth);
}
void Session::SetProxyAuth(const ProxyAuthentication& proxy_auth) {
proxyAuth_ = proxy_auth;
}
void Session::SetMultipart(const Multipart& multipart) {
// Make sure, we have a empty multipart to start with:
if (curl_->multipart) {
curl_mime_free(curl_->multipart);
}
curl_->multipart = curl_mime_init(curl_->handle);
// Add all multipart pieces:
for (const Part& part : multipart.parts) {
if (part.is_file) {
for (const File& file : part.files) {
curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart);
if (!part.content_type.empty()) {
curl_mime_type(mimePart, part.content_type.c_str());
}
curl_mime_filedata(mimePart, file.filepath.c_str());
curl_mime_name(mimePart, part.name.c_str());
if (file.hasOverridenFilename()) {
curl_mime_filename(mimePart, file.overriden_filename.c_str());
}
}
} else {
curl_mimepart* mimePart = curl_mime_addpart(curl_->multipart);
if (!part.content_type.empty()) {
curl_mime_type(mimePart, part.content_type.c_str());
}
if (part.is_buffer) {
// Do not use formdata, to prevent having to use reinterpreter_cast:
curl_mime_name(mimePart, part.name.c_str());
curl_mime_data(mimePart, part.data, part.datalen);
curl_mime_filename(mimePart, part.value.c_str());
} else {
curl_mime_name(mimePart, part.name.c_str());
curl_mime_data(mimePart, part.value.c_str(), CURL_ZERO_TERMINATED);
}
}
}
curl_easy_setopt(curl_->handle, CURLOPT_MIMEPOST, curl_->multipart);
hasBodyOrPayload_ = true;
}
void Session::SetMultipart(Multipart&& multipart) {
SetMultipart(multipart);
}
void Session::SetRedirect(const Redirect& redirect) {
curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, redirect.follow ? 1L : 0L);
curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, redirect.maximum);
curl_easy_setopt(curl_->handle, CURLOPT_UNRESTRICTED_AUTH, redirect.cont_send_cred ? 1L : 0L);
// NOLINTNEXTLINE (google-runtime-int)
long mask = 0;
if (any(redirect.post_flags & PostRedirectFlags::POST_301)) {
mask |= CURL_REDIR_POST_301;
}
if (any(redirect.post_flags & PostRedirectFlags::POST_302)) {
mask |= CURL_REDIR_POST_302;
}
if (any(redirect.post_flags & PostRedirectFlags::POST_303)) {
mask |= CURL_REDIR_POST_303;
}
curl_easy_setopt(curl_->handle, CURLOPT_POSTREDIR, mask);
}
void Session::SetCookies(const Cookies& cookies) {
curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL");
curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str());
}
void Session::SetBody(const Body& body) {
hasBodyOrPayload_ = true;
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.c_str());
}
void Session::SetBody(Body&& body) {
hasBodyOrPayload_ = true;
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str());
}
void Session::SetLowSpeed(const LowSpeed& low_speed) {
curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit);
curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, low_speed.time);
}
void Session::SetVerifySsl(const VerifySsl& verify) {
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF);
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L);
}
void Session::SetUnixSocket(const UnixSocket& unix_socket) {
curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString());
}
void Session::SetSslOptions(const SslOptions& options) {
if (!options.cert_file.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str());
if (!options.cert_type.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str());
}
}
if (!options.key_file.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str());
if (!options.key_type.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
}
if (!options.key_pass.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
}
#if SUPPORT_CURLOPT_SSLKEY_BLOB
} else if (!options.key_blob.empty()) {
std::string key_blob(options.key_blob);
curl_blob blob{};
// NOLINTNEXTLINE (readability-container-data-pointer)
blob.data = &key_blob[0];
blob.len = key_blob.length();
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY_BLOB, &blob);
if (!options.key_type.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
}
if (!options.key_pass.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
}
#endif
}
if (!options.pinned_public_key.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_PINNEDPUBLICKEY, options.pinned_public_key.c_str());
}
#if SUPPORT_ALPN
curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF);
#endif
#if SUPPORT_NPN
curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF);
#endif
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF);
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L);
#if LIBCURL_VERSION_NUM >= 0x072900
curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF);
#endif
int maxTlsVersion = options.ssl_version;
#if SUPPORT_MAX_TLS_VERSION
maxTlsVersion |= options.max_version;
#endif
curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION,
// Ignore here since this has been defined by libcurl.
maxTlsVersion);
#if SUPPORT_SSL_NO_REVOKE
if (options.ssl_no_revoke) {
curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
}
#endif
if (!options.ca_info.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str());
}
if (!options.ca_path.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str());
}
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
#ifdef OPENSSL_BACKEND_USED
if (!options.ca_buffer.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function_load_ca_cert_from_buffer);
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, options.ca_buffer.c_str());
}
#endif
#endif
if (!options.crl_file.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str());
}
if (!options.ciphers.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str());
}
#if SUPPORT_TLSv13_CIPHERS
if (!options.tls13_ciphers.empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.ciphers.c_str());
}
#endif
#if SUPPORT_SESSIONID_CACHE
curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, options.session_id_cache ? ON : OFF);
#endif
}
void Session::SetVerbose(const Verbose& verbose) {
curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF);
}
void Session::SetInterface(const Interface& iface) {
if (iface.str().empty()) {
curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, nullptr);
} else {
curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, iface.c_str());
}
}
void Session::SetLocalPort(const LocalPort& local_port) {
curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORT, local_port);
}
void Session::SetLocalPortRange(const LocalPortRange& local_port_range) {
curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORTRANGE, local_port_range);
}
void Session::SetHttpVersion(const HttpVersion& version) {
switch (version.code) {
case HttpVersionCode::VERSION_NONE:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
break;
case HttpVersionCode::VERSION_1_0:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
break;
case HttpVersionCode::VERSION_1_1:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
break;
#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0
case HttpVersionCode::VERSION_2_0:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
break;
#endif
#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0
case HttpVersionCode::VERSION_2_0_TLS:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
break;
#endif
#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0
case HttpVersionCode::VERSION_2_0_PRIOR_KNOWLEDGE:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
break;
#endif
#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0
case HttpVersionCode::VERSION_3_0:
curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
break;
#endif
default: // Should not happen
throw std::invalid_argument("Invalid/Unknown HTTP version type.");
break;
}
}
void Session::SetRange(const Range& range) {
const std::string range_str = range.str();
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str());
}
void Session::SetMultiRange(const MultiRange& multi_range) {
const std::string multi_range_str = multi_range.str();
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, multi_range_str.c_str());
}
void Session::SetReserveSize(const ReserveSize& reserve_size) {
ResponseStringReserve(reserve_size.size);
}
void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) {
acceptEncoding_ = accept_encoding;
}
void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) {
acceptEncoding_ = std::move(accept_encoding);
}
cpr_off_t Session::GetDownloadFileLength() {
cpr_off_t downloadFileLenth = -1;
curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
const std::string protocol = url_.str().substr(0, url_.str().find(':'));
if (proxies_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
if (proxyAuth_.has(protocol)) {
curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
}
}
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1);
if (DoEasyPerform() == CURLE_OK) {
// NOLINTNEXTLINE (google-runtime-int)
long status_code{};
curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code);
if (200 == status_code) {
curl_easy_getinfo(curl_->handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &downloadFileLenth);
}
}
return downloadFileLenth;
}
void Session::ResponseStringReserve(size_t size) {
response_string_reserve_size_ = size;
}
Response Session::Delete() {
PrepareDelete();
return makeRequest();
}
Response Session::Download(const WriteCallback& write) {
PrepareDownload(write);
return makeDownloadRequest();
}
Response Session::Download(std::ofstream& file) {
PrepareDownload(file);
return makeDownloadRequest();
}
Response Session::Get() {
PrepareGet();
return makeRequest();
}
Response Session::Head() {
PrepareHead();
return makeRequest();
}
Response Session::Options() {
PrepareOptions();
return makeRequest();
}
Response Session::Patch() {
PreparePatch();
return makeRequest();
}
Response Session::Post() {
PreparePost();
return makeRequest();
}
Response Session::Put() {
PreparePut();
return makeRequest();
}
std::shared_ptr<Session> Session::GetSharedPtrFromThis() {
try {
return shared_from_this();
} catch (std::bad_weak_ptr&) {
throw std::runtime_error("Failed to get a shared pointer from this. The reason is probably that the session object is not managed by a shared pointer, which is required to use this functionality.");
}
}
AsyncResponse Session::GetAsync() {
auto shared_this = shared_from_this();
return async([shared_this]() { return shared_this->Get(); });
}
AsyncResponse Session::DeleteAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Delete(); });
}
AsyncResponse Session::DownloadAsync(const WriteCallback& write) {
return async([shared_this = GetSharedPtrFromThis(), write]() { return shared_this->Download(write); });
}
AsyncResponse Session::DownloadAsync(std::ofstream& file) {
return async([shared_this = GetSharedPtrFromThis(), &file]() { return shared_this->Download(file); });
}
AsyncResponse Session::HeadAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Head(); });
}
AsyncResponse Session::OptionsAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Options(); });
}
AsyncResponse Session::PatchAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Patch(); });
}
AsyncResponse Session::PostAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Post(); });
}
AsyncResponse Session::PutAsync() {
return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Put(); });
}
std::shared_ptr<CurlHolder> Session::GetCurlHolder() {
return curl_;
}
std::string Session::GetFullRequestUrl() {
const std::string parametersContent = parameters_.GetContent(*curl_);
return url_.str() + (parametersContent.empty() ? "" : "?") + parametersContent;
}
void Session::PrepareDelete() {
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE");
prepareCommon();
}
void Session::PrepareGet() {
// In case there is a body or payload for this request, we create a custom GET-Request since a
// GET-Request with body is based on the HTTP RFC **not** a leagal request.
if (hasBodyOrPayload_) {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET");
} else {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L);
}
prepareCommon();
}
void Session::PrepareHead() {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
prepareCommon();
}
void Session::PrepareOptions() {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
prepareCommon();
}
void Session::PreparePatch() {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
prepareCommon();
}
void Session::PreparePost() {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
// In case there is no body or payload set it to an empty post:
if (hasBodyOrPayload_) {
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
} else {
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, readcb_.callback ? nullptr : "");
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST");
}
prepareCommon();
}
void Session::PreparePut() {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
if (!hasBodyOrPayload_ && readcb_.callback) {
/**
* Yes, this one has to be CURLOPT_POSTFIELDS even if we are performing a PUT request.
* In case we don't set this one, performing a POST-request with PUT won't work.
* It in theory this only enforces the usage of the readcallback for POST requests, but works here as well.
**/
curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr);
}
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl_->handle, CURLOPT_RANGE, nullptr);
prepareCommon();
}
void Session::PrepareDownload(std::ofstream& file) {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction);
curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
prepareCommonDownload();
}
void Session::PrepareDownload(const WriteCallback& write) {
curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
SetWriteCallback(write);
prepareCommonDownload();
}
Response Session::Complete(CURLcode curl_error) {
curl_slist* raw_cookies{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
Cookies cookies = util::parseCookies(raw_cookies);
curl_slist_free_all(raw_cookies);
// Reset the has no body property:
hasBodyOrPayload_ = false;
std::string errorMsg = curl_->error.data();
return Response(curl_, std::move(response_string_), std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
}
Response Session::CompleteDownload(CURLcode curl_error) {
if (!headercb_.callback) {
curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, nullptr);
curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, 0);
}
curl_slist* raw_cookies{nullptr};
curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
Cookies cookies = util::parseCookies(raw_cookies);
curl_slist_free_all(raw_cookies);
std::string errorMsg = curl_->error.data();
return Response(curl_, "", std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
}
void Session::AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor) {
interceptors_.push(pinterceptor);
}
Response Session::proceed() {
prepareCommon();
return makeRequest();
}
Response Session::intercept() {
// At least one interceptor exists -> Execute its intercept function
const std::shared_ptr<Interceptor> interceptor = interceptors_.front();
interceptors_.pop();
return interceptor->intercept(*this);
}
// clang-format off
void Session::SetOption(const Resolve& resolve) { SetResolve(resolve); }
void Session::SetOption(const std::vector<Resolve>& resolves) { SetResolves(resolves); }
void Session::SetOption(const ReadCallback& read) { SetReadCallback(read); }
void Session::SetOption(const HeaderCallback& header) { SetHeaderCallback(header); }
void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); }
void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); }
void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); }
void Session::SetOption(const Url& url) { SetUrl(url); }
void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); }
void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); }
void Session::SetOption(const Header& header) { SetHeader(header); }
void Session::SetOption(const Timeout& timeout) { SetTimeout(timeout); }
void Session::SetOption(const ConnectTimeout& timeout) { SetConnectTimeout(timeout); }
void Session::SetOption(const Authentication& auth) { SetAuth(auth); }
void Session::SetOption(const LimitRate& limit_rate) { SetLimitRate(limit_rate); }
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
void Session::SetOption(const Bearer& auth) { SetBearer(auth); }
#endif
void Session::SetOption(const UserAgent& ua) { SetUserAgent(ua); }
void Session::SetOption(const Payload& payload) { SetPayload(payload); }
void Session::SetOption(Payload&& payload) { SetPayload(std::move(payload)); }
void Session::SetOption(const Proxies& proxies) { SetProxies(proxies); }
void Session::SetOption(Proxies&& proxies) { SetProxies(std::move(proxies)); }
void Session::SetOption(ProxyAuthentication&& proxy_auth) { SetProxyAuth(std::move(proxy_auth)); }
void Session::SetOption(const ProxyAuthentication& proxy_auth) { SetProxyAuth(proxy_auth); }
void Session::SetOption(const Multipart& multipart) { SetMultipart(multipart); }
void Session::SetOption(Multipart&& multipart) { SetMultipart(std::move(multipart)); }
void Session::SetOption(const Redirect& redirect) { SetRedirect(redirect); }
void Session::SetOption(const Cookies& cookies) { SetCookies(cookies); }
void Session::SetOption(const Body& body) { SetBody(body); }
void Session::SetOption(Body&& body) { SetBody(std::move(body)); }
void Session::SetOption(const LowSpeed& low_speed) { SetLowSpeed(low_speed); }
void Session::SetOption(const VerifySsl& verify) { SetVerifySsl(verify); }
void Session::SetOption(const Verbose& verbose) { SetVerbose(verbose); }
void Session::SetOption(const UnixSocket& unix_socket) { SetUnixSocket(unix_socket); }
void Session::SetOption(const SslOptions& options) { SetSslOptions(options); }
void Session::SetOption(const Interface& iface) { SetInterface(iface); }
void Session::SetOption(const LocalPort& local_port) { SetLocalPort(local_port); }
void Session::SetOption(const LocalPortRange& local_port_range) { SetLocalPortRange(local_port_range); }
void Session::SetOption(const HttpVersion& version) { SetHttpVersion(version); }
void Session::SetOption(const Range& range) { SetRange(range); }
void Session::SetOption(const MultiRange& multi_range) { SetMultiRange(multi_range); }
void Session::SetOption(const ReserveSize& reserve_size) { SetReserveSize(reserve_size.size); }
void Session::SetOption(const AcceptEncoding& accept_encoding) { SetAcceptEncoding(accept_encoding); }
void Session::SetOption(AcceptEncoding&& accept_encoding) { SetAcceptEncoding(accept_encoding); }
// clang-format on
void Session::SetCancellationParam(std::shared_ptr<std::atomic_bool> param) {
cancellationcb_ = CancellationCallback{std::move(param)};
isCancellable = true;
#if LIBCURL_VERSION_NUM < 0x072000
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<CancellationCallback>);
curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &cancellationcb_);
#else
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<CancellationCallback>);
curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &cancellationcb_);
#endif
curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
}
} // namespace cpr

View file

@ -1,70 +0,0 @@
#include "cpr/ssl_ctx.h"
#if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
#ifdef OPENSSL_BACKEND_USED
#include <openssl/err.h>
#include <openssl/safestack.h>
#include <openssl/ssl.h>
namespace cpr {
/**
* The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL.
* If an error is returned from the callback no attempt to establish a connection is made and
* the perform operation will return the callback's error code.
*
* Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html
* https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html
*/
CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) {
// Check arguments
if (raw_cert_buf == nullptr || sslctx == nullptr) {
printf("Invalid callback arguments\n");
return CURLE_ABORTED_BY_CALLBACK;
}
// Setup pointer
X509_STORE* store = nullptr;
X509* cert = nullptr;
BIO* bio = nullptr;
char* cert_buf = static_cast<char*>(raw_cert_buf);
// Create a memory BIO using the data of cert_buf.
// Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen.
bio = BIO_new_mem_buf(cert_buf, -1);
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
PEM_read_bio_X509(bio, &cert, nullptr, nullptr);
if (cert == nullptr) {
printf("PEM_read_bio_X509 failed\n");
return CURLE_ABORTED_BY_CALLBACK;
}
// Get a pointer to the current certificate verification storage
store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
// Add the loaded certificate to the verification storage
const int status = X509_STORE_add_cert(store, cert);
if (status == 0) {
printf("Error adding certificate\n");
return CURLE_ABORTED_BY_CALLBACK;
}
// Decrement the reference count of the X509 structure cert and frees it up
X509_free(cert);
// Free the entire bio chain
BIO_free(bio);
// The CA certificate was loaded successfully into the verification storage
return CURLE_OK;
}
} // namespace cpr
#endif // OPENSSL_BACKEND_USED
#endif // SUPPORT_CURLOPT_SSL_CTX_FUNCTION

View file

@ -1,148 +0,0 @@
#include "cpr/threadpool.h"
namespace cpr {
ThreadPool::ThreadPool(size_t min_threads, size_t max_threads, std::chrono::milliseconds max_idle_ms) : min_thread_num(min_threads), max_thread_num(max_threads), max_idle_time(max_idle_ms), status(STOP), cur_thread_num(0), idle_thread_num(0) {}
ThreadPool::~ThreadPool() {
Stop();
}
int ThreadPool::Start(size_t start_threads) {
if (status != STOP) {
return -1;
}
status = RUNNING;
if (start_threads < min_thread_num) {
start_threads = min_thread_num;
}
if (start_threads > max_thread_num) {
start_threads = max_thread_num;
}
for (size_t i = 0; i < start_threads; ++i) {
CreateThread();
}
return 0;
}
int ThreadPool::Stop() {
if (status == STOP) {
return -1;
}
status = STOP;
task_cond.notify_all();
for (auto& i : threads) {
if (i.thread->joinable()) {
i.thread->join();
}
}
threads.clear();
cur_thread_num = 0;
idle_thread_num = 0;
return 0;
}
int ThreadPool::Pause() {
if (status == RUNNING) {
status = PAUSE;
}
return 0;
}
int ThreadPool::Resume() {
if (status == PAUSE) {
status = RUNNING;
}
return 0;
}
int ThreadPool::Wait() {
while (true) {
if (status == STOP || (tasks.empty() && idle_thread_num == cur_thread_num)) {
break;
}
std::this_thread::yield();
}
return 0;
}
bool ThreadPool::CreateThread() {
if (cur_thread_num >= max_thread_num) {
return false;
}
std::thread* thread = new std::thread([this] {
bool initialRun = true;
while (status != STOP) {
while (status == PAUSE) {
std::this_thread::yield();
}
Task task;
{
std::unique_lock<std::mutex> locker(task_mutex);
task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() { return status == STOP || !tasks.empty(); });
if (status == STOP) {
return;
}
if (tasks.empty()) {
if (cur_thread_num > min_thread_num) {
DelThread(std::this_thread::get_id());
return;
}
continue;
}
if (!initialRun) {
--idle_thread_num;
}
task = std::move(tasks.front());
tasks.pop();
}
if (task) {
task();
++idle_thread_num;
if (initialRun) {
initialRun = false;
}
}
}
});
AddThread(thread);
return true;
}
void ThreadPool::AddThread(std::thread* thread) {
thread_mutex.lock();
++cur_thread_num;
ThreadData data;
data.thread = std::shared_ptr<std::thread>(thread);
data.id = thread->get_id();
data.status = RUNNING;
data.start_time = time(nullptr);
data.stop_time = 0;
threads.emplace_back(data);
thread_mutex.unlock();
}
void ThreadPool::DelThread(std::thread::id id) {
const time_t now = time(nullptr);
thread_mutex.lock();
--cur_thread_num;
--idle_thread_num;
auto iter = threads.begin();
while (iter != threads.end()) {
if (iter->status == STOP && now > iter->stop_time) {
if (iter->thread->joinable()) {
iter->thread->join();
iter = threads.erase(iter);
continue;
}
} else if (iter->id == id) {
iter->status = STOP;
iter->stop_time = time(nullptr);
}
++iter;
}
thread_mutex.unlock();
}
} // namespace cpr

View file

@ -1,31 +0,0 @@
#include "cpr/timeout.h"
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
namespace cpr {
// No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int)
long Timeout::Milliseconds() const {
static_assert(std::is_same<std::chrono::milliseconds, decltype(ms)>::value, "Following casting expects milliseconds.");
// No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int)
if (ms.count() > static_cast<std::chrono::milliseconds::rep>(std::numeric_limits<long>::max())) {
throw std::overflow_error("cpr::Timeout: timeout value overflow: " + std::to_string(ms.count()) + " ms.");
}
// No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int)
if (ms.count() < static_cast<std::chrono::milliseconds::rep>(std::numeric_limits<long>::min())) {
throw std::underflow_error("cpr::Timeout: timeout value underflow: " + std::to_string(ms.count()) + " ms.");
}
// No way around since curl uses a long here.
// NOLINTNEXTLINE(google-runtime-int)
return static_cast<long>(ms.count());
}
} // namespace cpr

View file

@ -1,8 +0,0 @@
#include "cpr/unix_socket.h"
namespace cpr {
const char* UnixSocket::GetUnixSocketString() const noexcept {
return unix_socket_.data();
}
} // namespace cpr

View file

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

View file

@ -1,68 +0,0 @@
cmake_minimum_required(VERSION 3.15)
target_include_directories(cpr PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/cpr_generated_includes/>)
target_sources(cpr PRIVATE
# Header files (useful in IDEs)
cpr/accept_encoding.h
cpr/api.h
cpr/async.h
cpr/async_wrapper.h
cpr/auth.h
cpr/bearer.h
cpr/body.h
cpr/buffer.h
cpr/cert_info.h
cpr/cookies.h
cpr/cpr.h
cpr/cprtypes.h
cpr/curlholder.h
cpr/curlholder.h
cpr/error.h
cpr/file.h
cpr/limit_rate.h
cpr/local_port.h
cpr/local_port_range.h
cpr/multipart.h
cpr/parameters.h
cpr/payload.h
cpr/proxies.h
cpr/proxyauth.h
cpr/response.h
cpr/session.h
cpr/singleton.h
cpr/ssl_ctx.h
cpr/ssl_options.h
cpr/threadpool.h
cpr/timeout.h
cpr/unix_socket.h
cpr/util.h
cpr/verbose.h
cpr/interface.h
cpr/redirect.h
cpr/http_version.h
cpr/interceptor.h
cpr/filesystem.h
cpr/curlmultiholder.h
cpr/multiperform.h
cpr/resolve.h
${PROJECT_BINARY_DIR}/cpr_generated_includes/cpr/cprver.h
)
# Filesystem
if(CPR_USE_BOOST_FILESYSTEM)
find_package(Boost 1.44 REQUIRED COMPONENTS filesystem)
if(Boost_FOUND)
target_link_libraries(cpr PUBLIC Boost::filesystem)
endif()
endif()
if (((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1) OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT WIN32)) AND NOT CPR_USE_BOOST_FILESYSTEM)
target_link_libraries(cpr PUBLIC stdc++fs)
endif()
install(DIRECTORY cpr DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(DIRECTORY ${PROJECT_BINARY_DIR}/cpr_generated_includes/cpr DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

View file

@ -1,41 +0,0 @@
#ifndef CPR_ACCEPT_ENCODING_H
#define CPR_ACCEPT_ENCODING_H
#include <curl/curlver.h>
#include <initializer_list>
#include <map>
#include <string>
#include <unordered_set>
namespace cpr {
enum class AcceptEncodingMethods {
identity,
deflate,
zlib,
gzip,
disabled,
};
// 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"}};
class AcceptEncoding {
public:
AcceptEncoding() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
AcceptEncoding(const std::initializer_list<AcceptEncodingMethods>& methods);
// NOLINTNEXTLINE(google-explicit-constructor)
AcceptEncoding(const std::initializer_list<std::string>& methods);
[[nodiscard]] bool empty() const noexcept;
[[nodiscard]] const std::string getString() const;
[[nodiscard]] bool disabled() const;
private:
std::unordered_set<std::string> methods_;
};
} // namespace cpr
#endif

View file

@ -1,392 +0,0 @@
#ifndef CPR_API_H
#define CPR_API_H
#include <fstream>
#include <functional>
#include <future>
#include <string>
#include <utility>
#include "cpr/async.h"
#include "cpr/async_wrapper.h"
#include "cpr/auth.h"
#include "cpr/bearer.h"
#include "cpr/cprtypes.h"
#include "cpr/multipart.h"
#include "cpr/multiperform.h"
#include "cpr/payload.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include <cpr/filesystem.h>
namespace cpr {
using AsyncResponse = AsyncWrapper<Response>;
namespace priv {
template <bool processed_header, typename CurrentType>
void set_option_internal(Session& session, CurrentType&& current_option) {
session.SetOption(std::forward<CurrentType>(current_option));
}
template <>
inline void set_option_internal<true, Header>(Session& session, Header&& current_option) {
// Header option was already provided -> Update previous header
session.UpdateHeader(std::forward<Header>(current_option));
}
template <bool processed_header, typename CurrentType, typename... Ts>
void set_option_internal(Session& session, CurrentType&& current_option, Ts&&... ts) {
set_option_internal<processed_header, CurrentType>(session, std::forward<CurrentType>(current_option));
if (std::is_same<CurrentType, Header>::value) {
set_option_internal<true, Ts...>(session, std::forward<Ts>(ts)...);
} else {
set_option_internal<processed_header, Ts...>(session, std::forward<Ts>(ts)...);
}
}
template <typename... Ts>
void set_option(Session& session, Ts&&... ts) {
set_option_internal<false, Ts...>(session, std::forward<Ts>(ts)...);
}
// Idea: https://stackoverflow.com/a/19060157
template <typename Tuple, std::size_t... I>
void apply_set_option_internal(Session& session, Tuple&& t, std::index_sequence<I...>) {
set_option(session, std::get<I>(std::forward<Tuple>(t))...);
}
// Idea: https://stackoverflow.com/a/19060157
template <typename Tuple>
void apply_set_option(Session& session, Tuple&& t) {
using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
apply_set_option_internal(session, std::forward<Tuple>(t), Indices());
}
template <typename T>
void setup_multiperform_internal(MultiPerform& multiperform, T&& t) {
std::shared_ptr<Session> session = std::make_shared<Session>();
apply_set_option(*session, t);
multiperform.AddSession(session);
}
template <typename T, typename... Ts>
void setup_multiperform_internal(MultiPerform& multiperform, T&& t, Ts&&... ts) {
std::shared_ptr<Session> session = std::make_shared<Session>();
apply_set_option(*session, t);
multiperform.AddSession(session);
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
}
template <typename... Ts>
void setup_multiperform(MultiPerform& multiperform, Ts&&... ts) {
setup_multiperform_internal<Ts...>(multiperform, std::forward<Ts>(ts)...);
}
using session_action_t = cpr::Response (cpr::Session::*)();
template <session_action_t SessionAction, typename T>
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& parameters) {
std::shared_ptr<std::atomic_bool> cancellation_state = std::make_shared<std::atomic_bool>(false);
std::function<Response(T)> execFn{[cancellation_state](T params) {
if (cancellation_state->load()) {
return Response{};
}
cpr::Session s{};
s.SetCancellationParam(cancellation_state);
apply_set_option(s, std::forward<T>(params));
return std::invoke(SessionAction, s);
}};
responses.emplace_back(GlobalThreadPool::GetInstance()->Submit(std::move(execFn), std::forward<T>(parameters)), std::move(cancellation_state));
}
template <session_action_t SessionAction, typename T, typename... Ts>
void setup_multiasync(std::vector<AsyncWrapper<Response, true>>& responses, T&& head, Ts&&... tail) {
setup_multiasync<SessionAction>(responses, std::forward<T>(head));
if constexpr (sizeof...(Ts) > 0) {
setup_multiasync<SessionAction>(responses, std::forward<Ts>(tail)...);
}
}
} // namespace priv
// Get methods
template <typename... Ts>
Response Get(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Get();
}
// Get async methods
template <typename... Ts>
AsyncResponse GetAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...);
}
// Get callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto GetCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Post methods
template <typename... Ts>
Response Post(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Post();
}
// Post async methods
template <typename... Ts>
AsyncResponse PostAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...);
}
// Post callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto PostCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Put methods
template <typename... Ts>
Response Put(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Put();
}
// Put async methods
template <typename... Ts>
AsyncResponse PutAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...);
}
// Put callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto PutCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Head methods
template <typename... Ts>
Response Head(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Head();
}
// Head async methods
template <typename... Ts>
AsyncResponse HeadAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...);
}
// Head callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto HeadCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Delete methods
template <typename... Ts>
Response Delete(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Delete();
}
// Delete async methods
template <typename... Ts>
AsyncResponse DeleteAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...);
}
// Delete callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto DeleteCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Options methods
template <typename... Ts>
Response Options(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Options();
}
// Options async methods
template <typename... Ts>
AsyncResponse OptionsAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...);
}
// Options callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto OptionsCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Patch methods
template <typename... Ts>
Response Patch(Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Patch();
}
// Patch async methods
template <typename... Ts>
AsyncResponse PatchAsync(Ts... ts) {
return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...);
}
// Patch callback methods
template <typename Then, typename... Ts>
// NOLINTNEXTLINE(fuchsia-trailing-return)
auto PatchCallback(Then then, Ts... ts) {
return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...);
}
// Download methods
template <typename... Ts>
Response Download(std::ofstream& file, Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Download(file);
}
// Download async method
template <typename... Ts>
AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) {
return AsyncWrapper{std::async(
std::launch::async,
[](fs::path local_path_, Ts... ts_) {
std::ofstream f(local_path_.c_str());
return Download(f, std::move(ts_)...);
},
std::move(local_path), std::move(ts)...)};
}
// Download with user callback
template <typename... Ts>
Response Download(const WriteCallback& write, Ts&&... ts) {
Session session;
priv::set_option(session, std::forward<Ts>(ts)...);
return session.Download(write);
}
// Multi requests
template <typename... Ts>
std::vector<Response> MultiGet(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Get();
}
template <typename... Ts>
std::vector<Response> MultiDelete(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Delete();
}
template <typename... Ts>
std::vector<Response> MultiPut(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Put();
}
template <typename... Ts>
std::vector<Response> MultiHead(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Head();
}
template <typename... Ts>
std::vector<Response> MultiOptions(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Options();
}
template <typename... Ts>
std::vector<Response> MultiPatch(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Patch();
}
template <typename... Ts>
std::vector<Response> MultiPost(Ts&&... ts) {
MultiPerform multiperform;
priv::setup_multiperform<Ts...>(multiperform, std::forward<Ts>(ts)...);
return multiperform.Post();
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiGetAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiDeleteAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiHeadAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiOptionsAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiPatchAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiPostAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward<Ts>(ts)...);
return ret;
}
template <typename... Ts>
std::vector<AsyncWrapper<Response, true>> MultiPutAsync(Ts&&... ts) {
std::vector<AsyncWrapper<Response, true>> ret{};
priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward<Ts>(ts)...);
return ret;
}
} // namespace cpr
#endif

View file

@ -1,50 +0,0 @@
#ifndef CPR_ASYNC_H
#define CPR_ASYNC_H
#include "async_wrapper.h"
#include "singleton.h"
#include "threadpool.h"
namespace cpr {
class GlobalThreadPool : public ThreadPool {
CPR_SINGLETON_DECL(GlobalThreadPool)
protected:
GlobalThreadPool() = default;
public:
~GlobalThreadPool() override = default;
};
/**
* Return a wrapper for a future, calling future.get() will wait until the task is done and return RetType.
* async(fn, args...)
* async(std::bind(&Class::mem_fn, &obj))
* async(std::mem_fn(&Class::mem_fn, &obj))
**/
template <class Fn, class... Args>
auto async(Fn&& fn, Args&&... args) {
return AsyncWrapper{GlobalThreadPool::GetInstance()->Submit(std::forward<Fn>(fn), std::forward<Args>(args)...)};
}
class async {
public:
static void startup(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME) {
GlobalThreadPool* gtp = GlobalThreadPool::GetInstance();
if (gtp->IsStarted()) {
return;
}
gtp->SetMinThreadNum(min_threads);
gtp->SetMaxThreadNum(max_threads);
gtp->SetMaxIdleTime(max_idle_ms);
gtp->Start();
}
static void cleanup() {
GlobalThreadPool::ExitInstance();
}
};
} // namespace cpr
#endif

View file

@ -1,140 +0,0 @@
#ifndef CPR_ASYNC_WRAPPER_H
#define CPR_ASYNC_WRAPPER_H
#include <atomic>
#include <future>
#include <memory>
#include "cpr/response.h"
namespace cpr {
enum class [[nodiscard]] CancellationResult { failure, success, invalid_operation };
/**
* A class template intended to wrap results of async operations (instances of std::future<T>)
* and also provide extended capablilities relaed to these requests, for example cancellation.
*
* The RAII semantics are the same as std::future<T> - moveable, not copyable.
*/
template <typename T, bool isCancellable = false>
class AsyncWrapper {
private:
std::future<T> future;
std::shared_ptr<std::atomic_bool> is_cancelled;
public:
// Constructors
explicit AsyncWrapper(std::future<T>&& f) : future{std::move(f)} {}
AsyncWrapper(std::future<T>&& f, std::shared_ptr<std::atomic_bool>&& cancelledState) : future{std::move(f)}, is_cancelled{std::move(cancelledState)} {}
// Copy Semantics
AsyncWrapper(const AsyncWrapper&) = delete;
AsyncWrapper& operator=(const AsyncWrapper&) = delete;
// Move Semantics
AsyncWrapper(AsyncWrapper&&) noexcept = default;
AsyncWrapper& operator=(AsyncWrapper&&) noexcept = default;
// Destructor
~AsyncWrapper() {
if constexpr (isCancellable) {
if(is_cancelled) {
is_cancelled->store(true);
}
}
}
// These methods replicate the behaviour of std::future<T>
[[nodiscard]] T get() {
if constexpr (isCancellable) {
if (IsCancelled()) {
throw std::logic_error{"Calling AsyncWrapper::get on a cancelled request!"};
}
}
if (!future.valid()) {
throw std::logic_error{"Calling AsyncWrapper::get when the associated future instance is invalid!"};
}
return future.get();
}
[[nodiscard]] bool valid() const noexcept {
if constexpr (isCancellable) {
return !is_cancelled->load() && future.valid();
} else {
return future.valid();
}
}
void wait() const {
if constexpr (isCancellable) {
if (is_cancelled->load()) {
throw std::logic_error{"Calling AsyncWrapper::wait when the associated future is invalid or cancelled!"};
}
}
if (!future.valid()) {
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
}
future.wait();
}
template <class Rep, class Period>
std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
if constexpr (isCancellable) {
if (IsCancelled()) {
throw std::logic_error{"Calling AsyncWrapper::wait_for when the associated future is cancelled!"};
}
}
if (!future.valid()) {
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
}
return future.wait_for(timeout_duration);
}
template <class Clock, class Duration>
std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
if constexpr (isCancellable) {
if (IsCancelled()) {
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is cancelled!"};
}
}
if (!future.valid()) {
throw std::logic_error{"Calling AsyncWrapper::wait_until when the associated future is invalid!"};
}
return future.wait_until(timeout_time);
}
std::shared_future<T> share() noexcept {
return future.share();
}
// Cancellation-related methods
CancellationResult Cancel() {
if constexpr (!isCancellable) {
return CancellationResult::invalid_operation;
}
if (!future.valid() || is_cancelled->load()) {
return CancellationResult::invalid_operation;
}
is_cancelled->store(true);
return CancellationResult::success;
}
[[nodiscard]] bool IsCancelled() const {
if constexpr (isCancellable) {
return is_cancelled->load();
} else {
return false;
}
}
};
// Deduction guides
template <typename T>
AsyncWrapper(std::future<T>&&) -> AsyncWrapper<T, false>;
template <typename T>
AsyncWrapper(std::future<T>&&, std::shared_ptr<std::atomic_bool>&&) -> AsyncWrapper<T, true>;
} // namespace cpr
#endif

View file

@ -1,32 +0,0 @@
#ifndef CPR_AUTH_H
#define CPR_AUTH_H
#include <string>
#include <utility>
namespace cpr {
enum class AuthMode { BASIC, DIGEST, NTLM };
class Authentication {
public:
Authentication(std::string username, std::string password, AuthMode auth_mode) : auth_string_{std::move(username) + ":" + std::move(password)}, auth_mode_{std::move(auth_mode)} {}
Authentication(const Authentication& other) = default;
Authentication(Authentication&& old) noexcept = default;
~Authentication() noexcept;
Authentication& operator=(Authentication&& old) noexcept = default;
Authentication& operator=(const Authentication& other) = default;
const char* GetAuthString() const noexcept;
AuthMode GetAuthMode() const noexcept;
private:
std::string auth_string_;
AuthMode auth_mode_;
};
} // namespace cpr
#endif

View file

@ -1,34 +0,0 @@
#ifndef CPR_BEARER_H
#define CPR_BEARER_H
#include <curl/curlver.h>
#include <string>
#include <utility>
namespace cpr {
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
class Bearer {
public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Bearer(std::string token) : token_string_{std::move(token)} {}
Bearer(const Bearer& other) = default;
Bearer(Bearer&& old) noexcept = default;
virtual ~Bearer() noexcept;
Bearer& operator=(Bearer&& old) noexcept = default;
Bearer& operator=(const Bearer& other) = default;
virtual const char* GetToken() const noexcept;
protected:
std::string token_string_;
};
#endif
} // namespace cpr
#endif

View file

@ -1,54 +0,0 @@
#ifndef CPR_BODY_H
#define CPR_BODY_H
#include <exception>
#include <fstream>
#include <initializer_list>
#include <string>
#include <vector>
#include "cpr/buffer.h"
#include "cpr/cprtypes.h"
#include "cpr/file.h"
namespace cpr {
class Body : public StringHolder<Body> {
public:
Body() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Body(std::string body) : StringHolder<Body>(std::move(body)) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Body(std::string_view body) : StringHolder<Body>(body) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Body(const char* body) : StringHolder<Body>(body) {}
Body(const char* str, size_t len) : StringHolder<Body>(str, len) {}
Body(const std::initializer_list<std::string> args) : StringHolder<Body>(args) {}
// NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-reinterpret-cast)
Body(const Buffer& buffer) : StringHolder<Body>(reinterpret_cast<const char*>(buffer.data), static_cast<size_t>(buffer.datalen)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
Body(const File& file) {
std::ifstream is(file.filepath, std::ifstream::binary);
if (!is) {
throw std::invalid_argument("Can't open the file for HTTP request body!");
}
is.seekg(0, std::ios::end);
const std::streampos length = is.tellg();
is.seekg(0, std::ios::beg);
std::string buffer;
buffer.resize(static_cast<size_t>(length));
is.read(buffer.data(), length);
str_ = std::move(buffer);
}
Body(const Body& other) = default;
Body(Body&& old) noexcept = default;
~Body() override = default;
Body& operator=(Body&& old) noexcept = default;
Body& operator=(const Body& other) = default;
};
} // namespace cpr
#endif

View file

@ -1,33 +0,0 @@
#ifndef CPR_BUFFER_H
#define CPR_BUFFER_H
#include <string>
#include <cpr/filesystem.h>
namespace cpr {
struct Buffer {
using data_t = const char*;
template <typename Iterator>
Buffer(Iterator begin, Iterator end, fs::path&& p_filename)
// Ignored here since libcurl reqires a long.
// There is also no way around the reinterpret_cast.
// NOLINTNEXTLINE(google-runtime-int, cppcoreguidelines-pro-type-reinterpret-cast)
: data{reinterpret_cast<data_t>(&(*begin))}, datalen{static_cast<size_t>(std::distance(begin, end))}, filename(std::move(p_filename)) {
is_random_access_iterator(begin, end);
static_assert(sizeof(*begin) == 1, "Only byte buffers can be used");
}
template <typename Iterator>
typename std::enable_if<std::is_same<typename std::iterator_traits<Iterator>::iterator_category, std::random_access_iterator_tag>::value>::type is_random_access_iterator(Iterator /* begin */, Iterator /* end */) {}
data_t data;
size_t datalen;
const fs::path filename;
};
} // namespace cpr
#endif

View file

@ -1,111 +0,0 @@
#ifndef CPR_CALLBACK_H
#define CPR_CALLBACK_H
#include "cprtypes.h"
#include <atomic>
#include <functional>
#include <optional>
#include <utility>
namespace cpr {
class ReadCallback {
public:
ReadCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
ReadCallback(std::function<bool(char* buffer, size_t& size, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{-1}, callback{std::move(p_callback)} {}
ReadCallback(cpr_off_t p_size, std::function<bool(char* buffer, size_t& size, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{p_size}, callback{std::move(p_callback)} {}
bool operator()(char* buffer, size_t& buffer_size) const {
return callback(buffer, buffer_size, userdata);
}
intptr_t userdata{};
cpr_off_t size{};
std::function<bool(char* buffer, size_t& size, intptr_t userdata)> callback;
};
class HeaderCallback {
public:
HeaderCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
HeaderCallback(std::function<bool(std::string header, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
bool operator()(std::string header) const {
return callback(std::move(header), userdata);
}
intptr_t userdata{};
std::function<bool(std::string header, intptr_t userdata)> callback;
};
class WriteCallback {
public:
WriteCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
WriteCallback(std::function<bool(std::string data, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
bool operator()(std::string data) const {
return callback(std::move(data), userdata);
}
intptr_t userdata{};
std::function<bool(std::string data, intptr_t userdata)> callback;
};
class ProgressCallback {
public:
ProgressCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
ProgressCallback(std::function<bool(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
bool operator()(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow) const {
return callback(downloadTotal, downloadNow, uploadTotal, uploadNow, userdata);
}
intptr_t userdata{};
std::function<bool(cpr_pf_arg_t downloadTotal, cpr_pf_arg_t downloadNow, cpr_pf_arg_t uploadTotal, cpr_pf_arg_t uploadNow, intptr_t userdata)> callback;
};
class DebugCallback {
public:
enum class InfoType {
TEXT = 0,
HEADER_IN = 1,
HEADER_OUT = 2,
DATA_IN = 3,
DATA_OUT = 4,
SSL_DATA_IN = 5,
SSL_DATA_OUT = 6,
};
DebugCallback() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
DebugCallback(std::function<void(InfoType type, std::string data, intptr_t userdata)> p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {}
void operator()(InfoType type, std::string data) const {
callback(type, std::move(data), userdata);
}
intptr_t userdata{};
std::function<void(InfoType type, std::string data, intptr_t userdata)> callback;
};
/**
* Functor class for progress functions that will be used in cancellable requests.
*/
class CancellationCallback {
public:
CancellationCallback() = default;
explicit CancellationCallback(std::shared_ptr<std::atomic_bool>&& cs) : cancellation_state{std::move(cs)} {}
CancellationCallback(std::shared_ptr<std::atomic_bool>&& cs, ProgressCallback& u_cb) : cancellation_state{std::move(cs)}, user_cb{std::reference_wrapper{u_cb}} {}
bool operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) const;
void SetProgressCallback(ProgressCallback& u_cb);
private:
std::shared_ptr<std::atomic_bool> cancellation_state;
std::optional<std::reference_wrapper<ProgressCallback>> user_cb;
};
} // namespace cpr
#endif

View file

@ -1,35 +0,0 @@
#ifndef CPR_CERT_INFO_H
#define CPR_CERT_INFO_H
#include <initializer_list>
#include <string>
#include <vector>
namespace cpr {
class CertInfo {
private:
std::vector<std::string> cert_info_;
public:
CertInfo() = default;
CertInfo(const std::initializer_list<std::string>& entry) : cert_info_{entry} {};
~CertInfo() noexcept = default;
using iterator = std::vector<std::string>::iterator;
using const_iterator = std::vector<std::string>::const_iterator;
std::string& operator[](const size_t& pos);
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
void emplace_back(const std::string& str);
void push_back(const std::string& str);
void pop_back();
};
} // namespace cpr
#endif

View file

@ -1,18 +0,0 @@
#ifndef CPR_CONNECT_TIMEOUT_H
#define CPR_CONNECT_TIMEOUT_H
#include "cpr/timeout.h"
namespace cpr {
class ConnectTimeout : public Timeout {
public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
ConnectTimeout(const std::chrono::milliseconds& duration) : Timeout{duration} {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
ConnectTimeout(const std::int32_t& milliseconds) : Timeout{milliseconds} {}
};
} // namespace cpr
#endif

View file

@ -1,92 +0,0 @@
#ifndef CPR_COOKIES_H
#define CPR_COOKIES_H
#include "cpr/curlholder.h"
#include <chrono>
#include <initializer_list>
#include <sstream>
#include <string>
#include <vector>
namespace cpr {
/**
* EXPIRES_STRING_SIZE is an explicitly static and const variable that could be only accessed within the same namespace and is immutable.
* To be used for "std::array", the expression must have a constant value, so EXPIRES_STRING_SIZE must be a const value.
**/
static const std::size_t EXPIRES_STRING_SIZE = 100;
class Cookie {
public:
Cookie() = default;
/**
* Some notes for the default value used by expires:
* std::chrono::system_clock::time_point::min() won't work on Windows due to the min, max clash there.
* So we fall back to std::chrono::system_clock::from_time_t(0) for the minimum value here.
**/
Cookie(const std::string& name, const std::string& value, const std::string& domain = "", bool p_isIncludingSubdomains = false, const std::string& path = "/", bool p_isHttpsOnly = false, std::chrono::system_clock::time_point expires = std::chrono::system_clock::from_time_t(0)) : name_{name}, value_{value}, domain_{domain}, includeSubdomains_{p_isIncludingSubdomains}, path_{path}, httpsOnly_{p_isHttpsOnly}, expires_{expires} {};
const std::string GetDomain() const;
bool IsIncludingSubdomains() const;
const std::string GetPath() const;
bool IsHttpsOnly() const;
const std::chrono::system_clock::time_point GetExpires() const;
const std::string GetExpiresString() const;
const std::string GetName() const;
const std::string GetValue() const;
private:
std::string name_;
std::string value_;
std::string domain_;
bool includeSubdomains_{};
std::string path_;
bool httpsOnly_{};
/**
* TODO: Update the implementation using `std::chrono::utc_clock` of C++20
**/
std::chrono::system_clock::time_point expires_{};
};
class Cookies {
public:
/**
* Should we URL-encode cookies when making a request.
* Based on RFC6265, it is recommended but not mandatory to encode cookies.
*
* -------
* To maximize compatibility with user agents, servers that wish to
* store arbitrary data in a cookie-value SHOULD encode that data, for
* example, using Base64 [RFC4648].
* -------
* Source: RFC6265 (https://www.ietf.org/rfc/rfc6265.txt)
**/
bool encode{true};
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Cookies(bool p_encode = true) : encode{p_encode} {};
Cookies(const std::initializer_list<cpr::Cookie>& cookies, bool p_encode = true) : encode{p_encode}, cookies_{cookies} {};
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Cookies(const cpr::Cookie& cookie, bool p_encode = true) : encode{p_encode}, cookies_{cookie} {};
cpr::Cookie& operator[](size_t pos);
const std::string GetEncoded(const CurlHolder& holder) const;
using iterator = std::vector<cpr::Cookie>::iterator;
using const_iterator = std::vector<cpr::Cookie>::const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
void emplace_back(const Cookie& str);
void push_back(const Cookie& str);
void pop_back();
private:
std::vector<cpr::Cookie> cookies_;
};
} // namespace cpr
#endif

View file

@ -1,46 +0,0 @@
#ifndef CPR_CPR_H
#define CPR_CPR_H
#include "cpr/api.h"
#include "cpr/auth.h"
#include "cpr/bearer.h"
#include "cpr/callback.h"
#include "cpr/cert_info.h"
#include "cpr/connect_timeout.h"
#include "cpr/cookies.h"
#include "cpr/cprtypes.h"
#include "cpr/cprver.h"
#include "cpr/curl_container.h"
#include "cpr/curlholder.h"
#include "cpr/error.h"
#include "cpr/http_version.h"
#include "cpr/interceptor.h"
#include "cpr/interface.h"
#include "cpr/limit_rate.h"
#include "cpr/local_port.h"
#include "cpr/local_port_range.h"
#include "cpr/low_speed.h"
#include "cpr/multipart.h"
#include "cpr/multiperform.h"
#include "cpr/parameters.h"
#include "cpr/payload.h"
#include "cpr/proxies.h"
#include "cpr/proxyauth.h"
#include "cpr/range.h"
#include "cpr/redirect.h"
#include "cpr/reserve_size.h"
#include "cpr/resolve.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include "cpr/ssl_ctx.h"
#include "cpr/ssl_options.h"
#include "cpr/status_codes.h"
#include "cpr/timeout.h"
#include "cpr/unix_socket.h"
#include "cpr/user_agent.h"
#include "cpr/util.h"
#include "cpr/verbose.h"
#define CPR_LIBCURL_VERSION_NUM LIBCURL_VERSION_NUM
#endif

View file

@ -1,144 +0,0 @@
#ifndef CPR_CPR_TYPES_H
#define CPR_CPR_TYPES_H
#include <curl/curl.h>
#include <curl/system.h>
#include <initializer_list>
#include <map>
#include <memory>
#include <numeric>
#include <string>
#include <string_view>
namespace cpr {
/**
* Wrapper around "curl_off_t" to prevent applications from having to link against libcurl.
**/
using cpr_off_t = curl_off_t;
/**
* The argument type for progress functions, dependent on libcurl version
**/
#if LIBCURL_VERSION_NUM < 0x072000
using cpr_pf_arg_t = double;
#else
using cpr_pf_arg_t = cpr_off_t;
#endif
template <class T>
class StringHolder {
public:
StringHolder() = default;
explicit StringHolder(std::string str) : str_(std::move(str)) {}
explicit StringHolder(std::string_view str) : str_(str) {}
explicit StringHolder(const char* str) : str_(str) {}
StringHolder(const char* str, size_t len) : str_(str, len) {}
StringHolder(const std::initializer_list<std::string> args) {
str_ = std::accumulate(args.begin(), args.end(), str_);
}
StringHolder(const StringHolder& other) = default;
StringHolder(StringHolder&& old) noexcept = default;
virtual ~StringHolder() = default;
StringHolder& operator=(StringHolder&& old) noexcept = default;
StringHolder& operator=(const StringHolder& other) = default;
explicit operator std::string() const {
return str_;
}
T operator+(const char* rhs) const {
return T(str_ + rhs);
}
T operator+(const std::string& rhs) const {
return T(str_ + rhs);
}
T operator+(const StringHolder<T>& rhs) const {
return T(str_ + rhs.str_);
}
void operator+=(const char* rhs) {
str_ += rhs;
}
void operator+=(const std::string& rhs) {
str_ += rhs;
}
void operator+=(const StringHolder<T>& rhs) {
str_ += rhs;
}
bool operator==(const char* rhs) const {
return str_ == rhs;
}
bool operator==(const std::string& rhs) const {
return str_ == rhs;
}
bool operator==(const StringHolder<T>& rhs) const {
return str_ == rhs.str_;
}
bool operator!=(const char* rhs) const {
return str_.c_str() != rhs;
}
bool operator!=(const std::string& rhs) const {
return str_ != rhs;
}
bool operator!=(const StringHolder<T>& rhs) const {
return str_ != rhs.str_;
}
const std::string& str() {
return str_;
}
const std::string& str() const {
return str_;
}
const char* c_str() const {
return str_.c_str();
}
const char* data() const {
return str_.data();
}
protected:
std::string str_{};
};
template <class T>
std::ostream& operator<<(std::ostream& os, const StringHolder<T>& s) {
os << s.str();
return os;
}
class Url : public StringHolder<Url> {
public:
Url() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Url(std::string url) : StringHolder<Url>(std::move(url)) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Url(std::string_view url) : StringHolder<Url>(url) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Url(const char* url) : StringHolder<Url>(url) {}
Url(const char* str, size_t len) : StringHolder<Url>(std::string(str, len)) {}
Url(const std::initializer_list<std::string> args) : StringHolder<Url>(args) {}
Url(const Url& other) = default;
Url(Url&& old) noexcept = default;
~Url() override = default;
Url& operator=(Url&& old) noexcept = default;
Url& operator=(const Url& other) = default;
};
struct CaseInsensitiveCompare {
bool operator()(const std::string& a, const std::string& b) const noexcept;
};
using Header = std::map<std::string, std::string, CaseInsensitiveCompare>;
} // namespace cpr
#endif

View file

@ -1,51 +0,0 @@
#ifndef CURL_CONTAINER_H
#define CURL_CONTAINER_H
#include <initializer_list>
#include <memory>
#include <string>
#include <vector>
#include "cpr/curlholder.h"
namespace cpr {
struct Parameter {
Parameter(std::string p_key, std::string p_value) : key{std::move(p_key)}, value{std::move(p_value)} {}
std::string key;
std::string value;
};
struct Pair {
Pair(std::string p_key, std::string p_value) : key(std::move(p_key)), value(std::move(p_value)) {}
std::string key;
std::string value;
};
template <class T>
class CurlContainer {
public:
/**
* Enables or disables URL encoding for keys and values when calling GetContent(...).
**/
bool encode = true;
CurlContainer() = default;
CurlContainer(const std::initializer_list<T>&);
void Add(const std::initializer_list<T>&);
void Add(const T&);
const std::string GetContent(const CurlHolder&) const;
protected:
std::vector<T> containerList_;
};
} // namespace cpr
#endif //

View file

@ -1,54 +0,0 @@
#ifndef CPR_CURL_HOLDER_H
#define CPR_CURL_HOLDER_H
#include <array>
#include <mutex>
#include <string>
#include <curl/curl.h>
namespace cpr {
struct CurlHolder {
private:
/**
* Mutex for curl_easy_init().
* curl_easy_init() is not thread save.
* References:
* https://curl.haxx.se/libcurl/c/curl_easy_init.html
* https://curl.haxx.se/libcurl/c/threadsafe.html
**/
// Avoids initalization order problems in a static build
static std::mutex& curl_easy_init_mutex_() {
static std::mutex curl_easy_init_mutex_;
return curl_easy_init_mutex_;
}
public:
CURL* handle{nullptr};
struct curl_slist* chunk{nullptr};
struct curl_slist* resolveCurlList{nullptr};
curl_mime* multipart{nullptr};
std::array<char, CURL_ERROR_SIZE> error{};
CurlHolder();
CurlHolder(const CurlHolder& other) = default;
CurlHolder(CurlHolder&& old) noexcept = default;
~CurlHolder();
CurlHolder& operator=(CurlHolder&& old) noexcept = default;
CurlHolder& operator=(const CurlHolder& other) = default;
/**
* Uses curl_easy_escape(...) for escaping the given string.
**/
std::string urlEncode(const std::string& s) const;
/**
* Uses curl_easy_unescape(...) for unescaping the given string.
**/
std::string urlDecode(const std::string& s) const;
};
} // namespace cpr
#endif

View file

@ -1,18 +0,0 @@
#ifndef CPR_CURLMULTIHOLDER_H
#define CPR_CURLMULTIHOLDER_H
#include <curl/curl.h>
namespace cpr {
class CurlMultiHolder {
public:
CurlMultiHolder();
~CurlMultiHolder();
CURLM* handle{nullptr};
};
} // namespace cpr
#endif

View file

@ -1,53 +0,0 @@
#ifndef CPR_ERROR_H
#define CPR_ERROR_H
#include <cstdint>
#include <string>
#include "cpr/cprtypes.h"
#include <utility>
namespace cpr {
enum class ErrorCode {
OK = 0,
CONNECTION_FAILURE,
EMPTY_RESPONSE,
HOST_RESOLUTION_FAILURE,
INTERNAL_ERROR,
INVALID_URL_FORMAT,
NETWORK_RECEIVE_ERROR,
NETWORK_SEND_FAILURE,
OPERATION_TIMEDOUT,
PROXY_RESOLUTION_FAILURE,
SSL_CONNECT_ERROR,
SSL_LOCAL_CERTIFICATE_ERROR,
SSL_REMOTE_CERTIFICATE_ERROR,
SSL_CACERT_ERROR,
GENERIC_SSL_ERROR,
UNSUPPORTED_PROTOCOL,
REQUEST_CANCELLED,
TOO_MANY_REDIRECTS,
UNKNOWN_ERROR = 1000,
};
class Error {
public:
ErrorCode code = ErrorCode::OK;
std::string message{};
Error() = default;
Error(const std::int32_t& curl_code, std::string&& p_error_message) : code{getErrorCodeForCurlError(curl_code)}, message(std::move(p_error_message)) {}
explicit operator bool() const {
return code != ErrorCode::OK;
}
private:
static ErrorCode getErrorCodeForCurlError(std::int32_t curl_code);
};
} // namespace cpr
#endif

View file

@ -1,59 +0,0 @@
#ifndef CPR_FILE_H
#define CPR_FILE_H
#include <initializer_list>
#include <string>
#include <vector>
#include <cpr/filesystem.h>
namespace cpr {
struct File {
explicit File(std::string p_filepath, const std::string& p_overriden_filename = {}) : filepath(std::move(p_filepath)), overriden_filename(p_overriden_filename) {}
std::string filepath;
std::string overriden_filename;
[[nodiscard]] bool hasOverridenFilename() const noexcept {
return !overriden_filename.empty();
};
};
class Files {
public:
Files() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
Files(const File& p_file) : files{p_file} {};
Files(const Files& other) = default;
Files(Files&& old) noexcept = default;
Files(const std::initializer_list<File>& p_files) : files{p_files} {};
Files(const std::initializer_list<std::string>& p_filepaths);
~Files() noexcept = default;
Files& operator=(const Files& other);
Files& operator=(Files&& old) noexcept;
using iterator = std::vector<File>::iterator;
using const_iterator = std::vector<File>::const_iterator;
iterator begin();
iterator end();
[[nodiscard]] const_iterator begin() const;
[[nodiscard]] const_iterator end() const;
[[nodiscard]] const_iterator cbegin() const;
[[nodiscard]] const_iterator cend() const;
void emplace_back(const File& file);
void push_back(const File& file);
void pop_back();
private:
std::vector<File> files;
};
} // namespace cpr
#endif

View file

@ -1,26 +0,0 @@
#ifndef CPR_FILESYSTEM_H
#define CPR_FILESYSTEM_H
// Include filesystem into the namespace "fs" from either "filesystem" or "experimental/filesystem" or "boost/filesystem"
#ifdef CPR_USE_BOOST_FILESYSTEM
#define BOOST_FILESYSTEM_VERSION 4 // Use the latest, with the closest behavior to std::filesystem.
#include <boost/filesystem.hpp>
namespace cpr {
namespace fs = boost::filesystem;
}
// cppcheck-suppress preprocessorErrorDirective
#elif __has_include(<filesystem>)
#include <filesystem>
namespace cpr {
namespace fs = std::filesystem;
}
#elif __has_include("experimental/filesystem")
#include <experimental/filesystem>
namespace cpr {
namespace fs = std::experimental::filesystem;
}
#else
#error "Failed to include <filesystem> header!"
#endif
#endif

View file

@ -1,67 +0,0 @@
#ifndef CPR_HTTP_VERSION_H
#define CPR_HTTP_VERSION_H
#include <curl/curlver.h>
namespace cpr {
enum class HttpVersionCode {
/**
* Let libcurl decide which version is the best.
**/
VERSION_NONE,
/**
* Enforce HTTP 1.0 requests.
**/
VERSION_1_0,
/**
* Enforce HTTP 1.1 requests.
**/
VERSION_1_1,
#if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0
/**
* Attempt HTTP 2.0 requests.
* Fallback to HTTP 1.1 if negotiation fails.
**/
VERSION_2_0,
#endif
#if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0
/**
* Attempt HTTP 2.0 for HTTPS requests only.
* Fallback to HTTP 1.1 if negotiation fails.
* HTTP 1.1 will be used for HTTP connections.
**/
VERSION_2_0_TLS,
#endif
#if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0
/**
* Start HTTP 2.0 for HTTP requests.
* Requires prior knowledge that the server supports HTTP 2.0.
* For HTTPS requests we will negotiate the protocol version in the TLS handshake.
**/
VERSION_2_0_PRIOR_KNOWLEDGE,
#endif
#if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0
/**
* Attempt HTTP 3.0 requests.
* Requires prior knowledge that the server supports HTTP 3.0 since there is no gracefully downgrade.
* Fallback to HTTP 1.1 if negotiation fails.
**/
VERSION_3_0
#endif
};
class HttpVersion {
public:
/**
* The HTTP version that should be used by libcurl when initiating a HTTP(S) connection.
* Default: HttpVersionCode::VERSION_NONE
**/
HttpVersionCode code = HttpVersionCode::VERSION_NONE;
HttpVersion() = default;
explicit HttpVersion(HttpVersionCode _code) : code(_code) {}
};
} // namespace cpr
#endif

View file

@ -1,74 +0,0 @@
#ifndef CPR_INTERCEPTOR_H
#define CPR_INTERCEPTOR_H
#include "cpr/multiperform.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include <vector>
namespace cpr {
class Interceptor {
public:
enum class ProceedHttpMethod {
GET_REQUEST = 0,
POST_REQUEST,
PUT_REQUEST,
DELETE_REQUEST,
PATCH_REQUEST,
HEAD_REQUEST,
OPTIONS_REQUEST,
DOWNLOAD_CALLBACK_REQUEST,
DOWNLOAD_FILE_REQUEST,
};
Interceptor() = default;
Interceptor(const Interceptor& other) = default;
Interceptor(Interceptor&& old) = default;
virtual ~Interceptor() = default;
Interceptor& operator=(const Interceptor& other) = default;
Interceptor& operator=(Interceptor&& old) = default;
virtual Response intercept(Session& session) = 0;
protected:
static Response proceed(Session& session);
static Response proceed(Session& session, ProceedHttpMethod httpMethod);
static Response proceed(Session& session, ProceedHttpMethod httpMethod, std::ofstream& file);
static Response proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write);
};
class InterceptorMulti {
public:
enum class ProceedHttpMethod {
GET_REQUEST = 0,
POST_REQUEST,
PUT_REQUEST,
DELETE_REQUEST,
PATCH_REQUEST,
HEAD_REQUEST,
OPTIONS_REQUEST,
DOWNLOAD_CALLBACK_REQUEST,
DOWNLOAD_FILE_REQUEST,
};
InterceptorMulti() = default;
InterceptorMulti(const InterceptorMulti& other) = default;
InterceptorMulti(InterceptorMulti&& old) = default;
virtual ~InterceptorMulti() = default;
InterceptorMulti& operator=(const InterceptorMulti& other) = default;
InterceptorMulti& operator=(InterceptorMulti&& old) = default;
virtual std::vector<Response> intercept(MultiPerform& multi) = 0;
protected:
static std::vector<Response> proceed(MultiPerform& multi);
static void PrepareDownloadSession(MultiPerform& multi, size_t sessions_index, const WriteCallback& write);
};
} // namespace cpr
#endif

View file

@ -1,32 +0,0 @@
#ifndef CPR_INTERFACE_H
#define CPR_INTERFACE_H
#include <initializer_list>
#include <string>
#include "cpr/cprtypes.h"
namespace cpr {
class Interface : public StringHolder<Interface> {
public:
Interface() = default;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Interface(std::string iface) : StringHolder<Interface>(std::move(iface)) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Interface(std::string_view iface) : StringHolder<Interface>(iface) {}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
Interface(const char* iface) : StringHolder<Interface>(iface) {}
Interface(const char* str, size_t len) : StringHolder<Interface>(str, len) {}
Interface(const std::initializer_list<std::string> args) : StringHolder<Interface>(args) {}
Interface(const Interface& other) = default;
Interface(Interface&& old) noexcept = default;
~Interface() override = default;
Interface& operator=(Interface&& old) noexcept = default;
Interface& operator=(const Interface& other) = default;
};
} // namespace cpr
#endif

View file

@ -1,18 +0,0 @@
#ifndef CPR_SPEED_LIMIT_H
#define CPR_SPEED_LIMIT_H
#include <cstdint>
namespace cpr {
class LimitRate {
public:
LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) : downrate(p_downrate), uprate(p_uprate) {}
std::int64_t downrate = 0;
std::int64_t uprate = 0;
};
} // namespace cpr
#endif

View file

@ -1,23 +0,0 @@
#ifndef CPR_LOCAL_PORT_H
#define CPR_LOCAL_PORT_H
#include <cstdint>
namespace cpr {
class LocalPort {
public:
// NOLINTNEXTLINE(google-explicit-constructor)
LocalPort(const std::uint16_t p_localport) : localport_(p_localport) {}
operator std::uint16_t() const {
return localport_;
}
private:
std::uint16_t localport_ = 0;
};
} // namespace cpr
#endif

View file

@ -1,23 +0,0 @@
#ifndef CPR_LOCAL_PORT_RANGE_H
#define CPR_LOCAL_PORT_RANGE_H
#include <cstdint>
namespace cpr {
class LocalPortRange {
public:
// NOLINTNEXTLINE(google-explicit-constructor)
LocalPortRange(const std::uint16_t p_localportrange) : localportrange_(p_localportrange) {}
operator std::uint16_t() const {
return localportrange_;
}
private:
std::uint16_t localportrange_ = 0;
};
} // namespace cpr
#endif

View file

@ -1,18 +0,0 @@
#ifndef CPR_LOW_SPEED_H
#define CPR_LOW_SPEED_H
#include <cstdint>
namespace cpr {
class LowSpeed {
public:
LowSpeed(const std::int32_t p_limit, const std::int32_t p_time) : limit(p_limit), time(p_time) {}
std::int32_t limit;
std::int32_t time;
};
} // namespace cpr
#endif

View file

@ -1,43 +0,0 @@
#ifndef CPR_MULTIPART_H
#define CPR_MULTIPART_H
#include <cstdint>
#include <initializer_list>
#include <string>
#include <type_traits>
#include <vector>
#include "buffer.h"
#include "file.h"
namespace cpr {
struct Part {
Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {}) : name{p_name}, value{p_value}, content_type{p_content_type}, is_file{false}, is_buffer{false} {}
Part(const std::string& p_name, const std::int32_t& p_value, const std::string& p_content_type = {}) : name{p_name}, value{std::to_string(p_value)}, content_type{p_content_type}, is_file{false}, is_buffer{false} {}
Part(const std::string& p_name, const Files& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {}
Part(const std::string& p_name, Files&& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {}
Part(const std::string& p_name, const Buffer& buffer, const std::string& p_content_type = {}) : name{p_name}, value{buffer.filename.string()}, content_type{p_content_type}, data{buffer.data}, datalen{buffer.datalen}, is_file{false}, is_buffer{true} {}
std::string name;
// We don't use fs::path here, as this leads to problems using windows
std::string value;
std::string content_type;
Buffer::data_t data{nullptr};
size_t datalen{0};
bool is_file;
bool is_buffer;
Files files;
};
class Multipart {
public:
Multipart(const std::initializer_list<Part>& parts);
std::vector<Part> parts;
};
} // namespace cpr
#endif

View file

@ -1,137 +0,0 @@
#ifndef CPR_MULTIPERFORM_H
#define CPR_MULTIPERFORM_H
#include "cpr/curlmultiholder.h"
#include "cpr/response.h"
#include "cpr/session.h"
#include <functional>
#include <memory>
#include <queue>
#include <stdexcept>
#include <vector>
namespace cpr {
class InterceptorMulti;
class MultiPerform {
public:
enum class HttpMethod {
UNDEFINED = 0,
GET_REQUEST,
POST_REQUEST,
PUT_REQUEST,
DELETE_REQUEST,
PATCH_REQUEST,
HEAD_REQUEST,
OPTIONS_REQUEST,
DOWNLOAD_REQUEST,
};
MultiPerform();
MultiPerform(const MultiPerform& other) = delete;
MultiPerform(MultiPerform&& old) = default;
~MultiPerform();
MultiPerform& operator=(const MultiPerform& other) = delete;
MultiPerform& operator=(MultiPerform&& old) noexcept = default;
std::vector<Response> Get();
std::vector<Response> Delete();
template <typename... DownloadArgTypes>
std::vector<Response> Download(DownloadArgTypes... args);
std::vector<Response> Put();
std::vector<Response> Head();
std::vector<Response> Options();
std::vector<Response> Patch();
std::vector<Response> Post();
std::vector<Response> Perform();
template <typename... DownloadArgTypes>
std::vector<Response> PerformDownload(DownloadArgTypes... args);
void AddSession(std::shared_ptr<Session>& session, HttpMethod method = HttpMethod::UNDEFINED);
void RemoveSession(const std::shared_ptr<Session>& session);
std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions();
[[nodiscard]] const std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>>& GetSessions() const;
void AddInterceptor(const std::shared_ptr<InterceptorMulti>& pinterceptor);
private:
// Interceptors should be able to call the private proceed() and PrepareDownloadSessions() functions
friend InterceptorMulti;
void SetHttpMethod(HttpMethod method);
void PrepareSessions();
template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args);
template <typename CurrentDownloadArgType>
void PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg);
void PrepareDownloadSession(size_t sessions_index, std::ofstream& file);
void PrepareDownloadSession(size_t sessions_index, const WriteCallback& write);
void PrepareGet();
void PrepareDelete();
void PreparePut();
void PreparePatch();
void PrepareHead();
void PrepareOptions();
void PreparePost();
template <typename... DownloadArgTypes>
void PrepareDownload(DownloadArgTypes... args);
std::vector<Response> intercept();
std::vector<Response> proceed();
std::vector<Response> MakeRequest();
std::vector<Response> MakeDownloadRequest();
void DoMultiPerform();
std::vector<Response> ReadMultiInfo(std::function<Response(Session&, CURLcode)>&& complete_function);
std::vector<std::pair<std::shared_ptr<Session>, HttpMethod>> sessions_;
std::unique_ptr<CurlMultiHolder> multicurl_;
bool is_download_multi_perform{false};
std::queue<std::shared_ptr<InterceptorMulti>> interceptors_;
};
template <typename CurrentDownloadArgType>
void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg) {
PrepareDownloadSession(sessions_index, current_arg);
}
template <typename CurrentDownloadArgType, typename... DownloadArgTypes>
void MultiPerform::PrepareDownloadSessions(size_t sessions_index, CurrentDownloadArgType current_arg, DownloadArgTypes... args) {
PrepareDownloadSession(sessions_index, current_arg);
PrepareDownloadSessions<DownloadArgTypes...>(sessions_index + 1, args...);
}
template <typename... DownloadArgTypes>
void MultiPerform::PrepareDownload(DownloadArgTypes... args) {
SetHttpMethod(HttpMethod::DOWNLOAD_REQUEST);
PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
}
template <typename... DownloadArgTypes>
std::vector<Response> MultiPerform::Download(DownloadArgTypes... args) {
if (sizeof...(args) != sessions_.size()) {
throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
}
PrepareDownload(args...);
return MakeDownloadRequest();
}
template <typename... DownloadArgTypes>
std::vector<Response> MultiPerform::PerformDownload(DownloadArgTypes... args) {
if (sizeof...(args) != sessions_.size()) {
throw std::invalid_argument("Number of download arguments has to match the number of sessions added to the multiperform!");
}
PrepareDownloadSessions<DownloadArgTypes...>(0, args...);
return MakeDownloadRequest();
}
} // namespace cpr
#endif

View file

@ -1,18 +0,0 @@
#ifndef CPR_PARAMETERS_H
#define CPR_PARAMETERS_H
#include <initializer_list>
#include "cpr/curl_container.h"
namespace cpr {
class Parameters : public CurlContainer<Parameter> {
public:
Parameters() = default;
Parameters(const std::initializer_list<Parameter>& parameters);
};
} // namespace cpr
#endif

View file

@ -1,23 +0,0 @@
#ifndef CPR_PAYLOAD_H
#define CPR_PAYLOAD_H
#include <initializer_list>
#include "cpr/curl_container.h"
namespace cpr {
class Payload : public CurlContainer<Pair> {
public:
template <class It>
Payload(const It begin, const It end) {
for (It pair = begin; pair != end; ++pair) {
Add(*pair);
}
}
Payload(const std::initializer_list<Pair>& pairs);
};
} // namespace cpr
#endif

View file

@ -1,23 +0,0 @@
#ifndef CPR_PROXIES_H
#define CPR_PROXIES_H
#include <initializer_list>
#include <map>
#include <string>
namespace cpr {
class Proxies {
public:
Proxies() = default;
Proxies(const std::initializer_list<std::pair<const std::string, std::string>>& hosts);
Proxies(const std::map<std::string, std::string>& hosts);
bool has(const std::string& protocol) const;
const std::string& operator[](const std::string& protocol);
private:
std::map<std::string, std::string> hosts_;
};
} // namespace cpr
#endif

View file

@ -1,43 +0,0 @@
#ifndef CPR_PROXYAUTH_H
#define CPR_PROXYAUTH_H
#include <initializer_list>
#include <map>
#include "cpr/auth.h"
#include "cpr/util.h"
namespace cpr {
class EncodedAuthentication {
public:
EncodedAuthentication() : auth_string_{""} {}
EncodedAuthentication(std::string username, std::string password) : auth_string_{cpr::util::urlEncode(std::move(username)) + ":" + cpr::util::urlEncode(std::move(password))} {}
EncodedAuthentication(const EncodedAuthentication& other) = default;
EncodedAuthentication(EncodedAuthentication&& old) noexcept = default;
virtual ~EncodedAuthentication() noexcept;
EncodedAuthentication& operator=(EncodedAuthentication&& old) noexcept = default;
EncodedAuthentication& operator=(const EncodedAuthentication& other) = default;
const char* GetAuthString() const noexcept;
protected:
std::string auth_string_;
};
class ProxyAuthentication {
public:
ProxyAuthentication() = default;
ProxyAuthentication(const std::initializer_list<std::pair<const std::string, EncodedAuthentication>>& auths) : proxyAuth_{auths} {}
ProxyAuthentication(const std::map<std::string, EncodedAuthentication>& auths) : proxyAuth_{auths} {}
bool has(const std::string& protocol) const;
const char* operator[](const std::string& protocol);
private:
std::map<std::string, EncodedAuthentication> proxyAuth_;
};
} // namespace cpr
#endif

View file

@ -1,44 +0,0 @@
#ifndef CPR_RANGE_H
#define CPR_RANGE_H
#include <cstdint>
#include <optional>
namespace cpr {
class Range {
public:
Range(const std::optional<std::int64_t> p_resume_from = std::nullopt, const std::optional<std::int64_t> p_finish_at = std::nullopt) {
resume_from = p_resume_from.value_or(0);
finish_at = p_finish_at.value_or(-1);
}
std::int64_t resume_from;
std::int64_t finish_at;
const std::string str() const {
std::string from_str = (resume_from < 0U) ? "" : std::to_string(resume_from);
std::string to_str = (finish_at < 0U) ? "" : std::to_string(finish_at);
return from_str + "-" + to_str;
}
};
class MultiRange {
public:
MultiRange(std::initializer_list<Range> rs) : ranges{rs} {}
const std::string str() const {
std::string multi_range_string{};
for (Range range : ranges) {
multi_range_string += ((multi_range_string.empty()) ? "" : ", ") + range.str();
}
return multi_range_string;
}
private:
std::vector<Range> ranges;
}; // namespace cpr
} // namespace cpr
#endif

View file

@ -1,84 +0,0 @@
#ifndef CPR_REDIRECT_H
#define CPR_REDIRECT_H
#include <cstdint>
namespace cpr {
enum class PostRedirectFlags : uint8_t {
/**
* Respect RFC 7231 (section 6.4.2 to 6.4.4).
* Same as CURL_REDIR_POST_301 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html).
**/
POST_301 = 0x1 << 0,
/**
* Maintain the request method after a 302 redirect.
* Same as CURL_REDIR_POST_302 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html).
**/
POST_302 = 0x1 << 1,
/**
* Maintain the request method after a 303 redirect.
* Same as CURL_REDIR_POST_303 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html).
**/
POST_303 = 0x1 << 2,
/**
* Default value.
* Convenience option to enable all flags.
* Same as CURL_REDIR_POST_ALL (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html).
**/
POST_ALL = POST_301 | POST_302 | POST_303,
/**
* * Convenience option to disable all flags.
**/
NONE = 0x0
};
PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs);
PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs);
PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs);
PostRedirectFlags operator~(PostRedirectFlags flag);
PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs);
PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs);
PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs);
bool any(PostRedirectFlags flag);
class Redirect {
public:
/**
* The maximum number of redirects to follow.
* 0: Refuse any redirects.
* -1: Infinite number of redirects.
* Default: 50
* https://curl.se/libcurl/c/CURLOPT_MAXREDIRS.html
**/
// NOLINTNEXTLINE (google-runtime-int)
long maximum{50L};
/**
* Follow 3xx redirects.
* Default: true
* https://curl.se/libcurl/c/CURLOPT_FOLLOWLOCATION.html
**/
bool follow{true};
/**
* Continue to send authentication (user+password) credentials when following locations, even when hostname changed.
* Default: false
* https://curl.se/libcurl/c/CURLOPT_UNRESTRICTED_AUTH.html
**/
bool cont_send_cred{false};
/**
* Flags to control how to act after a redirect for a post request.
* Default: POST_ALL
**/
PostRedirectFlags post_flags{PostRedirectFlags::POST_ALL};
Redirect() = default;
// NOLINTNEXTLINE (google-runtime-int)
Redirect(long p_maximum, bool p_follow, bool p_cont_send_cred, PostRedirectFlags p_post_flags) : maximum(p_maximum), follow(p_follow), cont_send_cred(p_cont_send_cred), post_flags(p_post_flags){};
// NOLINTNEXTLINE (google-runtime-int)
explicit Redirect(long p_maximum) : maximum(p_maximum){};
explicit Redirect(bool p_follow) : follow(p_follow){};
Redirect(bool p_follow, bool p_cont_send_cred) : follow(p_follow), cont_send_cred(p_cont_send_cred){};
explicit Redirect(PostRedirectFlags p_post_flags) : post_flags(p_post_flags){};
};
} // namespace cpr
#endif

View file

@ -1,17 +0,0 @@
#ifndef CPR_RESERVE_SIZE_H
#define CPR_RESERVE_SIZE_H
#include <cstdint>
namespace cpr {
class ReserveSize {
public:
ReserveSize(const size_t _size) : size(_size) {}
size_t size = 0;
};
} // namespace cpr
#endif

View file

@ -1,23 +0,0 @@
#ifndef CPR_RESOLVE_H
#define CPR_RESOLVE_H
#include <string>
#include <set>
namespace cpr {
class Resolve {
public:
std::string host;
std::string addr;
std::set<uint16_t> ports;
Resolve(const std::string& host_param, const std::string& addr_param, const std::set<uint16_t>& ports_param = std::set<uint16_t>{80U, 443U}): host(host_param), addr(addr_param), ports(ports_param) {
if (this->ports.empty()) {
this->ports.insert(80U);
this->ports.insert(443U);
}
}
};
} // namespace cpr
#endif

View file

@ -1,58 +0,0 @@
#ifndef CPR_RESPONSE_H
#define CPR_RESPONSE_H
#include <cassert>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "cpr/cert_info.h"
#include "cpr/cookies.h"
#include "cpr/cprtypes.h"
#include "cpr/error.h"
#include "cpr/ssl_options.h"
#include "cpr/util.h"
namespace cpr {
class MultiPerform;
class Response {
private:
friend MultiPerform;
std::shared_ptr<CurlHolder> curl_{nullptr};
public:
// Ignored here since libcurl uses a long for this.
// NOLINTNEXTLINE(google-runtime-int)
long status_code{};
std::string text{};
Header header{};
Url url{};
double elapsed{};
Cookies cookies{};
Error error{};
std::string raw_header{};
std::string status_line{};
std::string reason{};
cpr_off_t uploaded_bytes{};
cpr_off_t downloaded_bytes{};
// Ignored here since libcurl uses a long for this.
// NOLINTNEXTLINE(google-runtime-int)
long redirect_count{};
Response() = default;
Response(std::shared_ptr<CurlHolder> curl, std::string&& p_text, std::string&& p_header_string, Cookies&& p_cookies, Error&& p_error);
std::vector<CertInfo> GetCertInfos();
Response(const Response& other) = default;
Response(Response&& old) noexcept = default;
~Response() noexcept = default;
Response& operator=(Response&& old) noexcept = default;
Response& operator=(const Response& other) = default;
};
} // namespace cpr
#endif

View file

@ -1,308 +0,0 @@
#ifndef CPR_SESSION_H
#define CPR_SESSION_H
#include <cstdint>
#include <fstream>
#include <functional>
#include <future>
#include <memory>
#include <queue>
#include "cpr/accept_encoding.h"
#include "cpr/async_wrapper.h"
#include "cpr/auth.h"
#include "cpr/bearer.h"
#include "cpr/body.h"
#include "cpr/callback.h"
#include "cpr/connect_timeout.h"
#include "cpr/cookies.h"
#include "cpr/cprtypes.h"
#include "cpr/curlholder.h"
#include "cpr/http_version.h"
#include "cpr/interface.h"
#include "cpr/limit_rate.h"
#include "cpr/local_port.h"
#include "cpr/local_port_range.h"
#include "cpr/low_speed.h"
#include "cpr/multipart.h"
#include "cpr/parameters.h"
#include "cpr/payload.h"
#include "cpr/proxies.h"
#include "cpr/proxyauth.h"
#include "cpr/range.h"
#include "cpr/redirect.h"
#include "cpr/reserve_size.h"
#include "cpr/resolve.h"
#include "cpr/response.h"
#include "cpr/ssl_options.h"
#include "cpr/timeout.h"
#include "cpr/unix_socket.h"
#include "cpr/user_agent.h"
#include "cpr/util.h"
#include "cpr/verbose.h"
namespace cpr {
using AsyncResponse = AsyncWrapper<Response>;
class Interceptor;
class MultiPerform;
class Session : public std::enable_shared_from_this<Session> {
public:
Session();
Session(const Session& other) = delete;
Session(Session&& old) = default;
~Session() = default;
Session& operator=(Session&& old) noexcept = default;
Session& operator=(const Session& other) = delete;
void SetUrl(const Url& url);
void SetParameters(const Parameters& parameters);
void SetParameters(Parameters&& parameters);
void SetHeader(const Header& header);
void UpdateHeader(const Header& header);
void SetTimeout(const Timeout& timeout);
void SetConnectTimeout(const ConnectTimeout& timeout);
void SetAuth(const Authentication& auth);
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
void SetBearer(const Bearer& token);
#endif
void SetUserAgent(const UserAgent& ua);
void SetPayload(Payload&& payload);
void SetPayload(const Payload& payload);
void SetProxies(Proxies&& proxies);
void SetProxies(const Proxies& proxies);
void SetProxyAuth(ProxyAuthentication&& proxy_auth);
void SetProxyAuth(const ProxyAuthentication& proxy_auth);
void SetMultipart(Multipart&& multipart);
void SetMultipart(const Multipart& multipart);
void SetRedirect(const Redirect& redirect);
void SetCookies(const Cookies& cookies);
void SetBody(Body&& body);
void SetBody(const Body& body);
void SetLowSpeed(const LowSpeed& low_speed);
void SetVerifySsl(const VerifySsl& verify);
void SetUnixSocket(const UnixSocket& unix_socket);
void SetSslOptions(const SslOptions& options);
void SetReadCallback(const ReadCallback& read);
void SetHeaderCallback(const HeaderCallback& header);
void SetWriteCallback(const WriteCallback& write);
void SetProgressCallback(const ProgressCallback& progress);
void SetDebugCallback(const DebugCallback& debug);
void SetVerbose(const Verbose& verbose);
void SetInterface(const Interface& iface);
void SetLocalPort(const LocalPort& local_port);
void SetLocalPortRange(const LocalPortRange& local_port_range);
void SetHttpVersion(const HttpVersion& version);
void SetRange(const Range& range);
void SetResolve(const Resolve& resolve);
void SetResolves(const std::vector<Resolve>& resolves);
void SetMultiRange(const MultiRange& multi_range);
void SetReserveSize(const ReserveSize& reserve_size);
void SetAcceptEncoding(const AcceptEncoding& accept_encoding);
void SetAcceptEncoding(AcceptEncoding&& accept_encoding);
void SetLimitRate(const LimitRate& limit_rate);
// For cancellable requests
void SetCancellationParam(std::shared_ptr<std::atomic_bool> param);
// Used in templated functions
void SetOption(const Url& url);
void SetOption(const Parameters& parameters);
void SetOption(Parameters&& parameters);
void SetOption(const Header& header);
void SetOption(const Timeout& timeout);
void SetOption(const ConnectTimeout& timeout);
void SetOption(const Authentication& auth);
// Only supported with libcurl >= 7.61.0.
// As an alternative use SetHeader and add the token manually.
#if LIBCURL_VERSION_NUM >= 0x073D00
void SetOption(const Bearer& auth);
#endif
void SetOption(const UserAgent& ua);
void SetOption(Payload&& payload);
void SetOption(const Payload& payload);
void SetOption(const LimitRate& limit_rate);
void SetOption(Proxies&& proxies);
void SetOption(const Proxies& proxies);
void SetOption(ProxyAuthentication&& proxy_auth);
void SetOption(const ProxyAuthentication& proxy_auth);
void SetOption(Multipart&& multipart);
void SetOption(const Multipart& multipart);
void SetOption(const Redirect& redirect);
void SetOption(const Cookies& cookies);
void SetOption(Body&& body);
void SetOption(const Body& body);
void SetOption(const ReadCallback& read);
void SetOption(const HeaderCallback& header);
void SetOption(const WriteCallback& write);
void SetOption(const ProgressCallback& progress);
void SetOption(const DebugCallback& debug);
void SetOption(const LowSpeed& low_speed);
void SetOption(const VerifySsl& verify);
void SetOption(const Verbose& verbose);
void SetOption(const UnixSocket& unix_socket);
void SetOption(const SslOptions& options);
void SetOption(const Interface& iface);
void SetOption(const LocalPort& local_port);
void SetOption(const LocalPortRange& local_port_range);
void SetOption(const HttpVersion& version);
void SetOption(const Range& range);
void SetOption(const MultiRange& multi_range);
void SetOption(const ReserveSize& reserve_size);
void SetOption(const AcceptEncoding& accept_encoding);
void SetOption(AcceptEncoding&& accept_encoding);
void SetOption(const Resolve& resolve);
void SetOption(const std::vector<Resolve>& resolves);
cpr_off_t GetDownloadFileLength();
/**
* Attempt to preallocate enough memory for specified number of characters in the response string.
* Pass 0 to disable this behavior and let the response string be allocated dynamically on demand.
*
* Example:
* cpr::Session session;
* session.SetUrl(cpr::Url{"http://xxx/file"});
* session.ResponseStringReserve(1024 * 512); // Reserve space for at least 1024 * 512 characters
* cpr::Response r = session.Get();
**/
void ResponseStringReserve(size_t size);
Response Delete();
Response Download(const WriteCallback& write);
Response Download(std::ofstream& file);
Response Get();
Response Head();
Response Options();
Response Patch();
Response Post();
Response Put();
AsyncResponse GetAsync();
AsyncResponse DeleteAsync();
AsyncResponse DownloadAsync(const WriteCallback& write);
AsyncResponse DownloadAsync(std::ofstream& file);
AsyncResponse HeadAsync();
AsyncResponse OptionsAsync();
AsyncResponse PatchAsync();
AsyncResponse PostAsync();
AsyncResponse PutAsync();
template <typename Then>
auto GetCallback(Then then);
template <typename Then>
auto PostCallback(Then then);
template <typename Then>
auto PutCallback(Then then);
template <typename Then>
auto HeadCallback(Then then);
template <typename Then>
auto DeleteCallback(Then then);
template <typename Then>
auto OptionsCallback(Then then);
template <typename Then>
auto PatchCallback(Then then);
std::shared_ptr<CurlHolder> GetCurlHolder();
std::string GetFullRequestUrl();
void PrepareDelete();
void PrepareGet();
void PrepareHead();
void PrepareOptions();
void PreparePatch();
void PreparePost();
void PreparePut();
void PrepareDownload(const WriteCallback& write);
void PrepareDownload(std::ofstream& file);
Response Complete(CURLcode curl_error);
Response CompleteDownload(CURLcode curl_error);
void AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor);
private:
// Interceptors should be able to call the private proceed() function
friend Interceptor;
friend MultiPerform;
bool hasBodyOrPayload_{false};
bool chunkedTransferEncoding_{false};
std::shared_ptr<CurlHolder> curl_;
Url url_;
Parameters parameters_;
Proxies proxies_;
ProxyAuthentication proxyAuth_;
Header header_;
AcceptEncoding acceptEncoding_;
/**
* Will be set by the read callback.
* Ensures that the "Transfer-Encoding" is set to "chunked", if not overriden in header_.
**/
ReadCallback readcb_;
HeaderCallback headercb_;
WriteCallback writecb_;
ProgressCallback progresscb_;
DebugCallback debugcb_;
CancellationCallback cancellationcb_;
size_t response_string_reserve_size_{0};
std::string response_string_;
std::string header_string_;
std::queue<std::shared_ptr<Interceptor>> interceptors_;
bool isUsedInMultiPerform{false};
bool isCancellable{false};
Response makeDownloadRequest();
Response makeRequest();
Response proceed();
Response intercept();
void prepareCommon();
void prepareCommonDownload();
void SetHeaderInternal();
std::shared_ptr<Session> GetSharedPtrFromThis();
CURLcode DoEasyPerform();
};
template <typename Then>
auto Session::GetCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Get()); }, std::move(then));
}
template <typename Then>
auto Session::PostCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Post()); }, std::move(then));
}
template <typename Then>
auto Session::PutCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Put()); }, std::move(then));
}
template <typename Then>
auto Session::HeadCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Head()); }, std::move(then));
}
template <typename Then>
auto Session::DeleteCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Delete()); }, std::move(then));
}
template <typename Then>
auto Session::OptionsCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Options()); }, std::move(then));
}
template <typename Then>
auto Session::PatchCallback(Then then) {
return async([shared_this = GetSharedPtrFromThis()](Then then_inner) { return then_inner(shared_this->Patch()); }, std::move(then));
}
} // namespace cpr
#endif

View file

@ -1,47 +0,0 @@
#ifndef CPR_SINGLETON_H
#define CPR_SINGLETON_H
#include <mutex>
#ifndef CPR_DISABLE_COPY
#define CPR_DISABLE_COPY(Class) \
Class(const Class&) = delete; \
Class& operator=(const Class&) = delete;
#endif
#ifndef CPR_SINGLETON_DECL
#define CPR_SINGLETON_DECL(Class) \
public: \
static Class* GetInstance(); \
static void ExitInstance(); \
private: \
CPR_DISABLE_COPY(Class) \
static Class* s_pInstance; \
static std::mutex s_mutex;
#endif
#ifndef CPR_SINGLETON_IMPL
#define CPR_SINGLETON_IMPL(Class) \
Class* Class::s_pInstance = nullptr; \
std::mutex Class::s_mutex; \
Class* Class::GetInstance() { \
if (s_pInstance == nullptr) { \
s_mutex.lock(); \
if (s_pInstance == nullptr) { \
s_pInstance = new Class; \
} \
s_mutex.unlock(); \
} \
return s_pInstance; \
} \
void Class::ExitInstance() { \
s_mutex.lock(); \
if (s_pInstance) { \
delete s_pInstance; \
s_pInstance = nullptr; \
} \
s_mutex.unlock(); \
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show more