// Copyright (c) 2011 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 "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_entry.h" #include "webkit/appcache/appcache_storage_impl.h" #include "webkit/quota/special_storage_policy.h" namespace appcache { AppCacheInfoCollection::AppCacheInfoCollection() {} AppCacheInfoCollection::~AppCacheInfoCollection() {} // 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; } // CanHandleOfflineHelper ------- class AppCacheService::CanHandleOfflineHelper : AsyncHelper { public: CanHandleOfflineHelper( AppCacheService* service, const GURL& url, net::CompletionCallback* callback) : AsyncHelper(service, callback), url_(url) { } virtual void Start() { service_->storage()->FindResponseForMainRequest(url_, GURL(), this); } private: // AppCacheStorage::Delegate override virtual void OnMainResponseFound( const GURL& url, const AppCacheEntry& entry, const GURL& fallback_url, const AppCacheEntry& fallback_entry, int64 cache_id, const GURL& mainfest_url, bool was_blocked_by_policy); GURL url_; DISALLOW_COPY_AND_ASSIGN(CanHandleOfflineHelper); }; void AppCacheService::CanHandleOfflineHelper::OnMainResponseFound( const GURL& url, const AppCacheEntry& entry, const GURL& fallback_url, const AppCacheEntry& fallback_entry, int64 cache_id, const GURL& mainfest_url, bool was_blocked_by_policy) { bool can = !was_blocked_by_policy && (entry.has_response_id() || fallback_entry.has_response_id()); CallCallback(can ? net::OK : net::ERR_FAILED); delete this; } // 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_; DISALLOW_COPY_AND_ASSIGN(DeleteHelper); }; 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 collection_; DISALLOW_COPY_AND_ASSIGN(GetInfoHelper); }; 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, base::MessageLoopProxy* cache_thread) { DCHECK(!storage_.get()); AppCacheStorageImpl* storage = new AppCacheStorageImpl(this); storage->Initialize(cache_directory, cache_thread); storage_.reset(storage); } void AppCacheService::CanHandleMainResourceOffline( const GURL& url, net::CompletionCallback* callback) { CanHandleOfflineHelper* helper = new CanHandleOfflineHelper(this, url, callback); helper->Start(); } 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::set_special_storage_policy( quota::SpecialStoragePolicy* policy) { special_storage_policy_ = policy; } void AppCacheService::RegisterBackend( AppCacheBackendImpl* backend_impl) { DCHECK(backends_.find(backend_impl->process_id()) == backends_.end()); backends_.insert( BackendMap::value_type(backend_impl->process_id(), backend_impl)); } void AppCacheService::UnregisterBackend( AppCacheBackendImpl* backend_impl) { backends_.erase(backend_impl->process_id()); } } // namespace appcache