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