[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 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 | #include "base/command_line.h" |
| 7 | #include "base/leak_tracker.h" |
| 8 | #include "base/logging.h" |
| 9 | #include "chrome/browser/browser_process.h" |
| 10 | #include "chrome/browser/chrome_thread.h" |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame^] | 11 | #include "chrome/browser/net/chrome_net_log.h" |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 12 | #include "chrome/browser/net/dns_global.h" |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame^] | 13 | #include "chrome/browser/net/passive_log_collector.h" |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 14 | #include "chrome/browser/net/url_fetcher.h" |
| 15 | #include "chrome/common/chrome_switches.h" |
[email protected] | 9087aa3 | 2010-02-18 08:03:38 | [diff] [blame] | 16 | #include "net/base/mapped_host_resolver.h" |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 17 | #include "net/base/host_cache.h" |
| 18 | #include "net/base/host_resolver.h" |
[email protected] | f2d8c421 | 2010-02-02 00:56:35 | [diff] [blame] | 19 | #include "net/base/host_resolver_impl.h" |
[email protected] | 32eaa33 | 2010-02-08 22:15:54 | [diff] [blame] | 20 | #include "net/base/net_util.h" |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 21 | #include "net/base/network_change_notifier.h" |
[email protected] | eb3cac7 | 2010-02-26 21:07:45 | [diff] [blame] | 22 | #include "net/http/http_auth_filter.h" |
[email protected] | fa55e19 | 2010-02-15 14:25:50 | [diff] [blame] | 23 | #include "net/http/http_auth_handler_factory.h" |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 24 | #include "net/url_request/url_request.h" |
| 25 | |
| 26 | namespace { |
| 27 | |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 28 | net::HostResolver* CreateGlobalHostResolver( |
| 29 | net::NetworkChangeNotifier* network_change_notifier) { |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 30 | net::HostResolver* global_host_resolver = NULL; |
| 31 | |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 32 | const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 33 | |
| 34 | global_host_resolver = |
[email protected] | 9087aa3 | 2010-02-18 08:03:38 | [diff] [blame] | 35 | net::CreateSystemHostResolver(network_change_notifier); |
| 36 | |
| 37 | if (!command_line.HasSwitch(switches::kEnableIPv6)) { |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 38 | // Measure impact of allowing IPv6 support without probing. |
| 39 | const FieldTrial::Probability kDivisor = 100; |
| 40 | const FieldTrial::Probability kProbability = 50; // 50% probability. |
| 41 | FieldTrial* trial = new FieldTrial("IPv6_Probe", kDivisor); |
| 42 | int skip_group = trial->AppendGroup("_IPv6_probe_skipped", kProbability); |
| 43 | trial->AppendGroup("_IPv6_probe_done", |
| 44 | FieldTrial::kAllRemainingProbability); |
| 45 | bool use_ipv6_probe = (trial->group() != skip_group); |
[email protected] | 7be4c7ee | 2010-02-26 05:33:45 | [diff] [blame] | 46 | |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 47 | // Perform probe, and then optionally use result to disable IPv6. |
| 48 | // Some users report confused OS handling of IPv6, leading to large |
| 49 | // latency. If we can show that IPv6 is not supported, then disabliing it |
| 50 | // will work around such problems. |
| 51 | if ((!net::IPv6Supported() && use_ipv6_probe) || |
| 52 | command_line.HasSwitch(switches::kDisableIPv6)) |
| 53 | global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4); |
[email protected] | 9087aa3 | 2010-02-18 08:03:38 | [diff] [blame] | 54 | } |
| 55 | |
[email protected] | 9087aa3 | 2010-02-18 08:03:38 | [diff] [blame] | 56 | // If hostname remappings were specified on the command-line, layer these |
| 57 | // rules on top of the real host resolver. This allows forwarding all requests |
| 58 | // through a designated test server. |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 59 | if (command_line.HasSwitch(switches::kHostResolverRules)) { |
| 60 | net::MappedHostResolver* remapped_resolver = |
| 61 | new net::MappedHostResolver(global_host_resolver); |
| 62 | global_host_resolver = remapped_resolver; |
| 63 | remapped_resolver->SetRulesFromString( |
| 64 | command_line.GetSwitchValueASCII(switches::kHostResolverRules)); |
| 65 | } |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 66 | |
[email protected] | 46f6e20 | 2010-02-26 06:07:25 | [diff] [blame] | 67 | return global_host_resolver; |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | } // namespace |
| 71 | |
| 72 | // The IOThread object must outlive any tasks posted to the IO thread before the |
| 73 | // Quit task. |
| 74 | template <> |
| 75 | struct RunnableMethodTraits<IOThread> { |
| 76 | void RetainCallee(IOThread* /* io_thread */) {} |
| 77 | void ReleaseCallee(IOThread* /* io_thread */) {} |
| 78 | }; |
| 79 | |
| 80 | IOThread::IOThread() |
| 81 | : BrowserProcessSubThread(ChromeThread::IO), |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 82 | globals_(NULL), |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 83 | prefetch_observer_(NULL), |
| 84 | dns_master_(NULL) {} |
| 85 | |
| 86 | IOThread::~IOThread() { |
| 87 | // We cannot rely on our base class to stop the thread since we want our |
| 88 | // CleanUp function to run. |
| 89 | Stop(); |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 90 | DCHECK(!globals_); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 91 | } |
| 92 | |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 93 | IOThread::Globals* IOThread::globals() { |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 94 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 95 | return globals_; |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | void IOThread::InitDnsMaster( |
| 99 | bool prefetching_enabled, |
| 100 | base::TimeDelta max_queue_delay, |
| 101 | size_t max_concurrent, |
| 102 | const chrome_common_net::NameList& hostnames_to_prefetch, |
| 103 | ListValue* referral_list) { |
| 104 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 105 | message_loop()->PostTask( |
| 106 | FROM_HERE, |
| 107 | NewRunnableMethod( |
| 108 | this, |
| 109 | &IOThread::InitDnsMasterOnIOThread, |
| 110 | prefetching_enabled, max_queue_delay, max_concurrent, |
| 111 | hostnames_to_prefetch, referral_list)); |
| 112 | } |
| 113 | |
| 114 | void IOThread::ChangedToOnTheRecord() { |
| 115 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 116 | message_loop()->PostTask( |
| 117 | FROM_HERE, |
| 118 | NewRunnableMethod( |
| 119 | this, |
| 120 | &IOThread::ChangedToOnTheRecordOnIOThread)); |
| 121 | } |
| 122 | |
| 123 | void IOThread::Init() { |
| 124 | BrowserProcessSubThread::Init(); |
| 125 | |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 126 | DCHECK(!globals_); |
| 127 | globals_ = new Globals; |
| 128 | |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame^] | 129 | globals_->net_log.reset(new ChromeNetLog()); |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 130 | globals_->network_change_notifier.reset( |
| 131 | net::NetworkChangeNotifier::CreateDefaultNetworkChangeNotifier()); |
| 132 | globals_->host_resolver = |
| 133 | CreateGlobalHostResolver(globals_->network_change_notifier.get()); |
[email protected] | eb3cac7 | 2010-02-26 21:07:45 | [diff] [blame] | 134 | globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory()); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | void IOThread::CleanUp() { |
| 138 | // Not initialized in Init(). May not be initialized. |
| 139 | if (dns_master_) { |
| 140 | DCHECK(prefetch_observer_); |
| 141 | |
| 142 | dns_master_->Shutdown(); |
| 143 | |
| 144 | // TODO(willchan): Stop reference counting DnsMaster. It's owned by |
| 145 | // IOThread now. |
| 146 | dns_master_->Release(); |
| 147 | dns_master_ = NULL; |
| 148 | chrome_browser_net::FreeDnsPrefetchResources(); |
| 149 | } |
| 150 | |
| 151 | // Not initialized in Init(). May not be initialized. |
| 152 | if (prefetch_observer_) { |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 153 | globals_->host_resolver->RemoveObserver(prefetch_observer_); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 154 | delete prefetch_observer_; |
| 155 | prefetch_observer_ = NULL; |
| 156 | } |
| 157 | |
[email protected] | e4d2dd82 | 2010-02-05 20:57:33 | [diff] [blame] | 158 | // TODO(eroman): hack for http://crbug.com/15513 |
[email protected] | 970210c | 2010-02-19 20:27:02 | [diff] [blame] | 159 | if (globals_->host_resolver->GetAsHostResolverImpl()) { |
| 160 | globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown(); |
[email protected] | e4d2dd82 | 2010-02-05 20:57:33 | [diff] [blame] | 161 | } |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 162 | |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 163 | delete globals_; |
| 164 | globals_ = NULL; |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 165 | |
| 166 | // URLFetcher and URLRequest instances must NOT outlive the IO thread. |
| 167 | // |
| 168 | // Strictly speaking, URLFetcher's CheckForLeaks() should be done on the |
| 169 | // UI thread. However, since there _shouldn't_ be any instances left |
| 170 | // at this point, it shouldn't be a race. |
| 171 | // |
| 172 | // We check URLFetcher first, since if it has leaked then an associated |
| 173 | // URLRequest will also have leaked. However it is more useful to |
| 174 | // crash showing the callstack of URLFetcher's allocation than its |
| 175 | // URLRequest member. |
| 176 | base::LeakTracker<URLFetcher>::CheckForLeaks(); |
| 177 | base::LeakTracker<URLRequest>::CheckForLeaks(); |
| 178 | |
| 179 | BrowserProcessSubThread::CleanUp(); |
| 180 | } |
| 181 | |
[email protected] | eb3cac7 | 2010-02-26 21:07:45 | [diff] [blame] | 182 | net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory() { |
| 183 | net::HttpAuthHandlerRegistryFactory* registry_factory = |
| 184 | net::HttpAuthHandlerFactory::CreateDefault(); |
| 185 | |
| 186 | // Get the whitelist information from the command line, create an |
| 187 | // HttpAuthFilterWhitelist, and attach it to the HttpAuthHandlerFactory. |
| 188 | const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 189 | |
| 190 | // Set the NTLM and Negotiate filters (from the same whitelist) |
| 191 | if (command_line.HasSwitch(switches::kAuthServerWhitelist)) { |
| 192 | std::string ntlm_server_whitelist = |
| 193 | command_line.GetSwitchValueASCII(switches::kAuthServerWhitelist); |
| 194 | net::HttpAuthFilterWhitelist* ntlm_whitelist = |
| 195 | new net::HttpAuthFilterWhitelist(); |
| 196 | net::HttpAuthFilterWhitelist* negotiate_whitelist = |
| 197 | new net::HttpAuthFilterWhitelist(); |
| 198 | |
| 199 | ntlm_whitelist->SetFilters(ntlm_server_whitelist); |
| 200 | negotiate_whitelist->SetFilters(ntlm_server_whitelist); |
| 201 | registry_factory->SetFilter("ntlm", ntlm_whitelist); |
| 202 | registry_factory->SetFilter("negotiate", negotiate_whitelist); |
| 203 | } |
| 204 | |
| 205 | return registry_factory; |
| 206 | } |
| 207 | |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 208 | void IOThread::InitDnsMasterOnIOThread( |
| 209 | bool prefetching_enabled, |
| 210 | base::TimeDelta max_queue_delay, |
| 211 | size_t max_concurrent, |
| 212 | chrome_common_net::NameList hostnames_to_prefetch, |
| 213 | ListValue* referral_list) { |
| 214 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 215 | CHECK(!dns_master_); |
| 216 | |
| 217 | chrome_browser_net::EnableDnsPrefetch(prefetching_enabled); |
| 218 | |
| 219 | dns_master_ = new chrome_browser_net::DnsMaster( |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 220 | globals_->host_resolver, max_queue_delay, max_concurrent); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 221 | dns_master_->AddRef(); |
| 222 | |
| 223 | DCHECK(!prefetch_observer_); |
| 224 | prefetch_observer_ = chrome_browser_net::CreatePrefetchObserver(); |
[email protected] | d13c327 | 2010-02-04 00:24:51 | [diff] [blame] | 225 | globals_->host_resolver->AddObserver(prefetch_observer_); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 226 | |
| 227 | FinalizeDnsPrefetchInitialization( |
| 228 | dns_master_, prefetch_observer_, hostnames_to_prefetch, referral_list); |
| 229 | } |
| 230 | |
| 231 | void IOThread::ChangedToOnTheRecordOnIOThread() { |
| 232 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 233 | |
| 234 | if (dns_master_) { |
| 235 | // Destroy all evidence of our OTR session. |
| 236 | dns_master_->DnsMaster::DiscardAllResults(); |
| 237 | } |
| 238 | |
| 239 | // Clear the host cache to avoid showing entries from the OTR session |
| 240 | // in about:net-internals. |
[email protected] | 970210c | 2010-02-19 20:27:02 | [diff] [blame] | 241 | if (globals_->host_resolver->GetAsHostResolverImpl()) { |
| 242 | net::HostCache* host_cache = |
| 243 | globals_->host_resolver.get()->GetAsHostResolverImpl()->cache(); |
[email protected] | f2d8c421 | 2010-02-02 00:56:35 | [diff] [blame] | 244 | if (host_cache) |
| 245 | host_cache->clear(); |
| 246 | } |
[email protected] | 9e743cd | 2010-03-16 07:03:53 | [diff] [blame^] | 247 | // Clear all of the passively logged data. |
| 248 | // TODO(eroman): this is a bit heavy handed, really all we need to do is |
| 249 | // clear the data pertaining to off the record context. |
| 250 | globals_->net_log->passive_collector()->Clear(); |
[email protected] | 0ac8368 | 2010-01-22 17:46:27 | [diff] [blame] | 251 | } |