• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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/proxy_resolution/proxy_list.h"
6 
7 #include "base/check.h"
8 #include "base/functional/callback.h"
9 #include "base/notreached.h"
10 #include "base/strings/string_tokenizer.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "net/base/proxy_server.h"
14 #include "net/base/proxy_string_util.h"
15 #include "net/log/net_log.h"
16 #include "net/log/net_log_event_type.h"
17 #include "net/log/net_log_with_source.h"
18 
19 using base::TimeTicks;
20 
21 namespace net {
22 
23 ProxyList::ProxyList() = default;
24 
25 ProxyList::ProxyList(const ProxyList& other) = default;
26 
27 ProxyList::ProxyList(ProxyList&& other) = default;
28 
29 ProxyList& ProxyList::operator=(const ProxyList& other) = default;
30 
31 ProxyList& ProxyList::operator=(ProxyList&& other) = default;
32 
33 ProxyList::~ProxyList() = default;
34 
Set(const std::string & proxy_uri_list)35 void ProxyList::Set(const std::string& proxy_uri_list) {
36   proxies_.clear();
37   base::StringTokenizer str_tok(proxy_uri_list, ";");
38   while (str_tok.GetNext()) {
39     ProxyServer uri =
40         ProxyUriToProxyServer(str_tok.token_piece(), ProxyServer::SCHEME_HTTP);
41     // Silently discard malformed inputs.
42     if (uri.is_valid())
43       proxies_.push_back(uri);
44   }
45 }
46 
SetSingleProxyServer(const ProxyServer & proxy_server)47 void ProxyList::SetSingleProxyServer(const ProxyServer& proxy_server) {
48   proxies_.clear();
49   AddProxyServer(proxy_server);
50 }
51 
AddProxyServer(const ProxyServer & proxy_server)52 void ProxyList::AddProxyServer(const ProxyServer& proxy_server) {
53   if (proxy_server.is_valid())
54     proxies_.push_back(proxy_server);
55 }
56 
DeprioritizeBadProxies(const ProxyRetryInfoMap & proxy_retry_info)57 void ProxyList::DeprioritizeBadProxies(
58     const ProxyRetryInfoMap& proxy_retry_info) {
59   // Partition the proxy list in two:
60   //   (1) the known bad proxies
61   //   (2) everything else
62   std::vector<ProxyServer> good_proxies;
63   std::vector<ProxyServer> bad_proxies_to_try;
64 
65   std::vector<ProxyServer>::const_iterator iter = proxies_.begin();
66   for (; iter != proxies_.end(); ++iter) {
67     auto bad_proxy = proxy_retry_info.find(ProxyServerToProxyUri(*iter));
68     if (bad_proxy != proxy_retry_info.end()) {
69       // This proxy is bad. Check if it's time to retry.
70       if (bad_proxy->second.bad_until >= TimeTicks::Now()) {
71         // still invalid.
72         if (bad_proxy->second.try_while_bad)
73           bad_proxies_to_try.push_back(*iter);
74         continue;
75       }
76     }
77     good_proxies.push_back(*iter);
78   }
79 
80   // "proxies_ = good_proxies + bad_proxies"
81   proxies_.swap(good_proxies);
82   proxies_.insert(proxies_.end(), bad_proxies_to_try.begin(),
83                   bad_proxies_to_try.end());
84 }
85 
RemoveProxiesWithoutScheme(int scheme_bit_field)86 void ProxyList::RemoveProxiesWithoutScheme(int scheme_bit_field) {
87   for (auto it = proxies_.begin(); it != proxies_.end();) {
88     if (!(scheme_bit_field & it->scheme())) {
89       it = proxies_.erase(it);
90       continue;
91     }
92     ++it;
93   }
94 }
95 
Clear()96 void ProxyList::Clear() {
97   proxies_.clear();
98 }
99 
IsEmpty() const100 bool ProxyList::IsEmpty() const {
101   return proxies_.empty();
102 }
103 
size() const104 size_t ProxyList::size() const {
105   return proxies_.size();
106 }
107 
108 // Returns true if |*this| lists the same proxies as |other|.
Equals(const ProxyList & other) const109 bool ProxyList::Equals(const ProxyList& other) const {
110   if (size() != other.size())
111     return false;
112   return proxies_ == other.proxies_;
113 }
114 
Get() const115 const ProxyServer& ProxyList::Get() const {
116   CHECK(!proxies_.empty());
117   return proxies_[0];
118 }
119 
GetAll() const120 const std::vector<ProxyServer>& ProxyList::GetAll() const {
121   return proxies_;
122 }
123 
SetFromPacString(const std::string & pac_string)124 void ProxyList::SetFromPacString(const std::string& pac_string) {
125   base::StringTokenizer entry_tok(pac_string, ";");
126   proxies_.clear();
127   while (entry_tok.GetNext()) {
128     ProxyServer uri = PacResultElementToProxyServer(entry_tok.token_piece());
129     // Silently discard malformed inputs.
130     if (uri.is_valid())
131       proxies_.push_back(uri);
132   }
133 
134   // If we failed to parse anything from the PAC results list, fallback to
135   // DIRECT (this basically means an error in the PAC script).
136   if (proxies_.empty()) {
137     proxies_.push_back(ProxyServer::Direct());
138   }
139 }
140 
ToPacString() const141 std::string ProxyList::ToPacString() const {
142   std::string proxy_list;
143   auto iter = proxies_.begin();
144   for (; iter != proxies_.end(); ++iter) {
145     if (!proxy_list.empty())
146       proxy_list += ";";
147     proxy_list += ProxyServerToPacResultElement(*iter);
148   }
149   return proxy_list.empty() ? std::string() : proxy_list;
150 }
151 
ToValue() const152 base::Value ProxyList::ToValue() const {
153   base::Value::List list;
154   for (const auto& proxy : proxies_)
155     list.Append(ProxyServerToProxyUri(proxy));
156   return base::Value(std::move(list));
157 }
158 
Fallback(ProxyRetryInfoMap * proxy_retry_info,int net_error,const NetLogWithSource & net_log)159 bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
160                          int net_error,
161                          const NetLogWithSource& net_log) {
162   if (proxies_.empty()) {
163     NOTREACHED();
164     return false;
165   }
166   // By default, proxies are not retried for 5 minutes.
167   UpdateRetryInfoOnFallback(proxy_retry_info, base::Minutes(5), true,
168                             std::vector<ProxyServer>(), net_error, net_log);
169 
170   // Remove this proxy from our list.
171   proxies_.erase(proxies_.begin());
172   return !proxies_.empty();
173 }
174 
AddProxyToRetryList(ProxyRetryInfoMap * proxy_retry_info,base::TimeDelta retry_delay,bool try_while_bad,const ProxyServer & proxy_to_retry,int net_error,const NetLogWithSource & net_log) const175 void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
176                                     base::TimeDelta retry_delay,
177                                     bool try_while_bad,
178                                     const ProxyServer& proxy_to_retry,
179                                     int net_error,
180                                     const NetLogWithSource& net_log) const {
181   // Mark this proxy as bad.
182   TimeTicks bad_until = TimeTicks::Now() + retry_delay;
183   std::string proxy_key = ProxyServerToProxyUri(proxy_to_retry);
184   auto iter = proxy_retry_info->find(proxy_key);
185   if (iter == proxy_retry_info->end() || bad_until > iter->second.bad_until) {
186     ProxyRetryInfo retry_info;
187     retry_info.current_delay = retry_delay;
188     retry_info.bad_until = bad_until;
189     retry_info.try_while_bad = try_while_bad;
190     retry_info.net_error = net_error;
191     (*proxy_retry_info)[proxy_key] = retry_info;
192   }
193   net_log.AddEventWithStringParams(NetLogEventType::PROXY_LIST_FALLBACK,
194                                    "bad_proxy", proxy_key);
195 }
196 
UpdateRetryInfoOnFallback(ProxyRetryInfoMap * proxy_retry_info,base::TimeDelta retry_delay,bool reconsider,const std::vector<ProxyServer> & additional_proxies_to_bypass,int net_error,const NetLogWithSource & net_log) const197 void ProxyList::UpdateRetryInfoOnFallback(
198     ProxyRetryInfoMap* proxy_retry_info,
199     base::TimeDelta retry_delay,
200     bool reconsider,
201     const std::vector<ProxyServer>& additional_proxies_to_bypass,
202     int net_error,
203     const NetLogWithSource& net_log) const {
204   DCHECK(!retry_delay.is_zero());
205 
206   if (proxies_.empty()) {
207     NOTREACHED();
208     return;
209   }
210 
211   if (!proxies_[0].is_direct()) {
212     AddProxyToRetryList(proxy_retry_info,
213                         retry_delay,
214                         reconsider,
215                         proxies_[0],
216                         net_error,
217                         net_log);
218     // If any additional proxies to bypass are specified, add to the retry map
219     // as well.
220     for (const ProxyServer& additional_proxy : additional_proxies_to_bypass) {
221       AddProxyToRetryList(proxy_retry_info, retry_delay, reconsider,
222                           additional_proxy, net_error, net_log);
223     }
224   }
225 }
226 
227 }  // namespace net
228