diff --git a/README.md b/README.md index 1037ab2..730ee57 100644 --- a/README.md +++ b/README.md @@ -1181,6 +1181,76 @@ cli.set_proxy_bearer_token_auth("pass"); > [!NOTE] > OpenSSL is required for Digest Authentication. +#### Bypass the proxy for specific hosts (`NO_PROXY`) + +`set_no_proxy` configures a bypass list. Each pattern is one of: + +- `*` — bypass the proxy for every target +- a hostname suffix, e.g. `example.com` — matches `example.com` and any + subdomain (`foo.example.com`). A leading dot (`.example.com`) 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` + +```cpp +cli.set_proxy("proxy.corp", 3128); +cli.set_no_proxy({"internal.corp", "10.0.0.0/8", "*.dev.local"}); +``` + +When a NO_PROXY entry matches the target host, the request is sent +directly and the corresponding `Proxy-Authorization` header is +suppressed. + +Hostname matching is **case-insensitive** and uses a dot-boundary rule, +so `evilexample.com` does **not** match an entry of `example.com`. IP +comparisons are normalized through `inet_pton`, so `127.0.0.1` cannot +be bypassed via alternate string forms (e.g. leading-zero octets or +decimal-form integers). Malformed entries are silently dropped. + +Limitations: + +- Port-specific entries (`example.com:8080`) are not supported. cpp-httplib's + other host-keyed APIs (e.g. `set_hostname_addr_map`) are also keyed on + hostname only; supporting host:port for NO_PROXY alone would be + inconsistent. +- IPv4-mapped IPv6 addresses (`::ffff:1.2.3.4`) are not cross-matched + against IPv4 NO_PROXY entries. +- `set_no_proxy` replaces any previously configured list; there is no + append API. + +#### Read proxy settings from the environment + +`set_proxy_from_env` configures the client from proxy-related +environment variables. + +```cpp +httplib::Client cli("https://api.example.com"); +cli.set_proxy_from_env(); +``` + +Variables read: + +- `https_proxy` / `HTTPS_PROXY` — used by HTTPS clients (`SSLClient`) +- `http_proxy` (lowercase only — see security note below) — used by HTTP clients +- `no_proxy` / `NO_PROXY` — comma-separated list of bypass patterns + +Returns `true` if at least one variable was found and applied. + +> [!IMPORTANT] +> The uppercase `HTTP_PROXY` is intentionally ignored to mitigate the +> "httpoxy" class of bugs ([CVE-2016-5385](https://httpoxy.org/)). In +> CGI / FastCGI environments the variable name collides with the +> `HTTP_*` namespace used to expose request headers, allowing a remote +> attacker to set the proxy URL via the `Proxy:` request header. +> cpp-httplib follows curl, Go, and Python `requests` in honoring only +> the lowercase `http_proxy`. `HTTPS_PROXY` and `NO_PROXY` are safe in +> either case because their names do not begin with `HTTP_`. + +> [!NOTE] +> `set_proxy_from_env` reads `getenv` synchronously. Call it once at +> startup before issuing any requests; concurrent `setenv` from other +> threads is undefined. + ### Range ```cpp