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