xref: /aosp_15_r20/external/cronet/net/base/proxy_chain.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #include "net/base/proxy_chain.h"
6 
7 #include <ostream>
8 #include <vector>
9 
10 #include "base/check.h"
11 #include "base/no_destructor.h"
12 #include "base/ranges/algorithm.h"
13 #include "base/strings/stringprintf.h"
14 #include "net/base/proxy_server.h"
15 #include "net/base/proxy_string_util.h"
16 
17 namespace net {
18 
ProxyChain()19 ProxyChain::ProxyChain() {
20   proxy_server_list_ = std::nullopt;
21 }
22 
23 ProxyChain::ProxyChain(const ProxyChain& other) = default;
24 ProxyChain::ProxyChain(ProxyChain&& other) noexcept = default;
25 
26 ProxyChain& ProxyChain::operator=(const ProxyChain& other) = default;
27 ProxyChain& ProxyChain::operator=(ProxyChain&& other) noexcept = default;
28 ProxyChain::~ProxyChain() = default;
29 
ProxyChain(ProxyServer proxy_server)30 ProxyChain::ProxyChain(ProxyServer proxy_server)
31     : ProxyChain(std::vector<ProxyServer>{std::move(proxy_server)}) {}
32 
ProxyChain(ProxyServer::Scheme scheme,const HostPortPair & host_port_pair)33 ProxyChain::ProxyChain(ProxyServer::Scheme scheme,
34                        const HostPortPair& host_port_pair)
35     : ProxyChain(ProxyServer(scheme, host_port_pair)) {}
36 
ProxyChain(std::vector<ProxyServer> proxy_server_list)37 ProxyChain::ProxyChain(std::vector<ProxyServer> proxy_server_list)
38     : proxy_server_list_(std::move(proxy_server_list)) {
39   if (!IsValidInternal()) {
40     proxy_server_list_ = std::nullopt;
41   }
42 }
43 
GetProxyServer(size_t chain_index) const44 const ProxyServer& ProxyChain::GetProxyServer(size_t chain_index) const {
45   DCHECK(IsValid());
46   CHECK_LT(chain_index, proxy_server_list_.value().size());
47   return proxy_server_list_.value().at(chain_index);
48 }
49 
proxy_servers() const50 const std::vector<ProxyServer>& ProxyChain::proxy_servers() const {
51   DCHECK(IsValid());
52   return proxy_server_list_.value();
53 }
54 
SplitLast() const55 std::pair<ProxyChain, const ProxyServer&> ProxyChain::SplitLast() const {
56   DCHECK(IsValid());
57   DCHECK_NE(length(), 0u);
58   ProxyChain new_chain =
59       ProxyChain({proxy_server_list_->begin(), proxy_server_list_->end() - 1},
60                  ip_protection_chain_id_);
61   return std::make_pair(new_chain, std::ref(proxy_server_list_->back()));
62 }
63 
Prefix(size_t len) const64 ProxyChain ProxyChain::Prefix(size_t len) const {
65   DCHECK(IsValid());
66   DCHECK_LE(len, length());
67   return ProxyChain(
68       {proxy_server_list_->begin(), proxy_server_list_->begin() + len},
69       ip_protection_chain_id_);
70 }
71 
First() const72 const ProxyServer& ProxyChain::First() const {
73   DCHECK(IsValid());
74   DCHECK_NE(length(), 0u);
75   return proxy_server_list_->front();
76 }
77 
Last() const78 const ProxyServer& ProxyChain::Last() const {
79   DCHECK(IsValid());
80   DCHECK_NE(length(), 0u);
81   return proxy_server_list_->back();
82 }
83 
ToDebugString() const84 std::string ProxyChain::ToDebugString() const {
85   if (!IsValid()) {
86     return "INVALID PROXY CHAIN";
87   }
88   std::string debug_string =
89       proxy_server_list_.value().empty() ? "direct://" : "";
90   for (const ProxyServer& proxy_server : proxy_server_list_.value()) {
91     if (!debug_string.empty()) {
92       debug_string += ", ";
93     }
94     debug_string += ProxyServerToProxyUri(proxy_server);
95   }
96   debug_string = "[" + debug_string + "]";
97   if (ip_protection_chain_id_ == 0) {
98     debug_string += " (IP Protection)";
99   } else if (ip_protection_chain_id_ >= 0) {
100     debug_string += base::StringPrintf(" (IP Protection chain %d)",
101                                        ip_protection_chain_id_);
102   }
103   return debug_string;
104 }
105 
ProxyChain(std::vector<ProxyServer> proxy_server_list,int ip_protection_chain_id)106 ProxyChain::ProxyChain(std::vector<ProxyServer> proxy_server_list,
107                        int ip_protection_chain_id)
108     : proxy_server_list_(std::move(proxy_server_list)),
109       ip_protection_chain_id_(ip_protection_chain_id) {
110   CHECK(IsValidInternal());
111 }
112 
IsValidInternal() const113 bool ProxyChain::IsValidInternal() const {
114   if (!proxy_server_list_.has_value()) {
115     return false;
116   }
117   if (is_direct()) {
118     return true;
119   }
120   if (is_single_proxy()) {
121     bool is_valid = proxy_server_list_.value().at(0).is_valid();
122     if (proxy_server_list_.value().at(0).is_quic()) {
123       is_valid = is_valid && is_for_ip_protection();
124     }
125     return is_valid;
126   }
127   DCHECK(is_multi_proxy());
128 
129   // Verify that the chain is zero or more SCHEME_QUIC servers followed by zero
130   // or more SCHEME_HTTPS servers.
131   bool seen_quic = false;
132   bool seen_https = false;
133   for (const auto& proxy_server : proxy_server_list_.value()) {
134     if (proxy_server.is_quic()) {
135       if (seen_https) {
136         // SCHEME_QUIC cannot follow SCHEME_HTTPS.
137         return false;
138       }
139       seen_quic = true;
140     } else if (proxy_server.is_https()) {
141       seen_https = true;
142     } else {
143       return false;
144     }
145   }
146 
147   // QUIC is only allowed for IP protection.
148   return !seen_quic || is_for_ip_protection();
149 }
150 
operator <<(std::ostream & os,const ProxyChain & proxy_chain)151 std::ostream& operator<<(std::ostream& os, const ProxyChain& proxy_chain) {
152   return os << proxy_chain.ToDebugString();
153 }
154 
155 }  // namespace net
156