• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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