Fix README samples and statements that no longer match the code

Samples that did not compile or did not do what they showed:
- SSLServer has no default constructor, and SSLClient("host:port") does
  not parse the port.
- res.user_data.get<T>() inside a generic lambda needs the `template`
  keyword; use explicit parameter types instead.
- get_header_value() takes the default value before the index.
- Server has no socket(); show set_socket_opt inside set_socket_options.
- The content provider sample used a local without capturing it.
- "*.dev.local" is not a NO_PROXY pattern; ".dev.local" is.
- The reverse proxy example in README-stream.md called open_stream()
  without a method and moved a StreamHandle into a std::function. Keep
  the client and the handle in one shared object.
- open_stream() does not follow redirects, so drop set_follow_location()
  from the Stream API samples.

Statements corrected:
- ssl_error() returns a tls::ErrorCode, not SSL_ERROR_*.
- An exception escaping the exception handler no longer crashes the
  server; the connection is dropped and the error logger is told.
- post_routing_handler runs before every response, including those the
  earlier hooks short-circuit; file_request_handler runs for GET only.
- Only wolfSSL cannot enumerate CAs loaded from a path or the system.
- Digest authentication and the WebSocket TLS setters need any TLS
  backend, not OpenSSL specifically.
- A dynamic pool thread exits on the idle timeout only.
- The stream connection closes when the Result is destroyed.
- The pong timeout takes two to three ping intervals to fire.
- Regex routes skip paths over CPPHTTPLIB_REGEX_ROUTE_PATH_MAX_LENGTH.

Also list the Error values and compressible MIME types that were
missing, note that a content receiver lifts the default client payload
limit, and update the docker server's startup output.
This commit is contained in:
yhirose
2026-10-08 00:40:16 -04:00
parent f6aee694e2
commit 05f7478523
3 changed files with 66 additions and 56 deletions

View File

@@ -4,7 +4,7 @@ This document describes the streaming extensions for cpp-httplib, providing an i
> **Important Notes**:
>
> - **No Keep-Alive**: Each `stream::Get()` call uses a dedicated connection that is closed after the response is fully read. For connection reuse, use `Client::Get()`.
> - **No Keep-Alive**: Each `stream::Get()` call uses a dedicated connection that is closed when the returned `stream::Result` is destroyed. For connection reuse, use `Client::Get()`.
> - **Single iteration only**: The `next()` method can only iterate through the body once.
> - **Result is not thread-safe**: While `stream::Get()` can be called from multiple threads simultaneously, the returned `stream::Result` must be used from a single thread only.
@@ -114,7 +114,6 @@ The `httplib.h` header provides a more ergonomic iterator-style API.
#include "httplib.h"
httplib::Client cli("http://localhost:8080");
cli.set_follow_location(true);
...
// Simple GET
@@ -243,23 +242,29 @@ int main() {
```cpp
#include "httplib.h"
// Keeps the client and its stream alive until the response has been sent.
struct Upstream {
httplib::Client cli{"http://backend:8080"};
httplib::ClientImpl::StreamHandle handle;
};
httplib::Server svr;
svr.Get("/proxy/(.*)", [](const httplib::Request& req, httplib::Response& res) {
httplib::Client upstream("http://backend:8080");
auto handle = upstream.open_stream("/" + req.matches[1].str());
if (!handle.is_valid()) {
auto upstream = std::make_shared<Upstream>();
upstream->handle = upstream->cli.open_stream("GET", "/" + req.matches[1].str());
if (!upstream->handle.is_valid()) {
res.status = 502;
return;
}
res.status = handle.response->status;
res.status = upstream->handle.response->status;
res.set_chunked_content_provider(
handle.response->get_header_value("Content-Type"),
[handle = std::move(handle)](size_t, httplib::DataSink& sink) mutable {
upstream->handle.response->get_header_value("Content-Type"),
[upstream](size_t, httplib::DataSink& sink) {
char buf[8192];
auto n = handle.read(buf, sizeof(buf));
auto n = upstream->handle.read(buf, sizeof(buf));
if (n > 0) {
sink.write(buf, static_cast<size_t>(n));
return true;