cpp-httplib: A Header-Only HTTP Library That Puts Blocking I/O First
A C++ header-only HTTP/HTTPS server and client library. [!NOTE] BoringSSL (best-effort): BoringSSL builds under CPPHTTPLIB_OPENSSL_SUPPORT and is exercised by CI against current upstream.
At a glance
- What is it?
- cpp-httplib is a C++11 single-file header-only HTTP/HTTPS server and client library with multiple TLS backends. It is easy to integrate but explicitly rejects non-blocking I/O and HTTP/2, which narrows its use to simpler synchronous workloads.
- Who is it for?
- Adopt cpp-httplib if you need a straightforward, blocking HTTP/1.1 server or client in a C++11 project and you can live with its explicit constraints: no HTTP/2, no non-blocking sockets, and no support for 32-bit platforms. Do not use it for high-concurrency event-driven services or if you must speak HTTP/2.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What cpp-httplib Actually Solves
cpp-httplib solves the problem of adding HTTP or HTTPS capabilities to a C++ program without pulling in a large framework or a build system dependency. The entire library is one header file, httplib.h, which you include directly. That is the core promise: no linking against a separate library, no CMake configuration, no package manager step. The intended user is a C++ developer who needs a server or client for a tool, an internal service, a test harness, or an embedded-ish application where dropping in a single file is more attractive than adopting a full networking stack. The README stresses that setup is extremely easy: just include the file. This is a real advantage for projects that want to avoid dependency management overhead. But the same simplicity comes with boundaries, and the README is upfront about them. The library uses blocking socket I/O only. If you need non-blocking sockets, it is not the tool. It also supports only HTTP/1.1, not HTTP/2 or HTTP/3. Those are hard limits, not omissions that a configuration flag can fix.
The Blocking I/O Constraint Shapes Everything
The README contains an IMPORTANT note: this library uses blocking socket I/O. If you are looking for non-blocking socket I/O, this is not the one that you want. That statement is not a minor caveat; it defines the library's character. A blocking server handles one request at a time per thread. To handle multiple clients, you must create threads yourself, typically one per connection. That model is simple and predictable, but it does not scale to thousands of concurrent connections the way an event-driven or non-blocking library would. The documentation does not promise any asynchronous API or callback-driven event loop. The examples show a server with a listen call and handler lambdas; the client calls Get and waits. For a developer coming from a framework like Boost.Asio or an event loop, this will feel primitive. But for a small internal tool or a prototype, the blocking model is easier to reason about. The trade-off is explicit, which is better than discovering it after integration.
TLS Backends: Choose Your Abstraction
cpp-httplib does not hard-code OpenSSL. It has an abstraction layer for TLS backends, and the README lists three: OpenSSL, Mbed TLS, and wolfSSL. Each is enabled with a preprocessor define: CPPHTTPLIB_OPENSSL_SUPPORT, CPPHTTPLIB_MBEDTLS_SUPPORT, or CPPHTTPLIB_WOLFSSL_SUPPORT. OpenSSL requires version 3.0 or later. Mbed TLS supports 2.x, 3.x, and 4.x, with a note that 4.x renames libmbedcrypto to libtfpsacrypto. wolfSSL supports 5.x and must be built with --enable-opensslall. This flexibility matters if you are on a platform where OpenSSL is not desirable or available. The cost is that you must understand the backend-specific quirks. For example, the README notes that Mbed TLS and wolfSSL cannot enumerate CA certificates loaded via set_ca_cert_path() or load_system_certs; only those loaded through load_ca_cert_store() appear in get_ca_certs() and get_ca_names(). That is a concrete limitation that could break code expecting uniform behavior across backends. The abstraction is not perfect, and the documentation is honest about it.
BoringSSL Support Is Best-Effort, With Known Differences
The repository also exercises BoringSSL builds under CPPHTTPLIB_OPENSSL_SUPPORT. The README calls this best-effort, because BoringSSL does not guarantee API stability. Breakage may occasionally land. That is a warning to anyone who wants to use BoringSSL in production. Two known behavioral differences are documented. First, BoringSSL's public headers require C++14 or later, so you must compile your code with at least C++14 even though the library itself is C++11. Second, hostname verification is SAN-only per RFC 6125 section 6.4.4, with no CN fallback. If your certificates rely on CN matching, they will fail verification under BoringSSL. This is a concrete edge case that could surprise a team migrating from OpenSSL. The library does not hide these differences; it states them plainly. If you need BoringSSL for licensing or size reasons, you can try it, but you should test your certificate validation paths thoroughly.
32-Bit Platforms Are Explicitly Unsupported
A WARNING in the README is stark: 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 those environments. Integer truncation and other 32-bit-specific issues may exist. The maintainer goes further: security reports that only affect 32-bit platforms will be closed without action. That is a strong stance. It means if you are building for an embedded ARM 32-bit device or a legacy 32-bit x86 system, you are on your own. The CI includes only basic compile checks for 32-bit, not functional or security testing. This is not a minor limitation; it is a policy decision. For a library that is often chosen for its simplicity, this narrows the field considerably. If your target is 32-bit, you should look elsewhere or be prepared to audit the code yourself. The README does not offer a workaround or a promise of future support.
Getting It Running: Single Header, Multiple TLS Modes
Setup is a download and an include. The README points to the raw httplib.h file on GitHub. You can fetch it with curl or wget and drop it into your source tree. For TLS, you define the appropriate macro before including the header. The server example is short: create an httplib::Server or httplib::SSLServer, register a handler with svr.Get("/hi", lambda), and call listen("0.0.0.0", 8080). The client side is equally direct: httplib::Client cli("http://yhirose.github.io") or httplib::SSLClient for HTTPS, then cli.Get("/hi") returns a Result object with status and body. For TLS, you can pass certificate and key paths to SSLServer, or use an in-memory PemMemory struct for both server and client. The README shows how to fill the struct with cert and key data, which is handy when certificates come from environment variables or a secrets manager. The same PemMemory constructor exists for httplib::ws::WebSocketClient, which is mentioned in the WebSocket README. The compile command is not shown in the README excerpt, but the examples imply you just compile your source with the header and link against the TLS backend libraries, such as libssl and libcrypto for OpenSSL. There is no separate build step for the library itself.
SSL Error Handling and Custom Verification
When SSL operations fail, cpp-httplib gives you two error accessors: ssl_error() returns the TLS-level error code, such as SSL_ERROR_SSL for OpenSSL, and ssl_backend_error() returns the backend-specific code, like ERR_get_error() for OpenSSL or wolfSSL, or the return value for Mbed TLS. This is useful for diagnosing connection failures without guessing. The README shows a switch on res.error() with a case for SSLConnection, where you can print both error codes. For certificate verification, you can set a custom verifier with set_server_certificate_verifier(), passing a lambda that receives a tls::VerifyContext. That context exposes subject_cn(), issuer_name(), depth, preverify_ok, and a list of SANs via sans(). You can inspect each SAN value and return true or false to accept or reject. This gives you fine-grained control beyond the default verification. The library also supports mutual TLS: the server can be constructed with a client CA certificate path, and the client can present its own certificate and key. Both SSLServer and SSLClient accept file paths or PemMemory. This is a complete mTLS flow, which is more than many small libraries offer.
Maintenance, License, and Upgrade Considerations
The project is under the MIT license, which is permissive and allows commercial use with attribution. The repository is active, with recent releases at v0.54.0, v0.53.1, and v0.53.0 in August 2026. The last push date is the same as the latest release, suggesting ongoing maintenance. The README mentions a docs site built with docs-gen, which indicates a commitment to documentation beyond the README. Upgrade cost is low because the library is a single header. You can replace the file and recompile. However, you should check release notes for behavior changes, especially around TLS backends and certificate handling. The BoringSSL best-effort warning implies that if you use that backend, upgrades may occasionally break. The 32-bit unsupported policy is permanent, so do not expect a fix. The library is not archived, and the release cadence suggests active development. For a production project, the MIT license is a plus, but the 32-bit stance and blocking I/O limit are permanent constraints that no upgrade will remove.
Alternatives and When to Choose Them
The most direct alternative is Boost.Beast, which is a header-only library built on Boost.Asio. Beast supports both synchronous and asynchronous I/O, and it has explicit support for HTTP/1.1 and HTTP/2 (the latter via a separate module). The key difference is that Beast gives you non-blocking, event-driven operation, which cpp-httplib explicitly does not. If you need to handle many concurrent connections without a thread per connection, Beast is a better fit, but it requires learning Asio's async model and has a steeper learning curve. Another alternative is libmicrohttpd, which is a C library with a non-blocking event loop and supports HTTP/1.1. It is not header-only and requires linking, but it offers more control over concurrency. For HTTP/2 specifically, nghttp2 is a C library that implements the protocol directly. cpp-httplib cannot be a drop-in for any of these if you need those features. The choice comes down to complexity tolerance. If you accept blocking I/O and HTTP/1.1, cpp-httplib is simpler to integrate than any of these. If you need non-blocking or HTTP/2, you must move to a different library, and the migration will involve rewriting your networking layer.
Editorial conclusion
Adopt cpp-httplib if you need a straightforward, blocking HTTP/1.1 server or client in a C++11 project and you can live with its explicit constraints: no HTTP/2, no non-blocking sockets, and no support for 32-bit platforms. Do not use it for high-concurrency event-driven services or if you must speak HTTP/2. Before adopting, verify your target platform is 64-bit, confirm your TLS backend choice (OpenSSL 3.0+, Mbed TLS, wolfSSL) is available, and test the specific certificate verification behavior you need, especially if you rely on CN fallback or CA enumeration.
Community notes