xref: /aosp_15_r20/external/cronet/net/base/proxy_chain.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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