Compare commits

..

No commits in common. "master" and "v0.16.3" have entirely different histories.

38 changed files with 866 additions and 27408 deletions

View File

@ -1,69 +0,0 @@
# SPDX-FileCopyrightText: 2025 Andrea Pappacoda <andrea@pappacoda.it>
# SPDX-License-Identifier: MIT
name: abidiff
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
defaults:
run:
shell: sh
jobs:
abi:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
container:
image: debian:testing
steps:
- name: Install dependencies
run: apt -y --update install --no-install-recommends
abigail-tools
ca-certificates
g++
git
libbrotli-dev
libssl-dev
meson
pkg-config
python3
zlib1g-dev
- uses: actions/checkout@v4
with:
path: current
- uses: actions/checkout@v4
with:
path: previous
fetch-depth: 0
- name: Checkout previous
working-directory: previous
run: |
git switch master
git describe --tags --abbrev=0 master | xargs git checkout
- name: Build current
working-directory: current
run: |
meson setup --buildtype=debug -Dcpp-httplib_compile=true build
ninja -C build
- name: Build previous
working-directory: previous
run: |
meson setup --buildtype=debug -Dcpp-httplib_compile=true build
ninja -C build
- name: Run abidiff
run: abidiff
--headers-dir1 previous/build
--headers-dir2 current/build
previous/build/libcpp-httplib.so
current/build/libcpp-httplib.so

View File

@ -1,11 +1,5 @@
name: CIFuzz name: CIFuzz
on: [pull_request] on: [pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs: jobs:
Fuzzing: Fuzzing:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -25,7 +19,7 @@ jobs:
dry-run: false dry-run: false
language: c++ language: c++
- name: Upload Crash - name: Upload Crash
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts

View File

@ -1,126 +1,43 @@
name: test name: test
on: on: [push, pull_request]
push:
pull_request:
workflow_dispatch:
inputs:
gtest_filter:
description: 'Google Test filter'
test_linux:
description: 'Test on Linux'
type: boolean
default: true
test_macos:
description: 'Test on MacOS'
type: boolean
default: true
test_windows:
description: 'Test on Windows'
type: boolean
default: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
env:
GTEST_FILTER: ${{ github.event.inputs.gtest_filter || '*' }}
jobs: jobs:
style-check:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
continue-on-error: true
steps:
- name: checkout
uses: actions/checkout@v4
- name: run style check
run: |
clang-format --version
cd test && make style_check
ubuntu: ubuntu:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_linux == 'true')
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: install libraries - name: install brotli
run: sudo apt-get update && sudo apt-get install -y libbrotli-dev libcurl4-openssl-dev run: sudo apt-get update && sudo apt-get install -y libbrotli-dev
- name: build and run tests - name: build and run tests
run: cd test && make run: cd test && make -j4
- name: run fuzz test target - name: run fuzz test target
run: cd test && make fuzz_test run: cd test && make fuzz_test
macos: macos:
runs-on: macos-latest runs-on: macos-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_macos == 'true')
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: build and run tests - name: build and run tests
run: cd test && make run: |
- name: run fuzz test target cd test && make -j2
run: cd test && make fuzz_test
windows: windows:
runs-on: windows-latest runs-on: windows-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_windows == 'true')
strategy:
matrix:
config:
- with_ssl: false
name: without SSL
- with_ssl: true
name: with SSL
name: windows ${{ matrix.config.name }}
steps: steps:
- name: Prepare Git for Checkout on Windows - name: prepare git for checkout on windows
run: | run: |
git config --global core.autocrlf false git config --global core.autocrlf false
git config --global core.eol lf git config --global core.eol lf
- name: Checkout - name: checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Export GitHub Actions cache environment variables - name: setup msbuild on windows
uses: actions/github-script@v7
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Setup msbuild on windows
uses: microsoft/setup-msbuild@v2 uses: microsoft/setup-msbuild@v2
- name: Install vcpkg dependencies - name: make-windows
run: vcpkg install gtest curl zlib brotli run: |
- name: Install OpenSSL cd test
if: ${{ matrix.config.with_ssl }} msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
run: choco install openssl x64\Release\test.exe
- name: Configure CMake ${{ matrix.config.name }}
run: >
cmake -B build -S .
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake
-DHTTPLIB_TEST=ON
-DHTTPLIB_REQUIRE_ZLIB=ON
-DHTTPLIB_REQUIRE_BROTLI=ON
-DHTTPLIB_REQUIRE_OPENSSL=${{ matrix.config.with_ssl && 'ON' || 'OFF' }}
- name: Build ${{ matrix.config.name }}
run: cmake --build build --config Release -- /v:m /clp:ShowCommandLine
- name: Run tests ${{ matrix.config.name }}
run: ctest --output-on-failure --test-dir build -C Release
env:
VCPKG_ROOT: "C:/vcpkg"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"

6
.gitignore vendored
View File

@ -9,8 +9,6 @@ example/benchmark
example/redirect example/redirect
example/sse* example/sse*
example/upload example/upload
example/one_time_request
example/server_and_client
example/*.pem example/*.pem
test/httplib.cc test/httplib.cc
test/httplib.h test/httplib.h
@ -23,9 +21,6 @@ test/test.xcodeproj/*/xcuser*
test/*.o test/*.o
test/*.pem test/*.pem
test/*.srl test/*.srl
test/_build_*
work/
benchmark/server*
*.swp *.swp
@ -39,7 +34,6 @@ Release
*.db *.db
ipch ipch
*.dSYM *.dSYM
*.pyc
.* .*
!/.gitattributes !/.gitattributes
!/.travis.yml !/.travis.yml

View File

@ -299,8 +299,6 @@ if(HTTPLIB_INSTALL)
# ex: /usr/share/doc/httplib/README.md and /usr/share/licenses/httplib/LICENSE # ex: /usr/share/doc/httplib/README.md and /usr/share/licenses/httplib/LICENSE
install(FILES "README.md" DESTINATION "${CMAKE_INSTALL_DOCDIR}") install(FILES "README.md" DESTINATION "${CMAKE_INSTALL_DOCDIR}")
install(FILES "LICENSE" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/${PROJECT_NAME}") install(FILES "LICENSE" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/${PROJECT_NAME}")
include(CPack)
endif() endif()
if(HTTPLIB_TEST) if(HTTPLIB_TEST)

View File

@ -1,11 +0,0 @@
FROM yhirose4dockerhub/ubuntu-builder AS builder
WORKDIR /build
COPY httplib.h .
COPY docker/main.cc .
RUN g++ -std=c++23 -static -o server -O2 -I. main.cc && strip server
FROM scratch
COPY --from=builder /build/server /server
COPY docker/html/index.html /html/index.html
EXPOSE 80
CMD ["/server"]

111
README.md
View File

@ -39,10 +39,10 @@ svr.listen("0.0.0.0", 8080);
#include "path/to/httplib.h" #include "path/to/httplib.h"
// HTTP // HTTP
httplib::Client cli("http://yhirose.github.io"); httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
// HTTPS // HTTPS
httplib::Client cli("https://yhirose.github.io"); httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
auto res = cli.Get("/hi"); auto res = cli.Get("/hi");
res->status; res->status;
@ -77,9 +77,6 @@ cli.set_ca_cert_path("./ca-bundle.crt");
// Disable cert verification // Disable cert verification
cli.enable_server_certificate_verification(false); cli.enable_server_certificate_verification(false);
// Disable host verification
cli.enable_server_hostname_verification(false);
``` ```
> [!NOTE] > [!NOTE]
@ -125,21 +122,6 @@ int main(void)
res.set_content(req.body, "text/plain"); res.set_content(req.body, "text/plain");
}); });
// If the handler takes time to finish, you can also poll the connection state
svr.Get("/task", [&](const Request& req, Response& res) {
const char * result = nullptr;
process.run(); // for example, starting an external process
while (result == nullptr) {
sleep(1);
if (req.is_connection_closed()) {
process.kill(); // kill the process
return;
}
result = process.stdout(); // != nullptr if the process finishes
}
res.set_content(result, "text/plain");
});
svr.Get("/stop", [&](const Request& req, Response& res) { svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop(); svr.stop();
}); });
@ -402,18 +384,6 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
}); });
``` ```
### Send file content
```cpp
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/content.html");
});
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/content", "text/html");
});
```
### 'Expect: 100-continue' handler ### 'Expect: 100-continue' handler
By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header. By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header.
@ -462,7 +432,7 @@ 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 the **default** task queue, with a default thread count of 8 or `std::thread::hardware_concurrency() - 1`, whichever is greater. You can change it with `CPPHTTPLIB_THREAD_POOL_COUNT`. `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`.
If you want to set the thread count at runtime, there is no convenient way... But here is how. If you want to set the thread count at runtime, there is no convenient way... But here is how.
@ -572,18 +542,18 @@ enum Error {
```c++ ```c++
httplib::Headers headers = { httplib::Headers headers = {
{ "Hello", "World!" } { "Accept-Encoding", "gzip, deflate" }
}; };
auto res = cli.Get("/hi", headers); auto res = cli.Get("/hi", headers);
``` ```
or or
```c++ ```c++
auto res = cli.Get("/hi", {{"Hello", "World!"}}); auto res = cli.Get("/hi", {{"Accept-Encoding", "gzip, deflate"}});
``` ```
or or
```c++ ```c++
cli.set_default_headers({ cli.set_default_headers({
{ "Hello", "World!" } { "Accept-Encoding", "gzip, deflate" }
}); });
auto res = cli.Get("/hi"); auto res = cli.Get("/hi");
``` ```
@ -654,9 +624,6 @@ res = cli.Options("/resource/foo");
cli.set_connection_timeout(0, 300000); // 300 milliseconds cli.set_connection_timeout(0, 300000); // 300 milliseconds
cli.set_read_timeout(5, 0); // 5 seconds cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds cli.set_write_timeout(5, 0); // 5 seconds
// This method works the same as curl's `--max-timeout` option
svr.set_max_timeout(5000); // 5 seconds
``` ```
### Receive content with a content receiver ### Receive content with a content receiver
@ -841,21 +808,6 @@ The server can apply compression to the following MIME type contents:
Brotli compression is available with `CPPHTTPLIB_BROTLI_SUPPORT`. Necessary libraries should be linked. Brotli compression is available with `CPPHTTPLIB_BROTLI_SUPPORT`. Necessary libraries should be linked.
Please see https://github.com/google/brotli for more detail. Please see https://github.com/google/brotli for more detail.
### Default `Accept-Encoding` value
The default `Accept-Encoding` value contains all possible compression types. So, the following two examples are same.
```c++
res = cli.Get("/resource/foo");
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
```
If we don't want a response without compression, we have to set `Accept-Encoding` to an empty string. This behavior is similar to curl.
```c++
res = cli.Get("/resource/foo", {{"Accept-Encoding", ""}});
```
### Compress request body on client ### Compress request body on client
```c++ ```c++
@ -867,27 +819,14 @@ res = cli.Post("/resource/foo", "...", "text/plain");
```c++ ```c++
cli.set_decompress(false); cli.set_decompress(false);
res = cli.Get("/resource/foo"); res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
res->body; // Compressed data res->body; // Compressed data
``` ```
Unix Domain Socket Support Use `poll` instead of `select`
-------------------------- ------------------------------
Unix Domain Socket support is available on Linux and macOS. `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`.
```c++
// Server
httplib::Server svr;
svr.set_address_family(AF_UNIX).listen("./my-socket.sock", 80);
// Client
httplib::Client cli("./my-socket.sock");
cli.set_address_family(AF_UNIX);
```
"my-socket.sock" can be a relative path or an absolute path. You application must have the appropriate permissions for the path. You can also use an abstract socket address on Linux. To use an abstract socket address, prepend a null byte ('\x00') to the path.
Split httplib.h into .h and .cc Split httplib.h into .h and .cc
@ -909,32 +848,6 @@ $ ./split.py
Wrote out/httplib.h and out/httplib.cc Wrote out/httplib.h and out/httplib.cc
``` ```
Dockerfile for Static HTTP Server
---------------------------------
Dockerfile for static HTTP server is available. Port number of this HTTP server is 80, and it serves static files from `/html` directory in the container.
```bash
> docker build -t cpp-httplib-server .
...
> docker run --rm -it -p 8080:80 -v ./docker/html:/html cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
```
From Docker Hub
```bash
> docker run --rm -it -p 8080:80 -v ./docker/html:/html yhirose4dockerhub/cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
```
NOTE NOTE
---- ----
@ -961,12 +874,12 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
> 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. > 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] > [!NOTE]
> Windows 8 or lower, Visual Studio 2015 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested. > Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.
License License
------- -------
MIT license (© 2025 Yuji Hirose) MIT license (© 2024 Yuji Hirose)
Special Thanks To Special Thanks To
----------------- -----------------

View File

@ -1,62 +0,0 @@
CXXFLAGS = -std=c++11 -O2 -I..
CPPHTTPLIB_FLAGS = -DCPPHTTPLIB_THREAD_POOL_COUNT=16
BENCH = bombardier -c 10 -d 5s localhost:8080
MONITOR = ali http://localhost:8080
# cpp-httplib
bench: server
@echo "--------------------\n cpp-httplib latest\n--------------------\n"
@./server & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor: server
@./server & export PID=$$!; $(MONITOR); kill $${PID}
run : server
@./server
server : cpp-httplib/main.cpp ../httplib.h
g++ -o $@ $(CXXFLAGS) $(CPPHTTPLIB_FLAGS) cpp-httplib/main.cpp
# cpp-httplib
bench-base: server-base
@echo "---------------------\n cpp-httplib v0.18.0\n---------------------\n"
@./server-base & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor-base: server-base
@./server-base & export PID=$$!; $(MONITOR); kill $${PID}
run-base : server-base
@./server-base
server-base : cpp-httplib-base/main.cpp cpp-httplib-base/httplib.h
g++ -o $@ $(CXXFLAGS) $(CPPHTTPLIB_FLAGS) cpp-httplib-base/main.cpp
# crow
bench-crow: server-crow
@echo "-------------\n Crow v1.2.0\n-------------\n"
@./server-crow & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor-crow: server-crow
@./server-crow & export PID=$$!; $(MONITOR); kill $${PID}
run-crow : server-crow
@./server-crow
server-crow : crow/main.cpp
g++ -o $@ $(CXXFLAGS) crow/main.cpp
# misc
build: server server-base server-crow
bench-all: bench-crow bench bench-base
issue:
bombardier -c 10 -d 30s localhost:8080
clean:
rm -rf server*

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
#include "./httplib.h"
using namespace httplib;
int main() {
Server svr;
svr.Get("/", [](const Request &, Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
}

View File

@ -1,12 +0,0 @@
#include "httplib.h"
using namespace httplib;
int main() {
Server svr;
svr.Get("/", [](const Request &, Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
#include "crow_all.h"
class CustomLogger : public crow::ILogHandler {
public:
void log(std::string, crow::LogLevel) {}
};
int main() {
CustomLogger logger;
crow::logger::setHandler(&logger);
crow::SimpleApp app;
CROW_ROUTE(app, "/")([]() { return "Hello world!"; });
app.port(8080).multithreaded().run();
}

View File

@ -1,2 +0,0 @@
rm -f httplib.h
wget https://raw.githubusercontent.com/yhirose/cpp-httplib/v$1/httplib.h

View File

@ -1,7 +0,0 @@
services:
http:
build: .
ports:
- "8080:80"
volumes:
- ./docker/html:/html

View File

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome to cpp-httplib!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to cpp-httplib!</h1>
<p>If you see this page, the cpp-httplib web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="https://github.com/yhirose/cpp-httplib">github.com/yhirose/cpp-httplib</a>.<br/>
<p><em>Thank you for using cpp-httplib.</em></p>
</body>
</html>

View File

@ -1,81 +0,0 @@
//
// main.cc
//
// Copyright (c) 2025 Yuji Hirose. All rights reserved.
// MIT License
//
#include <chrono>
#include <ctime>
#include <format>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <httplib.h>
constexpr auto error_html = R"(<html>
<head><title>{} {}</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>cpp-httplib/{}</center>
</body>
</html>
)";
void sigint_handler(int s) { exit(1); }
std::string time_local() {
auto p = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(p);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), "%d/%b/%Y:%H:%M:%S %z");
return ss.str();
}
std::string log(auto &req, auto &res) {
auto remote_user = "-"; // TODO:
auto request = std::format("{} {} {}", req.method, req.path, req.version);
auto body_bytes_sent = res.get_header_value("Content-Length");
auto http_referer = "-"; // TODO:
auto http_user_agent = req.get_header_value("User-Agent", "-");
// NOTE: From NGINX default access log format
// log_format combined '$remote_addr - $remote_user [$time_local] '
// '"$request" $status $body_bytes_sent '
// '"$http_referer" "$http_user_agent"';
return std::format(R"({} - {} [{}] "{}" {} {} "{}" "{}")", req.remote_addr,
remote_user, time_local(), request, res.status,
body_bytes_sent, http_referer, http_user_agent);
}
int main(int argc, const char **argv) {
signal(SIGINT, sigint_handler);
auto base_dir = "./html";
auto host = "0.0.0.0";
auto port = 80;
httplib::Server svr;
svr.set_error_handler([](auto & /*req*/, auto &res) {
auto body =
std::format(error_html, res.status, httplib::status_message(res.status),
CPPHTTPLIB_VERSION);
res.set_content(body, "text/html");
});
svr.set_logger(
[](auto &req, auto &res) { std::cout << log(req, res) << std::endl; });
svr.set_mount_point("/", base_dir);
std::cout << std::format("Serving HTTP on {0} port {1} ...", host, port)
<< std::endl;
auto ret = svr.listen(host, port);
return ret ? 0 : 1;
}

View File

@ -18,7 +18,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = $(PREFIX)/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: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark issue
server : server.cc ../httplib.h Makefile server : server.cc ../httplib.h Makefile
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
@ -53,12 +53,9 @@ benchmark : benchmark.cc ../httplib.h Makefile
one_time_request : one_time_request.cc ../httplib.h Makefile one_time_request : one_time_request.cc ../httplib.h Makefile
$(CXX) -o one_time_request $(CXXFLAGS) one_time_request.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(CXX) -o one_time_request $(CXXFLAGS) one_time_request.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
server_and_client : server_and_client.cc ../httplib.h Makefile
$(CXX) -o server_and_client $(CXXFLAGS) server_and_client.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
pem: pem:
openssl genrsa 2048 > key.pem openssl genrsa 2048 > key.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 ssecli benchmark one_time_request server_and_client *.pem rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request *.pem

View File

@ -22,34 +22,34 @@
<ProjectGuid>{6DB1FC63-B153-4279-92B7-D8A11AF285D6}</ProjectGuid> <ProjectGuid>{6DB1FC63-B153-4279-92B7-D8A11AF285D6}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>client</RootNamespace> <RootNamespace>client</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">

View File

@ -18,41 +18,38 @@
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClCompile Include="simplesvr.cc" />
</ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{864CD288-050A-4C8B-9BEF-3048BD876C5B}</ProjectGuid> <ProjectGuid>{864CD288-050A-4C8B-9BEF-3048BD876C5B}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>sample</RootNamespace> <RootNamespace>sample</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -154,6 +151,9 @@
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="server.cc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View File

@ -1,90 +0,0 @@
//
// server_and_client.cc
//
// Copyright (c) 2025 Yuji Hirose. All rights reserved.
// MIT License
//
#include <httplib.h>
#include <iostream>
#include <string>
using namespace httplib;
std::string dump_headers(const Headers &headers) {
std::string s;
char buf[BUFSIZ];
for (auto it = headers.begin(); it != headers.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
s += buf;
}
return s;
}
void logger(const Request &req, const Response &res) {
std::string s;
char buf[BUFSIZ];
s += "================================\n";
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
s += buf;
std::string query;
for (auto it = req.params.begin(); it != req.params.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%c%s=%s",
(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
x.second.c_str());
query += buf;
}
snprintf(buf, sizeof(buf), "%s\n", query.c_str());
s += buf;
s += dump_headers(req.headers);
s += "--------------------------------\n";
snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
s += buf;
s += dump_headers(res.headers);
s += "\n";
if (!res.body.empty()) { s += res.body; }
s += "\n";
std::cout << s;
}
int main(void) {
// Server
Server svr;
svr.set_logger(logger);
svr.Post("/post", [&](const Request & /*req*/, Response &res) {
res.set_content("POST", "text/plain");
});
auto th = std::thread([&]() { svr.listen("localhost", 8080); });
auto se = detail::scope_exit([&] {
svr.stop();
th.join();
});
svr.wait_until_ready();
// Client
Client cli{"localhost", 8080};
std::string body = R"({"hello": "world"})";
auto res = cli.Post("/post", body, "application/json");
std::cout << "--------------------------------" << std::endl;
std::cout << to_string(res.error()) << std::endl;
}

View File

@ -12,7 +12,8 @@ using namespace std;
class EventDispatcher { class EventDispatcher {
public: public:
EventDispatcher() {} EventDispatcher() {
}
void wait_event(DataSink *sink) { void wait_event(DataSink *sink) {
unique_lock<mutex> lk(m_); unique_lock<mutex> lk(m_);

1871
httplib.h

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ project(
'b_lto=true', 'b_lto=true',
'warning_level=3' 'warning_level=3'
], ],
meson_version: '>=0.62.0' meson_version: '>=0.47.0'
) )
# Check just in case downstream decides to edit the source # Check just in case downstream decides to edit the source
@ -98,18 +98,20 @@ if get_option('cpp-httplib_compile')
) )
else else
install_headers('httplib.h') install_headers('httplib.h')
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: '.') cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: include_directories('.'))
import('pkgconfig').generate( import('pkgconfig').generate(
name: 'cpp-httplib', name: 'cpp-httplib',
description: 'A C++ HTTP/HTTPS server and client library', description: 'A C++ HTTP/HTTPS server and client library',
install_dir: get_option('datadir')/'pkgconfig', install_dir: join_paths(get_option('datadir'), 'pkgconfig'),
url: 'https://github.com/yhirose/cpp-httplib', url: 'https://github.com/yhirose/cpp-httplib',
version: version version: version
) )
endif endif
meson.override_dependency('cpp-httplib', cpp_httplib_dep) if meson.version().version_compare('>=0.54.0')
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
endif
if get_option('cpp-httplib_test') if get_option('cpp-httplib_test')
subdir('test') subdir('test')

View File

@ -24,11 +24,9 @@ else()
FetchContent_MakeAvailable(gtest) FetchContent_MakeAvailable(gtest)
endif() endif()
find_package(CURL REQUIRED) add_executable(httplib-test test.cc)
add_executable(httplib-test test.cc include_httplib.cc $<$<BOOL:${WIN32}>:include_windows_h.cc>)
target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8;/bigobj>") target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8;/bigobj>")
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main CURL::libcurl) target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main)
gtest_discover_tests(httplib-test) gtest_discover_tests(httplib-test)
file( file(
@ -37,11 +35,6 @@ file(
) )
if(HTTPLIB_IS_USING_OPENSSL) if(HTTPLIB_IS_USING_OPENSSL)
if (OPENSSL_VERSION VERSION_LESS "3.2.0")
set(OPENSSL_X509_FLAG "-x509")
else()
set(OPENSSL_X509_FLAG "-x509v1")
endif()
find_program(OPENSSL_COMMAND find_program(OPENSSL_COMMAND
NAMES openssl NAMES openssl
PATHS ${OPENSSL_INCLUDE_DIR}/../bin PATHS ${OPENSSL_INCLUDE_DIR}/../bin
@ -61,7 +54,7 @@ if(HTTPLIB_IS_USING_OPENSSL)
COMMAND_ERROR_IS_FATAL ANY COMMAND_ERROR_IS_FATAL ANY
) )
execute_process( execute_process(
COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN 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} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY COMMAND_ERROR_IS_FATAL ANY
) )
@ -72,7 +65,7 @@ if(HTTPLIB_IS_USING_OPENSSL)
COMMAND_ERROR_IS_FATAL ANY COMMAND_ERROR_IS_FATAL ANY
) )
execute_process( execute_process(
COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.rootCA.conf -key rootCA.key.pem -days 1024 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 OUTPUT_FILE rootCA.cert.pem
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY COMMAND_ERROR_IS_FATAL ANY

View File

@ -18,7 +18,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = $(PREFIX)/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
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread -lcurl TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
# By default, use standalone_fuzz_target_runner. # By default, use standalone_fuzz_target_runner.
# This runner does no fuzzing, but simply executes the inputs # This runner does no fuzzing, but simply executes the inputs
@ -28,11 +28,6 @@ TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUP
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE. # OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
CLANG_FORMAT = clang-format
REALPATH = $(shell which grealpath 2>/dev/null || which realpath 2>/dev/null)
STYLE_CHECK_FILES = $(filter-out httplib.h httplib.cc, \
$(wildcard example/*.h example/*.cc fuzzing/*.h fuzzing/*.cc *.h *.cc ../httplib.h))
all : test test_split all : test test_split
./test ./test
@ -47,31 +42,6 @@ test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem
$(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS) $(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS)
check_abi:
@./check-shared-library-abi-compatibility.sh
.PHONY: style_check
style_check: $(STYLE_CHECK_FILES)
@for file in $(STYLE_CHECK_FILES); do \
$(CLANG_FORMAT) $$file > $$file.formatted; \
if ! diff -u $$file $$file.formatted; then \
file2=$$($(REALPATH) --relative-to=.. $$file); \
printf "\n%*s\n" 80 | tr ' ' '#'; \
printf "##%*s##\n" 76; \
printf "## %-70s ##\n" "$$file2 not properly formatted. Please run clang-format."; \
printf "##%*s##\n" 76; \
printf "%*s\n\n" 80 | tr ' ' '#'; \
failed=1; \
fi; \
rm -f $$file.formatted; \
done; \
if [ -n "$$failed" ]; then \
echo "Style check failed for one or more files. See above for details."; \
false; \
else \
echo "All files are properly formatted."; \
fi
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
$(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS) $(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS)
@ -93,8 +63,18 @@ httplib.cc : ../httplib.h
python3 ../split.py -o . python3 ../split.py -o .
cert.pem: cert.pem:
./gen-certs.sh 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 -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
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 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 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
openssl genrsa -aes256 -passout pass:test012! 2048 > client_encrypted.key.pem
openssl req -new -batch -config test.conf -key client_encrypted.key.pem -passin pass:test012! | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client_encrypted.cert.pem
#c_rehash .
clean: clean:
rm -rf test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM rm -f test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc

View File

@ -25,9 +25,7 @@ public:
bool is_readable() const override { return true; } bool is_readable() const override { return true; }
bool wait_readable() const override { return true; } bool is_writable() const override { return true; }
bool wait_writable() const override { return true; }
void get_remote_ip_and_port(std::string &ip, int &port) const override { void get_remote_ip_and_port(std::string &ip, int &port) const override {
ip = "127.0.0.1"; ip = "127.0.0.1";
@ -41,8 +39,6 @@ public:
socket_t socket() const override { return 0; } socket_t socket() const override { return 0; }
time_t duration() const override { return 0; };
private: private:
const uint8_t *data_; const uint8_t *data_;
size_t size_; size_t size_;
@ -54,12 +50,8 @@ class FuzzableServer : public httplib::Server {
public: public:
void ProcessFuzzedRequest(FuzzedStream &stream) { void ProcessFuzzedRequest(FuzzedStream &stream) {
bool connection_close = false; bool connection_close = false;
process_request(stream, process_request(stream, /*last_connection=*/false, connection_close,
/*remote_addr=*/"", nullptr);
/*remote_port =*/0,
/*local_addr=*/"",
/*local_port =*/0,
/*last_connection=*/false, connection_close, nullptr);
} }
}; };

View File

@ -1,18 +0,0 @@
#!/usr/bin/env bash
if [[ $(openssl version) =~ 3\.[2-9]\.[0-9]+ ]]; then
OPENSSL_X509_FLAG='-x509v1'
else
OPENSSL_X509_FLAG='-x509'
fi
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 -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
openssl genrsa 2048 > rootCA.key.pem
openssl req $OPENSSL_X509_FLAG -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.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 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
openssl genrsa -aes256 -passout pass:test012! 2048 > client_encrypted.key.pem
openssl req -new -batch -config test.conf -key client_encrypted.key.pem -passin pass:test012! | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client_encrypted.cert.pem

View File

@ -1,6 +0,0 @@
// Test if including windows.h conflicts with httplib.h
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <httplib.h>

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 build_dir"
exit 1
fi
BUILD_DIR=$1
# Make the build directory
rm -rf $BUILD_DIR
mkdir -p $BUILD_DIR/out
cd $BUILD_DIR
# Build the version
git checkout $BUILD_DIR -q
cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-g -Og" \
-DBUILD_SHARED_LIBS=ON \
-DHTTPLIB_COMPILE=ON \
-DCMAKE_INSTALL_PREFIX=./out \
../..
cmake --build . --target install
cmake --build . --target clean

View File

@ -3,10 +3,8 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
gtest_dep = dependency('gtest', main: true) gtest_dep = dependency('gtest', main: true)
libcurl_dep = dependency('libcurl')
openssl = find_program('openssl') openssl = find_program('openssl')
test_conf = files('test.conf') test_conf = files('test.conf')
req_x509_flag = openssl.version().version_compare('>=3.2.0') ? '-x509v1' : '-x509'
key_pem = custom_target( key_pem = custom_target(
'key_pem', 'key_pem',
@ -32,7 +30,7 @@ cert2_pem = custom_target(
'cert2_pem', 'cert2_pem',
input: key_pem, input: key_pem,
output: 'cert2.pem', output: 'cert2.pem',
command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN'] 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 = custom_target(
@ -45,7 +43,7 @@ cert_encrypted_pem = custom_target(
'cert_encrypted_pem', 'cert_encrypted_pem',
input: key_encrypted_pem, input: key_encrypted_pem,
output: 'cert_encrypted.pem', output: 'cert_encrypted.pem',
command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN'] 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 = custom_target(
@ -58,7 +56,7 @@ rootca_cert_pem = custom_target(
'rootca_cert_pem', 'rootca_cert_pem',
input: rootca_key_pem, input: rootca_key_pem,
output: 'rootCA.cert.pem', output: 'rootCA.cert.pem',
command: [openssl, 'req', req_x509_flag, '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@'] 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 = custom_target(
@ -104,9 +102,9 @@ client_encrypted_cert_pem = custom_target(
# Copy test files to the build directory # Copy test files to the build directory
configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true) configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
configure_file(input: 'image.jpg', output: 'image.jpg', copy: true) configure_file(input: 'image.jpg', output: 'image.jpg', copy: true)
subdir('www') subdir(join_paths('www', 'dir'))
subdir('www2'/'dir') subdir(join_paths('www2', 'dir'))
subdir('www3'/'dir') subdir(join_paths('www3', 'dir'))
# GoogleTest 1.13.0 requires C++14 # GoogleTest 1.13.0 requires C++14
test_options = [] test_options = []
@ -121,8 +119,7 @@ test(
'test.cc', 'test.cc',
dependencies: [ dependencies: [
cpp_httplib_dep, cpp_httplib_dep,
gtest_dep, gtest_dep
libcurl_dep
], ],
override_options: test_options override_options: test_options
), ),

File diff suppressed because it is too large Load Diff

View File

@ -28,26 +28,26 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@ -5,7 +5,8 @@
using namespace std; using namespace std;
using namespace httplib; using namespace httplib;
template <typename T> void ProxyTest(T &cli, bool basic) { template <typename T>
void ProxyTest(T& cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129); cli.set_proxy("localhost", basic ? 3128 : 3129);
auto res = cli.Get("/httpbin/get"); auto res = cli.Get("/httpbin/get");
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
@ -37,7 +38,7 @@ TEST(ProxyTest, SSLDigest) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
template <typename T> template <typename T>
void RedirectProxyText(T &cli, const char *path, bool basic) { void RedirectProxyText(T& cli, const char *path, 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");
@ -99,7 +100,8 @@ TEST(RedirectTest, YouTubeSSLDigest) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) { template <typename T>
void BaseAuthTestFromHTTPWatch(T& cli) {
cli.set_proxy("localhost", 3128); cli.set_proxy("localhost", 3128);
cli.set_proxy_basic_auth("hello", "world"); cli.set_proxy_basic_auth("hello", "world");
@ -110,11 +112,11 @@ template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) {
} }
{ {
auto res = cli.Get("/basic-auth/hello/world", auto res =
{make_basic_authentication_header("hello", "world")}); cli.Get("/basic-auth/hello/world",
{make_basic_authentication_header("hello", "world")});
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ(StatusCode::OK_200, res->status);
} }
@ -122,8 +124,7 @@ template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) {
cli.set_basic_auth("hello", "world"); cli.set_basic_auth("hello", "world");
auto res = cli.Get("/basic-auth/hello/world"); auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ(StatusCode::OK_200, res->status);
} }
@ -157,7 +158,8 @@ TEST(BaseAuthTest, SSL) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
template <typename T> void DigestAuthTestFromHTTPWatch(T &cli) { template <typename T>
void DigestAuthTestFromHTTPWatch(T& cli) {
cli.set_proxy("localhost", 3129); cli.set_proxy("localhost", 3129);
cli.set_proxy_digest_auth("hello", "world"); cli.set_proxy_digest_auth("hello", "world");
@ -179,8 +181,7 @@ template <typename T> void DigestAuthTestFromHTTPWatch(T &cli) {
for (auto path : paths) { for (auto path : paths) {
auto res = cli.Get(path.c_str()); auto res = cli.Get(path.c_str());
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ(StatusCode::OK_200, res->status);
} }
@ -215,7 +216,8 @@ TEST(DigestAuthTest, NoSSL) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
template <typename T> void KeepAliveTest(T &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");
@ -247,10 +249,9 @@ template <typename T> void KeepAliveTest(T &cli, bool basic) {
"/httpbin/digest-auth/auth-int/hello/world/MD5", "/httpbin/digest-auth/auth-int/hello/world/MD5",
}; };
for (auto path : paths) { for (auto path: paths) {
auto res = cli.Get(path.c_str()); auto res = cli.Get(path.c_str());
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status); EXPECT_EQ(StatusCode::OK_200, res->status);
} }
} }

View File

View File

@ -1 +0,0 @@
file

View File

@ -1,7 +0,0 @@
# SPDX-FileCopyrightText: 2024 Andrea Pappacoda
#
# SPDX-License-Identifier: MIT
configure_file(input: 'empty_file', output: 'empty_file', copy: true)
configure_file(input: 'file', output: 'file', copy: true)
subdir('dir')

View File

@ -1 +0,0 @@
日本語コンテンツ