mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-06 07:13:39 +07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e6ded1f36 | ||
|
|
d663588491 | ||
|
|
439caf5b79 | ||
|
|
c4ba43ca6f | ||
|
|
20cba2ecd9 | ||
|
|
0ff2e16d69 | ||
|
|
51607ec752 | ||
|
|
7992b14896 | ||
|
|
7e420aeed3 | ||
|
|
227d2c2050 | ||
|
|
93e53c91f7 | ||
|
|
58cffd3223 | ||
|
|
8f32271e8c | ||
|
|
c8c1c3d376 | ||
|
|
9f512acb42 | ||
|
|
c0b461a3b7 | ||
|
|
74fe5a5029 | ||
|
|
9d0a9d4e23 | ||
|
|
5758769ad3 | ||
|
|
e7eadc3605 | ||
|
|
07c6e58951 | ||
|
|
87994811a1 | ||
|
|
42feb7e8be | ||
|
|
26196b70af | ||
|
|
93a51979c4 | ||
|
|
ad7edc7b27 | ||
|
|
27cd4e6ffe | ||
|
|
cae5a8be1c | ||
|
|
8e10d4e8e7 | ||
|
|
b57f79f438 | ||
|
|
a9cf097951 | ||
|
|
5c3624e1af | ||
|
|
cba9ef8c0b | ||
|
|
4f8407a3a7 | ||
|
|
656e936f49 | ||
|
|
d92c314466 | ||
|
|
b747fb111d | ||
|
|
7e0a0b2d0c | ||
|
|
362d064afa | ||
|
|
1bd88de2e5 | ||
|
|
0b541ffebc | ||
|
|
106be19c3e | ||
|
|
25d72bf881 | ||
|
|
9d5b5297cc | ||
|
|
462884bebb | ||
|
|
b1cc24b795 | ||
|
|
f0eb55b327 | ||
|
|
6dc285b5ca | ||
|
|
07e614eef7 | ||
|
|
916b2a8fd3 | ||
|
|
869f5bb279 | ||
|
|
3e21338f82 | ||
|
|
37bb3c6a77 | ||
|
|
d4ab2fa0e6 | ||
|
|
72d3f4896a | ||
|
|
5e6f973b99 | ||
|
|
7ed77b02ad | ||
|
|
127a64d5a0 | ||
|
|
caa31aafda | ||
|
|
dae318495f | ||
|
|
305a7abcb9 | ||
|
|
219d13b718 | ||
|
|
df20c27696 | ||
|
|
a5a62768c0 | ||
|
|
4001637beb | ||
|
|
47044c05a8 | ||
|
|
a449d82723 | ||
|
|
fee8e97b4e | ||
|
|
72d9ed4056 | ||
|
|
1be1b3a86d | ||
|
|
9452c0a4b6 | ||
|
|
307b729549 | ||
|
|
696239d6e1 | ||
|
|
6929d90353 | ||
|
|
348d032029 | ||
|
|
d1d3fcdfd5 | ||
|
|
abf3a67dd0 | ||
|
|
d87abeecf0 | ||
|
|
4e28e4f741 | ||
|
|
80a55cedeb | ||
|
|
d05c343602 | ||
|
|
33f67386fe | ||
|
|
56d8168dc4 | ||
|
|
5d87cc0558 | ||
|
|
cb41947eb4 | ||
|
|
0857eba17b | ||
|
|
020b0db090 | ||
|
|
bf0760fde4 | ||
|
|
bb8e45383e | ||
|
|
a1df576e4f | ||
|
|
7fb0254794 | ||
|
|
c82d1e52cc | ||
|
|
846151b605 | ||
|
|
e44e31dd5b | ||
|
|
f7b9501662 | ||
|
|
e12fe4cbbb | ||
|
|
49d2e1f135 | ||
|
|
8191fd8e6c | ||
|
|
d73395e1dc | ||
|
|
64d001162b | ||
|
|
bb00a23116 | ||
|
|
63d6e9b91b | ||
|
|
66eed5681a | ||
|
|
8ecdb11979 | ||
|
|
894fcc8e02 | ||
|
|
7f43f0f3ff | ||
|
|
87e03dd1ce | ||
|
|
e5cacb465d | ||
|
|
ee8371f753 | ||
|
|
081723f983 | ||
|
|
b61f36579c | ||
|
|
33f53aa458 | ||
|
|
412ab5f063 | ||
|
|
11e02e901c | ||
|
|
65a8f4cf44 | ||
|
|
27d128bbb4 | ||
|
|
070f9bec58 | ||
|
|
f817032513 | ||
|
|
17abe221c0 | ||
|
|
4a7a81e039 | ||
|
|
37fd4eb643 | ||
|
|
865b0e4c03 | ||
|
|
b324921c1a | ||
|
|
63f72caf30 | ||
|
|
99ac17b90a | ||
|
|
4b0ed9ee88 | ||
|
|
20056f6cda | ||
|
|
3b35279b16 | ||
|
|
27deb44df5 | ||
|
|
24a3ef949b | ||
|
|
bc3e098964 | ||
|
|
c247dcdd7b | ||
|
|
793ae9855e | ||
|
|
9fa426d51b | ||
|
|
cec6288a99 | ||
|
|
9639578c2a | ||
|
|
743ecbd365 | ||
|
|
084c643973 | ||
|
|
824e7682e4 | ||
|
|
f9074684dd | ||
|
|
ddff782133 | ||
|
|
3051152103 | ||
|
|
06026bb47d | ||
|
|
226388ae27 | ||
|
|
ea7548b4cc | ||
|
|
c7486ead96 | ||
|
|
90a291214c | ||
|
|
c111c42a86 | ||
|
|
6fb5b63018 | ||
|
|
ec56dfa35e | ||
|
|
943cd51b67 | ||
|
|
301faa074c | ||
|
|
dc0481e832 | ||
|
|
4f8fcdbaf7 | ||
|
|
b80aa7fee3 | ||
|
|
c384be02c9 | ||
|
|
d17ac3bb40 | ||
|
|
c7554ccac2 | ||
|
|
35ef1c7bae | ||
|
|
d87d0672a8 | ||
|
|
3da42fd1e8 | ||
|
|
503aa61325 | ||
|
|
e4c276d0c2 | ||
|
|
e07f7691a8 | ||
|
|
623ab4a96e | ||
|
|
e1efa337a2 | ||
|
|
549cdf2f7d | ||
|
|
3c522386e9 | ||
|
|
c202aa9ce9 | ||
|
|
e3e28c6231 | ||
|
|
4e05368086 | ||
|
|
e1afe74fe2 | ||
|
|
461acb02f5 | ||
|
|
415edc237c | ||
|
|
e20ecd2574 | ||
|
|
ab477b5631 | ||
|
|
0823d5c7f2 | ||
|
|
1cc6930363 | ||
|
|
4297500928 | ||
|
|
a58f042614 | ||
|
|
469c6bc2b6 | ||
|
|
887074efd2 | ||
|
|
9c2c15ca45 | ||
|
|
1b3b098329 | ||
|
|
6f7075e3aa | ||
|
|
ccbddd8842 | ||
|
|
879dd261c2 | ||
|
|
52f5eb5980 | ||
|
|
ea2f69a0d7 | ||
|
|
9f2064a8ed | ||
|
|
e3750d9ddf | ||
|
|
c1eee3012e | ||
|
|
6b08babbd2 | ||
|
|
215b81342e | ||
|
|
06bfa7e08b | ||
|
|
3d83cbb872 | ||
|
|
8a803b30f6 | ||
|
|
80be649de7 | ||
|
|
9648f950f5 | ||
|
|
6b9ffc8bec | ||
|
|
d903053faf | ||
|
|
676f1b5a26 | ||
|
|
b8dec12f15 | ||
|
|
fc9b223acc | ||
|
|
ba824089d7 | ||
|
|
1a2faf09e0 | ||
|
|
5a43bb8149 | ||
|
|
0104614656 | ||
|
|
77a77f6d2d | ||
|
|
089b9daa1c | ||
|
|
ba34ea4ee8 | ||
|
|
2917b8a005 | ||
|
|
dcf24d45a2 | ||
|
|
75fdb06696 | ||
|
|
e00ad37580 | ||
|
|
5cfb70c2b4 | ||
|
|
2a70c45697 | ||
|
|
c58b00580e | ||
|
|
7c60e69c33 | ||
|
|
33e94891ee | ||
|
|
73e0729f63 | ||
|
|
21c529229c | ||
|
|
63643e6386 | ||
|
|
6cc2edce99 | ||
|
|
d122ff3ca8 | ||
|
|
14c6d526b4 | ||
|
|
28e07bca16 | ||
|
|
faa5f1d802 | ||
|
|
9d3365df54 | ||
|
|
6ff84d34d1 | ||
|
|
b845425cd0 | ||
|
|
89519c88e2 | ||
|
|
ff813bf99d | ||
|
|
cf475bcb50 | ||
|
|
bc80d7c789 | ||
|
|
b7566f6961 | ||
|
|
0542fdb8e4 | ||
|
|
78c474c744 | ||
|
|
88411a1f52 | ||
|
|
ae6cf70bc4 | ||
|
|
68d1281759 | ||
|
|
0308d60cb2 | ||
|
|
59f5fdbb33 | ||
|
|
13184f5f80 | ||
|
|
8d9a477edb | ||
|
|
85b4abbf16 | ||
|
|
e42a358da8 | ||
|
|
f008fe4539 | ||
|
|
ddf41d29ef | ||
|
|
3f88a46c4a | ||
|
|
242706ea34 | ||
|
|
a9f5f8683f | ||
|
|
60c2213893 | ||
|
|
eb2d28bca2 | ||
|
|
86f637a246 | ||
|
|
2c07ec4600 | ||
|
|
871d8d67b0 | ||
|
|
7299713195 | ||
|
|
96afa7e108 | ||
|
|
55f57af0b9 | ||
|
|
6b35cd0116 | ||
|
|
99f2229e48 | ||
|
|
b9641048fc | ||
|
|
e9c6c6e609 | ||
|
|
40db42108f | ||
|
|
24bb1387d6 | ||
|
|
d0bd4afb0b | ||
|
|
78ea786abd | ||
|
|
9cac2c9ceb | ||
|
|
0cff3245df | ||
|
|
0e3925db3f | ||
|
|
c9a13d214b | ||
|
|
0954af2d4c | ||
|
|
7c1c952f5a | ||
|
|
a6edfc730a | ||
|
|
c1264bfedc | ||
|
|
90a5b6ceb0 | ||
|
|
eb240ad2e5 | ||
|
|
88c961f37e | ||
|
|
b952376968 | ||
|
|
5dd605d3a2 | ||
|
|
9c0c98b1ed | ||
|
|
615867322d | ||
|
|
02d3cd5909 | ||
|
|
47e5af15ea | ||
|
|
a5c239c174 | ||
|
|
c2afc5ca44 | ||
|
|
cee062d4c9 | ||
|
|
b21dc8cbe0 | ||
|
|
e1133a2dcb | ||
|
|
e273fec93c | ||
|
|
95d0b073bd | ||
|
|
9c7d841b37 | ||
|
|
f086bf5310 | ||
|
|
6613d7b7ad | ||
|
|
6adf130bf3 | ||
|
|
b6b2eaf5bc | ||
|
|
eb4b7c70a9 | ||
|
|
84661ea6ed | ||
|
|
041122908c | ||
|
|
401de608df | ||
|
|
726c64cf10 | ||
|
|
e1f781a21a | ||
|
|
72b81badad | ||
|
|
17428a8fbf | ||
|
|
6e1879dfae | ||
|
|
eb1d2e04bc | ||
|
|
c909ffa758 | ||
|
|
ff5677ad19 | ||
|
|
8b1b31ac20 | ||
|
|
953600c177 | ||
|
|
536e7eb7f2 | ||
|
|
6d66721ba1 | ||
|
|
3b29cd0bdc | ||
|
|
109b624dfe | ||
|
|
0ed70c4d9f | ||
|
|
a50b7591ca | ||
|
|
bf8fc11b53 | ||
|
|
bc4a613b6d | ||
|
|
4bb001351c | ||
|
|
e155ba44bb | ||
|
|
a4a9637738 | ||
|
|
5292142046 | ||
|
|
cc5147ad72 | ||
|
|
fffbf1a669 | ||
|
|
d37bc0fb4d | ||
|
|
6d60dc8839 | ||
|
|
b713a3a651 | ||
|
|
7e8db1dc68 | ||
|
|
316add860b | ||
|
|
79ce6f1745 | ||
|
|
09fdf4eacd | ||
|
|
143b2dd15a | ||
|
|
e2c4e9d95c | ||
|
|
d87082f04b | ||
|
|
cc14855ba0 | ||
|
|
56c418745f | ||
|
|
4ce9911837 | ||
|
|
559c407552 | ||
|
|
a2f4e29a7b | ||
|
|
b8cf739d27 | ||
|
|
aec2f9521d | ||
|
|
7b55ecdc59 | ||
|
|
e9575bcb78 | ||
|
|
308aeb187b | ||
|
|
05d18f2bc5 | ||
|
|
3da4a0ac69 | ||
|
|
9d12b3f20e | ||
|
|
852a374748 | ||
|
|
3b5bab3308 | ||
|
|
69e75f4a67 | ||
|
|
b0fd4befb1 | ||
|
|
3e80666a74 | ||
|
|
3e4567bae8 | ||
|
|
db075d8cf9 | ||
|
|
16df0ef37e | ||
|
|
f1a2ac5108 | ||
|
|
e5743b358d | ||
|
|
1184bbe4cb | ||
|
|
9dcffda7ae | ||
|
|
e5903635e2 | ||
|
|
510b4eaaae | ||
|
|
d7e63b4316 | ||
|
|
e5dd410256 | ||
|
|
951e46929e | ||
|
|
c8adac30f4 | ||
|
|
b2b4f7635f | ||
|
|
649b1d2172 | ||
|
|
dc5f9ba164 |
@@ -0,0 +1,26 @@
|
|||||||
|
name: CIFuzz
|
||||||
|
on: [pull_request]
|
||||||
|
jobs:
|
||||||
|
Fuzzing:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Build Fuzzers
|
||||||
|
id: build
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'cpp-httplib'
|
||||||
|
dry-run: false
|
||||||
|
language: c++
|
||||||
|
- name: Run Fuzzers
|
||||||
|
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
|
||||||
|
with:
|
||||||
|
oss-fuzz-project-name: 'cpp-httplib'
|
||||||
|
fuzz-seconds: 600
|
||||||
|
dry-run: false
|
||||||
|
language: c++
|
||||||
|
- name: Upload Crash
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
if: failure() && steps.build.outcome == 'success'
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: ./out/artifacts
|
||||||
@@ -20,16 +20,19 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: install brotli library on ubuntu
|
- name: install brotli library on ubuntu
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
run: sudo apt-get install -y libbrotli-dev
|
run: sudo apt update && sudo apt-get install -y libbrotli-dev
|
||||||
- name: install brotli library on macOS
|
- name: install brotli library on macOS
|
||||||
if: matrix.os == 'macOS-latest'
|
if: matrix.os == 'macOS-latest'
|
||||||
run: brew install brotli
|
run: brew install brotli
|
||||||
- name: make
|
- name: make
|
||||||
if: matrix.os != 'windows-latest'
|
if: matrix.os != 'windows-latest'
|
||||||
run: cd test && make
|
run: cd test && make -j2
|
||||||
|
- name: check fuzz test target
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: cd test && make fuzz_test
|
||||||
- name: setup msbuild on windows
|
- name: setup msbuild on windows
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
uses: warrenbuckley/Setup-MSBuild@v1
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
- name: make-windows
|
- name: make-windows
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -10,10 +10,15 @@ example/redirect
|
|||||||
example/sse*
|
example/sse*
|
||||||
example/upload
|
example/upload
|
||||||
example/*.pem
|
example/*.pem
|
||||||
|
test/httplib.cc
|
||||||
|
test/httplib.h
|
||||||
test/test
|
test/test
|
||||||
|
test/server_fuzzer
|
||||||
test/test_proxy
|
test/test_proxy
|
||||||
|
test/test_split
|
||||||
test/test.xcodeproj/xcuser*
|
test/test.xcodeproj/xcuser*
|
||||||
test/test.xcodeproj/*/xcuser*
|
test/test.xcodeproj/*/xcuser*
|
||||||
|
test/*.o
|
||||||
test/*.pem
|
test/*.pem
|
||||||
test/*.srl
|
test/*.srl
|
||||||
|
|
||||||
|
|||||||
+28
-50
@@ -8,6 +8,7 @@
|
|||||||
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
|
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
|
||||||
* HTTPLIB_REQUIRE_BROTLI (default off)
|
* HTTPLIB_REQUIRE_BROTLI (default off)
|
||||||
* HTTPLIB_COMPILE (default off)
|
* HTTPLIB_COMPILE (default off)
|
||||||
|
* HTTPLIB_TEST (default off)
|
||||||
* BROTLI_USE_STATIC_LIBS - tells Cmake to use the static Brotli libs (only works if you have them installed).
|
* BROTLI_USE_STATIC_LIBS - tells Cmake to use the static Brotli libs (only works if you have them installed).
|
||||||
* OPENSSL_USE_STATIC_LIBS - tells Cmake to use the static OpenSSL libs (only works if you have them installed).
|
* OPENSSL_USE_STATIC_LIBS - tells Cmake to use the static OpenSSL libs (only works if you have them installed).
|
||||||
|
|
||||||
@@ -60,26 +61,11 @@
|
|||||||
]]
|
]]
|
||||||
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
||||||
|
|
||||||
# On systems without Git installed, there were errors since execute_process seemed to not throw an error without it?
|
# Get the CPPHTTPLIB_VERSION value and use it as a version
|
||||||
find_package(Git QUIET)
|
# This gets the string with the CPPHTTPLIB_VERSION value from the header.
|
||||||
if(Git_FOUND)
|
# This is so the maintainer doesn't actually need to update this manually.
|
||||||
# Gets the latest tag as a string like "v0.6.6"
|
file(STRINGS httplib.h _raw_version_string REGEX "CPPHTTPLIB_VERSION \"([0-9]+\\.[0-9]+\\.[0-9]+)\"")
|
||||||
# Can silently fail if git isn't on the system
|
|
||||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
|
|
||||||
OUTPUT_VARIABLE _raw_version_string
|
|
||||||
ERROR_VARIABLE _git_tag_error
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# execute_process can fail silenty, so check for an error
|
|
||||||
# if there was an error, just use the user agent as a version
|
|
||||||
if(_git_tag_error OR NOT Git_FOUND)
|
|
||||||
message(WARNING "cpp-httplib failed to find the latest Git tag, falling back to using user agent as the version.")
|
|
||||||
# Get the user agent and use it as a version
|
|
||||||
# This gets the string with the user agent from the header.
|
|
||||||
# This is so the maintainer doesn't actually need to update this manually.
|
|
||||||
file(STRINGS httplib.h _raw_version_string REGEX "User\-Agent.*cpp\-httplib/([0-9]+\.?)+")
|
|
||||||
endif()
|
|
||||||
# Needed since git tags have "v" prefixing them.
|
# Needed since git tags have "v" prefixing them.
|
||||||
# Also used if the fallback to user agent string is being used.
|
# Also used if the fallback to user agent string is being used.
|
||||||
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
|
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
|
||||||
@@ -103,7 +89,7 @@ option(HTTPLIB_COMPILE "If ON, uses a Python script to split the header into a c
|
|||||||
if(HTTPLIB_COMPILE)
|
if(HTTPLIB_COMPILE)
|
||||||
set(HTTPLIB_IS_COMPILED TRUE)
|
set(HTTPLIB_IS_COMPILED TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
option(HTTPLIB_TEST "Enables testing and builds tests" OFF)
|
||||||
option(HTTPLIB_REQUIRE_BROTLI "Requires Brotli to be found & linked, or fails build." OFF)
|
option(HTTPLIB_REQUIRE_BROTLI "Requires Brotli to be found & linked, or fails build." OFF)
|
||||||
option(HTTPLIB_USE_BROTLI_IF_AVAILABLE "Uses Brotli (if available) to enable Brotli decompression support." ON)
|
option(HTTPLIB_USE_BROTLI_IF_AVAILABLE "Uses Brotli (if available) to enable Brotli decompression support." ON)
|
||||||
# Defaults to static library
|
# Defaults to static library
|
||||||
@@ -115,6 +101,7 @@ if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
|
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG true)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
|
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
|
||||||
if(HTTPLIB_REQUIRE_OPENSSL)
|
if(HTTPLIB_REQUIRE_OPENSSL)
|
||||||
@@ -175,7 +162,7 @@ if(HTTPLIB_COMPILE)
|
|||||||
ERROR_VARIABLE _httplib_split_error
|
ERROR_VARIABLE _httplib_split_error
|
||||||
)
|
)
|
||||||
if(_httplib_split_error)
|
if(_httplib_split_error)
|
||||||
message(FATAL_ERROR "Failed when trying to split Cpp-httplib with the Python script.\n${_httplib_split_error}")
|
message(FATAL_ERROR "Failed when trying to split cpp-httplib with the Python script.\n${_httplib_split_error}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# split.py puts output in "out"
|
# split.py puts output in "out"
|
||||||
@@ -187,6 +174,11 @@ if(HTTPLIB_COMPILE)
|
|||||||
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
|
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
|
||||||
)
|
)
|
||||||
|
set_target_properties(${PROJECT_NAME}
|
||||||
|
PROPERTIES
|
||||||
|
VERSION ${${PROJECT_NAME}_VERSION}
|
||||||
|
SOVERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}"
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
# This is for header-only.
|
# This is for header-only.
|
||||||
set(_INTERFACE_OR_PUBLIC INTERFACE)
|
set(_INTERFACE_OR_PUBLIC INTERFACE)
|
||||||
@@ -197,22 +189,12 @@ endif()
|
|||||||
# Only useful if building in-tree, versus using it from an installation.
|
# Only useful if building in-tree, versus using it from an installation.
|
||||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||||
|
|
||||||
# Might be missing some, but this list is somewhat comprehensive
|
# Require C++11
|
||||||
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||||
cxx_std_11
|
cxx_std_11
|
||||||
cxx_nullptr
|
|
||||||
cxx_lambdas
|
|
||||||
cxx_override
|
|
||||||
cxx_defaulted_functions
|
|
||||||
cxx_attribute_deprecated
|
|
||||||
cxx_auto_type
|
|
||||||
cxx_decltype
|
|
||||||
cxx_deleted_functions
|
|
||||||
cxx_range_for
|
|
||||||
cxx_sizeof_member
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
target_include_directories(${PROJECT_NAME} SYSTEM ${_INTERFACE_OR_PUBLIC}
|
||||||
$<BUILD_INTERFACE:${_httplib_build_includedir}>
|
$<BUILD_INTERFACE:${_httplib_build_includedir}>
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
)
|
)
|
||||||
@@ -235,20 +217,13 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
|||||||
|
|
||||||
# Set the definitions to enable optional features
|
# Set the definitions to enable optional features
|
||||||
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:"CPPHTTPLIB_BROTLI_SUPPORT">
|
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:CPPHTTPLIB_BROTLI_SUPPORT>
|
||||||
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:"CPPHTTPLIB_ZLIB_SUPPORT">
|
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:CPPHTTPLIB_ZLIB_SUPPORT>
|
||||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:"CPPHTTPLIB_OPENSSL_SUPPORT">
|
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:CPPHTTPLIB_OPENSSL_SUPPORT>
|
||||||
)
|
)
|
||||||
|
|
||||||
# Cmake's find_package search path is different based on the system
|
# CMake configuration files installation directory
|
||||||
# See https://cmake.org/cmake/help/latest/command/find_package.html for the list
|
set(_TARGET_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|
||||||
set(_TARGET_INSTALL_CMAKEDIR "${CMAKE_INSTALL_PREFIX}/cmake/${PROJECT_NAME}")
|
|
||||||
else()
|
|
||||||
# On Non-Windows, it should be /usr/lib/cmake/<name>/<name>Config.cmake
|
|
||||||
# NOTE: This may or may not work for macOS...
|
|
||||||
set(_TARGET_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
@@ -266,13 +241,13 @@ if(HTTPLIB_COMPILE)
|
|||||||
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
|
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
|
||||||
# Example: if you find_package(httplib 0.5.4)
|
# Example: if you find_package(httplib 0.5.4)
|
||||||
# then anything >= 0.5 and <= 1.0 is accepted
|
# then anything >= 0.5 and <= 1.0 is accepted
|
||||||
COMPATIBILITY SameMajorVersion
|
COMPATIBILITY SameMinorVersion
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
|
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
|
||||||
# Example: if you find_package(httplib 0.5.4)
|
# Example: if you find_package(httplib 0.5.4)
|
||||||
# then anything >= 0.5 and <= 1.0 is accepted
|
# then anything >= 0.5 and <= 1.0 is accepted
|
||||||
COMPATIBILITY SameMajorVersion
|
COMPATIBILITY SameMinorVersion
|
||||||
# Tells Cmake that it's a header-only lib
|
# Tells Cmake that it's a header-only lib
|
||||||
# Mildly useful for end-users :)
|
# Mildly useful for end-users :)
|
||||||
ARCH_INDEPENDENT
|
ARCH_INDEPENDENT
|
||||||
@@ -284,11 +259,9 @@ endif()
|
|||||||
# and linkage information (doesn't find deps though).
|
# and linkage information (doesn't find deps though).
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
EXPORT httplibTargets
|
EXPORT httplibTargets
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
install(FILES "${_httplib_build_includedir}/httplib.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
install(FILES "${_httplib_build_includedir}/httplib.h" TYPE INCLUDE)
|
||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||||
@@ -306,3 +279,8 @@ install(EXPORT httplibTargets
|
|||||||
NAMESPACE ${PROJECT_NAME}::
|
NAMESPACE ${PROJECT_NAME}::
|
||||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(HTTPLIB_TEST)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -5,10 +5,79 @@ cpp-httplib
|
|||||||
|
|
||||||
A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
||||||
|
|
||||||
It's extremely easy to setup. Just include **httplib.h** file in your code!
|
It's extremely easy to setup. Just include the **httplib.h** file in your code!
|
||||||
|
|
||||||
Server Example
|
NOTE: This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
|
||||||
--------------
|
|
||||||
|
Simple examples
|
||||||
|
---------------
|
||||||
|
|
||||||
|
#### Server (Multi-threaded)
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
#include "path/to/httplib.h"
|
||||||
|
|
||||||
|
// HTTP
|
||||||
|
httplib::Server svr;
|
||||||
|
|
||||||
|
// HTTPS
|
||||||
|
httplib::SSLServer svr;
|
||||||
|
|
||||||
|
svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) {
|
||||||
|
res.set_content("Hello World!", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.listen("0.0.0.0", 8080);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
#include "path/to/httplib.h"
|
||||||
|
|
||||||
|
// HTTP
|
||||||
|
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
|
||||||
|
|
||||||
|
// HTTPS
|
||||||
|
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
|
||||||
|
|
||||||
|
auto res = cli.Get("/hi");
|
||||||
|
res->status;
|
||||||
|
res->body;
|
||||||
|
```
|
||||||
|
|
||||||
|
SSL Support
|
||||||
|
-----------
|
||||||
|
|
||||||
|
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
|
||||||
|
|
||||||
|
NOTE: cpp-httplib currently supports only version 1.1.1 and 3.0.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
#include "path/to/httplib.h"
|
||||||
|
|
||||||
|
// Server
|
||||||
|
httplib::SSLServer svr("./cert.pem", "./key.pem");
|
||||||
|
|
||||||
|
// Client
|
||||||
|
httplib::Client cli("https://localhost:1234"); // scheme + host
|
||||||
|
httplib::SSLClient cli("localhost:1234"); // host
|
||||||
|
httplib::SSLClient cli("localhost", 1234); // host, port
|
||||||
|
|
||||||
|
// Use your CA bundle
|
||||||
|
cli.set_ca_cert_path("./ca-bundle.crt");
|
||||||
|
|
||||||
|
// Disable cert verification
|
||||||
|
cli.enable_server_certificate_verification(false);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
|
||||||
|
|
||||||
|
Server
|
||||||
|
------
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#include <httplib.h>
|
#include <httplib.h>
|
||||||
@@ -87,24 +156,39 @@ svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");
|
|||||||
|
|
||||||
The followings are built-in mappings:
|
The followings are built-in mappings:
|
||||||
|
|
||||||
| Extension | MIME Type |
|
| Extension | MIME Type | Extension | MIME Type |
|
||||||
| :-------- | :--------------------- |
|
| :--------- | :-------------------------- | :--------- | :-------------------------- |
|
||||||
| txt | text/plain |
|
| css | text/css | mpga | audio/mpeg |
|
||||||
| html, htm | text/html |
|
| csv | text/csv | weba | audio/webm |
|
||||||
| css | text/css |
|
| txt | text/plain | wav | audio/wave |
|
||||||
| jpeg, jpg | image/jpg |
|
| vtt | text/vtt | otf | font/otf |
|
||||||
| png | image/png |
|
| html, htm | text/html | ttf | font/ttf |
|
||||||
| gif | image/gif |
|
| apng | image/apng | woff | font/woff |
|
||||||
| svg | image/svg+xml |
|
| avif | image/avif | woff2 | font/woff2 |
|
||||||
| ico | image/x-icon |
|
| bmp | image/bmp | 7z | application/x-7z-compressed |
|
||||||
| json | application/json |
|
| gif | image/gif | atom | application/atom+xml |
|
||||||
| pdf | application/pdf |
|
| png | image/png | pdf | application/pdf |
|
||||||
| js | application/javascript |
|
| svg | image/svg+xml | mjs, js | application/javascript |
|
||||||
| wasm | application/wasm |
|
| webp | image/webp | json | application/json |
|
||||||
| xml | application/xml |
|
| ico | image/x-icon | rss | application/rss+xml |
|
||||||
| xhtml | application/xhtml+xml |
|
| tif | image/tiff | tar | application/x-tar |
|
||||||
|
| tiff | image/tiff | xhtml, xht | application/xhtml+xml |
|
||||||
|
| jpeg, jpg | image/jpeg | xslt | application/xslt+xml |
|
||||||
|
| mp4 | video/mp4 | xml | application/xml |
|
||||||
|
| mpeg | video/mpeg | gz | application/gzip |
|
||||||
|
| webm | video/webm | zip | application/zip |
|
||||||
|
| mp3 | audio/mp3 | wasm | application/wasm |
|
||||||
|
|
||||||
NOTE: These the static file server methods are not thread safe.
|
### File request handler
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// The handler is called right before the response is sent to a client
|
||||||
|
svr.set_file_request_handler([](const Request &req, Response &res) {
|
||||||
|
...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: These static file server methods are not thread-safe.
|
||||||
|
|
||||||
### Logging
|
### Logging
|
||||||
|
|
||||||
@@ -125,6 +209,47 @@ svr.set_error_handler([](const auto& req, auto& res) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Exception handler
|
||||||
|
The exception handler gets called if a user routing handler throws an error.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_exception_handler([](const auto& req, auto& res, std::exception_ptr ep) {
|
||||||
|
auto fmt = "<h1>Error 500</h1><p>%s</p>";
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ep);
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
snprintf(buf, sizeof(buf), fmt, e.what());
|
||||||
|
} catch (...) { // See the following NOTE
|
||||||
|
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
|
||||||
|
}
|
||||||
|
res.set_content(buf, "text/html");
|
||||||
|
res.status = 500;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: if you don't provide the `catch (...)` block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!
|
||||||
|
|
||||||
|
### Pre routing handler
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_pre_routing_handler([](const auto& req, auto& res) {
|
||||||
|
if (req.path == "/hello") {
|
||||||
|
res.set_content("world", "text/html");
|
||||||
|
return Server::HandlerResponse::Handled;
|
||||||
|
}
|
||||||
|
return Server::HandlerResponse::Unhandled;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post routing handler
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_post_routing_handler([](const auto& req, auto& res) {
|
||||||
|
res.set_header("ADDITIONAL_HEADER", "value");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### 'multipart/form-data' POST data
|
### 'multipart/form-data' POST data
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -138,12 +263,13 @@ svr.Post("/multipart", [&](const auto& req, auto& res) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Receive content with Content receiver
|
### Receive content with a content receiver
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.Post("/content_receiver",
|
svr.Post("/content_receiver",
|
||||||
[&](const Request &req, Response &res, const ContentReader &content_reader) {
|
[&](const Request &req, Response &res, const ContentReader &content_reader) {
|
||||||
if (req.is_multipart_form_data()) {
|
if (req.is_multipart_form_data()) {
|
||||||
|
// NOTE: `content_reader` is blocking until every form data field is read
|
||||||
MultipartFormDataItems files;
|
MultipartFormDataItems files;
|
||||||
content_reader(
|
content_reader(
|
||||||
[&](const MultipartFormData &file) {
|
[&](const MultipartFormData &file) {
|
||||||
@@ -160,12 +286,11 @@ svr.Post("/content_receiver",
|
|||||||
body.append(data, data_length);
|
body.append(data, data_length);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
res.set_content(body, "text/plain");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Send content with Content provider
|
### Send content with the content provider
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
const size_t DATA_CHUNK_SIZE = 4;
|
const size_t DATA_CHUNK_SIZE = 4;
|
||||||
@@ -175,12 +300,32 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
|
|
||||||
res.set_content_provider(
|
res.set_content_provider(
|
||||||
data->size(), // Content length
|
data->size(), // Content length
|
||||||
|
"text/plain", // Content type
|
||||||
[data](size_t offset, size_t length, DataSink &sink) {
|
[data](size_t offset, size_t length, DataSink &sink) {
|
||||||
const auto &d = *data;
|
const auto &d = *data;
|
||||||
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||||
return true; // return 'false' if you want to cancel the process.
|
return true; // return 'false' if you want to cancel the process.
|
||||||
},
|
},
|
||||||
[data] { delete data; });
|
[data](bool success) { delete data; });
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Without content length:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||||
|
res.set_content_provider(
|
||||||
|
"text/plain", // Content type
|
||||||
|
[&](size_t offset, DataSink &sink) {
|
||||||
|
if (/* there is still data */) {
|
||||||
|
std::vector<char> data;
|
||||||
|
// prepare data...
|
||||||
|
sink.write(data.data(), data.size());
|
||||||
|
} else {
|
||||||
|
sink.done(); // No more data
|
||||||
|
}
|
||||||
|
return true; // return 'false' if you want to cancel the process.
|
||||||
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -189,11 +334,12 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||||
res.set_chunked_content_provider(
|
res.set_chunked_content_provider(
|
||||||
|
"text/plain",
|
||||||
[](size_t offset, DataSink &sink) {
|
[](size_t offset, DataSink &sink) {
|
||||||
sink.write("123", 3);
|
sink.write("123", 3);
|
||||||
sink.write("345", 3);
|
sink.write("345", 3);
|
||||||
sink.write("789", 3);
|
sink.write("789", 3);
|
||||||
sink.done();
|
sink.done(); // No more data
|
||||||
return true; // return 'false' if you want to cancel the process.
|
return true; // return 'false' if you want to cancel the process.
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -202,7 +348,7 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
|
|||||||
|
|
||||||
### 'Expect: 100-continue' handler
|
### 'Expect: 100-continue' handler
|
||||||
|
|
||||||
As default, the server sends `100 Continue` response for `Expect: 100-continue` header.
|
By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// Send a '417 Expectation Failed' response.
|
// Send a '417 Expectation Failed' response.
|
||||||
@@ -222,6 +368,7 @@ svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.set_keep_alive_max_count(2); // Default is 5
|
svr.set_keep_alive_max_count(2); // Default is 5
|
||||||
|
svr.set_keep_alive_timeout(10); // Default is 5
|
||||||
```
|
```
|
||||||
|
|
||||||
### Timeout
|
### Timeout
|
||||||
@@ -232,7 +379,7 @@ svr.set_write_timeout(5, 0); // 5 seconds
|
|||||||
svr.set_idle_interval(0, 100000); // 100 milliseconds
|
svr.set_idle_interval(0, 100000); // 100 milliseconds
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set maximum payload length for reading request body
|
### Set maximum payload length for reading a request body
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
|
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
|
||||||
@@ -244,13 +391,18 @@ Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/e
|
|||||||
|
|
||||||
### Default thread pool support
|
### Default thread pool support
|
||||||
|
|
||||||
|
`ThreadPool` is used as a **default** task queue, and the default thread count is 8, or `std::thread::hardware_concurrency()`. You can change it with `CPPHTTPLIB_THREAD_POOL_COUNT`.
|
||||||
|
|
||||||
`ThreadPool` is used as a default task queue, and the default thread count is set to value from `std::thread::hardware_concurrency()`.
|
If you want to set the thread count at runtime, there is no convenient way... But here is how.
|
||||||
|
|
||||||
You can change the thread count by setting `CPPHTTPLIB_THREAD_POOL_COUNT`.
|
```cpp
|
||||||
|
svr.new_task_queue = [] { return new ThreadPool(12); };
|
||||||
|
```
|
||||||
|
|
||||||
### Override the default thread pool with yours
|
### Override the default thread pool with yours
|
||||||
|
|
||||||
|
You can supply your own thread pool implementation according to your need.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
class YourThreadPoolTaskQueue : public TaskQueue {
|
class YourThreadPoolTaskQueue : public TaskQueue {
|
||||||
public:
|
public:
|
||||||
@@ -275,8 +427,8 @@ svr.new_task_queue = [] {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Client Example
|
Client
|
||||||
--------------
|
------
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#include <httplib.h>
|
#include <httplib.h>
|
||||||
@@ -286,9 +438,13 @@ int main(void)
|
|||||||
{
|
{
|
||||||
httplib::Client cli("localhost", 1234);
|
httplib::Client cli("localhost", 1234);
|
||||||
|
|
||||||
auto res = cli.Get("/hi");
|
if (auto res = cli.Get("/hi")) {
|
||||||
if (res && res->status == 200) {
|
if (res->status == 200) {
|
||||||
std::cout << res->body << std::endl;
|
std::cout << res->body << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto err = res.error();
|
||||||
|
std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -301,6 +457,30 @@ httplib::Client cli("localhost:8080");
|
|||||||
httplib::Client cli("http://localhost");
|
httplib::Client cli("http://localhost");
|
||||||
httplib::Client cli("http://localhost:8080");
|
httplib::Client cli("http://localhost:8080");
|
||||||
httplib::Client cli("https://localhost");
|
httplib::Client cli("https://localhost");
|
||||||
|
httplib::SSLClient cli("localhost");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error code
|
||||||
|
|
||||||
|
Here is the list of errors from `Result::error()`.
|
||||||
|
|
||||||
|
```c++
|
||||||
|
enum Error {
|
||||||
|
Success = 0,
|
||||||
|
Unknown,
|
||||||
|
Connection,
|
||||||
|
BindIPAddress,
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
ExceedRedirectCount,
|
||||||
|
Canceled,
|
||||||
|
SSLConnection,
|
||||||
|
SSLLoadingCerts,
|
||||||
|
SSLServerVerification,
|
||||||
|
UnsupportedMultipartBoundaryChars,
|
||||||
|
Compression,
|
||||||
|
ConnectionTimeout,
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### GET with HTTP headers
|
### GET with HTTP headers
|
||||||
@@ -313,6 +493,10 @@ auto res = cli.Get("/hi", headers);
|
|||||||
```
|
```
|
||||||
or
|
or
|
||||||
```c++
|
```c++
|
||||||
|
auto res = cli.Get("/hi", {{"Accept-Encoding", "gzip, deflate"}});
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```c++
|
||||||
cli.set_default_headers({
|
cli.set_default_headers({
|
||||||
{ "Accept-Encoding", "gzip, deflate" }
|
{ "Accept-Encoding", "gzip, deflate" }
|
||||||
});
|
});
|
||||||
@@ -387,7 +571,7 @@ cli.set_read_timeout(5, 0); // 5 seconds
|
|||||||
cli.set_write_timeout(5, 0); // 5 seconds
|
cli.set_write_timeout(5, 0); // 5 seconds
|
||||||
```
|
```
|
||||||
|
|
||||||
### Receive content with Content receiver
|
### Receive content with a content receiver
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
std::string body;
|
std::string body;
|
||||||
@@ -414,12 +598,12 @@ auto res = cli.Get(
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Send content with Content provider
|
### Send content with a content provider
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::string body = ...;
|
std::string body = ...;
|
||||||
|
|
||||||
auto res = cli_.Post(
|
auto res = cli.Post(
|
||||||
"/stream", body.size(),
|
"/stream", body.size(),
|
||||||
[](size_t offset, size_t length, DataSink &sink) {
|
[](size_t offset, size_t length, DataSink &sink) {
|
||||||
sink.write(body.data() + offset, length);
|
sink.write(body.data() + offset, length);
|
||||||
@@ -428,19 +612,33 @@ auto res = cli_.Post(
|
|||||||
"text/plain");
|
"text/plain");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Chunked transfer encoding
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto res = cli.Post(
|
||||||
|
"/stream",
|
||||||
|
[](size_t offset, DataSink &sink) {
|
||||||
|
sink.os << "chunked data 1";
|
||||||
|
sink.os << "chunked data 2";
|
||||||
|
sink.os << "chunked data 3";
|
||||||
|
sink.done();
|
||||||
|
return true; // return 'false' if you want to cancel the request.
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
```
|
||||||
|
|
||||||
### With Progress Callback
|
### With Progress Callback
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
httplib::Client client(url, port);
|
httplib::Client client(url, port);
|
||||||
|
|
||||||
// prints: 0 / 000 bytes => 50% complete
|
// prints: 0 / 000 bytes => 50% complete
|
||||||
std::shared_ptr<httplib::Response> res =
|
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
|
||||||
cli.Get("/", [](uint64_t len, uint64_t total) {
|
printf("%lld / %lld bytes => %d%% complete\n",
|
||||||
printf("%lld / %lld bytes => %d%% complete\n",
|
len, total,
|
||||||
len, total,
|
(int)(len*100/total));
|
||||||
(int)(len*100/total));
|
return true; // return 'false' if you want to cancel the request.
|
||||||
return true; // return 'false' if you want to cancel the request.
|
}
|
||||||
}
|
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -523,7 +721,7 @@ res = cli.Get("/");
|
|||||||
res->status; // 200
|
res->status; // 200
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use a specitic network interface
|
### Use a specific network interface
|
||||||
|
|
||||||
NOTE: This feature is not available on Windows, yet.
|
NOTE: This feature is not available on Windows, yet.
|
||||||
|
|
||||||
@@ -531,27 +729,10 @@ NOTE: This feature is not available on Windows, yet.
|
|||||||
cli.set_interface("eth0"); // Interface name, IP address or host name
|
cli.set_interface("eth0"); // Interface name, IP address or host name
|
||||||
```
|
```
|
||||||
|
|
||||||
OpenSSL Support
|
|
||||||
---------------
|
|
||||||
|
|
||||||
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
|
|
||||||
|
|
||||||
NOTE: cpp-httplib currently supports only version 1.1.1.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
|
||||||
|
|
||||||
SSLServer svr("./cert.pem", "./key.pem");
|
|
||||||
|
|
||||||
SSLClient cli("localhost", 8080);
|
|
||||||
cli.set_ca_cert_path("./ca-bundle.crt");
|
|
||||||
cli.enable_server_certificate_verification(true);
|
|
||||||
```
|
|
||||||
|
|
||||||
Compression
|
Compression
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The server can applie compression to the following MIME type contents:
|
The server can apply compression to the following MIME type contents:
|
||||||
|
|
||||||
* all text types except text/event-stream
|
* all text types except text/event-stream
|
||||||
* image/svg+xml
|
* image/svg+xml
|
||||||
@@ -584,13 +765,29 @@ res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
|
|||||||
res->body; // Compressed data
|
res->body; // Compressed data
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Use `poll` instead of `select`
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
`select` system call is used as default since it's more widely supported. If you want to let cpp-httplib use `poll` instead, you can do so with `CPPHTTPLIB_USE_POLL`.
|
||||||
|
|
||||||
|
|
||||||
Split httplib.h into .h and .cc
|
Split httplib.h into .h and .cc
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
```bash
|
```console
|
||||||
> python3 split.py
|
$ ./split.py -h
|
||||||
> ls out
|
usage: split.py [-h] [-e EXTENSION] [-o OUT]
|
||||||
httplib.h httplib.cc
|
|
||||||
|
This script splits httplib.h into .h and .cc parts.
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-e EXTENSION, --extension EXTENSION
|
||||||
|
extension of the implementation file (default: cc)
|
||||||
|
-o OUT, --out OUT where to write the files (default: out)
|
||||||
|
|
||||||
|
$ ./split.py
|
||||||
|
Wrote out/httplib.h and out/httplib.cc
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE
|
NOTE
|
||||||
@@ -615,12 +812,14 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
|
|||||||
#include <httplib.h>
|
#include <httplib.h>
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: Cygwin on Windows is not supported.
|
Note: cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
|
||||||
|
|
||||||
|
Note: Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin on Windows are not supported.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
MIT license (© 2020 Yuji Hirose)
|
MIT license (© 2022 Yuji Hirose)
|
||||||
|
|
||||||
Special Thanks To
|
Special Thanks To
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM alpine as builder
|
||||||
|
WORKDIR /src/example
|
||||||
|
RUN apk add g++ make openssl-dev zlib-dev brotli-dev
|
||||||
|
COPY ./httplib.h /src
|
||||||
|
COPY ./example/hello.cc /src/example
|
||||||
|
COPY ./example/Makefile /src/example
|
||||||
|
RUN make hello
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
RUN apk --no-cache add brotli libstdc++
|
||||||
|
COPY --from=builder /src/example/hello /bin/hello
|
||||||
|
CMD ["/bin/hello"]
|
||||||
+9
-6
@@ -1,14 +1,17 @@
|
|||||||
|
|
||||||
#CXX = clang++
|
#CXX = clang++
|
||||||
CXXFLAGS = -std=c++11 -I.. -Wall -Wextra -pthread
|
CXXFLAGS = -O2 -std=c++11 -I.. -Wall -Wextra -pthread
|
||||||
|
|
||||||
OPENSSL_DIR = /usr/local/opt/openssl
|
PREFIX = /usr/local
|
||||||
|
#PREFIX = $(shell brew --prefix)
|
||||||
|
|
||||||
|
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
|
||||||
|
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
|
||||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||||
|
|
||||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||||
|
|
||||||
BROTLI_DIR = /usr/local/opt/brotli
|
BROTLI_DIR = $(PREFIX)/opt/brotli
|
||||||
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon-static -lbrotlienc-static -lbrotlidec-static
|
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||||
|
|
||||||
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark
|
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark
|
||||||
|
|
||||||
@@ -47,4 +50,4 @@ pem:
|
|||||||
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm server client hello simplecli simplesvr upload redirect ssesvr sselci benchmark *.pem
|
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark *.pem
|
||||||
|
|||||||
+2
-2
@@ -23,12 +23,12 @@ int main(void) {
|
|||||||
httplib::Client cli("localhost", 8080);
|
httplib::Client cli("localhost", 8080);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto res = cli.Get("/hi");
|
if (auto res = cli.Get("/hi")) {
|
||||||
if (res) {
|
|
||||||
cout << res->status << endl;
|
cout << res->status << endl;
|
||||||
cout << res->get_header_value("Content-Type") << endl;
|
cout << res->get_header_value("Content-Type") << endl;
|
||||||
cout << res->body << endl;
|
cout << res->body << endl;
|
||||||
} else {
|
} else {
|
||||||
|
cout << "error code: " << res.error() << std::endl;
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
auto result = cli.get_openssl_verify_result();
|
auto result = cli.get_openssl_verify_result();
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|||||||
+1
-1
@@ -15,5 +15,5 @@ int main(void) {
|
|||||||
res.set_content("Hello World!", "text/plain");
|
res.set_content("Hello World!", "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.listen("localhost", 8080);
|
svr.listen("0.0.0.0", 8080);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ int main(void) {
|
|||||||
auto scheme_host_port = "http://localhost:8080";
|
auto scheme_host_port = "http://localhost:8080";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto res = httplib::Client(scheme_host_port).Get("/hi");
|
if (auto res = httplib::Client(scheme_host_port).Get("/hi")) {
|
||||||
|
|
||||||
if (res) {
|
|
||||||
cout << res->status << endl;
|
cout << res->status << endl;
|
||||||
cout << res->get_header_value("Content-Type") << endl;
|
cout << res->get_header_value("Content-Type") << endl;
|
||||||
cout << res->body << endl;
|
cout << res->body << endl;
|
||||||
|
} else {
|
||||||
|
cout << res.error() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+3
-12
@@ -1,10 +1,3 @@
|
|||||||
//
|
|
||||||
// sse.cc
|
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Yuji Hirose. All rights reserved.
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@@ -20,15 +13,13 @@ using namespace std;
|
|||||||
class EventDispatcher {
|
class EventDispatcher {
|
||||||
public:
|
public:
|
||||||
EventDispatcher() {
|
EventDispatcher() {
|
||||||
id_ = 0;
|
|
||||||
cid_ = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_event(DataSink *sink) {
|
void wait_event(DataSink *sink) {
|
||||||
unique_lock<mutex> lk(m_);
|
unique_lock<mutex> lk(m_);
|
||||||
int id = id_;
|
int id = id_;
|
||||||
cv_.wait(lk, [&] { return cid_ == id; });
|
cv_.wait(lk, [&] { return cid_ == id; });
|
||||||
if (sink->is_writable()) { sink->write(message_.data(), message_.size()); }
|
sink->write(message_.data(), message_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_event(const string &message) {
|
void send_event(const string &message) {
|
||||||
@@ -41,8 +32,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
mutex m_;
|
mutex m_;
|
||||||
condition_variable cv_;
|
condition_variable cv_;
|
||||||
atomic_int id_;
|
atomic_int id_{0};
|
||||||
atomic_int cid_;
|
atomic_int cid_{-1};
|
||||||
string message_;
|
string message_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#/usr/bin/env bash
|
||||||
|
for i in {1..1000000}
|
||||||
|
do
|
||||||
|
echo "#### $i ####"
|
||||||
|
curl -X POST -F image_file=@$1 http://localhost:1234/post > /dev/null
|
||||||
|
done
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
project(
|
||||||
|
'cpp-httplib',
|
||||||
|
'cpp',
|
||||||
|
license: 'MIT',
|
||||||
|
default_options: [
|
||||||
|
'cpp_std=c++11',
|
||||||
|
'buildtype=release',
|
||||||
|
'b_ndebug=if-release',
|
||||||
|
'b_lto=true',
|
||||||
|
'warning_level=3'
|
||||||
|
],
|
||||||
|
meson_version: '>=0.47.0'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check just in case downstream decides to edit the source
|
||||||
|
# and add a project version
|
||||||
|
version = meson.project_version()
|
||||||
|
if version == 'undefined'
|
||||||
|
cxx = meson.get_compiler('cpp')
|
||||||
|
version = cxx.get_define('CPPHTTPLIB_VERSION',
|
||||||
|
prefix: '#include <httplib.h>',
|
||||||
|
include_directories: include_directories('.')).strip('"')
|
||||||
|
assert(version != '', 'failed to get version from httplib.h')
|
||||||
|
endif
|
||||||
|
|
||||||
|
deps = [dependency('threads')]
|
||||||
|
args = []
|
||||||
|
|
||||||
|
openssl_dep = dependency('openssl', version: '>=1.1.1', required: get_option('cpp-httplib_openssl'))
|
||||||
|
if openssl_dep.found()
|
||||||
|
deps += openssl_dep
|
||||||
|
args += '-DCPPHTTPLIB_OPENSSL_SUPPORT'
|
||||||
|
endif
|
||||||
|
|
||||||
|
zlib_dep = dependency('zlib', required: get_option('cpp-httplib_zlib'))
|
||||||
|
if zlib_dep.found()
|
||||||
|
deps += zlib_dep
|
||||||
|
args += '-DCPPHTTPLIB_ZLIB_SUPPORT'
|
||||||
|
endif
|
||||||
|
|
||||||
|
brotli_deps = [dependency('libbrotlicommon', required: get_option('cpp-httplib_brotli'))]
|
||||||
|
brotli_deps += dependency('libbrotlidec', required: get_option('cpp-httplib_brotli'))
|
||||||
|
brotli_deps += dependency('libbrotlienc', required: get_option('cpp-httplib_brotli'))
|
||||||
|
|
||||||
|
brotli_found_all = true
|
||||||
|
foreach brotli_dep : brotli_deps
|
||||||
|
if not brotli_dep.found()
|
||||||
|
brotli_found_all = false
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
if brotli_found_all
|
||||||
|
deps += brotli_deps
|
||||||
|
args += '-DCPPHTTPLIB_BROTLI_SUPPORT'
|
||||||
|
endif
|
||||||
|
|
||||||
|
cpp_httplib_dep = dependency('', required: false)
|
||||||
|
|
||||||
|
if get_option('cpp-httplib_compile')
|
||||||
|
python3 = find_program('python3')
|
||||||
|
|
||||||
|
httplib_ch = custom_target(
|
||||||
|
'split',
|
||||||
|
input: 'httplib.h',
|
||||||
|
output: ['httplib.cc', 'httplib.h'],
|
||||||
|
command: [python3, files('split.py'), '--out', meson.current_build_dir()],
|
||||||
|
install: true,
|
||||||
|
install_dir: [false, get_option('includedir')]
|
||||||
|
)
|
||||||
|
lib = library(
|
||||||
|
'cpp-httplib',
|
||||||
|
sources: httplib_ch,
|
||||||
|
dependencies: deps,
|
||||||
|
cpp_args: args,
|
||||||
|
version: version,
|
||||||
|
soversion: version.split('.')[0] + '.' + version.split('.')[1],
|
||||||
|
install: true
|
||||||
|
)
|
||||||
|
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, link_with: lib, sources: httplib_ch[1])
|
||||||
|
|
||||||
|
import('pkgconfig').generate(
|
||||||
|
lib,
|
||||||
|
description: 'A C++ HTTP/HTTPS server and client library',
|
||||||
|
extra_cflags: args,
|
||||||
|
url: 'https://github.com/yhirose/cpp-httplib',
|
||||||
|
version: version
|
||||||
|
)
|
||||||
|
else
|
||||||
|
install_headers('httplib.h')
|
||||||
|
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: include_directories('.'))
|
||||||
|
|
||||||
|
import('pkgconfig').generate(
|
||||||
|
name: 'cpp-httplib',
|
||||||
|
description: 'A C++ HTTP/HTTPS server and client library',
|
||||||
|
install_dir: join_paths(get_option('datadir'), 'pkgconfig'),
|
||||||
|
url: 'https://github.com/yhirose/cpp-httplib',
|
||||||
|
version: version
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if meson.version().version_compare('>=0.54.0')
|
||||||
|
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('cpp-httplib_test')
|
||||||
|
subdir('test')
|
||||||
|
endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
|
||||||
|
option('cpp-httplib_zlib', type: 'feature', value: 'auto', description: 'Enable zlib support')
|
||||||
|
option('cpp-httplib_brotli', type: 'feature', value: 'auto', description: 'Enable Brotli support')
|
||||||
|
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file (requires python3)')
|
||||||
|
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
|
||||||
@@ -1,32 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""This script splits httplib.h into .h and .cc parts."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
border = '// ----------------------------------------------------------------------------'
|
border = '// ----------------------------------------------------------------------------'
|
||||||
|
|
||||||
PythonVersion = sys.version_info[0];
|
args_parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
args_parser.add_argument(
|
||||||
|
"-e", "--extension", help="extension of the implementation file (default: cc)",
|
||||||
|
default="cc"
|
||||||
|
)
|
||||||
|
args_parser.add_argument(
|
||||||
|
"-o", "--out", help="where to write the files (default: out)", default="out"
|
||||||
|
)
|
||||||
|
args = args_parser.parse_args()
|
||||||
|
|
||||||
with open('httplib.h') as f:
|
cur_dir = os.path.dirname(sys.argv[0])
|
||||||
lines = f.readlines()
|
lib_name = 'httplib'
|
||||||
inImplementation = False
|
header_name = '/' + lib_name + '.h'
|
||||||
|
source_name = '/' + lib_name + '.' + args.extension
|
||||||
if PythonVersion < 3:
|
# get the input file
|
||||||
os.makedirs('out')
|
in_file = cur_dir + header_name
|
||||||
|
# get the output file
|
||||||
|
h_out = args.out + header_name
|
||||||
|
cc_out = args.out + source_name
|
||||||
|
|
||||||
|
# if the modification time of the out file is after the in file,
|
||||||
|
# don't split (as it is already finished)
|
||||||
|
do_split = True
|
||||||
|
|
||||||
|
if os.path.exists(h_out):
|
||||||
|
in_time = os.path.getmtime(in_file)
|
||||||
|
out_time = os.path.getmtime(h_out)
|
||||||
|
do_split = in_time > out_time
|
||||||
|
|
||||||
|
if do_split:
|
||||||
|
with open(in_file) as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
python_version = sys.version_info[0]
|
||||||
|
if python_version < 3:
|
||||||
|
os.makedirs(args.out)
|
||||||
else:
|
else:
|
||||||
os.makedirs('out', exist_ok=True)
|
os.makedirs(args.out, exist_ok=True)
|
||||||
|
|
||||||
with open('out/httplib.h', 'w') as fh:
|
in_implementation = False
|
||||||
with open('out/httplib.cc', 'w') as fc:
|
cc_out = args.out + source_name
|
||||||
fc.write('#include "httplib.h"\n')
|
with open(h_out, 'w') as fh, open(cc_out, 'w') as fc:
|
||||||
fc.write('namespace httplib {\n')
|
fc.write('#include "httplib.h"\n')
|
||||||
for line in lines:
|
fc.write('namespace httplib {\n')
|
||||||
isBorderLine = border in line
|
for line in lines:
|
||||||
if isBorderLine:
|
is_border_line = border in line
|
||||||
inImplementation = not inImplementation
|
if is_border_line:
|
||||||
else:
|
in_implementation = not in_implementation
|
||||||
if inImplementation:
|
elif in_implementation:
|
||||||
fc.write(line.replace('inline ', ''))
|
fc.write(line.replace('inline ', ''))
|
||||||
pass
|
else:
|
||||||
else:
|
fh.write(line)
|
||||||
fh.write(line)
|
fc.write('} // namespace httplib\n')
|
||||||
pass
|
|
||||||
fc.write('} // namespace httplib\n')
|
print("Wrote {} and {}".format(h_out, cc_out))
|
||||||
|
else:
|
||||||
|
print("{} and {} are up to date".format(h_out, cc_out))
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
cmake_policy(SET CMP0135 NEW)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
include(GoogleTest)
|
||||||
|
|
||||||
|
set(BUILD_GMOCK OFF)
|
||||||
|
set(INSTALL_GTEST OFF)
|
||||||
|
set(gtest_force_shared_crt ON)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
gtest
|
||||||
|
URL https://github.com/google/googletest/archive/main.tar.gz
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(gtest)
|
||||||
|
|
||||||
|
add_executable(httplib-test test.cc)
|
||||||
|
target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||||
|
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main)
|
||||||
|
gtest_discover_tests(httplib-test)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www www
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www2 www2
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www3 www3
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_LIST_DIR}/ca-bundle.crt ca-bundle.crt
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_LIST_DIR}/image.jpg image.jpg
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
|
||||||
|
if(HTTPLIB_IS_USING_OPENSSL)
|
||||||
|
find_program(OPENSSL_COMMAND
|
||||||
|
NAMES openssl
|
||||||
|
PATHS ${OPENSSL_INCLUDE_DIR}/../bin
|
||||||
|
REQUIRED
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} genrsa 2048
|
||||||
|
OUTPUT_FILE key.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem
|
||||||
|
COMMAND ${OPENSSL_COMMAND} x509 -days 3650 -req -signkey key.pem
|
||||||
|
OUTPUT_FILE cert.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} req -x509 -new -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} genrsa 2048
|
||||||
|
OUTPUT_FILE rootCA.key.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} req -x509 -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.rootCA.conf -key rootCA.key.pem -days 1024
|
||||||
|
OUTPUT_FILE rootCA.cert.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} genrsa 2048
|
||||||
|
OUTPUT_FILE client.key.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key client.key.pem
|
||||||
|
COMMAND ${OPENSSL_COMMAND} x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial
|
||||||
|
OUTPUT_FILE client.cert.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} genrsa -passout pass:test123! 2048
|
||||||
|
OUTPUT_FILE key_encrypted.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key_encrypted.pem
|
||||||
|
COMMAND ${OPENSSL_COMMAND} x509 -days 3650 -req -signkey key_encrypted.pem
|
||||||
|
OUTPUT_FILE cert_encrypted.pem
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
|
)
|
||||||
|
endif()
|
||||||
+47
-9
@@ -1,35 +1,73 @@
|
|||||||
|
CXX = clang++
|
||||||
|
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion -Wshadow # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
|
||||||
|
|
||||||
#CXX = clang++
|
PREFIX = /usr/local
|
||||||
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion
|
#PREFIX = $(shell brew --prefix)
|
||||||
|
|
||||||
OPENSSL_DIR = /usr/local/opt/openssl@1.1
|
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
|
||||||
|
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
|
||||||
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
|
||||||
|
|
||||||
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||||
|
|
||||||
BROTLI_DIR = /usr/local/opt/brotli
|
BROTLI_DIR = $(PREFIX)/opt/brotli
|
||||||
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||||
|
|
||||||
all : test
|
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
|
||||||
|
|
||||||
|
# By default, use standalone_fuzz_target_runner.
|
||||||
|
# This runner does no fuzzing, but simply executes the inputs
|
||||||
|
# provided via parameters.
|
||||||
|
# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
|
||||||
|
# to link the fuzzer(s) against a real fuzzing engine.
|
||||||
|
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
|
||||||
|
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
|
||||||
|
|
||||||
|
all : test test_split
|
||||||
./test
|
./test
|
||||||
|
|
||||||
proxy : test_proxy
|
proxy : test_proxy
|
||||||
./test_proxy
|
./test_proxy
|
||||||
|
|
||||||
test : test.cc ../httplib.h Makefile cert.pem
|
test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
|
||||||
$(CXX) -o test $(CXXFLAGS) test.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
|
$(CXX) -o $@ -I.. $(CXXFLAGS) test.cc include_httplib.cc $(TEST_ARGS)
|
||||||
|
|
||||||
|
# Note: The intention of test_split is to verify that it works to compile and
|
||||||
|
# link the split httplib.h, so there is normally no need to execute it.
|
||||||
|
test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem
|
||||||
|
$(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS)
|
||||||
|
|
||||||
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
|
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
|
||||||
$(CXX) -o test_proxy $(CXXFLAGS) test_proxy.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
|
$(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS)
|
||||||
|
|
||||||
|
# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
|
||||||
|
# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
|
||||||
|
fuzz_test: server_fuzzer
|
||||||
|
./server_fuzzer fuzzing/corpus/*
|
||||||
|
|
||||||
|
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
|
||||||
|
server_fuzzer : fuzzing/server_fuzzer.cc ../httplib.h standalone_fuzz_target_runner.o
|
||||||
|
$(CXX) -o $@ -I.. $(CXXFLAGS) $< $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||||
|
|
||||||
|
# Standalone fuzz runner, which just reads inputs from fuzzing/corpus/ dir and
|
||||||
|
# feeds it to server_fuzzer.
|
||||||
|
standalone_fuzz_target_runner.o : fuzzing/standalone_fuzz_target_runner.cpp
|
||||||
|
$(CXX) -o $@ -I.. $(CXXFLAGS) -c $<
|
||||||
|
|
||||||
|
httplib.cc : ../httplib.h
|
||||||
|
python3 ../split.py -o .
|
||||||
|
|
||||||
cert.pem:
|
cert.pem:
|
||||||
openssl genrsa 2048 > key.pem
|
openssl genrsa 2048 > key.pem
|
||||||
openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
|
||||||
|
openssl req -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
|
||||||
openssl genrsa 2048 > rootCA.key.pem
|
openssl genrsa 2048 > rootCA.key.pem
|
||||||
openssl req -x509 -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
|
openssl req -x509 -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
|
||||||
openssl genrsa 2048 > client.key.pem
|
openssl genrsa 2048 > client.key.pem
|
||||||
openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
|
openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
|
||||||
|
openssl genrsa -passout pass:test123! 2048 > key_encrypted.pem
|
||||||
|
openssl req -new -batch -config test.conf -key key_encrypted.pem | openssl x509 -days 3650 -req -signkey key_encrypted.pem > cert_encrypted.pem
|
||||||
#c_rehash .
|
#c_rehash .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f test test_proxy pem *.0 *.1 *.srl
|
rm -f test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#CXX = clang++
|
||||||
|
# Do not add default sanitizer flags here as OSS-fuzz adds its own sanitizer flags.
|
||||||
|
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I../.. -I. -Wall -Wextra -Wtype-limits -Wconversion
|
||||||
|
|
||||||
|
OPENSSL_DIR = /usr/local/opt/openssl@1.1
|
||||||
|
|
||||||
|
# Using full path to libssl and libcrypto to avoid accidentally picking openssl libs brought in by msan.
|
||||||
|
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -I$(OPENSSL_DIR)/lib /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a
|
||||||
|
|
||||||
|
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||||
|
|
||||||
|
BROTLI_DIR = /usr/local/opt/brotli
|
||||||
|
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||||
|
|
||||||
|
# Runs all the tests and also fuzz tests against seed corpus.
|
||||||
|
all : server_fuzzer
|
||||||
|
./server_fuzzer corpus/*
|
||||||
|
|
||||||
|
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
|
||||||
|
server_fuzzer : server_fuzzer.cc ../../httplib.h
|
||||||
|
# $(CXX) $(CXXFLAGS) -o $@ $< -Wl,-Bstatic $(OPENSSL_SUPPORT) -Wl,-Bdynamic -ldl $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||||
|
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
|
||||||
|
zip -q -r server_fuzzer_seed_corpus.zip corpus
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
PUT /search/sample?a=12 HTTP/1.1
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
GET /hello.htm HTTP/1.1
|
||||||
|
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
|
||||||
|
Accept-Language: en-us
|
||||||
|
Accept-Encoding: gzip, deflate
|
||||||
|
Connection: Keep-Alive
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,91 @@
|
|||||||
|
#include <httplib.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class FuzzedStream : public httplib::Stream {
|
||||||
|
public:
|
||||||
|
FuzzedStream(const uint8_t *data, size_t size)
|
||||||
|
: data_(data), size_(size), read_pos_(0) {}
|
||||||
|
|
||||||
|
ssize_t read(char *ptr, size_t size) override {
|
||||||
|
if (size + read_pos_ > size_) { size = size_ - read_pos_; }
|
||||||
|
memcpy(ptr, data_ + read_pos_, size);
|
||||||
|
read_pos_ += size;
|
||||||
|
return static_cast<ssize_t>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write(const char *ptr, size_t size) override {
|
||||||
|
response_.append(ptr, size);
|
||||||
|
return static_cast<int>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
|
||||||
|
|
||||||
|
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
|
||||||
|
|
||||||
|
bool is_readable() const override { return true; }
|
||||||
|
|
||||||
|
bool is_writable() const override { return true; }
|
||||||
|
|
||||||
|
void get_remote_ip_and_port(std::string &ip, int &port) const override {
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_local_ip_and_port(std::string &ip, int &port) const override {
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_t socket() const override { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t *data_;
|
||||||
|
size_t size_;
|
||||||
|
size_t read_pos_;
|
||||||
|
std::string response_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FuzzableServer : public httplib::Server {
|
||||||
|
public:
|
||||||
|
void ProcessFuzzedRequest(FuzzedStream &stream) {
|
||||||
|
bool connection_close = false;
|
||||||
|
process_request(stream, /*last_connection=*/false, connection_close,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static FuzzableServer g_server;
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
|
||||||
|
g_server.Get(R"(.*)",
|
||||||
|
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
g_server.Post(R"(.*)",
|
||||||
|
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
g_server.Put(R"(.*)",
|
||||||
|
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
g_server.Patch(R"(.*)",
|
||||||
|
[&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
g_server.Delete(
|
||||||
|
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
g_server.Options(
|
||||||
|
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
|
||||||
|
res.set_content("response content", "text/plain");
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
FuzzedStream stream{data, size};
|
||||||
|
g_server.ProcessFuzzedRequest(stream);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
# Sources: https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
|
||||||
|
|
||||||
|
# misc
|
||||||
|
"HTTP/1.1"
|
||||||
|
|
||||||
|
# verbs
|
||||||
|
"CONNECT"
|
||||||
|
"DELETE"
|
||||||
|
"GET"
|
||||||
|
"HEAD"
|
||||||
|
"OPTIONS"
|
||||||
|
"PATCH"
|
||||||
|
"POST"
|
||||||
|
"PUT"
|
||||||
|
"TRACE"
|
||||||
|
|
||||||
|
|
||||||
|
# Webdav/caldav verbs
|
||||||
|
"ACL"
|
||||||
|
"BASELINE-CONTROL"
|
||||||
|
"BIND"
|
||||||
|
"CHECKIN"
|
||||||
|
"CHECKOUT"
|
||||||
|
"COPY"
|
||||||
|
"LABEL"
|
||||||
|
"LINK"
|
||||||
|
"LOCK"
|
||||||
|
"MERGE"
|
||||||
|
"MKACTIVITY"
|
||||||
|
"MKCALENDAR"
|
||||||
|
"MKCOL"
|
||||||
|
"MKREDIRECTREF"
|
||||||
|
"MKWORKSPACE"
|
||||||
|
"MOVE"
|
||||||
|
"ORDERPATCH"
|
||||||
|
"PRI"
|
||||||
|
"PROPFIND"
|
||||||
|
"PROPPATCH"
|
||||||
|
"REBIND"
|
||||||
|
"REPORT"
|
||||||
|
"SEARCH"
|
||||||
|
"UNBIND"
|
||||||
|
"UNCHECKOUT"
|
||||||
|
"UNLINK"
|
||||||
|
"UNLOCK"
|
||||||
|
"UPDATE"
|
||||||
|
"UPDATEREDIRECTREF"
|
||||||
|
"VERSION-CONTROL"
|
||||||
|
|
||||||
|
|
||||||
|
# Fields
|
||||||
|
"A-IM"
|
||||||
|
"Accept"
|
||||||
|
"Accept-Charset"
|
||||||
|
"Accept-Datetime"
|
||||||
|
"Accept-Encoding"
|
||||||
|
"Accept-Language"
|
||||||
|
"Accept-Patch"
|
||||||
|
"Accept-Ranges"
|
||||||
|
"Access-Control-Allow-Credentials"
|
||||||
|
"Access-Control-Allow-Headers"
|
||||||
|
"Access-Control-Allow-Methods"
|
||||||
|
"Access-Control-Allow-Origin"
|
||||||
|
"Access-Control-Expose-Headers"
|
||||||
|
"Access-Control-Max-Age"
|
||||||
|
"Access-Control-Request-Headers"
|
||||||
|
"Access-Control-Request-Method"
|
||||||
|
"Age"
|
||||||
|
"Allow"
|
||||||
|
"Alt-Svc"
|
||||||
|
"Authorization"
|
||||||
|
"Cache-Control"
|
||||||
|
"Connection"
|
||||||
|
"Connection:"
|
||||||
|
"Content-Disposition"
|
||||||
|
"Content-Encoding"
|
||||||
|
"Content-Language"
|
||||||
|
"Content-Length"
|
||||||
|
"Content-Location"
|
||||||
|
"Content-MD5"
|
||||||
|
"Content-Range"
|
||||||
|
"Content-Security-Policy"
|
||||||
|
"Content-Type"
|
||||||
|
"Cookie"
|
||||||
|
"DNT"
|
||||||
|
"Date"
|
||||||
|
"Delta-Base"
|
||||||
|
"ETag"
|
||||||
|
"Expect"
|
||||||
|
"Expires"
|
||||||
|
"Forwarded"
|
||||||
|
"From"
|
||||||
|
"Front-End-Https"
|
||||||
|
"HTTP2-Settings"
|
||||||
|
"Host"
|
||||||
|
"IM"
|
||||||
|
"If-Match"
|
||||||
|
"If-Modified-Since"
|
||||||
|
"If-None-Match"
|
||||||
|
"If-Range"
|
||||||
|
"If-Unmodified-Since"
|
||||||
|
"Last-Modified"
|
||||||
|
"Link"
|
||||||
|
"Location"
|
||||||
|
"Max-Forwards"
|
||||||
|
"Origin"
|
||||||
|
"P3P"
|
||||||
|
"Pragma"
|
||||||
|
"Proxy-Authenticate"
|
||||||
|
"Proxy-Authorization"
|
||||||
|
"Proxy-Connection"
|
||||||
|
"Public-Key-Pins"
|
||||||
|
"Range"
|
||||||
|
"Referer"
|
||||||
|
"Refresh"
|
||||||
|
"Retry-After"
|
||||||
|
"Save-Data"
|
||||||
|
"Server"
|
||||||
|
"Set-Cookie"
|
||||||
|
"Status"
|
||||||
|
"Strict-Transport-Security"
|
||||||
|
"TE"
|
||||||
|
"Timing-Allow-Origin"
|
||||||
|
"Tk"
|
||||||
|
"Trailer"
|
||||||
|
"Transfer-Encoding"
|
||||||
|
"Upgrade"
|
||||||
|
"Upgrade-Insecure-Requests"
|
||||||
|
"User-Agent"
|
||||||
|
"Vary"
|
||||||
|
"Via"
|
||||||
|
"WWW-Authenticate"
|
||||||
|
"Warning"
|
||||||
|
"X-ATT-DeviceId"
|
||||||
|
"X-Content-Duration"
|
||||||
|
"X-Content-Security-Policy"
|
||||||
|
"X-Content-Type-Options"
|
||||||
|
"X-Correlation-ID"
|
||||||
|
"X-Csrf-Token"
|
||||||
|
"X-Forwarded-For"
|
||||||
|
"X-Forwarded-Host"
|
||||||
|
"X-Forwarded-Proto"
|
||||||
|
"X-Frame-Options"
|
||||||
|
"X-Http-Method-Override"
|
||||||
|
"X-Powered-By"
|
||||||
|
"X-Request-ID"
|
||||||
|
"X-Requested-With"
|
||||||
|
"X-UA-Compatible"
|
||||||
|
"X-UIDH"
|
||||||
|
"X-Wap-Profile"
|
||||||
|
"X-WebKit-CSP"
|
||||||
|
"X-XSS-Protection"
|
||||||
|
|
||||||
|
# Source: string and character literals in httplib.h
|
||||||
|
" "
|
||||||
|
"&"
|
||||||
|
", "
|
||||||
|
"-"
|
||||||
|
"--"
|
||||||
|
"."
|
||||||
|
".."
|
||||||
|
":"
|
||||||
|
"="
|
||||||
|
" = = "
|
||||||
|
"0123456789abcdef"
|
||||||
|
"%02X"
|
||||||
|
"%0A"
|
||||||
|
"\\x0a\\x0d"
|
||||||
|
"%0D"
|
||||||
|
"%20"
|
||||||
|
"%27"
|
||||||
|
"%2B"
|
||||||
|
"%2C"
|
||||||
|
"%3A"
|
||||||
|
"%3B"
|
||||||
|
"application/javascript"
|
||||||
|
"application/json"
|
||||||
|
"application/pdf"
|
||||||
|
"application/xhtml+xml"
|
||||||
|
"application/xml"
|
||||||
|
"application/x-www-form-urlencoded"
|
||||||
|
"Bad Request"
|
||||||
|
"boundary="
|
||||||
|
"bytes="
|
||||||
|
"chunked"
|
||||||
|
"close"
|
||||||
|
"CONNECT"
|
||||||
|
"css"
|
||||||
|
"Forbidden"
|
||||||
|
"Found"
|
||||||
|
"gif"
|
||||||
|
"gzip"
|
||||||
|
"html"
|
||||||
|
"ico"
|
||||||
|
"image/gif"
|
||||||
|
"image/jpg"
|
||||||
|
"image/png"
|
||||||
|
"image/svg+xml"
|
||||||
|
"image/x-icon"
|
||||||
|
"index.html"
|
||||||
|
"Internal Server Error"
|
||||||
|
"jpeg"
|
||||||
|
"js"
|
||||||
|
"json"
|
||||||
|
"Location"
|
||||||
|
"Moved Permanently"
|
||||||
|
"multipart/form-data"
|
||||||
|
"Not Found"
|
||||||
|
"Not Modified"
|
||||||
|
"OK"
|
||||||
|
"pdf"
|
||||||
|
"png"
|
||||||
|
"Range"
|
||||||
|
"REMOTE_ADDR"
|
||||||
|
"See Other"
|
||||||
|
"svg"
|
||||||
|
"text/"
|
||||||
|
"text/css"
|
||||||
|
"text/html"
|
||||||
|
"text/plain"
|
||||||
|
"txt"
|
||||||
|
"Unsupported Media Type"
|
||||||
|
"xhtml"
|
||||||
|
"xml"
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
||||||
|
// This runner does not do any fuzzing, but allows us to run the fuzz target
|
||||||
|
// on the test corpus or on a single file,
|
||||||
|
// e.g. the one that comes from a bug report.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Forward declare the "fuzz target" interface.
|
||||||
|
// We deliberately keep this inteface simple and header-free.
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||||
|
|
||||||
|
// It reads all files passed as parameters and feeds their contents
|
||||||
|
// one by one into the fuzz target (LLVMFuzzerTestOneInput).
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
std::ifstream in(argv[i]);
|
||||||
|
in.seekg(0, in.end);
|
||||||
|
size_t length = static_cast<size_t>(in.tellg());
|
||||||
|
in.seekg (0, in.beg);
|
||||||
|
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
|
||||||
|
// Allocate exactly length bytes so that we reliably catch buffer overflows.
|
||||||
|
std::vector<char> bytes(length);
|
||||||
|
in.read(bytes.data(), static_cast<std::streamsize>(bytes.size()));
|
||||||
|
LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
|
||||||
|
bytes.size());
|
||||||
|
std::cout << "Execution successful" << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "Execution finished" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+5790
-2420
File diff suppressed because it is too large
Load Diff
+6845
-14038
File diff suppressed because it is too large
Load Diff
@@ -27,13 +27,28 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <iostream>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
GTEST_API_ int main(int argc, char **argv) {
|
#if GTEST_OS_ESP8266 || GTEST_OS_ESP32
|
||||||
std::cout << "Running main() from gtest_main.cc\n";
|
#if GTEST_OS_ESP8266
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void setup() {
|
||||||
|
testing::InitGoogleTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() { RUN_ALL_TESTS(); }
|
||||||
|
|
||||||
|
#if GTEST_OS_ESP8266
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
GTEST_API_ int main(int argc, char **argv) {
|
||||||
|
printf("Running main() from %s\n", __FILE__);
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// The sole purpose of this file is to include httplib.h in a separate
|
||||||
|
// compilation unit, thus verifying that inline keywords have not been forgotten
|
||||||
|
// when linked together with test.cc.
|
||||||
|
|
||||||
|
#include <httplib.h>
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
gtest_dep = dependency('gtest', main: true)
|
||||||
|
openssl = find_program('openssl')
|
||||||
|
test_conf = files('test.conf')
|
||||||
|
|
||||||
|
key_pem = custom_target(
|
||||||
|
'key_pem',
|
||||||
|
output: 'key.pem',
|
||||||
|
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||||
|
)
|
||||||
|
|
||||||
|
temp_req = custom_target(
|
||||||
|
'temp_req',
|
||||||
|
input: key_pem,
|
||||||
|
output: 'temp_req',
|
||||||
|
command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
cert_pem = custom_target(
|
||||||
|
'cert_pem',
|
||||||
|
input: [temp_req, key_pem],
|
||||||
|
output: 'cert.pem',
|
||||||
|
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '3650', '-req', '-signkey', '@INPUT1@', '-out', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
cert2_pem = custom_target(
|
||||||
|
'cert2_pem',
|
||||||
|
input: key_pem,
|
||||||
|
output: 'cert2.pem',
|
||||||
|
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
||||||
|
)
|
||||||
|
|
||||||
|
key_encrypted_pem = custom_target(
|
||||||
|
'key_encrypted_pem',
|
||||||
|
output: 'key_encrypted.pem',
|
||||||
|
command: [openssl, 'genrsa', '-passout', 'pass:test123!', '-out', '@OUTPUT@', '2048']
|
||||||
|
)
|
||||||
|
|
||||||
|
cert_encrypted_pem = custom_target(
|
||||||
|
'cert_encrypted_pem',
|
||||||
|
input: key_encrypted_pem,
|
||||||
|
output: 'cert_encrypted.pem',
|
||||||
|
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
|
||||||
|
)
|
||||||
|
|
||||||
|
rootca_key_pem = custom_target(
|
||||||
|
'rootca_key_pem',
|
||||||
|
output: 'rootCA.key.pem',
|
||||||
|
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||||
|
)
|
||||||
|
|
||||||
|
rootca_cert_pem = custom_target(
|
||||||
|
'rootca_cert_pem',
|
||||||
|
input: rootca_key_pem,
|
||||||
|
output: 'rootCA.cert.pem',
|
||||||
|
command: [openssl, 'req', '-x509', '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
client_key_pem = custom_target(
|
||||||
|
'client_key_pem',
|
||||||
|
output: 'client.key.pem',
|
||||||
|
command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
|
||||||
|
)
|
||||||
|
|
||||||
|
client_temp_req = custom_target(
|
||||||
|
'client_temp_req',
|
||||||
|
input: client_key_pem,
|
||||||
|
output: 'client_temp_req',
|
||||||
|
command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
client_cert_pem = custom_target(
|
||||||
|
'client_cert_pem',
|
||||||
|
input: [client_temp_req, rootca_cert_pem, rootca_key_pem],
|
||||||
|
output: 'client.cert.pem',
|
||||||
|
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy test files to the build directory
|
||||||
|
configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
|
||||||
|
configure_file(input: 'image.jpg', output: 'image.jpg', copy: true)
|
||||||
|
subdir(join_paths('www', 'dir'))
|
||||||
|
subdir(join_paths('www2', 'dir'))
|
||||||
|
subdir(join_paths('www3', 'dir'))
|
||||||
|
|
||||||
|
test(
|
||||||
|
'main',
|
||||||
|
executable(
|
||||||
|
'main',
|
||||||
|
'test.cc',
|
||||||
|
dependencies: [
|
||||||
|
cpp_httplib_dep,
|
||||||
|
gtest_dep
|
||||||
|
]
|
||||||
|
),
|
||||||
|
depends: [
|
||||||
|
key_pem,
|
||||||
|
cert_pem,
|
||||||
|
cert2_pem,
|
||||||
|
key_encrypted_pem,
|
||||||
|
cert_encrypted_pem,
|
||||||
|
rootca_key_pem,
|
||||||
|
rootca_cert_pem,
|
||||||
|
client_key_pem,
|
||||||
|
client_cert_pem
|
||||||
|
],
|
||||||
|
workdir: meson.current_build_dir(),
|
||||||
|
timeout: 300
|
||||||
|
)
|
||||||
@@ -1 +0,0 @@
|
|||||||
docker-compose down --rmi all
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
docker-compose up -d
|
|
||||||
+2961
-358
File diff suppressed because it is too large
Load Diff
@@ -16,3 +16,6 @@ emailAddress = test@email.address
|
|||||||
|
|
||||||
[req_attributes]
|
[req_attributes]
|
||||||
challengePassword = 1234
|
challengePassword = 1234
|
||||||
|
|
||||||
|
[SAN]
|
||||||
|
subjectAltName=IP:127.0.0.1
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
<AdditionalUsingDirectories>
|
<AdditionalUsingDirectories>
|
||||||
</AdditionalUsingDirectories>
|
</AdditionalUsingDirectories>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@@ -158,6 +159,7 @@
|
|||||||
<AdditionalUsingDirectories>
|
<AdditionalUsingDirectories>
|
||||||
</AdditionalUsingDirectories>
|
</AdditionalUsingDirectories>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
|||||||
+28
-31
@@ -8,29 +8,29 @@ using namespace httplib;
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void ProxyTest(T& cli, bool basic) {
|
void ProxyTest(T& cli, bool basic) {
|
||||||
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
||||||
auto res = cli.Get("/get");
|
auto res = cli.Get("/httpbin/get");
|
||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
EXPECT_EQ(407, res->status);
|
EXPECT_EQ(407, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ProxyTest, NoSSLBasic) {
|
TEST(ProxyTest, NoSSLBasic) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
ProxyTest(cli, true);
|
ProxyTest(cli, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
TEST(ProxyTest, SSLBasic) {
|
TEST(ProxyTest, SSLBasic) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
ProxyTest(cli, true);
|
ProxyTest(cli, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ProxyTest, NoSSLDigest) {
|
TEST(ProxyTest, NoSSLDigest) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
ProxyTest(cli, false);
|
ProxyTest(cli, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ProxyTest, SSLDigest) {
|
TEST(ProxyTest, SSLDigest) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
ProxyTest(cli, false);
|
ProxyTest(cli, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -54,29 +54,27 @@ void RedirectProxyText(T& cli, const char *path, bool basic) {
|
|||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
TEST(RedirectTest, HTTPBinNoSSLBasic) {
|
TEST(RedirectTest, HTTPBinNoSSLBasic) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
RedirectProxyText(cli, "/redirect/2", true);
|
RedirectProxyText(cli, "/httpbin/redirect/2", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
TEST(RedirectTest, HTTPBinNoSSLDigest) {
|
TEST(RedirectTest, HTTPBinNoSSLDigest) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
RedirectProxyText(cli, "/redirect/2", false);
|
RedirectProxyText(cli, "/httpbin/redirect/2", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RedirectTest, HTTPBinSSLBasic) {
|
TEST(RedirectTest, HTTPBinSSLBasic) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
RedirectProxyText(cli, "/redirect/2", true);
|
RedirectProxyText(cli, "/httpbin/redirect/2", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RedirectTest, HTTPBinSSLDigest) {
|
TEST(RedirectTest, HTTPBinSSLDigest) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
RedirectProxyText(cli, "/redirect/2", false);
|
RedirectProxyText(cli, "/httpbin/redirect/2", false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
TEST(RedirectTest, YouTubeNoSSLBasic) {
|
TEST(RedirectTest, YouTubeNoSSLBasic) {
|
||||||
@@ -84,7 +82,7 @@ TEST(RedirectTest, YouTubeNoSSLBasic) {
|
|||||||
RedirectProxyText(cli, "/", true);
|
RedirectProxyText(cli, "/", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RedirectTest, YouTubeNoSSLDigest) {
|
TEST(RedirectTest, DISABLED_YouTubeNoSSLDigest) {
|
||||||
Client cli("youtube.com");
|
Client cli("youtube.com");
|
||||||
RedirectProxyText(cli, "/", false);
|
RedirectProxyText(cli, "/", false);
|
||||||
}
|
}
|
||||||
@@ -218,7 +216,8 @@ TEST(DigestAuthTest, NoSSL) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void KeepAliveTest(Client& cli, bool basic) {
|
template <typename T>
|
||||||
|
void KeepAliveTest(T& cli, bool basic) {
|
||||||
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
cli.set_proxy("localhost", basic ? 3128 : 3129);
|
||||||
if (basic) {
|
if (basic) {
|
||||||
cli.set_proxy_basic_auth("hello", "world");
|
cli.set_proxy_basic_auth("hello", "world");
|
||||||
@@ -234,20 +233,20 @@ void KeepAliveTest(Client& cli, bool basic) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
auto res = cli.Get("/get");
|
auto res = cli.Get("/httpbin/get");
|
||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto res = cli.Get("/redirect/2");
|
auto res = cli.Get("/httpbin/redirect/2");
|
||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::vector<std::string> paths = {
|
std::vector<std::string> paths = {
|
||||||
"/digest-auth/auth/hello/world/MD5",
|
"/httpbin/digest-auth/auth/hello/world/MD5",
|
||||||
"/digest-auth/auth/hello/world/SHA-256",
|
"/httpbin/digest-auth/auth/hello/world/SHA-256",
|
||||||
"/digest-auth/auth/hello/world/SHA-512",
|
"/httpbin/digest-auth/auth/hello/world/SHA-512",
|
||||||
"/digest-auth/auth-int/hello/world/MD5",
|
"/httpbin/digest-auth/auth-int/hello/world/MD5",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto path: paths) {
|
for (auto path: paths) {
|
||||||
@@ -258,34 +257,32 @@ void KeepAliveTest(Client& cli, bool basic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int count = 100;
|
int count = 10;
|
||||||
while (count--) {
|
while (count--) {
|
||||||
auto res = cli.Get("/get");
|
auto res = cli.Get("/httpbin/get");
|
||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
TEST(KeepAliveTest, NoSSLWithBasic) {
|
TEST(KeepAliveTest, NoSSLWithBasic) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
KeepAliveTest(cli, true);
|
KeepAliveTest(cli, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(KeepAliveTest, SSLWithBasic) {
|
TEST(KeepAliveTest, SSLWithBasic) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
KeepAliveTest(cli, true);
|
KeepAliveTest(cli, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(KeepAliveTest, NoSSLWithDigest) {
|
TEST(KeepAliveTest, NoSSLWithDigest) {
|
||||||
Client cli("httpbin.org");
|
Client cli("nghttp2.org");
|
||||||
KeepAliveTest(cli, false);
|
KeepAliveTest(cli, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(KeepAliveTest, SSLWithDigest) {
|
TEST(KeepAliveTest, SSLWithDigest) {
|
||||||
SSLClient cli("httpbin.org");
|
SSLClient cli("nghttp2.org");
|
||||||
KeepAliveTest(cli, false);
|
KeepAliveTest(cli, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||||
|
configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
|
||||||
|
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||||
|
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
configure_file(input: 'index.html', output: 'index.html', copy: true)
|
||||||
|
configure_file(input: 'test.html', output: 'test.html', copy: true)
|
||||||
Reference in New Issue
Block a user