Compare commits

...

35 Commits

Author SHA1 Message Date
yhirose 6f2717e623 Release v0.38.0 2026-03-14 23:17:13 -04:00
yhirose 257b266190 Add runtime configuration for WebSocket ping interval and related tests 2026-03-14 22:44:17 -04:00
yhirose ba0d0b82db Add benchmark tests and related configurations for performance evaluation 2026-03-14 22:16:53 -04:00
yhirose 5ecba74a99 Remove large data tests for GzipDecompressor and SSLClientServerTest due to memory issues 2026-03-14 21:50:55 -04:00
yhirose ec1ffbc27d Add Brotli compression support and corresponding tests 2026-03-14 21:42:48 -04:00
yhirose 4978f26f86 Fix port number in OpenStreamMalformedContentLength test to avoid conflicts 2026-03-14 20:59:15 -04:00
yhirose bb7c7ab075 Add quality parameter parsing for Accept-Encoding header and enhance encoding type selection logic 2026-03-14 20:51:25 -04:00
yhirose 1c3d35f83c Update comment to clarify requirements for safe handling in ClientImpl::handle_request 2026-03-14 19:27:51 -04:00
yhirose b1bb2b7ecc Implement setup_proxy_connection method for SSLClient and refactor proxy handling in open_stream 2026-03-14 19:26:31 -04:00
yhirose f6ed5fc60f Add SSL support for proxy connections in open_stream and corresponding test 2026-03-14 18:38:34 -04:00
yhirose 69d468f4d9 Enable BindDualStack test and remove disabled large content test due to memory issues 2026-03-14 18:22:27 -04:00
yhirose 2e61fd3e6e Update documentation to clarify progress callback usage and user data handling in examples 2026-03-13 22:54:29 -04:00
yhirose 3ad4a4243a Update .gitignore to include AGENTS.md and related documentation files 2026-03-13 22:31:44 -04:00
yhirose 511e3ef9e5 Update README.md to enhance TLS backend documentation and clarify platform-specific certificate handling 2026-03-13 22:30:05 -04:00
yhirose f787f31b87 Implement symlink protection in static file server and add corresponding tests 2026-03-13 16:22:16 -04:00
yhirose 43a54a3e3d Add tests for Unicode path component decoding in decode_path_component function 2026-03-13 00:32:41 -04:00
yhirose 83e98a28dd Add filename sanitization function and tests to prevent path traversal vulnerabilities 2026-03-13 00:29:13 -04:00
yhirose 4d7c9a788d Release v0.37.2 2026-03-13 00:11:00 -04:00
yhirose 1cd0347ace Refactor parse_port function to accept char pointer and length, improving flexibility and validation 2026-03-13 00:05:13 -04:00
yhirose b3a8af80b9 Add port validation and corresponding tests to prevent overflow and out-of-range values 2026-03-13 00:05:13 -04:00
yhirose 1e97c28e36 Implement request smuggling protection for duplicate Content-Length headers and add corresponding tests 2026-03-13 00:05:13 -04:00
yhirose d279eff4db Fix the proxy test error 2026-03-12 23:15:10 -04:00
yhirose 188035fb6d Add a test for the previous change 2026-03-12 22:57:11 -04:00
yhirose 125272f34b Fix TLS cert verification bypass on proxy redirect introduced in #2165 (#2396) 2026-03-12 21:54:51 -04:00
yhirose 9ced2f614d Fix #2395 2026-03-12 19:18:09 -04:00
yhirose 68fa9bce0f Release v0.37.1 2026-03-09 20:51:37 -04:00
yhirose 1f34c541b0 Add more books 2026-03-09 19:30:18 -04:00
yhirose e41ec36274 Fix handling of malformed Content-Length in open_stream and add tests 2026-03-08 22:30:20 -04:00
yhirose 7489fd3a8b Remove 32-bit limitation (#2388)
* Remove 32-bit limitation

* Fix build problems

* Add 32-bit disclaimer and fix MSVC x86 warnings

- Move 32-bit warning to top of README with strong disclaimer
- Add static_cast<size_t> to fix truncation warnings on 32-bit MSVC

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:07:21 -05:00
yhirose ab3098f18b Update README 2026-03-06 18:50:23 -05:00
yhirose 0d3a3d805c Release v0.37.0 2026-03-06 16:57:33 -05:00
yhirose a058e31a3a Use doc.yml to generate document site 2026-03-05 20:50:22 -05:00
yhirose c87d442aac Remove docs-gen 2026-03-03 23:58:03 -05:00
yhirose de296af3eb Fix problem with alternate file name check 2026-03-03 13:37:28 -05:00
yhirose 41899acece Release v0.36.0 2026-03-02 21:56:38 -05:00
80 changed files with 1542 additions and 12898 deletions
+33
View File
@@ -0,0 +1,33 @@
name: docs
on:
push:
branches: [master]
paths:
- 'docs-src/**'
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install docs-gen
run: cargo install docs-gen
- name: Build
run: docs-gen build docs-src docs
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: docs
- id: deployment
uses: actions/deploy-pages@v4
+36
View File
@@ -0,0 +1,36 @@
name: 32-bit Build Test
on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
test-win32:
name: Windows 32-bit (MSVC x86)
runs-on: windows-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Build (Win32)
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86
cl /std:c++14 /EHsc /W4 /WX /c /Fo:NUL test\test_32bit_build.cpp
test-arm32:
name: ARM 32-bit (cross-compile)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install cross compiler
run: sudo apt-get update && sudo apt-get install -y g++-arm-linux-gnueabihf
- name: Build (ARM 32-bit)
run: arm-linux-gnueabihf-g++ -std=c++11 -Wall -Wextra -Wno-psabi -Werror -c -o /dev/null test/test_32bit_build.cpp
+3 -7
View File
@@ -40,7 +40,7 @@ jobs:
clang-format --version
cd test && make style_check
build-error-check-on-32bit:
build-and-test-on-32bit:
runs-on: ubuntu-latest
if: >
(github.event_name == 'push') ||
@@ -64,9 +64,8 @@ jobs:
libssl-dev${{ matrix.config.arch_suffix }} libcurl4-openssl-dev${{ matrix.config.arch_suffix }} \
zlib1g-dev${{ matrix.config.arch_suffix }} libbrotli-dev${{ matrix.config.arch_suffix }} \
libzstd-dev${{ matrix.config.arch_suffix }}
- name: build and run tests (expect failure)
- name: build and run tests
run: cd test && make test EXTRA_CXXFLAGS="${{ matrix.config.arch_flags }}"
continue-on-error: true
ubuntu:
runs-on: ubuntu-latest
@@ -229,7 +228,7 @@ jobs:
for ($i = 0; $i -lt $shards; $i++) {
$log = "shard_${i}.log"
$procs += Start-Process -FilePath ./Release/httplib-test.exe `
-ArgumentList "--gtest_color=yes","--gtest_filter=${{ github.event.inputs.gtest_filter || '*' }}-*BenchmarkTest*" `
-ArgumentList "--gtest_color=yes","--gtest_filter=${{ github.event.inputs.gtest_filter || '*' }}" `
-NoNewWindow -PassThru -RedirectStandardOutput $log -RedirectStandardError "${log}.err" `
-Environment @{ GTEST_TOTAL_SHARDS="$shards"; GTEST_SHARD_INDEX="$i" }
}
@@ -249,9 +248,6 @@ jobs:
}
if ($failed) { exit 1 }
Write-Host "All shards passed."
- name: Run benchmark tests with retry ${{ matrix.config.name }}
if: ${{ matrix.config.run_tests }}
run: ctest --output-on-failure --test-dir build -C Release -R "BenchmarkTest" --repeat until-pass:5
env:
VCPKG_ROOT: "C:/vcpkg"
+79
View File
@@ -0,0 +1,79 @@
name: benchmark
on:
push:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
ubuntu:
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
steps:
- name: checkout
uses: actions/checkout@v4
- name: build and run
run: cd test && make test_benchmark && ./test_benchmark
macos:
runs-on: macos-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
steps:
- name: checkout
uses: actions/checkout@v4
- name: build and run
run: cd test && make test_benchmark && ./test_benchmark
windows:
runs-on: windows-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
steps:
- name: Prepare Git for Checkout on Windows
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: checkout
uses: actions/checkout@v4
- name: Export GitHub Actions cache environment variables
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: Cache vcpkg packages
id: vcpkg-cache
uses: actions/cache@v4
with:
path: C:/vcpkg/installed
key: vcpkg-installed-windows-gtest
- name: Install vcpkg dependencies
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
run: vcpkg install gtest
- name: Configure and build
shell: pwsh
run: |
$cmake_content = @"
cmake_minimum_required(VERSION 3.14)
project(httplib-benchmark CXX)
find_package(GTest REQUIRED)
add_executable(httplib-benchmark test/test_benchmark.cc)
target_include_directories(httplib-benchmark PRIVATE .)
target_link_libraries(httplib-benchmark PRIVATE GTest::gtest_main)
target_compile_options(httplib-benchmark PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
"@
New-Item -ItemType Directory -Force -Path build_bench/test | Out-Null
Set-Content -Path build_bench/CMakeLists.txt -Value $cmake_content
Copy-Item -Path httplib.h -Destination build_bench/
Copy-Item -Path test/test_benchmark.cc -Destination build_bench/test/
cmake -B build_bench/build -S build_bench `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake --build build_bench/build --config Release
- name: Run with retry
run: ctest --output-on-failure --test-dir build_bench/build -C Release --repeat until-pass:5
env:
VCPKG_ROOT: "C:/vcpkg"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
+5 -1
View File
@@ -28,6 +28,10 @@ jobs:
- name: Run proxy tests (OpenSSL)
if: matrix.tls_backend == 'openssl'
run: cd test && make proxy
env:
COMPOSE_FILE: docker-compose.yml:docker-compose.ci.yml
- name: Run proxy tests (Mbed TLS)
if: matrix.tls_backend == 'mbedtls'
run: cd test && make proxy_mbedtls
run: cd test && make proxy_mbedtls
env:
COMPOSE_FILE: docker-compose.yml:docker-compose.ci.yml
+4
View File
@@ -1,4 +1,7 @@
tags
AGENTS.md
docs-src/pages/AGENTS.md
plans/
# Ignore executables (no extension) but not source files
example/server
@@ -48,6 +51,7 @@ test/test_split_wolfssl
test/test_split_no_tls
test/test_websocket_heartbeat
test/test_thread_pool
test/test_benchmark
test/test.xcodeproj/xcuser*
test/test.xcodeproj/*/xcuser*
test/*.o
-3
View File
@@ -173,9 +173,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows")
message(WARNING "The target is Windows but CMAKE_SYSTEM_VERSION is not set, the default system version is set to Windows 10.")
endif()
endif()
if(CMAKE_SIZEOF_VOID_P LESS 8)
message(WARNING "Pointer size ${CMAKE_SIZEOF_VOID_P} is not supported. Please use a 64-bit compiler.")
endif()
# Set some variables that are used in-tree and while building based on our options
set(HTTPLIB_IS_COMPILED ${HTTPLIB_COMPILE})
+2 -2
View File
@@ -45,7 +45,7 @@ cpp-httplib provides multiple API layers for different use cases:
```text
┌─────────────────────────────────────────────┐
│ SSEClient (planned) │ ← SSE-specific, parsed events
│ SSEClient │ ← SSE-specific, parsed events
│ - on_message(), on_event() │
│ - Auto-reconnect, Last-Event-ID │
├─────────────────────────────────────────────┤
@@ -61,7 +61,7 @@ cpp-httplib provides multiple API layers for different use cases:
| Use Case | Recommended API |
|----------|----------------|
| SSE with auto-reconnect | SSEClient (planned) or `ssecli-stream.cc` example |
| SSE with auto-reconnect | `SSEClient` (see [README-sse.md](README-sse.md)) |
| LLM streaming (JSON Lines) | `stream::Get()` |
| Large file download | `stream::Get()` or `open_stream()` |
| Reverse proxy | `open_stream()` |
+20
View File
@@ -353,6 +353,26 @@ if (ws.connect()) {
| `CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND` | `5` | Timeout for waiting peer's Close response (seconds) |
| `CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND` | `30` | Automatic Ping interval for heartbeat (seconds) |
### Runtime Ping Interval
You can override the ping interval at runtime instead of changing the compile-time macro. Set it to `0` to disable automatic pings entirely.
```cpp
// Server side
httplib::Server svr;
svr.set_websocket_ping_interval(10); // 10 seconds
// Or using std::chrono
svr.set_websocket_ping_interval(std::chrono::seconds(10));
// Client side
httplib::ws::WebSocketClient ws("ws://localhost:8080/ws");
ws.set_websocket_ping_interval(10); // 10 seconds
// Disable automatic pings
ws.set_websocket_ping_interval(0);
```
## Threading Model
WebSocket connections share the same thread pool as HTTP requests. Each WebSocket connection occupies one thread for its entire lifetime.
+36 -36
View File
@@ -5,11 +5,14 @@
A C++11 single-file header-only cross platform HTTP/HTTPS library.<br>
It's extremely easy to set up. Just include the **[httplib.h](https://raw.githubusercontent.com/yhirose/cpp-httplib/refs/heads/master/httplib.h)** file in your code!
**Learn more in the [official documentation](https://yhirose.github.io/cpp-httplib/)**.
Learn more in the [official documentation](https://yhirose.github.io/cpp-httplib/) (built with [docs-gen](https://github.com/yhirose/docs-gen)).
> [!IMPORTANT]
> This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
> [!WARNING]
> 32-bit platforms are **NOT supported**. Use at your own risk. The library may compile on 32-bit targets, but no security review has been conducted for 32-bit environments. Integer truncation and other 32-bit-specific issues may exist. **Security reports that only affect 32-bit platforms will be closed without action.** The maintainer does not have access to 32-bit environments for testing or fixing issues. CI includes basic compile checks only, not functional or security testing.
## Main Features
- HTTP Server/Client
@@ -61,26 +64,14 @@ if (auto res = cli.Get("/hi")) {
cpp-httplib supports multiple TLS backends through an abstraction layer:
| Backend | Define | Libraries |
| :------ | :----- | :-------- |
| OpenSSL | `CPPHTTPLIB_OPENSSL_SUPPORT` | `libssl`, `libcrypto` |
| Mbed TLS | `CPPHTTPLIB_MBEDTLS_SUPPORT` | `libmbedtls`, `libmbedx509`, `libmbedcrypto` |
| wolfSSL | `CPPHTTPLIB_WOLFSSL_SUPPORT` | `libwolfssl` |
| Backend | Define | Libraries | Notes |
| :------ | :----- | :-------- | :---- |
| OpenSSL | `CPPHTTPLIB_OPENSSL_SUPPORT` | `libssl`, `libcrypto` | [3.0 or later](https://www.openssl.org/policies/releasestrat.html) required |
| Mbed TLS | `CPPHTTPLIB_MBEDTLS_SUPPORT` | `libmbedtls`, `libmbedx509`, `libmbedcrypto` | 2.x and 3.x supported (auto-detected) |
| wolfSSL | `CPPHTTPLIB_WOLFSSL_SUPPORT` | `libwolfssl` | 5.x supported; must build with `--enable-opensslall` |
> [!NOTE]
> OpenSSL 3.0 or later is required. Please see [this page](https://www.openssl.org/policies/releasestrat.html) for more information.
> [!NOTE]
> Mbed TLS 2.x and 3.x are supported. The library automatically detects the version and uses the appropriate API.
> [!NOTE]
> wolfSSL must be built with OpenSSL compatibility layer enabled (`--enable-opensslall`). wolfSSL 5.x is supported.
> [!NOTE]
> **Mbed TLS / wolfSSL limitation:** `get_ca_certs()` and `get_ca_names()` only reflect CA certificates loaded via `load_ca_cert_store()` or `load_ca_cert_store(pem, size)`. Certificates loaded through `set_ca_cert_path()` or system certificates (`load_system_certs`) are not enumerable with these backends.
> [!TIP]
> For macOS: cpp-httplib automatically loads system certs from the Keychain when a TLS backend is enabled. `CoreFoundation` and `Security` must be linked with `-framework`. To disable this, define `CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES`.
> **Mbed TLS / wolfSSL limitation:** `get_ca_certs()` and `get_ca_names()` only reflect CA certificates loaded via `load_ca_cert_store()`. Certificates loaded through `set_ca_cert_path()` or system certificates (`load_system_certs`) are not enumerable.
```c++
// Use either OpenSSL, Mbed TLS, or wolfSSL
@@ -194,27 +185,21 @@ svr.Get("/", [](const httplib::Request &req, httplib::Response &res) {
});
```
### Windows Certificate Verification
### Platform-specific Certificate Handling
On Windows, cpp-httplib automatically performs additional certificate verification using the Windows certificate store via CryptoAPI (`CertGetCertificateChain` / `CertVerifyCertificateChainPolicy`). This works with all TLS backends (OpenSSL, Mbed TLS, and wolfSSL), providing:
cpp-httplib automatically integrates with the OS certificate store on macOS and Windows. This works with all TLS backends.
- Real-time certificate validation integrated with Windows Update
- Certificate revocation checking
- SSL/TLS policy verification using the system certificate store (ROOT and CA)
| Platform | Behavior | Disable (compile time) |
| :------- | :------- | :--------------------- |
| macOS | Loads system certs from Keychain (link `CoreFoundation` and `Security` with `-framework`) | `CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES` |
| Windows | Verifies certs via CryptoAPI (`CertGetCertificateChain` / `CertVerifyCertificateChainPolicy`) with revocation checking | `CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE` |
This feature is enabled by default and can be controlled at runtime:
On Windows, verification can also be disabled at runtime:
```c++
// Disable Windows certificate verification (use only OpenSSL/Mbed TLS/wolfSSL verification)
cli.enable_windows_certificate_verification(false);
```
To disable this feature at compile time, define:
```c++
#define CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
```
> [!NOTE]
> When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
@@ -347,6 +332,11 @@ The following are built-in mappings:
> [!WARNING]
> These static file server methods are not thread-safe.
<!-- -->
> [!NOTE]
> On POSIX systems, the static file server rejects requests that resolve (via symlinks) to a path outside the mounted base directory. Ensure that the served directory has appropriate permissions, as managing access to the served directory is the application developer's responsibility.
### File request handler
```cpp
@@ -538,16 +528,16 @@ svr.Post("/multipart", [&](const Request& req, Response& res) {
}
// IMPORTANT: file.filename is an untrusted value from the client.
// Always extract only the basename to prevent path traversal attacks.
auto safe_name = std::filesystem::path(file.filename).filename();
if (safe_name.empty() || safe_name == "." || safe_name == "..") {
// Always sanitize to prevent path traversal attacks.
auto safe_name = httplib::sanitize_filename(file.filename);
if (safe_name.empty()) {
res.status = StatusCode::BadRequest_400;
res.set_content("Invalid filename", "text/plain");
return;
}
// Save to disk
std::ofstream ofs(upload_dir / safe_name, std::ios::binary);
std::ofstream ofs(upload_dir + "/" + safe_name, std::ios::binary);
ofs << file.content;
}
@@ -583,6 +573,16 @@ svr.Post("/multipart", [&](const Request& req, Response& res) {
});
```
#### Filename Sanitization
`file.filename` in multipart uploads is an untrusted value from the client. Always sanitize before using it in file paths:
```cpp
auto safe = httplib::sanitize_filename(file.filename);
```
This function strips path separators (`/`, `\`), null bytes, leading/trailing whitespace, and rejects `.` and `..`. Returns an empty string if the filename is unsafe.
### Receive content with a content receiver
```cpp
-1992
View File
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
[package]
name = "docs-gen"
version = "0.1.0"
edition = "2021"
[dependencies]
pulldown-cmark = "0.12"
tera = "1"
walkdir = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
toml = "0.8"
syntect = "5"
anyhow = "1"
clap = { version = "4", features = ["derive"] }
notify = "7"
tiny_http = "0.12"
tungstenite = "0.24"
open = "5"
tempfile = "3"
socket2 = { version = "0.5", features = ["all"] }
-254
View File
@@ -1,254 +0,0 @@
# docs-gen
A static site generator for multi-language documentation. Markdown content, Tera templates, and syntax highlighting — all in a single binary.
## Quick Start
```bash
# 1. Scaffold a new project
docs-gen init my-docs
# 2. Start the local dev server with live-reload
docs-gen serve my-docs --open
# 3. Build for production
docs-gen build my-docs --out docs
```
---
## Commands
### `init [DIR]`
Creates a new project scaffold in `DIR` (default: `.`).
Generated files:
```
config.toml
pages/
en/index.md
ja/index.md
templates/
base.html
page.html
portal.html
static/
css/main.css
js/main.js
```
Existing files are never overwritten.
---
### `serve [SRC] [--port PORT] [--open]`
Builds the site into a temporary directory and serves it locally. Watches for changes and live-reloads the browser automatically.
| Option | Default | Description |
|--------|---------|-------------|
| `SRC` | `.` | Source directory |
| `--port` | `8080` | HTTP server port |
| `--open` | — | Open browser on startup |
---
### `build [SRC] [--out OUT]`
Generates the static site from source.
| Option | Default | Description |
|--------|---------|-------------|
| `SRC` | `.` | Source directory |
| `--out` | `docs` | Output directory |
---
## Source Directory Structure
Only `config.toml` and `pages/` are required. `templates/` and `static/` are optional — when absent, built-in defaults are used automatically.
```
my-docs/
├── config.toml # Site configuration (required)
├── pages/ # Markdown content (required)
│ ├── en/
│ │ ├── index.md # Portal page (homepage, no sidebar)
│ │ └── guide/
│ │ ├── index.md # Section index
│ │ ├── 01-intro.md
│ │ └── 02-usage.md
│ └── ja/
│ └── ...
├── templates/ # Override built-in HTML templates (optional)
│ ├── base.html
│ ├── page.html
│ └── portal.html
└── static/ # Override built-in CSS/JS/assets (optional)
├── css/main.css
└── js/main.js
```
---
## config.toml
```toml
[site]
title = "My Project"
version = "1.0.0" # Optional. Shown in header.
hostname = "https://example.github.io" # Optional. Combined with base_path for full URLs.
base_path = "/my-project" # URL prefix. Use "" for local-only.
[[nav]]
label = "Guide"
path = "guide/" # Internal section path (resolved per language)
icon_svg = '<svg ...>...</svg>' # Optional inline SVG icon
[[nav]]
label = "GitHub"
url = "https://github.com/your/repo" # External URL
icon_svg = '<svg ...>...</svg>'
[i18n]
langs = ["en", "ja"] # First entry is the default language
[highlight]
dark_theme = "base16-eighties.dark" # Dark mode theme
light_theme = "InspiredGitHub" # Light mode theme (optional)
```
### `[site]`
| Key | Required | Description |
|-----|----------|-------------|
| `title` | yes | Site title displayed in the header |
| `version` | no | Version string displayed in the header |
| `hostname` | no | Base hostname (e.g. `"https://user.github.io"`). Combined with `base_path` to form `site.base_url` in templates. |
| `base_path` | no | URL path prefix. Use `"/repo-name"` for GitHub Pages, `""` for local development. |
### `[[nav]]` — Toolbar Buttons
Defines buttons in the site header. Each entry supports:
| Key | Required | Description |
|-----|----------|-------------|
| `label` | yes | Button label text |
| `path` | no | Internal section path relative to `<lang>/` (e.g. `"guide/"`). Resolved using the current language. |
| `url` | no | Absolute external URL. Takes precedence over `path` if both are set. |
| `icon_svg` | no | Inline SVG markup displayed as an icon |
### `[i18n]`
| Key | Required | Description |
|-----|----------|-------------|
| `langs` | yes | List of language codes. At least one is required. The first entry is used as the default language. |
### `[highlight]`
| Key | Default | Description |
|-----|---------|-------------|
| `dark_theme` | `base16-ocean.dark` | Theme for dark mode |
| `light_theme` | _(none)_ | Theme for light mode. When set, both dark and light code blocks are emitted and toggled via CSS. |
Available themes: `base16-ocean.dark`, `base16-ocean.light`, `base16-eighties.dark`, `base16-mocha.dark`, `InspiredGitHub`, `Solarized (dark)`, `Solarized (light)`.
---
## Writing Pages
### Frontmatter
Every `.md` file must begin with YAML frontmatter:
```yaml
---
title: "Getting Started"
order: 1
---
Page content goes here...
```
| Field | Required | Description |
|-------|----------|-------------|
| `title` | yes | Page title shown in the heading and browser tab |
| `order` | no | Sort order within the section (default: `0`) |
| `status` | no | Set to `"draft"` to display a DRAFT banner |
### URL Routing
Files are mapped to URLs as follows:
| File | URL |
|------|-----|
| `en/index.md` | `<base_path>/en/` |
| `en/guide/index.md` | `<base_path>/en/guide/` |
| `en/guide/01-intro.md` | `<base_path>/en/guide/01-intro/` |
The root `index.html` is generated automatically and redirects to the default language, respecting the user's `localStorage` language preference.
### Sidebar Navigation
Sidebar navigation is generated automatically:
- Each subdirectory under a language becomes a **section**
- The section's `index.md` title is used as the section heading
- Pages within a section are sorted by `order`, then by filename
- `index.md` at the language root uses `portal.html` (no sidebar)
- All other pages use `page.html` (with sidebar)
---
## Customizing Templates and Assets
When `templates/` or `static/` directories exist in the source, files there override the built-in defaults. Use `docs-gen init` to generate the defaults as a starting point.
Three templates are available:
| Template | Used for |
|----------|----------|
| `base.html` | Shared layout: `<head>`, header, footer, scripts |
| `page.html` | Content pages with sidebar |
| `portal.html` | Homepage (`index.md` at language root), no sidebar |
---
## Template Variables
Templates use [Tera](https://keats.github.io/tera/) syntax. Available variables:
### All templates
| Variable | Type | Description |
|----------|------|-------------|
| `page.title` | string | Page title from frontmatter |
| `page.url` | string | Page URL path |
| `page.status` | string? | `"draft"` or null |
| `content` | string | Rendered HTML (use `{{ content \| safe }}`) |
| `lang` | string | Current language code |
| `site.title` | string | Site title |
| `site.version` | string? | Site version |
| `site.base_url` | string | Full base URL (`hostname` + `base_path`) |
| `site.base_path` | string | URL path prefix |
| `site.langs` | list | All language codes |
| `site.nav` | list | Toolbar button entries |
| `site.nav[].label` | string | Button label |
| `site.nav[].url` | string? | External URL (if set) |
| `site.nav[].path` | string? | Internal section path (if set) |
| `site.nav[].icon_svg` | string? | Inline SVG icon (if set) |
### `page.html` only
| Variable | Type | Description |
|----------|------|-------------|
| `nav` | list | Sidebar sections |
| `nav[].title` | string | Section title |
| `nav[].url` | string | Section index URL |
| `nav[].active` | bool | True if this section contains the current page |
| `nav[].children` | list | Pages within this section |
| `nav[].children[].title` | string | Page title |
| `nav[].children[].url` | string | Page URL |
| `nav[].children[].active` | bool | True if this is the current page |
-20
View File
@@ -1,20 +0,0 @@
[site]
title = "My Docs"
hostname = "https://example.github.io"
base_path = "/my-project"
# [[nav]]
# label = "Guide"
# path = "guide/"
#
# [[nav]]
# label = "GitHub"
# url = "https://github.com/your/repo"
# icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>'
[i18n]
langs = ["en"]
[highlight]
dark_theme = "base16-ocean.dark"
light_theme = "InspiredGitHub"
-10
View File
@@ -1,10 +0,0 @@
---
title: Welcome
order: 0
---
## Welcome
This is the home page of your documentation site.
Edit this file at `pages/en/index.md` to get started.
-10
View File
@@ -1,10 +0,0 @@
---
title: ようこそ
order: 0
---
## ようこそ
ドキュメントサイトのトップページです。
`pages/ja/index.md` を編集して始めましょう。
-603
View File
@@ -1,603 +0,0 @@
:root {
--bg: #333;
--bg-secondary: #3c3c3c;
--bg-code: #2a2a2a;
--text: #ccc;
--text-bright: white;
--text-muted: #999;
--text-code: #b0b0b0;
--text-inline-code: plum;
--border: #555;
--border-code: #3a3a3a;
--link: palegoldenrod;
--heading: lightskyblue;
--heading-link: #f0c090;
--header-nav-link: pink;
--emphasis: pink;
--nav-section: #bbb;
--nav-section-active: #ddd;
--content-width: 900px;
--sidebar-width: 280px;
--header-height: 48px;
--line-height: 1.6;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: var(--line-height);
}
a {
color: var(--link);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* Header */
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--header-height);
background-color: var(--bg-secondary);
border-bottom: 1px solid var(--border);
z-index: 100;
}
.header-inner {
height: 100%;
display: flex;
align-items: center;
padding: 0 16px;
gap: 24px;
}
.header-title {
color: var(--text);
font-weight: bold;
font-size: 1.1rem;
white-space: nowrap;
}
.header-title:hover {
text-decoration: none;
color: var(--text-bright);
}
.header-spacer {
flex: 1;
}
.header-nav {
display: flex;
gap: 16px;
}
.header-nav a {
display: flex;
align-items: center;
gap: 4px;
color: var(--header-nav-link);
font-size: 0.9rem;
}
.header-nav a svg {
flex-shrink: 0;
opacity: 0.85;
}
.header-tools {
display: flex;
align-items: center;
gap: 2px;
}
.lang-selector {
position: relative;
}
.lang-btn {
display: flex;
align-items: center;
gap: 5px;
background: none;
border: none;
color: var(--text);
padding: 4px 6px;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
opacity: 0.8;
}
.lang-btn:hover {
opacity: 1;
}
.lang-popup {
display: none;
position: absolute;
right: 0;
top: 100%;
margin-top: 4px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 4px;
list-style: none;
min-width: 60px;
z-index: 200;
}
.lang-popup.open {
display: block;
}
.lang-popup li a {
display: block;
padding: 6px 12px;
color: var(--text);
font-size: 0.85rem;
}
.lang-popup li a:hover {
background: var(--bg);
text-decoration: none;
}
.sidebar-toggle {
display: none;
background: none;
border: none;
color: var(--text);
font-size: 1.2rem;
cursor: pointer;
padding: 4px 8px;
}
/* Draft banner */
.draft-banner {
position: fixed;
top: var(--header-height);
right: 0;
background: #c44;
color: white;
padding: 4px 16px;
font-size: 0.75rem;
font-weight: bold;
letter-spacing: 0.1em;
z-index: 99;
}
/* Layout */
.layout {
margin-top: var(--header-height);
display: grid;
grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
min-height: calc(100vh - var(--header-height));
}
.layout.no-sidebar {
grid-template-columns: 1fr;
}
/* Sidebar */
.sidebar {
width: var(--sidebar-width);
flex-shrink: 0;
padding: 24px 16px;
border-right: 1px solid var(--bg-secondary);
position: sticky;
top: var(--header-height);
height: calc(100vh - var(--header-height));
overflow-y: auto;
}
.nav-section {
margin-bottom: 16px;
}
.nav-section-title {
color: var(--nav-section);
font-weight: bold;
font-size: 1.0rem;
display: block;
margin-bottom: 8px;
}
.nav-section-title.active {
color: var(--nav-section-active);
}
.nav-list {
list-style: none;
padding-left: 8px;
}
.nav-list li {
margin-bottom: 4px;
}
.nav-list li a {
color: var(--text-muted);
font-size: 0.85rem;
}
.nav-list li a:hover {
color: var(--text);
}
.nav-list li a.active {
color: var(--emphasis);
font-weight: bold;
}
/* Content */
.content {
min-width: 0;
max-width: var(--content-width);
padding: 32px 24px;
overflow-wrap: break-word;
}
.content.portal {
max-width: var(--content-width);
padding: 48px 24px;
margin: 0 auto;
}
.content article h1 {
font-size: 1.8rem;
margin-bottom: 24px;
color: var(--heading);
}
.content article h2 {
font-size: 1.4rem;
margin-top: 32px;
margin-bottom: 16px;
color: var(--heading-link);
}
.content article h3 {
font-size: 1.1rem;
margin-top: 24px;
margin-bottom: 12px;
color: var(--text);
}
.content article p {
margin-bottom: 12px;
}
.content article ul,
.content article ol {
margin-bottom: 12px;
padding-left: 24px;
}
.content article li {
margin-bottom: 4px;
}
.content article strong {
color: var(--emphasis);
}
.content article code {
background: var(--bg-code);
color: var(--text-inline-code);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
}
.content article pre {
background: var(--bg-code);
color: var(--text-code);
padding: 16px;
border-radius: 4px;
overflow-x: auto;
margin-bottom: 16px;
border: 1px solid var(--border-code);
}
.content article pre code {
background: none;
padding: 0;
}
.content article table {
width: 100%;
border-collapse: collapse;
margin-bottom: 16px;
}
.content article th,
.content article td {
border: 1px solid var(--bg-secondary);
padding: 8px 12px;
text-align: left;
}
.content article th {
background: var(--bg-secondary);
}
.content article blockquote {
border-left: 3px solid var(--text-muted);
padding-left: 16px;
margin-bottom: 12px;
color: var(--text-muted);
}
/* Code block theme switching: show dark by default, swap on light mode */
.code-block-wrapper > [data-code-theme="light"] {
display: none;
}
html[data-theme="light"] .code-block-wrapper > [data-code-theme="dark"] {
display: none;
}
html[data-theme="light"] .code-block-wrapper > [data-code-theme="light"] {
display: block;
}
/* Footer */
.footer {
padding: 12px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.8rem;
border-top: 1px solid var(--bg-secondary);
}
/* Responsive */
@media (max-width: 768px) {
.layout {
grid-template-columns: minmax(0, 1fr);
}
.sidebar {
position: fixed;
left: calc(-1 * var(--sidebar-width));
width: var(--sidebar-width);
top: var(--header-height);
height: calc(100vh - var(--header-height));
background: var(--bg);
z-index: 50;
transition: left 0.2s ease;
border-right: 1px solid var(--border);
}
.sidebar.open {
left: 0;
}
.sidebar-toggle {
display: block;
}
.content {
padding: 24px 16px;
}
}
@media (max-width: 480px) {
:root {
--header-height: 44px;
}
.header-inner {
padding: 0 12px;
gap: 12px;
}
.header-nav a {
font-size: 0.8rem;
}
.content article h1 {
font-size: 1.4rem;
}
.content article h2 {
font-size: 1.2rem;
}
}
/* Light mode */
[data-theme="light"] {
--bg: #f5f5f5;
--bg-secondary: #e8e8e8;
--bg-code: #eee;
--text: #333;
--text-bright: #000;
--text-muted: #666;
--text-code: #333;
--text-inline-code: #8b5ca0;
--border: #ccc;
--border-code: #ddd;
--link: #b8860b;
--heading: #2a6496;
--heading-link: #c06020;
--header-nav-link: #c04060;
--emphasis: #c04060;
--nav-section: #666;
--nav-section-active: #333;
}
/* Theme toggle */
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--text);
padding: 5px 6px;
border-radius: 4px;
cursor: pointer;
opacity: 0.8;
}
.theme-toggle:hover {
opacity: 1;
}
/* Search button */
.search-btn {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--text);
padding: 5px 6px;
border-radius: 4px;
cursor: pointer;
opacity: 0.8;
}
.search-btn:hover {
opacity: 1;
}
/* Search overlay & modal */
.search-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 300;
justify-content: center;
align-items: flex-start;
padding-top: 12vh;
}
.search-overlay.open {
display: flex;
}
.search-modal {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
width: 90%;
max-width: 560px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
overflow: hidden;
}
.search-input-wrap {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
}
.search-input-wrap svg {
flex-shrink: 0;
opacity: 0.5;
}
#search-input {
flex: 1;
background: none;
border: none;
outline: none;
color: var(--text-bright);
font-size: 1rem;
font-family: inherit;
}
#search-input::placeholder {
color: var(--text-muted);
}
.search-esc {
background: var(--bg);
color: var(--text-muted);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.7rem;
border: 1px solid var(--border);
}
.search-results {
list-style: none;
max-height: 50vh;
overflow-y: auto;
padding: 0;
margin: 0;
}
.search-results:empty::after {
content: "";
display: none;
}
.search-results li {
padding: 10px 16px;
cursor: pointer;
border-bottom: 1px solid var(--border);
}
.search-results li:last-child {
border-bottom: none;
}
.search-results li:hover,
.search-results li.active {
background: var(--bg);
}
.search-results li .search-result-title {
color: var(--text-bright);
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 2px;
}
.search-results li .search-result-snippet {
color: var(--text-muted);
font-size: 0.8rem;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.search-results li .search-result-snippet mark {
background: rgba(255, 215, 0, 0.3);
color: var(--text-bright);
border-radius: 2px;
padding: 0 1px;
}
[data-theme="light"] .search-results li .search-result-snippet mark {
background: rgba(255, 200, 0, 0.4);
color: var(--text);
}
.search-no-results {
padding: 24px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.9rem;
}
-4
View File
@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-297
View File
@@ -1,297 +0,0 @@
// Language selector
(function () {
var btn = document.querySelector('.lang-btn');
var popup = document.querySelector('.lang-popup');
if (!btn || !popup) return;
btn.addEventListener('click', function (e) {
e.stopPropagation();
popup.classList.toggle('open');
});
document.addEventListener('click', function () {
popup.classList.remove('open');
});
popup.addEventListener('click', function (e) {
var link = e.target.closest('[data-lang]');
if (!link) return;
e.preventDefault();
var lang = link.getAttribute('data-lang');
localStorage.setItem('preferred-lang', lang);
var basePath = document.documentElement.getAttribute('data-base-path') || '';
var path = window.location.pathname;
// Strip base path prefix, replace lang, then re-add base path
var pathWithoutBase = path.slice(basePath.length);
var newPath = basePath + pathWithoutBase.replace(/^\/[a-z]{2}\//, '/' + lang + '/');
window.location.href = newPath;
});
})();
// Theme toggle
(function () {
var btn = document.querySelector('.theme-toggle');
if (!btn) return;
// Feather Icons: sun (light mode) and moon (dark mode)
var sunSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>';
var moonSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
function getTheme() {
var stored = localStorage.getItem('preferred-theme');
if (stored) return stored;
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
}
function applyTheme(theme) {
if (theme === 'light') {
document.documentElement.setAttribute('data-theme', 'light');
} else {
document.documentElement.removeAttribute('data-theme');
}
btn.innerHTML = theme === 'light' ? sunSVG : moonSVG;
}
applyTheme(getTheme());
btn.addEventListener('click', function () {
var current = getTheme();
var next = current === 'dark' ? 'light' : 'dark';
localStorage.setItem('preferred-theme', next);
applyTheme(next);
});
})();
// Mobile sidebar toggle
(function () {
var toggle = document.querySelector('.sidebar-toggle');
var sidebar = document.querySelector('.sidebar');
if (!toggle || !sidebar) return;
toggle.addEventListener('click', function () {
sidebar.classList.toggle('open');
});
document.addEventListener('click', function (e) {
if (!sidebar.contains(e.target) && e.target !== toggle) {
sidebar.classList.remove('open');
}
});
})();
// Site search (⌘K / Ctrl+K)
(function () {
var overlay = document.getElementById('search-overlay');
var input = document.getElementById('search-input');
var resultsList = document.getElementById('search-results');
if (!overlay || !input || !resultsList) return;
var searchBtn = document.querySelector('.search-btn');
var pagesData = null; // cached pages-data.json
var activeIndex = -1;
function getCurrentLang() {
return document.documentElement.getAttribute('lang') || 'en';
}
function getBasePath() {
return document.documentElement.getAttribute('data-base-path') || '';
}
function openSearch() {
overlay.classList.add('open');
input.value = '';
resultsList.innerHTML = '';
activeIndex = -1;
input.focus();
loadPagesData();
}
function closeSearch() {
overlay.classList.remove('open');
input.value = '';
resultsList.innerHTML = '';
activeIndex = -1;
}
function loadPagesData() {
if (pagesData) return;
var basePath = getBasePath();
fetch(basePath + '/pages-data.json')
.then(function (res) { return res.json(); })
.then(function (data) { pagesData = data; })
.catch(function () { pagesData = []; });
}
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function highlightText(text, query) {
if (!query) return text;
var escaped = escapeRegExp(query);
var re = new RegExp('(' + escaped + ')', 'gi');
return text.replace(re, '<mark>$1</mark>');
}
function buildSnippet(body, query) {
if (!query || !body) return '';
var lower = body.toLowerCase();
var idx = lower.indexOf(query.toLowerCase());
var start, end, snippet;
if (idx === -1) {
snippet = body.substring(0, 120);
} else {
start = Math.max(0, idx - 40);
end = Math.min(body.length, idx + query.length + 80);
snippet = (start > 0 ? '...' : '') + body.substring(start, end) + (end < body.length ? '...' : '');
}
return highlightText(snippet, query);
}
function search(query) {
if (!pagesData || !query) {
resultsList.innerHTML = '';
activeIndex = -1;
return;
}
var lang = getCurrentLang();
var q = query.toLowerCase();
// Score and filter
var scored = [];
for (var i = 0; i < pagesData.length; i++) {
var page = pagesData[i];
if (page.lang !== lang) continue;
var score = 0;
var titleLower = page.title.toLowerCase();
var bodyLower = (page.body || '').toLowerCase();
if (titleLower.indexOf(q) !== -1) {
score += 10;
// Bonus for exact title match
if (titleLower === q) score += 5;
}
if (bodyLower.indexOf(q) !== -1) {
score += 3;
}
if (page.section.toLowerCase().indexOf(q) !== -1) {
score += 1;
}
if (score > 0) {
scored.push({ page: page, score: score });
}
}
// Sort by score descending
scored.sort(function (a, b) { return b.score - a.score; });
// Limit results
var results = scored.slice(0, 20);
if (results.length === 0) {
resultsList.innerHTML = '<li class="search-no-results">No results found.</li>';
activeIndex = -1;
return;
}
var html = '';
for (var j = 0; j < results.length; j++) {
var r = results[j];
var snippet = buildSnippet(r.page.body, query);
html += '<li data-url="' + r.page.url + '">'
+ '<div class="search-result-title">' + highlightText(r.page.title, query) + '</div>'
+ (snippet ? '<div class="search-result-snippet">' + snippet + '</div>' : '')
+ '</li>';
}
resultsList.innerHTML = html;
activeIndex = -1;
}
function setActive(index) {
var items = resultsList.querySelectorAll('li[data-url]');
if (items.length === 0) return;
// Remove previous active
for (var i = 0; i < items.length; i++) {
items[i].classList.remove('active');
}
if (index < 0) index = items.length - 1;
if (index >= items.length) index = 0;
activeIndex = index;
items[activeIndex].classList.add('active');
items[activeIndex].scrollIntoView({ block: 'nearest' });
}
function navigateToActive() {
var items = resultsList.querySelectorAll('li[data-url]');
if (activeIndex >= 0 && activeIndex < items.length) {
var url = items[activeIndex].getAttribute('data-url');
if (url) {
closeSearch();
window.location.href = url;
}
}
}
// Event: search button
if (searchBtn) {
searchBtn.addEventListener('click', function (e) {
e.stopPropagation();
openSearch();
});
}
// Use capture phase to intercept keys before browser default behavior
// (e.g. ESC clearing input text in some browsers)
document.addEventListener('keydown', function (e) {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
overlay.classList.contains('open') ? closeSearch() : openSearch();
return;
}
if (!overlay.classList.contains('open')) return;
if (e.key === 'Escape') {
e.preventDefault();
closeSearch();
} else if (e.key === 'ArrowDown') {
e.preventDefault();
setActive(activeIndex + 1);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setActive(activeIndex - 1);
} else if (e.key === 'Enter') {
e.preventDefault();
navigateToActive();
}
}, true); // capture phase
// Event: click overlay background to close
overlay.addEventListener('click', function (e) {
if (e.target === overlay) {
closeSearch();
}
});
// Event: click result item
resultsList.addEventListener('click', function (e) {
var li = e.target.closest('li[data-url]');
if (!li) return;
var url = li.getAttribute('data-url');
if (url) {
closeSearch();
window.location.href = url;
}
});
// Event: input for live search
var debounceTimer = null;
input.addEventListener('input', function () {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(function () {
search(input.value.trim());
}, 150);
});
})();
-88
View File
@@ -1,88 +0,0 @@
<!DOCTYPE html>
<html lang="{{ lang }}" data-base-path="{{ site.base_path }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page.title }} - {{ site.title }}</title>
<link rel="icon" type="image/svg+xml" href="{{ site.base_path }}/favicon.svg">
<link rel="stylesheet" href="{{ site.base_path }}/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="{{ site.base_path }}/{{ lang }}/" class="header-title">{{ site.title }}{% if site.version %} <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v{{ site.version }}</span>{% endif %}</a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="{{ site.base_path }}/{{ lang }}/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
{% for link in site.nav %}
{% if link.url %}
<a href="{{ link.url }}"{% if link.icon_svg %} aria-label="{{ link.label }}"{% endif %}>
{% if link.icon_svg %}{{ link.icon_svg | safe }}{% endif %}
{{ link.label }}
</a>
{% elif link.path %}
<a href="{{ site.base_path }}/{{ lang }}/{{ link.path }}">
{% if link.icon_svg %}{{ link.icon_svg | safe }}{% endif %}
{{ link.label }}
</a>
{% endif %}
{% endfor %}
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
{{ lang | upper }}
</button>
<ul class="lang-popup">
{% for l in site.langs %}
<li><a href="#" data-lang="{{ l }}">{{ l | upper }}</a></li>
{% endfor %}
</ul>
</div>
</div>
{% block sidebar_toggle %}{% endblock %}
</div>
</header>
{% if page.status == "draft" %}
<div class="draft-banner">DRAFT</div>
{% endif %}
<div class="layout {% block layout_class %}{% endblock %}">
{% block body %}{% endblock %}
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="{{ site.base_path }}/js/main.js"></script>
</body>
</html>
-30
View File
@@ -1,30 +0,0 @@
{% extends "base.html" %}
{% block layout_class %}has-sidebar{% endblock %}
{% block sidebar_toggle %}<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>{% endblock %}
{% block body %}
<aside class="sidebar">
<nav class="sidebar-nav">
{% for section in nav %}
<div class="nav-section">
<a href="{{ section.url }}" class="nav-section-title {% if section.active %}active{% endif %}">{{ section.title }}</a>
{% if section.children %}
<ul class="nav-list">
{% for item in section.children %}
<li><a href="{{ item.url }}" class="{% if item.active %}active{% endif %}">{{ item.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</nav>
</aside>
<main class="content">
<article>
<h1>{{ page.title }}</h1>
{{ content | safe }}
</article>
</main>
{% endblock %}
-12
View File
@@ -1,12 +0,0 @@
{% extends "base.html" %}
{% block layout_class %}no-sidebar{% endblock %}
{% block body %}
<main class="content portal">
<article>
<h1>{{ page.title }}</h1>
{{ content | safe }}
</article>
</main>
{% endblock %}
-468
View File
@@ -1,468 +0,0 @@
use crate::config::{NavLink, SiteConfig};
use crate::defaults;
use crate::markdown::{Frontmatter, MarkdownRenderer};
use crate::utils::copy_dir_recursive;
use anyhow::{Context, Result};
use serde::Serialize;
use std::fs;
use std::path::{Path, PathBuf};
use tera::Tera;
use walkdir::WalkDir;
#[derive(Debug, Serialize)]
struct PageContext {
title: String,
url: String,
status: Option<String>,
}
/// Entry for pages-data.json used by client-side search.
#[derive(Debug, Serialize)]
struct PageDataEntry {
title: String,
url: String,
lang: String,
section: String,
/// Plain-text body with HTML tags stripped (truncated to ~500 chars).
body: String,
}
#[derive(Debug, Serialize, Clone)]
struct NavItem {
title: String,
url: String,
children: Vec<NavItem>,
active: bool,
}
#[derive(Debug, Serialize)]
struct SiteContext {
title: String,
version: Option<String>,
base_url: String,
base_path: String,
langs: Vec<String>,
nav: Vec<NavLink>,
}
struct Page {
frontmatter: Frontmatter,
html_content: String,
url: String,
out_path: PathBuf,
rel_path: String,
section: String,
}
pub fn build(src: &Path, out: &Path) -> Result<()> {
let config = SiteConfig::load(src)?;
let renderer = MarkdownRenderer::new(
config.highlight_dark_theme(),
config.highlight_light_theme(),
);
// Build Tera: start with embedded defaults, then override with user templates
let tera = build_tera(src)?;
// Clean output directory
if out.exists() {
fs::remove_dir_all(out).context("Failed to clean output directory")?;
}
fs::create_dir_all(out)?;
// Copy static files: embedded defaults first, then user overrides on top
copy_default_static(out)?;
let static_dir = src.join("static");
if static_dir.exists() {
copy_dir_recursive(&static_dir, out)?;
}
// Collect page data entries for pages-data.json across all languages
let mut page_data_entries: Vec<PageDataEntry> = Vec::new();
// Build each language
for lang in &config.i18n.langs {
let pages_dir = src.join("pages").join(lang);
if !pages_dir.exists() {
eprintln!("Warning: pages directory not found for lang '{}', skipping", lang);
continue;
}
let pages = collect_pages(&pages_dir, lang, out, &renderer, &config.site.base_path)?;
let nav = build_nav(&pages);
for page in &pages {
// Collect search data for pages-data.json
let plain_body = strip_html_tags(&remove_light_theme_blocks(&page.html_content));
let truncated_body: String = plain_body.chars().take(500).collect();
page_data_entries.push(PageDataEntry {
title: page.frontmatter.title.clone(),
url: page.url.clone(),
lang: lang.clone(),
section: page.section.clone(),
body: truncated_body,
});
let template_name = if page.section.is_empty() {
"portal.html"
} else {
"page.html"
};
// Filter nav to only the current section
let section_nav: Vec<&NavItem> = nav
.iter()
.filter(|item| {
let item_section = extract_section(&item.url, &config.site.base_path);
item_section == page.section
})
.collect();
let mut ctx = tera::Context::new();
ctx.insert("page", &PageContext {
title: page.frontmatter.title.clone(),
url: page.url.clone(),
status: page.frontmatter.status.clone(),
});
ctx.insert("content", &page.html_content);
ctx.insert("lang", lang);
ctx.insert("site", &SiteContext {
title: config.site.title.clone(),
version: config.site.version.clone(),
base_url: config.site.base_url(),
base_path: config.site.base_path.clone(),
langs: config.i18n.langs.clone(),
nav: config.nav.clone(),
});
// Set active state and pass nav
let mut nav_with_active: Vec<NavItem> = section_nav
.into_iter()
.cloned()
.map(|mut item| {
set_active(&mut item, &page.url);
item
})
.collect();
// If we're on a section index page, expand its children
if let Some(item) = nav_with_active.first_mut() {
if item.url == page.url {
item.active = true;
}
}
ctx.insert("nav", &nav_with_active);
let html = tera
.render(template_name, &ctx)
.with_context(|| format!("Failed to render template for {}", page.url))?;
if let Some(parent) = page.out_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&page.out_path, html)?;
}
}
// Generate pages-data.json for client-side search
let pages_json = serde_json::to_string(&page_data_entries)
.context("Failed to serialize pages-data.json")?;
fs::write(out.join("pages-data.json"), pages_json)?;
// Generate root redirect
generate_root_redirect(out, &config)?;
println!(
"Site generated: {} languages, output at {}",
config.i18n.langs.len(),
out.display()
);
Ok(())
}
fn collect_pages(
pages_dir: &Path,
lang: &str,
out: &Path,
renderer: &MarkdownRenderer,
base_path: &str,
) -> Result<Vec<Page>> {
let mut pages = Vec::new();
for entry in WalkDir::new(pages_dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
e.path().extension().map_or(false, |ext| ext == "md")
})
{
let path = entry.path();
let content = fs::read_to_string(path)
.with_context(|| format!("Failed to read {}", path.display()))?;
let (frontmatter, body) = MarkdownRenderer::parse_frontmatter(&content)
.with_context(|| format!("Failed to parse frontmatter in {}", path.display()))?;
let html_content = renderer.render(body);
let rel = path.strip_prefix(pages_dir)?;
let rel_str = rel.to_string_lossy().to_string();
// Compute URL and output path
let (url, out_path) = if rel.file_name().map_or(false, |f| f == "index.md") {
// index.md -> <base_path>/<lang>/dir/
let parent = rel.parent().unwrap_or(Path::new(""));
if parent.as_os_str().is_empty() {
// Root index.md
(
format!("{}/{}/", base_path, lang),
out.join(lang).join("index.html"),
)
} else {
(
format!("{}/{}/{}/", base_path, lang, parent.display()),
out.join(lang).join(parent).join("index.html"),
)
}
} else {
// foo.md -> <base_path>/<lang>/foo/
let stem = rel.with_extension("");
(
format!("{}/{}/{}/", base_path, lang, stem.display()),
out.join(lang).join(&stem).join("index.html"),
)
};
let section = extract_section(&url, base_path);
pages.push(Page {
frontmatter,
html_content,
url,
out_path,
rel_path: rel_str,
section,
});
}
Ok(pages)
}
fn extract_section(url: &str, base_path: &str) -> String {
// Strip base_path prefix before parsing
let stripped = url.strip_prefix(base_path).unwrap_or(url);
// URL format: /<lang>/ or /<lang>/section/...
let parts: Vec<&str> = stripped.trim_matches('/').split('/').collect();
if parts.len() >= 2 {
parts[1].to_string()
} else {
String::new()
}
}
fn build_nav(pages: &[Page]) -> Vec<NavItem> {
// Group pages by section (top-level directory)
let mut sections: std::collections::BTreeMap<String, Vec<&Page>> =
std::collections::BTreeMap::new();
for page in pages {
if page.section.is_empty() {
continue; // Skip root index (portal)
}
sections
.entry(page.section.clone())
.or_default()
.push(page);
}
let mut nav = Vec::new();
for (section, mut section_pages) in sections {
// Sort by order, then by filename
section_pages.sort_by(|a, b| {
a.frontmatter
.order
.cmp(&b.frontmatter.order)
.then_with(|| a.rel_path.cmp(&b.rel_path))
});
// Find the section index page
let index_page = section_pages
.iter()
.find(|p| p.rel_path.ends_with("index.md") && p.section == section);
let section_title = index_page
.map(|p| p.frontmatter.title.clone())
.unwrap_or_else(|| section.clone());
let section_url = index_page
.map(|p| p.url.clone())
.unwrap_or_default();
let children: Vec<NavItem> = section_pages
.iter()
.filter(|p| !p.rel_path.ends_with("index.md") || p.section != section)
.map(|p| NavItem {
title: p.frontmatter.title.clone(),
url: p.url.clone(),
children: Vec::new(),
active: false,
})
.collect();
nav.push(NavItem {
title: section_title,
url: section_url,
children,
active: false,
});
}
// Sort nav sections by order of their index pages
nav
}
fn set_active(item: &mut NavItem, current_url: &str) {
if item.url == current_url {
item.active = true;
}
for child in &mut item.children {
set_active(child, current_url);
if child.active {
item.active = true;
}
}
}
fn generate_root_redirect(out: &Path, config: &SiteConfig) -> Result<()> {
let base_path = &config.site.base_path;
let html = format!(
r#"<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
(function() {{
var lang = localStorage.getItem('preferred-lang') || '{default_lang}';
window.location.replace('{base_path}/' + lang + '/');
}})();
</script>
<meta http-equiv="refresh" content="0;url={base_path}/{default_lang}/">
<title>Redirecting...</title>
</head>
<body>
<p>Redirecting to <a href="{base_path}/{default_lang}/">{base_path}/{default_lang}/</a>...</p>
</body>
</html>"#,
default_lang = config.i18n.default_lang(),
base_path = base_path,
);
fs::write(out.join("index.html"), html)?;
Ok(())
}
/// Build Tera with embedded default templates, then override with any files
/// found in `<src>/templates/`.
fn build_tera(src: &Path) -> Result<Tera> {
let mut tera = Tera::default();
// Register embedded defaults
for (name, source) in defaults::default_templates() {
tera.add_raw_template(name, source)
.with_context(|| format!("Failed to add default template '{}'", name))?;
}
// Override with user-provided templates (if any)
let templates_dir = src.join("templates");
if templates_dir.exists() {
for entry in WalkDir::new(&templates_dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "html"))
{
let path = entry.path();
let rel = path.strip_prefix(&templates_dir)?;
let name = rel.to_string_lossy().replace('\\', "/");
let source = fs::read_to_string(path)
.with_context(|| format!("Failed to read template {}", path.display()))?;
tera.add_raw_template(&name, &source)
.with_context(|| format!("Failed to register template '{}'", name))?;
}
}
Ok(tera)
}
/// Write embedded default static files (css/js) to the output directory.
fn copy_default_static(out: &Path) -> Result<()> {
for (rel_path, content) in defaults::default_static_files() {
let target = out.join(rel_path);
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
// Only write if not already present (user file takes precedence via
// the subsequent copy_dir_recursive call, but write defaults first)
fs::write(&target, content)?;
}
Ok(())
}
/// Strip HTML tags from a string and collapse whitespace into a single space,
/// producing a plain-text representation suitable for search indexing.
fn strip_html_tags(html: &str) -> String {
let mut result = String::with_capacity(html.len());
let mut in_tag = false;
for ch in html.chars() {
match ch {
'<' => in_tag = true,
'>' => {
in_tag = false;
// Insert a space to avoid words being glued across tags
result.push(' ');
}
_ if !in_tag => result.push(ch),
_ => {}
}
}
// Collapse whitespace
let collapsed: String = result.split_whitespace().collect::<Vec<_>>().join(" ");
collapsed
}
/// Remove `<div data-code-theme="light">...</div>` blocks so that
/// dual-theme code snippets are only indexed once.
fn remove_light_theme_blocks(html: &str) -> String {
const MARKER: &str = "<div data-code-theme=\"light\"";
let mut result = String::with_capacity(html.len());
let mut remaining = html;
while let Some(start) = remaining.find(MARKER) {
result.push_str(&remaining[..start]);
remaining = &remaining[start..];
let mut depth: usize = 0;
let mut i = 0;
while i < remaining.len() {
if remaining[i..].starts_with("<div") {
depth += 1;
i += 4;
} else if remaining[i..].starts_with("</div>") {
depth -= 1;
i += 6;
if depth == 0 {
break;
}
} else {
i += remaining[i..].chars().next().map_or(1, |c| c.len_utf8());
}
}
remaining = &remaining[i..];
}
result.push_str(remaining);
result
}
-97
View File
@@ -1,97 +0,0 @@
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Deserialize)]
pub struct SiteConfig {
pub site: Site,
pub i18n: I18n,
pub highlight: Option<Highlight>,
#[serde(default)]
pub nav: Vec<NavLink>,
}
/// A navigation link entry defined in config.toml under [[nav]].
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct NavLink {
pub label: String,
/// Absolute or external URL (e.g. GitHub link).
pub url: Option<String>,
/// Path relative to /<base_path>/<lang>/ (e.g. "tour/").
pub path: Option<String>,
/// Optional inline SVG string to display as an icon.
pub icon_svg: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct Site {
pub title: String,
pub version: Option<String>,
/// Optional hostname (e.g. "https://example.github.io"). Combined with
/// base_path to form the full base URL.
pub hostname: Option<String>,
#[serde(default)]
pub base_path: String,
}
impl Site {
/// Returns the full base URL derived from hostname + base_path.
/// Falls back to base_path alone if hostname is not set.
pub fn base_url(&self) -> String {
match &self.hostname {
Some(h) => format!("{}{}", h.trim_end_matches('/'), self.base_path),
None => self.base_path.clone(),
}
}
}
#[derive(Debug, Deserialize)]
pub struct I18n {
pub langs: Vec<String>,
}
impl I18n {
/// Returns the default language, which is the first entry in langs.
pub fn default_lang(&self) -> &str {
self.langs.first().map(|s| s.as_str()).unwrap_or("en")
}
}
#[derive(Debug, Deserialize)]
pub struct Highlight {
pub dark_theme: Option<String>,
pub light_theme: Option<String>,
}
impl SiteConfig {
pub fn load(src_dir: &Path) -> Result<Self> {
let path = src_dir.join("config.toml");
let content =
std::fs::read_to_string(&path).with_context(|| format!("Failed to read {}", path.display()))?;
let mut config: SiteConfig =
toml::from_str(&content).with_context(|| format!("Failed to parse {}", path.display()))?;
// Validate required fields
if config.i18n.langs.is_empty() {
anyhow::bail!("[i18n] langs must not be empty. Please specify at least one language.");
}
// Normalize base_path: strip trailing slash (but keep empty for root)
let bp = config.site.base_path.trim_end_matches('/').to_string();
config.site.base_path = bp;
Ok(config)
}
pub fn highlight_dark_theme(&self) -> &str {
self.highlight
.as_ref()
.and_then(|h| h.dark_theme.as_deref())
.unwrap_or("base16-ocean.dark")
}
pub fn highlight_light_theme(&self) -> Option<&str> {
self.highlight
.as_ref()
.and_then(|h| h.light_theme.as_deref())
}
}
-47
View File
@@ -1,47 +0,0 @@
// Default embedded theme files. Users can override any of these by placing
// a file with the same name under their <SRC>/templates/ or <SRC>/static/.
pub const TEMPLATE_BASE: &str = include_str!("../defaults/templates/base.html");
pub const TEMPLATE_PAGE: &str = include_str!("../defaults/templates/page.html");
pub const TEMPLATE_PORTAL: &str = include_str!("../defaults/templates/portal.html");
pub const STATIC_CSS_MAIN: &str = include_str!("../defaults/static/css/main.css");
pub const STATIC_JS_MAIN: &str = include_str!("../defaults/static/js/main.js");
pub const STATIC_FAVICON_SVG: &str = include_str!("../defaults/static/favicon.svg");
// Init command templates
pub const INIT_CONFIG_TOML: &str = include_str!("../defaults/config.toml");
pub const INIT_PAGE_EN_INDEX: &str = include_str!("../defaults/pages/en/index.md");
pub const INIT_PAGE_JA_INDEX: &str = include_str!("../defaults/pages/ja/index.md");
/// Returns all default templates as (name, source) pairs for Tera registration.
pub fn default_templates() -> Vec<(&'static str, &'static str)> {
vec![
("base.html", TEMPLATE_BASE),
("page.html", TEMPLATE_PAGE),
("portal.html", TEMPLATE_PORTAL),
]
}
/// Returns all default static files as (relative_path, content) pairs.
pub fn default_static_files() -> Vec<(&'static str, &'static str)> {
vec![
("css/main.css", STATIC_CSS_MAIN),
("js/main.js", STATIC_JS_MAIN),
("favicon.svg", STATIC_FAVICON_SVG),
]
}
/// Returns all init scaffold files as (relative_path, content) pairs.
pub fn init_files() -> Vec<(&'static str, &'static str)> {
vec![
("config.toml", INIT_CONFIG_TOML),
("templates/base.html", TEMPLATE_BASE),
("templates/page.html", TEMPLATE_PAGE),
("templates/portal.html", TEMPLATE_PORTAL),
("static/css/main.css", STATIC_CSS_MAIN),
("static/js/main.js", STATIC_JS_MAIN),
("pages/en/index.md", INIT_PAGE_EN_INDEX),
("pages/ja/index.md", INIT_PAGE_JA_INDEX),
]
}
-99
View File
@@ -1,99 +0,0 @@
mod builder;
mod config;
mod defaults;
mod markdown;
mod serve;
mod utils;
use anyhow::Result;
use clap::{Parser, Subcommand, CommandFactory};
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Parser)]
#[command(version, about = "A simple static site generator")]
struct Cli {
#[command(subcommand)]
command: Option<Command>,
/// Source directory containing config.toml (used when no subcommand given)
#[arg(default_value = ".")]
src: PathBuf,
/// Output directory (used when no subcommand given)
#[arg(long, default_value = "docs")]
out: PathBuf,
}
#[derive(Subcommand)]
enum Command {
/// Build the documentation site
Build {
/// Source directory containing config.toml
#[arg(default_value = ".")]
src: PathBuf,
/// Output directory
#[arg(long, default_value = "docs")]
out: PathBuf,
},
/// Initialize a new docs project with default scaffold files
Init {
/// Target directory to initialize (default: current directory)
#[arg(default_value = ".")]
src: PathBuf,
},
/// Start a local development server with live-reload
Serve {
/// Source directory containing config.toml
#[arg(default_value = ".")]
src: PathBuf,
/// Port number for the HTTP server
#[arg(long, default_value = "8080")]
port: u16,
/// Open browser automatically
#[arg(long)]
open: bool,
},
}
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Some(Command::Build { src, out }) => builder::build(&src, &out),
Some(Command::Init { src }) => cmd_init(&src),
Some(Command::Serve { src, port, open }) => serve::serve(&src, port, open),
None => {
Cli::command().print_help()?;
println!();
Ok(())
}
}
}
fn cmd_init(target: &Path) -> Result<()> {
let mut skipped = 0usize;
let mut created = 0usize;
for (rel_path, content) in defaults::init_files() {
let dest = target.join(rel_path);
if dest.exists() {
eprintln!("Skipping (already exists): {}", dest.display());
skipped += 1;
continue;
}
if let Some(parent) = dest.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&dest, content)?;
println!("Created: {}", dest.display());
created += 1;
}
println!("\nInit complete: {} file(s) created, {} skipped.", created, skipped);
Ok(())
}
-145
View File
@@ -1,145 +0,0 @@
use anyhow::{Context, Result};
use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag, TagEnd};
use serde::Deserialize;
use syntect::highlighting::ThemeSet;
use syntect::html::highlighted_html_for_string;
use syntect::parsing::SyntaxSet;
#[derive(Debug, Deserialize)]
pub struct Frontmatter {
pub title: String,
#[serde(default)]
pub order: i32,
pub status: Option<String>,
}
pub struct MarkdownRenderer {
syntax_set: SyntaxSet,
theme_set: ThemeSet,
dark_theme: String,
light_theme: Option<String>,
}
impl MarkdownRenderer {
pub fn new(dark_theme: &str, light_theme: Option<&str>) -> Self {
Self {
syntax_set: SyntaxSet::load_defaults_newlines(),
theme_set: ThemeSet::load_defaults(),
dark_theme: dark_theme.to_string(),
light_theme: light_theme.map(|s| s.to_string()),
}
}
pub fn parse_frontmatter(content: &str) -> Result<(Frontmatter, &str)> {
let content = content.trim_start();
if !content.starts_with("---") {
anyhow::bail!("Missing frontmatter delimiter");
}
let after_first = &content[3..];
let end = after_first
.find("\n---")
.context("Missing closing frontmatter delimiter")?;
let yaml = &after_first[..end];
let body = &after_first[end + 4..];
let fm: Frontmatter =
serde_yaml::from_str(yaml).context("Failed to parse frontmatter YAML")?;
Ok((fm, body))
}
pub fn render(&self, markdown: &str) -> String {
let options = Options::ENABLE_TABLES
| Options::ENABLE_STRIKETHROUGH
| Options::ENABLE_TASKLISTS;
let parser = Parser::new_ext(markdown, options);
let mut in_code_block = false;
let mut code_lang = String::new();
let mut code_buf = String::new();
let mut events: Vec<Event> = Vec::new();
for event in parser {
match event {
Event::Start(Tag::CodeBlock(kind)) => {
in_code_block = true;
code_buf.clear();
code_lang = match kind {
CodeBlockKind::Fenced(lang) => lang.to_string(),
CodeBlockKind::Indented => String::new(),
};
}
Event::End(TagEnd::CodeBlock) => {
in_code_block = false;
let html = self.highlight_code(&code_buf, &code_lang);
events.push(Event::Html(html.into()));
}
Event::Text(text) if in_code_block => {
code_buf.push_str(&text);
}
other => events.push(other),
}
}
let mut html_output = String::new();
pulldown_cmark::html::push_html(&mut html_output, events.into_iter());
html_output
}
fn highlight_code(&self, code: &str, lang: &str) -> String {
let syntax = if lang.is_empty() {
self.syntax_set.find_syntax_plain_text()
} else {
self.syntax_set
.find_syntax_by_token(lang)
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
};
let dark_html = self.highlight_with_theme(code, syntax, &self.dark_theme);
match &self.light_theme {
Some(light) => {
let light_html = self.highlight_with_theme(code, syntax, light);
format!(
concat!(
"<div class=\"code-block-wrapper\">",
"<div data-code-theme=\"dark\">{}</div>",
"<div data-code-theme=\"light\">{}</div>",
"</div>",
),
dark_html, light_html
)
}
None => dark_html,
}
}
fn highlight_with_theme(
&self,
code: &str,
syntax: &syntect::parsing::SyntaxReference,
theme_name: &str,
) -> String {
let theme = self
.theme_set
.themes
.get(theme_name)
.unwrap_or_else(|| {
self.theme_set
.themes
.values()
.next()
.expect("No themes available")
});
match highlighted_html_for_string(code, &self.syntax_set, syntax, theme) {
Ok(html) => html,
Err(_) => format!("<pre><code>{}</code></pre>", escape_html(code)),
}
}
}
fn escape_html(s: &str) -> String {
s.replace('&', "&amp;")
.replace('<', "&lt;")
.replace('>', "&gt;")
}
-340
View File
@@ -1,340 +0,0 @@
use crate::builder;
use crate::config::SiteConfig;
use crate::utils::copy_dir_recursive;
use anyhow::{Context, Result};
use notify::{Event, RecursiveMode, Watcher};
use socket2::{Domain, Protocol, Socket, Type};
use std::fs;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::path::Path;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use walkdir::WalkDir;
/// Live-reload WebSocket script injected into every HTML page during serve.
const LIVE_RELOAD_SCRIPT: &str = r#"<script>
(function() {
var ws = new WebSocket('ws://' + location.hostname + ':{{WS_PORT}}');
ws.onmessage = function(e) { if (e.data === 'reload') location.reload(); };
ws.onclose = function() {
setTimeout(function() { location.reload(); }, 2000);
};
})();
</script>"#;
/// Run the serve command: build, start HTTP + WebSocket servers, watch for changes.
pub fn serve(src: &Path, port: u16, open_browser: bool) -> Result<()> {
let config = SiteConfig::load(src)?;
let base_path = config.site.base_path.clone();
let ws_port = port + 1;
// Create temp directory for serving
let tmp_dir = tempfile::tempdir().context("Failed to create temp directory")?;
let serve_root = tmp_dir.path().to_path_buf();
println!("Serving from temp directory: {}", serve_root.display());
// Initial build
build_and_copy(src, &serve_root, &base_path, ws_port)?;
// Track connected WebSocket clients
let clients: Arc<Mutex<Vec<TcpStream>>> = Arc::new(Mutex::new(Vec::new()));
// Create HTTP and WebSocket listeners upfront with SO_REUSEADDR
// so that rapid restarts (after Ctrl+C) don't hit "address in use".
let http_listener = create_reuse_listener(port)
.with_context(|| format!("Failed to bind HTTP server to port {}", port))?;
let ws_listener = create_reuse_listener(ws_port)
.with_context(|| format!("Failed to bind WebSocket server to port {}", ws_port))?;
// Start WebSocket server for live-reload notifications
let ws_clients = clients.clone();
thread::spawn(move || {
if let Err(e) = run_ws_server(ws_listener, ws_clients) {
eprintln!("WebSocket server error: {}", e);
}
});
// Start HTTP server
let http_root = serve_root.clone();
thread::spawn(move || {
if let Err(e) = run_http_server(http_listener, &http_root) {
eprintln!("HTTP server error: {}", e);
}
});
let url = if base_path.is_empty() {
format!("http://localhost:{}/", port)
} else {
format!("http://localhost:{}{}/", port, base_path)
};
println!("\n Local: {}", url);
println!(" Press Ctrl+C to stop.\n");
if open_browser {
let _ = open::that(&url);
}
// File watcher
let (tx, rx) = mpsc::channel();
let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
if let Ok(event) = res {
if event.kind.is_modify() || event.kind.is_create() || event.kind.is_remove() {
let _ = tx.send(());
}
}
})?;
let src_abs = fs::canonicalize(src)?;
watcher.watch(&src_abs, RecursiveMode::Recursive)?;
println!("Watching for changes in {}...", src_abs.display());
// Debounce: wait for changes, then rebuild
loop {
// Block until a change notification arrives
if rx.recv().is_err() {
break;
}
// Drain any additional events within a short debounce window
thread::sleep(Duration::from_millis(200));
while rx.try_recv().is_ok() {}
println!("Change detected, rebuilding...");
match build_and_copy(src, &serve_root, &base_path, ws_port) {
Ok(()) => {
println!("Rebuild complete. Notifying browser...");
notify_clients(&clients);
}
Err(e) => {
eprintln!("Rebuild failed: {}", e);
}
}
}
Ok(())
}
/// Build site into a temp build dir, then copy to serve_root/<base_path>/
/// with live-reload script injected.
fn build_and_copy(src: &Path, serve_root: &Path, base_path: &str, ws_port: u16) -> Result<()> {
// Build into a temporary output directory
let build_tmp = tempfile::tempdir().context("Failed to create build temp dir")?;
let build_out = build_tmp.path();
builder::build(src, build_out)?;
// Determine the target directory under serve_root
let target = if base_path.is_empty() {
serve_root.to_path_buf()
} else {
let bp = base_path.trim_start_matches('/');
serve_root.join(bp)
};
// Clean target and copy
if target.exists() {
fs::remove_dir_all(&target).ok();
}
copy_dir_recursive(build_out, &target)?;
// Inject live-reload script into all HTML files
inject_live_reload(&target, ws_port)?;
Ok(())
}
/// Inject live-reload WebSocket script into all HTML files under dir.
fn inject_live_reload(dir: &Path, ws_port: u16) -> Result<()> {
let script = LIVE_RELOAD_SCRIPT.replace("{{WS_PORT}}", &ws_port.to_string());
for entry in WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| {
e.path()
.extension()
.map_or(false, |ext| ext == "html")
})
{
let path = entry.path();
let content = fs::read_to_string(path)?;
if let Some(pos) = content.rfind("</body>") {
let injected = format!("{}{}{}", &content[..pos], script, &content[pos..]);
fs::write(path, injected)?;
}
}
Ok(())
}
/// Simple HTTP static file server using tiny_http.
fn run_http_server(listener: TcpListener, root: &Path) -> Result<()> {
let server = tiny_http::Server::from_listener(listener, None)
.map_err(|e| anyhow::anyhow!("HTTP server: {}", e))?;
for request in server.incoming_requests() {
let url_path = percent_decode(request.url());
let rel = url_path.trim_start_matches('/');
let file_path = if rel.is_empty() {
root.join("index.html")
} else {
let candidate = root.join(rel);
if candidate.is_dir() {
candidate.join("index.html")
} else {
candidate
}
};
if file_path.exists() && file_path.is_file() {
let content = fs::read(&file_path).unwrap_or_default();
let mime = guess_mime(&file_path);
let response = tiny_http::Response::from_data(content)
.with_header(
tiny_http::Header::from_bytes(&b"Content-Type"[..], mime.as_bytes()).unwrap(),
);
let _ = request.respond(response);
} else {
let response = tiny_http::Response::from_string("404 Not Found")
.with_status_code(404);
let _ = request.respond(response);
}
}
Ok(())
}
/// WebSocket server that accepts connections and stores them for later notification.
fn run_ws_server(listener: TcpListener, clients: Arc<Mutex<Vec<TcpStream>>>) -> Result<()> {
for stream in listener.incoming().flatten() {
let clients = clients.clone();
thread::spawn(move || {
if let Ok(ws) = tungstenite::accept(stream.try_clone().unwrap()) {
// Store the underlying TCP stream for later notification
if let Ok(mut list) = clients.lock() {
list.push(stream);
}
// Keep the WebSocket connection alive - read until closed
let mut ws = ws;
loop {
match ws.read() {
Ok(msg) => {
if msg.is_close() {
break;
}
}
Err(_) => break,
}
}
}
});
}
Ok(())
}
/// Send "reload" to all connected WebSocket clients.
fn notify_clients(clients: &Arc<Mutex<Vec<TcpStream>>>) {
if let Ok(mut list) = clients.lock() {
let mut alive = Vec::new();
for stream in list.drain(..) {
if stream.try_clone().is_ok() {
// Re-wrap as WebSocket and send reload message
// Since we can't easily re-wrap existing TCP streams,
// we'll use a simpler approach: raw WebSocket frame
if send_ws_text_frame(&stream, "reload").is_ok() {
alive.push(stream);
}
}
}
*list = alive;
}
}
/// Send a WebSocket text frame directly on a TCP stream.
fn send_ws_text_frame(mut stream: &TcpStream, msg: &str) -> Result<()> {
let payload = msg.as_bytes();
let len = payload.len();
// WebSocket text frame: opcode 0x81
let mut frame = Vec::new();
frame.push(0x81);
if len < 126 {
frame.push(len as u8);
} else if len < 65536 {
frame.push(126);
frame.push((len >> 8) as u8);
frame.push((len & 0xFF) as u8);
}
frame.extend_from_slice(payload);
stream.write_all(&frame)?;
stream.flush()?;
Ok(())
}
fn guess_mime(path: &Path) -> String {
match path.extension().and_then(|e| e.to_str()) {
Some("html") => "text/html; charset=utf-8".to_string(),
Some("css") => "text/css; charset=utf-8".to_string(),
Some("js") => "application/javascript; charset=utf-8".to_string(),
Some("json") => "application/json; charset=utf-8".to_string(),
Some("svg") => "image/svg+xml".to_string(),
Some("png") => "image/png".to_string(),
Some("jpg") | Some("jpeg") => "image/jpeg".to_string(),
Some("gif") => "image/gif".to_string(),
Some("ico") => "image/x-icon".to_string(),
Some("wasm") => "application/wasm".to_string(),
Some("woff") => "font/woff".to_string(),
Some("woff2") => "font/woff2".to_string(),
Some("ttf") => "font/ttf".to_string(),
_ => "application/octet-stream".to_string(),
}
}
fn percent_decode(input: &str) -> String {
let mut result = String::with_capacity(input.len());
let mut chars = input.bytes();
while let Some(b) = chars.next() {
if b == b'%' {
let hi = chars.next().and_then(|c| hex_val(c));
let lo = chars.next().and_then(|c| hex_val(c));
if let (Some(h), Some(l)) = (hi, lo) {
result.push((h << 4 | l) as char);
}
} else {
result.push(b as char);
}
}
result
}
fn hex_val(b: u8) -> Option<u8> {
match b {
b'0'..=b'9' => Some(b - b'0'),
b'a'..=b'f' => Some(b - b'a' + 10),
b'A'..=b'F' => Some(b - b'A' + 10),
_ => None,
}
}
/// Create a TCP listener with SO_REUSEADDR (and SO_REUSEPORT on Unix) set,
/// so that rapid restarts after Ctrl+C don't fail with "address in use".
fn create_reuse_listener(port: u16) -> Result<TcpListener> {
let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?;
socket.set_reuse_address(true)?;
#[cfg(unix)]
socket.set_reuse_port(true)?;
let addr: std::net::SocketAddr = format!("0.0.0.0:{}", port).parse()?;
socket.bind(&addr.into())?;
socket.listen(128)?;
Ok(socket.into())
}
-22
View File
@@ -1,22 +0,0 @@
use anyhow::Result;
use std::fs;
use std::path::Path;
use walkdir::WalkDir;
pub fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
let rel = path.strip_prefix(src)?;
let target = dst.join(rel);
if path.is_dir() {
fs::create_dir_all(&target)?;
} else {
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(path, &target)?;
}
}
Ok(())
}
+16 -8
View File
@@ -1,22 +1,30 @@
[system]
theme = "monotone"
langs = ["en", "ja"]
[site]
title = "cpp-httplib"
version = "0.35.0"
version = "0.38.0"
hostname = "https://yhirose.github.io"
base_path = "/cpp-httplib"
footer_message = "© 2026 Yuji Hirose. All rights reserved."
[[nav]]
label = "Tour"
path = "tour/"
icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>'
[[nav]]
label = "Cookbook"
path = "cookbook/"
icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
[[nav]]
label = "LLM App"
path = "llm-app/"
icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
[[nav]]
label = "GitHub"
url = "https://github.com/yhirose/cpp-httplib"
icon_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>'
[i18n]
langs = ["en", "ja"]
[highlight]
dark_theme = "base16-eighties.dark"
light_theme = "InspiredGitHub"
+90 -3
View File
@@ -1,8 +1,95 @@
---
title: "Cookbook"
order: 1
order: 0
---
This section is under construction.
A collection of recipes that answer "How do I...?" questions. Each recipe is self-contained — read only what you need.
Check back soon for a collection of recipes organized by topic.
## Client
### Basics
- Get the response body as a string / save to a file
- Send and receive JSON
- Set default headers (`set_default_headers`)
- Follow redirects (`set_follow_location`)
### Authentication
- Use Basic authentication (`set_basic_auth`)
- Call an API with a Bearer token
### File Upload
- Upload a file as multipart form data (`make_file_provider`)
- POST a file as raw binary (`make_file_body`)
- Send the body with chunked transfer (Content Provider)
### Streaming & Progress
- Receive a response as a stream
- Use the progress callback (`DownloadProgress` / `UploadProgress`)
### Connection & Performance
- Set timeouts (`set_connection_timeout` / `set_read_timeout`)
- Set an overall timeout (`set_max_timeout`)
- Understand connection reuse and Keep-Alive behavior
- Enable compression (`set_compress` / `set_decompress`)
- Send requests through a proxy (`set_proxy`)
### Error Handling & Debugging
- Handle error codes (`Result::error()`)
- Handle SSL errors (`ssl_error()` / `ssl_backend_error()`)
- Set up client logging (`set_logger` / `set_error_logger`)
## Server
### Basics
- Register GET / POST / PUT / DELETE handlers
- Receive JSON requests and return JSON responses
- Use path parameters (`/users/:id`)
- Set up a static file server (`set_mount_point`)
### Streaming & Files
- Stream a large file in the response (`ContentProvider`)
- Return a file download response (`Content-Disposition`)
- Receive multipart data as a stream (`ContentReader`)
- Compress responses (gzip)
### Handler Chain
- Add pre-processing to all routes (Pre-routing handler)
- Add response headers with a Post-routing handler (CORS, etc.)
- Authenticate per route with a Pre-request handler (`matched_route`)
- Pass data between handlers with `res.user_data`
### Error Handling & Debugging
- Return custom error pages (`set_error_handler`)
- Catch exceptions (`set_exception_handler`)
- Log requests (Logger)
- Detect client disconnection (`req.is_connection_closed()`)
### Operations & Tuning
- Assign a port dynamically (`bind_to_any_port`)
- Control startup order with `listen_after_bind`
- Shut down gracefully (`stop()` and signal handling)
- Tune Keep-Alive (`set_keep_alive_max_count` / `set_keep_alive_timeout`)
- Configure the thread pool (`new_task_queue`)
## TLS / Security
- Choosing between OpenSSL, mbedTLS, and wolfSSL (build-time `#define` differences)
- Control SSL certificate verification (disable, custom CA, custom callback)
- Use a custom certificate verification callback (`set_server_certificate_verifier`)
- Set up an SSL/TLS server (certificate and private key)
- Configure mTLS (mutual TLS with client certificates)
- Access the peer certificate on the server (`req.peer_cert()` / SNI)
## SSE
- Implement an SSE server
- Use event names to distinguish event types
- Handle reconnection (`Last-Event-ID`)
- Receive SSE events on the client
## WebSocket
- Implement a WebSocket echo server and client
- Configure heartbeats (`set_websocket_ping_interval` / `CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND`)
- Handle connection close
- Send and receive binary frames
+1
View File
@@ -19,3 +19,4 @@ Under the hood, it uses blocking I/O with a thread pool. It's not built for hand
- [A Tour of cpp-httplib](tour/) — A step-by-step tutorial covering the basics. Start here if you're new
- [Cookbook](cookbook/) — A collection of recipes organized by topic. Jump to whatever you need
- [Building a Desktop LLM App](llm-app/) — A hands-on guide to building a desktop app with llama.cpp, step by step
+22
View File
@@ -0,0 +1,22 @@
---
title: "Building a Desktop LLM App with cpp-httplib"
order: 0
---
Build an LLM-powered translation desktop app step by step, learning both the server and client sides of cpp-httplib along the way. Translation is just an example — swap it out to build your own summarizer, code generator, chatbot, or any other LLM application.
## Dependencies
- [llama.cpp](https://github.com/ggml-org/llama.cpp) — LLM inference engine
- [nlohmann/json](https://github.com/nlohmann/json) — JSON parser (header-only)
- [webview/webview](https://github.com/webview/webview) — WebView wrapper (header-only)
- [cpp-httplib](https://github.com/yhirose/cpp-httplib) — HTTP server/client (header-only)
## Chapters
1. **Embed llama.cpp and create a REST API** — Start with a simple API that accepts text via POST and returns a translation as JSON
2. **Add token streaming with SSE** — Stream translation results token by token using the standard LLM API approach
3. **Add model discovery and download** — Use the client to search and download GGUF models from Hugging Face
4. **Add a Web UI** — Serve a translation UI with static file hosting, making the app accessible from a browser
5. **Turn it into a desktop app with WebView** — Wrap the web app with webview/webview to create an Electron-like desktop application
6. **Code reading: llama.cpp's server implementation** — Compare your implementation with production-quality code and learn from the differences
+4 -4
View File
@@ -60,7 +60,7 @@ For uploading large files, `make_file_provider()` comes in handy. It streams the
```cpp
httplib::Client cli("http://localhost:8080");
auto res = cli.Post("/upload", {}, {
auto res = cli.Post("/upload", {}, {}, {
httplib::make_file_provider("file", "/path/to/large-file.zip")
});
```
@@ -160,16 +160,16 @@ svr.set_post_routing_handler([](const auto &req, auto &res) {
});
```
Use `req.user_data` to pass data from middleware to handlers. This is useful for sharing things like decoded auth tokens.
Use `res.user_data` to pass data from middleware to handlers. This is useful for sharing things like decoded auth tokens.
```cpp
svr.set_pre_routing_handler([](const auto &req, auto &res) {
req.user_data["auth_user"] = std::string("alice");
res.user_data["auth_user"] = std::string("alice");
return httplib::Server::HandlerResponse::Unhandled;
});
svr.Get("/me", [](const auto &req, auto &res) {
auto user = std::any_cast<std::string>(req.user_data.at("auth_user"));
auto user = std::any_cast<std::string>(res.user_data.at("auth_user"));
res.set_content("Hello, " + user, "text/plain");
});
```
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: "A Tour of cpp-httplib"
order: 1
order: 0
---
This is a step-by-step tutorial that walks you through the basics of cpp-httplib. Each chapter builds on the previous one, so please read them in order starting from Chapter 1.
+90 -3
View File
@@ -1,8 +1,95 @@
---
title: "Cookbook"
order: 1
order: 0
---
This section is under construction.
「〇〇をするには?」という問いに答えるレシピ集です。各レシピは独立しているので、必要なページだけ読めます。
Check back soon for a collection of recipes organized by topic.
## クライアント
### 基本
- レスポンスボディを文字列で取得する / ファイルに保存する
- JSON を送受信する
- デフォルトヘッダーを設定する(`set_default_headers`
- リダイレクトを追従する(`set_follow_location`
### 認証
- Basic 認証を使う(`set_basic_auth`
- Bearer トークンで API を呼ぶ
### ファイル送信
- ファイルをマルチパートフォームとしてアップロードする(`make_file_provider`
- ファイルを生バイナリとして POST する(`make_file_body`
- チャンク転送でボディを送る(Content Provider
### ストリーミング・進捗
- レスポンスをストリーミングで受信する
- 進捗コールバックを使う(`DownloadProgress` / `UploadProgress`
### 接続・パフォーマンス
- タイムアウトを設定する(`set_connection_timeout` / `set_read_timeout`
- 全体タイムアウトを設定する(`set_max_timeout`
- 接続の再利用と Keep-Alive の挙動を理解する
- 圧縮を有効にする(`set_compress` / `set_decompress`
- プロキシを経由してリクエストを送る(`set_proxy`
### エラー処理・デバッグ
- エラーコードをハンドリングする(`Result::error()`
- SSL エラーをハンドリングする(`ssl_error()` / `ssl_backend_error()`
- クライアントにログを設定する(`set_logger` / `set_error_logger`
## サーバー
### 基本
- GET / POST / PUT / DELETE ハンドラを登録する
- JSON リクエストを受け取り JSON レスポンスを返す
- パスパラメーターを使う(`/users/:id`
- 静的ファイルサーバーを設定する(`set_mount_point`
### ストリーミング・ファイル
- 大きなファイルをストリーミングで返す(`ContentProvider`
- ファイルダウンロードレスポンスを返す(`Content-Disposition`
- マルチパートデータをストリーミングで受け取る(`ContentReader`
- レスポンスを圧縮して返す(gzip)
### ハンドラチェーン
- 全ルートに共通の前処理をする(Pre-routing handler
- Post-routing handler でレスポンスヘッダーを追加する(CORS など)
- Pre-request handler でルート単位の認証を行う(`matched_route`
- `res.user_data` でハンドラ間データを渡す
### エラー処理・デバッグ
- カスタムエラーページを返す(`set_error_handler`
- 例外をキャッチする(`set_exception_handler`
- リクエストをログに記録する(Logger)
- クライアントが切断したか検出する(`req.is_connection_closed()`
### 運用・チューニング
- ポートを動的に割り当てる(`bind_to_any_port`
- `listen_after_bind` で起動順序を制御する
- グレースフルシャットダウンする(`stop()` とシグナルハンドリング)
- Keep-Alive を調整する(`set_keep_alive_max_count` / `set_keep_alive_timeout`
- マルチスレッド数を設定する(`new_task_queue`
## TLS / セキュリティ
- OpenSSL・mbedTLS・wolfSSL の選択指針(ビルド時の `#define` の違い)
- SSL 証明書の検証を制御する(証明書の無効化・カスタム CA・カスタムコールバック)
- カスタム証明書検証コールバックを使う(`set_server_certificate_verifier`
- SSL/TLS サーバーを立ち上げる(証明書・秘密鍵の設定)
- mTLS(クライアント証明書による相互認証)を設定する
- サーバー側でピア証明書を参照する(`req.peer_cert()` / SNI
## SSE
- SSE サーバーを実装する
- SSE でイベント名を使い分ける
- SSE の再接続を処理する(`Last-Event-ID`
- SSE をクライアントで受信する
## WebSocket
- WebSocket エコーサーバー/クライアントを実装する
- ハートビートを設定する(`set_websocket_ping_interval` / `CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND`
- 接続クローズをハンドリングする
- バイナリフレームを送受信する
+1
View File
@@ -19,3 +19,4 @@ HTTPSも使えます。OpenSSLやmbedTLSをリンクするだけで、サーバ
- [A Tour of cpp-httplib](tour/) — 基本を順を追って学べるチュートリアル。初めての方はここから
- [Cookbook](cookbook/) — 目的別のレシピ集。必要なトピックから読めます
- [Building a Desktop LLM App](llm-app/) — llama.cpp を組み込んだデスクトップアプリを段階的に構築する実践ガイド
+22
View File
@@ -0,0 +1,22 @@
---
title: "Building a Desktop LLM App with cpp-httplib"
order: 0
---
llama.cpp を組み込んだ LLM 翻訳デスクトップアプリを段階的に構築しながら、cpp-httplib のサーバー・クライアント両面の使い方を実践的に学びます。翻訳は一例であり、この部分を差し替えることで要約・コード生成・チャットボットなど自分のアプリに応用できます。
## 依存ライブラリ
- [llama.cpp](https://github.com/ggml-org/llama.cpp) — LLM 推論エンジン
- [nlohmann/json](https://github.com/nlohmann/json) — JSON パーサー(ヘッダーオンリー)
- [webview/webview](https://github.com/webview/webview) — WebView ラッパー(ヘッダーオンリー)
- [cpp-httplib](https://github.com/yhirose/cpp-httplib) — HTTP サーバー/クライアント(ヘッダーオンリー)
## 章立て
1. **llama.cpp を組み込んで REST API を作る** — テキストを POST すると翻訳結果を JSON で返すシンプルな API から始める
2. **SSE でトークンストリーミングを追加する** — 翻訳結果をトークン単位で逐次返す LLM API 標準の方式を実装する
3. **モデルの取得・管理機能を追加する** — Hugging Face から GGUF モデルを検索・ダウンロードするクライアント機能を実装する
4. **Web UI を追加する** — 静的ファイル配信で翻訳 UI をホストし、ブラウザから操作できるようにする
5. **WebView でデスクトップアプリ化する** — webview/webview で包み、Electron 的なデスクトップアプリとして動作させる
6. **llama.cpp 本家のサーバー実装をコードリーディング** — 自分で作ったものとプロダクション品質のコードを比較して学ぶ
+4 -4
View File
@@ -60,7 +60,7 @@ svr.Get("/stream", [](const auto &, auto &res) {
```cpp
httplib::Client cli("http://localhost:8080");
auto res = cli.Post("/upload", {}, {
auto res = cli.Post("/upload", {}, {}, {
httplib::make_file_provider("file", "/path/to/large-file.zip")
});
```
@@ -160,16 +160,16 @@ svr.set_post_routing_handler([](const auto &req, auto &res) {
});
```
`req.user_data` を使うと、ミドルウェアからハンドラーにデータを渡せます。認証トークンのデコード結果を共有するときに便利です。
`res.user_data` を使うと、ミドルウェアからハンドラーにデータを渡せます。認証トークンのデコード結果を共有するときに便利です。
```cpp
svr.set_pre_routing_handler([](const auto &req, auto &res) {
req.user_data["auth_user"] = std::string("alice");
res.user_data["auth_user"] = std::string("alice");
return httplib::Server::HandlerResponse::Unhandled;
});
svr.Get("/me", [](const auto &req, auto &res) {
auto user = std::any_cast<std::string>(req.user_data.at("auth_user"));
auto user = std::any_cast<std::string>(res.user_data.at("auth_user"));
res.set_content("Hello, " + user, "text/plain");
});
```
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: "A Tour of cpp-httplib"
order: 1
order: 0
---
cpp-httplibの基本を、順番に学んでいくチュートリアルです。各章は前の章の内容を踏まえて進む構成なので、1章から順に読んでください。
-603
View File
@@ -1,603 +0,0 @@
:root {
--bg: #333;
--bg-secondary: #3c3c3c;
--bg-code: #2a2a2a;
--text: #ccc;
--text-bright: white;
--text-muted: #999;
--text-code: #b0b0b0;
--text-inline-code: plum;
--border: #555;
--border-code: #3a3a3a;
--link: palegoldenrod;
--heading: lightskyblue;
--heading-link: #f0c090;
--header-nav-link: pink;
--emphasis: pink;
--nav-section: #bbb;
--nav-section-active: #ddd;
--content-width: 900px;
--sidebar-width: 280px;
--header-height: 48px;
--line-height: 1.6;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: var(--line-height);
}
a {
color: var(--link);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* Header */
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--header-height);
background-color: var(--bg-secondary);
border-bottom: 1px solid var(--border);
z-index: 100;
}
.header-inner {
height: 100%;
display: flex;
align-items: center;
padding: 0 16px;
gap: 24px;
}
.header-title {
color: var(--text);
font-weight: bold;
font-size: 1.1rem;
white-space: nowrap;
}
.header-title:hover {
text-decoration: none;
color: var(--text-bright);
}
.header-spacer {
flex: 1;
}
.header-nav {
display: flex;
gap: 16px;
}
.header-nav a {
display: flex;
align-items: center;
gap: 4px;
color: var(--header-nav-link);
font-size: 0.9rem;
}
.header-nav a svg {
flex-shrink: 0;
opacity: 0.85;
}
.header-tools {
display: flex;
align-items: center;
gap: 2px;
}
.lang-selector {
position: relative;
}
.lang-btn {
display: flex;
align-items: center;
gap: 5px;
background: none;
border: none;
color: var(--text);
padding: 4px 6px;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
opacity: 0.8;
}
.lang-btn:hover {
opacity: 1;
}
.lang-popup {
display: none;
position: absolute;
right: 0;
top: 100%;
margin-top: 4px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 4px;
list-style: none;
min-width: 60px;
z-index: 200;
}
.lang-popup.open {
display: block;
}
.lang-popup li a {
display: block;
padding: 6px 12px;
color: var(--text);
font-size: 0.85rem;
}
.lang-popup li a:hover {
background: var(--bg);
text-decoration: none;
}
.sidebar-toggle {
display: none;
background: none;
border: none;
color: var(--text);
font-size: 1.2rem;
cursor: pointer;
padding: 4px 8px;
}
/* Draft banner */
.draft-banner {
position: fixed;
top: var(--header-height);
right: 0;
background: #c44;
color: white;
padding: 4px 16px;
font-size: 0.75rem;
font-weight: bold;
letter-spacing: 0.1em;
z-index: 99;
}
/* Layout */
.layout {
margin-top: var(--header-height);
display: grid;
grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
min-height: calc(100vh - var(--header-height));
}
.layout.no-sidebar {
grid-template-columns: 1fr;
}
/* Sidebar */
.sidebar {
width: var(--sidebar-width);
flex-shrink: 0;
padding: 24px 16px;
border-right: 1px solid var(--bg-secondary);
position: sticky;
top: var(--header-height);
height: calc(100vh - var(--header-height));
overflow-y: auto;
}
.nav-section {
margin-bottom: 16px;
}
.nav-section-title {
color: var(--nav-section);
font-weight: bold;
font-size: 1.0rem;
display: block;
margin-bottom: 8px;
}
.nav-section-title.active {
color: var(--nav-section-active);
}
.nav-list {
list-style: none;
padding-left: 8px;
}
.nav-list li {
margin-bottom: 4px;
}
.nav-list li a {
color: var(--text-muted);
font-size: 0.85rem;
}
.nav-list li a:hover {
color: var(--text);
}
.nav-list li a.active {
color: var(--emphasis);
font-weight: bold;
}
/* Content */
.content {
min-width: 0;
max-width: var(--content-width);
padding: 32px 24px;
overflow-wrap: break-word;
}
.content.portal {
max-width: var(--content-width);
padding: 48px 24px;
margin: 0 auto;
}
.content article h1 {
font-size: 1.8rem;
margin-bottom: 24px;
color: var(--heading);
}
.content article h2 {
font-size: 1.4rem;
margin-top: 32px;
margin-bottom: 16px;
color: var(--heading-link);
}
.content article h3 {
font-size: 1.1rem;
margin-top: 24px;
margin-bottom: 12px;
color: var(--text);
}
.content article p {
margin-bottom: 12px;
}
.content article ul,
.content article ol {
margin-bottom: 12px;
padding-left: 24px;
}
.content article li {
margin-bottom: 4px;
}
.content article strong {
color: var(--emphasis);
}
.content article code {
background: var(--bg-code);
color: var(--text-inline-code);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
}
.content article pre {
background: var(--bg-code);
color: var(--text-code);
padding: 16px;
border-radius: 4px;
overflow-x: auto;
margin-bottom: 16px;
border: 1px solid var(--border-code);
}
.content article pre code {
background: none;
padding: 0;
}
.content article table {
width: 100%;
border-collapse: collapse;
margin-bottom: 16px;
}
.content article th,
.content article td {
border: 1px solid var(--bg-secondary);
padding: 8px 12px;
text-align: left;
}
.content article th {
background: var(--bg-secondary);
}
.content article blockquote {
border-left: 3px solid var(--text-muted);
padding-left: 16px;
margin-bottom: 12px;
color: var(--text-muted);
}
/* Code block theme switching: show dark by default, swap on light mode */
.code-block-wrapper > [data-code-theme="light"] {
display: none;
}
html[data-theme="light"] .code-block-wrapper > [data-code-theme="dark"] {
display: none;
}
html[data-theme="light"] .code-block-wrapper > [data-code-theme="light"] {
display: block;
}
/* Footer */
.footer {
padding: 12px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.8rem;
border-top: 1px solid var(--bg-secondary);
}
/* Responsive */
@media (max-width: 768px) {
.layout {
grid-template-columns: minmax(0, 1fr);
}
.sidebar {
position: fixed;
left: calc(-1 * var(--sidebar-width));
width: var(--sidebar-width);
top: var(--header-height);
height: calc(100vh - var(--header-height));
background: var(--bg);
z-index: 50;
transition: left 0.2s ease;
border-right: 1px solid var(--border);
}
.sidebar.open {
left: 0;
}
.sidebar-toggle {
display: block;
}
.content {
padding: 24px 16px;
}
}
@media (max-width: 480px) {
:root {
--header-height: 44px;
}
.header-inner {
padding: 0 12px;
gap: 12px;
}
.header-nav a {
font-size: 0.8rem;
}
.content article h1 {
font-size: 1.4rem;
}
.content article h2 {
font-size: 1.2rem;
}
}
/* Light mode */
[data-theme="light"] {
--bg: #f5f5f5;
--bg-secondary: #e8e8e8;
--bg-code: #eee;
--text: #333;
--text-bright: #000;
--text-muted: #666;
--text-code: #333;
--text-inline-code: #8b5ca0;
--border: #ccc;
--border-code: #ddd;
--link: #b8860b;
--heading: #2a6496;
--heading-link: #c06020;
--header-nav-link: #c04060;
--emphasis: #c04060;
--nav-section: #666;
--nav-section-active: #333;
}
/* Theme toggle */
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--text);
padding: 5px 6px;
border-radius: 4px;
cursor: pointer;
opacity: 0.8;
}
.theme-toggle:hover {
opacity: 1;
}
/* Search button */
.search-btn {
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
color: var(--text);
padding: 5px 6px;
border-radius: 4px;
cursor: pointer;
opacity: 0.8;
}
.search-btn:hover {
opacity: 1;
}
/* Search overlay & modal */
.search-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 300;
justify-content: center;
align-items: flex-start;
padding-top: 12vh;
}
.search-overlay.open {
display: flex;
}
.search-modal {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
width: 90%;
max-width: 560px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
overflow: hidden;
}
.search-input-wrap {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
}
.search-input-wrap svg {
flex-shrink: 0;
opacity: 0.5;
}
#search-input {
flex: 1;
background: none;
border: none;
outline: none;
color: var(--text-bright);
font-size: 1rem;
font-family: inherit;
}
#search-input::placeholder {
color: var(--text-muted);
}
.search-esc {
background: var(--bg);
color: var(--text-muted);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.7rem;
border: 1px solid var(--border);
}
.search-results {
list-style: none;
max-height: 50vh;
overflow-y: auto;
padding: 0;
margin: 0;
}
.search-results:empty::after {
content: "";
display: none;
}
.search-results li {
padding: 10px 16px;
cursor: pointer;
border-bottom: 1px solid var(--border);
}
.search-results li:last-child {
border-bottom: none;
}
.search-results li:hover,
.search-results li.active {
background: var(--bg);
}
.search-results li .search-result-title {
color: var(--text-bright);
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 2px;
}
.search-results li .search-result-snippet {
color: var(--text-muted);
font-size: 0.8rem;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.search-results li .search-result-snippet mark {
background: rgba(255, 215, 0, 0.3);
color: var(--text-bright);
border-radius: 2px;
padding: 0 1px;
}
[data-theme="light"] .search-results li .search-result-snippet mark {
background: rgba(255, 200, 0, 0.4);
color: var(--text);
}
.search-no-results {
padding: 24px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.9rem;
}
-109
View File
@@ -1,109 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cookbook - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;cookbook&#x2F;" class="nav-section-title active">Cookbook</a>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Cookbook</h1>
<p>This section is under construction.</p>
<p>Check back soon for a collection of recipes organized by topic.</p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-108
View File
@@ -1,108 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>cpp-httplib - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
</div>
</header>
<div class="layout no-sidebar">
<main class="content portal">
<article>
<h1>cpp-httplib</h1>
<p><a href="https://github.com/yhirose/cpp-httplib">cpp-httplib</a> is an HTTP/HTTPS library for C++. Just copy a single header file, <a href="https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h"><code>httplib.h</code></a>, and you're ready to go.</p>
<p>When you need a quick HTTP server or client in C++, you want something that just works. That's exactly why I built cpp-httplib. You can start writing both servers and clients in just a few lines of code.</p>
<p>The API uses a lambda-based design that feels natural. It runs anywhere you have a C++11 or later compiler. Windows, macOS, Linux — use whatever environment you already have.</p>
<p>HTTPS works too. Just link OpenSSL or mbedTLS, and both server and client gain TLS support. Content-Encoding (gzip, Brotli, etc.), file uploads, and other features you actually need in real-world development are all included. WebSocket is also supported.</p>
<p>Under the hood, it uses blocking I/O with a thread pool. It's not built for handling massive numbers of simultaneous connections. But for API servers, embedded HTTP in tools, mock servers for testing, and many other use cases, it delivers solid performance.</p>
<p>"Solve today's problem, today." That's the kind of simplicity cpp-httplib aims for.</p>
<h2>Documentation</h2>
<ul>
<li><a href="tour/">A Tour of cpp-httplib</a> — A step-by-step tutorial covering the basics. Start here if you're new</li>
<li><a href="cookbook/">Cookbook</a> — A collection of recipes organized by topic. Jump to whatever you need</li>
</ul>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-234
View File
@@ -1,234 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Getting Started - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="active">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Getting Started</h1>
<p>All you need to get started with cpp-httplib is <code>httplib.h</code> and a C++ compiler. Let's download the file and get a Hello World server running.</p>
<h2>Getting httplib.h</h2>
<p>You can download it directly from GitHub. Always use the latest version.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -LO</span><span style="color:#d3d0c8;"> https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h
</span></pre>
</div></div>
<p>Place the downloaded <code>httplib.h</code> in your project directory and you're good to go.</p>
<h2>Setting Up Your Compiler</h2>
<table><thead><tr><th>OS</th><th>Development Environment</th><th>Setup</th></tr></thead><tbody>
<tr><td>macOS</td><td>Apple Clang</td><td>Xcode Command Line Tools (<code>xcode-select --install</code>)</td></tr>
<tr><td>Ubuntu</td><td>clang++ or g++</td><td><code>apt install clang</code> or <code>apt install g++</code></td></tr>
<tr><td>Windows</td><td>MSVC</td><td>Visual Studio 2022 or later (install with C++ components)</td></tr>
</tbody></table>
<h2>Hello World Server</h2>
<p>Save the following code as <code>server.cpp</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request&amp;, httplib::Response&amp; res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, World!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request</span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::Response</span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;"> res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, World!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>In just a few lines, you have a server that responds to HTTP requests.</p>
<h2>Compiling and Running</h2>
<p>The sample code in this tutorial is written in C++17 for cleaner, more concise code. cpp-httplib itself can compile with C++11 as well.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Linux
</span><span style="color:#747369;"># `-pthread`: cpp-httplib uses threads internally
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -pthread -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows (Developer Command Prompt)
</span><span style="color:#747369;"># `/EHsc`: Enable C++ exception handling
</span><span style="color:#6699cc;">cl</span><span style="color:#d3d0c8;"> /EHsc /std:c++17 server.cpp
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Linux
</span><span style="font-style:italic;color:#969896;"># `-pthread`: cpp-httplib uses threads internally
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -pthread -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows (Developer Command Prompt)
</span><span style="font-style:italic;color:#969896;"># `/EHsc`: Enable C++ exception handling
</span><span style="color:#323232;">cl /EHsc /std:c++17 server.cpp
</span></pre>
</div></div>
<p>Once it compiles, run it.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS / Linux
</span><span style="color:#6699cc;">./server
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows
</span><span style="color:#6699cc;">server.exe
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS / Linux
</span><span style="color:#323232;">./server
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows
</span><span style="color:#323232;">server.exe
</span></pre>
</div></div>
<p>Open <code>http://localhost:8080</code> in your browser. If you see "Hello, World!", you're all set.</p>
<p>You can also verify with <code>curl</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/
</span><span style="color:#747369;"># Hello, World!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/
</span><span style="font-style:italic;color:#969896;"># Hello, World!
</span></pre>
</div></div>
<p>To stop the server, press <code>Ctrl+C</code> in your terminal.</p>
<h2>Next Steps</h2>
<p>Now you know the basics of running a server. Next, let's look at the client side. cpp-httplib also comes with HTTP client functionality.</p>
<p><strong>Next:</strong> <a href="../02-basic-client">Basic Client</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-527
View File
@@ -1,527 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Client - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="active">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Basic Client</h1>
<p>cpp-httplib isn't just for servers -- it also comes with a full HTTP client. Let's use <code>httplib::Client</code> to send GET and POST requests.</p>
<h2>Preparing a Test Server</h2>
<p>To try out the client, you need a server that accepts requests. Save the following code, then compile and run it the same way you did in the previous chapter. We'll cover the server details in the next chapter.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">];
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">];
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<h2>GET Request</h2>
<p>Once the server is running, open a separate terminal and give it a try. Let's start with the simplest GET request.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>Pass the server address to the <code>httplib::Client</code> constructor, then call <code>Get()</code> to send a request. You can retrieve the status code and body from the returned <code>res</code>.</p>
<p>Here's the equivalent <code>curl</code> command.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/hi
</span><span style="color:#747369;"># Hello!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/hi
</span><span style="font-style:italic;color:#969896;"># Hello!
</span></pre>
</div></div>
<h2>Checking the Response</h2>
<p>A response contains header information in addition to the status code and body.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Status code
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Body
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello!
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Headers
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Content-Type</span><span style="color:#d3d0c8;">&quot;) &lt;&lt; std::endl; </span><span style="color:#747369;">// text/plain
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Status code
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Body
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello!
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Headers
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;get_header_value(</span><span style="color:#183691;">&quot;Content-Type&quot;</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// text/plain
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>res-&gt;body</code> is a <code>std::string</code>, so if you want to parse a JSON response, you can pass it directly to a JSON library like <a href="https://github.com/nlohmann/json">nlohmann/json</a>.</p>
<h2>Query Parameters</h2>
<p>To add query parameters to a GET request, you can either write them directly in the URL or use <code>httplib::Params</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, httplib::Params{{&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">cpp-httplib</span><span style="color:#d3d0c8;">&quot;}});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Query: cpp-httplib
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, httplib::Params{{</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;cpp-httplib&quot;</span><span style="color:#323232;">}});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Query: cpp-httplib
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>httplib::Params</code> automatically URL-encodes special characters for you.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">http://localhost:8080/search?q=cpp-httplib</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#747369;"># Query: cpp-httplib
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl </span><span style="color:#183691;">&quot;http://localhost:8080/search?q=cpp-httplib&quot;
</span><span style="font-style:italic;color:#969896;"># Query: cpp-httplib
</span></pre>
</div></div>
<h2>Path Parameters</h2>
<p>When values are embedded directly in the URL path, no special client API is needed. Just pass the path to <code>Get()</code> as-is.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/42</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// User ID: 42
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/users/42&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// User ID: 42
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/users/42
</span><span style="color:#747369;"># User ID: 42
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/users/42
</span><span style="font-style:italic;color:#969896;"># User ID: 42
</span></pre>
</div></div>
<p>The test server also has a <code>/files/(\d+)</code> route that uses a regex to accept numeric IDs only.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/files/42</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// File ID: 42
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/files/42&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// File ID: 42
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/files/42
</span><span style="color:#747369;"># File ID: 42
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/files/42
</span><span style="font-style:italic;color:#969896;"># File ID: 42
</span></pre>
</div></div>
<p>Pass a non-numeric ID like <code>/files/abc</code> and you'll get a 404. We'll cover how that works in the next chapter.</p>
<h2>Request Headers</h2>
<p>To add custom HTTP headers, pass an <code>httplib::Headers</code> object. This works with both <code>Get()</code> and <code>Post()</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, httplib::Headers{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Bearer my-token</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, httplib::Headers{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Bearer my-token&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -H </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Authorization: Bearer my-token</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/hi
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -H </span><span style="color:#183691;">&quot;Authorization: Bearer my-token&quot;</span><span style="color:#323232;"> http://localhost:8080/hi
</span></pre>
</div></div>
<h2>POST Request</h2>
<p>Let's POST some text data. Pass the body as the second argument to <code>Post()</code> and the Content-Type as the third.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Hello, Server!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, Server!
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Hello, Server!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, Server!
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>The test server's <code>/post</code> endpoint echoes the body back, so you get the same string you sent.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -X</span><span style="color:#d3d0c8;"> POST</span><span style="color:#f2777a;"> -H </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Content-Type: text/plain</span><span style="color:#d3d0c8;">&quot;</span><span style="color:#f2777a;"> -d </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Hello, Server!</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/post
</span><span style="color:#747369;"># Hello, Server!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -X POST -H </span><span style="color:#183691;">&quot;Content-Type: text/plain&quot;</span><span style="color:#323232;"> -d </span><span style="color:#183691;">&quot;Hello, Server!&quot;</span><span style="color:#323232;"> http://localhost:8080/post
</span><span style="font-style:italic;color:#969896;"># Hello, Server!
</span></pre>
</div></div>
<h2>Sending Form Data</h2>
<p>You can send key-value pairs just like an HTML form. Use <code>httplib::Params</code> for this.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, httplib::Params{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">name</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Alice</span><span style="color:#d3d0c8;">&quot;},
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">age</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">30</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// age = 30
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// name = Alice
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, httplib::Params{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;name&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Alice&quot;</span><span style="color:#323232;">},
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;age&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;30&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// age = 30
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// name = Alice
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>This sends the data in <code>application/x-www-form-urlencoded</code> format.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -X</span><span style="color:#d3d0c8;"> POST</span><span style="color:#f2777a;"> -d </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">name=Alice&amp;age=30</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/submit
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -X POST -d </span><span style="color:#183691;">&quot;name=Alice&amp;age=30&quot;</span><span style="color:#323232;"> http://localhost:8080/submit
</span></pre>
</div></div>
<h2>POSTing a File</h2>
<p>To upload a file, use <code>httplib::UploadFormDataItems</code> to send it as multipart form data.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, httplib::UploadFormDataItems{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Hello, File!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">hello.txt</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// hello.txt (12 bytes)
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, httplib::UploadFormDataItems{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Hello, File!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;hello.txt&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// hello.txt (12 bytes)
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>Each element in <code>UploadFormDataItems</code> has four fields: <code>{name, content, filename, content_type}</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -F </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">file=Hello, File!;filename=hello.txt;type=text/plain</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/upload
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -F </span><span style="color:#183691;">&quot;file=Hello, File!;filename=hello.txt;type=text/plain&quot;</span><span style="color:#323232;"> http://localhost:8080/upload
</span></pre>
</div></div>
<h2>Error Handling</h2>
<p>Network communication can fail -- the server might not be reachable. Always check whether <code>res</code> is valid.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:9999</span><span style="color:#d3d0c8;">&quot;); </span><span style="color:#747369;">// Non-existent port
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(!res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Connection error
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Error: Connection
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">}
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// If we reach here, we have a response
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">!= </span><span style="color:#f99157;">200</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">HTTP Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">}
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:9999&quot;</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// Non-existent port
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">!</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Connection error
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Error: Connection
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// If we reach here, we have a response
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">!= </span><span style="color:#0086b3;">200</span><span style="color:#323232;">) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;HTTP Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="color:#323232;">std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span></pre>
</div></div>
<p>There are two levels of errors.</p>
<ul>
<li><strong>Connection error</strong>: The client couldn't reach the server. <code>res</code> evaluates to false, and you can call <code>res.error()</code> to find out what went wrong.</li>
<li><strong>HTTP error</strong>: The server returned an error status (404, 500, etc.). <code>res</code> evaluates to true, but you need to check <code>res-&gt;status</code>.</li>
</ul>
<h2>Next Steps</h2>
<p>Now you know how to send requests from a client. Next, let's take a closer look at the server side. We'll dig into routing, path parameters, and more.</p>
<p><strong>Next:</strong> <a href="../03-basic-server">Basic Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-482
View File
@@ -1,482 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="active">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Basic Server</h1>
<p>In the previous chapter, you sent requests from a client to a test server. Now let's walk through how that server actually works.</p>
<h2>Starting the Server</h2>
<p>Once you've registered your routes, call <code>svr.listen()</code> to start the server.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>The first argument is the host, and the second is the port. <code>"0.0.0.0"</code> listens on all network interfaces. Use <code>"127.0.0.1"</code> if you want to accept connections from your own machine only.</p>
<p><code>listen()</code> is a blocking call. It won't return until the server stops. The server keeps running until you press <code>Ctrl+C</code> in your terminal or call <code>svr.stop()</code> from another thread.</p>
<h2>Routing</h2>
<p>Routing is the heart of any server. It's how you tell cpp-httplib: when a request comes in for this URL with this HTTP method, run this code.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;req, httplib::Response &amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">req, httplib::Response </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>svr.Get()</code> registers a handler for GET requests. The first argument is the path, the second is the handler function. When a GET request arrives at <code>/hi</code>, your lambda runs.</p>
<p>There's a method for each HTTP verb.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// GET
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// POST
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Put</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// PUT
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Delete</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// DELETE
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// GET
</span><span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// POST
</span><span style="color:#323232;">svr.Put(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// PUT
</span><span style="color:#323232;">svr.Delete(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// DELETE
</span></pre>
</div></div>
<p>The handler signature is <code>(const httplib::Request &amp;req, httplib::Response &amp;res)</code>. You can use <code>auto</code> to keep it short.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>The handler only runs when the path matches. Requests to unregistered paths automatically return 404.</p>
<h2>The Request Object</h2>
<p>The first parameter <code>req</code> gives you everything the client sent.</p>
<h3>Body</h3>
<p><code>req.body</code> holds the request body as a <code>std::string</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Echo the body back to the client
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Echo the body back to the client
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>Headers</h3>
<p>Use <code>req.get_header_value()</code> to read a request header.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/check</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> auth = req.</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Auth: </span><span style="color:#d3d0c8;">&quot; + auth, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/check&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> auth </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_header_value(</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Auth: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> auth, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>Query Parameters and Form Data</h3>
<p><code>req.get_param_value()</code> retrieves a parameter by name. It works for both GET query parameters and POST form data.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>A request to <code>/search?q=cpp-httplib</code> gives you <code>"cpp-httplib"</code> for <code>q</code>.</p>
<p>To loop over all parameters, use <code>req.params</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>File Uploads</h3>
<p>Files uploaded via multipart form data are available through <code>req.form.get_file()</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>f.filename</code> gives you the filename, and <code>f.content</code> gives you the file data.</p>
<h2>Path Parameters</h2>
<p>Sometimes you want to capture part of the URL as a variable -- for example, the <code>42</code> in <code>/users/42</code>. Use the <code>:param</code> syntax to do that.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>A request to <code>/users/42</code> gives you <code>"42"</code> from <code>req.path_params.at("id")</code>. <code>/users/100</code> gives you <code>"100"</code>.</p>
<p>You can capture multiple segments at once.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:user_id/posts/:post_id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> user_id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user_id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> post_id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">post_id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User: </span><span style="color:#d3d0c8;">&quot; + user_id + &quot;</span><span style="color:#99cc99;">, Post: </span><span style="color:#d3d0c8;">&quot; + post_id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:user_id/posts/:post_id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> user_id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;user_id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> post_id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;post_id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> user_id </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;, Post: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> post_id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>Regex Patterns</h3>
<p>You can also write a regular expression directly in the path instead of <code>:param</code>. Capture group values are available via <code>req.matches</code>, which is a <code>std::smatch</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// Only accept numeric IDs
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">]; </span><span style="color:#747369;">// First capture group
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// Only accept numeric IDs
</span><span style="color:#323232;">svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">]; </span><span style="font-style:italic;color:#969896;">// First capture group
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>/files/42</code> matches, but <code>/files/abc</code> doesn't. This is handy when you want to constrain what values are accepted.</p>
<h2>Building a Response</h2>
<p>The second parameter <code>res</code> is how you send data back to the client.</p>
<h3>Body and Content-Type</h3>
<p><code>res.set_content()</code> sets the body and Content-Type. That's all you need for a 200 response.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>Status Code</h3>
<p>To return a different status code, assign to <code>res.status</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/not-found</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">= </span><span style="color:#f99157;">404</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Not found</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/not-found&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">404</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Not found&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>Response Headers</h3>
<p>Add response headers with <code>res.set_header()</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/with-header</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_header</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">X-Custom</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">my-value</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/with-header&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_header(</span><span style="color:#183691;">&quot;X-Custom&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;my-value&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Walking Through the Test Server</h2>
<p>Now let's use what we've learned to read through the test server from the previous chapter.</p>
<h3>GET /hi</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>The simplest possible handler. We don't need any information from the request, so the <code>req</code> parameter is left unnamed. It just returns <code>"Hello!"</code>.</p>
<h3>GET /search</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>req.get_param_value("q")</code> pulls out the query parameter <code>q</code>. A request to <code>/search?q=cpp-httplib</code> returns <code>"Query: cpp-httplib"</code>.</p>
<h3>POST /post</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>An echo server. Whatever body the client sends, <code>req.body</code> holds it, and we send it straight back.</p>
<h3>POST /submit</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>Loops over the form data in <code>req.params</code> using structured bindings (<code>auto &amp;[key, val]</code>) to unpack each key-value pair.</p>
<h3>POST /upload</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>Receives a file uploaded via multipart form data. <code>req.form.get_file("file")</code> fetches the field named <code>"file"</code>, and we respond with the filename and size.</p>
<h3>GET /users/:id</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>:id</code> is the path parameter. <code>req.path_params.at("id")</code> retrieves its value. <code>/users/42</code> gives you <code>"42"</code>, <code>/users/alice</code> gives you <code>"alice"</code>.</p>
<h3>GET /files/(\d+)</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">];
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">];
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>The regex <code>(\d+)</code> matches numeric IDs only. <code>/files/42</code> hits this handler, but <code>/files/abc</code> returns 404. <code>req.matches[1]</code> retrieves the first capture group.</p>
<h2>Next Steps</h2>
<p>You now have the full picture of how a server works. Routing, reading requests, building responses -- that's enough to build a real API server.</p>
<p>Next, let's look at serving static files. We'll build a server that delivers HTML and CSS.</p>
<p><strong>Next:</strong> <a href="../04-static-file-server">Static File Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
@@ -1,305 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Static File Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="active">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Static File Server</h1>
<p>cpp-httplib can serve static files too — HTML, CSS, images, you name it. No complicated configuration required. One call to <code>set_mount_point()</code> is all it takes.</p>
<h2>The basics of set_mount_point</h2>
<p>Let's jump right in. <code>set_mount_point()</code> maps a URL path to a local directory.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./html</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./html&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>The first argument is the URL mount point. The second is the local directory path. In this example, requests to <code>/</code> are served from the <code>./html</code> directory.</p>
<p>Let's try it out. First, create an <code>html</code> directory and add an <code>index.html</code> file.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">mkdir</span><span style="color:#d3d0c8;"> html
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">mkdir html
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">&lt;!</span><span style="color:#f2777a;">DOCTYPE</span><span style="color:#d3d0c8;"> html&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">html</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">head</span><span style="color:#d3d0c8;">&gt;&lt;</span><span style="color:#f2777a;">title</span><span style="color:#d3d0c8;">&gt;My Page&lt;/</span><span style="color:#f2777a;">title</span><span style="color:#d3d0c8;">&gt;&lt;/</span><span style="color:#f2777a;">head</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;"> &lt;</span><span style="color:#f2777a;">h1</span><span style="color:#d3d0c8;">&gt;Hello from cpp-httplib!&lt;/</span><span style="color:#f2777a;">h1</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;"> &lt;</span><span style="color:#f2777a;">p</span><span style="color:#d3d0c8;">&gt;This is a static file.&lt;/</span><span style="color:#f2777a;">p</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;/</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;/</span><span style="color:#f2777a;">html</span><span style="color:#d3d0c8;">&gt;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">&lt;!</span><span style="color:#63a35c;">DOCTYPE</span><span style="color:#323232;"> html&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">html</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">head</span><span style="color:#323232;">&gt;&lt;</span><span style="color:#63a35c;">title</span><span style="color:#323232;">&gt;My Page&lt;/</span><span style="color:#63a35c;">title</span><span style="color:#323232;">&gt;&lt;/</span><span style="color:#63a35c;">head</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">body</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;"> &lt;</span><span style="color:#63a35c;">h1</span><span style="color:#323232;">&gt;Hello from cpp-httplib!&lt;/</span><span style="color:#63a35c;">h1</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;"> &lt;</span><span style="color:#63a35c;">p</span><span style="color:#323232;">&gt;This is a static file.&lt;/</span><span style="color:#63a35c;">p</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;/</span><span style="color:#63a35c;">body</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;/</span><span style="color:#63a35c;">html</span><span style="color:#323232;">&gt;
</span></pre>
</div></div>
<p>Compile and start the server.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">g++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp</span><span style="color:#f2777a;"> -pthread
</span><span style="color:#6699cc;">./server
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">g++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -o server server.cpp -pthread
</span><span style="color:#323232;">./server
</span></pre>
</div></div>
<p>Open <code>http://localhost:8080</code> in your browser. You should see the contents of <code>html/index.html</code>. Visiting <code>http://localhost:8080/index.html</code> returns the same page.</p>
<p>You can also access it with the client code from the previous chapter, or with <code>curl</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// HTML is displayed
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// HTML is displayed
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080
</span></pre>
</div></div>
<h2>Multiple mount points</h2>
<p>You can call <code>set_mount_point()</code> as many times as you like. Each URL path gets its own directory.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/assets</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./static/assets</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/docs</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./documentation</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/assets&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./static/assets&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/docs&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./documentation&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>A request to <code>/assets/style.css</code> serves <code>./static/assets/style.css</code>. A request to <code>/docs/guide.html</code> serves <code>./documentation/guide.html</code>.</p>
<h2>Combining with handlers</h2>
<p>Static file serving and routing handlers — the kind you learned about in the previous chapter — work side by side.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// API endpoint
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/api/hello</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">{&quot;message&quot;:&quot;Hello!&quot;}</span><span style="color:#d3d0c8;">)&quot;, &quot;</span><span style="color:#99cc99;">application/json</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// Static file serving
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// API endpoint
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/api/hello&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;({&quot;message&quot;:&quot;Hello!&quot;})&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;application/json&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// Static file serving
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>Handlers take priority. The handler responds to <code>/api/hello</code>. For every other path, the server looks for a file in <code>./public</code>.</p>
<h2>Adding response headers</h2>
<p>Pass headers as the third argument to <code>set_mount_point()</code> and they get attached to every static file response. This is great for cache control.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;, {
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">Cache-Control</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">max-age=3600</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">, {
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;Cache-Control&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;max-age=3600&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>With this in place, the browser caches served files for one hour.</p>
<h2>A Dockerfile for your static file server</h2>
<p>The cpp-httplib repository includes a <code>Dockerfile</code> built for static file serving. We also publish a pre-built image on Docker Hub, so you can get up and running with a single command.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">&gt; docker run</span><span style="color:#f2777a;"> -p</span><span style="color:#d3d0c8;"> 8080:80</span><span style="color:#f2777a;"> -v</span><span style="color:#d3d0c8;"> ./my-site:/html yhirose4dockerhub/cpp-httplib-server
</span><span style="color:#6699cc;">Serving</span><span style="color:#d3d0c8;"> HTTP on 0.0.0.0:80
</span><span style="color:#6699cc;">Mount</span><span style="color:#d3d0c8;"> point: / -&gt; ./html
</span><span style="color:#6699cc;">Press</span><span style="color:#d3d0c8;"> Ctrl+C to shutdown gracefully...
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:00 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET / HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 200 256 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:00 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET /style.css HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 200 1024 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:01 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET /favicon.ico HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 404 152 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">&gt;</span><span style="color:#323232;"> docker run -p 8080:80 -v ./my-site:/html yhirose4dockerhub/cpp-httplib-server
</span><span style="color:#323232;">Serving HTTP on 0.0.0.0:80
</span><span style="color:#323232;">Mount point: / -</span><span style="font-weight:bold;color:#a71d5d;">&gt;</span><span style="color:#323232;"> ./html
</span><span style="color:#323232;">Press Ctrl+C to shutdown gracefully...
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:00 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET / HTTP/1.1&quot;</span><span style="color:#323232;"> 200 256 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:00 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET /style.css HTTP/1.1&quot;</span><span style="color:#323232;"> 200 1024 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:01 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET /favicon.ico HTTP/1.1&quot;</span><span style="color:#323232;"> 404 152 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span></pre>
</div></div>
<p>Everything in your <code>./my-site</code> directory gets served on port 8080. The access log follows the same format as NGINX, so you can see exactly what's happening.</p>
<h2>What's next</h2>
<p>You can now serve static files. A web server that delivers HTML, CSS, and JavaScript — built with this little code.</p>
<p>Next, let's encrypt your connections with HTTPS. We'll start by setting up a TLS library.</p>
<p><strong>Next:</strong> <a href="../05-tls-setup">TLS Setup</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-229
View File
@@ -1,229 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TLS Setup - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="active">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>TLS Setup</h1>
<p>So far we've been using plain HTTP, but in the real world, HTTPS is the norm. To use HTTPS with cpp-httplib, you need a TLS library.</p>
<p>In this tour, we'll use OpenSSL. It's the most widely used option, and you'll find plenty of resources online.</p>
<h2>Installing OpenSSL</h2>
<p>Install it for your OS.</p>
<table><thead><tr><th>OS</th><th>How to install</th></tr></thead><tbody>
<tr><td>macOS</td><td><a href="https://brew.sh/">Homebrew</a> (<code>brew install openssl</code>)</td></tr>
<tr><td>Ubuntu / Debian</td><td><code>sudo apt install libssl-dev</code></td></tr>
<tr><td>Windows</td><td><a href="https://vcpkg.io/">vcpkg</a> (<code>vcpkg install openssl</code>)</td></tr>
</tbody></table>
<h2>Compile Options</h2>
<p>To enable TLS, define the <code>CPPHTTPLIB_OPENSSL_SUPPORT</code> macro when compiling. You'll need a few extra options compared to the previous chapters.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS (Homebrew)
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -DCPPHTTPLIB_OPENSSL_SUPPORT </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -I</span><span style="color:#d3d0c8;">$</span><span style="color:#f2777a;">(</span><span style="color:#6699cc;">brew</span><span style="color:#f2777a;"> --prefix openssl)</span><span style="color:#d3d0c8;">/include \
</span><span style="color:#f2777a;"> -L</span><span style="color:#d3d0c8;">$</span><span style="color:#f2777a;">(</span><span style="color:#6699cc;">brew</span><span style="color:#f2777a;"> --prefix openssl)</span><span style="color:#d3d0c8;">/lib \
</span><span style="color:#f2777a;"> -lssl -lcrypto </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -framework</span><span style="color:#d3d0c8;"> CoreFoundation</span><span style="color:#f2777a;"> -framework</span><span style="color:#d3d0c8;"> Security \
</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Linux
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -pthread -DCPPHTTPLIB_OPENSSL_SUPPORT </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -lssl -lcrypto </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows (Developer Command Prompt)
</span><span style="color:#6699cc;">cl</span><span style="color:#d3d0c8;"> /EHsc /std:c++17 /DCPPHTTPLIB_OPENSSL_SUPPORT server.cpp libssl.lib libcrypto.lib
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS (Homebrew)
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -DCPPHTTPLIB_OPENSSL_SUPPORT \
</span><span style="color:#323232;"> -I$(brew --prefix openssl)/include \
</span><span style="color:#323232;"> -L$(brew --prefix openssl)/lib \
</span><span style="color:#323232;"> -lssl -lcrypto \
</span><span style="color:#323232;"> -framework CoreFoundation -framework Security \
</span><span style="color:#323232;"> -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Linux
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -pthread -DCPPHTTPLIB_OPENSSL_SUPPORT \
</span><span style="color:#323232;"> -lssl -lcrypto \
</span><span style="color:#323232;"> -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows (Developer Command Prompt)
</span><span style="color:#323232;">cl /EHsc /std:c++17 /DCPPHTTPLIB_OPENSSL_SUPPORT server.cpp libssl.lib libcrypto.lib
</span></pre>
</div></div>
<p>Let's look at what each option does.</p>
<ul>
<li><strong><code>-DCPPHTTPLIB_OPENSSL_SUPPORT</code></strong> — Defines the macro that enables TLS support</li>
<li><strong><code>-lssl -lcrypto</code></strong> — Links the OpenSSL libraries</li>
<li><strong><code>-I</code> / <code>-L</code></strong> (macOS only) — Points to the Homebrew OpenSSL paths</li>
<li><strong><code>-framework CoreFoundation -framework Security</code></strong> (macOS only) — Needed to automatically load system certificates from the Keychain</li>
</ul>
<h2>Verifying the Setup</h2>
<p>Let's make sure everything works. Here's a simple program that passes an HTTPS URL to <code>httplib::Client</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://www.google.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Status: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://www.google.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Status: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>Compile and run it. If you see <code>Status: 200</code>, your setup is complete.</p>
<h2>Other TLS Backends</h2>
<p>cpp-httplib also supports Mbed TLS and wolfSSL in addition to OpenSSL. You can switch between them just by changing the macro definition and linked libraries.</p>
<table><thead><tr><th style="text-align: left">Backend</th><th style="text-align: left">Macro</th><th style="text-align: left">Libraries to link</th></tr></thead><tbody>
<tr><td style="text-align: left">OpenSSL</td><td style="text-align: left"><code>CPPHTTPLIB_OPENSSL_SUPPORT</code></td><td style="text-align: left"><code>libssl</code>, <code>libcrypto</code></td></tr>
<tr><td style="text-align: left">Mbed TLS</td><td style="text-align: left"><code>CPPHTTPLIB_MBEDTLS_SUPPORT</code></td><td style="text-align: left"><code>libmbedtls</code>, <code>libmbedx509</code>, <code>libmbedcrypto</code></td></tr>
<tr><td style="text-align: left">wolfSSL</td><td style="text-align: left"><code>CPPHTTPLIB_WOLFSSL_SUPPORT</code></td><td style="text-align: left"><code>libwolfssl</code></td></tr>
</tbody></table>
<p>This tour assumes OpenSSL, but the API is the same regardless of which backend you choose.</p>
<h2>Next Step</h2>
<p>You're all set with TLS. Next, let's send a request to an HTTPS site.</p>
<p><strong>Next:</strong> <a href="../06-https-client">HTTPS Client</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-287
View File
@@ -1,287 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HTTPS Client - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="active">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>HTTPS Client</h1>
<p>In the previous chapter, you set up OpenSSL. Now let's put it to use with an HTTPS client. You can use the same <code>httplib::Client</code> from Chapter 2. Just pass a URL with the <code>https://</code> scheme to the constructor.</p>
<h2>GET Request</h2>
<p>Let's try accessing a real HTTPS site.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">substr</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">100</span><span style="color:#d3d0c8;">) &lt;&lt; std::endl; </span><span style="color:#747369;">// First 100 chars of the HTML
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body.substr(</span><span style="color:#0086b3;">0</span><span style="color:#323232;">, </span><span style="color:#0086b3;">100</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// First 100 chars of the HTML
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>In Chapter 2, you wrote <code>httplib::Client cli("http://localhost:8080")</code>. All you need to change is the scheme to <code>https://</code>. Every API you learned in Chapter 2 -- <code>Get()</code>, <code>Post()</code>, and so on -- works exactly the same way.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> https://nghttp2.org/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl https://nghttp2.org/
</span></pre>
</div></div>
<h2>Specifying a Port</h2>
<p>The default port for HTTPS is 443. If you need a different port, include it in the URL.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>CA Certificate Verification</h2>
<p>When connecting over HTTPS, <code>httplib::Client</code> verifies the server certificate by default. It only connects to servers whose certificate was issued by a trusted CA (Certificate Authority).</p>
<p>CA certificates are loaded automatically from the Keychain on macOS, the system CA certificate store on Linux, and the Windows certificate store on Windows. In most cases, no extra configuration is needed.</p>
<h3>Specifying a CA Certificate File</h3>
<p>On some environments, the system CA certificates may not be found. In that case, use <code>set_ca_cert_path()</code> to specify the path directly.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_ca_cert_path</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/etc/ssl/certs/ca-certificates.crt</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_ca_cert_path(</span><span style="color:#183691;">&quot;/etc/ssl/certs/ca-certificates.crt&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> --cacert</span><span style="color:#d3d0c8;"> /etc/ssl/certs/ca-certificates.crt https://nghttp2.org/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl --cacert /etc/ssl/certs/ca-certificates.crt https://nghttp2.org/
</span></pre>
</div></div>
<h3>Disabling Certificate Verification</h3>
<p>During development, you might want to connect to a server with a self-signed certificate. You can disable verification for that.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">enable_server_certificate_verification</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">false</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.enable_server_certificate_verification(</span><span style="color:#0086b3;">false</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -k</span><span style="color:#d3d0c8;"> https://localhost:8443/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -k https://localhost:8443/
</span></pre>
</div></div>
<p>Never disable this in production. It opens you up to man-in-the-middle attacks.</p>
<h2>Following Redirects</h2>
<p>When accessing HTTPS sites, you'll often encounter redirects. For example, <code>http://</code> to <code>https://</code>, or a bare domain to <code>www</code>.</p>
<p>By default, redirects are not followed. You can check the redirect target in the <code>Location</code> header.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/httpbin/redirect/3</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 302
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Location</span><span style="color:#d3d0c8;">&quot;) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/httpbin/redirect/3&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 302
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;get_header_value(</span><span style="color:#183691;">&quot;Location&quot;</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div></div>
<p>Call <code>set_follow_location(true)</code> to automatically follow redirects and get the final response.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_follow_location</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/httpbin/redirect/3</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200 (the final response)
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_follow_location(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/httpbin/redirect/3&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200 (the final response)
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -L</span><span style="color:#d3d0c8;"> https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -L https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div></div>
<h2>Next Steps</h2>
<p>Now you know how to use the HTTPS client. Next, let's set up your own HTTPS server. We'll start with creating a self-signed certificate.</p>
<p><strong>Next:</strong> <a href="../07-https-server">HTTPS Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-276
View File
@@ -1,276 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HTTPS Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="active">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>HTTPS Server</h1>
<p>In the previous chapter, you used an HTTPS client. Now let's set up your own HTTPS server. Just swap <code>httplib::Server</code> from Chapter 3 with <code>httplib::SSLServer</code>.</p>
<p>A TLS server needs a server certificate and a private key, though. Let's get those ready first.</p>
<h2>Creating a Self-Signed Certificate</h2>
<p>For development and testing, a self-signed certificate works just fine. You can generate one quickly with an OpenSSL command.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">openssl</span><span style="color:#d3d0c8;"> req</span><span style="color:#f2777a;"> -x509 -noenc -keyout</span><span style="color:#d3d0c8;"> key.pem</span><span style="color:#f2777a;"> -out</span><span style="color:#d3d0c8;"> cert.pem</span><span style="color:#f2777a;"> -subj</span><span style="color:#d3d0c8;"> /CN=localhost
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">openssl req -x509 -noenc -keyout key.pem -out cert.pem -subj /CN=localhost
</span></pre>
</div></div>
<p>This creates two files:</p>
<ul>
<li><strong><code>cert.pem</code></strong> — Server certificate</li>
<li><strong><code>key.pem</code></strong> — Private key</li>
</ul>
<h2>A Minimal HTTPS Server</h2>
<p>Once you have your certificate, let's write the server.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::SSLServer </span><span style="color:#6699cc;">svr</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">key.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, HTTPS!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on https://localhost:8443</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8443</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::SSLServer svr(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;key.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, HTTPS!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on https://localhost:8443&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8443</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>Just pass the certificate and private key paths to the <code>httplib::SSLServer</code> constructor. The routing API is exactly the same as <code>httplib::Server</code> from Chapter 3.</p>
<p>Compile and start it up.</p>
<h2>Testing It Out</h2>
<p>With the server running, try accessing it with <code>curl</code>. Since we're using a self-signed certificate, add the <code>-k</code> option to skip certificate verification.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -k</span><span style="color:#d3d0c8;"> https://localhost:8443/
</span><span style="color:#747369;"># Hello, HTTPS!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -k https://localhost:8443/
</span><span style="font-style:italic;color:#969896;"># Hello, HTTPS!
</span></pre>
</div></div>
<p>If you open <code>https://localhost:8443</code> in a browser, you'll see a "This connection is not secure" warning. That's expected with a self-signed certificate. Just proceed past it.</p>
<h2>Connecting from a Client</h2>
<p>Let's connect using <code>httplib::Client</code> from the previous chapter. There are two ways to connect to a server with a self-signed certificate.</p>
<h3>Option 1: Disable Certificate Verification</h3>
<p>This is the quick and easy approach for development.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> cli.</span><span style="color:#6699cc;">enable_server_certificate_verification</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">false</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, HTTPS!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> cli.enable_server_certificate_verification(</span><span style="color:#0086b3;">false</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, HTTPS!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<h3>Option 2: Specify the Self-Signed Certificate as a CA Certificate</h3>
<p>This is the safer approach. You tell the client to trust <code>cert.pem</code> as a CA certificate.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> cli.</span><span style="color:#6699cc;">set_ca_cert_path</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, HTTPS!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> cli.set_ca_cert_path(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, HTTPS!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>This way, only connections to the server with that specific certificate are allowed, preventing impersonation. Use this approach whenever possible, even in test environments.</p>
<h2>Comparing Server and SSLServer</h2>
<p>The <code>httplib::Server</code> API you learned in Chapter 3 works exactly the same with <code>httplib::SSLServer</code>. The only difference is the constructor.</p>
<table><thead><tr><th></th><th><code>httplib::Server</code></th><th><code>httplib::SSLServer</code></th></tr></thead><tbody>
<tr><td>Constructor</td><td>No arguments</td><td>Certificate and private key paths</td></tr>
<tr><td>Protocol</td><td>HTTP</td><td>HTTPS</td></tr>
<tr><td>Port (convention)</td><td>8080</td><td>8443</td></tr>
<tr><td>Routing</td><td>Same</td><td>Same</td></tr>
</tbody></table>
<p>To switch an HTTP server to HTTPS, just change the constructor.</p>
<h2>Next Steps</h2>
<p>Your HTTPS server is up and running. You now have the basics of both HTTP/HTTPS clients and servers covered.</p>
<p>Next, let's look at the WebSocket support that was recently added to cpp-httplib.</p>
<p><strong>Next:</strong> <a href="../08-websocket">WebSocket</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-328
View File
@@ -1,328 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebSocket - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="active">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>WebSocket</h1>
<p>cpp-httplib supports WebSocket as well. Unlike HTTP request/response, WebSocket lets the server and client exchange messages in both directions. It's great for chat apps and real-time notifications.</p>
<p>Let's build an echo server and client right away.</p>
<h2>Echo Server</h2>
<p>Here's an echo server that sends back whatever message it receives.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg); </span><span style="color:#747369;">// Send back the received message as-is
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg); </span><span style="font-style:italic;color:#969896;">// Send back the received message as-is
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>You register a WebSocket handler with <code>svr.WebSocket()</code>. It works just like <code>svr.Get()</code> and <code>svr.Post()</code> from Chapter 3.</p>
<p>Inside the handler, <code>ws.read(msg)</code> waits for a message. When the connection closes, <code>read()</code> returns <code>false</code>, so the loop exits. <code>ws.send(msg)</code> sends a message back.</p>
<h2>Connecting from a Client</h2>
<p>Let's connect to the server using <code>httplib::ws::WebSocketClient</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::ws::WebSocketClient </span><span style="color:#6699cc;">client</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">ws://localhost:8080/ws</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(!client.</span><span style="color:#6699cc;">connect</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Connection failed</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Send a message
</span><span style="color:#d3d0c8;"> client.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, WebSocket!</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Receive a response from the server
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(client.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; msg &lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, WebSocket!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> client.</span><span style="color:#6699cc;">close</span><span style="color:#d3d0c8;">();
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::ws::WebSocketClient client(</span><span style="color:#183691;">&quot;ws://localhost:8080/ws&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">!</span><span style="color:#323232;">client.connect()) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Connection failed&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Send a message
</span><span style="color:#323232;"> client.send(</span><span style="color:#183691;">&quot;Hello, WebSocket!&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Receive a response from the server
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(client.read(msg)) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, WebSocket!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> client.close();
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>Pass a URL in <code>ws://host:port/path</code> format to the constructor. Call <code>connect()</code> to start the connection, then use <code>send()</code> and <code>read()</code> to exchange messages.</p>
<h2>Text and Binary</h2>
<p>WebSocket has two types of messages: text and binary. You can tell them apart by the return value of <code>read()</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> httplib::ws::ReadResult ret;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">((ret = ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg))) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(ret == httplib::ws::Binary) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg.</span><span style="color:#6699cc;">data</span><span style="color:#d3d0c8;">(), msg.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()); </span><span style="color:#747369;">// Send as binary
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg); </span><span style="color:#747369;">// Send as text
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> httplib::ws::ReadResult ret;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">((ret </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> ws.read(msg))) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(ret </span><span style="font-weight:bold;color:#a71d5d;">==</span><span style="color:#323232;"> httplib::ws::Binary) {
</span><span style="color:#323232;"> ws.send(msg.data(), msg.size()); </span><span style="font-style:italic;color:#969896;">// Send as binary
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> ws.send(msg); </span><span style="font-style:italic;color:#969896;">// Send as text
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<ul>
<li><code>ws.send(const std::string &amp;)</code> — sends as a text message</li>
<li><code>ws.send(const char *, size_t)</code> — sends as a binary message</li>
</ul>
<p>The client-side API is the same.</p>
<h2>Accessing Request Information</h2>
<p>You can read HTTP request information from the handshake through the first argument <code>req</code> in the handler. This is handy for checking authentication tokens.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;req, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> token = req.</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(token.</span><span style="color:#6699cc;">empty</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">close</span><span style="color:#d3d0c8;">(httplib::ws::CloseStatus::PolicyViolation, &quot;</span><span style="color:#99cc99;">unauthorized</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg);
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">req, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> token </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_header_value(</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(token.empty()) {
</span><span style="color:#323232;"> ws.close(httplib::ws::CloseStatus::PolicyViolation, </span><span style="color:#183691;">&quot;unauthorized&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg);
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Using WSS</h2>
<p>WebSocket over HTTPS (WSS) is also supported. On the server side, just register a WebSocket handler on <code>httplib::SSLServer</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::SSLServer </span><span style="color:#6699cc;">svr</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">key.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg);
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8443</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::SSLServer </span><span style="font-weight:bold;color:#795da3;">svr</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;key.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg);
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8443</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>On the client side, use the <code>wss://</code> scheme.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::ws::WebSocketClient </span><span style="color:#6699cc;">client</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">wss://localhost:8443/ws</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::ws::WebSocketClient </span><span style="font-weight:bold;color:#795da3;">client</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;wss://localhost:8443/ws&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>Next Steps</h2>
<p>Now you know the basics of WebSocket. This wraps up the Tour.</p>
<p>The next page gives you a summary of features we didn't cover in the Tour.</p>
<p><strong>Next:</strong> <a href="../09-whats-next">What's Next</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-460
View File
@@ -1,460 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>What&#x27;s Next - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="active">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>What&#x27;s Next</h1>
<p>Great job finishing the Tour! You now have a solid grasp of the cpp-httplib basics. But there's a lot more to explore. Here's a quick overview of features we didn't cover in the Tour, organized by category.</p>
<h2>Streaming API</h2>
<p>When you're working with LLM streaming responses or downloading large files, you don't want to load the entire response into memory. Use <code>stream::Get()</code> to process data chunk by chunk.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:11434</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> result = </span><span style="color:#6699cc;">httplib::stream::Get</span><span style="color:#d3d0c8;">(cli, &quot;</span><span style="color:#99cc99;">/api/generate</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(result) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(result.</span><span style="color:#6699cc;">next</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> std::cout.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(result.</span><span style="color:#6699cc;">data</span><span style="color:#d3d0c8;">(), result.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">());
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:11434&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">httplib::stream::Get(cli, </span><span style="color:#183691;">&quot;/api/generate&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(result) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(result.next()) {
</span><span style="color:#323232;"> std::cout.write(result.data(), result.size());
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>You can also pass a <code>content_receiver</code> callback to <code>Get()</code>. This approach works with Keep-Alive.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/stream</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const char </span><span style="color:#d3d0c8;">*data, size_t len) {
</span><span style="color:#d3d0c8;"> std::cout.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(data, len);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">cli.Get(</span><span style="color:#183691;">&quot;/stream&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const char *</span><span style="color:#323232;">data, </span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> len) {
</span><span style="color:#323232;"> std::cout.write(data, len);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">;
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>On the server side, you have <code>set_content_provider()</code> and <code>set_chunked_content_provider()</code>. Use the former when you know the size, and the latter when you don't.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// With known size (sets Content-Length)
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/file</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> size = </span><span style="color:#6699cc;">get_file_size</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">large.bin</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content_provider</span><span style="color:#d3d0c8;">(size, &quot;</span><span style="color:#99cc99;">application/octet-stream</span><span style="color:#d3d0c8;">&quot;,
</span><span style="color:#d3d0c8;"> [](size_t offset, size_t length, httplib::DataSink &amp;sink) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Send &#39;length&#39; bytes starting from &#39;offset&#39;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// Unknown size (Chunked Transfer Encoding)
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/stream</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_chunked_content_provider</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;,
</span><span style="color:#d3d0c8;"> [](size_t offset, httplib::DataSink &amp;sink) {
</span><span style="color:#d3d0c8;"> sink.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">chunk</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">6</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">; </span><span style="color:#747369;">// Return false to finish
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// With known size (sets Content-Length)
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/file&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> size </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">get_file_size(</span><span style="color:#183691;">&quot;large.bin&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content_provider(size, </span><span style="color:#183691;">&quot;application/octet-stream&quot;</span><span style="color:#323232;">,
</span><span style="color:#323232;"> [](</span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> offset, </span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> length, httplib::DataSink </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">sink) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Send &#39;length&#39; bytes starting from &#39;offset&#39;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">;
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// Unknown size (Chunked Transfer Encoding)
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/stream&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_chunked_content_provider(</span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">,
</span><span style="color:#323232;"> [](</span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> offset, httplib::DataSink </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">sink) {
</span><span style="color:#323232;"> sink.write(</span><span style="color:#183691;">&quot;chunk</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">6</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">; </span><span style="font-style:italic;color:#969896;">// Return false to finish
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>For uploading large files, <code>make_file_provider()</code> comes in handy. It streams the file instead of loading it all into memory.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, {}, {
</span><span style="color:#d3d0c8;"> </span><span style="color:#6699cc;">httplib::make_file_provider</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">/path/to/large-file.zip</span><span style="color:#d3d0c8;">&quot;)
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, {}, {
</span><span style="color:#323232;"> httplib::make_file_provider(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;/path/to/large-file.zip&quot;</span><span style="color:#323232;">)
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Server-Sent Events (SSE)</h2>
<p>We provide an SSE client as well. It supports automatic reconnection and resuming via <code>Last-Event-ID</code>.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">httplib::sse::SSEClient </span><span style="color:#6699cc;">sse</span><span style="color:#d3d0c8;">(</span><span style="color:#f2777a;">cli</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">/events</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">on_message</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::sse::SSEMessage &amp;msg) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; msg.</span><span style="color:#f2777a;">event </span><span style="color:#d3d0c8;">&lt;&lt; &quot;</span><span style="color:#99cc99;">: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; msg.</span><span style="color:#f2777a;">data </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">start</span><span style="color:#d3d0c8;">(); </span><span style="color:#747369;">// Blocking, with auto-reconnection
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">httplib::sse::SSEClient </span><span style="font-weight:bold;color:#795da3;">sse</span><span style="color:#323232;">(cli, </span><span style="color:#183691;">&quot;/events&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">sse.on_message([](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::sse::SSEMessage </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">msg) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg.event </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg.data </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">sse.start(); </span><span style="font-style:italic;color:#969896;">// Blocking, with auto-reconnection
</span></pre>
</div></div>
<p>You can also set separate handlers for each event type.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">on_event</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">update</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::sse::SSEMessage &amp;msg) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Only handles &quot;update&quot; events
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">sse.on_event(</span><span style="color:#183691;">&quot;update&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::sse::SSEMessage </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">msg) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Only handles &quot;update&quot; events
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Authentication</h2>
<p>The client has helpers for Basic auth, Bearer Token auth, and Digest auth.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://api.example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_basic_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">password</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_bearer_token_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">my-token</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://api.example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_basic_auth(</span><span style="color:#183691;">&quot;user&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;password&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_bearer_token_auth(</span><span style="color:#183691;">&quot;my-token&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>Compression</h2>
<p>We support compression and decompression with gzip, Brotli, and Zstandard. Define the corresponding macro when you compile.</p>
<table><thead><tr><th>Method</th><th>Macro</th></tr></thead><tbody>
<tr><td>gzip</td><td><code>CPPHTTPLIB_ZLIB_SUPPORT</code></td></tr>
<tr><td>Brotli</td><td><code>CPPHTTPLIB_BROTLI_SUPPORT</code></td></tr>
<tr><td>Zstandard</td><td><code>CPPHTTPLIB_ZSTD_SUPPORT</code></td></tr>
</tbody></table>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_compress</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// Compress request body
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_decompress</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// Decompress response body
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_compress(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// Compress request body
</span><span style="color:#323232;">cli.set_decompress(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// Decompress response body
</span></pre>
</div></div>
<h2>Proxy</h2>
<p>You can connect through an HTTP proxy.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_proxy</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">proxy.example.com</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_proxy_basic_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">password</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_proxy(</span><span style="color:#183691;">&quot;proxy.example.com&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_proxy_basic_auth(</span><span style="color:#183691;">&quot;user&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;password&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>Timeouts</h2>
<p>You can set connection, read, and write timeouts individually.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_connection_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">5</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 5 seconds
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_read_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">10</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 10 seconds
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_write_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">10</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 10 seconds
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_connection_timeout(</span><span style="color:#0086b3;">5</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 5 seconds
</span><span style="color:#323232;">cli.set_read_timeout(</span><span style="color:#0086b3;">10</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 10 seconds
</span><span style="color:#323232;">cli.set_write_timeout(</span><span style="color:#0086b3;">10</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 10 seconds
</span></pre>
</div></div>
<h2>Keep-Alive</h2>
<p>If you're making multiple requests to the same server, enable Keep-Alive. It reuses the TCP connection, which is much more efficient.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_keep_alive</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_keep_alive(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>Server Middleware</h2>
<p>You can hook into request processing before and after handlers run.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_pre_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Runs before every request
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;"> httplib::Server::HandlerResponse::Unhandled; </span><span style="color:#747369;">// Continue to normal routing
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_post_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Runs after the response is sent
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_header</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">X-Server</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">cpp-httplib</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_pre_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Runs before every request
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> httplib::Server::HandlerResponse::Unhandled; </span><span style="font-style:italic;color:#969896;">// Continue to normal routing
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.set_post_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Runs after the response is sent
</span><span style="color:#323232;"> res.set_header(</span><span style="color:#183691;">&quot;X-Server&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;cpp-httplib&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>Use <code>req.user_data</code> to pass data from middleware to handlers. This is useful for sharing things like decoded auth tokens.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_pre_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> req.</span><span style="color:#f2777a;">user_data</span><span style="color:#d3d0c8;">[&quot;</span><span style="color:#99cc99;">auth_user</span><span style="color:#d3d0c8;">&quot;] = </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">alice</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;"> httplib::Server::HandlerResponse::Unhandled;
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/me</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> user = std::</span><span style="color:#6699cc;">any_cast</span><span style="color:#d3d0c8;">&lt;std::string&gt;(req.</span><span style="color:#f2777a;">user_data</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">auth_user</span><span style="color:#d3d0c8;">&quot;));
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, </span><span style="color:#d3d0c8;">&quot; + user, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_pre_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> req.user_data[</span><span style="color:#183691;">&quot;auth_user&quot;</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">std::string(</span><span style="color:#183691;">&quot;alice&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> httplib::Server::HandlerResponse::Unhandled;
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/me&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> user </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">std::any_cast&lt;std::string&gt;(req.user_data.at(</span><span style="color:#183691;">&quot;auth_user&quot;</span><span style="color:#323232;">));
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> user, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>You can also customize error and exception handlers.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_error_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Custom Error Page</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/html</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_exception_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res, std::exception_ptr ep) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">= </span><span style="color:#f99157;">500</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Internal Server Error</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_error_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Custom Error Page&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/html&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.set_exception_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res, std::exception_ptr ep) {
</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">500</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Internal Server Error&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Logging</h2>
<p>You can set a logger on both the server and the client.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_logger</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; req.</span><span style="color:#f2777a;">method </span><span style="color:#d3d0c8;">&lt;&lt; &quot; &quot; &lt;&lt; req.</span><span style="color:#f2777a;">path </span><span style="color:#d3d0c8;">&lt;&lt; &quot; &quot; &lt;&lt; res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_logger([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> req.method </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot; &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> req.path </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot; &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Unix Domain Socket</h2>
<p>In addition to TCP, we support Unix Domain Sockets. You can use them for inter-process communication on the same machine.</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// Server
</span><span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_address_family</span><span style="color:#d3d0c8;">(AF_UNIX);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/tmp/httplib.sock</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// Server
</span><span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">svr.set_address_family(AF_UNIX);
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;/tmp/httplib.sock&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// Client
</span><span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_address_family</span><span style="color:#d3d0c8;">(AF_UNIX);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_hostname_addr_map</span><span style="color:#d3d0c8;">({{&quot;</span><span style="color:#99cc99;">localhost</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">/tmp/httplib.sock</span><span style="color:#d3d0c8;">&quot;}});
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// Client
</span><span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_address_family(AF_UNIX);
</span><span style="color:#323232;">cli.set_hostname_addr_map({{</span><span style="color:#183691;">&quot;localhost&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;/tmp/httplib.sock&quot;</span><span style="color:#323232;">}});
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>Learn More</h2>
<p>Want to dig deeper? Check out these resources.</p>
<ul>
<li>Cookbook — A collection of recipes for common use cases</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README.md">README</a> — Full API reference</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-sse.md">README-sse</a> — How to use Server-Sent Events</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-stream.md">README-stream</a> — How to use the Streaming API</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-websocket.md">README-websocket</a> — How to use the WebSocket server</li>
</ul>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-141
View File
@@ -1,141 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A Tour of cpp-httplib - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/en/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/en/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/en/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
EN
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;en&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>A Tour of cpp-httplib</h1>
<p>This is a step-by-step tutorial that walks you through the basics of cpp-httplib. Each chapter builds on the previous one, so please read them in order starting from Chapter 1.</p>
<ol>
<li><a href="01-getting-started">Getting Started</a> — Get httplib.h and build a Hello World server</li>
<li><a href="02-basic-client">Basic Client</a> — Send GET/POST requests and use path parameters</li>
<li><a href="03-basic-server">Basic Server</a> — Routing, path parameters, and building responses</li>
<li><a href="04-static-file-server">Static File Server</a> — Serve static files</li>
<li><a href="05-tls-setup">TLS Setup</a> — Set up OpenSSL / mbedTLS</li>
<li><a href="06-https-client">HTTPS Client</a> — Make requests to HTTPS sites</li>
<li><a href="07-https-server">HTTPS Server</a> — Build an HTTPS server</li>
<li><a href="08-websocket">WebSocket</a> — Learn the basics of WebSocket communication</li>
<li><a href="09-whats-next">What's Next</a> — Explore more features</li>
</ol>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-4
View File
@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-17
View File
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
(function() {
var lang = localStorage.getItem('preferred-lang') || 'en';
window.location.replace('/cpp-httplib/' + lang + '/');
})();
</script>
<meta http-equiv="refresh" content="0;url=/cpp-httplib/en/">
<title>Redirecting...</title>
</head>
<body>
<p>Redirecting to <a href="/cpp-httplib/en/">/cpp-httplib/en/</a>...</p>
</body>
</html>
-109
View File
@@ -1,109 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cookbook - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;cookbook&#x2F;" class="nav-section-title active">Cookbook</a>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Cookbook</h1>
<p>This section is under construction.</p>
<p>Check back soon for a collection of recipes organized by topic.</p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-108
View File
@@ -1,108 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>cpp-httplib - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
</div>
</header>
<div class="layout no-sidebar">
<main class="content portal">
<article>
<h1>cpp-httplib</h1>
<p><a href="https://github.com/yhirose/cpp-httplib">cpp-httplib</a>は、C++用のHTTP/HTTPSライブラリです。<a href="https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h"><code>httplib.h</code></a> というヘッダーファイルを1枚コピーするだけで使えます。</p>
<p>C++でちょっとしたHTTPサーバーやクライアントが必要になったとき、すぐに動くものが欲しいですよね。cpp-httplibはまさにそのために作られました。サーバーもクライアントも、数行のコードで書き始められます。</p>
<p>APIはラムダ式をベースにした直感的な設計で、C++11以降のコンパイラーがあればどこでも動きます。Windows、macOS、Linux — お使いの環境をそのまま使えます。</p>
<p>HTTPSも使えます。OpenSSLやmbedTLSをリンクするだけで、サーバー・クライアントの両方がTLSに対応します。Content-Encodinggzip, brotli等)、ファイルアップロードなど、実際の開発で必要になる機能もひと通り揃っています。WebSocketもサポートしています。</p>
<p>内部的にはブロッキングI/Oとスレッドプールを使っています。大量の同時接続を捌くような用途には向きませんが、APIサーバーやツールの組み込みHTTP、テスト用のモックサーバーなど、多くのユースケースで十分な性能を発揮します。</p>
<p>「今日の課題を、今日中に解決する」— cpp-httplibが目指しているのは、そういうシンプルさです。</p>
<h2>ドキュメント</h2>
<ul>
<li><a href="tour/">A Tour of cpp-httplib</a> — 基本を順を追って学べるチュートリアル。初めての方はここから</li>
<li><a href="cookbook/">Cookbook</a> — 目的別のレシピ集。必要なトピックから読めます</li>
</ul>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-234
View File
@@ -1,234 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Getting Started - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="active">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Getting Started</h1>
<p>cpp-httplibを始めるのに必要なのは、<code>httplib.h</code>とC++コンパイラーだけです。ファイルをダウンロードして、Hello Worldサーバーを動かすところまでやってみましょう。</p>
<h2>httplib.h の入手</h2>
<p>GitHubから直接ダウンロードできます。常に最新版を使ってください。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -LO</span><span style="color:#d3d0c8;"> https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -LO https://github.com/yhirose/cpp-httplib/raw/refs/tags/latest/httplib.h
</span></pre>
</div></div>
<p>ダウンロードした <code>httplib.h</code> をプロジェクトのディレクトリに置けば、準備完了です。</p>
<h2>コンパイラーの準備</h2>
<table><thead><tr><th>OS</th><th>開発環境</th><th>セットアップ</th></tr></thead><tbody>
<tr><td>macOS</td><td>Apple Clang</td><td>Xcode Command Line Tools (<code>xcode-select --install</code>)</td></tr>
<tr><td>Ubuntu</td><td>clang++ または g++</td><td><code>apt install clang</code> または <code>apt install g++</code></td></tr>
<tr><td>Windows</td><td>MSVC</td><td>Visual Studio 2022 以降(C++ コンポーネントを含めてインストール)</td></tr>
</tbody></table>
<h2>Hello World サーバー</h2>
<p>次のコードを <code>server.cpp</code> として保存しましょう。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request&amp;, httplib::Response&amp; res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, World!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request</span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::Response</span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;"> res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, World!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>たった数行で、HTTPリクエストに応答するサーバーが書けます。</p>
<h2>コンパイルと実行</h2>
<p>このチュートリアルのサンプルコードは、コードを簡潔に書けるC++17で書いています。cpp-httplib自体はC++11でもコンパイルできます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Linux
</span><span style="color:#747369;"># `-pthread`: cpp-httplibは内部でスレッドを使用
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -pthread -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows (Developer Command Prompt)
</span><span style="color:#747369;"># `/EHsc`: C++例外処理を有効化
</span><span style="color:#6699cc;">cl</span><span style="color:#d3d0c8;"> /EHsc /std:c++17 server.cpp
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Linux
</span><span style="font-style:italic;color:#969896;"># `-pthread`: cpp-httplibは内部でスレッドを使用
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -pthread -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows (Developer Command Prompt)
</span><span style="font-style:italic;color:#969896;"># `/EHsc`: C++例外処理を有効化
</span><span style="color:#323232;">cl /EHsc /std:c++17 server.cpp
</span></pre>
</div></div>
<p>コンパイルできたら実行します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS / Linux
</span><span style="color:#6699cc;">./server
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows
</span><span style="color:#6699cc;">server.exe
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS / Linux
</span><span style="color:#323232;">./server
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows
</span><span style="color:#323232;">server.exe
</span></pre>
</div></div>
<p>ブラウザで <code>http://localhost:8080</code> を開いてください。"Hello, World!" と表示されれば成功です。</p>
<p><code>curl</code> でも確認できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/
</span><span style="color:#747369;"># Hello, World!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/
</span><span style="font-style:italic;color:#969896;"># Hello, World!
</span></pre>
</div></div>
<p>サーバーを停止するには、ターミナルで <code>Ctrl+C</code> を押します。</p>
<h2>次のステップ</h2>
<p>サーバーの基本がわかりましたね。次は、クライアント側を見てみましょう。cpp-httplibはHTTPクライアント機能も備えています。</p>
<p><strong>次:</strong> <a href="../02-basic-client">Basic Client</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-527
View File
@@ -1,527 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Client - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="active">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Basic Client</h1>
<p>cpp-httplibはサーバーだけでなく、HTTPクライアント機能も備えています。<code>httplib::Client</code> を使って、GETやPOSTリクエストを送ってみましょう。</p>
<h2>テスト用サーバーの準備</h2>
<p>クライアントの動作を確認するために、リクエストを受け付けるサーバーを用意します。次のコードを保存し、前章と同じ手順でコンパイル・実行してください。サーバーの詳しい解説は次章で行います。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">];
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">];
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<h2>GETリクエスト</h2>
<p>サーバーが起動したら、別のターミナルを開いて試してみましょう。まず、最もシンプルなGETリクエストです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>httplib::Client</code> のコンストラクターにサーバーのアドレスを渡し、<code>Get()</code> でリクエストを送ります。戻り値の <code>res</code> からステータスコードやボディを取得できます。</p>
<p>対応する <code>curl</code> コマンドはこうなります。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/hi
</span><span style="color:#747369;"># Hello!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/hi
</span><span style="font-style:italic;color:#969896;"># Hello!
</span></pre>
</div></div>
<h2>レスポンスの確認</h2>
<p>レスポンスには、ステータスコードとボディ以外にもヘッダー情報が含まれています。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// ステータスコード
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// ボディ
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello!
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// ヘッダー
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Content-Type</span><span style="color:#d3d0c8;">&quot;) &lt;&lt; std::endl; </span><span style="color:#747369;">// text/plain
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// ステータスコード
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// ボディ
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello!
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// ヘッダー
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;get_header_value(</span><span style="color:#183691;">&quot;Content-Type&quot;</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// text/plain
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>res-&gt;body</code><code>std::string</code> なので、JSON レスポンスをパースしたい場合は <a href="https://github.com/nlohmann/json">nlohmann/json</a> などの JSON ライブラリにそのまま渡せます。</p>
<h2>クエリパラメーター</h2>
<p>GETリクエストにクエリパラメーターを付けるには、URLに直接書くか、<code>httplib::Params</code> を使います。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, httplib::Params{{&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">cpp-httplib</span><span style="color:#d3d0c8;">&quot;}});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Query: cpp-httplib
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, httplib::Params{{</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;cpp-httplib&quot;</span><span style="color:#323232;">}});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Query: cpp-httplib
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>httplib::Params</code> を使うと、特殊文字のURLエンコードを自動で行ってくれます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">http://localhost:8080/search?q=cpp-httplib</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#747369;"># Query: cpp-httplib
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl </span><span style="color:#183691;">&quot;http://localhost:8080/search?q=cpp-httplib&quot;
</span><span style="font-style:italic;color:#969896;"># Query: cpp-httplib
</span></pre>
</div></div>
<h2>パスパラメーター</h2>
<p>URLのパスに値を直接埋め込む場合も、クライアント側は特別なAPIは不要です。パスをそのまま <code>Get()</code> に渡すだけです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/42</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// User ID: 42
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/users/42&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// User ID: 42
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/users/42
</span><span style="color:#747369;"># User ID: 42
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/users/42
</span><span style="font-style:italic;color:#969896;"># User ID: 42
</span></pre>
</div></div>
<p>テスト用サーバーには、正規表現でIDを数字のみに絞った <code>/files/(\d+)</code> もあります。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/files/42</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// File ID: 42
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/files/42&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// File ID: 42
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080/files/42
</span><span style="color:#747369;"># File ID: 42
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080/files/42
</span><span style="font-style:italic;color:#969896;"># File ID: 42
</span></pre>
</div></div>
<p><code>/files/abc</code> のように数字以外を渡すと404が返ります。仕組みは次章で解説します。</p>
<h2>リクエストヘッダー</h2>
<p>カスタムHTTPヘッダーを付けるには、<code>httplib::Headers</code> を渡します。<code>Get()</code><code>Post()</code> のどちらでも使えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, httplib::Headers{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Bearer my-token</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, httplib::Headers{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Bearer my-token&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -H </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Authorization: Bearer my-token</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/hi
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -H </span><span style="color:#183691;">&quot;Authorization: Bearer my-token&quot;</span><span style="color:#323232;"> http://localhost:8080/hi
</span></pre>
</div></div>
<h2>POSTリクエスト</h2>
<p>テキストデータをPOSTしてみましょう。<code>Post()</code> の第2引数にボディ、第3引数にContent-Typeを指定します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Hello, Server!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, Server!
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Hello, Server!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, Server!
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>テスト用サーバーの <code>/post</code> はボディをそのまま返すので、送った文字列がそのまま返ってきます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -X</span><span style="color:#d3d0c8;"> POST</span><span style="color:#f2777a;"> -H </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Content-Type: text/plain</span><span style="color:#d3d0c8;">&quot;</span><span style="color:#f2777a;"> -d </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">Hello, Server!</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/post
</span><span style="color:#747369;"># Hello, Server!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -X POST -H </span><span style="color:#183691;">&quot;Content-Type: text/plain&quot;</span><span style="color:#323232;"> -d </span><span style="color:#183691;">&quot;Hello, Server!&quot;</span><span style="color:#323232;"> http://localhost:8080/post
</span><span style="font-style:italic;color:#969896;"># Hello, Server!
</span></pre>
</div></div>
<h2>フォームデータの送信</h2>
<p>HTMLフォームのように、キーと値のペアを送ることもできます。<code>httplib::Params</code> を使います。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, httplib::Params{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">name</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Alice</span><span style="color:#d3d0c8;">&quot;},
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">age</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">30</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// age = 30
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// name = Alice
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, httplib::Params{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;name&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Alice&quot;</span><span style="color:#323232;">},
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;age&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;30&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// age = 30
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// name = Alice
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>これは <code>application/x-www-form-urlencoded</code> 形式で送信されます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -X</span><span style="color:#d3d0c8;"> POST</span><span style="color:#f2777a;"> -d </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">name=Alice&amp;age=30</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/submit
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -X POST -d </span><span style="color:#183691;">&quot;name=Alice&amp;age=30&quot;</span><span style="color:#323232;"> http://localhost:8080/submit
</span></pre>
</div></div>
<h2>ファイルのPOST</h2>
<p>ファイルをアップロードするには、<code>httplib::UploadFormDataItems</code> を使ってマルチパートフォームデータとして送信します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, httplib::UploadFormDataItems{
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">Hello, File!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">hello.txt</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// hello.txt (12 bytes)
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, httplib::UploadFormDataItems{
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;Hello, File!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;hello.txt&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// hello.txt (12 bytes)
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>UploadFormDataItems</code> の各要素は <code>{name, content, filename, content_type}</code> の4つのフィールドで構成されます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -F </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">file=Hello, File!;filename=hello.txt;type=text/plain</span><span style="color:#d3d0c8;">&quot; http://localhost:8080/upload
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -F </span><span style="color:#183691;">&quot;file=Hello, File!;filename=hello.txt;type=text/plain&quot;</span><span style="color:#323232;"> http://localhost:8080/upload
</span></pre>
</div></div>
<h2>エラーハンドリング</h2>
<p>ネットワーク通信では、サーバーに接続できない場合があります。<code>res</code> が有効かどうかを必ず確認しましょう。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:9999</span><span style="color:#d3d0c8;">&quot;); </span><span style="color:#747369;">// 存在しないポート
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(!res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// 接続エラー
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// Error: Connection
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">}
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// ここに到達すればレスポンスを受信できている
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">!= </span><span style="color:#f99157;">200</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">HTTP Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">}
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:9999&quot;</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 存在しないポート
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">!</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// 接続エラー
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// Error: Connection
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// ここに到達すればレスポンスを受信できている
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">!= </span><span style="color:#0086b3;">200</span><span style="color:#323232;">) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;HTTP Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="color:#323232;">std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span></pre>
</div></div>
<p>エラーには2つのレベルがあります。</p>
<ul>
<li><strong>接続エラー</strong>: サーバーに到達できなかった場合。<code>res</code> が偽になり、<code>res.error()</code> でエラーの種類を取得できます</li>
<li><strong>HTTPエラー</strong>: サーバーからエラーステータス(404、500など)が返ってきた場合。<code>res</code> は真ですが、<code>res-&gt;status</code> を確認する必要があります</li>
</ul>
<h2>次のステップ</h2>
<p>クライアントからリクエストを送る方法がわかりました。次は、サーバー側をもっと詳しく見てみましょう。ルーティングやパスパラメータなど、サーバーの機能を掘り下げます。</p>
<p><strong>次:</strong> <a href="../03-basic-server">Basic Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-482
View File
@@ -1,482 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="active">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Basic Server</h1>
<p>前章ではクライアントからリクエストを送りました。そのとき、テスト用サーバーを用意しましたね。この章では、あのサーバーの仕組みをひとつずつ紐解いていきます。</p>
<h2>サーバーの起動</h2>
<p>ルーティングを登録したら、最後に <code>svr.listen()</code> を呼んでサーバーを起動します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>第1引数はホスト、第2引数はポート番号です。<code>"0.0.0.0"</code> を指定すると、すべてのネットワークインターフェースでリクエストを受け付けます。自分のマシンからのアクセスだけに限定したいときは <code>"127.0.0.1"</code> を使います。</p>
<p><code>listen()</code> はブロッキング呼び出しです。サーバーが停止するまで、この行から先には進みません。ターミナルで <code>Ctrl+C</code> を押すか、別スレッドから <code>svr.stop()</code> を呼ぶまでサーバーは動き続けます。</p>
<h2>ルーティング</h2>
<p>サーバーの核になるのは「ルーティング」です。どのURLに、どのHTTPメソッドでアクセスされたら、何をするか。それを登録する仕組みです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;req, httplib::Response &amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">req, httplib::Response </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>svr.Get()</code> は、GETリクエストに対するハンドラーを登録します。第1引数がパス、第2引数がハンドラー関数です。<code>/hi</code> にGETリクエストが来たら、このラムダが呼ばれます。</p>
<p>HTTPメソッドごとにメソッドが用意されています。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// GET
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// POST
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Put</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// PUT
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Delete</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/path</span><span style="color:#d3d0c8;">&quot;, handler); </span><span style="color:#747369;">// DELETE
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// GET
</span><span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// POST
</span><span style="color:#323232;">svr.Put(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// PUT
</span><span style="color:#323232;">svr.Delete(</span><span style="color:#183691;">&quot;/path&quot;</span><span style="color:#323232;">, handler); </span><span style="font-style:italic;color:#969896;">// DELETE
</span></pre>
</div></div>
<p>ハンドラーのシグネチャは <code>(const httplib::Request &amp;req, httplib::Response &amp;res)</code> です。<code>auto</code> を使って短く書くこともできます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>パスが一致したときだけハンドラーが呼ばれます。登録されていないパスにアクセスすると、自動的に404が返ります。</p>
<h2>リクエストオブジェクト</h2>
<p>ハンドラーの第1引数 <code>req</code> から、クライアントが送ってきた情報を読み取れます。</p>
<h3>ボディ</h3>
<p><code>req.body</code> でリクエストボディを取得できます。型は <code>std::string</code> です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// クライアントが送ったボディをそのまま返す
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// クライアントが送ったボディをそのまま返す
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>ヘッダー</h3>
<p><code>req.get_header_value()</code> でリクエストヘッダーの値を取得できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/check</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> auth = req.</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Auth: </span><span style="color:#d3d0c8;">&quot; + auth, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/check&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> auth </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_header_value(</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Auth: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> auth, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>クエリパラメーターとフォームデータ</h3>
<p><code>req.get_param_value()</code> でパラメーターを取得できます。GETのクエリパラメーターと、POSTのフォームデータの両方に使えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>/search?q=cpp-httplib</code> にアクセスすると、<code>q</code> の値は <code>"cpp-httplib"</code> になります。</p>
<p>すべてのパラメーターをループで処理したいときは、<code>req.params</code> を使います。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>ファイルアップロード</h3>
<p>マルチパートフォームでアップロードされたファイルは、<code>req.form.get_file()</code> で取得します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>f.filename</code> でファイル名、<code>f.content</code> でファイルの中身にアクセスできます。</p>
<h2>パスパラメーター</h2>
<p>URLの一部を変数として受け取りたいことがあります。たとえば <code>/users/42</code><code>42</code> を取得したい場合です。<code>:param</code> 記法を使うと、URLの一部をキャプチャできます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>/users/42</code> にアクセスすると、<code>req.path_params.at("id")</code><code>"42"</code> を返します。<code>/users/100</code> なら <code>"100"</code> です。</p>
<p>複数のパスパラメーターも使えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:user_id/posts/:post_id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> user_id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user_id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> post_id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">post_id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User: </span><span style="color:#d3d0c8;">&quot; + user_id + &quot;</span><span style="color:#99cc99;">, Post: </span><span style="color:#d3d0c8;">&quot; + post_id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:user_id/posts/:post_id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> user_id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;user_id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> post_id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;post_id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> user_id </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;, Post: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> post_id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>正規表現パターン</h3>
<p><code>:param</code> の代わりに正規表現をパスに書くこともできます。キャプチャグループの値は <code>req.matches</code> で取得します。型は <code>std::smatch</code> です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// 数字のみのIDを受け付ける
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">]; </span><span style="color:#747369;">// 最初のキャプチャグループ
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// 数字のみのIDを受け付ける
</span><span style="color:#323232;">svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">]; </span><span style="font-style:italic;color:#969896;">// 最初のキャプチャグループ
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>/files/42</code> にはマッチしますが、<code>/files/abc</code> にはマッチしません。入力値を絞り込みたいときに便利です。</p>
<h2>レスポンスの組み立て</h2>
<p>ハンドラーの第2引数 <code>res</code> を使って、クライアントに返すレスポンスを組み立てます。</p>
<h3>ボディとContent-Type</h3>
<p><code>res.set_content()</code> でボディとContent-Typeを設定します。これだけでステータスコード200のレスポンスが返ります。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>ステータスコード</h3>
<p>ステータスコードを変えたいときは、<code>res.status</code> に代入します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/not-found</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">= </span><span style="color:#f99157;">404</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Not found</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/not-found&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">404</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Not found&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h3>レスポンスヘッダー</h3>
<p><code>res.set_header()</code> でレスポンスヘッダーを追加できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/with-header</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_header</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">X-Custom</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">my-value</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/with-header&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_header(</span><span style="color:#183691;">&quot;X-Custom&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;my-value&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>前章のサーバーを読み解く</h2>
<p>ここまでの知識を使って、前章で用意したテスト用サーバーを改めて見てみましょう。</p>
<h3>GET /hi</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/hi</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/hi&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>最もシンプルなハンドラーです。リクエストの情報は使わないので、<code>req</code> の変数名を省略しています。<code>"Hello!"</code> というテキストをそのまま返します。</p>
<h3>GET /search</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/search</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> q = req.</span><span style="color:#6699cc;">get_param_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">q</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Query: </span><span style="color:#d3d0c8;">&quot; + q, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/search&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> q </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_param_value(</span><span style="color:#183691;">&quot;q&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Query: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> q, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>req.get_param_value("q")</code> でクエリパラメーター <code>q</code> の値を取り出します。<code>/search?q=cpp-httplib</code> なら、レスポンスは <code>"Query: cpp-httplib"</code> になります。</p>
<h3>POST /post</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/post</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(req.</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/post&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(req.body, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>クライアントが送ったリクエストボディを、そのままレスポンスとして返すエコーサーバーです。<code>req.body</code> にボディが丸ごと入っています。</p>
<h3>POST /submit</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/submit</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::string result;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">for </span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;[key, val] : req.</span><span style="color:#f2777a;">params</span><span style="color:#d3d0c8;">) {
</span><span style="color:#d3d0c8;"> result += key + &quot;</span><span style="color:#99cc99;"> = </span><span style="color:#d3d0c8;">&quot; + val + &quot;</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(result, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/submit&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::string result;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">[key, val] </span><span style="font-weight:bold;color:#a71d5d;">:</span><span style="color:#323232;"> req.params) {
</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span style="color:#323232;"> key </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; = &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> val </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot;</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> res.set_content(result, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>フォームデータとして送られたキーと値のペアを、<code>req.params</code> でループ処理しています。構造化束縛 <code>auto &amp;[key, val]</code> を使って、各ペアを取り出しています。</p>
<h3>POST /upload</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> f = req.</span><span style="color:#f2777a;">form</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">get_file</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> content = f.</span><span style="color:#f2777a;">filename </span><span style="color:#d3d0c8;">+ &quot;</span><span style="color:#99cc99;"> (</span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::to_string</span><span style="color:#d3d0c8;">(f.</span><span style="color:#f2777a;">content</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()) + &quot;</span><span style="color:#99cc99;"> bytes)</span><span style="color:#d3d0c8;">&quot;;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(content, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.form.get_file(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> content </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> f.filename </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; (&quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::to_string(f.content.size()) </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#183691;">&quot; bytes)&quot;</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(content, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>マルチパートフォームで送られたファイルを受け取ります。<code>req.form.get_file("file")</code><code>"file"</code> という名前のフィールドを取得し、<code>f.filename</code><code>f.content.size()</code> でファイル名とサイズを返しています。</p>
<h3>GET /users/:id</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/users/:id</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">path_params</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">id</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">User ID: </span><span style="color:#d3d0c8;">&quot; + id, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/users/:id&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.path_params.at(</span><span style="color:#183691;">&quot;id&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;User ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> id, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>:id</code> の部分がパスパラメーターです。<code>req.path_params.at("id")</code> で値を取り出しています。<code>/users/42</code> なら <code>"42"</code><code>/users/alice</code> なら <code>"alice"</code> が得られます。</p>
<h3>GET /files/(\d+)</h3>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">/files/(\d+)</span><span style="color:#d3d0c8;">)&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> id = req.</span><span style="color:#f2777a;">matches</span><span style="color:#d3d0c8;">[</span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">];
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">File ID: </span><span style="color:#d3d0c8;">&quot; + </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(id), &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.Get(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;(/files/(\d+))&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> id </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.matches[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">];
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;File ID: &quot; </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#323232;">std::string(id), </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>正規表現 <code>(\d+)</code> で数字だけのIDにマッチします。<code>/files/42</code> にはマッチしますが、<code>/files/abc</code> は404になります。<code>req.matches[1]</code> で最初のキャプチャグループの値を取得しています。</p>
<h2>次のステップ</h2>
<p>サーバーの基本がわかりましたね。ルーティング、リクエストの読み取り、レスポンスの組み立て。これだけで、十分に実用的なAPIサーバーが作れます。</p>
<p>次は、静的ファイルの配信を見てみましょう。HTMLやCSSを配信するサーバーを作ります。</p>
<p><strong>次:</strong> <a href="../04-static-file-server">Static File Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
@@ -1,305 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Static File Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="active">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>Static File Server</h1>
<p>cpp-httplibは、HTMLやCSS、画像ファイルなどの静的ファイルも配信できます。面倒な設定は要りません。<code>set_mount_point()</code> を1行呼ぶだけです。</p>
<h2>set_mount_point の基本</h2>
<p>さっそくやってみましょう。<code>set_mount_point()</code> は、URLのパスとローカルディレクトリを紐づけます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./html</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./html&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>第1引数がURLのマウントポイント、第2引数がローカルのディレクトリパスです。この例だと、<code>/</code> へのリクエストを <code>./html</code> ディレクトリから配信します。</p>
<p>試してみましょう。まず <code>html</code> ディレクトリを作って、<code>index.html</code> を置きます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">mkdir</span><span style="color:#d3d0c8;"> html
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">mkdir html
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">&lt;!</span><span style="color:#f2777a;">DOCTYPE</span><span style="color:#d3d0c8;"> html&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">html</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">head</span><span style="color:#d3d0c8;">&gt;&lt;</span><span style="color:#f2777a;">title</span><span style="color:#d3d0c8;">&gt;My Page&lt;/</span><span style="color:#f2777a;">title</span><span style="color:#d3d0c8;">&gt;&lt;/</span><span style="color:#f2777a;">head</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;"> &lt;</span><span style="color:#f2777a;">h1</span><span style="color:#d3d0c8;">&gt;Hello from cpp-httplib!&lt;/</span><span style="color:#f2777a;">h1</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;"> &lt;</span><span style="color:#f2777a;">p</span><span style="color:#d3d0c8;">&gt;This is a static file.&lt;/</span><span style="color:#f2777a;">p</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;/</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">&lt;/</span><span style="color:#f2777a;">html</span><span style="color:#d3d0c8;">&gt;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">&lt;!</span><span style="color:#63a35c;">DOCTYPE</span><span style="color:#323232;"> html&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">html</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">head</span><span style="color:#323232;">&gt;&lt;</span><span style="color:#63a35c;">title</span><span style="color:#323232;">&gt;My Page&lt;/</span><span style="color:#63a35c;">title</span><span style="color:#323232;">&gt;&lt;/</span><span style="color:#63a35c;">head</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;</span><span style="color:#63a35c;">body</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;"> &lt;</span><span style="color:#63a35c;">h1</span><span style="color:#323232;">&gt;Hello from cpp-httplib!&lt;/</span><span style="color:#63a35c;">h1</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;"> &lt;</span><span style="color:#63a35c;">p</span><span style="color:#323232;">&gt;This is a static file.&lt;/</span><span style="color:#63a35c;">p</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;/</span><span style="color:#63a35c;">body</span><span style="color:#323232;">&gt;
</span><span style="color:#323232;">&lt;/</span><span style="color:#63a35c;">html</span><span style="color:#323232;">&gt;
</span></pre>
</div></div>
<p>コンパイルして起動します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">g++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp</span><span style="color:#f2777a;"> -pthread
</span><span style="color:#6699cc;">./server
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">g++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -o server server.cpp -pthread
</span><span style="color:#323232;">./server
</span></pre>
</div></div>
<p>ブラウザで <code>http://localhost:8080</code> を開いてみてください。<code>html/index.html</code> の内容が表示されるはずです。<code>http://localhost:8080/index.html</code> でも同じページが返ります。</p>
<p>もちろん、前章のクライアントコードや <code>curl</code> でもアクセスできますよ。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// HTMLが表示される
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// HTMLが表示される
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> http://localhost:8080
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl http://localhost:8080
</span></pre>
</div></div>
<h2>複数のマウントポイント</h2>
<p><code>set_mount_point()</code> は何回でも呼べます。URLのパスごとに、別々のディレクトリを割り当てられます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/assets</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./static/assets</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/docs</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./documentation</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/assets&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./static/assets&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/docs&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./documentation&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p><code>/assets/style.css</code> なら <code>./static/assets/style.css</code> を、<code>/docs/guide.html</code> なら <code>./documentation/guide.html</code> を配信します。</p>
<h2>ハンドラーとの組み合わせ</h2>
<p>静的ファイルの配信と、前章で学んだルーティングハンドラーは共存できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// APIエンドポイント
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/api/hello</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(</span><span style="color:#cc99cc;">R</span><span style="color:#d3d0c8;">&quot;(</span><span style="color:#99cc99;">{&quot;message&quot;:&quot;Hello!&quot;}</span><span style="color:#d3d0c8;">)&quot;, &quot;</span><span style="color:#99cc99;">application/json</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// 静的ファイル配信
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// APIエンドポイント
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/api/hello&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="font-weight:bold;color:#a71d5d;">R</span><span style="color:#183691;">&quot;({&quot;message&quot;:&quot;Hello!&quot;})&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;application/json&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// 静的ファイル配信
</span><span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>ハンドラーが先に評価されます。<code>/api/hello</code> にはハンドラーが応答し、それ以外のパスは <code>./public</code> ディレクトリからファイルを探します。</p>
<h2>レスポンスヘッダーの追加</h2>
<p><code>set_mount_point()</code> の第3引数にヘッダーを渡すと、静的ファイルのレスポンスにカスタムヘッダーを付けられます。キャッシュ制御に便利です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_mount_point</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">./public</span><span style="color:#d3d0c8;">&quot;, {
</span><span style="color:#d3d0c8;"> {&quot;</span><span style="color:#99cc99;">Cache-Control</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">max-age=3600</span><span style="color:#d3d0c8;">&quot;}
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_mount_point(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;./public&quot;</span><span style="color:#323232;">, {
</span><span style="color:#323232;"> {</span><span style="color:#183691;">&quot;Cache-Control&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;max-age=3600&quot;</span><span style="color:#323232;">}
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>こうすると、ブラウザは配信されたファイルを1時間キャッシュします。</p>
<h2>静的ファイルサーバー用のDockerファイル</h2>
<p>cpp-httplibのリポジトリには、静的ファイルサーバー用の <code>Dockerfile</code> が含まれています。Docker Hubにビルド済みイメージも公開しているので、1コマンドで起動できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">&gt; docker run</span><span style="color:#f2777a;"> -p</span><span style="color:#d3d0c8;"> 8080:80</span><span style="color:#f2777a;"> -v</span><span style="color:#d3d0c8;"> ./my-site:/html yhirose4dockerhub/cpp-httplib-server
</span><span style="color:#6699cc;">Serving</span><span style="color:#d3d0c8;"> HTTP on 0.0.0.0:80
</span><span style="color:#6699cc;">Mount</span><span style="color:#d3d0c8;"> point: / -&gt; ./html
</span><span style="color:#6699cc;">Press</span><span style="color:#d3d0c8;"> Ctrl+C to shutdown gracefully...
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:00 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET / HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 200 256 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:00 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET /style.css HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 200 1024 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#6699cc;">192.168.65.1</span><span style="color:#d3d0c8;"> - - </span><span style="color:#cc99cc;">[</span><span style="color:#d3d0c8;">22/Feb/2026:12:00:01 +0000</span><span style="color:#cc99cc;">] </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">GET /favicon.ico HTTP/1.1</span><span style="color:#d3d0c8;">&quot; 404 152 &quot;</span><span style="color:#99cc99;">-</span><span style="color:#d3d0c8;">&quot; &quot;</span><span style="color:#99cc99;">Mozilla/5.0 ...</span><span style="color:#d3d0c8;">&quot;
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">&gt;</span><span style="color:#323232;"> docker run -p 8080:80 -v ./my-site:/html yhirose4dockerhub/cpp-httplib-server
</span><span style="color:#323232;">Serving HTTP on 0.0.0.0:80
</span><span style="color:#323232;">Mount point: / -</span><span style="font-weight:bold;color:#a71d5d;">&gt;</span><span style="color:#323232;"> ./html
</span><span style="color:#323232;">Press Ctrl+C to shutdown gracefully...
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:00 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET / HTTP/1.1&quot;</span><span style="color:#323232;"> 200 256 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:00 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET /style.css HTTP/1.1&quot;</span><span style="color:#323232;"> 200 1024 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span><span style="color:#323232;">192.168.65.1 - - </span><span style="font-weight:bold;color:#a71d5d;">[</span><span style="color:#323232;">22/Feb/2026:12:00:01 +0000</span><span style="font-weight:bold;color:#a71d5d;">] </span><span style="color:#183691;">&quot;GET /favicon.ico HTTP/1.1&quot;</span><span style="color:#323232;"> 404 152 </span><span style="color:#183691;">&quot;-&quot; &quot;Mozilla/5.0 ...&quot;
</span></pre>
</div></div>
<p><code>./my-site</code> ディレクトリの中身が、そのままポート8080で配信されます。NGINXと同じログ形式で、アクセスの様子を確認できますよ。</p>
<h2>次のステップ</h2>
<p>静的ファイルの配信ができるようになりましたね。HTMLやCSS、JavaScriptを配信するWebサーバーが、これだけのコードで作れます。</p>
<p>次は、HTTPSで暗号化通信をしてみましょう。まずはTLSライブラリのセットアップからです。</p>
<p><strong>次:</strong> <a href="../05-tls-setup">TLS Setup</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-229
View File
@@ -1,229 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TLS Setup - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="active">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>TLS Setup</h1>
<p>ここまではHTTP(平文)でやってきましたが、実際のWebではHTTPS(暗号化通信)が当たり前ですよね。cpp-httplibでHTTPSを使うには、TLSライブラリが必要です。</p>
<p>このTourではOpenSSLを使います。最も広く使われていて、情報も豊富です。</p>
<h2>OpenSSLのインストール</h2>
<p>お使いのOSに合わせてインストールしましょう。</p>
<table><thead><tr><th>OS</th><th>インストール方法</th></tr></thead><tbody>
<tr><td>macOS</td><td><a href="https://brew.sh/">Homebrew</a> (<code>brew install openssl</code>)</td></tr>
<tr><td>Ubuntu / Debian</td><td><code>sudo apt install libssl-dev</code></td></tr>
<tr><td>Windows</td><td><a href="https://vcpkg.io/">vcpkg</a> (<code>vcpkg install openssl</code>)</td></tr>
</tbody></table>
<h2>コンパイルオプション</h2>
<p>TLS機能を有効にするには、<code>CPPHTTPLIB_OPENSSL_SUPPORT</code> マクロを定義してコンパイルします。前章までのコンパイルコマンドに、いくつかオプションが増えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;"># macOS (Homebrew)
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -DCPPHTTPLIB_OPENSSL_SUPPORT </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -I</span><span style="color:#d3d0c8;">$</span><span style="color:#f2777a;">(</span><span style="color:#6699cc;">brew</span><span style="color:#f2777a;"> --prefix openssl)</span><span style="color:#d3d0c8;">/include \
</span><span style="color:#f2777a;"> -L</span><span style="color:#d3d0c8;">$</span><span style="color:#f2777a;">(</span><span style="color:#6699cc;">brew</span><span style="color:#f2777a;"> --prefix openssl)</span><span style="color:#d3d0c8;">/lib \
</span><span style="color:#f2777a;"> -lssl -lcrypto </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -framework</span><span style="color:#d3d0c8;"> CoreFoundation</span><span style="color:#f2777a;"> -framework</span><span style="color:#d3d0c8;"> Security \
</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Linux
</span><span style="color:#6699cc;">clang++</span><span style="color:#f2777a;"> -std</span><span style="color:#d3d0c8;">=c++17</span><span style="color:#f2777a;"> -pthread -DCPPHTTPLIB_OPENSSL_SUPPORT </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -lssl -lcrypto </span><span style="color:#d3d0c8;">\
</span><span style="color:#f2777a;"> -o</span><span style="color:#d3d0c8;"> server server.cpp
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;"># Windows (Developer Command Prompt)
</span><span style="color:#6699cc;">cl</span><span style="color:#d3d0c8;"> /EHsc /std:c++17 /DCPPHTTPLIB_OPENSSL_SUPPORT server.cpp libssl.lib libcrypto.lib
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;"># macOS (Homebrew)
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -DCPPHTTPLIB_OPENSSL_SUPPORT \
</span><span style="color:#323232;"> -I$(brew --prefix openssl)/include \
</span><span style="color:#323232;"> -L$(brew --prefix openssl)/lib \
</span><span style="color:#323232;"> -lssl -lcrypto \
</span><span style="color:#323232;"> -framework CoreFoundation -framework Security \
</span><span style="color:#323232;"> -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Linux
</span><span style="color:#323232;">clang++ -std</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;">c++17 -pthread -DCPPHTTPLIB_OPENSSL_SUPPORT \
</span><span style="color:#323232;"> -lssl -lcrypto \
</span><span style="color:#323232;"> -o server server.cpp
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;"># Windows (Developer Command Prompt)
</span><span style="color:#323232;">cl /EHsc /std:c++17 /DCPPHTTPLIB_OPENSSL_SUPPORT server.cpp libssl.lib libcrypto.lib
</span></pre>
</div></div>
<p>それぞれのオプションの役割を見てみましょう。</p>
<ul>
<li><strong><code>-DCPPHTTPLIB_OPENSSL_SUPPORT</code></strong> — TLS機能を有効にするマクロ定義</li>
<li><strong><code>-lssl -lcrypto</code></strong> — OpenSSLのライブラリをリンク</li>
<li><strong><code>-I</code> / <code>-L</code></strong>macOSのみ)— Homebrew版OpenSSLのパスを指定</li>
<li><strong><code>-framework CoreFoundation -framework Security</code></strong>macOSのみ)— Keychainからシステム証明書を自動で読み込むために必要です</li>
</ul>
<h2>動作確認</h2>
<p>ちゃんと動くか確認してみましょう。<code>httplib::Client</code> にHTTPSのURLを渡してアクセスするだけのプログラムです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://www.google.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Status: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://www.google.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Status: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>コンパイルして実行してみてください。<code>Status: 200</code> と表示されれば、セットアップ完了です。</p>
<h2>他のTLSバックエンド</h2>
<p>cpp-httplibはOpenSSL以外にも、Mbed TLSとwolfSSLに対応しています。マクロ定義とリンクするライブラリを変えるだけで切り替えられます。</p>
<table><thead><tr><th style="text-align: left">バックエンド</th><th style="text-align: left">マクロ定義</th><th style="text-align: left">リンクするライブラリ</th></tr></thead><tbody>
<tr><td style="text-align: left">OpenSSL</td><td style="text-align: left"><code>CPPHTTPLIB_OPENSSL_SUPPORT</code></td><td style="text-align: left"><code>libssl</code>, <code>libcrypto</code></td></tr>
<tr><td style="text-align: left">Mbed TLS</td><td style="text-align: left"><code>CPPHTTPLIB_MBEDTLS_SUPPORT</code></td><td style="text-align: left"><code>libmbedtls</code>, <code>libmbedx509</code>, <code>libmbedcrypto</code></td></tr>
<tr><td style="text-align: left">wolfSSL</td><td style="text-align: left"><code>CPPHTTPLIB_WOLFSSL_SUPPORT</code></td><td style="text-align: left"><code>libwolfssl</code></td></tr>
</tbody></table>
<p>このTourではOpenSSLを前提に進めますが、APIはどのバックエンドでも共通です。</p>
<h2>次のステップ</h2>
<p>TLSの準備ができましたね。次は、HTTPSサイトにリクエストを送ってみましょう。</p>
<p><strong>次:</strong> <a href="../06-https-client">HTTPS Client</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-287
View File
@@ -1,287 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HTTPS Client - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="active">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>HTTPS Client</h1>
<p>前章でOpenSSLのセットアップが済んだので、さっそくHTTPSクライアントを使ってみましょう。2章で使った <code>httplib::Client</code> がそのまま使えます。コンストラクタに <code>https://</code> 付きのURLを渡すだけです。</p>
<h2>GETリクエスト</h2>
<p>実在するHTTPSサイトにアクセスしてみましょう。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">substr</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">100</span><span style="color:#d3d0c8;">) &lt;&lt; std::endl; </span><span style="color:#747369;">// HTMLの先頭部分
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Error: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; </span><span style="color:#6699cc;">httplib::to_string</span><span style="color:#d3d0c8;">(res.</span><span style="color:#6699cc;">error</span><span style="color:#d3d0c8;">()) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body.substr(</span><span style="color:#0086b3;">0</span><span style="color:#323232;">, </span><span style="color:#0086b3;">100</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// HTMLの先頭部分
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Error: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#323232;">httplib::to_string(res.error()) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>2章では <code>httplib::Client cli("http://localhost:8080")</code> と書きましたよね。スキームを <code>https://</code> に変えるだけです。<code>Get()</code><code>Post()</code> など、2章で学んだAPIはすべてそのまま使えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> https://nghttp2.org/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl https://nghttp2.org/
</span></pre>
</div></div>
<h2>ポートの指定</h2>
<p>HTTPSのデフォルトポートは443です。別のポートを使いたい場合は、URLにポートを含めます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>CA証明書の検証</h2>
<p><code>httplib::Client</code> はHTTPS接続時、デフォルトでサーバー証明書を検証します。信頼できるCA(認証局)が発行した証明書を持つサーバーにしか接続しません。</p>
<p>CA証明書は、macOSならKeychain、LinuxならシステムのCA証明書ストア、WindowsならWindowsの証明書ストアから自動で読み込みます。ほとんどの場合、追加の設定は要りません。</p>
<h3>CA証明書ファイルの指定</h3>
<p>環境によってはシステムのCA証明書が見つからないこともあります。そのときは <code>set_ca_cert_path()</code> でパスを直接指定してください。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_ca_cert_path</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/etc/ssl/certs/ca-certificates.crt</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_ca_cert_path(</span><span style="color:#183691;">&quot;/etc/ssl/certs/ca-certificates.crt&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> --cacert</span><span style="color:#d3d0c8;"> /etc/ssl/certs/ca-certificates.crt https://nghttp2.org/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl --cacert /etc/ssl/certs/ca-certificates.crt https://nghttp2.org/
</span></pre>
</div></div>
<h3>証明書検証の無効化</h3>
<p>開発中、自己署名証明書のサーバーに接続したいときは、検証を無効にできます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">enable_server_certificate_verification</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">false</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.enable_server_certificate_verification(</span><span style="color:#0086b3;">false</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -k</span><span style="color:#d3d0c8;"> https://localhost:8443/
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -k https://localhost:8443/
</span></pre>
</div></div>
<p>本番では絶対に無効にしないでください。中間者攻撃のリスクがあります。</p>
<h2>リダイレクトの追跡</h2>
<p>HTTPSサイトへのアクセスでは、リダイレクトに遭遇することがよくあります。たとえば <code>http://</code> から <code>https://</code> へ、あるいは <code>www</code> なしから <code>www</code> ありへ転送されるケースです。</p>
<p>デフォルトではリダイレクトを追跡しません。リダイレクト先は <code>Location</code> ヘッダーで確認できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/httpbin/redirect/3</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 302
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Location</span><span style="color:#d3d0c8;">&quot;) &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/httpbin/redirect/3&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 302
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;get_header_value(</span><span style="color:#183691;">&quot;Location&quot;</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#d3d0c8;"> https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div></div>
<p><code>set_follow_location(true)</code> を設定すると、リダイレクトを自動で追跡して、最終的なレスポンスを返してくれます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://nghttp2.org</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_follow_location</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/httpbin/redirect/3</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// 200(最終的なレスポンス)
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://nghttp2.org&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_follow_location(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/httpbin/redirect/3&quot;</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// 200(最終的なレスポンス)
</span><span style="color:#323232;">}
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -L</span><span style="color:#d3d0c8;"> https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -L https://nghttp2.org/httpbin/redirect/3
</span></pre>
</div></div>
<h2>次のステップ</h2>
<p>HTTPSクライアントの使い方がわかりましたね。次は自分でHTTPSサーバーを立ててみましょう。自己署名証明書の作り方から始めます。</p>
<p><strong>次:</strong> <a href="../07-https-server">HTTPS Server</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-276
View File
@@ -1,276 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HTTPS Server - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="active">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>HTTPS Server</h1>
<p>前章ではHTTPSクライアントを使いました。今度は自分でHTTPSサーバーを立ててみましょう。3章の <code>httplib::Server</code><code>httplib::SSLServer</code> に置き換えるだけです。</p>
<p>ただし、TLSサーバーにはサーバー証明書と秘密鍵が必要です。まずはそこから準備しましょう。</p>
<h2>自己署名証明書の作成</h2>
<p>開発やテスト用なら、自己署名証明書(いわゆるオレオレ証明書)で十分です。OpenSSLのコマンドでサクッと作れます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">openssl</span><span style="color:#d3d0c8;"> req</span><span style="color:#f2777a;"> -x509 -noenc -keyout</span><span style="color:#d3d0c8;"> key.pem</span><span style="color:#f2777a;"> -out</span><span style="color:#d3d0c8;"> cert.pem</span><span style="color:#f2777a;"> -subj</span><span style="color:#d3d0c8;"> /CN=localhost
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">openssl req -x509 -noenc -keyout key.pem -out cert.pem -subj /CN=localhost
</span></pre>
</div></div>
<p>これで2つのファイルができます。</p>
<ul>
<li><strong><code>cert.pem</code></strong> — サーバー証明書</li>
<li><strong><code>key.pem</code></strong> — 秘密鍵</li>
</ul>
<h2>最小のHTTPSサーバー</h2>
<p>証明書ができたら、さっそくサーバーを書いてみましょう。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::SSLServer </span><span style="color:#6699cc;">svr</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">key.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, HTTPS!</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on https://localhost:8443</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8443</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::SSLServer svr(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;key.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, HTTPS!&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on https://localhost:8443&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8443</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>httplib::SSLServer</code> のコンストラクタに証明書と秘密鍵のパスを渡すだけです。ルーティングの書き方は3章の <code>httplib::Server</code> とまったく同じですよ。</p>
<p>コンパイルして起動しましょう。</p>
<h2>動作確認</h2>
<p>サーバーが起動したら、<code>curl</code> でアクセスしてみましょう。自己署名証明書なので、<code>-k</code> オプションで証明書検証をスキップします。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#6699cc;">curl</span><span style="color:#f2777a;"> -k</span><span style="color:#d3d0c8;"> https://localhost:8443/
</span><span style="color:#747369;"># Hello, HTTPS!
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">curl -k https://localhost:8443/
</span><span style="font-style:italic;color:#969896;"># Hello, HTTPS!
</span></pre>
</div></div>
<p>ブラウザで <code>https://localhost:8443</code> を開くと、「この接続は安全ではありません」と警告が出ます。自己署名証明書なので正常です。気にせず進めてください。</p>
<h2>クライアントからの接続</h2>
<p>前章の <code>httplib::Client</code> で接続してみましょう。自己署名証明書のサーバーに接続するには、2つの方法があります。</p>
<h3>方法1: 証明書検証を無効にする</h3>
<p>開発時の手軽な方法です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> cli.</span><span style="color:#6699cc;">enable_server_certificate_verification</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">false</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, HTTPS!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> cli.enable_server_certificate_verification(</span><span style="color:#0086b3;">false</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, HTTPS!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<h3>方法2: 自己署名証明書をCA証明書として指定する</h3>
<p>こちらのほうが安全です。<code>cert.pem</code> をCA証明書として信頼するよう指定します。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#define </span><span style="color:#d3d0c8;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://localhost:8443</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> cli.</span><span style="color:#6699cc;">set_ca_cert_path</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; res-&gt;</span><span style="color:#f2777a;">body </span><span style="color:#d3d0c8;">&lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, HTTPS!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#define </span><span style="color:#323232;">CPPHTTPLIB_OPENSSL_SUPPORT
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Client cli(</span><span style="color:#183691;">&quot;https://localhost:8443&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> cli.set_ca_cert_path(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res-&gt;body </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, HTTPS!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>この方法なら、指定した証明書のサーバーにだけ接続を許可して、なりすましを防げます。テスト環境でもなるべくこちらを使いましょう。</p>
<h2>Server と SSLServer の比較</h2>
<p>3章で学んだ <code>httplib::Server</code> のAPIは、<code>httplib::SSLServer</code> でもそのまま使えます。違いはコンストラクタだけです。</p>
<table><thead><tr><th></th><th><code>httplib::Server</code></th><th><code>httplib::SSLServer</code></th></tr></thead><tbody>
<tr><td>コンストラクタ</td><td>引数なし</td><td>証明書と秘密鍵のパス</td></tr>
<tr><td>プロトコル</td><td>HTTP</td><td>HTTPS</td></tr>
<tr><td>ポート(慣例)</td><td>8080</td><td>8443</td></tr>
<tr><td>ルーティング</td><td>共通</td><td>共通</td></tr>
</tbody></table>
<p>HTTPサーバーをHTTPSに切り替えるには、コンストラクタを変えるだけです。</p>
<h2>次のステップ</h2>
<p>HTTPSサーバーが動きましたね。これでHTTP/HTTPSのクライアントとサーバー、両方の基本がそろいました。</p>
<p>次は、cpp-httplibに新しく加わったWebSocket機能を見てみましょう。</p>
<p><strong>次:</strong> <a href="../08-websocket">WebSocket</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-328
View File
@@ -1,328 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebSocket - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="active">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>WebSocket</h1>
<p>cpp-httplibはWebSocketにも対応しています。HTTPのリクエスト/レスポンスと違い、WebSocketはサーバーとクライアントが双方向にメッセージをやり取りできます。チャットやリアルタイム通知に便利です。</p>
<p>さっそく、エコーサーバーとクライアントを作ってみましょう。</p>
<h2>エコーサーバー</h2>
<p>受け取ったメッセージをそのまま返すエコーサーバーです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::Server svr;
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg); </span><span style="color:#747369;">// 受け取ったメッセージをそのまま返す
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Listening on port 8080...</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::Server svr;
</span><span style="color:#323232;">
</span><span style="color:#323232;"> svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg); </span><span style="font-style:italic;color:#969896;">// 受け取ったメッセージをそのまま返す
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Listening on port 8080...&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>svr.WebSocket()</code> でWebSocketハンドラーを登録します。3章の <code>svr.Get()</code><code>svr.Post()</code> と同じ感覚ですね。</p>
<p>ハンドラーの中では、<code>ws.read(msg)</code> でメッセージを待ちます。接続が閉じられると <code>read()</code><code>false</code> を返すので、ループを抜けます。<code>ws.send(msg)</code> でメッセージを送り返します。</p>
<h2>クライアントからの接続</h2>
<p><code>httplib::ws::WebSocketClient</code> を使ってサーバーに接続してみましょう。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&quot;</span><span style="color:#99cc99;">httplib.h</span><span style="color:#d3d0c8;">&quot;
</span><span style="color:#cc99cc;">#include </span><span style="color:#d3d0c8;">&lt;</span><span style="color:#99cc99;">iostream</span><span style="color:#d3d0c8;">&gt;
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">int </span><span style="color:#6699cc;">main</span><span style="color:#d3d0c8;">() {
</span><span style="color:#d3d0c8;"> httplib::ws::WebSocketClient </span><span style="color:#6699cc;">client</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">ws://localhost:8080/ws</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(!client.</span><span style="color:#6699cc;">connect</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; &quot;</span><span style="color:#99cc99;">Connection failed</span><span style="color:#d3d0c8;">&quot; &lt;&lt; std::endl;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">1</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// メッセージを送信
</span><span style="color:#d3d0c8;"> client.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, WebSocket!</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// サーバーからの応答を受信
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(client.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; msg &lt;&lt; std::endl; </span><span style="color:#747369;">// Hello, WebSocket!
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> client.</span><span style="color:#6699cc;">close</span><span style="color:#d3d0c8;">();
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&quot;httplib.h&quot;
</span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;">&lt;iostream&gt;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main</span><span style="color:#323232;">() {
</span><span style="color:#323232;"> httplib::ws::WebSocketClient client(</span><span style="color:#183691;">&quot;ws://localhost:8080/ws&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">!</span><span style="color:#323232;">client.connect()) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;Connection failed&quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// メッセージを送信
</span><span style="color:#323232;"> client.send(</span><span style="color:#183691;">&quot;Hello, WebSocket!&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// サーバーからの応答を受信
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(client.read(msg)) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl; </span><span style="font-style:italic;color:#969896;">// Hello, WebSocket!
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> client.close();
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p>コンストラクタには <code>ws://host:port/path</code> 形式のURLを渡します。<code>connect()</code> で接続を開始し、<code>send()</code><code>read()</code> でメッセージをやり取りします。</p>
<h2>テキストとバイナリ</h2>
<p>WebSocketにはテキストとバイナリの2種類のメッセージがあります。<code>read()</code> の戻り値で区別できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> httplib::ws::ReadResult ret;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">((ret = ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg))) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(ret == httplib::ws::Binary) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg.</span><span style="color:#6699cc;">data</span><span style="color:#d3d0c8;">(), msg.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">()); </span><span style="color:#747369;">// バイナリとして送信
</span><span style="color:#d3d0c8;"> } </span><span style="color:#cc99cc;">else </span><span style="color:#d3d0c8;">{
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg); </span><span style="color:#747369;">// テキストとして送信
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> httplib::ws::ReadResult ret;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">((ret </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> ws.read(msg))) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(ret </span><span style="font-weight:bold;color:#a71d5d;">==</span><span style="color:#323232;"> httplib::ws::Binary) {
</span><span style="color:#323232;"> ws.send(msg.data(), msg.size()); </span><span style="font-style:italic;color:#969896;">// バイナリとして送信
</span><span style="color:#323232;"> } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;"> ws.send(msg); </span><span style="font-style:italic;color:#969896;">// テキストとして送信
</span><span style="color:#323232;"> }
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<ul>
<li><code>ws.send(const std::string &amp;)</code> — テキストメッセージとして送信</li>
<li><code>ws.send(const char *, size_t)</code> — バイナリメッセージとして送信</li>
</ul>
<p>クライアント側も同じAPIです。</p>
<h2>リクエスト情報へのアクセス</h2>
<p>ハンドラーの第1引数 <code>req</code> から、ハンドシェイク時のHTTPリクエスト情報を読み取れます。認証トークンの確認などに便利です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;req, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> token = req.</span><span style="color:#6699cc;">get_header_value</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Authorization</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(token.</span><span style="color:#6699cc;">empty</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">close</span><span style="color:#d3d0c8;">(httplib::ws::CloseStatus::PolicyViolation, &quot;</span><span style="color:#99cc99;">unauthorized</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg);
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">req, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> token </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> req.get_header_value(</span><span style="color:#183691;">&quot;Authorization&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(token.empty()) {
</span><span style="color:#323232;"> ws.close(httplib::ws::CloseStatus::PolicyViolation, </span><span style="color:#183691;">&quot;unauthorized&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;">;
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg);
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>WSSで使う</h2>
<p>HTTPS上のWebSocket(WSS)にも対応しています。サーバー側は <code>httplib::SSLServer</code> にWebSocketハンドラーを登録するだけです。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::SSLServer </span><span style="color:#6699cc;">svr</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">cert.pem</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">key.pem</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">WebSocket</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/ws</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::Request &amp;, httplib::ws::WebSocket &amp;ws) {
</span><span style="color:#d3d0c8;"> std::string msg;
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(ws.</span><span style="color:#6699cc;">read</span><span style="color:#d3d0c8;">(msg)) {
</span><span style="color:#d3d0c8;"> ws.</span><span style="color:#6699cc;">send</span><span style="color:#d3d0c8;">(msg);
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">0.0.0.0</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8443</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::SSLServer </span><span style="font-weight:bold;color:#795da3;">svr</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;cert.pem&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;key.pem&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.WebSocket(</span><span style="color:#183691;">&quot;/ws&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::Request </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">, httplib::ws::WebSocket </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">ws) {
</span><span style="color:#323232;"> std::string msg;
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(ws.read(msg)) {
</span><span style="color:#323232;"> ws.send(msg);
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;0.0.0.0&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8443</span><span style="color:#323232;">);
</span></pre>
</div></div>
<p>クライアント側は <code>wss://</code> スキームを使います。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::ws::WebSocketClient </span><span style="color:#6699cc;">client</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">wss://localhost:8443/ws</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::ws::WebSocketClient </span><span style="font-weight:bold;color:#795da3;">client</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;wss://localhost:8443/ws&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>次のステップ</h2>
<p>WebSocketの基本がわかりましたね。ここまでで Tourは終わりです。</p>
<p>次のページでは、Tourで取り上げなかった機能をまとめて紹介します。</p>
<p><strong>次:</strong> <a href="../09-whats-next">What's Next</a></p>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-460
View File
@@ -1,460 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>What&#x27;s Next - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="active">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>What&#x27;s Next</h1>
<p>Tourお疲れさまでした! cpp-httplibの基本はひと通り押さえましたね。でも、まだまだ便利な機能があります。Tourで取り上げなかった機能をカテゴリー別に紹介します。</p>
<h2>Streaming API</h2>
<p>LLMのストリーミング応答や大きなファイルのダウンロードでは、レスポンス全体をメモリに載せたくないですよね。<code>stream::Get()</code> を使えば、データをチャンクごとに処理できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:11434</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> result = </span><span style="color:#6699cc;">httplib::stream::Get</span><span style="color:#d3d0c8;">(cli, &quot;</span><span style="color:#99cc99;">/api/generate</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">if </span><span style="color:#d3d0c8;">(result) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">while </span><span style="color:#d3d0c8;">(result.</span><span style="color:#6699cc;">next</span><span style="color:#d3d0c8;">()) {
</span><span style="color:#d3d0c8;"> std::cout.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(result.</span><span style="color:#6699cc;">data</span><span style="color:#d3d0c8;">(), result.</span><span style="color:#6699cc;">size</span><span style="color:#d3d0c8;">());
</span><span style="color:#d3d0c8;"> }
</span><span style="color:#d3d0c8;">}
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:11434&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> result </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">httplib::stream::Get(cli, </span><span style="color:#183691;">&quot;/api/generate&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">if </span><span style="color:#323232;">(result) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span style="color:#323232;">(result.next()) {
</span><span style="color:#323232;"> std::cout.write(result.data(), result.size());
</span><span style="color:#323232;"> }
</span><span style="color:#323232;">}
</span></pre>
</div></div>
<p><code>Get()</code><code>content_receiver</code> コールバックを渡す方法もあります。こちらはKeep-Aliveと併用できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/stream</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const char </span><span style="color:#d3d0c8;">*data, size_t len) {
</span><span style="color:#d3d0c8;"> std::cout.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(data, len);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">cli.Get(</span><span style="color:#183691;">&quot;/stream&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const char *</span><span style="color:#323232;">data, </span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> len) {
</span><span style="color:#323232;"> std::cout.write(data, len);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">;
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>サーバー側には <code>set_content_provider()</code><code>set_chunked_content_provider()</code> があります。サイズがわかっているなら前者、不明なら後者を使ってください。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// サイズ指定あり(Content-Length が設定される)
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/file</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> size = </span><span style="color:#6699cc;">get_file_size</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">large.bin</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content_provider</span><span style="color:#d3d0c8;">(size, &quot;</span><span style="color:#99cc99;">application/octet-stream</span><span style="color:#d3d0c8;">&quot;,
</span><span style="color:#d3d0c8;"> [](size_t offset, size_t length, httplib::DataSink &amp;sink) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// offset から length バイト分を送る
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#747369;">// サイズ不明(Chunked Transfer Encoding
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/stream</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_chunked_content_provider</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;,
</span><span style="color:#d3d0c8;"> [](size_t offset, httplib::DataSink &amp;sink) {
</span><span style="color:#d3d0c8;"> sink.</span><span style="color:#6699cc;">write</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">chunk</span><span style="color:#66cccc;">\n</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">6</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return </span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">; </span><span style="color:#747369;">// falseを返すと終了
</span><span style="color:#d3d0c8;"> });
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// サイズ指定あり(Content-Length が設定される)
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/file&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> size </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">get_file_size(</span><span style="color:#183691;">&quot;large.bin&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> res.set_content_provider(size, </span><span style="color:#183691;">&quot;application/octet-stream&quot;</span><span style="color:#323232;">,
</span><span style="color:#323232;"> [](</span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> offset, </span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> length, httplib::DataSink </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">sink) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// offset から length バイト分を送る
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">;
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// サイズ不明(Chunked Transfer Encoding
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/stream&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_chunked_content_provider(</span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">,
</span><span style="color:#323232;"> [](</span><span style="color:#0086b3;">size_t</span><span style="color:#323232;"> offset, httplib::DataSink </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">sink) {
</span><span style="color:#323232;"> sink.write(</span><span style="color:#183691;">&quot;chunk</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">6</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#0086b3;">true</span><span style="color:#323232;">; </span><span style="font-style:italic;color:#969896;">// falseを返すと終了
</span><span style="color:#323232;"> });
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>大きなファイルのアップロードには <code>make_file_provider()</code> が便利です。ファイルを全部メモリに読み込まず、ストリーミングで送れます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Post</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/upload</span><span style="color:#d3d0c8;">&quot;, {}, {
</span><span style="color:#d3d0c8;"> </span><span style="color:#6699cc;">httplib::make_file_provider</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">file</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">/path/to/large-file.zip</span><span style="color:#d3d0c8;">&quot;)
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Post(</span><span style="color:#183691;">&quot;/upload&quot;</span><span style="color:#323232;">, {}, {
</span><span style="color:#323232;"> httplib::make_file_provider(</span><span style="color:#183691;">&quot;file&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;/path/to/large-file.zip&quot;</span><span style="color:#323232;">)
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Server-Sent Events (SSE)</h2>
<p>SSEクライアントも用意しています。自動再接続や <code>Last-Event-ID</code> による再開にも対応しています。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost:8080</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">httplib::sse::SSEClient </span><span style="color:#6699cc;">sse</span><span style="color:#d3d0c8;">(</span><span style="color:#f2777a;">cli</span><span style="color:#d3d0c8;">, &quot;</span><span style="color:#99cc99;">/events</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">on_message</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::sse::SSEMessage &amp;msg) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; msg.</span><span style="color:#f2777a;">event </span><span style="color:#d3d0c8;">&lt;&lt; &quot;</span><span style="color:#99cc99;">: </span><span style="color:#d3d0c8;">&quot; &lt;&lt; msg.</span><span style="color:#f2777a;">data </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">start</span><span style="color:#d3d0c8;">(); </span><span style="color:#747369;">// ブロッキング、自動再接続あり
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost:8080&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">httplib::sse::SSEClient </span><span style="font-weight:bold;color:#795da3;">sse</span><span style="color:#323232;">(cli, </span><span style="color:#183691;">&quot;/events&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">
</span><span style="color:#323232;">sse.on_message([](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::sse::SSEMessage </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">msg) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg.event </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot;: &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> msg.data </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">sse.start(); </span><span style="font-style:italic;color:#969896;">// ブロッキング、自動再接続あり
</span></pre>
</div></div>
<p>イベントタイプごとにハンドラーを分けることもできますよ。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">sse.</span><span style="color:#6699cc;">on_event</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">update</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const</span><span style="color:#d3d0c8;"> httplib::sse::SSEMessage &amp;msg) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// &quot;update&quot; イベントだけ処理
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">sse.on_event(</span><span style="color:#183691;">&quot;update&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const</span><span style="color:#323232;"> httplib::sse::SSEMessage </span><span style="font-weight:bold;color:#a71d5d;">&amp;</span><span style="color:#323232;">msg) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// &quot;update&quot; イベントだけ処理
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>認証</h2>
<p>クライアントにはBasic認証、Bearer Token認証、Digest認証のヘルパーを用意しています。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://api.example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_basic_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">password</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_bearer_token_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">my-token</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://api.example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_basic_auth(</span><span style="color:#183691;">&quot;user&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;password&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_bearer_token_auth(</span><span style="color:#183691;">&quot;my-token&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>圧縮</h2>
<p>gzip、Brotli、Zstandardによる圧縮・展開に対応しています。使いたい方式のマクロを定義してコンパイルしましょう。</p>
<table><thead><tr><th>圧縮方式</th><th>マクロ定義</th></tr></thead><tbody>
<tr><td>gzip</td><td><code>CPPHTTPLIB_ZLIB_SUPPORT</code></td></tr>
<tr><td>Brotli</td><td><code>CPPHTTPLIB_BROTLI_SUPPORT</code></td></tr>
<tr><td>Zstandard</td><td><code>CPPHTTPLIB_ZSTD_SUPPORT</code></td></tr>
</tbody></table>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_compress</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// リクエストボディを圧縮
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_decompress</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// レスポンスボディを展開
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_compress(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// リクエストボディを圧縮
</span><span style="color:#323232;">cli.set_decompress(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// レスポンスボディを展開
</span></pre>
</div></div>
<h2>プロキシ</h2>
<p>HTTPプロキシ経由で接続できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_proxy</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">proxy.example.com</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">8080</span><span style="color:#d3d0c8;">);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_proxy_basic_auth</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">user</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">password</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_proxy(</span><span style="color:#183691;">&quot;proxy.example.com&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">8080</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_proxy_basic_auth(</span><span style="color:#183691;">&quot;user&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;password&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>タイムアウト</h2>
<p>接続・読み取り・書き込みのタイムアウトを個別に設定できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_connection_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">5</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 5秒
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_read_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">10</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 10秒
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_write_timeout</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">10</span><span style="color:#d3d0c8;">, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">); </span><span style="color:#747369;">// 10秒
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_connection_timeout(</span><span style="color:#0086b3;">5</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 5秒
</span><span style="color:#323232;">cli.set_read_timeout(</span><span style="color:#0086b3;">10</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 10秒
</span><span style="color:#323232;">cli.set_write_timeout(</span><span style="color:#0086b3;">10</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">); </span><span style="font-style:italic;color:#969896;">// 10秒
</span></pre>
</div></div>
<h2>Keep-Alive</h2>
<p>同じサーバーに何度もリクエストするなら、Keep-Aliveを有効にしましょう。TCP接続を再利用するので効率的です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">https://example.com</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_keep_alive</span><span style="color:#d3d0c8;">(</span><span style="color:#f99157;">true</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;https://example.com&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_keep_alive(</span><span style="color:#0086b3;">true</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>サーバーのミドルウェア</h2>
<p>リクエスト処理の前後にフックを挟めます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_pre_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// すべてのリクエストの前に実行される
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;"> httplib::Server::HandlerResponse::Unhandled; </span><span style="color:#747369;">// 通常のルーティングに進む
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_post_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#747369;">// レスポンスが返された後に実行される
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_header</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">X-Server</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">cpp-httplib</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_pre_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// すべてのリクエストの前に実行される
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> httplib::Server::HandlerResponse::Unhandled; </span><span style="font-style:italic;color:#969896;">// 通常のルーティングに進む
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.set_post_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-style:italic;color:#969896;">// レスポンスが返された後に実行される
</span><span style="color:#323232;"> res.set_header(</span><span style="color:#183691;">&quot;X-Server&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;cpp-httplib&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p><code>req.user_data</code> を使うと、ミドルウェアからハンドラーにデータを渡せます。認証トークンのデコード結果を共有するときに便利です。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_pre_routing_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> req.</span><span style="color:#f2777a;">user_data</span><span style="color:#d3d0c8;">[&quot;</span><span style="color:#99cc99;">auth_user</span><span style="color:#d3d0c8;">&quot;] = </span><span style="color:#6699cc;">std::string</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">alice</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">return</span><span style="color:#d3d0c8;"> httplib::Server::HandlerResponse::Unhandled;
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/me</span><span style="color:#d3d0c8;">&quot;, [](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> </span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> user = std::</span><span style="color:#6699cc;">any_cast</span><span style="color:#d3d0c8;">&lt;std::string&gt;(req.</span><span style="color:#f2777a;">user_data</span><span style="color:#d3d0c8;">.</span><span style="color:#6699cc;">at</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">auth_user</span><span style="color:#d3d0c8;">&quot;));
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Hello, </span><span style="color:#d3d0c8;">&quot; + user, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_pre_routing_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> req.user_data[</span><span style="color:#183691;">&quot;auth_user&quot;</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">std::string(</span><span style="color:#183691;">&quot;alice&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span style="color:#323232;"> httplib::Server::HandlerResponse::Unhandled;
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.Get(</span><span style="color:#183691;">&quot;/me&quot;</span><span style="color:#323232;">, [](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> user </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">std::any_cast&lt;std::string&gt;(req.user_data.at(</span><span style="color:#183691;">&quot;auth_user&quot;</span><span style="color:#323232;">));
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Hello, &quot; </span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#323232;"> user, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<p>エラーや例外のハンドラーもカスタマイズできますよ。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_error_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Custom Error Page</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/html</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span><span style="color:#d3d0c8;">
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_exception_handler</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">auto </span><span style="color:#d3d0c8;">&amp;res, std::exception_ptr ep) {
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">= </span><span style="color:#f99157;">500</span><span style="color:#d3d0c8;">;
</span><span style="color:#d3d0c8;"> res.</span><span style="color:#6699cc;">set_content</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">Internal Server Error</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">text/plain</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_error_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Custom Error Page&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/html&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span><span style="color:#323232;">
</span><span style="color:#323232;">svr.set_exception_handler([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">auto &amp;</span><span style="color:#323232;">res, std::exception_ptr ep) {
</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">500</span><span style="color:#323232;">;
</span><span style="color:#323232;"> res.set_content(</span><span style="color:#183691;">&quot;Internal Server Error&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;text/plain&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>ロギング</h2>
<p>サーバーでもクライアントでもロガーを設定できます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_logger</span><span style="color:#d3d0c8;">([](</span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;req, </span><span style="color:#cc99cc;">const auto </span><span style="color:#d3d0c8;">&amp;res) {
</span><span style="color:#d3d0c8;"> std::cout &lt;&lt; req.</span><span style="color:#f2777a;">method </span><span style="color:#d3d0c8;">&lt;&lt; &quot; &quot; &lt;&lt; req.</span><span style="color:#f2777a;">path </span><span style="color:#d3d0c8;">&lt;&lt; &quot; &quot; &lt;&lt; res.</span><span style="color:#f2777a;">status </span><span style="color:#d3d0c8;">&lt;&lt; std::endl;
</span><span style="color:#d3d0c8;">});
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="color:#323232;">svr.set_logger([](</span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">req, </span><span style="font-weight:bold;color:#a71d5d;">const auto &amp;</span><span style="color:#323232;">res) {
</span><span style="color:#323232;"> std::cout </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> req.method </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot; &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> req.path </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt; </span><span style="color:#183691;">&quot; &quot; </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> res.status </span><span style="font-weight:bold;color:#a71d5d;">&lt;&lt;</span><span style="color:#323232;"> std::endl;
</span><span style="color:#323232;">});
</span></pre>
</div></div>
<h2>Unix Domain Socket</h2>
<p>TCP以外に、Unix Domain Socketでの通信にも対応しています。同じマシン上のプロセス間通信に使えます。</p>
<div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// サーバー
</span><span style="color:#d3d0c8;">httplib::Server svr;
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">set_address_family</span><span style="color:#d3d0c8;">(AF_UNIX);
</span><span style="color:#d3d0c8;">svr.</span><span style="color:#6699cc;">listen</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/tmp/httplib.sock</span><span style="color:#d3d0c8;">&quot;, </span><span style="color:#f99157;">0</span><span style="color:#d3d0c8;">);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// サーバー
</span><span style="color:#323232;">httplib::Server svr;
</span><span style="color:#323232;">svr.set_address_family(AF_UNIX);
</span><span style="color:#323232;">svr.listen(</span><span style="color:#183691;">&quot;/tmp/httplib.sock&quot;</span><span style="color:#323232;">, </span><span style="color:#0086b3;">0</span><span style="color:#323232;">);
</span></pre>
</div></div><div class="code-block-wrapper"><div data-code-theme="dark"><pre style="background-color:#2d2d2d;">
<span style="color:#747369;">// クライアント
</span><span style="color:#d3d0c8;">httplib::Client </span><span style="color:#6699cc;">cli</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">http://localhost</span><span style="color:#d3d0c8;">&quot;);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_address_family</span><span style="color:#d3d0c8;">(AF_UNIX);
</span><span style="color:#d3d0c8;">cli.</span><span style="color:#6699cc;">set_hostname_addr_map</span><span style="color:#d3d0c8;">({{&quot;</span><span style="color:#99cc99;">localhost</span><span style="color:#d3d0c8;">&quot;, &quot;</span><span style="color:#99cc99;">/tmp/httplib.sock</span><span style="color:#d3d0c8;">&quot;}});
</span><span style="color:#d3d0c8;">
</span><span style="color:#cc99cc;">auto</span><span style="color:#d3d0c8;"> res = cli.</span><span style="color:#6699cc;">Get</span><span style="color:#d3d0c8;">(&quot;</span><span style="color:#99cc99;">/</span><span style="color:#d3d0c8;">&quot;);
</span></pre>
</div><div data-code-theme="light"><pre style="background-color:#ffffff;">
<span style="font-style:italic;color:#969896;">// クライアント
</span><span style="color:#323232;">httplib::Client </span><span style="font-weight:bold;color:#795da3;">cli</span><span style="color:#323232;">(</span><span style="color:#183691;">&quot;http://localhost&quot;</span><span style="color:#323232;">);
</span><span style="color:#323232;">cli.set_address_family(AF_UNIX);
</span><span style="color:#323232;">cli.set_hostname_addr_map({{</span><span style="color:#183691;">&quot;localhost&quot;</span><span style="color:#323232;">, </span><span style="color:#183691;">&quot;/tmp/httplib.sock&quot;</span><span style="color:#323232;">}});
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">auto</span><span style="color:#323232;"> res </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> cli.Get(</span><span style="color:#183691;">&quot;/&quot;</span><span style="color:#323232;">);
</span></pre>
</div></div>
<h2>さらに詳しく</h2>
<p>もっと詳しく知りたいときは、以下を参照してください。</p>
<ul>
<li>Cookbook — よくあるユースケースのレシピ集</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README.md">README</a> — 全APIのリファレンス</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-sse.md">README-sse</a> — Server-Sent Eventsの使い方</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-stream.md">README-stream</a> — Streaming APIの使い方</li>
<li><a href="https://github.com/yhirose/cpp-httplib/blob/master/README-websocket.md">README-websocket</a> — WebSocketサーバーの使い方</li>
</ul>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-141
View File
@@ -1,141 +0,0 @@
<!DOCTYPE html>
<html lang="ja" data-base-path="&#x2F;cpp-httplib">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A Tour of cpp-httplib - cpp-httplib</title>
<link rel="icon" type="image/svg+xml" href="&#x2F;cpp-httplib/favicon.svg">
<link rel="stylesheet" href="&#x2F;cpp-httplib/css/main.css">
<script>
(function() {
var t = localStorage.getItem('preferred-theme');
if (!t) t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
</head>
<body>
<header class="header">
<div class="header-inner">
<a href="&#x2F;cpp-httplib/ja/" class="header-title">cpp-httplib <span style="font-size:0.75em;font-weight:normal;margin-left:4px">v0.35.0</span></a>
<div class="header-spacer"></div>
<nav class="header-nav">
<a href="&#x2F;cpp-httplib/ja/">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Home
</a>
<a href="&#x2F;cpp-httplib/ja/tour&#x2F;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>
Tour
</a>
<a href="https:&#x2F;&#x2F;github.com&#x2F;yhirose&#x2F;cpp-httplib" aria-label="GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
GitHub
</a>
</nav>
<div class="header-tools">
<button class="search-btn" aria-label="Search (⌘K)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
</button>
<button class="theme-toggle" aria-label="Toggle theme"></button>
<div class="lang-selector">
<button class="lang-btn" aria-label="Language">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
JA
</button>
<ul class="lang-popup">
<li><a href="#" data-lang="en">EN</a></li>
<li><a href="#" data-lang="ja">JA</a></li>
</ul>
</div>
</div>
<button class="sidebar-toggle" aria-label="Menu">&#9776;</button>
</div>
</header>
<div class="layout has-sidebar">
<aside class="sidebar">
<nav class="sidebar-nav">
<div class="nav-section">
<a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;" class="nav-section-title active">A Tour of cpp-httplib</a>
<ul class="nav-list">
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;01-getting-started&#x2F;" class="">Getting Started</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;02-basic-client&#x2F;" class="">Basic Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;03-basic-server&#x2F;" class="">Basic Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;04-static-file-server&#x2F;" class="">Static File Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;05-tls-setup&#x2F;" class="">TLS Setup</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;06-https-client&#x2F;" class="">HTTPS Client</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;07-https-server&#x2F;" class="">HTTPS Server</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;08-websocket&#x2F;" class="">WebSocket</a></li>
<li><a href="&#x2F;cpp-httplib&#x2F;ja&#x2F;tour&#x2F;09-whats-next&#x2F;" class="">What&#x27;s Next</a></li>
</ul>
</div>
</nav>
</aside>
<main class="content">
<article>
<h1>A Tour of cpp-httplib</h1>
<p>cpp-httplibの基本を、順番に学んでいくチュートリアルです。各章は前の章の内容を踏まえて進む構成なので、1章から順に読んでください。</p>
<ol>
<li><a href="01-getting-started">Getting Started</a> — httplib.h の入手とHello Worldサーバー</li>
<li><a href="02-basic-client">Basic Client</a> — GET/POST・パスパラメーターのリクエスト送信</li>
<li><a href="03-basic-server">Basic Server</a> — ルーティング、パスパラメーター、レスポンスの組み立て</li>
<li><a href="04-static-file-server">Static File Server</a> — 静的ファイルの配信</li>
<li><a href="05-tls-setup">TLS Setup</a> — OpenSSL / mbedTLS のセットアップ</li>
<li><a href="06-https-client">HTTPS Client</a> — HTTPSサイトへのリクエスト</li>
<li><a href="07-https-server">HTTPS Server</a> — HTTPSサーバーの構築</li>
<li><a href="08-websocket">WebSocket</a> — WebSocket通信の基本</li>
<li><a href="09-whats-next">What's Next</a> — さらなる機能の紹介</li>
</ol>
</article>
</main>
</div>
<footer class="footer">
&copy; 2026 yhirose. All rights reserved.
</footer>
<!-- Search modal -->
<div class="search-overlay" id="search-overlay">
<div class="search-modal">
<div class="search-input-wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
<input type="text" id="search-input" placeholder="Search..." autocomplete="off" spellcheck="false">
<kbd class="search-esc">ESC</kbd>
</div>
<ul class="search-results" id="search-results"></ul>
</div>
</div>
<script src="&#x2F;cpp-httplib/js/main.js"></script>
</body>
</html>
-297
View File
@@ -1,297 +0,0 @@
// Language selector
(function () {
var btn = document.querySelector('.lang-btn');
var popup = document.querySelector('.lang-popup');
if (!btn || !popup) return;
btn.addEventListener('click', function (e) {
e.stopPropagation();
popup.classList.toggle('open');
});
document.addEventListener('click', function () {
popup.classList.remove('open');
});
popup.addEventListener('click', function (e) {
var link = e.target.closest('[data-lang]');
if (!link) return;
e.preventDefault();
var lang = link.getAttribute('data-lang');
localStorage.setItem('preferred-lang', lang);
var basePath = document.documentElement.getAttribute('data-base-path') || '';
var path = window.location.pathname;
// Strip base path prefix, replace lang, then re-add base path
var pathWithoutBase = path.slice(basePath.length);
var newPath = basePath + pathWithoutBase.replace(/^\/[a-z]{2}\//, '/' + lang + '/');
window.location.href = newPath;
});
})();
// Theme toggle
(function () {
var btn = document.querySelector('.theme-toggle');
if (!btn) return;
// Feather Icons: sun (light mode) and moon (dark mode)
var sunSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>';
var moonSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
function getTheme() {
var stored = localStorage.getItem('preferred-theme');
if (stored) return stored;
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
}
function applyTheme(theme) {
if (theme === 'light') {
document.documentElement.setAttribute('data-theme', 'light');
} else {
document.documentElement.removeAttribute('data-theme');
}
btn.innerHTML = theme === 'light' ? sunSVG : moonSVG;
}
applyTheme(getTheme());
btn.addEventListener('click', function () {
var current = getTheme();
var next = current === 'dark' ? 'light' : 'dark';
localStorage.setItem('preferred-theme', next);
applyTheme(next);
});
})();
// Mobile sidebar toggle
(function () {
var toggle = document.querySelector('.sidebar-toggle');
var sidebar = document.querySelector('.sidebar');
if (!toggle || !sidebar) return;
toggle.addEventListener('click', function () {
sidebar.classList.toggle('open');
});
document.addEventListener('click', function (e) {
if (!sidebar.contains(e.target) && e.target !== toggle) {
sidebar.classList.remove('open');
}
});
})();
// Site search (⌘K / Ctrl+K)
(function () {
var overlay = document.getElementById('search-overlay');
var input = document.getElementById('search-input');
var resultsList = document.getElementById('search-results');
if (!overlay || !input || !resultsList) return;
var searchBtn = document.querySelector('.search-btn');
var pagesData = null; // cached pages-data.json
var activeIndex = -1;
function getCurrentLang() {
return document.documentElement.getAttribute('lang') || 'en';
}
function getBasePath() {
return document.documentElement.getAttribute('data-base-path') || '';
}
function openSearch() {
overlay.classList.add('open');
input.value = '';
resultsList.innerHTML = '';
activeIndex = -1;
input.focus();
loadPagesData();
}
function closeSearch() {
overlay.classList.remove('open');
input.value = '';
resultsList.innerHTML = '';
activeIndex = -1;
}
function loadPagesData() {
if (pagesData) return;
var basePath = getBasePath();
fetch(basePath + '/pages-data.json')
.then(function (res) { return res.json(); })
.then(function (data) { pagesData = data; })
.catch(function () { pagesData = []; });
}
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function highlightText(text, query) {
if (!query) return text;
var escaped = escapeRegExp(query);
var re = new RegExp('(' + escaped + ')', 'gi');
return text.replace(re, '<mark>$1</mark>');
}
function buildSnippet(body, query) {
if (!query || !body) return '';
var lower = body.toLowerCase();
var idx = lower.indexOf(query.toLowerCase());
var start, end, snippet;
if (idx === -1) {
snippet = body.substring(0, 120);
} else {
start = Math.max(0, idx - 40);
end = Math.min(body.length, idx + query.length + 80);
snippet = (start > 0 ? '...' : '') + body.substring(start, end) + (end < body.length ? '...' : '');
}
return highlightText(snippet, query);
}
function search(query) {
if (!pagesData || !query) {
resultsList.innerHTML = '';
activeIndex = -1;
return;
}
var lang = getCurrentLang();
var q = query.toLowerCase();
// Score and filter
var scored = [];
for (var i = 0; i < pagesData.length; i++) {
var page = pagesData[i];
if (page.lang !== lang) continue;
var score = 0;
var titleLower = page.title.toLowerCase();
var bodyLower = (page.body || '').toLowerCase();
if (titleLower.indexOf(q) !== -1) {
score += 10;
// Bonus for exact title match
if (titleLower === q) score += 5;
}
if (bodyLower.indexOf(q) !== -1) {
score += 3;
}
if (page.section.toLowerCase().indexOf(q) !== -1) {
score += 1;
}
if (score > 0) {
scored.push({ page: page, score: score });
}
}
// Sort by score descending
scored.sort(function (a, b) { return b.score - a.score; });
// Limit results
var results = scored.slice(0, 20);
if (results.length === 0) {
resultsList.innerHTML = '<li class="search-no-results">No results found.</li>';
activeIndex = -1;
return;
}
var html = '';
for (var j = 0; j < results.length; j++) {
var r = results[j];
var snippet = buildSnippet(r.page.body, query);
html += '<li data-url="' + r.page.url + '">'
+ '<div class="search-result-title">' + highlightText(r.page.title, query) + '</div>'
+ (snippet ? '<div class="search-result-snippet">' + snippet + '</div>' : '')
+ '</li>';
}
resultsList.innerHTML = html;
activeIndex = -1;
}
function setActive(index) {
var items = resultsList.querySelectorAll('li[data-url]');
if (items.length === 0) return;
// Remove previous active
for (var i = 0; i < items.length; i++) {
items[i].classList.remove('active');
}
if (index < 0) index = items.length - 1;
if (index >= items.length) index = 0;
activeIndex = index;
items[activeIndex].classList.add('active');
items[activeIndex].scrollIntoView({ block: 'nearest' });
}
function navigateToActive() {
var items = resultsList.querySelectorAll('li[data-url]');
if (activeIndex >= 0 && activeIndex < items.length) {
var url = items[activeIndex].getAttribute('data-url');
if (url) {
closeSearch();
window.location.href = url;
}
}
}
// Event: search button
if (searchBtn) {
searchBtn.addEventListener('click', function (e) {
e.stopPropagation();
openSearch();
});
}
// Use capture phase to intercept keys before browser default behavior
// (e.g. ESC clearing input text in some browsers)
document.addEventListener('keydown', function (e) {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
overlay.classList.contains('open') ? closeSearch() : openSearch();
return;
}
if (!overlay.classList.contains('open')) return;
if (e.key === 'Escape') {
e.preventDefault();
closeSearch();
} else if (e.key === 'ArrowDown') {
e.preventDefault();
setActive(activeIndex + 1);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setActive(activeIndex - 1);
} else if (e.key === 'Enter') {
e.preventDefault();
navigateToActive();
}
}, true); // capture phase
// Event: click overlay background to close
overlay.addEventListener('click', function (e) {
if (e.target === overlay) {
closeSearch();
}
});
// Event: click result item
resultsList.addEventListener('click', function (e) {
var li = e.target.closest('li[data-url]');
if (!li) return;
var url = li.getAttribute('data-url');
if (url) {
closeSearch();
window.location.href = url;
}
});
// Event: input for live search
var debounceTimer = null;
input.addEventListener('input', function () {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(function () {
search(input.value.trim());
}, 150);
});
})();
File diff suppressed because one or more lines are too long
+395 -180
View File
@@ -8,28 +8,8 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.35.0"
#define CPPHTTPLIB_VERSION_NUM "0x002300"
/*
* Platform compatibility check
*/
#if defined(_WIN32) && !defined(_WIN64)
#if defined(_MSC_VER)
#pragma message( \
"cpp-httplib doesn't support 32-bit Windows. Please use a 64-bit compiler.")
#else
#warning \
"cpp-httplib doesn't support 32-bit Windows. Please use a 64-bit compiler."
#endif
#elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ < 8
#warning \
"cpp-httplib doesn't support 32-bit platforms. Please use a 64-bit compiler."
#elif defined(__SIZEOF_SIZE_T__) && __SIZEOF_SIZE_T__ < 8
#warning \
"cpp-httplib doesn't support platforms where size_t is less than 64 bits."
#endif
#define CPPHTTPLIB_VERSION "0.38.0"
#define CPPHTTPLIB_VERSION_NUM "0x002600"
#ifdef _WIN32
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00
@@ -709,6 +689,18 @@ inline from_chars_result<double> from_chars(const char *first, const char *last,
return {first + (endptr - s.c_str()), std::errc{}};
}
inline bool parse_port(const char *s, size_t len, int &port) {
int val = 0;
auto r = from_chars(s, s + len, val);
if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; }
port = val;
return true;
}
inline bool parse_port(const std::string &s, int &port) {
return parse_port(s.data(), s.size(), port);
}
} // namespace detail
enum SSLVerifierResponse {
@@ -1678,6 +1670,11 @@ public:
Server &set_payload_max_length(size_t length);
Server &set_websocket_ping_interval(time_t sec);
template <class Rep, class Period>
Server &set_websocket_ping_interval(
const std::chrono::duration<Rep, Period> &duration);
bool bind_to_port(const std::string &host, int port, int socket_flags = 0);
int bind_to_any_port(const std::string &host, int socket_flags = 0);
bool listen_after_bind();
@@ -1712,6 +1709,8 @@ protected:
time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
time_t websocket_ping_interval_sec_ =
CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND;
private:
using Handlers =
@@ -1781,6 +1780,7 @@ private:
struct MountPointEntry {
std::string mount_point;
std::string base_dir;
std::string resolved_base_dir;
Headers headers;
};
std::vector<MountPointEntry> base_dirs_;
@@ -2198,6 +2198,10 @@ protected:
virtual bool create_and_connect_socket(Socket &socket, Error &error);
virtual bool ensure_socket_connection(Socket &socket, Error &error);
virtual bool setup_proxy_connection(
Socket &socket,
std::chrono::time_point<std::chrono::steady_clock> start_time,
Response &res, bool &success, Error &error);
// All of:
// shutdown_ssl
@@ -2724,6 +2728,10 @@ private:
std::function<bool(Stream &strm)> callback) override;
bool is_ssl() const override;
bool setup_proxy_connection(
Socket &socket,
std::chrono::time_point<std::chrono::steady_clock> start_time,
Response &res, bool &success, Error &error) override;
bool connect_with_proxy(
Socket &sock,
std::chrono::time_point<std::chrono::steady_clock> start_time,
@@ -2801,7 +2809,7 @@ inline size_t get_header_value_u64(const Headers &headers,
std::advance(it, static_cast<ssize_t>(id));
if (it != rng.second) {
if (is_numeric(it->second)) {
return std::strtoull(it->second.data(), nullptr, 10);
return static_cast<size_t>(std::strtoull(it->second.data(), nullptr, 10));
} else {
is_invalid_value = true;
}
@@ -2923,6 +2931,8 @@ std::string encode_query_component(const std::string &component,
std::string decode_query_component(const std::string &component,
bool plus_as_space = true);
std::string sanitize_filename(const std::string &filename);
std::string append_query_params(const std::string &path, const Params &params);
std::pair<std::string, std::string> make_range_header(const Ranges &ranges);
@@ -3726,15 +3736,19 @@ private:
friend class httplib::Server;
friend class WebSocketClient;
WebSocket(Stream &strm, const Request &req, bool is_server)
: strm_(strm), req_(req), is_server_(is_server) {
WebSocket(
Stream &strm, const Request &req, bool is_server,
time_t ping_interval_sec = CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND)
: strm_(strm), req_(req), is_server_(is_server),
ping_interval_sec_(ping_interval_sec) {
start_heartbeat();
}
WebSocket(std::unique_ptr<Stream> &&owned_strm, const Request &req,
bool is_server)
WebSocket(
std::unique_ptr<Stream> &&owned_strm, const Request &req, bool is_server,
time_t ping_interval_sec = CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND)
: strm_(*owned_strm), owned_strm_(std::move(owned_strm)), req_(req),
is_server_(is_server) {
is_server_(is_server), ping_interval_sec_(ping_interval_sec) {
start_heartbeat();
}
@@ -3745,6 +3759,7 @@ private:
std::unique_ptr<Stream> owned_strm_;
Request req_;
bool is_server_;
time_t ping_interval_sec_;
std::atomic<bool> closed_{false};
std::mutex write_mutex_;
std::thread ping_thread_;
@@ -3773,6 +3788,7 @@ public:
const std::string &subprotocol() const;
void set_read_timeout(time_t sec, time_t usec = 0);
void set_write_timeout(time_t sec, time_t usec = 0);
void set_websocket_ping_interval(time_t sec);
#ifdef CPPHTTPLIB_SSL_ENABLED
void set_ca_cert_path(const std::string &path);
@@ -3796,6 +3812,8 @@ private:
time_t read_timeout_usec_ = 0;
time_t write_timeout_sec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND;
time_t write_timeout_usec_ = CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND;
time_t websocket_ping_interval_sec_ =
CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND;
#ifdef CPPHTTPLIB_SSL_ENABLED
bool is_ssl_ = false;
@@ -4842,6 +4860,30 @@ inline bool is_valid_path(const std::string &path) {
return true;
}
inline bool canonicalize_path(const char *path, std::string &resolved) {
#if defined(_WIN32)
char buf[_MAX_PATH];
if (_fullpath(buf, path, _MAX_PATH) == nullptr) { return false; }
resolved = buf;
#else
char buf[PATH_MAX];
if (realpath(path, buf) == nullptr) { return false; }
resolved = buf;
#endif
return true;
}
inline bool is_path_within_base(const std::string &resolved_path,
const std::string &resolved_base) {
#if defined(_WIN32)
return _strnicmp(resolved_path.c_str(), resolved_base.c_str(),
resolved_base.size()) == 0;
#else
return strncmp(resolved_path.c_str(), resolved_base.c_str(),
resolved_base.size()) == 0;
#endif
}
inline FileStat::FileStat(const std::string &path) {
#if defined(_WIN32)
auto wpath = u8string_to_wstring(path.c_str());
@@ -5812,9 +5854,9 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
memcpy((*current)->ai_addr, sockaddr_ptr, sockaddr_len);
// Set port if service is specified
if (service && strlen(service) > 0) {
int port = atoi(service);
if (port > 0) {
if (service && *service) {
int port = 0;
if (parse_port(service, strlen(service), port)) {
if (sockaddr_ptr->sa_family == AF_INET) {
reinterpret_cast<struct sockaddr_in *>((*current)->ai_addr)
->sin_port = htons(static_cast<uint16_t>(port));
@@ -6444,33 +6486,114 @@ inline bool can_compress_content_type(const std::string &content_type) {
}
}
inline bool parse_quality(const char *b, const char *e, std::string &token,
double &quality) {
quality = 1.0;
token.clear();
// Split on first ';': left = token name, right = parameters
const char *params_b = nullptr;
std::size_t params_len = 0;
divide(
b, static_cast<std::size_t>(e - b), ';',
[&](const char *lb, std::size_t llen, const char *rb, std::size_t rlen) {
auto r = trim(lb, lb + llen, 0, llen);
if (r.first < r.second) { token.assign(lb + r.first, lb + r.second); }
params_b = rb;
params_len = rlen;
});
if (token.empty()) { return false; }
if (params_len == 0) { return true; }
// Scan parameters for q= (stops on first match)
bool invalid = false;
split_find(params_b, params_b + params_len, ';',
(std::numeric_limits<size_t>::max)(),
[&](const char *pb, const char *pe) -> bool {
// Match exactly "q=" or "Q=" (not "query=" etc.)
auto len = static_cast<size_t>(pe - pb);
if (len < 2) { return false; }
if ((pb[0] != 'q' && pb[0] != 'Q') || pb[1] != '=') {
return false;
}
// Trim the value portion
auto r = trim(pb, pe, 2, len);
if (r.first >= r.second) {
invalid = true;
return true;
}
double v = 0.0;
auto res = from_chars(pb + r.first, pb + r.second, v);
if (res.ec != std::errc{} || v < 0.0 || v > 1.0) {
invalid = true;
return true;
}
quality = v;
return true;
});
return !invalid;
}
inline EncodingType encoding_type(const Request &req, const Response &res) {
auto ret =
detail::can_compress_content_type(res.get_header_value("Content-Type"));
if (!ret) { return EncodingType::None; }
if (!can_compress_content_type(res.get_header_value("Content-Type"))) {
return EncodingType::None;
}
const auto &s = req.get_header_value("Accept-Encoding");
(void)(s);
if (s.empty()) { return EncodingType::None; }
// Single-pass: iterate tokens and track the best supported encoding.
// Server preference breaks ties (br > gzip > zstd).
EncodingType best = EncodingType::None;
double best_q = 0.0; // q=0 means "not acceptable"
// Server preference: Brotli > Gzip > Zstd (lower = more preferred)
auto priority = [](EncodingType t) -> int {
switch (t) {
case EncodingType::Brotli: return 0;
case EncodingType::Gzip: return 1;
case EncodingType::Zstd: return 2;
default: return 3;
}
};
std::string name;
split(s.data(), s.data() + s.size(), ',', [&](const char *b, const char *e) {
double quality = 1.0;
if (!parse_quality(b, e, name, quality)) { return; }
if (quality <= 0.0) { return; }
EncodingType type = EncodingType::None;
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
// TODO: 'Accept-Encoding' has br, not br;q=0
ret = s.find("br") != std::string::npos;
if (ret) { return EncodingType::Brotli; }
if (case_ignore::equal(name, "br")) { type = EncodingType::Brotli; }
#endif
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
// TODO: 'Accept-Encoding' has gzip, not gzip;q=0
ret = s.find("gzip") != std::string::npos;
if (ret) { return EncodingType::Gzip; }
if (type == EncodingType::None && case_ignore::equal(name, "gzip")) {
type = EncodingType::Gzip;
}
#endif
#ifdef CPPHTTPLIB_ZSTD_SUPPORT
// TODO: 'Accept-Encoding' has zstd, not zstd;q=0
ret = s.find("zstd") != std::string::npos;
if (ret) { return EncodingType::Zstd; }
if (type == EncodingType::None && case_ignore::equal(name, "zstd")) {
type = EncodingType::Zstd;
}
#endif
return EncodingType::None;
if (type == EncodingType::None) { return; }
// Higher q-value wins; for equal q, server preference breaks ties
if (quality > best_q ||
(quality == best_q && priority(type) < priority(best))) {
best_q = quality;
best = type;
}
});
return best;
}
inline bool nocompressor::compress(const char *data, size_t data_length,
@@ -6754,6 +6877,21 @@ create_decompressor(const std::string &encoding) {
return decompressor;
}
// Returns the best available compressor and its Content-Encoding name.
// Priority: Brotli > Gzip > Zstd (matches server-side preference).
inline std::pair<std::unique_ptr<compressor>, const char *>
create_compressor() {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
return {detail::make_unique<brotli_compressor>(), "br"};
#elif defined(CPPHTTPLIB_ZLIB_SUPPORT)
return {detail::make_unique<gzip_compressor>(), "gzip"};
#elif defined(CPPHTTPLIB_ZSTD_SUPPORT)
return {detail::make_unique<zstd_compressor>(), "zstd"};
#else
return {nullptr, nullptr};
#endif
}
inline bool is_prohibited_header_name(const std::string &name) {
using udl::operator""_t;
@@ -6833,6 +6971,16 @@ inline bool read_headers(Stream &strm, Headers &headers) {
header_count++;
}
// RFC 9110 Section 8.6: Reject requests with multiple Content-Length
// headers that have different values to prevent request smuggling.
auto cl_range = headers.equal_range("Content-Length");
if (cl_range.first != cl_range.second) {
const auto &first_val = cl_range.first->second;
for (auto it = std::next(cl_range.first); it != cl_range.second; ++it) {
if (it->second != first_val) { return false; }
}
}
return true;
}
@@ -7576,7 +7724,7 @@ inline bool parse_accept_header(const std::string &s,
struct AcceptEntry {
std::string media_type;
double quality;
int order; // Original order in header
int order;
};
std::vector<AcceptEntry> entries;
@@ -7594,48 +7742,12 @@ inline bool parse_accept_header(const std::string &s,
}
AcceptEntry accept_entry;
accept_entry.quality = 1.0; // Default quality
accept_entry.order = order++;
// Find q= parameter
auto q_pos = entry.find(";q=");
if (q_pos == std::string::npos) { q_pos = entry.find("; q="); }
if (q_pos != std::string::npos) {
// Extract media type (before q parameter)
accept_entry.media_type = trim_copy(entry.substr(0, q_pos));
// Extract quality value
auto q_start = entry.find('=', q_pos) + 1;
auto q_end = entry.find(';', q_start);
if (q_end == std::string::npos) { q_end = entry.length(); }
std::string quality_str =
trim_copy(entry.substr(q_start, q_end - q_start));
if (quality_str.empty()) {
has_invalid_entry = true;
return;
}
{
double v = 0.0;
auto res = detail::from_chars(
quality_str.data(), quality_str.data() + quality_str.size(), v);
if (res.ec == std::errc{}) {
accept_entry.quality = v;
} else {
has_invalid_entry = true;
return;
}
}
// Check if quality is in valid range [0.0, 1.0]
if (accept_entry.quality < 0.0 || accept_entry.quality > 1.0) {
has_invalid_entry = true;
return;
}
} else {
// No quality parameter, use entire entry as media type
accept_entry.media_type = entry;
if (!parse_quality(entry.data(), entry.data() + entry.size(),
accept_entry.media_type, accept_entry.quality)) {
has_invalid_entry = true;
return;
}
// Remove additional parameters from media type
@@ -7748,14 +7860,10 @@ public:
file_.content_type =
trim_copy(header.substr(str_len(header_content_type)));
} else {
thread_local const std::regex re_content_disposition(
R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
std::regex_constants::icase);
std::smatch m;
if (std::regex_match(header, m, re_content_disposition)) {
std::string disposition_params;
if (parse_content_disposition(header, disposition_params)) {
Params params;
parse_disposition_params(m[1], params);
parse_disposition_params(disposition_params, params);
auto it = params.find("name");
if (it != params.end()) {
@@ -7772,10 +7880,10 @@ public:
if (it != params.end()) {
// RFC 5987: only UTF-8 encoding is allowed
const auto &val = it->second;
constexpr size_t prefix_len = 7; // length of "UTF-8''"
constexpr const char utf8_prefix[] = "UTF-8''";
constexpr size_t prefix_len = str_len(utf8_prefix);
if (val.size() > prefix_len &&
case_ignore::to_lower(val.substr(0, prefix_len)) ==
"utf-8''") {
start_with_case_ignore(val, utf8_prefix)) {
file_.filename = decode_path_component(
val.substr(prefix_len)); // override...
} else {
@@ -7845,17 +7953,48 @@ private:
file_.headers.clear();
}
bool start_with_case_ignore(const std::string &a, const char *b) const {
bool start_with_case_ignore(const std::string &a, const char *b,
size_t offset = 0) const {
const auto b_len = strlen(b);
if (a.size() < b_len) { return false; }
if (a.size() < offset + b_len) { return false; }
for (size_t i = 0; i < b_len; i++) {
if (case_ignore::to_lower(a[i]) != case_ignore::to_lower(b[i])) {
if (case_ignore::to_lower(a[offset + i]) != case_ignore::to_lower(b[i])) {
return false;
}
}
return true;
}
// Parses "Content-Disposition: form-data; <params>" without std::regex.
// Returns true if header matches, with the params portion in `params_out`.
bool parse_content_disposition(const std::string &header,
std::string &params_out) const {
constexpr const char prefix[] = "Content-Disposition:";
constexpr size_t prefix_len = str_len(prefix);
if (!start_with_case_ignore(header, prefix)) { return false; }
// Skip whitespace after "Content-Disposition:"
auto pos = prefix_len;
while (pos < header.size() && (header[pos] == ' ' || header[pos] == '\t')) {
pos++;
}
// Match "form-data;" (case-insensitive)
constexpr const char form_data[] = "form-data;";
constexpr size_t form_data_len = str_len(form_data);
if (!start_with_case_ignore(header, form_data, pos)) { return false; }
pos += form_data_len;
// Skip whitespace after "form-data;"
while (pos < header.size() && (header[pos] == ' ' || header[pos] == '\t')) {
pos++;
}
params_out = header.substr(pos);
return true;
}
const std::string dash_ = "--";
const std::string crlf_ = "\r\n";
std::string boundary_;
@@ -8214,7 +8353,8 @@ get_range_offset_and_length(Range r, size_t content_length) {
assert(r.first <= r.second &&
r.second < static_cast<ssize_t>(content_length));
(void)(content_length);
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
return std::make_pair(static_cast<size_t>(r.first),
static_cast<size_t>(r.second - r.first) + 1);
}
inline std::string make_content_range_header_field(
@@ -9260,7 +9400,8 @@ inline std::string decode_path_component(const std::string &component) {
// Unicode %uXXXX encoding
auto val = 0;
if (detail::from_hex_to_i(component, i + 2, 4, val)) {
// 4 digits Unicode codes
// 4 digits Unicode codes: val is 0x0000-0xFFFF (from 4 hex digits),
// so to_utf8 writes at most 3 bytes. buff[4] is safe.
char buff[4];
size_t len = detail::to_utf8(val, buff);
if (len > 0) { result.append(buff, len); }
@@ -9365,6 +9506,30 @@ inline std::string decode_query_component(const std::string &component,
return result;
}
inline std::string sanitize_filename(const std::string &filename) {
// Extract basename: find the last path separator (/ or \)
auto pos = filename.find_last_of("/\\");
auto result =
(pos != std::string::npos) ? filename.substr(pos + 1) : filename;
// Strip null bytes
result.erase(std::remove(result.begin(), result.end(), '\0'), result.end());
// Trim whitespace
{
auto start = result.find_first_not_of(" \t");
auto end = result.find_last_not_of(" \t");
result = (start == std::string::npos)
? ""
: result.substr(start, end - start + 1);
}
// Reject . and ..
if (result == "." || result == "..") { return ""; }
return result;
}
inline std::string append_query_params(const std::string &path,
const Params &params) {
std::string path_with_query = path;
@@ -10493,7 +10658,18 @@ inline bool Server::set_mount_point(const std::string &mount_point,
if (stat.is_dir()) {
std::string mnt = !mount_point.empty() ? mount_point : "/";
if (!mnt.empty() && mnt[0] == '/') {
base_dirs_.push_back({std::move(mnt), dir, std::move(headers)});
std::string resolved_base;
if (detail::canonicalize_path(dir.c_str(), resolved_base)) {
#if defined(_WIN32)
if (resolved_base.back() != '\\' && resolved_base.back() != '/') {
resolved_base += '\\';
}
#else
if (resolved_base.back() != '/') { resolved_base += '/'; }
#endif
}
base_dirs_.push_back(
{std::move(mnt), dir, std::move(resolved_base), std::move(headers)});
return true;
}
}
@@ -10653,6 +10829,20 @@ inline Server &Server::set_payload_max_length(size_t length) {
return *this;
}
inline Server &Server::set_websocket_ping_interval(time_t sec) {
websocket_ping_interval_sec_ = sec;
return *this;
}
template <class Rep, class Period>
inline Server &Server::set_websocket_ping_interval(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t /*usec*/) {
set_websocket_ping_interval(sec);
});
return *this;
}
inline bool Server::bind_to_port(const std::string &host, int port,
int socket_flags) {
auto ret = bind_internal(host, port, socket_flags);
@@ -11073,6 +11263,18 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
auto path = entry.base_dir + sub_path;
if (path.back() == '/') { path += "index.html"; }
// Defense-in-depth: is_valid_path blocks ".." traversal in the URL,
// but symlinks/junctions can still escape the base directory.
if (!entry.resolved_base_dir.empty()) {
std::string resolved_path;
if (detail::canonicalize_path(path.c_str(), resolved_path) &&
!detail::is_path_within_base(resolved_path,
entry.resolved_base_dir)) {
res.status = StatusCode::Forbidden_403;
return true;
}
}
detail::FileStat stat(path);
if (stat.is_dir()) {
@@ -11311,6 +11513,10 @@ inline bool Server::listen_internal() {
detail::set_socket_opt_time(sock, SOL_SOCKET, SO_SNDTIMEO,
write_timeout_sec_, write_timeout_usec_);
if (tcp_nodelay_) {
detail::set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
}
if (!task_queue->enqueue(
[this, sock]() { process_and_close_socket(sock); })) {
output_error_log(Error::ResourceExhaustion, nullptr);
@@ -11787,7 +11993,7 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
{
// Use WebSocket-specific read timeout instead of HTTP timeout
strm.set_read_timeout(CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND, 0);
ws::WebSocket ws(strm, req, true);
ws::WebSocket ws(strm, req, true, websocket_ping_interval_sec_);
entry.handler(req, ws);
}
return true;
@@ -12031,6 +12237,13 @@ inline bool ClientImpl::ensure_socket_connection(Socket &socket, Error &error) {
return create_and_connect_socket(socket, error);
}
inline bool ClientImpl::setup_proxy_connection(
Socket & /*socket*/,
std::chrono::time_point<std::chrono::steady_clock> /*start_time*/,
Response & /*res*/, bool & /*success*/, Error & /*error*/) {
return true;
}
inline void ClientImpl::shutdown_ssl(Socket & /*socket*/,
bool /*shutdown_gracefully*/) {
// If there are any requests in flight from threads other than us, then it's
@@ -12152,27 +12365,14 @@ inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
return false;
}
#ifdef CPPHTTPLIB_SSL_ENABLED
// TODO: refactoring
if (is_ssl()) {
auto &scli = static_cast<SSLClient &>(*this);
if (!proxy_host_.empty() && proxy_port_ != -1) {
auto success = false;
if (!scli.connect_with_proxy(socket_, req.start_time_, res, success,
error)) {
if (!success) { output_error_log(error, &req); }
return success;
}
}
if (!proxy_host_.empty() && proxy_port_ != -1) {
if (!scli.initialize_ssl(socket_, error)) {
output_error_log(error, &req);
return false;
}
{
auto success = true;
if (!setup_proxy_connection(socket_, req.start_time_, res, success,
error)) {
if (!success) { output_error_log(error, &req); }
return success;
}
}
#endif
}
// Mark the current socket as being in use so that it cannot be closed by
@@ -12333,17 +12533,15 @@ ClientImpl::open_stream(const std::string &method, const std::string &path,
return handle;
}
#ifdef CPPHTTPLIB_SSL_ENABLED
if (is_ssl()) {
auto &scli = static_cast<SSLClient &>(*this);
if (!proxy_host_.empty() && proxy_port_ != -1) {
if (!scli.initialize_ssl(socket_, handle.error)) {
handle.response.reset();
return handle;
}
{
auto success = true;
auto start_time = std::chrono::steady_clock::now();
if (!setup_proxy_connection(socket_, start_time, *handle.response,
success, handle.error)) {
if (!success) { handle.response.reset(); }
return handle;
}
}
#endif
}
transfer_socket_ownership_to_handle(handle);
@@ -12406,11 +12604,17 @@ ClientImpl::open_stream(const std::string &method, const std::string &path,
handle.body_reader_.stream = handle.stream_;
handle.body_reader_.payload_max_length = payload_max_length_;
auto content_length_str = handle.response->get_header_value("Content-Length");
if (!content_length_str.empty()) {
if (handle.response->has_header("Content-Length")) {
bool is_invalid = false;
auto content_length = detail::get_header_value_u64(
handle.response->headers, "Content-Length", 0, 0, is_invalid);
if (is_invalid) {
handle.error = Error::Read;
handle.response.reset();
return handle;
}
handle.body_reader_.has_content_length = true;
handle.body_reader_.content_length =
static_cast<size_t>(std::stoull(content_length_str));
handle.body_reader_.content_length = content_length;
}
auto transfer_encoding =
@@ -12616,7 +12820,7 @@ inline bool ClientImpl::handle_request(Stream &strm, Request &req,
if (res.get_header_value("Connection") == "close" ||
(res.version == "HTTP/1.0" && res.reason != "Connection established")) {
// TODO this requires a not-entirely-obvious chain of calls to be correct
// NOTE: this requires a not-entirely-obvious chain of calls to be correct
// for this to be safe.
// This is safe to call because handle_request is only called by send_
@@ -12694,7 +12898,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
auto next_port = port_;
if (!port_str.empty()) {
next_port = std::stoi(port_str);
if (!detail::parse_port(port_str, next_port)) { return false; }
} else if (!next_scheme.empty()) {
next_port = next_scheme == "https" ? 443 : 80;
}
@@ -12745,18 +12949,10 @@ inline bool ClientImpl::create_redirect_client(
// Setup basic client configuration first
setup_redirect_client(redirect_client);
// SSL-specific configuration for proxy environments
if (!proxy_host_.empty() && proxy_port_ != -1) {
// Critical: Disable SSL verification for proxy environments
redirect_client.enable_server_certificate_verification(false);
redirect_client.enable_server_hostname_verification(false);
} else {
// For direct SSL connections, copy SSL verification settings
redirect_client.enable_server_certificate_verification(
server_certificate_verification_);
redirect_client.enable_server_hostname_verification(
server_hostname_verification_);
}
redirect_client.enable_server_certificate_verification(
server_certificate_verification_);
redirect_client.enable_server_hostname_verification(
server_hostname_verification_);
// Transfer CA certificate to redirect client
if (!ca_cert_pem_.empty()) {
@@ -12863,14 +13059,9 @@ inline bool ClientImpl::write_content_with_provider(Stream &strm,
auto is_shutting_down = []() { return false; };
if (req.is_chunked_content_provider_) {
// TODO: Brotli support
std::unique_ptr<detail::compressor> compressor;
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
if (compress_) {
compressor = detail::make_unique<detail::gzip_compressor>();
} else
#endif
{
auto compressor = compress_ ? detail::create_compressor().first
: std::unique_ptr<detail::compressor>();
if (!compressor) {
compressor = detail::make_unique<detail::nocompressor>();
}
@@ -13101,14 +13292,15 @@ ClientImpl::send_with_content_provider_and_receiver(
Error &error) {
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
if (compress_) { req.set_header("Content-Encoding", "gzip"); }
#endif
auto enc = compress_
? detail::create_compressor()
: std::pair<std::unique_ptr<detail::compressor>, const char *>(
nullptr, nullptr);
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
if (compress_ && !content_provider_without_length) {
// TODO: Brotli support
detail::gzip_compressor compressor;
if (enc.second) { req.set_header("Content-Encoding", enc.second); }
if (enc.first && !content_provider_without_length) {
auto &compressor = enc.first;
if (content_provider) {
auto ok = true;
@@ -13119,7 +13311,7 @@ ClientImpl::send_with_content_provider_and_receiver(
if (ok) {
auto last = offset + data_len == content_length;
auto ret = compressor.compress(
auto ret = compressor->compress(
data, data_len, last,
[&](const char *compressed_data, size_t compressed_data_len) {
req.body.append(compressed_data, compressed_data_len);
@@ -13143,19 +13335,17 @@ ClientImpl::send_with_content_provider_and_receiver(
}
}
} else {
if (!compressor.compress(body, content_length, true,
[&](const char *data, size_t data_len) {
req.body.append(data, data_len);
return true;
})) {
if (!compressor->compress(body, content_length, true,
[&](const char *data, size_t data_len) {
req.body.append(data, data_len);
return true;
})) {
error = Error::Compression;
output_error_log(error, &req);
return nullptr;
}
}
} else
#endif
{
} else {
if (content_provider) {
req.content_length_ = content_length;
req.content_provider_ = std::move(content_provider);
@@ -14473,7 +14663,8 @@ inline Client::Client(const std::string &scheme_host_port,
if (host.empty()) { host = m[3].str(); }
auto port_str = m[4].str();
auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
auto port = is_ssl ? 443 : 80;
if (!port_str.empty() && !detail::parse_port(port_str, port)) { return; }
if (is_ssl) {
#ifdef CPPHTTPLIB_SSL_ENABLED
@@ -15321,6 +15512,24 @@ inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
return ClientImpl::create_and_connect_socket(socket, error);
}
inline bool SSLClient::setup_proxy_connection(
Socket &socket,
std::chrono::time_point<std::chrono::steady_clock> start_time,
Response &res, bool &success, Error &error) {
if (proxy_host_.empty() || proxy_port_ == -1) { return true; }
if (!connect_with_proxy(socket, start_time, res, success, error)) {
return false;
}
if (!initialize_ssl(socket, error)) {
success = false;
return false;
}
return true;
}
// Assumes that socket_mutex_ is locked and that there are no requests in
// flight
inline bool SSLClient::connect_with_proxy(
@@ -19837,11 +20046,11 @@ inline WebSocket::~WebSocket() {
}
inline void WebSocket::start_heartbeat() {
if (ping_interval_sec_ == 0) { return; }
ping_thread_ = std::thread([this]() {
std::unique_lock<std::mutex> lock(ping_mutex_);
while (!closed_) {
ping_cv_.wait_for(lock, std::chrono::seconds(
CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND));
ping_cv_.wait_for(lock, std::chrono::seconds(ping_interval_sec_));
if (closed_) { break; }
lock.unlock();
if (!send_frame(Opcode::Ping, nullptr, 0)) {
@@ -19886,7 +20095,8 @@ inline WebSocketClient::WebSocketClient(
if (host_.empty()) { host_ = m[3].str(); }
auto port_str = m[4].str();
port_ = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
port_ = is_ssl ? 443 : 80;
if (!port_str.empty() && !detail::parse_port(port_str, port_)) { return; }
path_ = m[5].str();
@@ -19978,7 +20188,8 @@ inline bool WebSocketClient::connect() {
Request req;
req.method = "GET";
req.path = path_;
ws_ = std::unique_ptr<WebSocket>(new WebSocket(std::move(strm), req, false));
ws_ = std::unique_ptr<WebSocket>(
new WebSocket(std::move(strm), req, false, websocket_ping_interval_sec_));
return true;
}
@@ -20018,6 +20229,10 @@ inline void WebSocketClient::set_write_timeout(time_t sec, time_t usec) {
write_timeout_usec_ = usec;
}
inline void WebSocketClient::set_websocket_ping_interval(time_t sec) {
websocket_ping_interval_sec_ = sec;
}
#ifdef CPPHTTPLIB_SSL_ENABLED
inline void WebSocketClient::set_ca_cert_path(const std::string &path) {
+1
View File
@@ -36,6 +36,7 @@ others:
@(cd test && make fuzz_test)
@(cd test && make test_websocket_heartbeat && ./test_websocket_heartbeat)
@(cd test && make test_thread_pool && ./test_thread_pool)
@(cd test && make test_benchmark && ./test_benchmark)
build:
@(cd test && make test_split)
+11 -1
View File
@@ -219,6 +219,16 @@ style_check: $(STYLE_CHECK_FILES)
echo "All files are properly formatted."; \
fi
BENCHMARK_LIBS = -lpthread
ifneq ($(OS), Windows_NT)
ifeq ($(shell uname -s), Darwin)
BENCHMARK_LIBS += -framework CoreFoundation -framework CFNetwork
endif
endif
test_benchmark : test_benchmark.cc ../httplib.h Makefile
$(CXX) -o $@ -I.. $(CXXFLAGS) test_benchmark.cc gtest/src/gtest-all.cc gtest/src/gtest_main.cc -Igtest -Igtest/include $(BENCHMARK_LIBS)
test_websocket_heartbeat : test_websocket_heartbeat.cc ../httplib.h Makefile
$(CXX) -o $@ -I.. $(CXXFLAGS) test_websocket_heartbeat.cc $(TEST_ARGS)
@file $@
@@ -254,5 +264,5 @@ cert.pem:
./gen-certs.sh
clean:
rm -rf test test_split test_mbedtls test_split_mbedtls test_wolfssl test_split_wolfssl test_no_tls, test_split_no_tls test_proxy test_proxy_mbedtls test_proxy_wolfssl server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM *_shard_*.log cpp-httplib
rm -rf test test_split test_mbedtls test_split_mbedtls test_wolfssl test_split_wolfssl test_no_tls, test_split_no_tls test_proxy test_proxy_mbedtls test_proxy_wolfssl test_benchmark server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM *_shard_*.log cpp-httplib
+1
View File
@@ -15,6 +15,7 @@ acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl SSL_ports port 1025-65535
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
+1
View File
@@ -15,6 +15,7 @@ acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl SSL_ports port 1025-65535
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
+8
View File
@@ -0,0 +1,8 @@
services:
squid_basic:
extra_hosts:
- "host.docker.internal:host-gateway"
squid_digest:
extra_hosts:
- "host.docker.internal:host-gateway"
+418 -190
View File
@@ -102,71 +102,6 @@ static void read_file(const std::string &path, std::string &out) {
fs.read(&out[0], static_cast<std::streamsize>(size));
}
void performance_test(const char *host) {
Server svr;
svr.Get("/benchmark", [&](const Request & /*req*/, Response &res) {
res.set_content("Benchmark Response", "text/plain");
});
auto listen_thread = std::thread([&]() { svr.listen(host, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(host, PORT);
// Warm-up request to establish connection and resolve DNS
auto warmup_res = cli.Get("/benchmark");
ASSERT_TRUE(warmup_res); // Ensure server is responding correctly
// Run multiple trials and collect timings
const int num_trials = 20;
std::vector<int64_t> timings;
timings.reserve(num_trials);
for (int i = 0; i < num_trials; i++) {
auto start = std::chrono::high_resolution_clock::now();
auto res = cli.Get("/benchmark");
auto end = std::chrono::high_resolution_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
// Assertions after timing measurement to avoid overhead
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
timings.push_back(elapsed);
}
// Calculate 25th percentile (lower quartile)
std::sort(timings.begin(), timings.end());
auto p25 = timings[num_trials / 4];
// Format timings for output
std::ostringstream timings_str;
timings_str << "[";
for (size_t i = 0; i < timings.size(); i++) {
if (i > 0) timings_str << ", ";
timings_str << timings[i];
}
timings_str << "]";
// Localhost HTTP GET should be fast even in CI environments
EXPECT_LE(p25, 5) << "25th percentile performance is too slow: " << p25
<< "ms (Issue #1777). Timings: " << timings_str.str();
}
TEST(BenchmarkTest, localhost) { performance_test("localhost"); }
TEST(BenchmarkTest, v6) { performance_test("::1"); }
class UnixSocketTest : public ::testing::Test {
protected:
void TearDown() override { std::remove(pathname_.c_str()); }
@@ -413,6 +348,38 @@ TEST(DecodePathTest, PercentCharacterNUL) {
EXPECT_EQ(decode_path_component("x%00x"), expected);
}
TEST(DecodePathTest, UnicodeEncoding) {
// %u0041 = 'A' (1-byte UTF-8)
EXPECT_EQ("A", decode_path_component("%u0041"));
// %u00E9 = 'é' (2-byte UTF-8)
EXPECT_EQ(U8("é"), decode_path_component("%u00E9"));
// %u3042 = 'あ' (3-byte UTF-8)
EXPECT_EQ(U8(""), decode_path_component("%u3042"));
// %uFFFF = max 4-digit hex (3-byte UTF-8, must not overflow buff[4])
EXPECT_FALSE(decode_path_component("%uFFFF").empty());
// %uD800 = surrogate (invalid, silently dropped)
EXPECT_EQ("", decode_path_component("%uD800"));
}
TEST(SanitizeFilenameTest, VariousPatterns) {
// Path traversal
EXPECT_EQ("passwd", httplib::sanitize_filename("../../../etc/passwd"));
EXPECT_EQ("passwd", httplib::sanitize_filename("..\\..\\etc\\passwd"));
EXPECT_EQ("file.txt", httplib::sanitize_filename("path/to\\..\\file.txt"));
// Normal and edge cases
EXPECT_EQ("photo.jpg", httplib::sanitize_filename("photo.jpg"));
EXPECT_EQ("filename.txt",
httplib::sanitize_filename("/path/to/filename.txt"));
EXPECT_EQ(".gitignore", httplib::sanitize_filename(".gitignore"));
EXPECT_EQ("", httplib::sanitize_filename(".."));
EXPECT_EQ("", httplib::sanitize_filename(""));
// Null bytes stripped
EXPECT_EQ("safe.txt",
httplib::sanitize_filename(std::string("safe\0.txt", 9)));
// Whitespace-only rejected
EXPECT_EQ("", httplib::sanitize_filename(" "));
}
TEST(EncodeQueryParamTest, ParseUnescapedChararactersTest) {
string unescapedCharacters = "-_.!~*'()";
@@ -1235,6 +1202,89 @@ TEST(ParseAcceptEncoding3, AcceptEncoding) {
#endif
}
TEST(ParseAcceptEncoding4, AcceptEncodingQZero) {
// All supported encodings rejected with q=0 should return None
Request req;
req.set_header("Accept-Encoding", "gzip;q=0, br;q=0, zstd;q=0, deflate");
Response res;
res.set_header("Content-Type", "text/plain");
auto ret = detail::encoding_type(req, res);
EXPECT_TRUE(ret == detail::EncodingType::None);
}
TEST(ParseAcceptEncoding5, AcceptEncodingQZeroVariants) {
// q=0.0, q=0.00, q=0.000 should also be treated as rejected
Request req;
req.set_header("Accept-Encoding", "gzip;q=0.000, br;q=0.0, zstd;q=0.00");
Response res;
res.set_header("Content-Type", "text/plain");
auto ret = detail::encoding_type(req, res);
EXPECT_TRUE(ret == detail::EncodingType::None);
}
TEST(ParseAcceptEncoding6, AcceptEncodingXGzipQZero) {
// x-gzip;q=0 should not cause "gzip" to be incorrectly detected
Request req;
req.set_header("Accept-Encoding", "x-gzip;q=0");
Response res;
res.set_header("Content-Type", "text/plain");
auto ret = detail::encoding_type(req, res);
EXPECT_TRUE(ret == detail::EncodingType::None);
}
TEST(ParseAcceptEncoding7, AcceptEncodingCaseInsensitive) {
// RFC 7231: Accept-Encoding values are case-insensitive
Request req;
req.set_header("Accept-Encoding", "GZIP, BR, ZSTD");
Response res;
res.set_header("Content-Type", "text/plain");
auto ret = detail::encoding_type(req, res);
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Brotli);
#elif CPPHTTPLIB_ZLIB_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Gzip);
#elif CPPHTTPLIB_ZSTD_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Zstd);
#else
EXPECT_TRUE(ret == detail::EncodingType::None);
#endif
}
TEST(ParseAcceptEncoding8, AcceptEncodingQValuePriority) {
// q value should determine priority, not hardcoded order
Request req;
req.set_header("Accept-Encoding", "br;q=0.5, gzip;q=1.0, zstd;q=0.8");
Response res;
res.set_header("Content-Type", "text/plain");
auto ret = detail::encoding_type(req, res);
// gzip has highest q=1.0, so it should be selected even though
// br and zstd are also supported
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Gzip);
#elif CPPHTTPLIB_ZSTD_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Zstd);
#elif CPPHTTPLIB_BROTLI_SUPPORT
EXPECT_TRUE(ret == detail::EncodingType::Brotli);
#else
EXPECT_TRUE(ret == detail::EncodingType::None);
#endif
}
TEST(BufferStreamTest, read) {
detail::BufferStream strm1;
Stream &strm = strm1;
@@ -2330,6 +2380,31 @@ TEST(RedirectToDifferentPort, Redirect) {
EXPECT_EQ("Hello World!", res->body);
}
TEST(RedirectToDifferentPort, OverflowPortNumber) {
Server svr;
svr.Get("/redir", [&](const Request & /*req*/, Response &res) {
// Port number that overflows int — should not crash
res.set_redirect("http://localhost:99999999999999999999/target");
});
auto port = svr.bind_to_any_port(HOST);
auto thread = std::thread([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
thread.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, port);
cli.set_follow_location(true);
auto res = cli.Get("/redir");
// Should fail gracefully, not crash (no valid response due to bad port)
EXPECT_FALSE(res);
}
TEST(RedirectFromPageWithContent, Redirect) {
Server svr;
@@ -2512,7 +2587,7 @@ TEST(PathUrlEncodeTest, IncludePercentEncodingLF) {
}
}
TEST(BindServerTest, DISABLED_BindDualStack) {
TEST(BindServerTest, BindDualStack) {
Server svr;
svr.Get("/1", [&](const Request & /*req*/, Response &res) {
@@ -5605,7 +5680,13 @@ TEST_F(ServerTest, PutLargeFileWithGzip2) {
// depending on the zlib library.
EXPECT_LT(res.get_request_header_value_u64("Content-Length"),
static_cast<uint64_t>(10 * 1024 * 1024));
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
EXPECT_EQ("br", res.get_request_header_value("Content-Encoding"));
#elif defined(CPPHTTPLIB_ZLIB_SUPPORT)
EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
#elif defined(CPPHTTPLIB_ZSTD_SUPPORT)
EXPECT_EQ("zstd", res.get_request_header_value("Content-Encoding"));
#endif
}
TEST_F(ServerTest, PutContentWithDeflate) {
@@ -5746,53 +5827,6 @@ TEST(GzipDecompressor, DeflateDecompressionTrailingBytes) {
ASSERT_EQ(original_text, decompressed_data);
}
#ifdef _WIN32
TEST(GzipDecompressor, LargeRandomData) {
// prepare large random data that is difficult to be compressed and is
// expected to have large size even when compressed
std::random_device seed_gen;
std::mt19937 random(seed_gen());
constexpr auto large_size_byte = 4294967296UL; // 4GiB
constexpr auto data_size = large_size_byte + 134217728UL; // + 128MiB
std::vector<std::uint32_t> data(data_size / sizeof(std::uint32_t));
std::generate(data.begin(), data.end(), [&]() { return random(); });
// compress data over 4GiB
std::string compressed_data;
compressed_data.reserve(large_size_byte + 536870912UL); // + 512MiB reserved
httplib::detail::gzip_compressor compressor;
auto result = compressor.compress(reinterpret_cast<const char *>(data.data()),
data.size() * sizeof(std::uint32_t), true,
[&](const char *data, size_t size) {
compressed_data.insert(
compressed_data.size(), data, size);
return true;
});
ASSERT_TRUE(result);
// FIXME: compressed data size is expected to be greater than 4GiB,
// but there is no guarantee
// ASSERT_TRUE(compressed_data.size() >= large_size_byte);
// decompress data over 4GiB
std::string decompressed_data;
decompressed_data.reserve(data_size);
httplib::detail::gzip_decompressor decompressor;
result = decompressor.decompress(
compressed_data.data(), compressed_data.size(),
[&](const char *data, size_t size) {
decompressed_data.insert(decompressed_data.size(), data, size);
return true;
});
ASSERT_TRUE(result);
// compare
ASSERT_EQ(data_size, decompressed_data.size());
ASSERT_TRUE(std::memcmp(data.data(), decompressed_data.data(), data_size) ==
0);
}
#endif
#endif
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
@@ -5815,6 +5849,47 @@ TEST_F(ServerTest, GetStreamedChunkedWithBrotli2) {
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(std::string("123456789"), res->body);
}
TEST_F(ServerTest, PutWithContentProviderWithBrotli) {
cli_.set_compress(true);
auto res = cli_.Put(
"/put", 3,
[](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
sink.os << "PUT";
return true;
},
"text/plain");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("PUT", res->body);
}
TEST_F(ServerTest, PutWithContentProviderWithoutLengthWithBrotli) {
cli_.set_compress(true);
auto res = cli_.Put(
"/put",
[](size_t /*offset*/, DataSink &sink) {
sink.os << "PUT";
sink.done();
return true;
},
"text/plain");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("PUT", res->body);
}
TEST_F(ServerTest, PutLargeFileWithBrotli) {
cli_.set_compress(true);
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(LARGE_DATA, res->body);
EXPECT_EQ("br", res.get_request_header_value("Content-Encoding"));
}
#endif
TEST_F(ServerTest, Patch) {
@@ -9441,6 +9516,18 @@ TEST(HostAndPortPropertiesTest, NoSSLWithSimpleAPI) {
ASSERT_EQ(1234, cli.port());
}
TEST(HostAndPortPropertiesTest, OverflowPortNumber) {
// Port number that overflows int — should not crash, client becomes invalid
httplib::Client cli("http://www.google.com:99999999999999999999");
ASSERT_FALSE(cli.is_valid());
}
TEST(HostAndPortPropertiesTest, PortOutOfRange) {
// Port 99999 exceeds valid range (1-65535) — should not crash
httplib::Client cli("http://www.google.com:99999");
ASSERT_FALSE(cli.is_valid());
}
#ifdef CPPHTTPLIB_SSL_ENABLED
TEST(HostAndPortPropertiesTest, SSL) {
httplib::SSLClient cli("www.google.com");
@@ -10713,38 +10800,6 @@ TEST(ClientImplMethods, GetSocketTest) {
}
}
// Disabled due to out-of-memory problem on GitHub Actions
#ifdef _WIN64
TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
// allocate content size larger than 2GB in memory
const size_t content_size = 2LL * 1024LL * 1024LL * 1024LL + 1LL;
char *content = (char *)malloc(content_size);
ASSERT_TRUE(content);
Server svr;
svr.Get("/foo",
[=](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content(content, content_size, "application/octet-stream");
});
auto listen_thread = std::thread([&svr]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
listen_thread.join();
if (content) free(content);
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/foo");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(content_size, res->body.length());
}
#endif
#ifdef CPPHTTPLIB_SSL_ENABLED
TEST(YahooRedirectTest2, SimpleInterface_Online) {
Client cli("http://yahoo.com");
@@ -11617,7 +11672,11 @@ TEST(MultipartFormDataTest, AlternateFilenameLongValueAndCaseInsensitive) {
// Case-insensitive "utf-8''" prefix with a long value
const auto &file = req.form.get_file("file1");
ASSERT_EQ("file1", file.name);
std::string expected_filename(2000, 'A');
// 8000 chars exercises both the Content-Disposition parser and the
// filename* parser near the CPPHTTPLIB_HEADER_MAX_LENGTH limit (8192).
// Prior to the fix, std::regex_match on this header would cause O(N)
// stack recursion in libstdc++, leading to SIGSEGV.
std::string expected_filename(8000, 'A');
ASSERT_EQ(expected_filename, file.filename);
res.set_content("ok", "text/plain");
@@ -11635,8 +11694,8 @@ TEST(MultipartFormDataTest, AlternateFilenameLongValueAndCaseInsensitive) {
svr.wait_until_ready();
// Build body with a long filename* value using mixed-case prefix "Utf-8''"
// Prior to the fix, this would cause O(N) stack recursion in std::regex
std::string long_filename(2000, 'A');
// Regression test for GHSA-qq6v-r583-3h69
std::string long_filename(8000, 'A');
std::string body = "----------\r\n"
"Content-Disposition: form-data; name=\"file1\"; "
"filename*=\"Utf-8''" +
@@ -13047,6 +13106,66 @@ TEST(ClientInThreadTest, Issue2068) {
}
}
TEST(RequestSmugglingTest, DuplicateContentLengthDifferentValues) {
auto handled = false;
Server svr;
svr.Post("/test", [&](const Request &, Response &) { handled = true; });
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
ASSERT_FALSE(handled);
});
svr.wait_until_ready();
// Two Content-Length headers with different values — must be rejected
auto req = "POST /test HTTP/1.1\r\n"
"Content-Length: 5\r\n"
"Content-Length: 10\r\n"
"\r\n"
"hello";
std::string response;
ASSERT_TRUE(send_request(1, req, &response));
ASSERT_EQ("HTTP/1.1 400 Bad Request",
response.substr(0, response.find("\r\n")));
}
TEST(RequestSmugglingTest, DuplicateContentLengthSameValues) {
auto handled = false;
Server svr;
svr.Post("/test", [&](const Request &, Response &res) {
handled = true;
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
ASSERT_TRUE(handled);
});
svr.wait_until_ready();
// Two Content-Length headers with same value — should be accepted (RFC 9110)
auto req = "POST /test HTTP/1.1\r\n"
"Content-Length: 5\r\n"
"Content-Length: 5\r\n"
"\r\n"
"hello";
std::string response;
ASSERT_TRUE(send_request(1, req, &response));
ASSERT_EQ("HTTP/1.1 200 OK", response.substr(0, response.find("\r\n")));
}
TEST(HeaderSmugglingTest, ChunkedTrailerHeadersMerged) {
Server svr;
@@ -13708,6 +13827,102 @@ TEST_F(OpenStreamTest, ProhibitedTrailersAreIgnored_Stream) {
EXPECT_EQ(std::string(""), handle.response->get_header_value("X-Allowed"));
}
static std::thread serve_single_response(int port,
const std::string &response) {
return std::thread([port, response] {
auto srv = ::socket(AF_INET, SOCK_STREAM, 0);
default_socket_options(srv);
detail::set_socket_opt_time(srv, SOL_SOCKET, SO_RCVTIMEO, 5, 0);
detail::set_socket_opt_time(srv, SOL_SOCKET, SO_SNDTIMEO, 5, 0);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(static_cast<uint16_t>(port));
::inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
int opt = 1;
::setsockopt(srv, SOL_SOCKET, SO_REUSEADDR,
#ifdef _WIN32
reinterpret_cast<const char *>(&opt),
#else
&opt,
#endif
sizeof(opt));
::bind(srv, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
::listen(srv, 1);
sockaddr_in cli_addr{};
socklen_t cli_len = sizeof(cli_addr);
auto cli = ::accept(srv, reinterpret_cast<sockaddr *>(&cli_addr), &cli_len);
if (cli != INVALID_SOCKET) {
char buf[4096];
::recv(cli, buf, sizeof(buf), 0);
::send(cli,
#ifdef _WIN32
static_cast<const char *>(response.c_str()),
static_cast<int>(response.size()),
#else
response.c_str(), response.size(),
#endif
0);
detail::close_socket(cli);
}
detail::close_socket(srv);
});
}
TEST(OpenStreamMalformedContentLength, InvalidArgument) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
auto server_thread =
serve_single_response(PORT + 2, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: not-a-number\r\n"
"Connection: close\r\n"
"\r\n"
"hello");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
Client cli("127.0.0.1", PORT + 2);
auto handle = cli.open_stream("GET", "/");
EXPECT_FALSE(handle.is_valid());
server_thread.join();
}
TEST(OpenStreamMalformedContentLength, OutOfRange) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
auto server_thread = serve_single_response(
PORT + 4, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 99999999999999999999999999\r\n"
"Connection: close\r\n"
"\r\n"
"hello");
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// Before the fix, std::stoull would throw std::out_of_range here and
// crash the process. After the fix, strtoull silently clamps to
// ULLONG_MAX so the stream opens without crashing. The important thing
// is that the process does NOT terminate.
Client cli("127.0.0.1", PORT + 4);
auto handle = cli.open_stream("GET", "/");
EXPECT_TRUE(handle.is_valid());
server_thread.join();
}
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
TEST_F(OpenStreamTest, Gzip) {
Client cli("127.0.0.1", port_);
@@ -15936,48 +16151,6 @@ TEST(SSLClientServerTest, FilePathConstructorSetsClientCAList) {
EXPECT_GT(sk_X509_NAME_num(ca_list), 0);
}
// Disabled due to the out-of-memory problem on GitHub Actions Workflows
TEST(SSLClientServerTest, DISABLED_LargeDataTransfer) {
// prepare large data
std::random_device seed_gen;
std::mt19937 random(seed_gen());
constexpr auto large_size_byte = 2147483648UL + 1048576UL; // 2GiB + 1MiB
std::vector<std::uint32_t> binary(large_size_byte / sizeof(std::uint32_t));
std::generate(binary.begin(), binary.end(), [&random]() { return random(); });
// server
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(svr.is_valid());
svr.Post("/binary", [&](const Request &req, Response &res) {
EXPECT_EQ(large_size_byte, req.body.size());
EXPECT_EQ(0, std::memcmp(binary.data(), req.body.data(), large_size_byte));
res.set_content(req.body, "application/octet-stream");
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
// client POST
SSLClient cli("localhost", PORT);
cli.enable_server_certificate_verification(false);
cli.set_read_timeout(std::chrono::seconds(100));
cli.set_write_timeout(std::chrono::seconds(100));
auto res = cli.Post("/binary", reinterpret_cast<char *>(binary.data()),
large_size_byte, "application/octet-stream");
// compare
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(large_size_byte, res->body.size());
EXPECT_EQ(0, std::memcmp(binary.data(), res->body.data(), large_size_byte));
}
#endif
// ============================================================================
@@ -16325,6 +16498,14 @@ TEST(WebSocketTest, InvalidURL) {
// Missing host
ws::WebSocketClient ws4("ws://:8080/path");
EXPECT_FALSE(ws4.is_valid());
// Port number overflow — should not crash
ws::WebSocketClient ws5("ws://localhost:99999999999999999999/path");
EXPECT_FALSE(ws5.is_valid());
// Port out of range
ws::WebSocketClient ws6("ws://localhost:99999/path");
EXPECT_FALSE(ws6.is_valid());
}
TEST(WebSocketTest, UnsupportedScheme) {
@@ -16839,3 +17020,50 @@ TEST_F(WebSocketSSLIntegrationTest, TextEcho) {
client.close();
}
#endif
#if !defined(_WIN32)
TEST(SymlinkTest, SymlinkEscapeFromBaseDirectory) {
auto secret_dir = std::string("./symlink_test_secret");
auto served_dir = std::string("./symlink_test_served");
auto secret_file = secret_dir + "/secret.txt";
auto symlink_path = served_dir + "/escape";
// Setup: create directories and files
mkdir(secret_dir.c_str(), 0755);
mkdir(served_dir.c_str(), 0755);
{
std::ofstream ofs(secret_file);
ofs << "SECRET_DATA";
}
// Create symlink using absolute path so it resolves correctly
char abs_secret[PATH_MAX];
ASSERT_NE(nullptr, realpath(secret_dir.c_str(), abs_secret));
ASSERT_EQ(0, symlink(abs_secret, symlink_path.c_str()));
auto se = detail::scope_exit([&] {
unlink(symlink_path.c_str());
unlink(secret_file.c_str());
rmdir(served_dir.c_str());
rmdir(secret_dir.c_str());
});
Server svr;
svr.set_mount_point("/", served_dir);
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
auto se2 = detail::scope_exit([&] {
svr.stop();
listen_thread.join();
});
svr.wait_until_ready();
Client cli("localhost", PORT);
// Symlink pointing outside base dir should be blocked
auto res = cli.Get("/escape/secret.txt");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::Forbidden_403, res->status);
}
#endif
+9
View File
@@ -0,0 +1,9 @@
#include "../httplib.h"
int main() {
httplib::Server svr;
httplib::Client cli("localhost", 8080);
(void)svr;
(void)cli;
return 0;
}
+78
View File
@@ -0,0 +1,78 @@
#include <httplib.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <sstream>
#include <thread>
#include <vector>
using namespace httplib;
static const int PORT = 11134;
static void performance_test(const char *host) {
Server svr;
svr.Get("/benchmark", [&](const Request & /*req*/, Response &res) {
res.set_content("Benchmark Response", "text/plain");
});
auto listen_thread = std::thread([&]() { svr.listen(host, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(host, PORT);
// Warm-up request to establish connection and resolve DNS
auto warmup_res = cli.Get("/benchmark");
ASSERT_TRUE(warmup_res); // Ensure server is responding correctly
// Run multiple trials and collect timings
const int num_trials = 20;
std::vector<int64_t> timings;
timings.reserve(num_trials);
for (int i = 0; i < num_trials; i++) {
auto start = std::chrono::high_resolution_clock::now();
auto res = cli.Get("/benchmark");
auto end = std::chrono::high_resolution_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start)
.count();
// Assertions after timing measurement to avoid overhead
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
timings.push_back(elapsed);
}
// Calculate 25th percentile (lower quartile)
std::sort(timings.begin(), timings.end());
auto p25 = timings[num_trials / 4];
// Format timings for output
std::ostringstream timings_str;
timings_str << "[";
for (size_t i = 0; i < timings.size(); i++) {
if (i > 0) timings_str << ", ";
timings_str << timings[i];
}
timings_str << "]";
// Localhost HTTP GET should be fast even in CI environments
EXPECT_LE(p25, 5) << "25th percentile performance is too slow: " << p25
<< "ms (Issue #1777). Timings: " << timings_str.str();
}
TEST(BenchmarkTest, localhost) { performance_test("localhost"); }
TEST(BenchmarkTest, v6) { performance_test("::1"); }
+71
View File
@@ -109,6 +109,55 @@ TEST(RedirectTest, YouTubeSSLDigest) {
// ----------------------------------------------------------------------------
#ifdef CPPHTTPLIB_SSL_ENABLED
TEST(RedirectTest, TLSVerificationOnProxyRedirect) {
// Untrusted HTTPS server with self-signed cert
SSLServer untrusted_svr("cert.pem", "key.pem");
untrusted_svr.Get("/", [](const Request &, Response &res) {
res.set_content("MITM'd", "text/plain");
});
auto untrusted_port = untrusted_svr.bind_to_any_port("0.0.0.0");
auto t1 = thread([&]() { untrusted_svr.listen_after_bind(); });
auto se1 = detail::scope_exit([&] {
untrusted_svr.stop();
t1.join();
});
// HTTP server that redirects to the untrusted HTTPS server
// Use host.docker.internal so the proxy container can reach the host
Server redirect_svr;
redirect_svr.Get("/", [&](const Request &, Response &res) {
res.set_redirect(
"https://host.docker.internal:" + to_string(untrusted_port) + "/");
});
auto redirect_port = redirect_svr.bind_to_any_port("0.0.0.0");
auto t2 = thread([&]() { redirect_svr.listen_after_bind(); });
auto se2 = detail::scope_exit([&] {
redirect_svr.stop();
t2.join();
});
// Wait until servers are up
untrusted_svr.wait_until_ready();
redirect_svr.wait_until_ready();
// Client with proxy + follow_location, verification ON (default)
Client cli("host.docker.internal", redirect_port);
cli.set_proxy("localhost", 3128);
cli.set_proxy_basic_auth("hello", "world");
cli.set_follow_location(true);
auto res = cli.Get("/");
// Self-signed cert must be rejected
ASSERT_TRUE(res == nullptr);
}
#endif
// ----------------------------------------------------------------------------
template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) {
cli.set_proxy("localhost", 3128);
cli.set_proxy_basic_auth("hello", "world");
@@ -295,3 +344,25 @@ TEST(KeepAliveTest, SSLWithDigest) {
KeepAliveTest(cli, false);
}
#endif
// ----------------------------------------------------------------------------
#ifdef CPPHTTPLIB_SSL_ENABLED
TEST(ProxyTest, SSLOpenStream) {
SSLClient cli("nghttp2.org");
cli.set_proxy("localhost", 3128);
cli.set_proxy_basic_auth("hello", "world");
auto handle = cli.open_stream("GET", "/httpbin/get");
ASSERT_TRUE(handle.response);
EXPECT_EQ(StatusCode::OK_200, handle.response->status);
std::string body;
char buf[8192];
ssize_t n;
while ((n = handle.read(buf, sizeof(buf))) > 0) {
body.append(buf, static_cast<size_t>(n));
}
EXPECT_FALSE(body.empty());
}
#endif
+79
View File
@@ -57,6 +57,85 @@ TEST_F(WebSocketHeartbeatTest, IdleConnectionStaysAlive) {
client.close();
}
// Verify that set_websocket_ping_interval overrides the compile-time default
TEST_F(WebSocketHeartbeatTest, RuntimePingIntervalOverride) {
// The server is already using the compile-time default (1s).
// Create a client with a custom runtime interval.
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + "/ws");
client.set_websocket_ping_interval(2);
ASSERT_TRUE(client.connect());
// Sleep longer than read timeout (3s). Client heartbeat at 2s keeps alive.
std::this_thread::sleep_for(std::chrono::seconds(5));
ASSERT_TRUE(client.is_open());
ASSERT_TRUE(client.send("runtime interval"));
std::string msg;
ASSERT_TRUE(client.read(msg));
EXPECT_EQ("runtime interval", msg);
client.close();
}
// Verify that ping_interval=0 disables heartbeat without breaking basic I/O.
TEST_F(WebSocketHeartbeatTest, ZeroDisablesHeartbeat) {
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + "/ws");
client.set_websocket_ping_interval(0);
ASSERT_TRUE(client.connect());
// Basic send/receive still works with heartbeat disabled
ASSERT_TRUE(client.send("no client ping"));
std::string msg;
ASSERT_TRUE(client.read(msg));
EXPECT_EQ("no client ping", msg);
client.close();
}
// Verify that Server::set_websocket_ping_interval works at runtime
class WebSocketServerPingIntervalTest : public ::testing::Test {
protected:
void SetUp() override {
svr_.set_websocket_ping_interval(2);
svr_.WebSocket("/ws", [](const Request &, ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
});
port_ = svr_.bind_to_any_port("localhost");
thread_ = std::thread([this]() { svr_.listen_after_bind(); });
svr_.wait_until_ready();
}
void TearDown() override {
svr_.stop();
thread_.join();
}
Server svr_;
int port_;
std::thread thread_;
};
TEST_F(WebSocketServerPingIntervalTest, ServerRuntimeInterval) {
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + "/ws");
ASSERT_TRUE(client.connect());
// Server ping interval is 2s; client uses compile-time default (1s).
// Both keep the connection alive.
std::this_thread::sleep_for(std::chrono::seconds(5));
ASSERT_TRUE(client.is_open());
ASSERT_TRUE(client.send("server interval"));
std::string msg;
ASSERT_TRUE(client.read(msg));
EXPECT_EQ("server interval", msg);
client.close();
}
// Verify that multiple heartbeat cycles work
TEST_F(WebSocketHeartbeatTest, MultipleHeartbeatCycles) {
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + "/ws");