1// Copyright (c) 2012 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/profiles/off_the_record_profile_io_data.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/logging.h" 10#include "base/prefs/pref_service.h" 11#include "base/stl_util.h" 12#include "base/threading/worker_pool.h" 13#include "build/build_config.h" 14#include "chrome/browser/browser_process.h" 15#include "chrome/browser/custom_handlers/protocol_handler_registry.h" 16#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 17#include "chrome/browser/io_thread.h" 18#include "chrome/browser/net/about_protocol_handler.h" 19#include "chrome/browser/net/chrome_net_log.h" 20#include "chrome/browser/net/chrome_network_delegate.h" 21#include "chrome/browser/net/chrome_url_request_context.h" 22#include "chrome/browser/profiles/profile.h" 23#include "chrome/common/chrome_switches.h" 24#include "chrome/common/pref_names.h" 25#include "chrome/common/url_constants.h" 26#include "content/public/browser/browser_thread.h" 27#include "content/public/browser/resource_context.h" 28#include "extensions/common/constants.h" 29#include "extensions/common/extension.h" 30#include "net/ftp/ftp_network_layer.h" 31#include "net/http/http_cache.h" 32#include "net/http/http_network_session.h" 33#include "net/http/http_server_properties_impl.h" 34#include "net/ssl/default_server_bound_cert_store.h" 35#include "net/ssl/server_bound_cert_service.h" 36#include "net/url_request/protocol_intercept_job_factory.h" 37#include "net/url_request/url_request_job_factory_impl.h" 38#include "webkit/browser/database/database_tracker.h" 39 40using content::BrowserThread; 41 42OffTheRecordProfileIOData::Handle::Handle(Profile* profile) 43 : io_data_(new OffTheRecordProfileIOData), 44 profile_(profile), 45 initialized_(false) { 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 47 DCHECK(profile); 48} 49 50OffTheRecordProfileIOData::Handle::~Handle() { 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 52 io_data_->ShutdownOnUIThread(); 53} 54 55content::ResourceContext* 56OffTheRecordProfileIOData::Handle::GetResourceContext() const { 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 58 LazyInitialize(); 59 return GetResourceContextNoInit(); 60} 61 62content::ResourceContext* 63OffTheRecordProfileIOData::Handle::GetResourceContextNoInit() const { 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 65 // Don't call LazyInitialize here, since the resource context is created at 66 // the beginning of initalization and is used by some members while they're 67 // being initialized (i.e. AppCacheService). 68 return io_data_->GetResourceContext(); 69} 70 71scoped_refptr<ChromeURLRequestContextGetter> 72OffTheRecordProfileIOData::Handle::CreateMainRequestContextGetter( 73 content::ProtocolHandlerMap* protocol_handlers) const { 74 // TODO(oshima): Re-enable when ChromeOS only accesses the profile on the UI 75 // thread. 76#if !defined(OS_CHROMEOS) 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 78#endif // defined(OS_CHROMEOS) 79 LazyInitialize(); 80 DCHECK(!main_request_context_getter_.get()); 81 main_request_context_getter_ = 82 ChromeURLRequestContextGetter::Create( 83 profile_, io_data_, protocol_handlers); 84 return main_request_context_getter_; 85} 86 87scoped_refptr<ChromeURLRequestContextGetter> 88OffTheRecordProfileIOData::Handle::GetExtensionsRequestContextGetter() const { 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 90 LazyInitialize(); 91 if (!extensions_request_context_getter_.get()) { 92 extensions_request_context_getter_ = 93 ChromeURLRequestContextGetter::CreateForExtensions(profile_, io_data_); 94 } 95 return extensions_request_context_getter_; 96} 97 98scoped_refptr<ChromeURLRequestContextGetter> 99OffTheRecordProfileIOData::Handle::GetIsolatedAppRequestContextGetter( 100 const base::FilePath& partition_path, 101 bool in_memory) const { 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 103 DCHECK(!partition_path.empty()); 104 LazyInitialize(); 105 106 // Keep a map of request context getters, one per requested app ID. 107 StoragePartitionDescriptor descriptor(partition_path, in_memory); 108 ChromeURLRequestContextGetterMap::iterator iter = 109 app_request_context_getter_map_.find(descriptor); 110 CHECK(iter != app_request_context_getter_map_.end()); 111 return iter->second; 112} 113 114scoped_refptr<ChromeURLRequestContextGetter> 115OffTheRecordProfileIOData::Handle::CreateIsolatedAppRequestContextGetter( 116 const base::FilePath& partition_path, 117 bool in_memory, 118 content::ProtocolHandlerMap* protocol_handlers) const { 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 120 DCHECK(!partition_path.empty()); 121 LazyInitialize(); 122 123 // Keep a map of request context getters, one per requested app ID. 124 StoragePartitionDescriptor descriptor(partition_path, in_memory); 125 DCHECK_EQ(app_request_context_getter_map_.count(descriptor), 0u); 126 127 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 128 protocol_handler_interceptor( 129 ProtocolHandlerRegistryFactory::GetForProfile(profile_)-> 130 CreateJobInterceptorFactory()); 131 ChromeURLRequestContextGetter* context = 132 ChromeURLRequestContextGetter::CreateForIsolatedApp( 133 profile_, io_data_, descriptor, protocol_handler_interceptor.Pass(), 134 protocol_handlers); 135 app_request_context_getter_map_[descriptor] = context; 136 137 return context; 138} 139 140void OffTheRecordProfileIOData::Handle::LazyInitialize() const { 141 if (initialized_) 142 return; 143 144 // Set initialized_ to true at the beginning in case any of the objects 145 // below try to get the ResourceContext pointer. 146 initialized_ = true; 147#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING) 148 io_data_->safe_browsing_enabled()->Init(prefs::kSafeBrowsingEnabled, 149 profile_->GetPrefs()); 150 io_data_->safe_browsing_enabled()->MoveToThread( 151 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); 152#endif 153 io_data_->InitializeOnUIThread(profile_); 154} 155 156OffTheRecordProfileIOData::OffTheRecordProfileIOData() 157 : ProfileIOData(true) {} 158OffTheRecordProfileIOData::~OffTheRecordProfileIOData() { 159 DestroyResourceContext(); 160} 161 162void OffTheRecordProfileIOData::InitializeInternal( 163 ProfileParams* profile_params, 164 content::ProtocolHandlerMap* protocol_handlers) const { 165 ChromeURLRequestContext* main_context = main_request_context(); 166 167 IOThread* const io_thread = profile_params->io_thread; 168 IOThread::Globals* const io_thread_globals = io_thread->globals(); 169 170 ApplyProfileParamsToContext(main_context); 171 172 main_context->set_transport_security_state(transport_security_state()); 173 174 main_context->set_net_log(io_thread->net_log()); 175 176 main_context->set_network_delegate(network_delegate()); 177 178 main_context->set_host_resolver( 179 io_thread_globals->host_resolver.get()); 180 main_context->set_http_auth_handler_factory( 181 io_thread_globals->http_auth_handler_factory.get()); 182 main_context->set_fraudulent_certificate_reporter( 183 fraudulent_certificate_reporter()); 184 main_context->set_proxy_service(proxy_service()); 185 186 main_context->set_throttler_manager( 187 io_thread_globals->throttler_manager.get()); 188 189 // For incognito, we use the default non-persistent HttpServerPropertiesImpl. 190 set_http_server_properties( 191 scoped_ptr<net::HttpServerProperties>( 192 new net::HttpServerPropertiesImpl())); 193 main_context->set_http_server_properties(http_server_properties()); 194 195 // For incognito, we use a non-persistent server bound cert store. 196 net::ServerBoundCertService* server_bound_cert_service = 197 new net::ServerBoundCertService( 198 new net::DefaultServerBoundCertStore(NULL), 199 base::WorkerPool::GetTaskRunner(true)); 200 set_server_bound_cert_service(server_bound_cert_service); 201 main_context->set_server_bound_cert_service(server_bound_cert_service); 202 203 main_context->set_cookie_store(new net::CookieMonster( 204 NULL, profile_params->cookie_monster_delegate.get())); 205 206 net::HttpCache::BackendFactory* main_backend = 207 net::HttpCache::DefaultBackend::InMemory(0); 208 net::HttpNetworkSession::Params network_session_params; 209 PopulateNetworkSessionParams(profile_params, &network_session_params); 210 net::HttpCache* cache = new net::HttpCache( 211 network_session_params, main_backend); 212 213 main_http_factory_.reset(cache); 214 main_context->set_http_transaction_factory(cache); 215#if !defined(DISABLE_FTP_SUPPORT) 216 ftp_factory_.reset( 217 new net::FtpNetworkLayer(main_context->host_resolver())); 218#endif // !defined(DISABLE_FTP_SUPPORT) 219 220 scoped_ptr<net::URLRequestJobFactoryImpl> main_job_factory( 221 new net::URLRequestJobFactoryImpl()); 222 223 InstallProtocolHandlers(main_job_factory.get(), protocol_handlers); 224 main_job_factory_ = SetUpJobFactoryDefaults( 225 main_job_factory.Pass(), 226 profile_params->protocol_handler_interceptor.Pass(), 227 network_delegate(), 228 ftp_factory_.get()); 229 main_context->set_job_factory(main_job_factory_.get()); 230 231#if defined(ENABLE_EXTENSIONS) 232 InitializeExtensionsRequestContext(profile_params); 233#endif 234} 235 236void OffTheRecordProfileIOData:: 237 InitializeExtensionsRequestContext(ProfileParams* profile_params) const { 238 ChromeURLRequestContext* extensions_context = extensions_request_context(); 239 240 IOThread* const io_thread = profile_params->io_thread; 241 IOThread::Globals* const io_thread_globals = io_thread->globals(); 242 243 ApplyProfileParamsToContext(extensions_context); 244 245 extensions_context->set_transport_security_state(transport_security_state()); 246 247 extensions_context->set_net_log(io_thread->net_log()); 248 249 extensions_context->set_throttler_manager( 250 io_thread_globals->throttler_manager.get()); 251 252 // All we care about for extensions is the cookie store. For incognito, we 253 // use a non-persistent cookie store. 254 net::CookieMonster* extensions_cookie_store = 255 new net::CookieMonster(NULL, NULL); 256 // Enable cookies for devtools and extension URLs. 257 const char* schemes[] = {chrome::kChromeDevToolsScheme, 258 extensions::kExtensionScheme}; 259 extensions_cookie_store->SetCookieableSchemes(schemes, 2); 260 extensions_context->set_cookie_store(extensions_cookie_store); 261 262 scoped_ptr<net::URLRequestJobFactoryImpl> extensions_job_factory( 263 new net::URLRequestJobFactoryImpl()); 264 // TODO(shalev): The extensions_job_factory has a NULL NetworkDelegate. 265 // Without a network_delegate, this protocol handler will never 266 // handle file: requests, but as a side effect it makes 267 // job_factory::IsHandledProtocol return true, which prevents attempts to 268 // handle the protocol externally. We pass NULL in to 269 // SetUpJobFactoryDefaults() to get this effect. 270 extensions_job_factory_ = SetUpJobFactoryDefaults( 271 extensions_job_factory.Pass(), 272 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>(), 273 NULL, 274 ftp_factory_.get()); 275 extensions_context->set_job_factory(extensions_job_factory_.get()); 276} 277 278ChromeURLRequestContext* 279OffTheRecordProfileIOData::InitializeAppRequestContext( 280 ChromeURLRequestContext* main_context, 281 const StoragePartitionDescriptor& partition_descriptor, 282 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 283 protocol_handler_interceptor, 284 content::ProtocolHandlerMap* protocol_handlers) const { 285 AppRequestContext* context = new AppRequestContext(load_time_stats()); 286 287 // Copy most state from the main context. 288 context->CopyFrom(main_context); 289 290 // Use a separate in-memory cookie store for the app. 291 // TODO(creis): We should have a cookie delegate for notifying the cookie 292 // extensions API, but we need to update it to understand isolated apps first. 293 context->SetCookieStore(new net::CookieMonster(NULL, NULL)); 294 295 // Use a separate in-memory cache for the app. 296 net::HttpCache::BackendFactory* app_backend = 297 net::HttpCache::DefaultBackend::InMemory(0); 298 net::HttpNetworkSession* main_network_session = 299 main_http_factory_->GetSession(); 300 scoped_ptr<net::HttpTransactionFactory> app_http_cache( 301 new net::HttpCache(main_network_session, app_backend)); 302 303 context->SetHttpTransactionFactory(app_http_cache.Pass()); 304 305 scoped_ptr<net::URLRequestJobFactoryImpl> job_factory( 306 new net::URLRequestJobFactoryImpl()); 307 InstallProtocolHandlers(job_factory.get(), protocol_handlers); 308 scoped_ptr<net::URLRequestJobFactory> top_job_factory; 309 top_job_factory = SetUpJobFactoryDefaults(job_factory.Pass(), 310 protocol_handler_interceptor.Pass(), 311 network_delegate(), 312 ftp_factory_.get()); 313 context->SetJobFactory(top_job_factory.Pass()); 314 return context; 315} 316 317ChromeURLRequestContext* 318OffTheRecordProfileIOData::InitializeMediaRequestContext( 319 ChromeURLRequestContext* original_context, 320 const StoragePartitionDescriptor& partition_descriptor) const { 321 NOTREACHED(); 322 return NULL; 323} 324 325ChromeURLRequestContext* 326OffTheRecordProfileIOData::AcquireMediaRequestContext() const { 327 NOTREACHED(); 328 return NULL; 329} 330 331ChromeURLRequestContext* 332OffTheRecordProfileIOData::AcquireIsolatedAppRequestContext( 333 ChromeURLRequestContext* main_context, 334 const StoragePartitionDescriptor& partition_descriptor, 335 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 336 protocol_handler_interceptor, 337 content::ProtocolHandlerMap* protocol_handlers) const { 338 // We create per-app contexts on demand, unlike the others above. 339 ChromeURLRequestContext* app_request_context = 340 InitializeAppRequestContext(main_context, partition_descriptor, 341 protocol_handler_interceptor.Pass(), 342 protocol_handlers); 343 DCHECK(app_request_context); 344 return app_request_context; 345} 346 347ChromeURLRequestContext* 348OffTheRecordProfileIOData::AcquireIsolatedMediaRequestContext( 349 ChromeURLRequestContext* app_context, 350 const StoragePartitionDescriptor& partition_descriptor) const { 351 NOTREACHED(); 352 return NULL; 353} 354 355chrome_browser_net::LoadTimeStats* OffTheRecordProfileIOData::GetLoadTimeStats( 356 IOThread::Globals* io_thread_globals) const { 357 return NULL; 358} 359