LCOV - code coverage report
Current view: top level - http/client - proxy.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 3 3
Test Date: 2026-11-10 10:38:07 Functions: 100.0 % 3 3

            Line data    Source code
       1              : #ifndef THINGER_HTTP_CLIENT_PROXY_HPP
       2              : #define THINGER_HTTP_CLIENT_PROXY_HPP
       3              : 
       4              : #include <boost/asio/ip/address.hpp>
       5              : #include <cstdint>
       6              : #include <functional>
       7              : #include <memory>
       8              : #include <optional>
       9              : #include <string>
      10              : #include <string_view>
      11              : #include <vector>
      12              : 
      13              : namespace thinger::http {
      14              : 
      15              : /**
      16              :  * Outbound proxy settings of a client or of a request (see http_client_base::proxy()).
      17              :  *
      18              :  * Plain http:// requests are sent to the proxy with an absolute-form target (RFC 9112,
      19              :  * section 3.2.2); https://, ws:// and wss:// ones go through a tunnel opened with CONNECT
      20              :  * (RFC 9110, section 9.3.6), with TLS end to end to the origin. Hosts in `no_proxy`, and
      21              :  * localhost, loopback addresses and Unix sockets always, are reached directly.
      22              :  */
      23              : struct proxy_config {
      24              :     /// Proxy for http:// and ws:// requests, and for https:// and wss:// ones:
      25              :     /// "http://[user:password@]host[:port]" (the scheme is optional, the port 80 by default,
      26              :     /// user and password percent-encoded). Empty to connect directly. Only HTTP proxies are
      27              :     /// supported: an https:// (TLS to the proxy) or socks URL fails the requests using it.
      28              :     std::string http;
      29              :     std::string https;
      30              : 
      31              :     /// Hosts reached directly, comma separated (case-insensitive, spaces trimmed):
      32              :     ///  - "example.com" or ".example.com": that domain and its subdomains ("*.example.com" too);
      33              :     ///  - an IP address ("10.1.2.3", "::1" or "[::1]") or a CIDR range ("10.0.0.0/8");
      34              :     ///  - any of them with a port ("example.com:8080", "[::1]:8080"): only for that port;
      35              :     ///  - "*": every host.
      36              :     std::string no_proxy;
      37              : 
      38              :     /// Read an environment variable: its value, or nothing if it is not set
      39              :     using env_reader = std::function<std::optional<std::string>(const char* name)>;
      40              : 
      41              :     /**
      42              :      * Settings from the environment, as curl reads them (the first variable set and not
      43              :      * empty wins):
      44              :      *  - http:  http_proxy (lowercase only: HTTP_PROXY is ignored, as in a CGI program it is
      45              :      *           the Proxy header of the request it serves: "httpoxy", CVE-2016-5385);
      46              :      *  - https: https_proxy, HTTPS_PROXY;
      47              :      *  - both, when not set above: all_proxy, ALL_PROXY;
      48              :      *  - no_proxy, NO_PROXY.
      49              :      */
      50              :     static proxy_config from_environment();
      51              :     static proxy_config from_environment(const env_reader& getenv);
      52              : };
      53              : 
      54              : /// An HTTP proxy, from its URL (see proxy_config)
      55              : struct proxy_endpoint {
      56              :     std::string host;           // lowercase, an IPv6 address without brackets
      57              :     std::string port;
      58              :     std::string authorization;  // Proxy-Authorization value ("Basic ..."), empty without credentials
      59              : 
      60              :     /// The proxy of a URL; nothing (and why in `error`) if the URL is invalid or not of an
      61              :     /// HTTP proxy
      62              :     static std::optional<proxy_endpoint> parse(std::string_view url, std::string* error = nullptr);
      63              : 
      64              :     /// "http://host:port", without the credentials (for logs and proxy_for())
      65              :     std::string url() const;
      66              : 
      67              :     /// Identifies the proxy and its credentials (connections through it are only reused by
      68              :     /// requests with the same one)
      69              :     std::string key() const;
      70              : };
      71              : 
      72              : /// Hosts reached without a proxy, from a NO_PROXY list (see proxy_config::no_proxy)
      73              : class no_proxy_list {
      74              : public:
      75            3 :     no_proxy_list() = default;
      76              :     explicit no_proxy_list(std::string_view list);
      77              : 
      78              :     /// Whether a request to host:port goes directly
      79              :     bool matches(std::string_view host, std::string_view port) const;
      80              : 
      81            6 :     bool empty() const { return !all_ && entries_.empty(); }
      82              : 
      83              : private:
      84              :     struct entry {
      85              :         std::string domain;                             // a host name, without leading dot
      86              :         std::optional<boost::asio::ip::address> ip;     // an address or the start of a range
      87              :         unsigned prefix = 0;                            // range bits (ip only)
      88              :         bool range = false;
      89              :         std::string port;                               // empty for any port
      90              :     };
      91              :     // An entry of the list (lowercase); nothing if it cannot be parsed
      92              :     static std::optional<entry> parse_entry(std::string_view token);
      93              : 
      94              :     bool all_ = false;
      95              :     std::vector<entry> entries_;
      96              : };
      97              : 
      98              : /// Whether a host is never proxied: localhost (and *.localhost) or a loopback address
      99              : bool is_loopback_host(std::string_view host);
     100              : 
     101              : /// Proxy settings parsed once, to choose the proxy of each request
     102              : class proxy_resolver {
     103              : public:
     104              :     /// What to do with a request
     105              :     struct choice {
     106              :         std::shared_ptr<const proxy_endpoint> proxy;    // null to connect directly
     107              :         std::string error;                              // the configured proxy cannot be used
     108              :     };
     109              : 
     110            3 :     proxy_resolver() = default;
     111              :     explicit proxy_resolver(const proxy_config& config);
     112              : 
     113              :     /// The proxy of a request to host:port, over TLS (https, wss) or not
     114              :     choice select(bool secure, std::string_view host, std::string_view port) const;
     115              : 
     116              : private:
     117              :     struct proxy {
     118              :         std::shared_ptr<const proxy_endpoint> endpoint;
     119              :         std::string error;
     120              :         bool configured = false;
     121              :     };
     122              : 
     123              :     static proxy parse(const std::string& url);
     124              : 
     125              :     proxy http_;
     126              :     proxy https_;
     127              :     no_proxy_list no_proxy_;
     128              : };
     129              : 
     130              : }
     131              : 
     132              : #endif
        

Generated by: LCOV version 2.0-1