| 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 |