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