OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/proxy/proxy_list.h" | 5 #include "net/proxy/proxy_list.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/string_tokenizer.h" | 8 #include "base/string_tokenizer.h" |
9 #include "base/time.h" | 9 #include "base/time.h" |
10 | 10 |
(...skipping 13 matching lines...) Expand all Loading... |
24 proxies_.push_back(uri); | 24 proxies_.push_back(uri); |
25 } | 25 } |
26 } | 26 } |
27 | 27 |
28 void ProxyList::SetSingleProxyServer(const ProxyServer& proxy_server) { | 28 void ProxyList::SetSingleProxyServer(const ProxyServer& proxy_server) { |
29 proxies_.clear(); | 29 proxies_.clear(); |
30 if (proxy_server.is_valid()) | 30 if (proxy_server.is_valid()) |
31 proxies_.push_back(proxy_server); | 31 proxies_.push_back(proxy_server); |
32 } | 32 } |
33 | 33 |
34 void ProxyList::RemoveBadProxies(const ProxyRetryInfoMap& proxy_retry_info) { | 34 void ProxyList::DeprioritizeBadProxies( |
35 std::vector<ProxyServer> new_proxy_list; | 35 const ProxyRetryInfoMap& proxy_retry_info) { |
| 36 // Partition the proxy list in two: |
| 37 // (1) the known bad proxies |
| 38 // (2) everything else |
| 39 std::vector<ProxyServer> good_proxies; |
| 40 std::vector<ProxyServer> bad_proxies; |
| 41 |
36 std::vector<ProxyServer>::const_iterator iter = proxies_.begin(); | 42 std::vector<ProxyServer>::const_iterator iter = proxies_.begin(); |
37 for (; iter != proxies_.end(); ++iter) { | 43 for (; iter != proxies_.end(); ++iter) { |
38 ProxyRetryInfoMap::const_iterator bad_proxy = | 44 ProxyRetryInfoMap::const_iterator bad_proxy = |
39 proxy_retry_info.find(iter->ToURI()); | 45 proxy_retry_info.find(iter->ToURI()); |
40 if (bad_proxy != proxy_retry_info.end()) { | 46 if (bad_proxy != proxy_retry_info.end()) { |
41 // This proxy is bad. Check if it's time to retry. | 47 // This proxy is bad. Check if it's time to retry. |
42 if (bad_proxy->second.bad_until >= TimeTicks::Now()) { | 48 if (bad_proxy->second.bad_until >= TimeTicks::Now()) { |
43 // still invalid. | 49 // still invalid. |
| 50 bad_proxies.push_back(*iter); |
44 continue; | 51 continue; |
45 } | 52 } |
46 } | 53 } |
47 new_proxy_list.push_back(*iter); | 54 good_proxies.push_back(*iter); |
48 } | 55 } |
49 | 56 |
50 proxies_ = new_proxy_list; | 57 // "proxies_ = good_proxies + bad_proxies" |
| 58 proxies_.swap(good_proxies); |
| 59 proxies_.insert(proxies_.end(), bad_proxies.begin(), bad_proxies.end()); |
51 } | 60 } |
52 | 61 |
53 void ProxyList::RemoveProxiesWithoutScheme(int scheme_bit_field) { | 62 void ProxyList::RemoveProxiesWithoutScheme(int scheme_bit_field) { |
54 for (std::vector<ProxyServer>::iterator it = proxies_.begin(); | 63 for (std::vector<ProxyServer>::iterator it = proxies_.begin(); |
55 it != proxies_.end(); ) { | 64 it != proxies_.end(); ) { |
56 if (!(scheme_bit_field & it->scheme())) { | 65 if (!(scheme_bit_field & it->scheme())) { |
57 it = proxies_.erase(it); | 66 it = proxies_.erase(it); |
58 continue; | 67 continue; |
59 } | 68 } |
60 ++it; | 69 ++it; |
61 } | 70 } |
62 } | 71 } |
63 | 72 |
64 ProxyServer ProxyList::Get() const { | 73 bool ProxyList::IsEmpty() const { |
65 if (!proxies_.empty()) | 74 return proxies_.empty(); |
66 return proxies_[0]; | 75 } |
67 return ProxyServer(ProxyServer::SCHEME_DIRECT, std::string(), -1); | 76 |
| 77 const ProxyServer& ProxyList::Get() const { |
| 78 DCHECK(!proxies_.empty()); |
| 79 return proxies_[0]; |
68 } | 80 } |
69 | 81 |
70 std::string ProxyList::ToPacString() const { | 82 std::string ProxyList::ToPacString() const { |
71 std::string proxy_list; | 83 std::string proxy_list; |
72 std::vector<ProxyServer>::const_iterator iter = proxies_.begin(); | 84 std::vector<ProxyServer>::const_iterator iter = proxies_.begin(); |
73 for (; iter != proxies_.end(); ++iter) { | 85 for (; iter != proxies_.end(); ++iter) { |
74 if (!proxy_list.empty()) | 86 if (!proxy_list.empty()) |
75 proxy_list += ";"; | 87 proxy_list += ";"; |
76 proxy_list += iter->ToPacString(); | 88 proxy_list += iter->ToPacString(); |
77 } | 89 } |
78 return proxy_list.empty() ? "DIRECT" : proxy_list; | 90 return proxy_list.empty() ? std::string() : proxy_list; |
79 } | 91 } |
80 | 92 |
81 void ProxyList::SetFromPacString(const std::string& pac_string) { | 93 void ProxyList::SetFromPacString(const std::string& pac_string) { |
82 StringTokenizer entry_tok(pac_string, ";"); | 94 StringTokenizer entry_tok(pac_string, ";"); |
83 proxies_.clear(); | 95 proxies_.clear(); |
84 while (entry_tok.GetNext()) { | 96 while (entry_tok.GetNext()) { |
85 ProxyServer uri = ProxyServer::FromPacString( | 97 ProxyServer uri = ProxyServer::FromPacString( |
86 entry_tok.token_begin(), entry_tok.token_end()); | 98 entry_tok.token_begin(), entry_tok.token_end()); |
87 // Silently discard malformed inputs. | 99 // Silently discard malformed inputs. |
88 if (uri.is_valid()) | 100 if (uri.is_valid()) |
89 proxies_.push_back(uri); | 101 proxies_.push_back(uri); |
90 } | 102 } |
| 103 |
| 104 // If we failed to parse anything from the PAC results list, fallback to |
| 105 // DIRECT (this basically means an error in the PAC script). |
| 106 if (proxies_.empty()) { |
| 107 proxies_.push_back(ProxyServer::Direct()); |
| 108 } |
91 } | 109 } |
92 | 110 |
93 bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info) { | 111 bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info) { |
94 // Number of minutes to wait before retrying a bad proxy server. | 112 // Number of minutes to wait before retrying a bad proxy server. |
95 const TimeDelta kProxyRetryDelay = TimeDelta::FromMinutes(5); | 113 const TimeDelta kProxyRetryDelay = TimeDelta::FromMinutes(5); |
96 | 114 |
| 115 // TODO(eroman): It would be good if instead of removing failed proxies |
| 116 // from the list, we simply annotated them with the error code they failed |
| 117 // with. Of course, ProxyService::ReconsiderProxyAfterError() would need to |
| 118 // be given this information by the network transaction. |
| 119 // |
| 120 // The advantage of this approach is when the network transaction |
| 121 // fails, we could output the full list of proxies that were attempted, and |
| 122 // why each one of those failed (as opposed to just the last failure). |
| 123 // |
| 124 // And also, before failing the transaction wholesale, we could go back and |
| 125 // retry the "bad proxies" which we never tried to begin with. |
| 126 // (RemoveBadProxies would annotate them as 'expected bad' rather then delete |
| 127 // them from the list, so we would know what they were). |
| 128 |
97 if (proxies_.empty()) { | 129 if (proxies_.empty()) { |
98 NOTREACHED(); | 130 NOTREACHED(); |
99 return false; | 131 return false; |
100 } | 132 } |
101 | 133 |
102 std::string key = proxies_[0].ToURI(); | 134 if (!proxies_[0].is_direct()) { |
103 | 135 std::string key = proxies_[0].ToURI(); |
104 // Mark this proxy as bad. | 136 // Mark this proxy as bad. |
105 ProxyRetryInfoMap::iterator iter = proxy_retry_info->find(key); | 137 ProxyRetryInfoMap::iterator iter = proxy_retry_info->find(key); |
106 if (iter != proxy_retry_info->end()) { | 138 if (iter != proxy_retry_info->end()) { |
107 // TODO(nsylvain): This is not the first time we get this. We should | 139 // TODO(nsylvain): This is not the first time we get this. We should |
108 // double the retry time. Bug 997660. | 140 // double the retry time. Bug 997660. |
109 iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay; | 141 iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay; |
110 } else { | 142 } else { |
111 ProxyRetryInfo retry_info; | 143 ProxyRetryInfo retry_info; |
112 retry_info.current_delay = kProxyRetryDelay; | 144 retry_info.current_delay = kProxyRetryDelay; |
113 retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay; | 145 retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay; |
114 (*proxy_retry_info)[key] = retry_info; | 146 (*proxy_retry_info)[key] = retry_info; |
| 147 } |
115 } | 148 } |
116 | 149 |
117 // Remove this proxy from our list. | 150 // Remove this proxy from our list. |
118 proxies_.erase(proxies_.begin()); | 151 proxies_.erase(proxies_.begin()); |
119 | 152 |
120 return !proxies_.empty(); | 153 return !proxies_.empty(); |
121 } | 154 } |
122 | 155 |
123 } // namespace net | 156 } // namespace net |
OLD | NEW |