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 "net/base/proxy_string_util.h"
13
14 namespace net {
15
ProxyChain()16 ProxyChain::ProxyChain() {
17 proxy_server_list_ = std::nullopt;
18 }
19
20 ProxyChain::ProxyChain(const ProxyChain& other) = default;
21 ProxyChain::ProxyChain(ProxyChain&& other) noexcept = default;
22
23 ProxyChain& ProxyChain::operator=(const ProxyChain& other) = default;
24 ProxyChain& ProxyChain::operator=(ProxyChain&& other) noexcept = default;
25
26 ProxyChain::~ProxyChain() = default;
27
28 // TODO(crbug.com/1491092): Remove is_direct() check when
29 // ProxyServer::SCHEME_DIRECT is deprecated.
ProxyChain(ProxyServer proxy_server)30 ProxyChain::ProxyChain(ProxyServer proxy_server)
31 : ProxyChain(!proxy_server.is_direct()
32 ? std::vector<ProxyServer>{std::move(proxy_server)}
33 : std::vector<ProxyServer>()) {}
34
ProxyChain(ProxyServer::Scheme scheme,const HostPortPair & host_port_pair)35 ProxyChain::ProxyChain(ProxyServer::Scheme scheme,
36 const HostPortPair& host_port_pair)
37 : ProxyChain({ProxyServer(scheme, host_port_pair)}) {}
38
ProxyChain(std::vector<ProxyServer> proxy_server_list)39 ProxyChain::ProxyChain(std::vector<ProxyServer> proxy_server_list)
40 : proxy_server_list_(std::move(proxy_server_list)) {
41 if (!IsValidInternal()) {
42 proxy_server_list_ = std::nullopt;
43 }
44 }
45
GetProxyServer(size_t chain_index) const46 const ProxyServer& ProxyChain::GetProxyServer(size_t chain_index) const {
47 DCHECK(IsValid());
48 CHECK_LT(chain_index, proxy_server_list_.value().size());
49 return proxy_server_list_.value().at(chain_index);
50 }
51
proxy_servers() const52 const std::vector<ProxyServer>& ProxyChain::proxy_servers() const {
53 DCHECK(IsValid());
54 return proxy_server_list_.value();
55 }
56
proxy_server() const57 const ProxyServer& ProxyChain::proxy_server() const {
58 if (!proxy_server_list_.has_value()) {
59 static base::NoDestructor<ProxyServer> invalid(ProxyServer::SCHEME_INVALID,
60 HostPortPair());
61 return *invalid;
62 } else if (proxy_server_list_.value().empty()) {
63 static base::NoDestructor<ProxyServer> direct(ProxyServer::SCHEME_DIRECT,
64 HostPortPair());
65 return *direct;
66 }
67 CHECK_EQ(1u, proxy_server_list_->size())
68 << "Cannot call `proxy_server() on a ProxyChain with multiple proxies: "
69 << ToDebugString();
70 return proxy_server_list_.value().at(0);
71 }
72
ToDebugString() const73 std::string ProxyChain::ToDebugString() const {
74 if (!IsValid()) {
75 return "INVALID PROXY CHAIN";
76 }
77 std::string debug_string =
78 proxy_server_list_.value().empty() ? "direct://" : "";
79 for (const ProxyServer& proxy_server : proxy_server_list_.value()) {
80 if (!debug_string.empty()) {
81 debug_string += ", ";
82 }
83 debug_string += ProxyServerToProxyUri(proxy_server);
84 }
85 return "[" + debug_string + "]";
86 }
87
88 // TODO(crbug.com/1491092): Remove is_direct() checks when
89 // ProxyServer::SCHEME_DIRECT is deprecated.
IsValidInternal() const90 bool ProxyChain::IsValidInternal() const {
91 if (!proxy_server_list_.has_value()) {
92 return false;
93 }
94 if (is_single_proxy()) {
95 return proxy_server_list_.value().at(0).is_valid() &&
96 !proxy_server_list_.value().at(0).is_direct();
97 }
98 for (const auto& proxy_server : proxy_server_list_.value()) {
99 if (!proxy_server.is_valid() || !proxy_server.is_https() ||
100 proxy_server.is_direct()) {
101 return false;
102 }
103 }
104 return true;
105 }
106
operator <<(std::ostream & os,const ProxyChain & proxy_chain)107 std::ostream& operator<<(std::ostream& os, const ProxyChain& proxy_chain) {
108 return os << proxy_chain.ToDebugString();
109 }
110
111 } // namespace net
112