Files
cpp-httplib/docs-src/pages/en/cookbook/c16-proxy.md
T
yhirose 9bfd2ddf1c Fix README and docs pages that no longer match the code
Bring the READMEs and the docs pages (en and ja) in line with the
current header:

- Fix the client sample that does not compile, the Transfer-Encoding
  statement for default headers, the verifier callback comment, the
  thread pool spawn rule, the sanitize_filename description, and the
  inverted Accept-Encoding sentence.
- Describe recent behaviour: TLS errors behind Read/Write failures,
  Host validation, Connection: close for a body without length,
  content_reader rules, refused CONNECT, WebSocketClient proxies,
  CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT, the SSE event size limit, and
  the payload limit of the Stream API.
- Complete the API references of WebSocket, WebSocketClient and the
  stream:: helpers, and the SSE reconnect rules.
- Fix cookbook pages: keychain loading on every backend, received Close
  status, a multipart sample that trusted the client's file name, an
  echo sample that sent binary as text, SNI, pre-request handler scope,
  stop() with WebSocket handlers, and the thread pool notes.
- Restore the mutex in the LLM app's Chapter 5 code.
2026-10-18 10:13:57 -04:00

4.1 KiB

title, order, status
title order status
C16. Send Requests Through a Proxy 16 draft

To route traffic through a corporate network or a specific path, send requests via an HTTP proxy. Just pass the proxy host and port to set_proxy().

Basic usage

httplib::Client cli("https://api.example.com");
cli.set_proxy("proxy.internal", 8080);

auto res = cli.Get("/users");

The request goes through the proxy. For HTTPS, the client uses the CONNECT method to tunnel through — no extra setup required.

If the proxy refuses the tunnel, the request fails with Error::ProxyConnection. The exception is a 407: it comes back as the response, so res is truthy and res->status is 407, while res.error() still returns Error::ProxyConnection.

Proxy authentication

If the proxy itself requires authentication, use set_proxy_basic_auth() or set_proxy_bearer_token_auth().

cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("user", "password");
cli.set_proxy_bearer_token_auth("token");

If cpp-httplib is built with OpenSSL (or another TLS backend), you can also use Digest authentication for the proxy.

cli.set_proxy_digest_auth("user", "password");

Combine with end-server authentication

Proxy authentication is separate from authenticating to the end server (C05. Use Basic authentication, C06. Call an API with a Bearer token). When both are needed, set both.

cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("proxy-user", "proxy-pass");

cli.set_bearer_token_auth("api-token"); // for the end server

Proxy-Authorization is sent to the proxy, Authorization to the end server.

Bypass the proxy for specific hosts

You often want internal endpoints to skip the proxy. Configure a bypass list with set_no_proxy().

cli.set_proxy("proxy.internal", 8080);
cli.set_no_proxy({"internal.corp", "10.0.0.0/8", ".dev.local"});

Each entry is one of:

  • * — bypass the proxy for all hosts
  • a hostname suffix (e.g. example.com) — matches example.com itself and any subdomain (foo.example.com). A leading dot is permitted but informational; both forms are equivalent.
  • a single IP literal (e.g. 192.168.1.1, ::1)
  • a CIDR block (e.g. 10.0.0.0/8, fe80::/10)

Hostname matching is case-insensitive and uses a dot-boundary rule, so an entry of example.com does not match evilexample.com. IP comparisons are normalized through inet_pton, so 127.0.0.1 cannot be bypassed via alternate string forms (e.g. 127.000.000.001). When an entry matches, the Proxy-Authorization header is suppressed as well.

Malformed entries are silently dropped. Port-specific entries such as example.com:8080 are not supported (cpp-httplib's other host-keyed APIs are also keyed on hostname only).

Use a proxy for WebSocket

ws::WebSocketClient has the same proxy setters.

httplib::ws::WebSocketClient cli("wss://ws.example.com/chat");
cli.set_proxy("proxy.internal", 8080);
cli.set_proxy_basic_auth("user", "password");

auto res = cli.connect();

For both ws:// and wss://, the client opens a tunnel with the CONNECT method and then performs the WebSocket handshake through it. set_no_proxy() works the same way.

Read proxy settings from the environment

cpp-httplib doesn't touch HTTP_PROXY / HTTPS_PROXY / NO_PROXY on its own — the config API is always explicit, the same way set_ca_cert_path() is. If you'd like that behavior, read the variables in your application and feed them to set_proxy() and set_no_proxy().

if (const char *v = std::getenv("no_proxy")) {
  std::vector<std::string> patterns;
  std::stringstream ss(v);
  for (std::string item; std::getline(ss, item, ',');) {
    if (!item.empty()) { patterns.push_back(item); }
  }
  cli.set_no_proxy(patterns);
}

If you also read HTTP_PROXY yourself, honor the lowercase http_proxy only. The uppercase form is poisoned in CGI/FastCGI environments by the Proxy: request header (CVE-2016-5385 / "httpoxy"). HTTPS_PROXY and NO_PROXY are safe in either case because their names don't begin with HTTP_.