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