[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" |
| 11 | #include "chrome/browser/net/dns_global.h" |
| 12 | #include "chrome/browser/net/url_fetcher.h" |
| 13 | #include "chrome/common/chrome_switches.h" |
| 14 | #include "net/base/fixed_host_resolver.h" |
| 15 | #include "net/base/host_cache.h" |
| 16 | #include "net/base/host_resolver.h" |
| 17 | #include "net/url_request/url_request.h" |
| 18 | |
| 19 | namespace { |
| 20 | |
| 21 | net::HostResolver* CreateGlobalHostResolver() { |
| 22 | net::HostResolver* global_host_resolver = NULL; |
| 23 | |
| 24 | const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 25 | |
| 26 | // The FixedHostResolver allows us to send all network requests through |
| 27 | // a designated test server. |
| 28 | if (command_line.HasSwitch(switches::kFixedHost)) { |
| 29 | std::string host = |
| 30 | command_line.GetSwitchValueASCII(switches::kFixedHost); |
| 31 | global_host_resolver = new net::FixedHostResolver(host); |
| 32 | } else { |
| 33 | global_host_resolver = net::CreateSystemHostResolver(); |
| 34 | |
| 35 | if (command_line.HasSwitch(switches::kDisableIPv6)) |
| 36 | global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4); |
| 37 | } |
| 38 | |
| 39 | return global_host_resolver; |
| 40 | } |
| 41 | |
| 42 | } // namespace |
| 43 | |
| 44 | // The IOThread object must outlive any tasks posted to the IO thread before the |
| 45 | // Quit task. |
| 46 | template <> |
| 47 | struct RunnableMethodTraits<IOThread> { |
| 48 | void RetainCallee(IOThread* /* io_thread */) {} |
| 49 | void ReleaseCallee(IOThread* /* io_thread */) {} |
| 50 | }; |
| 51 | |
| 52 | IOThread::IOThread() |
| 53 | : BrowserProcessSubThread(ChromeThread::IO), |
| 54 | host_resolver_(NULL), |
| 55 | prefetch_observer_(NULL), |
| 56 | dns_master_(NULL) {} |
| 57 | |
| 58 | IOThread::~IOThread() { |
| 59 | // We cannot rely on our base class to stop the thread since we want our |
| 60 | // CleanUp function to run. |
| 61 | Stop(); |
| 62 | } |
| 63 | |
| 64 | net::HostResolver* IOThread::host_resolver() { |
| 65 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 66 | return host_resolver_; |
| 67 | } |
| 68 | |
| 69 | void IOThread::InitDnsMaster( |
| 70 | bool prefetching_enabled, |
| 71 | base::TimeDelta max_queue_delay, |
| 72 | size_t max_concurrent, |
| 73 | const chrome_common_net::NameList& hostnames_to_prefetch, |
| 74 | ListValue* referral_list) { |
| 75 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 76 | message_loop()->PostTask( |
| 77 | FROM_HERE, |
| 78 | NewRunnableMethod( |
| 79 | this, |
| 80 | &IOThread::InitDnsMasterOnIOThread, |
| 81 | prefetching_enabled, max_queue_delay, max_concurrent, |
| 82 | hostnames_to_prefetch, referral_list)); |
| 83 | } |
| 84 | |
| 85 | void IOThread::ChangedToOnTheRecord() { |
| 86 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 87 | message_loop()->PostTask( |
| 88 | FROM_HERE, |
| 89 | NewRunnableMethod( |
| 90 | this, |
| 91 | &IOThread::ChangedToOnTheRecordOnIOThread)); |
| 92 | } |
| 93 | |
| 94 | void IOThread::Init() { |
| 95 | BrowserProcessSubThread::Init(); |
| 96 | |
| 97 | DCHECK(!host_resolver_); |
| 98 | host_resolver_ = CreateGlobalHostResolver(); |
| 99 | host_resolver_->AddRef(); |
| 100 | } |
| 101 | |
| 102 | void IOThread::CleanUp() { |
| 103 | // Not initialized in Init(). May not be initialized. |
| 104 | if (dns_master_) { |
| 105 | DCHECK(prefetch_observer_); |
| 106 | |
| 107 | dns_master_->Shutdown(); |
| 108 | |
| 109 | // TODO(willchan): Stop reference counting DnsMaster. It's owned by |
| 110 | // IOThread now. |
| 111 | dns_master_->Release(); |
| 112 | dns_master_ = NULL; |
| 113 | chrome_browser_net::FreeDnsPrefetchResources(); |
| 114 | } |
| 115 | |
| 116 | // Not initialized in Init(). May not be initialized. |
| 117 | if (prefetch_observer_) { |
| 118 | host_resolver_->RemoveObserver(prefetch_observer_); |
| 119 | delete prefetch_observer_; |
| 120 | prefetch_observer_ = NULL; |
| 121 | } |
| 122 | |
| 123 | // TODO(eroman): temp hack for http://crbug.com/15513 |
| 124 | host_resolver_->Shutdown(); |
| 125 | |
| 126 | // TODO(willchan): Stop reference counting HostResolver. It's owned by |
| 127 | // IOThread now. |
| 128 | host_resolver_->Release(); |
| 129 | host_resolver_ = NULL; |
| 130 | |
| 131 | // URLFetcher and URLRequest instances must NOT outlive the IO thread. |
| 132 | // |
| 133 | // Strictly speaking, URLFetcher's CheckForLeaks() should be done on the |
| 134 | // UI thread. However, since there _shouldn't_ be any instances left |
| 135 | // at this point, it shouldn't be a race. |
| 136 | // |
| 137 | // We check URLFetcher first, since if it has leaked then an associated |
| 138 | // URLRequest will also have leaked. However it is more useful to |
| 139 | // crash showing the callstack of URLFetcher's allocation than its |
| 140 | // URLRequest member. |
| 141 | base::LeakTracker<URLFetcher>::CheckForLeaks(); |
| 142 | base::LeakTracker<URLRequest>::CheckForLeaks(); |
| 143 | |
| 144 | BrowserProcessSubThread::CleanUp(); |
| 145 | } |
| 146 | |
| 147 | void IOThread::InitDnsMasterOnIOThread( |
| 148 | bool prefetching_enabled, |
| 149 | base::TimeDelta max_queue_delay, |
| 150 | size_t max_concurrent, |
| 151 | chrome_common_net::NameList hostnames_to_prefetch, |
| 152 | ListValue* referral_list) { |
| 153 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 154 | CHECK(!dns_master_); |
| 155 | |
| 156 | chrome_browser_net::EnableDnsPrefetch(prefetching_enabled); |
| 157 | |
| 158 | dns_master_ = new chrome_browser_net::DnsMaster( |
| 159 | host_resolver_, max_queue_delay, max_concurrent); |
| 160 | dns_master_->AddRef(); |
| 161 | |
| 162 | DCHECK(!prefetch_observer_); |
| 163 | prefetch_observer_ = chrome_browser_net::CreatePrefetchObserver(); |
| 164 | host_resolver_->AddObserver(prefetch_observer_); |
| 165 | |
| 166 | FinalizeDnsPrefetchInitialization( |
| 167 | dns_master_, prefetch_observer_, hostnames_to_prefetch, referral_list); |
| 168 | } |
| 169 | |
| 170 | void IOThread::ChangedToOnTheRecordOnIOThread() { |
| 171 | DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 172 | |
| 173 | if (dns_master_) { |
| 174 | // Destroy all evidence of our OTR session. |
| 175 | dns_master_->DnsMaster::DiscardAllResults(); |
| 176 | } |
| 177 | |
| 178 | // Clear the host cache to avoid showing entries from the OTR session |
| 179 | // in about:net-internals. |
| 180 | net::HostCache* host_cache = host_resolver_->GetHostCache(); |
| 181 | if (host_cache) |
| 182 | host_cache->clear(); |
| 183 | } |