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_getter.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/cookie_store_factory.h" 28#include "content/public/browser/resource_context.h" 29#include "extensions/common/constants.h" 30#include "extensions/common/extension.h" 31#include "net/base/sdch_dictionary_fetcher.h" 32#include "net/base/sdch_manager.h" 33#include "net/ftp/ftp_network_layer.h" 34#include "net/http/http_cache.h" 35#include "net/http/http_network_session.h" 36#include "net/http/http_server_properties_impl.h" 37#include "net/ssl/channel_id_service.h" 38#include "net/ssl/default_channel_id_store.h" 39#include "net/url_request/url_request_job_factory_impl.h" 40#include "storage/browser/database/database_tracker.h" 41 42using content::BrowserThread; 43 44OffTheRecordProfileIOData::Handle::Handle(Profile* profile) 45 : io_data_(new OffTheRecordProfileIOData(profile->GetProfileType())), 46 profile_(profile), 47 initialized_(false) { 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 49 DCHECK(profile); 50} 51 52OffTheRecordProfileIOData::Handle::~Handle() { 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 54 io_data_->ShutdownOnUIThread(GetAllContextGetters().Pass()); 55} 56 57content::ResourceContext* 58OffTheRecordProfileIOData::Handle::GetResourceContext() const { 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 60 LazyInitialize(); 61 return GetResourceContextNoInit(); 62} 63 64content::ResourceContext* 65OffTheRecordProfileIOData::Handle::GetResourceContextNoInit() const { 66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 67 // Don't call LazyInitialize here, since the resource context is created at 68 // the beginning of initalization and is used by some members while they're 69 // being initialized (i.e. AppCacheService). 70 return io_data_->GetResourceContext(); 71} 72 73scoped_refptr<ChromeURLRequestContextGetter> 74OffTheRecordProfileIOData::Handle::CreateMainRequestContextGetter( 75 content::ProtocolHandlerMap* protocol_handlers, 76 content::URLRequestInterceptorScopedVector request_interceptors) const { 77 // TODO(oshima): Re-enable when ChromeOS only accesses the profile on the UI 78 // thread. 79#if !defined(OS_CHROMEOS) 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 81#endif // defined(OS_CHROMEOS) 82 LazyInitialize(); 83 DCHECK(!main_request_context_getter_.get()); 84 main_request_context_getter_ = ChromeURLRequestContextGetter::Create( 85 profile_, io_data_, protocol_handlers, request_interceptors.Pass()); 86 return main_request_context_getter_; 87} 88 89scoped_refptr<ChromeURLRequestContextGetter> 90OffTheRecordProfileIOData::Handle::GetExtensionsRequestContextGetter() const { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 LazyInitialize(); 93 if (!extensions_request_context_getter_.get()) { 94 extensions_request_context_getter_ = 95 ChromeURLRequestContextGetter::CreateForExtensions(profile_, io_data_); 96 } 97 return extensions_request_context_getter_; 98} 99 100scoped_refptr<ChromeURLRequestContextGetter> 101OffTheRecordProfileIOData::Handle::GetIsolatedAppRequestContextGetter( 102 const base::FilePath& partition_path, 103 bool in_memory) const { 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 105 DCHECK(!partition_path.empty()); 106 LazyInitialize(); 107 108 // Keep a map of request context getters, one per requested app ID. 109 StoragePartitionDescriptor descriptor(partition_path, in_memory); 110 ChromeURLRequestContextGetterMap::iterator iter = 111 app_request_context_getter_map_.find(descriptor); 112 CHECK(iter != app_request_context_getter_map_.end()); 113 return iter->second; 114} 115 116scoped_refptr<ChromeURLRequestContextGetter> 117OffTheRecordProfileIOData::Handle::CreateIsolatedAppRequestContextGetter( 118 const base::FilePath& partition_path, 119 bool in_memory, 120 content::ProtocolHandlerMap* protocol_handlers, 121 content::URLRequestInterceptorScopedVector request_interceptors) const { 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 123 DCHECK(!partition_path.empty()); 124 LazyInitialize(); 125 126 // Keep a map of request context getters, one per requested app ID. 127 StoragePartitionDescriptor descriptor(partition_path, in_memory); 128 DCHECK_EQ(app_request_context_getter_map_.count(descriptor), 0u); 129 130 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 131 protocol_handler_interceptor( 132 ProtocolHandlerRegistryFactory::GetForBrowserContext(profile_)-> 133 CreateJobInterceptorFactory()); 134 ChromeURLRequestContextGetter* context = 135 ChromeURLRequestContextGetter::CreateForIsolatedApp( 136 profile_, 137 io_data_, 138 descriptor, 139 protocol_handler_interceptor.Pass(), 140 protocol_handlers, 141 request_interceptors.Pass()); 142 app_request_context_getter_map_[descriptor] = context; 143 144 return context; 145} 146 147DevToolsNetworkController* 148OffTheRecordProfileIOData::Handle::GetDevToolsNetworkController() const { 149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 150 return io_data_->network_controller(); 151} 152 153void OffTheRecordProfileIOData::Handle::LazyInitialize() const { 154 if (initialized_) 155 return; 156 157 // Set initialized_ to true at the beginning in case any of the objects 158 // below try to get the ResourceContext pointer. 159 initialized_ = true; 160#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING) 161 io_data_->safe_browsing_enabled()->Init(prefs::kSafeBrowsingEnabled, 162 profile_->GetPrefs()); 163 io_data_->safe_browsing_enabled()->MoveToThread( 164 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); 165#endif 166 // TODO(kundaji): Remove data_reduction_proxy_enabled pref for incognito. 167 // Bug http://crbug/412873. 168 io_data_->data_reduction_proxy_enabled()->Init( 169 data_reduction_proxy::prefs::kDataReductionProxyEnabled, 170 profile_->GetPrefs()); 171 io_data_->data_reduction_proxy_enabled()->MoveToThread( 172 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); 173 io_data_->InitializeOnUIThread(profile_); 174} 175 176scoped_ptr<ProfileIOData::ChromeURLRequestContextGetterVector> 177OffTheRecordProfileIOData::Handle::GetAllContextGetters() { 178 scoped_ptr<ChromeURLRequestContextGetterVector> context_getters( 179 new ChromeURLRequestContextGetterVector()); 180 ChromeURLRequestContextGetterMap::iterator iter = 181 app_request_context_getter_map_.begin(); 182 for (; iter != app_request_context_getter_map_.end(); ++iter) 183 context_getters->push_back(iter->second); 184 185 if (extensions_request_context_getter_.get()) 186 context_getters->push_back(extensions_request_context_getter_); 187 188 if (main_request_context_getter_.get()) 189 context_getters->push_back(main_request_context_getter_); 190 191 return context_getters.Pass(); 192} 193 194OffTheRecordProfileIOData::OffTheRecordProfileIOData( 195 Profile::ProfileType profile_type) 196 : ProfileIOData(profile_type) {} 197 198OffTheRecordProfileIOData::~OffTheRecordProfileIOData() { 199 DestroyResourceContext(); 200} 201 202void OffTheRecordProfileIOData::InitializeInternal( 203 ProfileParams* profile_params, 204 content::ProtocolHandlerMap* protocol_handlers, 205 content::URLRequestInterceptorScopedVector request_interceptors) const { 206 net::URLRequestContext* main_context = main_request_context(); 207 208 IOThread* const io_thread = profile_params->io_thread; 209 IOThread::Globals* const io_thread_globals = io_thread->globals(); 210 211 ApplyProfileParamsToContext(main_context); 212 213 main_context->set_transport_security_state(transport_security_state()); 214 215 main_context->set_net_log(io_thread->net_log()); 216 217 main_context->set_network_delegate(network_delegate()); 218 219 main_context->set_host_resolver( 220 io_thread_globals->host_resolver.get()); 221 main_context->set_http_auth_handler_factory( 222 io_thread_globals->http_auth_handler_factory.get()); 223 main_context->set_fraudulent_certificate_reporter( 224 fraudulent_certificate_reporter()); 225 main_context->set_proxy_service(proxy_service()); 226 227 main_context->set_throttler_manager( 228 io_thread_globals->throttler_manager.get()); 229 230 main_context->set_cert_transparency_verifier( 231 io_thread_globals->cert_transparency_verifier.get()); 232 233 // For incognito, we use the default non-persistent HttpServerPropertiesImpl. 234 set_http_server_properties( 235 scoped_ptr<net::HttpServerProperties>( 236 new net::HttpServerPropertiesImpl())); 237 main_context->set_http_server_properties(http_server_properties()); 238 239 // For incognito, we use a non-persistent channel ID store. 240 net::ChannelIDService* channel_id_service = 241 new net::ChannelIDService( 242 new net::DefaultChannelIDStore(NULL), 243 base::WorkerPool::GetTaskRunner(true)); 244 set_channel_id_service(channel_id_service); 245 main_context->set_channel_id_service(channel_id_service); 246 247 using content::CookieStoreConfig; 248 main_context->set_cookie_store( 249 CreateCookieStore(CookieStoreConfig( 250 base::FilePath(), 251 CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, 252 NULL, 253 profile_params->cookie_monster_delegate.get()))); 254 255 net::HttpCache::BackendFactory* main_backend = 256 net::HttpCache::DefaultBackend::InMemory(0); 257 main_http_factory_ = CreateMainHttpFactory(profile_params, main_backend); 258 259 main_context->set_http_transaction_factory(main_http_factory_.get()); 260#if !defined(DISABLE_FTP_SUPPORT) 261 ftp_factory_.reset( 262 new net::FtpNetworkLayer(main_context->host_resolver())); 263#endif // !defined(DISABLE_FTP_SUPPORT) 264 265 scoped_ptr<net::URLRequestJobFactoryImpl> main_job_factory( 266 new net::URLRequestJobFactoryImpl()); 267 268 InstallProtocolHandlers(main_job_factory.get(), protocol_handlers); 269 main_job_factory_ = SetUpJobFactoryDefaults( 270 main_job_factory.Pass(), 271 request_interceptors.Pass(), 272 profile_params->protocol_handler_interceptor.Pass(), 273 network_delegate(), 274 ftp_factory_.get()); 275 main_context->set_job_factory(main_job_factory_.get()); 276 277 // Setup the SDCHManager for this profile. 278 sdch_manager_.reset(new net::SdchManager); 279 sdch_manager_->set_sdch_fetcher(scoped_ptr<net::SdchFetcher>( 280 new net::SdchDictionaryFetcher(sdch_manager_.get(), 281 main_context)).Pass()); 282 main_context->set_sdch_manager(sdch_manager_.get()); 283 284#if defined(ENABLE_EXTENSIONS) 285 InitializeExtensionsRequestContext(profile_params); 286#endif 287} 288 289void OffTheRecordProfileIOData:: 290 InitializeExtensionsRequestContext(ProfileParams* profile_params) const { 291 net::URLRequestContext* extensions_context = extensions_request_context(); 292 293 IOThread* const io_thread = profile_params->io_thread; 294 IOThread::Globals* const io_thread_globals = io_thread->globals(); 295 296 ApplyProfileParamsToContext(extensions_context); 297 298 extensions_context->set_transport_security_state(transport_security_state()); 299 300 extensions_context->set_net_log(io_thread->net_log()); 301 302 extensions_context->set_throttler_manager( 303 io_thread_globals->throttler_manager.get()); 304 305 extensions_context->set_cert_transparency_verifier( 306 io_thread_globals->cert_transparency_verifier.get()); 307 308 // All we care about for extensions is the cookie store. For incognito, we 309 // use a non-persistent cookie store. 310 net::CookieMonster* extensions_cookie_store = 311 content::CreateCookieStore(content::CookieStoreConfig())-> 312 GetCookieMonster(); 313 // Enable cookies for devtools and extension URLs. 314 const char* const schemes[] = { 315 content::kChromeDevToolsScheme, 316 extensions::kExtensionScheme 317 }; 318 extensions_cookie_store->SetCookieableSchemes(schemes, arraysize(schemes)); 319 extensions_context->set_cookie_store(extensions_cookie_store); 320 321 scoped_ptr<net::URLRequestJobFactoryImpl> extensions_job_factory( 322 new net::URLRequestJobFactoryImpl()); 323 // TODO(shalev): The extensions_job_factory has a NULL NetworkDelegate. 324 // Without a network_delegate, this protocol handler will never 325 // handle file: requests, but as a side effect it makes 326 // job_factory::IsHandledProtocol return true, which prevents attempts to 327 // handle the protocol externally. We pass NULL in to 328 // SetUpJobFactoryDefaults() to get this effect. 329 extensions_job_factory_ = SetUpJobFactoryDefaults( 330 extensions_job_factory.Pass(), 331 content::URLRequestInterceptorScopedVector(), 332 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>(), 333 NULL, 334 ftp_factory_.get()); 335 extensions_context->set_job_factory(extensions_job_factory_.get()); 336} 337 338net::URLRequestContext* OffTheRecordProfileIOData::InitializeAppRequestContext( 339 net::URLRequestContext* main_context, 340 const StoragePartitionDescriptor& partition_descriptor, 341 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 342 protocol_handler_interceptor, 343 content::ProtocolHandlerMap* protocol_handlers, 344 content::URLRequestInterceptorScopedVector request_interceptors) const { 345 AppRequestContext* context = new AppRequestContext(); 346 347 // Copy most state from the main context. 348 context->CopyFrom(main_context); 349 350 // Use a separate in-memory cookie store for the app. 351 // TODO(creis): We should have a cookie delegate for notifying the cookie 352 // extensions API, but we need to update it to understand isolated apps first. 353 context->SetCookieStore( 354 content::CreateCookieStore(content::CookieStoreConfig())); 355 356 // Use a separate in-memory cache for the app. 357 net::HttpCache::BackendFactory* app_backend = 358 net::HttpCache::DefaultBackend::InMemory(0); 359 net::HttpNetworkSession* main_network_session = 360 main_http_factory_->GetSession(); 361 scoped_ptr<net::HttpCache> app_http_cache = 362 CreateHttpFactory(main_network_session, app_backend); 363 364 context->SetHttpTransactionFactory( 365 app_http_cache.PassAs<net::HttpTransactionFactory>()); 366 367 scoped_ptr<net::URLRequestJobFactoryImpl> job_factory( 368 new net::URLRequestJobFactoryImpl()); 369 InstallProtocolHandlers(job_factory.get(), protocol_handlers); 370 scoped_ptr<net::URLRequestJobFactory> top_job_factory; 371 top_job_factory = SetUpJobFactoryDefaults(job_factory.Pass(), 372 request_interceptors.Pass(), 373 protocol_handler_interceptor.Pass(), 374 network_delegate(), 375 ftp_factory_.get()); 376 context->SetJobFactory(top_job_factory.Pass()); 377 return context; 378} 379 380net::URLRequestContext* 381OffTheRecordProfileIOData::InitializeMediaRequestContext( 382 net::URLRequestContext* original_context, 383 const StoragePartitionDescriptor& partition_descriptor) const { 384 NOTREACHED(); 385 return NULL; 386} 387 388net::URLRequestContext* 389OffTheRecordProfileIOData::AcquireMediaRequestContext() const { 390 NOTREACHED(); 391 return NULL; 392} 393 394net::URLRequestContext* 395OffTheRecordProfileIOData::AcquireIsolatedAppRequestContext( 396 net::URLRequestContext* main_context, 397 const StoragePartitionDescriptor& partition_descriptor, 398 scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory> 399 protocol_handler_interceptor, 400 content::ProtocolHandlerMap* protocol_handlers, 401 content::URLRequestInterceptorScopedVector request_interceptors) const { 402 // We create per-app contexts on demand, unlike the others above. 403 net::URLRequestContext* app_request_context = 404 InitializeAppRequestContext(main_context, 405 partition_descriptor, 406 protocol_handler_interceptor.Pass(), 407 protocol_handlers, 408 request_interceptors.Pass()); 409 DCHECK(app_request_context); 410 return app_request_context; 411} 412 413net::URLRequestContext* 414OffTheRecordProfileIOData::AcquireIsolatedMediaRequestContext( 415 net::URLRequestContext* app_context, 416 const StoragePartitionDescriptor& partition_descriptor) const { 417 NOTREACHED(); 418 return NULL; 419} 420