// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/public/browser/browser_context.h" #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/dom_storage/dom_storage_context_impl.h" #include "content/browser/fileapi/browser_file_system_helper.h" #include "content/browser/in_process_webkit/indexed_db_context_impl.h" #include "content/browser/resource_context_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_constants.h" #include "net/cookies/cookie_monster.h" #include "net/cookies/cookie_store.h" #include "net/url_request/url_request_context.h" #include "webkit/database/database_tracker.h" #include "webkit/quota/quota_manager.h" using appcache::AppCacheService; using base::UserDataAdapter; using content::BrowserThread; using fileapi::FileSystemContext; using quota::QuotaManager; using webkit_database::DatabaseTracker; // Key names on BrowserContext. static const char* kAppCacheServicKeyName = "content_appcache_service_tracker"; static const char* kDatabaseTrackerKeyName = "content_database_tracker"; static const char* kDOMStorageContextKeyName = "content_dom_storage_context"; static const char* kFileSystemContextKeyName = "content_file_system_context"; static const char* kIndexedDBContextKeyName = "content_indexed_db_context"; static const char* kQuotaManagerKeyName = "content_quota_manager"; namespace content { namespace { void CreateQuotaManagerAndClients(BrowserContext* context) { if (context->GetUserData(kQuotaManagerKeyName)) { DCHECK(context->GetUserData(kDatabaseTrackerKeyName)); DCHECK(context->GetUserData(kDOMStorageContextKeyName)); DCHECK(context->GetUserData(kFileSystemContextKeyName)); DCHECK(context->GetUserData(kIndexedDBContextKeyName)); return; } // All of the clients have to be created and registered with the // QuotaManager prior to the QuotaManger being used. So we do them // all together here prior to handing out a reference to anything // that utlizes the QuotaManager. scoped_refptr quota_manager = new quota::QuotaManager( context->IsOffTheRecord(), context->GetPath(), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB), context->GetSpecialStoragePolicy()); context->SetUserData(kQuotaManagerKeyName, new UserDataAdapter(quota_manager)); // Each consumer is responsible for registering its QuotaClient during // its construction. scoped_refptr filesystem_context = CreateFileSystemContext( context->GetPath(), context->IsOffTheRecord(), context->GetSpecialStoragePolicy(), quota_manager->proxy()); context->SetUserData( kFileSystemContextKeyName, new UserDataAdapter(filesystem_context)); scoped_refptr db_tracker = new DatabaseTracker( context->GetPath(), context->IsOffTheRecord(), context->GetSpecialStoragePolicy(), quota_manager->proxy(), BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); context->SetUserData(kDatabaseTrackerKeyName, new UserDataAdapter(db_tracker)); FilePath path = context->IsOffTheRecord() ? FilePath() : context->GetPath(); scoped_refptr dom_storage_context = new DOMStorageContextImpl(path, context->GetSpecialStoragePolicy()); context->SetUserData( kDOMStorageContextKeyName, new UserDataAdapter(dom_storage_context)); scoped_refptr indexed_db_context = new IndexedDBContextImpl( path, context->GetSpecialStoragePolicy(), quota_manager->proxy(), BrowserThread::GetMessageLoopProxyForThread( BrowserThread::WEBKIT_DEPRECATED)); context->SetUserData( kIndexedDBContextKeyName, new UserDataAdapter(indexed_db_context)); scoped_refptr appcache_service = new ChromeAppCacheService(quota_manager->proxy()); context->SetUserData( kAppCacheServicKeyName, new UserDataAdapter(appcache_service)); InitializeResourceContext(context); // Check first to avoid memory leak in unittests. if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&ChromeAppCacheService::InitializeOnIOThread, appcache_service, context->IsOffTheRecord() ? FilePath() : context->GetPath().Append(content::kAppCacheDirname), context->GetResourceContext(), make_scoped_refptr(context->GetSpecialStoragePolicy()))); } } void SaveSessionStateOnIOThread(ResourceContext* resource_context) { resource_context->GetRequestContext()->cookie_store()->GetCookieMonster()-> SaveSessionCookies(); ResourceContext::GetAppCacheService(resource_context)->set_save_session_state( true); } void SaveSessionStateOnWebkitThread( scoped_refptr indexed_db_context) { indexed_db_context->SaveSessionState(); } void PurgeMemoryOnIOThread(ResourceContext* resource_context) { ResourceContext::GetAppCacheService(resource_context)->PurgeMemory(); } DOMStorageContextImpl* GetDOMStorageContextImpl(BrowserContext* context) { return static_cast( BrowserContext::GetDOMStorageContext(context)); } } // namespace QuotaManager* BrowserContext::GetQuotaManager(BrowserContext* context) { CreateQuotaManagerAndClients(context); return UserDataAdapter::Get(context, kQuotaManagerKeyName); } DOMStorageContext* BrowserContext::GetDOMStorageContext( BrowserContext* context) { CreateQuotaManagerAndClients(context); return UserDataAdapter::Get( context, kDOMStorageContextKeyName); } IndexedDBContext* BrowserContext::GetIndexedDBContext(BrowserContext* context) { CreateQuotaManagerAndClients(context); return UserDataAdapter::Get( context, kIndexedDBContextKeyName); } DatabaseTracker* BrowserContext::GetDatabaseTracker(BrowserContext* context) { CreateQuotaManagerAndClients(context); return UserDataAdapter::Get( context, kDatabaseTrackerKeyName); } AppCacheService* BrowserContext::GetAppCacheService( BrowserContext* browser_context) { CreateQuotaManagerAndClients(browser_context); return UserDataAdapter::Get( browser_context, kAppCacheServicKeyName); } FileSystemContext* BrowserContext::GetFileSystemContext( BrowserContext* browser_context) { CreateQuotaManagerAndClients(browser_context); return UserDataAdapter::Get( browser_context, kFileSystemContextKeyName); } void BrowserContext::EnsureResourceContextInitialized(BrowserContext* context) { // This will be enough to tickle initialization of BrowserContext if // necessary, which initializes ResourceContext. The reason we don't call // ResourceContext::InitializeResourceContext directly here is that if // ResourceContext ends up initializing it will call back into BrowserContext // and when that call return it'll end rewriting its UserData map (with the // same value) but this causes a race condition. See http://crbug.com/115678. CreateQuotaManagerAndClients(context); } void BrowserContext::SaveSessionState(BrowserContext* browser_context) { GetDatabaseTracker(browser_context)->SaveSessionState(); if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&SaveSessionStateOnIOThread, browser_context->GetResourceContext())); } GetDOMStorageContextImpl(browser_context)->SaveSessionState(); if (BrowserThread::IsMessageLoopValid(BrowserThread::WEBKIT_DEPRECATED)) { IndexedDBContextImpl* indexed_db = static_cast( GetIndexedDBContext(browser_context)); BrowserThread::PostTask( BrowserThread::WEBKIT_DEPRECATED, FROM_HERE, base::Bind(&SaveSessionStateOnWebkitThread, make_scoped_refptr(indexed_db))); } } void BrowserContext::ClearLocalOnDestruction(BrowserContext* browser_context) { GetDOMStorageContextImpl(browser_context)->SetClearLocalState(true); IndexedDBContextImpl* indexed_db = static_cast( GetIndexedDBContext(browser_context)); indexed_db->set_clear_local_state_on_exit(true); GetDatabaseTracker(browser_context)->SetClearLocalStateOnExit(true); if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&appcache::AppCacheService::set_clear_local_state_on_exit, base::Unretained(GetAppCacheService(browser_context)), true)); } } void BrowserContext::PurgeMemory(BrowserContext* browser_context) { if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&PurgeMemoryOnIOThread, browser_context->GetResourceContext())); } GetDOMStorageContextImpl(browser_context)->PurgeMemory(); } BrowserContext::~BrowserContext() { // These message loop checks are just to avoid leaks in unittests. if (GetUserData(kDatabaseTrackerKeyName) && BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, base::Bind(&webkit_database::DatabaseTracker::Shutdown, GetDatabaseTracker(this))); } if (GetUserData(kDOMStorageContextKeyName)) GetDOMStorageContextImpl(this)->Shutdown(); } } // namespace content