1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef NET_BASE_PROXY_CHAIN_H_ 6*6777b538SAndroid Build Coastguard Worker #define NET_BASE_PROXY_CHAIN_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <stdint.h> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include <iosfwd> 11*6777b538SAndroid Build Coastguard Worker #include <optional> 12*6777b538SAndroid Build Coastguard Worker #include <string> 13*6777b538SAndroid Build Coastguard Worker #include <string_view> 14*6777b538SAndroid Build Coastguard Worker #include <tuple> 15*6777b538SAndroid Build Coastguard Worker #include <vector> 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker #include "net/base/host_port_pair.h" 18*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h" 19*6777b538SAndroid Build Coastguard Worker #include "net/base/proxy_server.h" 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker namespace net { 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker // ProxyChain represents a chain of ProxyServers. A chain with multiple proxy 24*6777b538SAndroid Build Coastguard Worker // servers means that a single connection will go through all of the proxies in 25*6777b538SAndroid Build Coastguard Worker // order, using a tunnel through the first proxy to connect to the second, etc. 26*6777b538SAndroid Build Coastguard Worker // A "direct" connection is a chain of length zero. 27*6777b538SAndroid Build Coastguard Worker class NET_EXPORT ProxyChain { 28*6777b538SAndroid Build Coastguard Worker public: 29*6777b538SAndroid Build Coastguard Worker // Constructs an invalid ProxyChain. 30*6777b538SAndroid Build Coastguard Worker ProxyChain(); 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker ProxyChain(const ProxyChain& other); // Copy constructor 33*6777b538SAndroid Build Coastguard Worker ProxyChain(ProxyChain&& other) noexcept; // Move constructor 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Worker ProxyChain& operator=(const ProxyChain& other); // Copy assignment operator 36*6777b538SAndroid Build Coastguard Worker ProxyChain& operator=( 37*6777b538SAndroid Build Coastguard Worker ProxyChain&& other) noexcept; // Move assignment operator 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Worker ProxyChain(ProxyServer::Scheme scheme, const HostPortPair& host_port_pair); 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker explicit ProxyChain(std::vector<ProxyServer> proxy_server_list); 42*6777b538SAndroid Build Coastguard Worker explicit ProxyChain(ProxyServer proxy_server); 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker ~ProxyChain(); // Destructor declaration 45*6777b538SAndroid Build Coastguard Worker 46*6777b538SAndroid Build Coastguard Worker // Creates a single-proxy ProxyChain, validating and canonicalizing input. 47*6777b538SAndroid Build Coastguard Worker // Port is optional and, if not provided, will be replaced with the default 48*6777b538SAndroid Build Coastguard Worker // port for the given scheme. Accepts IPv6 literal `host`s with surrounding 49*6777b538SAndroid Build Coastguard Worker // brackets (URL format) or without (HostPortPair format). On invalid input, 50*6777b538SAndroid Build Coastguard Worker // result will be a `SCHEME_INVALID` ProxyChain. 51*6777b538SAndroid Build Coastguard Worker // 52*6777b538SAndroid Build Coastguard Worker // Must not be called with `SCHEME_INVALID` or `SCHEME_DIRECT`. Use 53*6777b538SAndroid Build Coastguard Worker // `ProxyChain()` or `Direct()` respectively to create an invalid or direct 54*6777b538SAndroid Build Coastguard Worker // ProxyChain. FromSchemeHostAndPort(ProxyServer::Scheme scheme,std::string_view host,std::string_view port_str)55*6777b538SAndroid Build Coastguard Worker static ProxyChain FromSchemeHostAndPort(ProxyServer::Scheme scheme, 56*6777b538SAndroid Build Coastguard Worker std::string_view host, 57*6777b538SAndroid Build Coastguard Worker std::string_view port_str) { 58*6777b538SAndroid Build Coastguard Worker return ProxyChain( 59*6777b538SAndroid Build Coastguard Worker ProxyServer::FromSchemeHostAndPort(scheme, host, port_str)); 60*6777b538SAndroid Build Coastguard Worker } FromSchemeHostAndPort(ProxyServer::Scheme scheme,std::string_view host,std::optional<uint16_t> port)61*6777b538SAndroid Build Coastguard Worker static ProxyChain FromSchemeHostAndPort(ProxyServer::Scheme scheme, 62*6777b538SAndroid Build Coastguard Worker std::string_view host, 63*6777b538SAndroid Build Coastguard Worker std::optional<uint16_t> port) { 64*6777b538SAndroid Build Coastguard Worker return ProxyChain(ProxyServer::FromSchemeHostAndPort(scheme, host, port)); 65*6777b538SAndroid Build Coastguard Worker } 66*6777b538SAndroid Build Coastguard Worker // Create a "direct" proxy chain, which includes no proxy servers. Direct()67*6777b538SAndroid Build Coastguard Worker static ProxyChain Direct() { return ProxyChain(std::vector<ProxyServer>()); } 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker // Creates a `ProxyChain` for use by the IP Protection feature. This is used 70*6777b538SAndroid Build Coastguard Worker // for metrics collection and for special handling. If not given, the 71*6777b538SAndroid Build Coastguard Worker // chain_id defaults to 0 which corresponds to an un-identified chain. 72*6777b538SAndroid Build Coastguard Worker static ProxyChain ForIpProtection(std::vector<ProxyServer> proxy_server_list, 73*6777b538SAndroid Build Coastguard Worker int chain_id = 0) { 74*6777b538SAndroid Build Coastguard Worker return ProxyChain(std::move(proxy_server_list), chain_id); 75*6777b538SAndroid Build Coastguard Worker } 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker // Get ProxyServer at index in chain. This is not valid for direct or invalid 78*6777b538SAndroid Build Coastguard Worker // proxy chains. 79*6777b538SAndroid Build Coastguard Worker const ProxyServer& GetProxyServer(size_t chain_index) const; 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker // Get the ProxyServers in this chain. This must not be called on invalid 82*6777b538SAndroid Build Coastguard Worker // proxy chains. An empty vector is returned for direct proxy chains. 83*6777b538SAndroid Build Coastguard Worker const std::vector<ProxyServer>& proxy_servers() const; 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker // Return the last proxy server in the chain, together with all of the 86*6777b538SAndroid Build Coastguard Worker // preceding proxies. The chain must have at least one proxy server. If it 87*6777b538SAndroid Build Coastguard Worker // only has one proxy server, then the resulting chain will be direct. 88*6777b538SAndroid Build Coastguard Worker std::pair<ProxyChain, const ProxyServer&> SplitLast() const; 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker // Return a prefix of this proxy chain, of the given length. This length must 91*6777b538SAndroid Build Coastguard Worker // be less than or equal to the chain's length. 92*6777b538SAndroid Build Coastguard Worker ProxyChain Prefix(size_t length) const; 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker // Get the first ProxyServer in this chain, which must have at least one 95*6777b538SAndroid Build Coastguard Worker // server. 96*6777b538SAndroid Build Coastguard Worker const ProxyServer& First() const; 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker // Get the last ProxyServer in this chain, which must have at least one 99*6777b538SAndroid Build Coastguard Worker // server. 100*6777b538SAndroid Build Coastguard Worker const ProxyServer& Last() const; 101*6777b538SAndroid Build Coastguard Worker 102*6777b538SAndroid Build Coastguard Worker // Get the ProxyServers in this chain, or `nullopt` if the chain is not valid. proxy_servers_if_valid()103*6777b538SAndroid Build Coastguard Worker const std::optional<std::vector<ProxyServer>>& proxy_servers_if_valid() 104*6777b538SAndroid Build Coastguard Worker const { 105*6777b538SAndroid Build Coastguard Worker return proxy_server_list_; 106*6777b538SAndroid Build Coastguard Worker } 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Worker // Returns number of proxy servers in chain. length()109*6777b538SAndroid Build Coastguard Worker size_t length() const { 110*6777b538SAndroid Build Coastguard Worker return proxy_server_list_.has_value() ? proxy_server_list_.value().size() 111*6777b538SAndroid Build Coastguard Worker : 0; 112*6777b538SAndroid Build Coastguard Worker } 113*6777b538SAndroid Build Coastguard Worker 114*6777b538SAndroid Build Coastguard Worker // Returns true if this chain contains more than one proxy. is_multi_proxy()115*6777b538SAndroid Build Coastguard Worker bool is_multi_proxy() const { 116*6777b538SAndroid Build Coastguard Worker return proxy_server_list_.has_value() 117*6777b538SAndroid Build Coastguard Worker ? proxy_server_list_.value().size() > 1 118*6777b538SAndroid Build Coastguard Worker : false; 119*6777b538SAndroid Build Coastguard Worker } 120*6777b538SAndroid Build Coastguard Worker 121*6777b538SAndroid Build Coastguard Worker // Returns true if this chain contains exactly one proxy. is_single_proxy()122*6777b538SAndroid Build Coastguard Worker bool is_single_proxy() const { 123*6777b538SAndroid Build Coastguard Worker return proxy_server_list_.has_value() 124*6777b538SAndroid Build Coastguard Worker ? proxy_server_list_.value().size() == 1 125*6777b538SAndroid Build Coastguard Worker : false; 126*6777b538SAndroid Build Coastguard Worker } 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker // Returns true if this is a direct (equivalently, zero-proxy) chain. is_direct()129*6777b538SAndroid Build Coastguard Worker bool is_direct() const { 130*6777b538SAndroid Build Coastguard Worker return proxy_server_list_.has_value() ? proxy_server_list_.value().empty() 131*6777b538SAndroid Build Coastguard Worker : false; 132*6777b538SAndroid Build Coastguard Worker } 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker template <class Predicate> AnyProxy(Predicate p)135*6777b538SAndroid Build Coastguard Worker bool AnyProxy(Predicate p) const { 136*6777b538SAndroid Build Coastguard Worker return proxy_server_list_.has_value() && 137*6777b538SAndroid Build Coastguard Worker std::any_of(proxy_server_list_->begin(), proxy_server_list_->end(), 138*6777b538SAndroid Build Coastguard Worker p); 139*6777b538SAndroid Build Coastguard Worker } 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker // Determines if HTTP GETs to the last proxy in the chain are allowed, 142*6777b538SAndroid Build Coastguard Worker // instead of establishing a tunnel with CONNECT. This is no longer supported 143*6777b538SAndroid Build Coastguard Worker // for QUIC proxy chains and is not currently supported for multi-proxy 144*6777b538SAndroid Build Coastguard Worker // chains. is_get_to_proxy_allowed()145*6777b538SAndroid Build Coastguard Worker bool is_get_to_proxy_allowed() const { 146*6777b538SAndroid Build Coastguard Worker return is_single_proxy() && (First().is_http() || First().is_https()); 147*6777b538SAndroid Build Coastguard Worker } 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Worker // Returns true if a proxy server list is available. IsValid()150*6777b538SAndroid Build Coastguard Worker bool IsValid() const { return proxy_server_list_.has_value(); } 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker // A negative value for `ip_protection_chain_id()` indicating this is not an 153*6777b538SAndroid Build Coastguard Worker // IP protection chain. All IP-Protection chain IDs are non-negative. 154*6777b538SAndroid Build Coastguard Worker static constexpr int kNotIpProtectionChainId = -1; 155*6777b538SAndroid Build Coastguard Worker 156*6777b538SAndroid Build Coastguard Worker // A value for `ip_protection_chain_id()` for IP protection chains for which 157*6777b538SAndroid Build Coastguard Worker // no other chain ID was specified. 158*6777b538SAndroid Build Coastguard Worker static constexpr int kDefaultIpProtectionChainId = 0; 159*6777b538SAndroid Build Coastguard Worker 160*6777b538SAndroid Build Coastguard Worker // The largest allowed ip_protection_chain_id. 161*6777b538SAndroid Build Coastguard Worker static constexpr int kMaxIpProtectionChainId = 3; 162*6777b538SAndroid Build Coastguard Worker is_for_ip_protection()163*6777b538SAndroid Build Coastguard Worker bool is_for_ip_protection() const { 164*6777b538SAndroid Build Coastguard Worker return ip_protection_chain_id_ != kNotIpProtectionChainId; 165*6777b538SAndroid Build Coastguard Worker } ip_protection_chain_id()166*6777b538SAndroid Build Coastguard Worker int ip_protection_chain_id() const { return ip_protection_chain_id_; } 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Worker bool operator==(const ProxyChain& other) const { 169*6777b538SAndroid Build Coastguard Worker return std::tie(proxy_server_list_, ip_protection_chain_id_) == 170*6777b538SAndroid Build Coastguard Worker std::tie(other.proxy_server_list_, other.ip_protection_chain_id_); 171*6777b538SAndroid Build Coastguard Worker } 172*6777b538SAndroid Build Coastguard Worker 173*6777b538SAndroid Build Coastguard Worker bool operator!=(const ProxyChain& other) const { return !(*this == other); } 174*6777b538SAndroid Build Coastguard Worker 175*6777b538SAndroid Build Coastguard Worker // Comparator function so this can be placed in a std::map. 176*6777b538SAndroid Build Coastguard Worker bool operator<(const ProxyChain& other) const { 177*6777b538SAndroid Build Coastguard Worker return std::tie(proxy_server_list_, ip_protection_chain_id_) < 178*6777b538SAndroid Build Coastguard Worker std::tie(other.proxy_server_list_, other.ip_protection_chain_id_); 179*6777b538SAndroid Build Coastguard Worker } 180*6777b538SAndroid Build Coastguard Worker 181*6777b538SAndroid Build Coastguard Worker std::string ToDebugString() const; 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker private: 184*6777b538SAndroid Build Coastguard Worker explicit ProxyChain(std::vector<ProxyServer> proxy_server_list, 185*6777b538SAndroid Build Coastguard Worker int ip_protection_chain_id); 186*6777b538SAndroid Build Coastguard Worker 187*6777b538SAndroid Build Coastguard Worker std::optional<std::vector<ProxyServer>> proxy_server_list_; 188*6777b538SAndroid Build Coastguard Worker 189*6777b538SAndroid Build Coastguard Worker // If used for IP protection, this is the chain_id received from the server. 190*6777b538SAndroid Build Coastguard Worker // A negative value indicates this chain is not used for IP protection. 191*6777b538SAndroid Build Coastguard Worker int ip_protection_chain_id_ = kNotIpProtectionChainId; 192*6777b538SAndroid Build Coastguard Worker 193*6777b538SAndroid Build Coastguard Worker // Returns true if this chain is valid. A chain is considered valid if 194*6777b538SAndroid Build Coastguard Worker // (1) it is a single valid proxy server, or 195*6777b538SAndroid Build Coastguard Worker // (2) it is a chain of servers, composed of zero or more SCHEME_QUIC servers 196*6777b538SAndroid Build Coastguard Worker // followed by zero or more SCHEME_HTTPS servers. 197*6777b538SAndroid Build Coastguard Worker // If any SCHEME_QUIC servers are included, then the chain must be for IP 198*6777b538SAndroid Build Coastguard Worker // protection. 199*6777b538SAndroid Build Coastguard Worker bool IsValidInternal() const; 200*6777b538SAndroid Build Coastguard Worker }; 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 203*6777b538SAndroid Build Coastguard Worker const ProxyChain& proxy_chain); 204*6777b538SAndroid Build Coastguard Worker 205*6777b538SAndroid Build Coastguard Worker // A HostPortProxyPair holds a host/port destination and a ProxyChain describing 206*6777b538SAndroid Build Coastguard Worker // how that destination is reached. 207*6777b538SAndroid Build Coastguard Worker typedef std::pair<HostPortPair, ProxyChain> HostPortProxyPair; 208*6777b538SAndroid Build Coastguard Worker 209*6777b538SAndroid Build Coastguard Worker } // namespace net 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker #endif // NET_BASE_PROXY_CHAIN_H_ 212