Library

cpp-httplib v0.53.0

Versionv0.53.0
Stars★ 16,735
Released2026-08-09

A C++ header-only HTTP/HTTPS server and client library

Release notes

## What's Changed

**Breaking changes**
- `WebSocketClient::connect()` now returns `httplib::ws::Result` instead of `bool` (issue #2531). `ws::Result` supports `explicit operator bool()`, `error()`, and flattened accessors for the upgrade response (`status()`, `headers()`, `get_header_value()`, `has_header()`), plus `ssl_error()`/`ssl_backend_error()` on SSL builds, matching how `ClientImpl`/`SSLClient` already report `Result`. A new `Error::WebSocketHandshake` covers upgrade-validation failures (non-101 status, bad `Sec-WebSocket-Accept`, bad `Upgrade`/`Connection` headers), and the handshake response is now parsed with `detail::parse_status_line` instead of a `"HTTP/1.1 101"` substring match, so a non-101 response surfaces its real status and headers instead of being silently discarded. This is source-breaking only for code that assigns the result directly to `bool` (e.g. `bool ok = cli.connect();`); `if (cli.connect())` and gtest's `ASSERT_TRUE`/`EXPECT_FALSE` still work via contextual conversion

**WebSocketClient/SSLClient API alignment (closes #2531)**
- `WebSocketClient` gains the setters `SSLClient` already had: `enable_server_hostname_verification()`, a `PemMemory` client-certificate constructor for mutual TLS, a `(ca_cert_file_path, ca_cert_dir_path)` overload for `set_ca_cert_path()`, and the `std::chrono::duration` overloads for its read/write/connection timeouts
- The TLS session setup the two clients had each implemented separately is now one shared `detail::setup_client_tls_session()`. As part of merging them, `WebSocketClient` moves from calling `tls::set_hostname()` (which turns on OpenSSL's in-handshake verification) to SSLClient's SNI-then-post-handshake-verify approach, and the default Host/User-Agent header logic is shared between both clients as well
- That merge exposed two backend-parity bugs, now fixed: on Mbed TLS and wolfSSL, `enable_server_hostname_verification(false)` had no effect on DNS hosts, because `mbedtls_ssl_set_hostname()` and `wolfSSL_check_domain_name()` bind SNI and identity checking together; and Mbed TLS reported the generic `Error::SSLServerVerification` on a genuine hostname mismatch instead of `Error::SSLServerHostnameVerification`. `set_sni()` now takes a `verify_hostname` flag, and `map_mbedtls_error()` inspects which verify flag actually fired

**Bug fixes**
- Match mount points on a path segment boundary in `handle_file_request()` (#2529, thanks @metsw24-max). The mount point was compared as a plain byte prefix, so `set_mount_point("/mount", "./www2")` also served `/mountdir/...` out of `./www2`. Nothing escaped the base directory (`is_valid_path()` still rejects traversal), but a mount became reachable under URLs outside the prefix it declared, which is enough to slip past a reverse-proxy location, auth filter, or cache rule keyed on `/mount/`. A mount point ending in `/` (the root mount included) is unaffected
- Drain the socket gracefully before closing it in `Server::process_and_close_socket()` (#2534, root cause identified by @Hyukya in #2533). Closing a connection while the receive queue still has unread data, or bytes are still in flight, can make the OS send an abortive RST instead of a graceful FIN; on Windows this surfaces as `WSAECONNABORTED`/`WSAECONNRESET` on the peer's read, making an otherwise fully-written response look like a failed request. This was a likely contributor to the intermittent `ServerTest.HTTP2Magic` failures on the Windows CI job (#2533). `detail::drain_and_close_socket()` half-closes the write side, drains queued/in-flight bytes (bounded to 100ms / 1MB), then does the final shutdown+close

**Development**
- Document the WebSocketClient/SSLClient TLS parity gaps closed above in both READMEs, and add two Cookbook recipes (W05: wss:// TLS setup, W06: WebSocketClient's three timeouts) so this content lives in the WebSocket section instead of scattered asides in the mTLS/timeout/CA pages
- Document `Headers`/`Params`/`FormFields`/`FormFiles` ordering…

Share this resource


Discovered 2026-08-11 Source GitHub Archive 2026-08 →