diff options
21 files changed, 509 insertions, 111 deletions
diff --git a/chrome/browser/browsing_data_appcache_helper.cc b/chrome/browser/browsing_data_appcache_helper.cc index c0d7ced..9e62809 100644 --- a/chrome/browser/browsing_data_appcache_helper.cc +++ b/chrome/browser/browsing_data_appcache_helper.cc @@ -3,55 +3,70 @@ // found in the LICENSE file. #include "chrome/browser/browsing_data_appcache_helper.h" +#include "chrome/browser/net/chrome_url_request_context.h" +#include "chrome/browser/profile.h" +#include "webkit/appcache/appcache_database.h" +#include "webkit/appcache/appcache_storage.h" + +using appcache::AppCacheDatabase; BrowsingDataAppCacheHelper::BrowsingDataAppCacheHelper(Profile* profile) - : is_fetching_(false) { + : request_context_getter_(profile->GetRequestContext()), + is_fetching_(false) { + DCHECK(request_context_getter_.get()); } void BrowsingDataAppCacheHelper::StartFetching(Callback0::Type* callback) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DCHECK(!is_fetching_); - DCHECK(callback); - is_fetching_ = true; - info_list_.clear(); - completion_callback_.reset(callback); - ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod( - this, &BrowsingDataAppCacheHelper::StartFetchingInIOThread)); + if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { + DCHECK(!is_fetching_); + DCHECK(callback); + is_fetching_ = true; + info_collection_ = new appcache::AppCacheInfoCollection; + completion_callback_.reset(callback); + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod( + this, &BrowsingDataAppCacheHelper::StartFetching, callback)); + return; + } + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + appcache_info_callback_ = + new net::CancelableCompletionCallback<BrowsingDataAppCacheHelper>( + this, &BrowsingDataAppCacheHelper::OnFetchComplete); + GetAppCacheService()->GetAllAppCacheInfo(info_collection_, + appcache_info_callback_); } void BrowsingDataAppCacheHelper::CancelNotification() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - completion_callback_.reset(); -} + if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { + completion_callback_.reset(); + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod( + this, &BrowsingDataAppCacheHelper::CancelNotification)); + return; + } -void BrowsingDataAppCacheHelper::DeleteAppCache(int64 group_id) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod( - this, &BrowsingDataAppCacheHelper::DeleteAppCacheInIOThread, - group_id)); + if (appcache_info_callback_) + appcache_info_callback_.release()->Cancel(); } -void BrowsingDataAppCacheHelper::StartFetchingInIOThread() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - -#ifndef NDEBUG - // TODO(michaeln): get real data from the appcache service - info_list_.push_back( - AppCacheInfo(GURL("http://bogus/manifest"), - 1 * 1024 * 1024, base::Time::Now(), base::Time::Now(), 1)); - info_list_.push_back( - AppCacheInfo(GURL("https://bogus/manifest"), - 2 * 1024 * 1024, base::Time::Now(), base::Time::Now(), 2)); - info_list_.push_back( - AppCacheInfo(GURL("http://bogus:8080/manifest"), - 3 * 1024 * 1024, base::Time::Now(), base::Time::Now(), 3)); -#endif - - ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod( - this, &BrowsingDataAppCacheHelper::OnFetchComplete)); +void BrowsingDataAppCacheHelper::DeleteAppCacheGroup( + const GURL& manifest_url) { + if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, NewRunnableMethod( + this, &BrowsingDataAppCacheHelper::DeleteAppCacheGroup, + manifest_url)); + return; + } + GetAppCacheService()->DeleteAppCacheGroup(manifest_url, NULL); } -void BrowsingDataAppCacheHelper::OnFetchComplete() { +void BrowsingDataAppCacheHelper::OnFetchComplete(int rv) { + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { + appcache_info_callback_ = NULL; + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, NewRunnableMethod( + this, &BrowsingDataAppCacheHelper::OnFetchComplete, rv)); + return; + } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); DCHECK(is_fetching_); is_fetching_ = false; @@ -61,8 +76,11 @@ void BrowsingDataAppCacheHelper::OnFetchComplete() { } } -void BrowsingDataAppCacheHelper::DeleteAppCacheInIOThread( - int64 group_id) { +ChromeAppCacheService* BrowsingDataAppCacheHelper::GetAppCacheService() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - // TODO(michaeln): plumb to the appcache service + ChromeURLRequestContext* request_context = + reinterpret_cast<ChromeURLRequestContext*>( + request_context_getter_->GetURLRequestContext()); + return request_context ? request_context->appcache_service() + : NULL; } diff --git a/chrome/browser/browsing_data_appcache_helper.h b/chrome/browser/browsing_data_appcache_helper.h index aa04dae..695a271 100644 --- a/chrome/browser/browsing_data_appcache_helper.h +++ b/chrome/browser/browsing_data_appcache_helper.h @@ -11,6 +11,7 @@ #include "base/scoped_ptr.h" #include "base/task.h" #include "chrome/browser/appcache/chrome_appcache_service.h" +#include "chrome/browser/net/url_request_context_getter.h" class Profile; @@ -19,37 +20,15 @@ class Profile; class BrowsingDataAppCacheHelper : public base::RefCountedThreadSafe<BrowsingDataAppCacheHelper> { public: - // Contains detailed information about an appcache. - struct AppCacheInfo { - AppCacheInfo() {} - AppCacheInfo(const GURL& manifest_url, - int64 size, - base::Time creation_time, - base::Time last_access_time, - int64 group_id) - : manifest_url(manifest_url), - size(size), - creation_time(creation_time), - last_access_time(last_access_time), - group_id(group_id) { - } - - GURL manifest_url; - int64 size; - base::Time creation_time; - base::Time last_access_time; - int64 group_id; - }; - explicit BrowsingDataAppCacheHelper(Profile* profile); virtual void StartFetching(Callback0::Type* completion_callback); virtual void CancelNotification(); - virtual void DeleteAppCache(int64 group_id); + virtual void DeleteAppCacheGroup(const GURL& manifest_url); - const std::vector<AppCacheInfo>& info_list() const { + appcache::AppCacheInfoCollection* info_collection() const { DCHECK(!is_fetching_); - return info_list_; + return info_collection_; } private: @@ -58,13 +37,15 @@ class BrowsingDataAppCacheHelper virtual ~BrowsingDataAppCacheHelper() {} - void StartFetchingInIOThread(); - void OnFetchComplete(); - void DeleteAppCacheInIOThread(int64 group_id); + void OnFetchComplete(int rv); + ChromeAppCacheService* GetAppCacheService(); + scoped_refptr<URLRequestContextGetter> request_context_getter_; bool is_fetching_; - std::vector<AppCacheInfo> info_list_; scoped_ptr<Callback0::Type> completion_callback_; + scoped_refptr<appcache::AppCacheInfoCollection> info_collection_; + scoped_refptr<net::CancelableCompletionCallback<BrowsingDataAppCacheHelper> > + appcache_info_callback_; DISALLOW_COPY_AND_ASSIGN(BrowsingDataAppCacheHelper); }; diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc index b4468c7..0614969 100644 --- a/chrome/browser/browsing_data_remover.cc +++ b/chrome/browser/browsing_data_remover.cc @@ -11,6 +11,7 @@ #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/profile.h" #include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/url_request_context_getter.h" #include "chrome/browser/password_manager/password_store.h" #include "chrome/browser/search_engines/template_url_model.h" @@ -46,9 +47,16 @@ BrowsingDataRemover::BrowsingDataRemover(Profile* profile, delete_end_(delete_end), ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( this, &BrowsingDataRemover::OnClearedDatabases)), + ALLOW_THIS_IN_INITIALIZER_LIST(appcache_got_info_callback_( + this, &BrowsingDataRemover::OnGotAppCacheInfo)), + ALLOW_THIS_IN_INITIALIZER_LIST(appcache_deleted_callback_( + this, &BrowsingDataRemover::OnAppCacheDeleted)), + request_context_getter_(profile->GetRequestContext()), + appcaches_to_be_deleted_count_(0), waiting_for_clear_databases_(false), waiting_for_clear_history_(false), - waiting_for_clear_cache_(false) { + waiting_for_clear_cache_(false), + waiting_for_clear_appcache_(false) { DCHECK(profile); } @@ -60,9 +68,16 @@ BrowsingDataRemover::BrowsingDataRemover(Profile* profile, delete_end_(delete_end), ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( this, &BrowsingDataRemover::OnClearedDatabases)), + ALLOW_THIS_IN_INITIALIZER_LIST(appcache_got_info_callback_( + this, &BrowsingDataRemover::OnGotAppCacheInfo)), + ALLOW_THIS_IN_INITIALIZER_LIST(appcache_deleted_callback_( + this, &BrowsingDataRemover::OnAppCacheDeleted)), + request_context_getter_(profile->GetRequestContext()), + appcaches_to_be_deleted_count_(0), waiting_for_clear_databases_(false), waiting_for_clear_history_(false), - waiting_for_clear_cache_(false) { + waiting_for_clear_cache_(false), + waiting_for_clear_appcache_(false) { DCHECK(profile); } @@ -146,7 +161,13 @@ void BrowsingDataRemover::Remove(int remove_mask) { profile_->GetTransportSecurityState(); ts_state->DeleteSince(delete_begin_); - // TODO(michaeln): clear appcaches created in the date range + waiting_for_clear_appcache_ = true; + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, + &BrowsingDataRemover::ClearAppCacheOnIOThread, + delete_begin_)); // we assume end time == now } if (remove_mask & REMOVE_PASSWORDS) { @@ -336,3 +357,62 @@ void BrowsingDataRemover::ClearDatabasesOnFILEThread(base::Time delete_begin) { if (rv != net::ERR_IO_PENDING) OnClearedDatabases(rv); } + +void BrowsingDataRemover::OnClearedAppCache() { + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + bool result = ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &BrowsingDataRemover::OnClearedAppCache)); + DCHECK(result); + return; + } + waiting_for_clear_appcache_ = false; + NotifyAndDeleteIfDone(); +} + +void BrowsingDataRemover::ClearAppCacheOnIOThread(base::Time delete_begin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(waiting_for_clear_appcache_); + + appcache_info_ = new appcache::AppCacheInfoCollection; + GetAppCacheService()->GetAllAppCacheInfo( + appcache_info_, &appcache_got_info_callback_); + // continues in OnGotAppCacheInfo +} + +void BrowsingDataRemover::OnGotAppCacheInfo(int rv) { + using appcache::AppCacheInfoVector; + typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin; + + for (InfoByOrigin::const_iterator origin = + appcache_info_->infos_by_origin.begin(); + origin != appcache_info_->infos_by_origin.end(); ++origin) { + for (AppCacheInfoVector::const_iterator info = origin->second.begin(); + info != origin->second.end(); ++info) { + if (info->creation_time > delete_begin_) { + ++appcaches_to_be_deleted_count_; + GetAppCacheService()->DeleteAppCacheGroup( + info->manifest_url, &appcache_deleted_callback_); + } + } + } + + if (!appcaches_to_be_deleted_count_) + OnClearedAppCache(); + // else continues in OnAppCacheDeleted +} + +void BrowsingDataRemover::OnAppCacheDeleted(int rv) { + --appcaches_to_be_deleted_count_; + if (!appcaches_to_be_deleted_count_) + OnClearedAppCache(); +} + +ChromeAppCacheService* BrowsingDataRemover::GetAppCacheService() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + ChromeURLRequestContext* request_context = + reinterpret_cast<ChromeURLRequestContext*>( + request_context_getter_->GetURLRequestContext()); + return request_context ? request_context->appcache_service() + : NULL; +} diff --git a/chrome/browser/browsing_data_remover.h b/chrome/browser/browsing_data_remover.h index 74ba60e..591427c 100644 --- a/chrome/browser/browsing_data_remover.h +++ b/chrome/browser/browsing_data_remover.h @@ -8,6 +8,7 @@ #include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/time.h" +#include "chrome/browser/appcache/chrome_appcache_service.h" #include "chrome/browser/cancelable_request.h" #include "chrome/common/notification_registrar.h" #include "webkit/database/database_tracker.h" @@ -104,13 +105,26 @@ class BrowsingDataRemover : public NotificationObserver { // Invoked on the FILE thread to delete HTML5 databases. void ClearDatabasesOnFILEThread(base::Time delete_begin); + // Callback when the appcache has been cleared. Invokes + // NotifyAndDeleteIfDone. + void OnClearedAppCache(); + + // Invoked on the IO thread to delete from the AppCache. + void ClearAppCacheOnIOThread(base::Time delete_begin); + + // Lower level helpers. + void OnGotAppCacheInfo(int rv); + void OnAppCacheDeleted(int rv); + ChromeAppCacheService* GetAppCacheService(); + // Calculate the begin time for the deletion range specified by |time_period|. base::Time CalculateBeginDeleteTime(TimePeriod time_period); // Returns true if we're all done. bool all_done() { return registrar_.IsEmpty() && !waiting_for_clear_cache_ && - !waiting_for_clear_history_ && !waiting_for_clear_databases_; + !waiting_for_clear_history_ && !waiting_for_clear_databases_ && + !waiting_for_clear_appcache_; } NotificationRegistrar registrar_; @@ -132,14 +146,18 @@ class BrowsingDataRemover : public NotificationObserver { net::CompletionCallbackImpl<BrowsingDataRemover> database_cleared_callback_; - // True if we're waiting for HTML5 databases to be deleted. - bool waiting_for_clear_databases_; + // Used to clear the appcache. + net::CompletionCallbackImpl<BrowsingDataRemover> appcache_got_info_callback_; + net::CompletionCallbackImpl<BrowsingDataRemover> appcache_deleted_callback_; + scoped_refptr<appcache::AppCacheInfoCollection> appcache_info_; + scoped_refptr<URLRequestContextGetter> request_context_getter_; + int appcaches_to_be_deleted_count_; - // True if we're waiting for the history to be deleted. + // True if we're waiting for various data to be deleted. + bool waiting_for_clear_databases_; bool waiting_for_clear_history_; - - // True if we're waiting for the cache to be cleared. bool waiting_for_clear_cache_; + bool waiting_for_clear_appcache_; ObserverList<Observer> observer_list_; diff --git a/chrome/browser/cookies_tree_model.cc b/chrome/browser/cookies_tree_model.cc index d884b11..3fd2fca 100644 --- a/chrome/browser/cookies_tree_model.cc +++ b/chrome/browser/cookies_tree_model.cc @@ -131,14 +131,15 @@ class OriginNodeComparator { // CookieTreeAppCacheNode, public: CookieTreeAppCacheNode::CookieTreeAppCacheNode( - const BrowsingDataAppCacheHelper::AppCacheInfo* appcache_info) + const appcache::AppCacheInfo* appcache_info) : CookieTreeNode(UTF8ToWide(appcache_info->manifest_url.spec())), appcache_info_(appcache_info) { } void CookieTreeAppCacheNode::DeleteStoredObjects() { DCHECK(GetModel()->appcache_helper_); - GetModel()->appcache_helper_->DeleteAppCache(appcache_info_->group_id); + GetModel()->appcache_helper_->DeleteAppCacheGroup( + appcache_info_->manifest_url); } /////////////////////////////////////////////////////////////////////////////// @@ -441,27 +442,37 @@ void CookiesTreeModel::RemoveObserver(Observer* observer) { } void CookiesTreeModel::OnAppCacheModelInfoLoaded() { + appcache_info_ = appcache_helper_->info_collection(); PopulateAppCacheInfoWithFilter(std::wstring()); } void CookiesTreeModel::PopulateAppCacheInfoWithFilter( const std::wstring& filter) { - if (!appcache_helper_ || appcache_helper_->info_list().empty()) + using appcache::AppCacheInfo; + using appcache::AppCacheInfoVector; + typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin; + + if (!appcache_info_ || appcache_info_->infos_by_origin.empty()) return; + CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot()); NotifyObserverBeginBatch(); - for (AppCacheInfoList::const_iterator info = - appcache_helper_->info_list().begin(); - info != appcache_helper_->info_list().end(); ++info) { - std::wstring origin_node_name = UTF8ToWide(info->manifest_url.host()); + for (InfoByOrigin::const_iterator origin = + appcache_info_->infos_by_origin.begin(); + origin != appcache_info_->infos_by_origin.end(); ++origin) { + std::wstring origin_node_name = UTF8ToWide(origin->first.host()); if (filter.empty() || (origin_node_name.find(filter) != std::wstring::npos)) { CookieTreeOriginNode* origin_node = root->GetOrCreateOriginNode(origin_node_name); CookieTreeAppCachesNode* appcaches_node = origin_node->GetOrCreateAppCachesNode(); - appcaches_node->AddAppCacheNode( - new CookieTreeAppCacheNode(&(*info))); + + for (AppCacheInfoVector::const_iterator info = origin->second.begin(); + info != origin->second.end(); ++info) { + appcaches_node->AddAppCacheNode( + new CookieTreeAppCacheNode(&(*info))); + } } } NotifyObserverTreeNodeChanged(root); diff --git a/chrome/browser/cookies_tree_model.h b/chrome/browser/cookies_tree_model.h index 056fe5f..50f2e4a 100644 --- a/chrome/browser/cookies_tree_model.h +++ b/chrome/browser/cookies_tree_model.h @@ -57,7 +57,7 @@ class CookieTreeNode : public TreeNode<CookieTreeNode> { const BrowsingDataDatabaseHelper::DatabaseInfo* database_info, const BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info, - const BrowsingDataAppCacheHelper::AppCacheInfo* appcache_info) + const appcache::AppCacheInfo* appcache_info) : origin(origin), node_type(node_type), cookie(cookie), @@ -74,7 +74,7 @@ class CookieTreeNode : public TreeNode<CookieTreeNode> { const net::CookieMonster::CookieListPair* cookie; const BrowsingDataDatabaseHelper::DatabaseInfo* database_info; const BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info; - const BrowsingDataAppCacheHelper::AppCacheInfo* appcache_info; + const appcache::AppCacheInfo* appcache_info; }; CookieTreeNode() {} @@ -217,7 +217,7 @@ class CookieTreeAppCacheNode : public CookieTreeNode { // Does not take ownership of appcache_info, and appcache_info should remain // valid at least as long as the CookieTreeAppCacheNode is valid. explicit CookieTreeAppCacheNode( - const BrowsingDataAppCacheHelper::AppCacheInfo* appcache_info); + const appcache::AppCacheInfo* appcache_info); virtual ~CookieTreeAppCacheNode() {} virtual void DeleteStoredObjects(); @@ -228,7 +228,7 @@ class CookieTreeAppCacheNode : public CookieTreeNode { } private: - const BrowsingDataAppCacheHelper::AppCacheInfo* appcache_info_; + const appcache::AppCacheInfo* appcache_info_; DISALLOW_COPY_AND_ASSIGN(CookieTreeAppCacheNode); }; @@ -398,8 +398,6 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> { }; typedef net::CookieMonster::CookieList CookieList; typedef std::vector<net::CookieMonster::CookieListPair*> CookiePtrList; - typedef std::vector<BrowsingDataAppCacheHelper::AppCacheInfo> - AppCacheInfoList; typedef std::vector<BrowsingDataDatabaseHelper::DatabaseInfo> DatabaseInfoList; typedef std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo> @@ -427,6 +425,7 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> { scoped_refptr<BrowsingDataAppCacheHelper> appcache_helper_; scoped_refptr<BrowsingDataDatabaseHelper> database_helper_; + scoped_refptr<appcache::AppCacheInfoCollection> appcache_info_; DatabaseInfoList database_info_list_; scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper_; diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.cc b/chrome/browser/gtk/gtk_chrome_cookie_view.cc index b6a6728..9c03994 100644 --- a/chrome/browser/gtk/gtk_chrome_cookie_view.cc +++ b/chrome/browser/gtk/gtk_chrome_cookie_view.cc @@ -432,7 +432,7 @@ void gtk_chrome_cookie_view_display_local_storage( // Switches the display to showing the passed in app cache. void gtk_chrome_cookie_view_display_app_cache( GtkChromeCookieView* self, - const BrowsingDataAppCacheHelper::AppCacheInfo& info) { + const appcache::AppCacheInfo& info) { UpdateVisibleDetailedInfo(self, self->appcache_details_table_); gtk_entry_set_text(GTK_ENTRY(self->appcache_manifest_entry_), diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.h b/chrome/browser/gtk/gtk_chrome_cookie_view.h index 2716eeb..ce157bf 100644 --- a/chrome/browser/gtk/gtk_chrome_cookie_view.h +++ b/chrome/browser/gtk/gtk_chrome_cookie_view.h @@ -141,7 +141,7 @@ void gtk_chrome_cookie_view_display_local_storage( // Switches the display to showing the passed in app cache. void gtk_chrome_cookie_view_display_app_cache( GtkChromeCookieView* widget, - const BrowsingDataAppCacheHelper::AppCacheInfo& info); + const appcache::AppCacheInfo& info); // Switches the display to an individual storage item. void gtk_chrome_cookie_view_display_local_storage_item( diff --git a/chrome/browser/mock_browsing_data_appcache_helper.cc b/chrome/browser/mock_browsing_data_appcache_helper.cc index 1dccff4..e056004 100644 --- a/chrome/browser/mock_browsing_data_appcache_helper.cc +++ b/chrome/browser/mock_browsing_data_appcache_helper.cc @@ -24,6 +24,7 @@ void MockBrowsingDataAppCacheHelper::CancelNotification() { completion_callback_.reset(NULL); } -void MockBrowsingDataAppCacheHelper::DeleteAppCache(int64 group_id) { +void MockBrowsingDataAppCacheHelper::DeleteAppCacheGroup( + const GURL& manifest_url) { } diff --git a/chrome/browser/mock_browsing_data_appcache_helper.h b/chrome/browser/mock_browsing_data_appcache_helper.h index 6dc6607..e5b3630 100644 --- a/chrome/browser/mock_browsing_data_appcache_helper.h +++ b/chrome/browser/mock_browsing_data_appcache_helper.h @@ -17,7 +17,7 @@ class MockBrowsingDataAppCacheHelper virtual void StartFetching(Callback0::Type* completion_callback); virtual void CancelNotification(); - virtual void DeleteAppCache(int64 group_id); + virtual void DeleteAppCacheGroup(const GURL& manifest_url); private: virtual ~MockBrowsingDataAppCacheHelper(); diff --git a/chrome/browser/views/appcache_info_view.cc b/chrome/browser/views/appcache_info_view.cc index fd23e7f..4de638c 100755 --- a/chrome/browser/views/appcache_info_view.cc +++ b/chrome/browser/views/appcache_info_view.cc @@ -29,8 +29,7 @@ AppCacheInfoView::AppCacheInfoView() AppCacheInfoView::~AppCacheInfoView() { } -void AppCacheInfoView::SetAppCacheInfo( - const BrowsingDataAppCacheHelper::AppCacheInfo* info) { +void AppCacheInfoView::SetAppCacheInfo(const appcache::AppCacheInfo* info) { DCHECK(info); manifest_url_field_->SetText(UTF8ToWide(info->manifest_url.spec())); size_field_->SetText( diff --git a/chrome/browser/views/appcache_info_view.h b/chrome/browser/views/appcache_info_view.h index ad209d0..25db5dd 100755 --- a/chrome/browser/views/appcache_info_view.h +++ b/chrome/browser/views/appcache_info_view.h @@ -26,7 +26,7 @@ class AppCacheInfoView : public views::View { AppCacheInfoView(); virtual ~AppCacheInfoView(); - void SetAppCacheInfo(const BrowsingDataAppCacheHelper::AppCacheInfo* info); + void SetAppCacheInfo(const appcache::AppCacheInfo* info); void ClearAppCacheDisplay(); void EnableAppCacheDisplay(bool enabled); diff --git a/webkit/appcache/appcache_group.cc b/webkit/appcache/appcache_group.cc index 8063b911..0f9b4af 100644 --- a/webkit/appcache/appcache_group.cc +++ b/webkit/appcache/appcache_group.cc @@ -41,6 +41,7 @@ AppCacheGroup::AppCacheGroup(AppCacheService* service, manifest_url_(manifest_url), update_status_(IDLE), is_obsolete_(false), + is_being_deleted_(false), newest_complete_cache_(NULL), update_job_(NULL), service_(service), @@ -137,9 +138,8 @@ void AppCacheGroup::RemoveCache(AppCache* cache) { void AppCacheGroup::AddNewlyDeletableResponseIds( std::vector<int64>* response_ids) { - if (!is_obsolete() && old_caches_.empty()) { - service_->storage()->DeleteResponses( - manifest_url_, *response_ids); + if (is_being_deleted() || (!is_obsolete() && old_caches_.empty())) { + service_->storage()->DeleteResponses(manifest_url_, *response_ids); response_ids->clear(); return; } @@ -156,6 +156,7 @@ void AppCacheGroup::AddNewlyDeletableResponseIds( void AppCacheGroup::StartUpdateWithNewMasterEntry( AppCacheHost* host, const GURL& new_master_resource) { + DCHECK(!is_obsolete() && !is_being_deleted()); if (is_in_dtor_) return; @@ -172,6 +173,14 @@ void AppCacheGroup::StartUpdateWithNewMasterEntry( } } +void AppCacheGroup::CancelUpdate() { + if (update_job_) { + delete update_job_; + DCHECK(!update_job_); + DCHECK_EQ(IDLE, update_status_); + } +} + void AppCacheGroup::QueueUpdate(AppCacheHost* host, const GURL& new_master_resource) { DCHECK(update_job_ && host && !new_master_resource.is_empty()); @@ -208,7 +217,7 @@ void AppCacheGroup::RunQueuedUpdates() { observers_.AddObserver(host); } - if (!is_obsolete()) + if (!is_obsolete() && !is_being_deleted()) StartUpdateWithNewMasterEntry(host, it->second); } } diff --git a/webkit/appcache/appcache_group.h b/webkit/appcache/appcache_group.h index 1558b5a8..c1bb1fc 100644 --- a/webkit/appcache/appcache_group.h +++ b/webkit/appcache/appcache_group.h @@ -55,6 +55,9 @@ class AppCacheGroup : public base::RefCounted<AppCacheGroup> { bool is_obsolete() const { return is_obsolete_; } void set_obsolete(bool value) { is_obsolete_ = value; } + bool is_being_deleted() const { return is_being_deleted_; } + void set_being_deleted(bool value) { is_being_deleted_ = value; } + AppCache* newest_complete_cache() const { return newest_complete_cache_; } void AddCache(AppCache* complete_cache); @@ -81,6 +84,9 @@ class AppCacheGroup : public base::RefCounted<AppCacheGroup> { void StartUpdateWithNewMasterEntry(AppCacheHost* host, const GURL& new_master_resource); + // Cancels an update if one is running. + void CancelUpdate(); + private: class HostObserver; @@ -113,6 +119,7 @@ class AppCacheGroup : public base::RefCounted<AppCacheGroup> { const GURL manifest_url_; UpdateStatus update_status_; bool is_obsolete_; + bool is_being_deleted_; std::vector<int64> newly_deletable_response_ids_; // Old complete app caches. diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc index 9d1bf9c..4fb098f 100644 --- a/webkit/appcache/appcache_host.cc +++ b/webkit/appcache/appcache_host.cc @@ -142,7 +142,7 @@ void AppCacheHost::DoPendingStartUpdate() { bool success = false; if (associated_cache_ && associated_cache_->owning_group()) { AppCacheGroup* group = associated_cache_->owning_group(); - if (!group->is_obsolete()) { + if (!group->is_obsolete() && !group->is_being_deleted()) { success = true; group->StartUpdate(); } @@ -235,7 +235,7 @@ void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) { } void AppCacheHost::OnGroupLoaded(AppCacheGroup* group, - const GURL& manifest_url) { + const GURL& manifest_url) { DCHECK(manifest_url == pending_selected_manifest_url_); pending_selected_manifest_url_ = GURL(); FinishCacheSelection(NULL, group); @@ -270,11 +270,12 @@ void AppCacheHost::FinishCacheSelection( DCHECK(cache->owning_group()); DCHECK(new_master_entry_url_.is_empty()); AssociateCache(cache); - if (!cache->owning_group()->is_obsolete()) { - cache->owning_group()->StartUpdateWithHost(this); - ObserveGroupBeingUpdated(cache->owning_group()); + AppCacheGroup* owing_group = cache->owning_group(); + if (!owing_group->is_obsolete() && !owing_group->is_being_deleted()) { + owing_group->StartUpdateWithHost(this); + ObserveGroupBeingUpdated(owing_group); } - } else if (group) { + } else if (group && !group->is_being_deleted()) { // If document was loaded using HTTP GET or equivalent, and, there is a // manifest URL, and manifest URL has the same origin as document. // Invoke the application cache update process for manifest URL, with @@ -287,6 +288,7 @@ void AppCacheHost::FinishCacheSelection( ObserveGroupBeingUpdated(group); } else { // Otherwise, the Document is not associated with any application cache. + new_master_entry_url_ = GURL(); AssociateCache(NULL); } diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc index 65cc457..a6bc24a 100644 --- a/webkit/appcache/appcache_service.cc +++ b/webkit/appcache/appcache_service.cc @@ -5,17 +5,142 @@ #include "webkit/appcache/appcache_service.h" #include "base/logging.h" +#include "base/message_loop.h" +#include "base/stl_util-inl.h" #include "webkit/appcache/appcache_backend_impl.h" #include "webkit/appcache/appcache_storage_impl.h" namespace appcache { +// AsyncHelper ------- + +class AppCacheService::AsyncHelper + : public AppCacheStorage::Delegate { + public: + AsyncHelper( + AppCacheService* service, net::CompletionCallback* callback) + : service_(service), callback_(callback) { + service_->pending_helpers_.insert(this); + } + + virtual ~AsyncHelper() { + if (service_) + service_->pending_helpers_.erase(this); + } + + virtual void Start() = 0; + virtual void Cancel(); + + protected: + void CallCallback(int rv) { + if (callback_) { + // Defer to guarentee async completion. + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableFunction(&DeferredCallCallback, callback_, rv)); + } + callback_ = NULL; + } + + static void DeferredCallCallback(net::CompletionCallback* callback, int rv) { + callback->Run(rv); + } + + AppCacheService* service_; + net::CompletionCallback* callback_; +}; + +void AppCacheService::AsyncHelper::Cancel() { + CallCallback(net::ERR_ABORTED); + service_->storage()->CancelDelegateCallbacks(this); + service_ = NULL; +} + +// DeleteHelper ------- + +class AppCacheService::DeleteHelper : public AsyncHelper { + public: + DeleteHelper( + AppCacheService* service, const GURL& manifest_url, + net::CompletionCallback* callback) + : AsyncHelper(service, callback), manifest_url_(manifest_url) { + } + + virtual void Start() { + service_->storage()->LoadOrCreateGroup(manifest_url_, this); + } + + private: + // AppCacheStorage::Delegate methods + virtual void OnGroupLoaded( + appcache::AppCacheGroup* group, const GURL& manifest_url); + virtual void OnGroupMadeObsolete( + appcache::AppCacheGroup* group, bool success); + + GURL manifest_url_; +}; + +void AppCacheService::DeleteHelper::OnGroupLoaded( + appcache::AppCacheGroup* group, const GURL& manifest_url) { + if (group) { + group->set_being_deleted(true); + group->CancelUpdate(); + service_->storage()->MakeGroupObsolete(group, this); + } else { + CallCallback(net::ERR_FAILED); + delete this; + } +} + +void AppCacheService::DeleteHelper::OnGroupMadeObsolete( + appcache::AppCacheGroup* group, bool success) { + CallCallback(success ? net::OK : net::ERR_FAILED); + delete this; +} + +// GetInfoHelper ------- + +class AppCacheService::GetInfoHelper : AsyncHelper { + public: + GetInfoHelper( + AppCacheService* service, AppCacheInfoCollection* collection, + net::CompletionCallback* callback) + : AsyncHelper(service, callback), collection_(collection) { + } + + virtual void Start() { + service_->storage()->GetAllInfo(this); + } + + private: + // AppCacheStorage::Delegate override + virtual void OnAllInfo(AppCacheInfoCollection* collection); + + scoped_refptr<AppCacheInfoCollection> collection_; +}; + +void AppCacheService::GetInfoHelper::OnAllInfo( + AppCacheInfoCollection* collection) { + if (collection) + collection->infos_by_origin.swap(collection_->infos_by_origin); + CallCallback(collection ? net::OK : net::ERR_FAILED); + delete this; +} + + +// AppCacheService ------- + AppCacheService::AppCacheService() : appcache_policy_(NULL), request_context_(NULL) { } AppCacheService::~AppCacheService() { DCHECK(backends_.empty()); + + std::for_each(pending_helpers_.begin(), + pending_helpers_.end(), + std::mem_fun(&AsyncHelper::Cancel)); + STLDeleteElements(&pending_helpers_); } void AppCacheService::Initialize(const FilePath& cache_directory) { @@ -25,6 +150,19 @@ void AppCacheService::Initialize(const FilePath& cache_directory) { storage_.reset(storage); } +void AppCacheService::GetAllAppCacheInfo(AppCacheInfoCollection* collection, + net::CompletionCallback* callback) { + DCHECK(collection); + GetInfoHelper* helper = new GetInfoHelper(this, collection, callback); + helper->Start(); +} + +void AppCacheService::DeleteAppCacheGroup(const GURL& manifest_url, + net::CompletionCallback* callback) { + DeleteHelper* helper = new DeleteHelper(this, manifest_url, callback); + helper->Start(); +} + void AppCacheService::RegisterBackend( AppCacheBackendImpl* backend_impl) { DCHECK(backends_.find(backend_impl->process_id()) == backends_.end()); diff --git a/webkit/appcache/appcache_service.h b/webkit/appcache/appcache_service.h index 70a0953..7ccdeea 100644 --- a/webkit/appcache/appcache_service.h +++ b/webkit/appcache/appcache_service.h @@ -5,8 +5,15 @@ #ifndef WEBKIT_APPCACHE_APPCACHE_SERVICE_H_ #define WEBKIT_APPCACHE_APPCACHE_SERVICE_H_ +#include <set> +#include <vector> + #include "base/file_path.h" +#include "base/ref_counted.h" #include "base/scoped_ptr.h" +#include "base/time.h" +#include "net/base/completion_callback.h" +#include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest_prod.h" #include "webkit/appcache/appcache_storage.h" @@ -17,6 +24,36 @@ namespace appcache { class AppCacheBackendImpl; class AppCachePolicy; +// Structure that contains basic info about an appcache. +struct AppCacheInfo { + AppCacheInfo() {} + AppCacheInfo(const GURL& manifest_url, + int64 size, + base::Time creation_time, + base::Time last_access_time, + base::Time last_update_time) + : manifest_url(manifest_url), + size(size), + creation_time(creation_time), + last_access_time(last_access_time), + last_update_time(last_update_time) { + } + GURL manifest_url; + int64 size; + base::Time creation_time; + base::Time last_access_time; + base::Time last_update_time; +}; + +typedef std::vector<AppCacheInfo> AppCacheInfoVector; + +// Refcounted container to avoid copying the collection in callbacks. +struct AppCacheInfoCollection + : public base::RefCountedThreadSafe<AppCacheInfoCollection> { + virtual ~AppCacheInfoCollection() {} + std::map<GURL, AppCacheInfoVector> infos_by_origin; +}; + // Class that manages the application cache service. Sends notifications // to many frontends. One instance per user-profile. Each instance has // exclusive access to it's cache_directory on disk. @@ -27,11 +64,27 @@ class AppCacheService { void Initialize(const FilePath& cache_directory); + // Purges any memory not needed. void PurgeMemory() { if (storage_.get()) storage_->PurgeMemory(); } + // Populates 'collection' with info about all of the appcaches stored + // within the service, 'callback' is invoked upon completion. The service + // acquires a reference to the 'collection' until until completion. + // This method always completes asynchronously. + void GetAllAppCacheInfo(AppCacheInfoCollection* collection, + net::CompletionCallback* callback); + + // Deletes the group identified by 'manifest_url', 'callback' is + // invoked upon completion. Upon completion, the cache group and + // any resources within the group are no longer loadable and all + // subresource loads for pages associated with a deleted group + // will fail. This method always completes asynchronously. + void DeleteAppCacheGroup(const GURL& manifest_url, + net::CompletionCallback* callback); + // Context for use during cache updates, should only be accessed // on the IO thread. We do NOT add a reference to the request context, // it is the callers responsibility to ensure that the pointer @@ -49,7 +102,8 @@ class AppCacheService { appcache_policy_ = policy; } - // Track which processes are using this appcache service. + // Each child process in chrome uses a distinct backend instance. + // See chrome/browser/AppCacheDispatcherHost. void RegisterBackend(AppCacheBackendImpl* backend_impl); void UnregisterBackend(AppCacheBackendImpl* backend_impl); AppCacheBackendImpl* GetBackend(int id) const { @@ -60,11 +114,19 @@ class AppCacheService { AppCacheStorage* storage() const { return storage_.get(); } protected: + class AsyncHelper; + class DeleteHelper; + class GetInfoHelper; + + typedef std::set<AsyncHelper*> PendingAsyncHelpers; + AppCachePolicy* appcache_policy_; // Deals with persistence. scoped_ptr<AppCacheStorage> storage_; + PendingAsyncHelpers pending_helpers_; + // Track current processes. One 'backend' per child process. typedef std::map<int, AppCacheBackendImpl*> BackendMap; BackendMap backends_; diff --git a/webkit/appcache/appcache_storage.h b/webkit/appcache/appcache_storage.h index 4c51e39..5618be4 100644 --- a/webkit/appcache/appcache_storage.h +++ b/webkit/appcache/appcache_storage.h @@ -26,6 +26,7 @@ class AppCacheGroup; class AppCacheResponseReader; class AppCacheResponseWriter; class AppCacheService; +struct AppCacheInfoCollection; struct HttpResponseInfoIOBuffer; class AppCacheStorage { @@ -35,6 +36,9 @@ class AppCacheStorage { public: virtual ~Delegate() {} + // If retrieval fails, 'collection' will be NULL. + virtual void OnAllInfo(AppCacheInfoCollection* collection) {} + // If a load fails the 'cache' will be NULL. virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) {} @@ -65,6 +69,11 @@ class AppCacheStorage { explicit AppCacheStorage(AppCacheService* service); virtual ~AppCacheStorage(); + // Schedules a task to retrieve basic info about all groups and caches + // stored in the system. Upon completion the delegate will be called + // with the results. + virtual void GetAllInfo(Delegate* delegate) = 0; + // Schedules a cache to be loaded from storage. Upon load completion // the delegate will be called back. If the cache already resides in // memory, the delegate will be called back immediately without returning diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 6fd5486..54afc9a 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -183,6 +183,49 @@ class AppCacheStorageImpl::DisableDatabaseTask : public DatabaseTask { virtual void Run() { database_->Disable(); } }; +// GetAllInfoTask ------- + +class AppCacheStorageImpl::GetAllInfoTask : public DatabaseTask { + public: + explicit GetAllInfoTask(AppCacheStorageImpl* storage) + : DatabaseTask(storage), + info_collection_(new AppCacheInfoCollection()) { + } + + virtual void Run(); + virtual void RunCompleted(); + + scoped_refptr<AppCacheInfoCollection> info_collection_; +}; + +void AppCacheStorageImpl::GetAllInfoTask::Run() { + std::set<GURL> origins; + database_->FindOriginsWithGroups(&origins); + for (std::set<GURL>::const_iterator origin = origins.begin(); + origin != origins.end(); ++origin) { + AppCacheInfoVector& infos = + info_collection_->infos_by_origin[*origin]; + std::vector<AppCacheDatabase::GroupRecord> groups; + database_->FindGroupsForOrigin(*origin, &groups); + for (std::vector<AppCacheDatabase::GroupRecord>::const_iterator + group = groups.begin(); + group != groups.end(); ++group) { + AppCacheDatabase::CacheRecord cache_record; + database_->FindCacheForGroup(group->group_id, &cache_record); + infos.push_back( + AppCacheInfo( + group->manifest_url, cache_record.cache_size, + group->creation_time, group->last_access_time, + cache_record.update_time)); + } + } +} + +void AppCacheStorageImpl::GetAllInfoTask::RunCompleted() { + DCHECK(delegates_.size() == 1); + FOR_EACH_DELEGATE(delegates_, OnAllInfo(info_collection_)); +} + // StoreOrLoadTask ------- class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask { @@ -812,6 +855,13 @@ void AppCacheStorageImpl::Disable() { task->Schedule(); } +void AppCacheStorageImpl::GetAllInfo(Delegate* delegate) { + DCHECK(delegate); + scoped_refptr<GetAllInfoTask> task = new GetAllInfoTask(this); + task->AddDelegate(GetOrCreateDelegateReference(delegate)); + task->Schedule(); +} + void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) { DCHECK(delegate); if (is_disabled_) { @@ -993,6 +1043,17 @@ void AppCacheStorageImpl::FindResponseForSubRequest( AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, bool* found_network_namespace) { DCHECK(cache && cache->is_complete()); + + // When a group is forcibly deleted, all subresource loads for pages + // using caches in the group will result in a synthesized network errors. + // Forcible deletion is not a function that is covered by the HTML5 spec. + if (cache->owning_group()->is_being_deleted()) { + *found_entry = AppCacheEntry(); + *found_fallback_entry = AppCacheEntry(); + *found_network_namespace = false; + return; + } + GURL fallback_namespace_not_used; cache->FindResponseForRequest( url, found_entry, found_fallback_entry, diff --git a/webkit/appcache/appcache_storage_impl.h b/webkit/appcache/appcache_storage_impl.h index b644eff..5771dd4 100644 --- a/webkit/appcache/appcache_storage_impl.h +++ b/webkit/appcache/appcache_storage_impl.h @@ -27,7 +27,8 @@ class AppCacheStorageImpl : public AppCacheStorage { void Disable(); bool is_disabled() const { return is_disabled_; } - // AppCacheStorage methods + // AppCacheStorage methods, see the base class for doc comments. + virtual void GetAllInfo(Delegate* delegate); virtual void LoadCache(int64 id, Delegate* delegate); virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate); virtual void StoreGroupAndNewestCache( @@ -59,6 +60,7 @@ class AppCacheStorageImpl : public AppCacheStorage { class InitTask; class CloseConnectionTask; class DisableDatabaseTask; + class GetAllInfoTask; class StoreOrLoadTask; class CacheLoadTask; class GroupLoadTask; diff --git a/webkit/appcache/mock_appcache_storage.h b/webkit/appcache/mock_appcache_storage.h index 48834bd..10bd780 100644 --- a/webkit/appcache/mock_appcache_storage.h +++ b/webkit/appcache/mock_appcache_storage.h @@ -28,6 +28,7 @@ class MockAppCacheStorage : public AppCacheStorage { explicit MockAppCacheStorage(AppCacheService* service); virtual ~MockAppCacheStorage(); + virtual void GetAllInfo(Delegate* delegate) {} // not implemented virtual void LoadCache(int64 id, Delegate* delegate); virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate); virtual void StoreGroupAndNewestCache( |