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

            Line data    Source code
       1              : #ifndef THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
       2              : #define THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
       3              : 
       4              : #include <boost/asio/ip/address.hpp>
       5              : #include <string>
       6              : #include <string_view>
       7              : #include <vector>
       8              : 
       9              : namespace thinger::http {
      10              : 
      11              : class headers;
      12              : 
      13              : // Header the trusted proxies use to report the client address. Only one is read: a proxy
      14              : // that appends to one of them passes the other one through, as sent by the client. The
      15              : // scheme comes with it: X-Forwarded-Proto with X-Forwarded-For, proto= with Forwarded.
      16              : //
      17              : // The client of a request, as a trusted proxy reports it (see trusted_proxies::resolve())
      18              : struct forwarded_client {
      19              :     std::string ip;
      20              :     std::string scheme;   // "http" or "https"
      21              : };
      22              : 
      23              : enum class forwarded_header {
      24              :     x_forwarded_for,    // X-Forwarded-For: client, proxy1, proxy2 (and X-Forwarded-Proto: https)
      25              :     forwarded           // Forwarded: for=client;proto=https, for=proxy1 (RFC 7239)
      26              : };
      27              : 
      28              : // Proxies (IPs and CIDR ranges, IPv4 and IPv6) allowed to report the address and the scheme
      29              : // of the client they forward a request for
      30              : class trusted_proxies {
      31              : public:
      32           90 :     explicit trusted_proxies(forwarded_header header = forwarded_header::x_forwarded_for)
      33           90 :         : header_(header) {}
      34              : 
      35              :     // Trust an IP ("10.0.0.1", "::1") or a CIDR range ("10.0.0.0/8", "fd00::/8");
      36              :     // returns false if it is not valid
      37              :     bool add(std::string_view network);
      38              : 
      39              :     // Whether an address belongs to a trusted proxy (IPv4-mapped IPv6 addresses are
      40              :     // compared as IPv4); false for anything that is not an IP address
      41              :     bool contains(std::string_view ip) const;
      42              : 
      43          222 :     bool empty() const { return networks_.empty(); }
      44              : 
      45            6 :     forwarded_header header() const { return header_; }
      46              : 
      47              :     // Name of the header read ("X-Forwarded-For" or "Forwarded")
      48              :     const std::string& header_name() const;
      49              : 
      50              : 
      51              :     // Client address of a request received from `peer`, given the values of the forwarding
      52              :     // header (all its occurrences, in order). The peer itself unless it is trusted; then the
      53              :     // forwarded addresses are walked from right to left, skipping trusted proxies, and the
      54              :     // first untrusted one is returned (the leftmost if all of them are trusted). An entry
      55              :     // that is not an IP ("unknown") ends the walk at the address after it.
      56              :     std::string client_ip(const std::string& peer, const std::vector<std::string>& header_values) const;
      57              : 
      58              :     // Client address and scheme of a request received from `peer`, on a connection of
      59              :     // `scheme` ("http" or "https"), with the headers `request` (all the occurrences of the
      60              :     // forwarding headers, in order). The peer and the scheme of the connection unless the peer
      61              :     // is trusted; then one walk, as client_ip() does, gives both: the address where it stops,
      62              :     // and the scheme of the entry it stops at, the last one a trusted proxy wrote (the one
      63              :     // giving the client address, or one whose address is not an IP): its proto= with
      64              :     // Forwarded; with X-Forwarded-For, the X-Forwarded-Proto value in the same position when
      65              :     // both have as many values (each proxy appended to both), else the last one, written by
      66              :     // the nearest proxy (which overwrote it, or did not append to both). So what a client sends
      67              :     // ahead of a trusted proxy is never read, whether the proxy appends or overwrites. A scheme
      68              :     // other than http or https (case-insensitive), or none, leaves the one of the connection.
      69              :     forwarded_client resolve(const std::string& peer, std::string_view scheme, const headers& request) const;
      70              : 
      71              :     // Addresses in the forwarding headers, left to right, without ports nor brackets;
      72              :     // empty strings for entries that are not IP addresses
      73              :     static std::vector<std::string> parse_x_forwarded_for(std::string_view value);
      74              :     static std::vector<std::string> parse_forwarded(std::string_view value);
      75              : 
      76              :     // Scheme of a forwarded value ("http" or "https", lowercase), empty for anything else
      77              :     static std::string parse_scheme(std::string_view value);
      78              : 
      79              : private:
      80              :     struct network {
      81              :         boost::asio::ip::address address;
      82              :         unsigned prefix;
      83              :     };
      84              : 
      85              :     static bool in_network(const boost::asio::ip::address& address, const network& net);
      86              : 
      87              :     std::vector<network> networks_;
      88              :     forwarded_header header_;
      89              : };
      90              : 
      91              : } // namespace thinger::http
      92              : 
      93              : #endif // THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
        

Generated by: LCOV version 2.0-1