io_thread.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 "chrome/browser/io_thread.h" 6 7#include "base/command_line.h" 8#include "base/leak_tracker.h" 9#include "base/logging.h" 10#include "base/string_number_conversions.h" 11#include "base/string_split.h" 12#include "base/string_util.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/chrome_thread.h" 15#include "chrome/browser/gpu_process_host.h" 16#include "chrome/browser/net/chrome_net_log.h" 17#include "chrome/browser/net/predictor_api.h" 18#include "chrome/browser/net/passive_log_collector.h" 19#include "chrome/common/chrome_switches.h" 20#include "chrome/common/net/url_fetcher.h" 21#include "net/base/mapped_host_resolver.h" 22#include "net/base/host_cache.h" 23#include "net/base/host_resolver.h" 24#include "net/base/host_resolver_impl.h" 25#include "net/base/net_util.h" 26#include "net/http/http_auth_filter.h" 27#include "net/http/http_auth_handler_factory.h" 28 29namespace { 30 31net::HostResolver* CreateGlobalHostResolver(net::NetLog* net_log) { 32 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 33 34 size_t parallelism = net::HostResolver::kDefaultParallelism; 35 36 // Use the concurrency override from the command-line, if any. 37 if (command_line.HasSwitch(switches::kHostResolverParallelism)) { 38 std::string s = 39 command_line.GetSwitchValueASCII(switches::kHostResolverParallelism); 40 41 // Parse the switch (it should be a positive integer formatted as decimal). 42 int n; 43 if (base::StringToInt(s, &n) && n > 0) { 44 parallelism = static_cast<size_t>(n); 45 } else { 46 LOG(ERROR) << "Invalid switch for host resolver parallelism: " << s; 47 } 48 } 49 50 net::HostResolver* global_host_resolver = 51 net::CreateSystemHostResolver(parallelism, net_log); 52 53 // Determine if we should disable IPv6 support. 54 if (!command_line.HasSwitch(switches::kEnableIPv6)) { 55 if (command_line.HasSwitch(switches::kDisableIPv6)) { 56 global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4); 57 } else { 58 net::HostResolverImpl* host_resolver_impl = 59 global_host_resolver->GetAsHostResolverImpl(); 60 if (host_resolver_impl != NULL) { 61 // Use probe to decide if support is warranted. 62 host_resolver_impl->ProbeIPv6Support(); 63 } 64 } 65 } 66 67 // If hostname remappings were specified on the command-line, layer these 68 // rules on top of the real host resolver. This allows forwarding all requests 69 // through a designated test server. 70 if (!command_line.HasSwitch(switches::kHostResolverRules)) 71 return global_host_resolver; 72 73 net::MappedHostResolver* remapped_resolver = 74 new net::MappedHostResolver(global_host_resolver); 75 remapped_resolver->SetRulesFromString( 76 command_line.GetSwitchValueASCII(switches::kHostResolverRules)); 77 return remapped_resolver; 78} 79 80class LoggingNetworkChangeObserver 81 : public net::NetworkChangeNotifier::Observer { 82 public: 83 // |net_log| must remain valid throughout our lifetime. 84 explicit LoggingNetworkChangeObserver(net::NetLog* net_log) 85 : net_log_(net_log) { 86 net::NetworkChangeNotifier::AddObserver(this); 87 } 88 89 ~LoggingNetworkChangeObserver() { 90 net::NetworkChangeNotifier::RemoveObserver(this); 91 } 92 93 virtual void OnIPAddressChanged() { 94 LOG(INFO) << "Observed a change to the network IP addresses"; 95 96 net_log_->AddEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED, 97 base::TimeTicks::Now(), 98 net::NetLog::Source(), 99 net::NetLog::PHASE_NONE, 100 NULL); 101 } 102 103 private: 104 net::NetLog* net_log_; 105 DISALLOW_COPY_AND_ASSIGN(LoggingNetworkChangeObserver); 106}; 107 108} // namespace 109 110// The IOThread object must outlive any tasks posted to the IO thread before the 111// Quit task. 112DISABLE_RUNNABLE_METHOD_REFCOUNT(IOThread); 113 114IOThread::IOThread() 115 : BrowserProcessSubThread(ChromeThread::IO), 116 globals_(NULL), 117 speculative_interceptor_(NULL), 118 predictor_(NULL) {} 119 120IOThread::~IOThread() { 121 // We cannot rely on our base class to stop the thread since we want our 122 // CleanUp function to run. 123 Stop(); 124 DCHECK(!globals_); 125} 126 127IOThread::Globals* IOThread::globals() { 128 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 129 return globals_; 130} 131 132void IOThread::InitNetworkPredictor( 133 bool prefetching_enabled, 134 base::TimeDelta max_dns_queue_delay, 135 size_t max_concurrent, 136 const chrome_common_net::UrlList& startup_urls, 137 ListValue* referral_list, 138 bool preconnect_enabled) { 139 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 140 message_loop()->PostTask( 141 FROM_HERE, 142 NewRunnableMethod( 143 this, 144 &IOThread::InitNetworkPredictorOnIOThread, 145 prefetching_enabled, max_dns_queue_delay, max_concurrent, 146 startup_urls, referral_list, preconnect_enabled)); 147} 148 149void IOThread::ChangedToOnTheRecord() { 150 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 151 message_loop()->PostTask( 152 FROM_HERE, 153 NewRunnableMethod( 154 this, 155 &IOThread::ChangedToOnTheRecordOnIOThread)); 156} 157 158void IOThread::Init() { 159 BrowserProcessSubThread::Init(); 160 161 DCHECK(!globals_); 162 globals_ = new Globals; 163 164 globals_->net_log.reset(new ChromeNetLog()); 165 166 // Add an observer that will emit network change events to the ChromeNetLog. 167 // Assuming NetworkChangeNotifier dispatches in FIFO order, we should be 168 // logging the network change before other IO thread consumers respond to it. 169 network_change_observer_.reset( 170 new LoggingNetworkChangeObserver(globals_->net_log.get())); 171 172 globals_->host_resolver = CreateGlobalHostResolver(globals_->net_log.get()); 173 globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory( 174 globals_->host_resolver)); 175} 176 177void IOThread::CleanUp() { 178 // This must be reset before the ChromeNetLog is destroyed. 179 network_change_observer_.reset(); 180 181 // If any child processes are still running, terminate them and 182 // and delete the BrowserChildProcessHost instances to release whatever 183 // IO thread only resources they are referencing. 184 BrowserChildProcessHost::TerminateAll(); 185 186 // Not initialized in Init(). May not be initialized. 187 if (predictor_) { 188 predictor_->Shutdown(); 189 190 // TODO(willchan): Stop reference counting Predictor. It's owned by 191 // IOThread now. 192 predictor_->Release(); 193 predictor_ = NULL; 194 chrome_browser_net::FreePredictorResources(); 195 } 196 197 // Deletion will unregister this interceptor. 198 delete speculative_interceptor_; 199 speculative_interceptor_ = NULL; 200 201 // TODO(eroman): hack for http://crbug.com/15513 202 if (globals_->host_resolver->GetAsHostResolverImpl()) { 203 globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown(); 204 } 205 206 // We will delete the NetLog as part of CleanUpAfterMessageLoopDestruction() 207 // in case any of the message loop destruction observers try to access it. 208 deferred_net_log_to_delete_.reset(globals_->net_log.release()); 209 210 delete globals_; 211 globals_ = NULL; 212 213 BrowserProcessSubThread::CleanUp(); 214} 215 216void IOThread::CleanUpAfterMessageLoopDestruction() { 217 // TODO(eroman): get rid of this special case for 39723. If we could instead 218 // have a method that runs after the message loop destruction obsevers have 219 // run, but before the message loop itself is destroyed, we could safely 220 // combine the two cleanups. 221 deferred_net_log_to_delete_.reset(); 222 BrowserProcessSubThread::CleanUpAfterMessageLoopDestruction(); 223 224 // URLRequest instances must NOT outlive the IO thread. 225 // 226 // To allow for URLRequests to be deleted from 227 // MessageLoop::DestructionObserver this check has to happen after CleanUp 228 // (which runs before DestructionObservers). 229 base::LeakTracker<URLRequest>::CheckForLeaks(); 230} 231 232net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory( 233 net::HostResolver* resolver) { 234 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 235 236 // Get the whitelist information from the command line, create an 237 // HttpAuthFilterWhitelist, and attach it to the HttpAuthHandlerFactory. 238 net::HttpAuthFilterWhitelist* auth_filter_default_credentials = NULL; 239 if (command_line.HasSwitch(switches::kAuthServerWhitelist)) { 240 auth_filter_default_credentials = new net::HttpAuthFilterWhitelist( 241 command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist)); 242 } 243 net::HttpAuthFilterWhitelist* auth_filter_delegate = NULL; 244 if (command_line.HasSwitch(switches::kAuthNegotiateDelegateWhitelist)) { 245 auth_filter_delegate = new net::HttpAuthFilterWhitelist( 246 command_line.GetSwitchValueASCII( 247 switches::kAuthNegotiateDelegateWhitelist)); 248 } 249 globals_->url_security_manager.reset( 250 net::URLSecurityManager::Create(auth_filter_default_credentials, 251 auth_filter_delegate)); 252 253 // Determine which schemes are supported. 254 std::string csv_auth_schemes = "basic,digest,ntlm,negotiate"; 255 if (command_line.HasSwitch(switches::kAuthSchemes)) 256 csv_auth_schemes = StringToLowerASCII( 257 command_line.GetSwitchValueASCII(switches::kAuthSchemes)); 258 std::vector<std::string> supported_schemes; 259 SplitString(csv_auth_schemes, ',', &supported_schemes); 260 261 return net::HttpAuthHandlerRegistryFactory::Create( 262 supported_schemes, 263 globals_->url_security_manager.get(), 264 resolver, 265 command_line.HasSwitch(switches::kDisableAuthNegotiateCnameLookup), 266 command_line.HasSwitch(switches::kEnableAuthNegotiatePort)); 267} 268 269void IOThread::InitNetworkPredictorOnIOThread( 270 bool prefetching_enabled, 271 base::TimeDelta max_dns_queue_delay, 272 size_t max_concurrent, 273 const chrome_common_net::UrlList& startup_urls, 274 ListValue* referral_list, 275 bool preconnect_enabled) { 276 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 277 CHECK(!predictor_); 278 279 chrome_browser_net::EnablePredictor(prefetching_enabled); 280 281 predictor_ = new chrome_browser_net::Predictor( 282 globals_->host_resolver, 283 max_dns_queue_delay, 284 max_concurrent, 285 preconnect_enabled); 286 predictor_->AddRef(); 287 288 // Speculative_interceptor_ is used to predict subresource usage. 289 DCHECK(!speculative_interceptor_); 290 speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor; 291 292 FinalizePredictorInitialization(predictor_, startup_urls, referral_list); 293} 294 295void IOThread::ChangedToOnTheRecordOnIOThread() { 296 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 297 298 if (predictor_) { 299 // Destroy all evidence of our OTR session. 300 predictor_->Predictor::DiscardAllResults(); 301 } 302 303 // Clear the host cache to avoid showing entries from the OTR session 304 // in about:net-internals. 305 if (globals_->host_resolver->GetAsHostResolverImpl()) { 306 net::HostCache* host_cache = 307 globals_->host_resolver.get()->GetAsHostResolverImpl()->cache(); 308 if (host_cache) 309 host_cache->clear(); 310 } 311 // Clear all of the passively logged data. 312 // TODO(eroman): this is a bit heavy handed, really all we need to do is 313 // clear the data pertaining to off the record context. 314 globals_->net_log->passive_collector()->Clear(); 315} 316