blob: 8d1f2508c21ece05f819f2bdddeaa4bda80cf7f5 [file] [log] [blame]
[email protected]0ac83682010-01-22 17:46:271// 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"
[email protected]e83326f2010-07-31 17:29:256
[email protected]0ac83682010-01-22 17:46:277#include "base/command_line.h"
8#include "base/leak_tracker.h"
9#include "base/logging.h"
[email protected]e83326f2010-07-31 17:29:2510#include "base/string_number_conversions.h"
[email protected]0ac83682010-01-22 17:46:2711#include "chrome/browser/browser_process.h"
12#include "chrome/browser/chrome_thread.h"
[email protected]1082b1d2010-03-30 00:31:2213#include "chrome/browser/gpu_process_host.h"
[email protected]9e743cd2010-03-16 07:03:5314#include "chrome/browser/net/chrome_net_log.h"
[email protected]3530cd92010-06-27 06:22:0115#include "chrome/browser/net/predictor_api.h"
[email protected]9e743cd2010-03-16 07:03:5316#include "chrome/browser/net/passive_log_collector.h"
[email protected]0ac83682010-01-22 17:46:2717#include "chrome/common/chrome_switches.h"
[email protected]68d2a05f2010-05-07 21:39:5518#include "chrome/common/net/url_fetcher.h"
[email protected]9087aa32010-02-18 08:03:3819#include "net/base/mapped_host_resolver.h"
[email protected]0ac83682010-01-22 17:46:2720#include "net/base/host_cache.h"
21#include "net/base/host_resolver.h"
[email protected]f2d8c4212010-02-02 00:56:3522#include "net/base/host_resolver_impl.h"
[email protected]32eaa332010-02-08 22:15:5423#include "net/base/net_util.h"
[email protected]eb3cac72010-02-26 21:07:4524#include "net/http/http_auth_filter.h"
[email protected]fa55e192010-02-15 14:25:5025#include "net/http/http_auth_handler_factory.h"
[email protected]e5ae96a2010-04-14 20:12:4526#include "net/http/http_auth_handler_negotiate.h"
[email protected]0ac83682010-01-22 17:46:2727
28namespace {
29
[email protected]66761b952010-06-25 21:30:3830net::HostResolver* CreateGlobalHostResolver() {
[email protected]0ac83682010-01-22 17:46:2731 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
[email protected]962b98212010-07-17 03:37:5132
33 size_t parallelism = net::HostResolver::kDefaultParallelism;
34
35 // Use the concurrency override from the command-line, if any.
36 if (command_line.HasSwitch(switches::kHostResolverParallelism)) {
37 std::string s =
38 command_line.GetSwitchValueASCII(switches::kHostResolverParallelism);
39
40 // Parse the switch (it should be a positive integer formatted as decimal).
41 int n;
[email protected]e83326f2010-07-31 17:29:2542 if (base::StringToInt(s, &n) && n > 0) {
[email protected]962b98212010-07-17 03:37:5143 parallelism = static_cast<size_t>(n);
44 } else {
45 LOG(ERROR) << "Invalid switch for host resolver parallelism: " << s;
46 }
47 }
48
49 net::HostResolver* global_host_resolver =
50 net::CreateSystemHostResolver(parallelism);
[email protected]9087aa32010-02-18 08:03:3851
[email protected]0f8f1b432010-03-16 19:06:0352 // Determine if we should disable IPv6 support.
[email protected]9087aa32010-02-18 08:03:3853 if (!command_line.HasSwitch(switches::kEnableIPv6)) {
[email protected]0f8f1b432010-03-16 19:06:0354 if (command_line.HasSwitch(switches::kDisableIPv6)) {
[email protected]46f6e202010-02-26 06:07:2555 global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
[email protected]0f8f1b432010-03-16 19:06:0356 } else {
57 net::HostResolverImpl* host_resolver_impl =
58 global_host_resolver->GetAsHostResolverImpl();
59 if (host_resolver_impl != NULL) {
60 // (optionally) Use probe to decide if support is warranted.
[email protected]26b0f372010-03-24 21:58:3161 bool use_ipv6_probe = true;
[email protected]0f8f1b432010-03-16 19:06:0362
[email protected]26b0f372010-03-24 21:58:3163#if defined(OS_WIN)
[email protected]0f8f1b432010-03-16 19:06:0364 // Measure impact of probing to allow IPv6.
65 // Some users report confused OS handling of IPv6, leading to large
66 // latency. If we can show that IPv6 is not supported, then disabliing
[email protected]26b0f372010-03-24 21:58:3167 // it will work around such problems. This is the test of the probe.
[email protected]0f8f1b432010-03-16 19:06:0368 const FieldTrial::Probability kDivisor = 100;
69 const FieldTrial::Probability kProbability = 50; // 50% probability.
70 FieldTrial* trial = new FieldTrial("IPv6_Probe", kDivisor);
71 int skip_group = trial->AppendGroup("_IPv6_probe_skipped",
72 kProbability);
73 trial->AppendGroup("_IPv6_probe_done",
74 FieldTrial::kAllRemainingProbability);
[email protected]26b0f372010-03-24 21:58:3175 use_ipv6_probe = (trial->group() != skip_group);
76#endif
77
[email protected]0f8f1b432010-03-16 19:06:0378 if (use_ipv6_probe)
79 host_resolver_impl->ProbeIPv6Support();
80 }
81 }
[email protected]9087aa32010-02-18 08:03:3882 }
83
[email protected]9087aa32010-02-18 08:03:3884 // If hostname remappings were specified on the command-line, layer these
85 // rules on top of the real host resolver. This allows forwarding all requests
86 // through a designated test server.
[email protected]0f8f1b432010-03-16 19:06:0387 if (!command_line.HasSwitch(switches::kHostResolverRules))
88 return global_host_resolver;
[email protected]0ac83682010-01-22 17:46:2789
[email protected]0f8f1b432010-03-16 19:06:0390 net::MappedHostResolver* remapped_resolver =
91 new net::MappedHostResolver(global_host_resolver);
92 remapped_resolver->SetRulesFromString(
93 command_line.GetSwitchValueASCII(switches::kHostResolverRules));
94 return remapped_resolver;
[email protected]0ac83682010-01-22 17:46:2795}
96
[email protected]58bc7042010-07-07 18:04:1497class LoggingNetworkChangeObserver
98 : public net::NetworkChangeNotifier::Observer {
99 public:
100 // |net_log| must remain valid throughout our lifetime.
101 explicit LoggingNetworkChangeObserver(net::NetLog* net_log)
102 : net_log_(net_log) {
103 net::NetworkChangeNotifier::AddObserver(this);
104 }
105
106 ~LoggingNetworkChangeObserver() {
107 net::NetworkChangeNotifier::RemoveObserver(this);
108 }
109
110 virtual void OnIPAddressChanged() {
111 LOG(INFO) << "Observed a change to the network IP addresses";
112
113 net::NetLog::Source global_source;
114
115 // TODO(eroman): We shouldn't need to assign an ID to this source, since
116 // conceptually it is the "global event stream". However
117 // currently the javascript does a grouping on source id, so
118 // the display will look weird if we don't give it one.
119 global_source.id = net_log_->NextID();
120
121 net_log_->AddEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSSES_CHANGED,
122 base::TimeTicks::Now(),
123 global_source,
124 net::NetLog::PHASE_NONE,
125 NULL);
126 }
127
128 private:
129 net::NetLog* net_log_;
130 DISALLOW_COPY_AND_ASSIGN(LoggingNetworkChangeObserver);
131};
132
[email protected]0ac83682010-01-22 17:46:27133} // namespace
134
135// The IOThread object must outlive any tasks posted to the IO thread before the
136// Quit task.
[email protected]c56428f22010-06-16 02:17:23137DISABLE_RUNNABLE_METHOD_REFCOUNT(IOThread);
[email protected]0ac83682010-01-22 17:46:27138
139IOThread::IOThread()
140 : BrowserProcessSubThread(ChromeThread::IO),
[email protected]d13c3272010-02-04 00:24:51141 globals_(NULL),
[email protected]c5629c32010-06-23 01:22:43142 speculative_interceptor_(NULL),
[email protected]0ac83682010-01-22 17:46:27143 prefetch_observer_(NULL),
[email protected]74be069e82010-06-25 00:12:49144 predictor_(NULL) {}
[email protected]0ac83682010-01-22 17:46:27145
146IOThread::~IOThread() {
147 // We cannot rely on our base class to stop the thread since we want our
148 // CleanUp function to run.
149 Stop();
[email protected]d13c3272010-02-04 00:24:51150 DCHECK(!globals_);
[email protected]0ac83682010-01-22 17:46:27151}
152
[email protected]d13c3272010-02-04 00:24:51153IOThread::Globals* IOThread::globals() {
[email protected]0ac83682010-01-22 17:46:27154 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]d13c3272010-02-04 00:24:51155 return globals_;
[email protected]0ac83682010-01-22 17:46:27156}
157
[email protected]74be069e82010-06-25 00:12:49158void IOThread::InitNetworkPredictor(
[email protected]0ac83682010-01-22 17:46:27159 bool prefetching_enabled,
[email protected]74be069e82010-06-25 00:12:49160 base::TimeDelta max_dns_queue_delay,
[email protected]0ac83682010-01-22 17:46:27161 size_t max_concurrent,
[email protected]c5629c32010-06-23 01:22:43162 const chrome_common_net::UrlList& startup_urls,
[email protected]760d970a2010-05-18 00:39:18163 ListValue* referral_list,
164 bool preconnect_enabled) {
[email protected]0ac83682010-01-22 17:46:27165 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
166 message_loop()->PostTask(
167 FROM_HERE,
168 NewRunnableMethod(
169 this,
[email protected]74be069e82010-06-25 00:12:49170 &IOThread::InitNetworkPredictorOnIOThread,
171 prefetching_enabled, max_dns_queue_delay, max_concurrent,
[email protected]c5629c32010-06-23 01:22:43172 startup_urls, referral_list, preconnect_enabled));
[email protected]0ac83682010-01-22 17:46:27173}
174
175void IOThread::ChangedToOnTheRecord() {
176 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
177 message_loop()->PostTask(
178 FROM_HERE,
179 NewRunnableMethod(
180 this,
181 &IOThread::ChangedToOnTheRecordOnIOThread));
182}
183
184void IOThread::Init() {
185 BrowserProcessSubThread::Init();
186
[email protected]d13c3272010-02-04 00:24:51187 DCHECK(!globals_);
188 globals_ = new Globals;
189
[email protected]aa92ba22010-06-21 23:17:24190 globals_->net_log.reset(new ChromeNetLog());
[email protected]58bc7042010-07-07 18:04:14191
192 // Add an observer that will emit network change events to the ChromeNetLog.
193 // Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
194 // logging the network change before other IO thread consumers respond to it.
195 network_change_observer_.reset(
196 new LoggingNetworkChangeObserver(globals_->net_log.get()));
197
[email protected]66761b952010-06-25 21:30:38198 globals_->host_resolver = CreateGlobalHostResolver();
[email protected]65d34382010-07-01 18:12:26199 globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
200 globals_->host_resolver));
[email protected]0ac83682010-01-22 17:46:27201}
202
[email protected]2a92cd92010-04-27 00:01:41203void IOThread::CleanUp() {
[email protected]58bc7042010-07-07 18:04:14204 // This must be reset before the ChromeNetLog is destroyed.
205 network_change_observer_.reset();
206
[email protected]325a71f2010-05-21 23:05:27207 // If any child processes are still running, terminate them and
[email protected]d27893f62010-07-03 05:47:42208 // and delete the BrowserChildProcessHost instances to release whatever
[email protected]325a71f2010-05-21 23:05:27209 // IO thread only resources they are referencing.
[email protected]d27893f62010-07-03 05:47:42210 BrowserChildProcessHost::TerminateAll();
[email protected]325a71f2010-05-21 23:05:27211
[email protected]0ac83682010-01-22 17:46:27212 // Not initialized in Init(). May not be initialized.
[email protected]74be069e82010-06-25 00:12:49213 if (predictor_) {
214 predictor_->Shutdown();
[email protected]0ac83682010-01-22 17:46:27215
[email protected]74be069e82010-06-25 00:12:49216 // TODO(willchan): Stop reference counting Predictor. It's owned by
[email protected]0ac83682010-01-22 17:46:27217 // IOThread now.
[email protected]74be069e82010-06-25 00:12:49218 predictor_->Release();
219 predictor_ = NULL;
220 chrome_browser_net::FreePredictorResources();
[email protected]0ac83682010-01-22 17:46:27221 }
222
[email protected]c5629c32010-06-23 01:22:43223 // Deletion will unregister this interceptor.
224 delete speculative_interceptor_;
225 speculative_interceptor_ = NULL;
226
[email protected]0ac83682010-01-22 17:46:27227 // Not initialized in Init(). May not be initialized.
228 if (prefetch_observer_) {
[email protected]d13c3272010-02-04 00:24:51229 globals_->host_resolver->RemoveObserver(prefetch_observer_);
[email protected]0ac83682010-01-22 17:46:27230 delete prefetch_observer_;
231 prefetch_observer_ = NULL;
232 }
233
[email protected]e4d2dd822010-02-05 20:57:33234 // TODO(eroman): hack for http://crbug.com/15513
[email protected]970210c2010-02-19 20:27:02235 if (globals_->host_resolver->GetAsHostResolverImpl()) {
236 globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown();
[email protected]e4d2dd822010-02-05 20:57:33237 }
[email protected]0ac83682010-01-22 17:46:27238
[email protected]2a92cd92010-04-27 00:01:41239 // We will delete the NetLog as part of CleanUpAfterMessageLoopDestruction()
240 // in case any of the message loop destruction observers try to access it.
241 deferred_net_log_to_delete_.reset(globals_->net_log.release());
242
[email protected]d13c3272010-02-04 00:24:51243 delete globals_;
244 globals_ = NULL;
[email protected]0ac83682010-01-22 17:46:27245
[email protected]71197432010-06-15 03:09:12246 // URLRequest instances must NOT outlive the IO thread.
[email protected]0ac83682010-01-22 17:46:27247 base::LeakTracker<URLRequest>::CheckForLeaks();
248
[email protected]2a92cd92010-04-27 00:01:41249 BrowserProcessSubThread::CleanUp();
250}
251
252void IOThread::CleanUpAfterMessageLoopDestruction() {
253 // TODO(eroman): get rid of this special case for 39723. If we could instead
254 // have a method that runs after the message loop destruction obsevers have
255 // run, but before the message loop itself is destroyed, we could safely
256 // combine the two cleanups.
257 deferred_net_log_to_delete_.reset();
[email protected]9aa33e82010-04-15 00:15:39258 BrowserProcessSubThread::CleanUpAfterMessageLoopDestruction();
[email protected]0ac83682010-01-22 17:46:27259}
260
[email protected]65d34382010-07-01 18:12:26261net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
262 net::HostResolver* resolver) {
[email protected]b4955e7d2010-04-16 20:22:30263 net::HttpAuthFilterWhitelist* auth_filter = NULL;
[email protected]eb3cac72010-02-26 21:07:45264
265 // Get the whitelist information from the command line, create an
266 // HttpAuthFilterWhitelist, and attach it to the HttpAuthHandlerFactory.
267 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
268
[email protected]eb3cac72010-02-26 21:07:45269 if (command_line.HasSwitch(switches::kAuthServerWhitelist)) {
[email protected]8f777e52010-03-30 20:48:15270 std::string auth_server_whitelist =
[email protected]eb3cac72010-02-26 21:07:45271 command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist);
[email protected]8f777e52010-03-30 20:48:15272
[email protected]b4955e7d2010-04-16 20:22:30273 // Create a whitelist filter.
274 auth_filter = new net::HttpAuthFilterWhitelist();
275 auth_filter->SetWhitelist(auth_server_whitelist);
[email protected]eb3cac72010-02-26 21:07:45276 }
277
[email protected]aef04272010-06-28 18:03:04278 // Set the flag that enables or disables the Negotiate auth handler.
[email protected]aef04272010-06-28 18:03:04279 static const bool kNegotiateAuthEnabledDefault = true;
[email protected]9bc3b4a2010-07-20 02:30:49280
[email protected]aef04272010-06-28 18:03:04281 bool negotiate_auth_enabled = kNegotiateAuthEnabledDefault;
282 if (command_line.HasSwitch(switches::kExperimentalEnableNegotiateAuth)) {
283 std::string enable_negotiate_auth = command_line.GetSwitchValueASCII(
284 switches::kExperimentalEnableNegotiateAuth);
285 // Enabled if no value, or value is 'true'. Disabled otherwise.
286 negotiate_auth_enabled =
287 enable_negotiate_auth.empty() ||
288 (StringToLowerASCII(enable_negotiate_auth) == "true");
289 }
290
[email protected]b4955e7d2010-04-16 20:22:30291 net::HttpAuthHandlerRegistryFactory* registry_factory =
292 net::HttpAuthHandlerFactory::CreateDefault();
293
294 globals_->url_security_manager.reset(
295 net::URLSecurityManager::Create(auth_filter));
296
297 // Add the security manager to the auth factories that need it.
298 registry_factory->SetURLSecurityManager("ntlm",
299 globals_->url_security_manager.get());
300 registry_factory->SetURLSecurityManager("negotiate",
301 globals_->url_security_manager.get());
[email protected]aef04272010-06-28 18:03:04302 if (negotiate_auth_enabled) {
303 // Configure the Negotiate settings for the Kerberos SPN.
304 // TODO(cbentzel): Read the related IE registry settings on Windows builds.
305 // TODO(cbentzel): Ugly use of static_cast here.
306 net::HttpAuthHandlerNegotiate::Factory* negotiate_factory =
307 static_cast<net::HttpAuthHandlerNegotiate::Factory*>(
308 registry_factory->GetSchemeFactory("negotiate"));
309 DCHECK(negotiate_factory);
[email protected]7658fb22b2010-07-10 00:27:00310 negotiate_factory->set_host_resolver(resolver);
[email protected]aef04272010-06-28 18:03:04311 if (command_line.HasSwitch(switches::kDisableAuthNegotiateCnameLookup))
312 negotiate_factory->set_disable_cname_lookup(true);
313 if (command_line.HasSwitch(switches::kEnableAuthNegotiatePort))
314 negotiate_factory->set_use_port(true);
315 } else {
316 // Disable the Negotiate authentication handler.
317 registry_factory->RegisterSchemeFactory("negotiate", NULL);
318 }
[email protected]eb3cac72010-02-26 21:07:45319 return registry_factory;
320}
321
[email protected]74be069e82010-06-25 00:12:49322void IOThread::InitNetworkPredictorOnIOThread(
[email protected]0ac83682010-01-22 17:46:27323 bool prefetching_enabled,
[email protected]74be069e82010-06-25 00:12:49324 base::TimeDelta max_dns_queue_delay,
[email protected]0ac83682010-01-22 17:46:27325 size_t max_concurrent,
[email protected]c5629c32010-06-23 01:22:43326 const chrome_common_net::UrlList& startup_urls,
[email protected]760d970a2010-05-18 00:39:18327 ListValue* referral_list,
328 bool preconnect_enabled) {
[email protected]0ac83682010-01-22 17:46:27329 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]74be069e82010-06-25 00:12:49330 CHECK(!predictor_);
[email protected]0ac83682010-01-22 17:46:27331
[email protected]74be069e82010-06-25 00:12:49332 chrome_browser_net::EnablePredictor(prefetching_enabled);
[email protected]0ac83682010-01-22 17:46:27333
[email protected]74be069e82010-06-25 00:12:49334 predictor_ = new chrome_browser_net::Predictor(
[email protected]760d970a2010-05-18 00:39:18335 globals_->host_resolver,
[email protected]74be069e82010-06-25 00:12:49336 max_dns_queue_delay,
[email protected]760d970a2010-05-18 00:39:18337 max_concurrent,
338 preconnect_enabled);
[email protected]74be069e82010-06-25 00:12:49339 predictor_->AddRef();
[email protected]0ac83682010-01-22 17:46:27340
[email protected]f4ef861ba2010-07-28 22:37:23341 // Speculative_interceptor_ is used to predict subresource usage.
342 DCHECK(!speculative_interceptor_);
343 speculative_interceptor_ = new chrome_browser_net::ConnectInterceptor;
344
345 // TODO(jar): We can completely replace prefetch_observer with
346 // speculative_interceptor.
347 // Prefetch_observer is used to monitor initial resolutions.
348 DCHECK(!prefetch_observer_);
349 prefetch_observer_ = chrome_browser_net::CreateResolverObserver();
350 globals_->host_resolver->AddObserver(prefetch_observer_);
[email protected]0ac83682010-01-22 17:46:27351
[email protected]74be069e82010-06-25 00:12:49352 FinalizePredictorInitialization(
353 predictor_, prefetch_observer_, startup_urls, referral_list);
[email protected]0ac83682010-01-22 17:46:27354}
355
356void IOThread::ChangedToOnTheRecordOnIOThread() {
357 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
358
[email protected]74be069e82010-06-25 00:12:49359 if (predictor_) {
[email protected]0ac83682010-01-22 17:46:27360 // Destroy all evidence of our OTR session.
[email protected]74be069e82010-06-25 00:12:49361 predictor_->Predictor::DiscardAllResults();
[email protected]0ac83682010-01-22 17:46:27362 }
363
364 // Clear the host cache to avoid showing entries from the OTR session
365 // in about:net-internals.
[email protected]970210c2010-02-19 20:27:02366 if (globals_->host_resolver->GetAsHostResolverImpl()) {
367 net::HostCache* host_cache =
368 globals_->host_resolver.get()->GetAsHostResolverImpl()->cache();
[email protected]f2d8c4212010-02-02 00:56:35369 if (host_cache)
370 host_cache->clear();
371 }
[email protected]9e743cd2010-03-16 07:03:53372 // Clear all of the passively logged data.
373 // TODO(eroman): this is a bit heavy handed, really all we need to do is
374 // clear the data pertaining to off the record context.
375 globals_->net_log->passive_collector()->Clear();
[email protected]0ac83682010-01-22 17:46:27376}