Light-weight HTTP/2 server in C++
I'm using this as a learning exercise to learn more about HTTP/2 and modern C++. As such, I am intentionally using low-level APIs and avoiding libraries for the core flow (but using modern C++ features to wrap the POSIX interfaces). It is not intended to be a production-ready server! I'm documenting non-obvious stuff I've learnt along the way in LEARNINGS.md.
- HTTP/2 over TLS or cleartext (h2c)
- Support for HPACK (headers):
- Static table entries
- Dynamic table entries
- Huffman encoded & plain text strings
- Supports response body, status codes
- Route registration
- Middleware support for manipulating requests/responses
- Static file serving (GET, HEAD requests)
- Non-blocking network I/O (uses
epollon Linux,pollon macOS) - Combined Log Format (CLF) access logs
- Close server using Ctrl+C (
SIGINT) orSIGTERM
#include "ion/http2_server.h"
int main() {
ion::Http2Server server{};
auto& router = server.router();
router.add_route("/", "GET", [](const ion::HttpRequest&) {
const std::string body_text = "hello";
const std::vector<uint8_t> body_bytes(body_text.begin(), body_text.end());
return ion::HttpResponse{
.status_code = 200,
.body = body_bytes,
.headers = {{"content-type", "text/plain"}}};
});
server.start(8443);
return 0;
}See app/main.cpp for a more complete example, including signal handling.
Use --cleartext to run the server in h2c mode. The HTTP/1.1 upgrade mechanism is not supported, so you will
need to ensure the client behaves accordingly (e.g. use curl --http2-prior-knowledge).
Requirements:
- CMake 4.0+
- LLVM/Clang 17+ (GCC not tested)
- OpenSSL 3+
- Python 3.13+
Development is typically done using JetBrains CLion.
make buildDocker:
docker build -f build.Dockerfile -t ion .
docker run -it \
-e BUILD_SUFFIX=docker \
-p 8443:8443 \
-w /workspace \
-v $(pwd):/workspace ion \
make buildMake:
make buildYou can also run the server as a standalone app.
Local:
./build/make/app/ion-server &
curl -k --http2 -v https://localhost:8443/_test/okDocker:
# build server image
docker build -f app.Dockerfile -t ion-server .
# run server
docker run -v $(pwd):/certs \
-p 8443:8443 \
-e ION_TLS_CERT_PATH=/certs/cert.pem \
-e ION_TLS_KEY_PATH=/certs/key.pem \
-it \
ion-serverion: the light-weight HTTP/2 server ⚡️
build/make/app/ion-server [OPTIONS]
OPTIONS:
-h, --help Print this help message and exit
-p, --port UINT:INT in [1 - 65535] [8443]
Port to listen on
-l, --log-level TEXT:{trace,debug,info,warn,error,critical,off} [info]
Set logging level (trace, debug, info, warn, error, critical,
off)
-s, --static TEXT x 2 Map URL prefix to directory. Usage: --static /url/path ./fs/path
--access-log TEXT
--cleartext Disables TLS and handles requests in HTTP/2 cleartext (h2c)
--tls-cert-path TEXT (Env:ION_TLS_CERT_PATH)
Path to certificate file for TLS
--tls-key-path TEXT (Env:ION_TLS_KEY_PATH)
Path to private key file for TLS
--custom-404-file-path TEXT
Path to custom 404 page
--under-test Adds routes used for internal testing. Do not enable in
production
--status-page Adds page (/_ion/status) displaying server status
-v, --version Display program version information and exit
Run all tests using make test
C++-based Catch2 tests:
make test-unit
make test-integration
Python-based tests employing curl, hyperh2 & httpx to test the server end-to-end:
make test-system
Using h2spec:
make test-h2spec
Using h2load. See benchmark/results.md for tests ran during development.
