A simple HTTP server built using C++ and WebAssembly Components with wasi:http.
- WASI SDK 28.0 (wasm32-wasip2)
- wit-bindgen 0.48.0+
- wkg CLI
The easiest way to build is using the provided Makefile:
makeIf you have WASI SDK installed in a non-standard location:
make WASI_SDK_PATH=/opt/wasi-sdk-28.0Or set it as an environment variable:
export WASI_SDK_PATH=/opt/wasi-sdk-28.0
makeIf you prefer to build manually:
-
Fetch WIT dependencies:
wkg wit fetch
-
Generate C++ bindings:
wit-bindgen cpp --out-dir bindings wit
-
Compile the component:
wasm32-wasip2-clang++ \ server.cpp \ bindings/http_server.cpp \ bindings/http_server_component_type.o \ -I bindings \ -I include \ -Wall -Wextra -Werror -Wno-unused-parameter \ -std=c++20 \ -fno-exceptions \ -mexec-model=reactor \ -o http-server.wasm
You can run this component with any WASI HTTP host, such as wasmtime:
wasmtime serve -Scli http-server.wasmThen test the endpoints:
curl http://localhost:8080/
curl http://localhost:8080/hello
curl http://localhost:8080/echo/test/- Returns "Hello, World!"/hello- Returns a greeting from the C++ component/echo/*- Echoes back the request method and path- Other paths return 404
- Uses wasi:http imported resources (IncomingRequest, ResponseOutparam, etc.)
- Demonstrates proper use of
&&move semantics for imported resources - Shows how to work with wit::string, std::expected, and std::variant
- Properly handles resource lifetimes and cleanup
Built using wit-bindgen with the following fixes:
- Type alias resolution for imported resources
- Proper
&&usage instead of::Ownedfor imported resources - Move semantics for
std::expectedin optional emplacement
This project uses tl::expected (included in include/tl/) to provide std::expected compatibility for WASI SDK.
The generated C++ bindings use std::expected, which is a C++23 feature. While WASI SDK 28.0 uses LLVM 21 (which has libc++ 21 with std::expected support), the WASI SDK distribution may not include the <expected> header in its sysroot.
tl::expected is a header-only, single-file implementation of std::expected that:
- Works with C++11 and later (we use C++20)
- Is API-compatible with the C++23 standard
- Is released under CC0-1.0 license (public domain)
- Requires no external dependencies
The include/expected header provides a compatibility layer that aliases tl::expected to std::expected, making the code work seamlessly with generated bindings.