Compare commits

...

69 Commits

Author SHA1 Message Date
Gregor Jasny 87e03dd1ce Report connection timeout as separate event (#1171) 2022-01-26 17:32:40 -05:00
yhirose e5cacb465d Fix #1172 (#1173)
This change is based on RFC7230, § 3.5 'Message Parsing Robustness': "Although the line terminator for the start-line and header fields is the sequence CRLF, a recipient MAY recognize a single LF as a line terminator and ignore any preceding CR."
2022-01-26 13:34:23 -05:00
yhirose ee8371f753 Added 'PostLarge' unit test for #1169 2022-01-22 09:52:27 -05:00
yhirose 081723f983 Add another fuzz test corpus 2022-01-20 15:27:26 -05:00
yhirose b61f36579c Fix #1166 2022-01-20 15:24:09 -05:00
ArnaudBienner 33f53aa458 Fix set_content_provider example in README.md (#1163) 2022-01-13 12:26:34 -05:00
yhirose 412ab5f063 Added example/Dockerfile.hello 2022-01-11 00:18:20 -05:00
yhirose 11e02e901c Fixed unit test 2021-12-31 16:10:57 -05:00
yhirose 65a8f4cf44 Added hosted_at. (Resolve #1113) 2021-12-31 15:35:52 -05:00
yhirose 27d128bbb4 Fix problems in #1154 2021-12-31 14:55:40 -05:00
yhirose 070f9bec58 Code cleanup 2021-12-31 13:27:47 -05:00
c00c f817032513 fix socket option setting for windows (#1154)
* fix socket option setting for windows

* misc

Co-authored-by: zhangsen <zhangsen@cyberkl.com>
2021-12-31 10:07:59 -05:00
yhirose 17abe221c0 Fix is_file problem on Windows (#1153) 2021-12-30 14:54:57 -05:00
vitaly-ivanov 4a7a81e039 Work around silly Win defines to support BoringSSL (#1148)
* Work around silly Win defines to support BoringSSL

* changes wrapped into ifdef(_WIN32) just in case
2021-12-30 11:08:51 -05:00
yhirose 37fd4eb643 Code cleanup 2021-12-26 07:53:56 -05:00
yhirose 865b0e4c03 Resolve #1145 2021-12-26 07:53:06 -05:00
yhirose b324921c1a Release v0.10.1 2021-12-24 21:01:06 -05:00
yhirose 63f72caf30 Fix "Issue 42689 in oss-fuzz: cpp-httplib:server_fuzzer: Timeout in server_fuzzer" 2021-12-24 20:58:09 -05:00
yhirose 99ac17b90a Fix #1140 2021-12-23 23:19:14 -05:00
yhirose 4b0ed9ee88 Release v0.10.0 2021-12-21 18:15:41 -05:00
yhirose 20056f6cda Update test.cc 2021-12-19 14:19:10 -05:00
yhirose 3b35279b16 Added SSLServer::ssl_context() 2021-12-18 00:21:41 -05:00
yhirose 27deb44df5 Update SSL related code 2021-12-18 00:15:38 -05:00
yhirose 24a3ef949b Performance improvement for multipart form data file upload. 2021-12-18 00:15:10 -05:00
yhirose bc3e098964 Updated .gitignore 2021-12-17 22:36:02 -05:00
yhirose c247dcdd7b Added uploader.sh 2021-12-17 22:34:00 -05:00
yhirose 793ae9855e Fix #1041 (#1132)
* Fix #1041

* Fixed problem with is_socket_alive

* Adjust the way to check if the sockt is still alive.

* Revert "Adjust the way to check if the sockt is still alive."

This reverts commit 6c673b21e5.

* Adjust is_socket_alive according to the code review
2021-12-16 21:06:17 -05:00
yhirose 9fa426d51b Added more fuzzing corpus 2021-12-14 18:35:20 -05:00
yhirose cec6288a99 Resolve #1131 2021-12-14 07:58:21 -05:00
yhirose 9639578c2a Release v0.9.10 2021-12-11 19:26:22 -05:00
yhirose 743ecbd365 Issue1121 (#1122)
* Fixed test/Makefile problem when cleaning *.pem files

* Fix #1121
2021-12-11 19:07:12 -05:00
yhirose 084c643973 Fixed README 2021-12-10 22:33:59 -05:00
Andrea Pappacoda 824e7682e4 test: add missing _Online suffixes (#1110) 2021-11-27 09:54:05 -05:00
Andrea Pappacoda f9074684dd build(meson): drop Git-based version detection (#1109)
See 3051152103
2021-11-27 09:47:09 -05:00
yhirose ddff782133 Release v0.9.9 2021-11-26 20:46:38 -05:00
yhirose 3051152103 Fix #1102 (#1108) 2021-11-26 20:44:58 -05:00
yhirose 06026bb47d Code formating 2021-11-23 10:53:05 -05:00
yhirose 226388ae27 Resolve #1100 2021-11-23 10:47:30 -05:00
Scott Graham ea7548b4cc Remove stray ; causing warning with -Wextra-semi (#1099) 2021-11-22 07:16:07 -05:00
Rodolphe c7486ead96 accept protobuf encoding (#1096)
Co-authored-by: rodolphe <rodolphe@zen.ly>
2021-11-17 13:14:31 -05:00
yhirose 90a291214c Update Makefile 2021-11-15 23:08:49 -05:00
Andrea Pappacoda c111c42a86 build(meson): feature args in pkg-config file (#1092)
Follow-up for #1090. The args are now also added to the pkg-config file.
2021-11-15 22:50:33 -05:00
yhirose 6fb5b63018 Fix #1093. Remove meson-build tests from GitHubActions (#1094) 2021-11-15 22:49:40 -05:00
yhirose ec56dfa35e Fix #1085 (#1091) 2021-11-15 14:37:10 -05:00
Andrea Pappacoda 943cd51b67 build(meson): pass feature args to dependency consumers (#1090)
Fixes #1087
2021-11-15 14:03:25 -05:00
Yuji Hirose 301faa074c Added test case for #1065 2021-10-29 07:29:23 -04:00
DavidKorczynski dc0481e832 Add CIFuzz integration (#1079)
Signed-off-by: David Korczynski <david@adalogics.com>
2021-10-27 12:19:21 -04:00
zhenyolka 4f8fcdbaf7 Allow to specify server IP address (#1067)
* Allow to specify server IP address

* Reimplement in set_hostname_addr_map

* Add tests for set_hostname_addr_map

* Fix tests after implement set_hostname_addr_map

* SpecifyServerIPAddressTest.RealHostname typo
2021-10-16 15:05:55 -04:00
CarlosLeeGit b80aa7fee3 support custom ssl ctx configuration for SSLServer (#1073) 2021-10-15 07:13:16 -04:00
yhirose c384be02c9 Fixed GitHub Actions build error 2021-10-14 10:52:05 -04:00
yhirose d17ac3bb40 Fix "Issue 39922 in oss-fuzz: cpp-httplib:server_fuzzer: Timeout in server_fuzzer" 2021-10-14 08:55:29 -04:00
yhirose c7554ccac2 Fix #1069 (#1070) 2021-10-09 20:35:58 -04:00
yhirose 35ef1c7bae Fix #1063 2021-10-03 18:37:59 -04:00
David Pfahler d87d0672a8 Split the header only if needed (#1060)
* Update split.py

* Update split.py

* Update split.py

* Update split.py
2021-09-28 18:11:50 -04:00
estshorter 3da42fd1e8 Avoid min/max macro expansion on Windows (#1057) 2021-09-25 08:53:15 -04:00
yhirose 503aa61325 Fix problem with an empty parameter in set_base_dir 2021-09-20 17:40:05 -04:00
null e4c276d0c2 doc: fix typo in README (#1056)
fixed typo in README.md, replacing `Sutudio` with `Studio`.
2021-09-18 11:33:23 -04:00
yhirose e07f7691a8 Update README 2021-09-17 21:26:31 -04:00
yhirose 623ab4a96e Updated README regarding Visual Studio support 2021-09-17 11:36:08 -04:00
Zizheng Tai e1efa337a2 Make Client move-constructible (#1051) 2021-09-16 14:05:42 -04:00
Andrea Pappacoda 549cdf2f7d test: avoid infinite loop when IPV6 is unsupported (#1054) 2021-09-16 14:04:43 -04:00
yhirose 3c522386e9 Fix "Issue 38551 in oss-fuzz: cpp-httplib:server_fuzzer: Timeout in server_fuzze" 2021-09-12 19:24:48 -04:00
yhirose c202aa9ce9 Read buffer support. (Fix #1023) (#1046) 2021-09-12 00:26:02 -04:00
Andrea Pappacoda e3e28c6231 meson: add tests (#1044)
This integrates the "main" test suite (test/test.cc) in Meson.

This allows to run the tests in the CI with the Meson-built version of
the library to ensure that nothing breaks unexpectedly.

It also simplifies life of downstream packagers, that do not have to
write a custom build script to split the library and run tests but can
instead just let Meson do that for them.
2021-09-11 14:26:48 -04:00
yhirose 4e05368086 Fix #1054 2021-09-11 14:13:49 -04:00
yhirose e1afe74fe2 Fix #1037 2021-09-10 22:42:14 -04:00
yhirose 461acb02f5 Comment out SlowPostFail test for now 2021-09-10 22:37:31 -04:00
Gregor Jasny 415edc237c Set error variable for failed write_data (#1036) 2021-09-05 16:15:46 -04:00
Andrea Pappacoda e20ecd2574 Full Meson support (#1033)
* Full Meson support
cpp-httplib can be now built with Meson even in compiled library mode.

The library is built with LTO, supports OpenSSL, zlib and Brotli,
and the build system also generates a pkg-config file when needed.

Compared to the CMake file this one is quite small (more than five times
smaller!), and maintaining it won't be an issue :)

* meson: automatic versioning
2021-09-04 11:33:53 -04:00
27 changed files with 1169 additions and 326 deletions
+26
View File
@@ -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
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
run: cd test && make -j2
- name: check fuzz test target
if: matrix.os == 'ubuntu-latest'
run: cd test && make -f Makefile.fuzz_test
run: cd test && make fuzz_test
- name: setup msbuild on windows
if: matrix.os == 'windows-latest'
uses: microsoft/setup-msbuild@v1.0.2
+2
View File
@@ -13,10 +13,12 @@ example/*.pem
test/httplib.cc
test/httplib.h
test/test
test/server_fuzzer
test/test_proxy
test/test_split
test/test.xcodeproj/xcuser*
test/test.xcodeproj/*/xcuser*
test/*.o
test/*.pem
test/*.srl
+4 -20
View File
@@ -60,27 +60,11 @@
]]
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?
find_package(Git QUIET)
if(Git_FOUND)
# Gets the latest tag as a string like "v0.6.6"
# Can silently fail if git isn't on the system
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE _raw_version_string
ERROR_VARIABLE _git_tag_error
)
endif()
# 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]+\.?)+")
# 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.
# Also used if the fallback to user agent string is being used.
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
+10 -2
View File
@@ -220,7 +220,7 @@ svr.set_exception_handler([](const auto& req, auto& res, std::exception &e) {
### Pre routing handler
```cpp
svr.set_pre_routing_handler([](const auto& req, auto& res) -> bool {
svr.set_pre_routing_handler([](const auto& req, auto& res) {
if (req.path == "/hello") {
res.set_content("world", "text/html");
return Server::HandlerResponse::Handled;
@@ -303,7 +303,7 @@ Without content length:
svr.Get("/stream", [&](const Request &req, Response &res) {
res.set_content_provider(
"text/plain", // Content type
[&](size_t offset, size_t length, DataSink &sink) {
[&](size_t offset, DataSink &sink) {
if (/* there is still data */) {
std::vector<char> data;
// prepare data...
@@ -746,6 +746,12 @@ res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
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
-------------------------------
@@ -787,6 +793,8 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
#include <httplib.h>
```
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 and Cygwin on Windows are not supported.
License
+12
View File
@@ -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
View File
@@ -1,14 +1,17 @@
#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
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-static -lbrotlienc-static -lbrotlidec-static
BROTLI_DIR = $(PREFIX)/opt/brotli
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
@@ -47,4 +50,4 @@ pem:
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
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
+1 -1
View File
@@ -15,5 +15,5 @@ int main(void) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("localhost", 8080);
svr.listen("0.0.0.0", 8080);
}
+6
View File
@@ -0,0 +1,6 @@
#/usr/bin/env bash
for i in {1..10000}
do
echo "#### $i ####"
curl -X POST -F image_file=@$1 http://localhost:1234/post > /dev/null
done
+536 -204
View File
File diff suppressed because it is too large Load Diff
+98 -2
View File
@@ -1,7 +1,103 @@
project('cpp-httplib', 'cpp', license: 'MIT')
# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
#
# SPDX-License-Identifier: MIT
cpp_httplib_dep = declare_dependency(include_directories: include_directories('.'))
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()
python = import('python').find_installation('python3')
if version == 'undefined'
# Meson doesn't have regular expressions, but since it is implemented
# in python we can be sure we can use it to parse the file manually
version = run_command(
python, '-c', 'import re; raw_version = re.search("User\-Agent.*cpp\-httplib/([0-9]+\.?)+", open("httplib.h").read()).group(0); print(re.search("([0-9]+\\.?)+", raw_version).group(0))'
).stdout().strip()
endif
message('cpp-httplib version ' + version)
deps = [dependency('threads')]
args = []
openssl_dep = dependency('openssl', version: ['>=1.1.1', '<1.1.2'], 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')
httplib_ch = custom_target(
'split',
input: 'httplib.h',
output: ['httplib.cc', 'httplib.h'],
command: [python, 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,
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('.'))
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
+9
View File
@@ -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 Python 3)')
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
+44 -24
View File
@@ -19,29 +19,49 @@ args_parser.add_argument(
args = args_parser.parse_args()
cur_dir = os.path.dirname(sys.argv[0])
with open(cur_dir + '/httplib.h') as f:
lines = f.readlines()
lib_name = 'httplib'
header_name = '/' + lib_name + '.h'
source_name = '/' + lib_name + '.' + args.extension
# get the input file
in_file = cur_dir + header_name
# get the output file
h_out = args.out + header_name
cc_out = args.out + source_name
python_version = sys.version_info[0]
if python_version < 3:
os.makedirs(args.out)
# 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:
os.makedirs(args.out, exist_ok=True)
in_implementation = False
cc_out = args.out + source_name
with open(h_out, 'w') as fh, open(cc_out, 'w') as fc:
fc.write('#include "httplib.h"\n')
fc.write('namespace httplib {\n')
for line in lines:
is_border_line = border in line
if is_border_line:
in_implementation = not in_implementation
elif in_implementation:
fc.write(line.replace('inline ', ''))
else:
fh.write(line)
fc.write('} // namespace httplib\n')
print("Wrote {} and {}".format(h_out, cc_out))
else:
os.makedirs(args.out, exist_ok=True)
in_implementation = False
h_out = args.out + '/httplib.h'
cc_out = args.out + '/httplib.' + args.extension
with open(h_out, 'w') as fh, open(cc_out, 'w') as fc:
fc.write('#include "httplib.h"\n')
fc.write('namespace httplib {\n')
for line in lines:
is_border_line = border in line
if is_border_line:
in_implementation = not in_implementation
elif in_implementation:
fc.write(line.replace('inline ', ''))
else:
fh.write(line)
fc.write('} // namespace httplib\n')
print("Wrote {} and {}".format(h_out, cc_out))
print("{} and {} are up to date".format(h_out, cc_out))
+33 -7
View File
@@ -1,20 +1,30 @@
#CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address
CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
OPENSSL_DIR = /usr/local/opt/openssl@1.1
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
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
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
# 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.
proxy : test_proxy
./test_proxy
@@ -22,12 +32,28 @@ proxy : test_proxy
test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
$(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
$(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 .
@@ -42,4 +68,4 @@ cert.pem:
#c_rehash .
clean:
rm -f test test_proxy pem *.0 *.1 *.srl httplib.h httplib.cc
rm -f test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc
-36
View File
@@ -1,36 +0,0 @@
#CXX = clang++
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
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
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
# 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
# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
all 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) $(CXXFLAGS) -o $@ $< $(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) $(CXXFLAGS) -c -o $@ $<
clean:
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -20,16 +20,16 @@ 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 = in.tellg();
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(), bytes.size());
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;
}
}
+97
View File
@@ -0,0 +1,97 @@
# 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']
)
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,
rootca_key_pem,
rootca_cert_pem,
client_key_pem,
client_cert_pem
],
workdir: meson.current_build_dir(),
timeout: 300
)
+252 -20
View File
@@ -8,6 +8,7 @@
#include <sstream>
#include <stdexcept>
#include <thread>
#include <type_traits>
#define SERVER_CERT_FILE "./cert.pem"
#define SERVER_CERT2_FILE "./cert2.pem"
@@ -36,8 +37,17 @@ MultipartFormData &get_file_value(MultipartFormDataItems &files,
auto it = std::find_if(
files.begin(), files.end(),
[&](const MultipartFormData &file) { return file.name == key; });
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
return *it;
#else
if (it != files.end()) { return *it; }
throw std::runtime_error("invalid mulitpart form data name error");
#endif
}
TEST(ConstructorTest, MoveConstructible) {
EXPECT_FALSE(std::is_copy_constructible<Client>::value);
EXPECT_TRUE(std::is_nothrow_move_constructible<Client>::value);
}
#ifdef _WIN32
@@ -48,6 +58,14 @@ TEST(StartupTest, WSAStartup) {
}
#endif
TEST(DecodeURLTest, PercentCharacter) {
EXPECT_EQ(
detail::decode_url(
R"(descrip=Gastos%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA%C3%B1%C3%91%206)",
false),
R"(descrip=Gastos áéíóúñÑ 6)");
}
TEST(EncodeQueryParamTest, ParseUnescapedChararactersTest) {
string unescapedCharacters = "-_.!~*'()";
@@ -165,6 +183,12 @@ TEST(GetHeaderValueTest, RegularValue) {
EXPECT_STREQ("text/html", val);
}
TEST(GetHeaderValueTest, RegularValueWithDifferentCase) {
Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
auto val = detail::get_header_value(headers, "content-type", 0, "text/plain");
EXPECT_STREQ("text/html", val);
}
TEST(GetHeaderValueTest, SetContent) {
Response res;
@@ -377,6 +401,31 @@ TEST(ChunkedEncodingTest, FromHTTPWatch_Online) {
EXPECT_EQ(out, res->body);
}
TEST(HostnameToIPConversionTest, HTTPWatch_Online) {
auto host = "www.httpwatch.com";
auto ip = hosted_at(host);
EXPECT_EQ("191.236.16.12", ip);
std::vector<std::string> addrs;
hosted_at(host, addrs);
EXPECT_EQ(1u, addrs.size());
}
#if 0 // It depends on each test environment...
TEST(HostnameToIPConversionTest, YouTube_Online) {
auto host = "www.youtube.com";
std::vector<std::string> addrs;
hosted_at(host, addrs);
EXPECT_EQ(20u, addrs.size());
auto it = std::find(addrs.begin(), addrs.end(), "2607:f8b0:4006:809::200e");
EXPECT_TRUE(it != addrs.end());
}
#endif
TEST(ChunkedEncodingTest, WithContentReceiver_Online) {
auto host = "www.httpwatch.com";
@@ -573,9 +622,14 @@ TEST(ConnectionErrorTest, Timeout) {
#endif
cli.set_connection_timeout(std::chrono::seconds(2));
// only probe one address type so that the error reason
// correlates to the timed-out IPv4, not the unsupported
// IPv6 connection attempt
cli.set_address_family(AF_INET);
auto res = cli.Get("/");
ASSERT_TRUE(!res);
EXPECT_TRUE(res.error() == Error::Connection);
EXPECT_EQ(Error::ConnectionTimeout, res.error());
}
TEST(CancelTest, NoCancel_Online) {
@@ -730,6 +784,39 @@ TEST(DigestAuthTest, FromHTTPWatch_Online) {
}
#endif
TEST(SpecifyServerIPAddressTest, AnotherHostname_Online) {
auto host = "google.com";
auto another_host = "example.com";
auto wrong_ip = "0.0.0.0";
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host);
#else
Client cli(host);
#endif
cli.set_hostname_addr_map({{another_host, wrong_ip}});
auto res = cli.Get("/");
ASSERT_TRUE(res);
ASSERT_EQ(301, res->status);
}
TEST(SpecifyServerIPAddressTest, RealHostname_Online) {
auto host = "google.com";
auto wrong_ip = "0.0.0.0";
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host);
#else
Client cli(host);
#endif
cli.set_hostname_addr_map({{host, wrong_ip}});
auto res = cli.Get("/");
ASSERT_TRUE(!res);
EXPECT_EQ(Error::Connection, res.error());
}
TEST(AbsoluteRedirectTest, Redirect_Online) {
auto host = "nghttp2.org";
@@ -971,8 +1058,15 @@ TEST(RedirectFromPageWithContentIP6, Redirect) {
auto th = std::thread([&]() { svr.listen("::1", 1234); });
while (!svr.is_running()) {
// When IPV6 support isn't available svr.listen("::1", 1234) never
// actually starts anything, so the condition !svr.is_running() will
// always remain true, and the loop never stops.
// This basically counts how many milliseconds have passed since the
// call to svr.listen(), and if after 5 seconds nothing started yet
// aborts the test.
for (unsigned int milliseconds = 0; !svr.is_running(); milliseconds++) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
ASSERT_LT(milliseconds, 5000U);
}
// Give GET time to get a few messages.
@@ -1135,15 +1229,17 @@ TEST(ErrorHandlerTest, ContentLength) {
ASSERT_FALSE(svr.is_running());
}
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(ExceptionHandlerTest, ContentLength) {
Server svr;
svr.set_exception_handler(
[](const Request & /*req*/, Response &res, std::exception & /*e*/) {
res.status = 500;
res.set_content("abcdefghijklmnopqrstuvwxyz",
"text/html"); // <= Content-Length still 13
});
svr.set_exception_handler([](const Request & /*req*/, Response &res,
std::exception &e) {
EXPECT_EQ("abc", std::string(e.what()));
res.status = 500;
res.set_content("abcdefghijklmnopqrstuvwxyz",
"text/html"); // <= Content-Length still 13 at this point
});
svr.Get("/hi", [](const Request & /*req*/, Response &res) {
res.set_content("Hello World!\n", "text/plain");
@@ -1155,21 +1251,35 @@ TEST(ExceptionHandlerTest, ContentLength) {
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
{
for (size_t i = 0; i < 10; i++) {
Client cli(HOST, PORT);
auto res = cli.Get("/hi");
ASSERT_TRUE(res);
EXPECT_EQ(500, res->status);
EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
EXPECT_EQ("26", res->get_header_value("Content-Length"));
EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
for (size_t j = 0; j < 100; j++) {
auto res = cli.Get("/hi");
ASSERT_TRUE(res);
EXPECT_EQ(500, res->status);
EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
EXPECT_EQ("26", res->get_header_value("Content-Length"));
EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
}
cli.set_keep_alive(true);
for (size_t j = 0; j < 100; j++) {
auto res = cli.Get("/hi");
ASSERT_TRUE(res);
EXPECT_EQ(500, res->status);
EXPECT_EQ("text/html", res->get_header_value("Content-Type"));
EXPECT_EQ("26", res->get_header_value("Content-Length"));
EXPECT_EQ("abcdefghijklmnopqrstuvwxyz", res->body);
}
}
svr.stop();
thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
TEST(NoContentTest, ContentLength) {
Server svr;
@@ -1349,11 +1459,13 @@ protected:
std::this_thread::sleep_for(std::chrono::seconds(2));
res.set_content("slow", "text/plain");
})
#if 0
.Post("/slowpost",
[&](const Request & /*req*/, Response &res) {
std::this_thread::sleep_for(std::chrono::seconds(2));
res.set_content("slow", "text/plain");
})
#endif
.Get("/remote_addr",
[&](const Request &req, Response &res) {
auto remote_addr = req.headers.find("REMOTE_ADDR")->second;
@@ -1556,6 +1668,11 @@ protected:
EXPECT_EQ("0", req.get_header_value("Content-Length"));
res.set_content("empty-no-content-type", "text/plain");
})
.Post("/post-large",
[&](const Request &req, Response &res) {
EXPECT_EQ(req.body, LARGE_DATA);
res.set_content(req.body, "text/plain");
})
.Put("/empty-no-content-type",
[&](const Request &req, Response &res) {
EXPECT_EQ(req.body, "");
@@ -1961,6 +2078,13 @@ TEST_F(ServerTest, PostEmptyContentWithNoContentType) {
ASSERT_EQ("empty-no-content-type", res->body);
}
TEST_F(ServerTest, PostLarge) {
auto res = cli_.Post("/post-large", LARGE_DATA, "text/plain");
ASSERT_TRUE(res);
ASSERT_EQ(200, res->status);
EXPECT_EQ(LARGE_DATA, res->body);
}
TEST_F(ServerTest, PutEmptyContentWithNoContentType) {
auto res = cli_.Put("/empty-no-content-type");
ASSERT_TRUE(res);
@@ -2623,6 +2747,7 @@ TEST_F(ServerTest, SlowRequest) {
std::thread([=]() { auto res = cli_.Get("/slow"); }));
}
#if 0
TEST_F(ServerTest, SlowPost) {
char buffer[64 * 1024];
memset(buffer, 0x42, sizeof(buffer));
@@ -2656,6 +2781,7 @@ TEST_F(ServerTest, SlowPostFail) {
ASSERT_TRUE(!res);
EXPECT_EQ(Error::Write, res.error());
}
#endif
TEST_F(ServerTest, Put) {
auto res = cli_.Put("/put", "PUT", "text/plain");
@@ -3304,7 +3430,7 @@ static bool send_request(time_t read_timeout_sec, const std::string &req,
auto error = Error::Success;
auto client_sock = detail::create_client_socket(
HOST, PORT, AF_UNSPEC, false, nullptr,
HOST, "", PORT, AF_UNSPEC, false, nullptr,
/*connection_timeout_sec=*/5, 0,
/*read_timeout_sec=*/5, 0,
/*write_timeout_sec=*/5, 0, std::string(), error);
@@ -3562,10 +3688,13 @@ TEST(StreamingTest, NoContentLengthStreaming) {
Client client(HOST, PORT);
auto get_thread = std::thread([&client]() {
auto res = client.Get("/stream", [](const char *data, size_t len) -> bool {
EXPECT_EQ("aaabbb", std::string(data, len));
return true;
});
std::string s;
auto res =
client.Get("/stream", [&s](const char *data, size_t len) -> bool {
s += std::string(data, len);
return true;
});
EXPECT_EQ("aaabbb", s);
});
// Give GET time to get a few messages.
@@ -3623,6 +3752,7 @@ TEST(MountTest, Unmount) {
ASSERT_FALSE(svr.is_running());
}
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(ExceptionTest, ThrowExceptionInHandler) {
Server svr;
@@ -3651,6 +3781,7 @@ TEST(ExceptionTest, ThrowExceptionInHandler) {
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
#endif
TEST(KeepAliveTest, ReadTimeout) {
Server svr;
@@ -3690,6 +3821,36 @@ TEST(KeepAliveTest, ReadTimeout) {
ASSERT_FALSE(svr.is_running());
}
TEST(KeepAliveTest, Issue1041) {
const auto resourcePath = "/hi";
Server svr;
svr.set_keep_alive_timeout(3);
svr.Get(resourcePath, [](const httplib::Request &, httplib::Response &res) {
res.set_content("Hello World!", "text/plain");
});
auto a2 = std::async(std::launch::async, [&svr] { svr.listen(HOST, PORT); });
std::this_thread::sleep_for(std::chrono::milliseconds(200));
Client cli(HOST, PORT);
cli.set_keep_alive(true);
auto result = cli.Get(resourcePath);
ASSERT_TRUE(result);
EXPECT_EQ(200, result->status);
std::this_thread::sleep_for(std::chrono::seconds(5));
result = cli.Get(resourcePath);
ASSERT_TRUE(result);
EXPECT_EQ(200, result->status);
svr.stop();
a2.wait();
}
TEST(ClientProblemDetectionTest, ContentProvider) {
Server svr;
@@ -4373,6 +4534,75 @@ TEST(SSLClientServerTest, SSLConnectTimeout) {
svr.stop();
t.join();
}
TEST(SSLClientServerTest, CustomizeServerSSLCtx) {
auto setup_ssl_ctx_callback = [](SSL_CTX &ssl_ctx) {
SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_COMPRESSION);
SSL_CTX_set_options(&ssl_ctx,
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_SSLv3);
SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_set_options(&ssl_ctx, SSL_OP_NO_TLSv1_1);
auto ciphers = "ECDHE-RSA-AES128-SHA256:"
"ECDHE-DSS-AES128-SHA256:"
"ECDHE-RSA-AES256-SHA256:"
"ECDHE-DSS-AES256-SHA256:";
SSL_CTX_set_cipher_list(&ssl_ctx, ciphers);
if (SSL_CTX_use_certificate_chain_file(&ssl_ctx, SERVER_CERT_FILE) != 1 ||
SSL_CTX_use_PrivateKey_file(&ssl_ctx, SERVER_PRIVATE_KEY_FILE,
SSL_FILETYPE_PEM) != 1) {
return false;
}
SSL_CTX_load_verify_locations(&ssl_ctx, CLIENT_CA_CERT_FILE,
CLIENT_CA_CERT_DIR);
SSL_CTX_set_verify(
&ssl_ctx,
SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE,
nullptr);
return true;
};
SSLServer svr(setup_ssl_ctx_callback);
ASSERT_TRUE(svr.is_valid());
svr.Get("/test", [&](const Request &req, Response &res) {
res.set_content("test", "text/plain");
svr.stop();
ASSERT_TRUE(true);
auto peer_cert = SSL_get_peer_certificate(req.ssl);
ASSERT_TRUE(peer_cert != nullptr);
auto subject_name = X509_get_subject_name(peer_cert);
ASSERT_TRUE(subject_name != nullptr);
std::string common_name;
{
char name[BUFSIZ];
auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
name, sizeof(name));
common_name.assign(name, static_cast<size_t>(name_len));
}
EXPECT_EQ("Common Name", common_name);
X509_free(peer_cert);
});
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
std::this_thread::sleep_for(std::chrono::milliseconds(1));
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
cli.enable_server_certificate_verification(false);
cli.set_connection_timeout(30);
auto res = cli.Get("/test");
ASSERT_TRUE(res);
ASSERT_EQ(200, res->status);
t.join();
}
#endif
#ifdef _WIN32
@@ -4388,9 +4618,11 @@ TEST(NoSSLSupport, SimpleInterface) {
}
#endif
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
TEST(InvalidScheme, SimpleInterface) {
ASSERT_ANY_THROW(Client cli("scheme://yahoo.com"));
}
#endif
TEST(NoScheme, SimpleInterface) {
Client cli("yahoo.com:80");
+7
View File
@@ -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)
+6
View File
@@ -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)
+6
View File
@@ -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)