summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/appcache')
-rw-r--r--webkit/appcache/appcache.cc5
-rw-r--r--webkit/appcache/appcache_group.cc5
-rw-r--r--webkit/appcache/appcache_group_unittest.cc8
-rw-r--r--webkit/appcache/appcache_host.cc18
-rw-r--r--webkit/appcache/appcache_host.h13
-rw-r--r--webkit/appcache/appcache_host_unittest.cc8
-rw-r--r--webkit/appcache/appcache_interfaces.h1
-rw-r--r--webkit/appcache/appcache_response.h181
-rw-r--r--webkit/appcache/appcache_service.cc75
-rw-r--r--webkit/appcache/appcache_service.h85
-rw-r--r--webkit/appcache/appcache_storage.h178
-rw-r--r--webkit/appcache/appcache_storage_impl.cc15
-rw-r--r--webkit/appcache/appcache_storage_impl.h28
-rw-r--r--webkit/appcache/appcache_storage_unittest.cc (renamed from webkit/appcache/appcache_service_unittest.cc)25
-rw-r--r--webkit/appcache/appcache_unittest.cc14
-rw-r--r--webkit/appcache/appcache_update_job.cc3
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc30
-rw-r--r--webkit/appcache/appcache_working_set.cc38
-rw-r--r--webkit/appcache/appcache_working_set.h57
-rw-r--r--webkit/appcache/mock_appcache_service.h24
-rw-r--r--webkit/appcache/mock_appcache_storage.cc98
-rw-r--r--webkit/appcache/mock_appcache_storage.h38
22 files changed, 745 insertions, 202 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc
index 450f978..01bf37d 100644
--- a/webkit/appcache/appcache.cc
+++ b/webkit/appcache/appcache.cc
@@ -9,6 +9,7 @@
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/appcache_storage.h"
namespace appcache {
@@ -18,13 +19,13 @@ AppCache::AppCache(AppCacheService *service, int64 cache_id)
online_whitelist_all_(false),
is_complete_(false),
service_(service) {
- service_->AddCache(this);
+ service_->storage()->working_set()->AddCache(this);
}
AppCache::~AppCache() {
DCHECK(associated_hosts_.empty());
DCHECK(!owning_group_);
- service_->RemoveCache(this);
+ service_->storage()->working_set()->RemoveCache(this);
}
void AppCache::UnassociateHost(AppCacheHost* host) {
diff --git a/webkit/appcache/appcache_group.cc b/webkit/appcache/appcache_group.cc
index 67ca4cc..b45e90b 100644
--- a/webkit/appcache/appcache_group.cc
+++ b/webkit/appcache/appcache_group.cc
@@ -10,6 +10,7 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/appcache_storage.h"
#include "webkit/appcache/appcache_update_job.h"
namespace appcache {
@@ -22,7 +23,7 @@ AppCacheGroup::AppCacheGroup(AppCacheService* service,
newest_complete_cache_(NULL),
update_job_(NULL),
service_(service) {
- service_->AddGroup(this);
+ service_->storage()->working_set()->AddGroup(this);
}
AppCacheGroup::~AppCacheGroup() {
@@ -34,7 +35,7 @@ AppCacheGroup::~AppCacheGroup() {
if (newest_complete_cache_)
RemoveCache(newest_complete_cache_);
- service_->RemoveGroup(this);
+ service_->storage()->working_set()->RemoveGroup(this);
}
void AppCacheGroup::AddObserver(Observer* observer) {
diff --git a/webkit/appcache/appcache_group_unittest.cc b/webkit/appcache/appcache_group_unittest.cc
index 6eeb209..e9b7acd 100644
--- a/webkit/appcache/appcache_group_unittest.cc
+++ b/webkit/appcache/appcache_group_unittest.cc
@@ -6,7 +6,7 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
-#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/mock_appcache_service.h"
#include "webkit/appcache/appcache_update_job.h"
namespace {
@@ -46,7 +46,7 @@ class AppCacheGroupTest : public testing::Test {
};
TEST(AppCacheGroupTest, AddRemoveCache) {
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(&service, GURL::EmptyGURL());
@@ -110,7 +110,7 @@ TEST(AppCacheGroupTest, AddRemoveCache) {
}
TEST(AppCacheGroupTest, CleanupUnusedGroup) {
- AppCacheService service;
+ MockAppCacheService service;
TestAppCacheFrontend frontend;
AppCacheGroup* group = new AppCacheGroup(&service, GURL::EmptyGURL());
@@ -153,7 +153,7 @@ TEST(AppCacheGroupTest, CleanupUnusedGroup) {
TEST(AppCacheGroupTest, StartUpdate) {
/* TODO(jennb) - uncomment after AppCacheGroup::StartUpdate does something.
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(&service, GURL("http://foo.com"));
diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc
index 77a0d96..50b24a5 100644
--- a/webkit/appcache/appcache_host.cc
+++ b/webkit/appcache/appcache_host.cc
@@ -25,7 +25,7 @@ AppCacheHost::~AppCacheHost() {
FOR_EACH_OBSERVER(Observer, observers_, OnDestructionImminent(this));
if (associated_cache_.get())
associated_cache_->UnassociateHost(this);
- service_->CancelLoads(this);
+ service_->storage()->CancelDelegateCallbacks(this);
}
void AppCacheHost::AddObserver(Observer* observer) {
@@ -54,7 +54,7 @@ void AppCacheHost::SelectCache(const GURL& document_url,
// results (or suggest changes to the algorihtms described in the spec
// if the resulting behavior is just too insane).
if (is_selection_pending()) {
- service_->CancelLoads(this);
+ service_->storage()->CancelDelegateCallbacks(this);
pending_selected_manifest_url_ = GURL::EmptyGURL();
pending_selected_cache_id_ = kNoCacheId;
} else if (associated_cache()) {
@@ -89,9 +89,11 @@ void AppCacheHost::SelectCache(const GURL& document_url,
FinishCacheSelection(NULL, NULL);
}
+// TODO(michaeln): change method name to MarkEntryAsForeign for consistency
void AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
int64 cache_document_was_loaded_from) {
- service_->MarkAsForeignEntry(document_url, cache_document_was_loaded_from);
+ service_->storage()->MarkEntryAsForeign(
+ document_url, cache_document_was_loaded_from);
SelectCache(document_url, kNoCacheId, GURL::EmptyGURL());
}
@@ -191,11 +193,11 @@ Status AppCacheHost::GetStatus() {
void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) {
DCHECK(manifest_url.is_valid());
pending_selected_manifest_url_ = manifest_url;
- service_->LoadOrCreateGroup(manifest_url, this);
+ service_->storage()->LoadOrCreateGroup(manifest_url, this);
}
-void AppCacheHost::GroupLoadedCallback(
- AppCacheGroup* group, const GURL& manifest_url) {
+void AppCacheHost::OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url) {
DCHECK(manifest_url == pending_selected_manifest_url_);
pending_selected_manifest_url_ = GURL::EmptyGURL();
FinishCacheSelection(NULL, group);
@@ -204,10 +206,10 @@ void AppCacheHost::GroupLoadedCallback(
void AppCacheHost::LoadCache(int64 cache_id) {
DCHECK(cache_id != kNoCacheId);
pending_selected_cache_id_ = cache_id;
- service_->LoadCache(cache_id, this);
+ service_->storage()->LoadCache(cache_id, this);
}
-void AppCacheHost::CacheLoadedCallback(AppCache* cache, int64 cache_id) {
+void AppCacheHost::OnCacheLoaded(AppCache* cache, int64 cache_id) {
DCHECK(cache_id == pending_selected_cache_id_);
pending_selected_cache_id_ = kNoCacheId;
if (cache)
diff --git a/webkit/appcache/appcache_host.h b/webkit/appcache/appcache_host.h
index 9b7db30..5be3c5c 100644
--- a/webkit/appcache/appcache_host.h
+++ b/webkit/appcache/appcache_host.h
@@ -8,12 +8,12 @@
#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "base/task.h"
-#include "base/weak_ptr.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/appcache_storage.h"
class URLRequest;
@@ -29,8 +29,7 @@ typedef Callback2<bool, void*>::Type StartUpdateCallback;
typedef Callback2<bool, void*>::Type SwapCacheCallback;
// Server-side representation of an application cache host.
-class AppCacheHost : public base::SupportsWeakPtr<AppCacheHost>,
- public AppCacheService::LoadClient {
+class AppCacheHost : public AppCacheStorage::Delegate {
public:
class Observer {
@@ -91,10 +90,10 @@ class AppCacheHost : public base::SupportsWeakPtr<AppCacheHost>,
void LoadCache(int64 cache_id);
void LoadOrCreateGroup(const GURL& manifest_url);
- // LoadClient impl
- virtual void CacheLoadedCallback(AppCache* cache, int64 cache_id);
- virtual void GroupLoadedCallback(AppCacheGroup* group,
- const GURL& manifest_url);
+ // AppCacheStorage::Delegate impl
+ virtual void OnCacheLoaded(AppCache* cache, int64 cache_id);
+ virtual void OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url);
void FinishCacheSelection(AppCache* cache, AppCacheGroup* group);
void DoPendingGetStatus();
diff --git a/webkit/appcache/appcache_host_unittest.cc b/webkit/appcache/appcache_host_unittest.cc
index cd1497b..cdfaee2 100644
--- a/webkit/appcache/appcache_host_unittest.cc
+++ b/webkit/appcache/appcache_host_unittest.cc
@@ -7,7 +7,7 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
-#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/mock_appcache_service.h"
namespace appcache {
@@ -65,7 +65,7 @@ class AppCacheHostTest : public testing::Test {
}
// Mock classes for the 'host' to work with
- AppCacheService service_; // TODO(michaeln): make service mockable?
+ MockAppCacheService service_;
MockFrontend mock_frontend_;
// Mock callbacks we expect to receive from the 'host'
@@ -179,7 +179,7 @@ TEST_F(AppCacheHostTest, FailedCacheLoad) {
EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_);
// Satisfy the load with NULL, a failure.
- host.CacheLoadedCallback(NULL, kMockCacheId);
+ host.OnCacheLoaded(NULL, kMockCacheId);
// Cache selection should have finished
EXPECT_FALSE(host.is_selection_pending());
@@ -211,7 +211,7 @@ TEST_F(AppCacheHostTest, FailedGroupLoad) {
EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_);
// Satisfy the load will NULL, a failure.
- host.GroupLoadedCallback(NULL, kMockManifestUrl);
+ host.OnGroupLoaded(NULL, kMockManifestUrl);
// Cache selection should have finished
EXPECT_FALSE(host.is_selection_pending());
diff --git a/webkit/appcache/appcache_interfaces.h b/webkit/appcache/appcache_interfaces.h
index fcba1d8..223e560 100644
--- a/webkit/appcache/appcache_interfaces.h
+++ b/webkit/appcache/appcache_interfaces.h
@@ -20,6 +20,7 @@ extern const char kManifestMimeType[];
static const int kNoHostId = 0;
static const int64 kNoCacheId = 0;
+static const int64 kNoResponseId = 0;
static const int64 kUnknownCacheId = -1;
enum Status {
diff --git a/webkit/appcache/appcache_response.h b/webkit/appcache/appcache_response.h
new file mode 100644
index 0000000..c791a01
--- /dev/null
+++ b/webkit/appcache/appcache_response.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_APPCACHE_RESPONSE_H_
+#define WEBKIT_APPCACHE_APPCACHE_RESPONSE_H_
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "net/base/completion_callback.h"
+#include "net/http/http_response_info.h"
+#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/appcache_storage.h"
+
+namespace net {
+class IOBuffer;
+}
+namespace disk_cache {
+class Backend;
+};
+
+
+namespace appcache {
+
+// Response info for a particular response id. Instances are tracked in
+// the working set.
+class AppCacheResponseInfo
+ : public base::RefCounted<AppCacheResponseInfo> {
+
+ // AppCacheResponseInfo takes ownership of the http_info.
+ AppCacheResponseInfo(AppCacheService* service, int64 response_id,
+ net::HttpResponseInfo* http_info)
+ : response_id_(response_id), http_response_info_(http_info),
+ service_(service) {
+ DCHECK(http_info);
+ DCHECK(response_id != kNoResponseId);
+ service_->storage()->working_set()->AddResponseInfo(this);
+ }
+
+ ~AppCacheResponseInfo() {
+ service_->storage()->working_set()->RemoveResponseInfo(this);
+ }
+
+ int64 response_id() const { return response_id_; }
+
+ const net::HttpResponseInfo* http_response_info() const {
+ return http_response_info_.get();
+ }
+
+ private:
+ const int64 response_id_;
+ const scoped_ptr<net::HttpResponseInfo> http_response_info_;
+ const AppCacheService* service_;
+};
+
+// Common base class for response reader and writer.
+class AppCacheResponseIO {
+ public:
+ virtual ~AppCacheResponseIO() {}
+ int64 response_id() const { return response_id_; }
+ protected:
+ explicit AppCacheResponseIO(
+ int64 response_id, disk_cache::Backend* disk_cache)
+ : response_id_(response_id), disk_cache_(disk_cache) {}
+ const int64 response_id_;
+ disk_cache::Backend* disk_cache_;
+};
+
+// A refcounted wrapper for HttpResponseInfo so we can apply the
+// refcounting semantics used with IOBuffer with these structures too.
+struct HttpResponseInfoIOBuffer
+ : public base::RefCountedThreadSafe<HttpResponseInfoIOBuffer> {
+ scoped_ptr<net::HttpResponseInfo> http_info;
+};
+
+// Reads existing response data from storage. If the object is deleted
+// and there is a read in progress, the implementation will return
+// immediately but will take care of any side effect of cancelling the
+// operation. In other words, instances are safe to delete at will.
+class AppCacheResponseReader : public AppCacheResponseIO {
+ public:
+ // Reads http info from storage. Returns the number of bytes read
+ // or a net:: error code. Guaranteed to not perform partial reads of
+ // the info data. ERR_IO_PENDING is returned if the
+ // operation could not be completed synchronously, in which case the reader
+ // acquires a reference to the provided 'info_buf' until completion at which
+ // time the callback is invoked with either a negative error code or the
+ // number of bytes written. The 'info_buf' argument should contain a NULL
+ // http_info when ReadInfo is called. The 'callback' is a required parameter.
+ // Should only be called where there is no Read operation in progress.
+ int ReadInfo(HttpResponseInfoIOBuffer* info_buf,
+ net::CompletionCallback* callback) {
+ DCHECK(info_buf && !info_buf->http_info.get());
+ return -2;
+ }
+
+ // Reads data from storage. Returns the number of bytes read
+ // or a net:: error code. EOF is indicated with a return value of zero.
+ // ERR_IO_PENDING is returned if the operation could not be completed
+ // synchronously, in which case the reader acquires a reference to the
+ // provided 'buf' until completion at which time the callback is invoked
+ // with either a negative error code or the number of bytes read. The
+ // 'callback' is a required parameter.
+ // Should only be called where there is no Read operation in progress.
+ int ReadData(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback) { return -2; }
+
+ // Returns true if there is a read operation, for data or info, pending.
+ bool IsReadPending() { return false; }
+
+ // Used to support range requests. If not called, the reader will
+ // read the entire response body. If called, this must be called prior
+ // to the first call to the ReadData method.
+ void SetReadRange(int64 offset, int64 length) {
+ range_offset_ = offset;
+ range_length_ = length;
+ }
+
+ private:
+ friend class AppCacheStorageImpl;
+ friend class MockAppCacheStorage;
+
+ // Should only be constructed by the storage class.
+ explicit AppCacheResponseReader(
+ int64 response_id, disk_cache::Backend* disk_cache)
+ : AppCacheResponseIO(response_id, disk_cache),
+ range_offset_(0), range_length_(kint64max) {}
+
+ int64 range_offset_;
+ int64 range_length_;
+};
+
+// Writes new response data to storage. If the object is deleted
+// and there is a write in progress, the implementation will return
+// immediately but will take care of any side effect of cancelling the
+// operation. In other words, instances are safe to delete at will.
+class AppCacheResponseWriter : public AppCacheResponseIO {
+ public:
+ // Writes the http info to storage. Returns the number of bytes written
+ // or a net:: error code. ERR_IO_PENDING is returned if the
+ // operation could not be completed synchronously, in which case the writer
+ // acquires a reference to the provided 'info_buf' until completion at which
+ // time the callback is invoked with either a negative error code or the
+ // number of bytes written. The 'callback' is a required parameter. The
+ // contents of 'info_buf' are not modified.
+ // Should only be called where there is no Write operation in progress.
+ int WriteInfo(HttpResponseInfoIOBuffer* info_buf,
+ net::CompletionCallback* callback) {
+ DCHECK(info_buf && info_buf->http_info.get());
+ return -2;
+ }
+
+ // Writes data to storage. Returns the number of bytes written
+ // or a net:: error code. Guaranteed to not perform partial writes.
+ // ERR_IO_PENDING is returned if the operation could not be completed
+ // synchronously, in which case the writer acquires a reference to the
+ // provided 'buf' until completion at which time the callback is invoked
+ // with either a negative error code or the number of bytes written. The
+ // 'callback' is a required parameter. The contents of 'buf' are not
+ // modified.
+ // Should only be called where there is no Write operation in progress.
+ int WriteData(net::IOBuffer* buf, int buf_len,
+ net::CompletionCallback* callback) { return -2; }
+
+ // Returns true if there is a write pending.
+ bool IsWritePending() { return false; }
+
+ private:
+ friend class AppCacheStorageImpl;
+ friend class MockAppCacheStorage;
+
+ // Should only be constructed by the storage class.
+ explicit AppCacheResponseWriter(
+ int64 response_id, disk_cache::Backend* disk_cache)
+ : AppCacheResponseIO(response_id, disk_cache) {}
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_APPCACHE_RESPONSE_H_
+
diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc
index c36ad1e..f0c8784 100644
--- a/webkit/appcache/appcache_service.cc
+++ b/webkit/appcache/appcache_service.cc
@@ -5,30 +5,24 @@
#include "webkit/appcache/appcache_service.h"
#include "base/logging.h"
-#include "base/ref_counted.h"
-#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_backend_impl.h"
-#include "webkit/appcache/appcache_entry.h"
-#include "webkit/appcache/appcache_group.h"
+#include "webkit/appcache/appcache_storage_impl.h"
namespace appcache {
AppCacheService::AppCacheService()
- : last_cache_id_(0), last_group_id_(0),
- last_entry_id_(0), last_response_id_(0),
- request_context_(NULL) {
+ : request_context_(NULL) {
}
AppCacheService::~AppCacheService() {
DCHECK(backends_.empty());
- DCHECK(caches_.empty());
- DCHECK(groups_.empty());
}
void AppCacheService::Initialize(const FilePath& cache_directory) {
- // An empty cache directory indicates chrome incognito.
- cache_directory_ = cache_directory;
- // TODO(michaeln): load last_<foo>_ids from storage
+ DCHECK(!storage_.get());
+ AppCacheStorageImpl* storage = new AppCacheStorageImpl(this);
+ storage->Initialize(cache_directory);
+ storage_.reset(storage);
}
void AppCacheService::RegisterBackend(
@@ -43,61 +37,4 @@ void AppCacheService::UnregisterBackend(
backends_.erase(backend_impl->process_id());
}
-void AppCacheService::AddCache(AppCache* cache) {
- int64 cache_id = cache->cache_id();
- DCHECK(caches_.find(cache_id) == caches_.end());
- caches_.insert(CacheMap::value_type(cache_id, cache));
-}
-
-void AppCacheService::RemoveCache(AppCache* cache) {
- caches_.erase(cache->cache_id());
-}
-
-void AppCacheService::AddGroup(AppCacheGroup* group) {
- const GURL& url = group->manifest_url();
- DCHECK(groups_.find(url) == groups_.end());
- groups_.insert(GroupMap::value_type(url, group));
-}
-
-void AppCacheService::RemoveGroup(AppCacheGroup* group) {
- groups_.erase(group->manifest_url());
-
- // TODO(jennb): if group is obsolete, delete from storage.
-}
-
-void AppCacheService::LoadCache(int64 id, LoadClient* client) {
- // TODO(michaeln): actually retrieve from storage if needed
- client->CacheLoadedCallback(GetCache(id), id);
-}
-
-void AppCacheService::LoadOrCreateGroup(const GURL& manifest_url,
- LoadClient* client) {
- // TODO(michaeln): actually retrieve from storage
- scoped_refptr<AppCacheGroup> group = GetGroup(manifest_url);
- if (!group.get()) {
- group = new AppCacheGroup(this, manifest_url);
- DCHECK(GetGroup(manifest_url));
- }
- client->GroupLoadedCallback(group.get(), manifest_url);
-}
-
-void AppCacheService::CancelLoads(LoadClient* client) {
- // TODO(michaeln): remove client from loading lists
-}
-
-void AppCacheService::MarkAsForeignEntry(const GURL& entry_url,
- int64 cache_id) {
- // Update the in-memory cache.
- AppCache* cache = GetCache(cache_id);
- if (cache) {
- AppCacheEntry* entry = cache->GetEntry(entry_url);
- DCHECK(entry);
- if (entry)
- entry->add_types(AppCacheEntry::FOREIGN);
- }
-
- // TODO(michaeln): actually update in storage, and if this cache is
- // being loaded be sure to update the memory cache upon load completion.
-}
-
} // namespace appcache
diff --git a/webkit/appcache/appcache_service.h b/webkit/appcache/appcache_service.h
index 4dff28e..5cdaed4 100644
--- a/webkit/appcache/appcache_service.h
+++ b/webkit/appcache/appcache_service.h
@@ -5,40 +5,23 @@
#ifndef WEBKIT_APPCACHE_APPCACHE_SERVICE_H_
#define WEBKIT_APPCACHE_APPCACHE_SERVICE_H_
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/hash_tables.h"
#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "base/task.h"
-#include "googleurl/src/gurl.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+#include "webkit/appcache/appcache_storage.h"
class URLRequestContext;
namespace appcache {
-class AppCache;
class AppCacheBackendImpl;
-class AppCacheGroup;
// 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.
class AppCacheService {
public:
-
- class LoadClient {
- public:
- virtual ~LoadClient() {}
-
- // If a load fails the object pointer will be NULL.
- virtual void CacheLoadedCallback(AppCache* cache, int64 cache_id) = 0;
- virtual void GroupLoadedCallback(AppCacheGroup* group,
- const GURL& manifest_url) = 0;
- };
-
AppCacheService();
virtual ~AppCacheService();
@@ -56,71 +39,27 @@ class AppCacheService {
// Track which processes are using this appcache service.
void RegisterBackend(AppCacheBackendImpl* backend_impl);
void UnregisterBackend(AppCacheBackendImpl* backend_impl);
- AppCacheBackendImpl* GetBackend(int id) {
- BackendMap::iterator it = backends_.find(id);
+ AppCacheBackendImpl* GetBackend(int id) const {
+ BackendMap::const_iterator it = backends_.find(id);
return (it != backends_.end()) ? it->second : NULL;
}
- // Track what we have in our in-memory cache.
- void AddCache(AppCache* cache);
- void RemoveCache(AppCache* cache);
- void AddGroup(AppCacheGroup* group);
- void RemoveGroup(AppCacheGroup* group);
- AppCache* GetCache(int64 id) {
- CacheMap::iterator it = caches_.find(id);
- return (it != caches_.end()) ? it->second : NULL;
- }
- AppCacheGroup* GetGroup(const GURL& manifest_url) {
- GroupMap::iterator it = groups_.find(manifest_url);
- return (it != groups_.end()) ? it->second : NULL;
- }
+ AppCacheStorage* storage() const { return storage_.get(); }
- // Load caches and groups from storage. If the request object
- // is already in memory, the client is called immediately
- // without returning to the message loop.
- void LoadCache(int64 id, LoadClient* client);
- void LoadOrCreateGroup(const GURL& manifest_url,
- LoadClient* client);
-
- // Cancels pending callbacks for this client.
- void CancelLoads(LoadClient* client);
-
- // Updates in memory and persistent storage.
- void MarkAsForeignEntry(const GURL& entry_url, int64 cache_id);
-
- // The service generates unique storage ids for different object types.
- int64 NewCacheId() { return ++last_cache_id_; }
- int64 NewGroupId() { return ++last_group_id_; }
- int64 NewEntryId() { return ++last_entry_id_; }
- int64 NewResponseId() { return ++last_response_id_; }
-
- private:
- // In-memory representation of stored appcache data. Represents a subset
- // of the appcache database currently in use.
- typedef base::hash_map<int64, AppCache*> CacheMap;
- typedef std::map<GURL, AppCacheGroup*> GroupMap;
- CacheMap caches_;
- GroupMap groups_;
-
- // The last storage id used for different object types.
- int64 last_cache_id_;
- int64 last_group_id_;
- int64 last_entry_id_;
- int64 last_response_id_;
+ protected:
+ // Deals with persistence.
+ scoped_ptr<AppCacheStorage> storage_;
// Track current processes. One 'backend' per child process.
typedef std::map<int, AppCacheBackendImpl*> BackendMap;
BackendMap backends_;
- // Where we save our data.
- FilePath cache_directory_;
-
// Context for use during cache updates.
URLRequestContext* request_context_;
- // TODO(michaeln): cache and group loading book keeping.
- // TODO(michaeln): database and response storage
// TODO(jennb): service state: e.g. reached quota?
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheService);
};
} // namespace appcache
diff --git a/webkit/appcache/appcache_storage.h b/webkit/appcache/appcache_storage.h
new file mode 100644
index 0000000..47d1af8
--- /dev/null
+++ b/webkit/appcache/appcache_storage.h
@@ -0,0 +1,178 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_APPCACHE_STORAGE_H_
+#define WEBKIT_APPCACHE_APPCACHE_STORAGE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "webkit/appcache/appcache_working_set.h"
+
+class GURL;
+
+namespace appcache {
+
+class AppCache;
+class AppCacheGroup;
+class AppCacheResponseInfo;
+class AppCacheResponseReader;
+class AppCacheResponseWriter;
+class AppCacheService;
+
+class AppCacheStorage {
+ public:
+
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // If a load fails the 'cache' will be NULL.
+ virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) {}
+
+ // If a load fails the 'group' will be NULL.
+ virtual void OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) {}
+
+ // If successfully stored 'success' will be true.
+ virtual void OnGroupAndNewestCacheStored(
+ AppCacheGroup* group, bool success) {}
+
+ // If the update fails, success will be false.
+ virtual void OnGroupMarkedAsObsolete(GURL& manifest_url, bool success) {}
+
+ // If a load fails the 'response_info' will be NULL.
+ virtual void OnResponseInfoLoaded(
+ AppCacheResponseInfo* response_info, int64 response_id) {}
+
+ // If no response is found, response_id will be kNoResponseId.
+ // If a response is found, the cache id and manifest url of the
+ // containing cache and group are also returned.
+ virtual void OnMainResponseFound(
+ const GURL& url, int64 response_id, bool is_fallback,
+ int64 cache_id, const GURL& mainfest_url) {}
+ };
+
+ explicit AppCacheStorage(AppCacheService* service)
+ : last_cache_id_(kUnitializedId), last_group_id_(kUnitializedId),
+ last_entry_id_(kUnitializedId), last_response_id_(kUnitializedId),
+ service_(service) {}
+ virtual ~AppCacheStorage() {}
+
+ // 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
+ // to the message loop. If the load fails, the delegate will be called
+ // back with a NULL cache pointer.
+ virtual void LoadCache(int64 id, Delegate* delegate) = 0;
+
+ // Schedules a group and its newest cache, if any, to be loaded from storage.
+ // Upon load completion the delegate will be called back. If the group
+ // and newest cache already reside in memory, the delegate will be called
+ // back immediately without returning to the message loop. If the load fails,
+ // the delegate will be called back with a NULL group pointer.
+ virtual void LoadOrCreateGroup(
+ const GURL& manifest_url, Delegate* delegate) = 0;
+
+ // Schedules response info to be loaded from storage.
+ // Upon load completion the delegate will be called back. If the data
+ // already resides in memory, the delegate will be called back
+ // immediately without returning to the message loop. If the load fails,
+ // the delegate will be called back with a NULL pointer.
+ virtual void LoadResponseInfo(
+ const GURL& manifest_url, int64 response_id, Delegate* delegate) = 0;
+
+ // Schedules a group and its newest complete cache to be initially stored or
+ // incrementally updated with new changes. Upon completion the delegate
+ // will be called back. A group without a newest cache cannot be stored.
+ // It's a programming error to call this method with such a group. A
+ // side effect of storing a new newest cache is the removal of the group's
+ // old caches and responses from persistent storage (although they may still
+ // linger in the in-memory working set until no longer needed).
+ virtual void StoreGroupAndNewestCache(
+ AppCacheGroup* group, Delegate* delegate) = 0;
+
+ // Schedules a query to identify a response for a main request. Upon
+ // completion the delegate will be called back.
+ virtual void FindResponseForMainRequest(
+ const GURL& url, Delegate* delegate) = 0;
+
+ // Immediately updates in-memory storage, if the cache is in memory,
+ // and schedules a task to update persistent storage. If the cache is
+ // already scheduled to be loaded, upon loading completion the entry
+ // will be marked. There is no delegate completion callback.
+ virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) = 0;
+
+ // Schedules a task to update persistent storage and doom the group and all
+ // related caches and responses for deletion. Upon completion the in-memory
+ // instance is marked as obsolete and the delegate callback is called.
+ virtual void MarkGroupAsObsolete(
+ AppCacheGroup* group, Delegate* delegate) = 0;
+
+ // Cancels all pending callbacks for the delegate. The delegate callbacks
+ // will not be invoked after, however any scheduled operations will still
+ // take place. The callbacks for subsequently scheduled operations are
+ // unaffected.
+ virtual void CancelDelegateCallbacks(Delegate* delegate) = 0;
+
+ // Creates a reader to read a response from storage.
+ virtual AppCacheResponseReader* CreateResponseReader(
+ const GURL& manifest_url, int64 response_id) = 0;
+
+ // Creates a writer to write a new response to storage. This call
+ // establishes a new response id.
+ virtual AppCacheResponseWriter* CreateResponseWriter(
+ const GURL& manifest_url) = 0;
+
+ // Schedules the deletion of many responses.
+ virtual void DoomResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
+
+ // Generates unique storage ids for different object types.
+ int64 NewCacheId() {
+ DCHECK(last_cache_id_ != kUnitializedId);
+ return ++last_cache_id_;
+ }
+ int64 NewGroupId() {
+ DCHECK(last_group_id_ != kUnitializedId);
+ return ++last_group_id_;
+ }
+ int64 NewEntryId() {
+ DCHECK(last_entry_id_ != kUnitializedId);
+ return ++last_entry_id_;
+ }
+
+ // The working set of object instances currently in memory.
+ AppCacheWorkingSet* working_set() { return &working_set_; }
+
+ // Simple ptr back to the service object that owns us.
+ AppCacheService* service() { return service_; }
+
+ protected:
+ // Should only be called when creating a new response writer.
+ int64 NewResponseId() {
+ DCHECK(last_response_id_ != kUnitializedId);
+ return ++last_response_id_;
+ }
+
+ // The last storage id used for different object types.
+ int64 last_cache_id_;
+ int64 last_group_id_;
+ int64 last_entry_id_;
+ int64 last_response_id_;
+
+ AppCacheWorkingSet working_set_;
+ AppCacheService* service_;
+
+ // The set of last ids must be retrieved from storage prior to being used.
+ static const int64 kUnitializedId = -1;
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheStorage);
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_APPCACHE_STORAGE_H_
+
diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc
new file mode 100644
index 0000000..3fb8280
--- /dev/null
+++ b/webkit/appcache/appcache_storage_impl.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 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_storage_impl.h"
+
+namespace appcache {
+
+void AppCacheStorageImpl::Initialize(const FilePath& cache_directory) {
+ is_incognito_ = cache_directory.empty();
+ cache_directory_ = cache_directory;
+ // TODO(michaeln): retrieve last_ids from storage
+}
+
+} // namespace appcache
diff --git a/webkit/appcache/appcache_storage_impl.h b/webkit/appcache/appcache_storage_impl.h
new file mode 100644
index 0000000..ef75d1e
--- /dev/null
+++ b/webkit/appcache/appcache_storage_impl.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_APPCACHE_STORAGE_IMPL_H_
+#define WEBKIT_APPCACHE_APPCACHE_STORAGE_IMPL_H_
+
+#include "base/file_path.h"
+#include "webkit/appcache/mock_appcache_storage.h"
+
+namespace appcache {
+
+// TODO(michaeln): write me, for now we derive from 'mock' storage.
+class AppCacheStorageImpl : public MockAppCacheStorage {
+ public:
+ explicit AppCacheStorageImpl(AppCacheService* service)
+ : MockAppCacheStorage(service), is_incognito_(false) {}
+
+ void Initialize(const FilePath& cache_directory);
+
+ private:
+ bool is_incognito_;
+ FilePath cache_directory_;
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_APPCACHE_STORAGE_IMPL_H_
diff --git a/webkit/appcache/appcache_service_unittest.cc b/webkit/appcache/appcache_storage_unittest.cc
index d142e8b..f5f9e06 100644
--- a/webkit/appcache/appcache_service_unittest.cc
+++ b/webkit/appcache/appcache_storage_unittest.cc
@@ -5,32 +5,33 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_group.h"
-#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/appcache_storage.h"
+#include "webkit/appcache/mock_appcache_service.h"
namespace appcache {
-class AppCacheServiceTest : public testing::Test {
+class AppCacheStorageTest : public testing::Test {
};
-TEST(AppCacheServiceTest, AddRemoveCache) {
- AppCacheService service;
+TEST(AppCacheStorageTest, AddRemoveCache) {
+ MockAppCacheService service;
scoped_refptr<AppCache> cache = new AppCache(&service, 111);
- service.RemoveCache(cache);
+ service.storage()->working_set()->RemoveCache(cache);
// Removing non-existing cache from service should not fail.
- AppCacheService dummy;
- dummy.RemoveCache(cache);
+ MockAppCacheService dummy;
+ dummy.storage()->working_set()->RemoveCache(cache);
}
-TEST(AppCacheServiceTest, AddRemoveGroup) {
- AppCacheService service;
+TEST(AppCacheStorageTest, AddRemoveGroup) {
+ MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(&service, GURL::EmptyGURL());
- service.RemoveGroup(group);
+ service.storage()->working_set()->RemoveGroup(group);
// Removing non-existing group from service should not fail.
- AppCacheService dummy;
- dummy.RemoveGroup(group);
+ MockAppCacheService dummy;
+ dummy.storage()->working_set()->RemoveGroup(group);
}
} // namespace appcache
diff --git a/webkit/appcache/appcache_unittest.cc b/webkit/appcache/appcache_unittest.cc
index 3d33358..12f8b30 100644
--- a/webkit/appcache/appcache_unittest.cc
+++ b/webkit/appcache/appcache_unittest.cc
@@ -6,7 +6,7 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_frontend_impl.h"
#include "webkit/appcache/appcache_host.h"
-#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/mock_appcache_service.h"
namespace appcache {
@@ -14,23 +14,23 @@ class AppCacheTest : public testing::Test {
};
TEST(AppCacheTest, CleanupUnusedCache) {
- AppCacheService service;
+ MockAppCacheService service;
AppCacheFrontendImpl frontend;
- AppCache* cache = new AppCache(&service, 111);
+ scoped_refptr<AppCache> cache(new AppCache(&service, 111));
cache->set_complete(true);
AppCacheHost host1(1, &frontend, &service);
AppCacheHost host2(2, &frontend, &service);
- host1.AssociateCache(cache);
- host2.AssociateCache(cache);
+ host1.AssociateCache(cache.get());
+ host2.AssociateCache(cache.get());
host1.AssociateCache(NULL);
host2.AssociateCache(NULL);
}
TEST(AppCacheTest, AddModifyEntry) {
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCache> cache = new AppCache(&service, 111);
const GURL kUrl1("http://foo.com");
@@ -51,7 +51,7 @@ TEST(AppCacheTest, AddModifyEntry) {
}
TEST(AppCacheTest, InitializeWithManifest) {
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCache> cache = new AppCache(&service, 1234);
EXPECT_TRUE(cache->fallback_namespaces_.empty());
diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc
index 0834039..d9cf729 100644
--- a/webkit/appcache/appcache_update_job.cc
+++ b/webkit/appcache/appcache_update_job.cc
@@ -344,7 +344,8 @@ void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) {
// Proceed with update process. Section 6.9.4 steps 8-20.
internal_state_ = DOWNLOADING;
- inprogress_cache_ = new AppCache(service_, service_->NewCacheId());
+ inprogress_cache_ = new AppCache(service_,
+ service_->storage()->NewCacheId());
inprogress_cache_->set_owning_group(group_);
BuildUrlFileList(manifest);
inprogress_cache_->InitializeWithManifest(&manifest);
diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc
index 00fc819..5dd1536 100644
--- a/webkit/appcache/appcache_update_job_unittest.cc
+++ b/webkit/appcache/appcache_update_job_unittest.cc
@@ -11,8 +11,8 @@
#include "net/url_request/url_request_unittest.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
-#include "webkit/appcache/appcache_service.h"
#include "webkit/appcache/appcache_update_job.h"
+#include "webkit/appcache/mock_appcache_service.h"
namespace appcache {
class AppCacheUpdateJobTest;
@@ -617,7 +617,7 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
- AppCache* cache = MakeCacheForGroup(service_->NewCacheId());
+ AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId());
MockFrontend* frontend1 = MakeMockFrontend();
MockFrontend* frontend2 = MakeMockFrontend();
AppCacheHost* host1 = MakeHost(1, frontend1);
@@ -662,7 +662,7 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
- AppCache* cache = MakeCacheForGroup(service_->NewCacheId());
+ AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId());
MockFrontend* frontend1 = MakeMockFrontend();
MockFrontend* frontend2 = MakeMockFrontend();
AppCacheHost* host1 = MakeHost(1, frontend1);
@@ -738,7 +738,7 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
- AppCache* cache = MakeCacheForGroup(service_->NewCacheId());
+ AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId());
MockFrontend* frontend1 = MakeMockFrontend();
MockFrontend* frontend2 = MakeMockFrontend();
AppCacheHost* host1 = MakeHost(1, frontend1);
@@ -784,7 +784,7 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
- AppCache* cache = MakeCacheForGroup(service_->NewCacheId());
+ AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId());
MockFrontend* frontend1 = MakeMockFrontend();
MockFrontend* frontend2 = MakeMockFrontend();
AppCacheHost* host1 = MakeHost(1, frontend1);
@@ -858,7 +858,7 @@ class AppCacheUpdateJobTest : public testing::Test,
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
- AppCache* cache = MakeCacheForGroup(service_->NewCacheId());
+ AppCache* cache = MakeCacheForGroup(service_->storage()->NewCacheId());
MockFrontend* frontend1 = MakeMockFrontend();
MockFrontend* frontend2 = MakeMockFrontend();
AppCacheHost* host1 = MakeHost(1, frontend1);
@@ -1048,14 +1048,18 @@ class AppCacheUpdateJobTest : public testing::Test,
void OnUpdateComplete(AppCacheGroup* group) {
ASSERT_EQ(group_, group);
+ UpdateFinished();
+ }
- // Finish up outside of observer callback so that group can be deleted.
+ void UpdateFinished() {
+ // We unwind the stack prior to finishing up to let stack
+ // based objects get deleted.
MessageLoop::current()->PostTask(FROM_HERE,
method_factory_.NewRunnableMethod(
- &AppCacheUpdateJobTest::UpdateFinished));
+ &AppCacheUpdateJobTest::UpdateFinishedUnwound));
}
- void UpdateFinished() {
+ void UpdateFinishedUnwound() {
EXPECT_EQ(AppCacheGroup::IDLE, group_->update_status());
EXPECT_TRUE(group_->update_job() == NULL);
if (do_checks_after_update_finished_)
@@ -1073,7 +1077,7 @@ class AppCacheUpdateJobTest : public testing::Test,
}
void MakeService() {
- service_.reset(new AppCacheService());
+ service_.reset(new MockAppCacheService());
request_context_ = new TestURLRequestContext();
service_->set_request_context(request_context_);
}
@@ -1273,7 +1277,7 @@ class AppCacheUpdateJobTest : public testing::Test,
static scoped_refptr<HTTPTestServer> http_server_;
ScopedRunnableMethodFactory<AppCacheUpdateJobTest> method_factory_;
- scoped_ptr<AppCacheService> service_;
+ scoped_ptr<MockAppCacheService> service_;
scoped_refptr<TestURLRequestContext> request_context_;
scoped_refptr<AppCacheGroup> group_;
scoped_ptr<base::WaitableEvent> event_;
@@ -1301,7 +1305,7 @@ scoped_ptr<base::Thread> AppCacheUpdateJobTest::io_thread_;
scoped_refptr<HTTPTestServer> AppCacheUpdateJobTest::http_server_;
TEST_F(AppCacheUpdateJobTest, AlreadyChecking) {
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(&service, GURL("http://manifesturl.com"));
@@ -1328,7 +1332,7 @@ TEST_F(AppCacheUpdateJobTest, AlreadyChecking) {
}
TEST_F(AppCacheUpdateJobTest, AlreadyDownloading) {
- AppCacheService service;
+ MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(&service, GURL("http://manifesturl.com"));
diff --git a/webkit/appcache/appcache_working_set.cc b/webkit/appcache/appcache_working_set.cc
new file mode 100644
index 0000000..a5b544f
--- /dev/null
+++ b/webkit/appcache/appcache_working_set.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2009 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_working_set.h"
+
+#include "base/logging.h"
+#include "webkit/appcache/appcache.h"
+#include "webkit/appcache/appcache_group.h"
+
+namespace appcache {
+
+AppCacheWorkingSet::~AppCacheWorkingSet() {
+ DCHECK(caches_.empty());
+ DCHECK(groups_.empty());
+}
+
+void AppCacheWorkingSet::AddCache(AppCache* cache) {
+ int64 cache_id = cache->cache_id();
+ DCHECK(caches_.find(cache_id) == caches_.end());
+ caches_.insert(CacheMap::value_type(cache_id, cache));
+}
+
+void AppCacheWorkingSet::RemoveCache(AppCache* cache) {
+ caches_.erase(cache->cache_id());
+}
+
+void AppCacheWorkingSet::AddGroup(AppCacheGroup* group) {
+ const GURL& url = group->manifest_url();
+ DCHECK(groups_.find(url) == groups_.end());
+ groups_.insert(GroupMap::value_type(url, group));
+}
+
+void AppCacheWorkingSet::RemoveGroup(AppCacheGroup* group) {
+ groups_.erase(group->manifest_url());
+}
+
+} // namespace
diff --git a/webkit/appcache/appcache_working_set.h b/webkit/appcache/appcache_working_set.h
new file mode 100644
index 0000000..6785d50
--- /dev/null
+++ b/webkit/appcache/appcache_working_set.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_APPCACHE_WORKING_SET_H_
+#define WEBKIT_APPCACHE_APPCACHE_WORKING_SET_H_
+
+#include <map>
+
+#include "base/hash_tables.h"
+#include "googleurl/src/gurl.h"
+
+namespace appcache {
+
+class AppCache;
+class AppCacheGroup;
+class AppCacheResponseInfo;
+
+// Represents the working set of appcache object instances
+// currently in memory.
+class AppCacheWorkingSet {
+ public:
+ ~AppCacheWorkingSet();
+
+ void AddCache(AppCache* cache);
+ void RemoveCache(AppCache* cache);
+ AppCache* GetCache(int64 id) {
+ CacheMap::iterator it = caches_.find(id);
+ return (it != caches_.end()) ? it->second : NULL;
+ }
+
+ void AddGroup(AppCacheGroup* group);
+ void RemoveGroup(AppCacheGroup* group);
+ AppCacheGroup* GetGroup(const GURL& manifest_url) {
+ GroupMap::iterator it = groups_.find(manifest_url);
+ return (it != groups_.end()) ? it->second : NULL;
+ }
+
+ void AddResponseInfo(AppCacheResponseInfo* response_info);
+ void RemoveResponseInfo(AppCacheResponseInfo* response_info);
+ AppCacheResponseInfo* GetResponseInfo(int64 id) {
+ ResponseInfoMap::iterator it = response_infos_.find(id);
+ return (it != response_infos_.end()) ? it->second : NULL;
+ }
+
+ private:
+ typedef base::hash_map<int64, AppCache*> CacheMap;
+ typedef std::map<GURL, AppCacheGroup*> GroupMap;
+ typedef base::hash_map<int64, AppCacheResponseInfo*> ResponseInfoMap;
+ CacheMap caches_;
+ GroupMap groups_;
+ ResponseInfoMap response_infos_;
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_APPCACHE_WORKING_SET_H_
diff --git a/webkit/appcache/mock_appcache_service.h b/webkit/appcache/mock_appcache_service.h
new file mode 100644
index 0000000..705dc0e
--- /dev/null
+++ b/webkit/appcache/mock_appcache_service.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_MOCK_APPCACHE_SERVICE_H_
+#define WEBKIT_APPCACHE_MOCK_APPCACHE_SERVICE_H_
+
+#include "base/compiler_specific.h"
+#include "webkit/appcache/appcache_service.h"
+#include "webkit/appcache/mock_appcache_storage.h"
+
+namespace appcache {
+
+// For use by unit tests.
+class MockAppCacheService : public AppCacheService {
+ public:
+ MockAppCacheService() {
+ storage_.reset(new MockAppCacheStorage(this));
+ }
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_MOCK_APPCACHE_SERVICE_H_
diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc
new file mode 100644
index 0000000..4dfb8c9
--- /dev/null
+++ b/webkit/appcache/mock_appcache_storage.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 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/mock_appcache_storage.h"
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "webkit/appcache/appcache.h"
+#include "webkit/appcache/appcache_backend_impl.h"
+#include "webkit/appcache/appcache_entry.h"
+#include "webkit/appcache/appcache_group.h"
+#include "webkit/appcache/appcache_response.h"
+
+namespace appcache {
+
+MockAppCacheStorage::MockAppCacheStorage(AppCacheService* service)
+ : AppCacheStorage(service) {
+ last_cache_id_ = 0;
+ last_entry_id_ = 0;
+ last_group_id_ = 0;
+ last_response_id_ = 0;
+}
+
+void MockAppCacheStorage::LoadCache(int64 id, Delegate* delegate) {
+ AppCache* cache = working_set_.GetCache(id);
+ delegate->OnCacheLoaded(cache, id);
+}
+
+void MockAppCacheStorage::LoadOrCreateGroup(
+ const GURL& manifest_url, Delegate* delegate) {
+ scoped_refptr<AppCacheGroup> group = working_set_.GetGroup(manifest_url);
+ if (!group.get()) {
+ group = new AppCacheGroup(service_, manifest_url);
+ DCHECK(working_set_.GetGroup(manifest_url));
+ }
+ delegate->OnGroupLoaded(group.get(), manifest_url);
+}
+
+void MockAppCacheStorage::LoadResponseInfo(
+ const GURL& manifest_url, int64 id, Delegate* delegate) {
+ delegate->OnResponseInfoLoaded(working_set_.GetResponseInfo(id), id);
+}
+
+void MockAppCacheStorage::StoreGroupAndNewestCache(
+ AppCacheGroup* group, Delegate* delegate) {
+ // TODO(michaeln): write me
+ delegate->OnGroupAndNewestCacheStored(group, false);
+}
+
+void MockAppCacheStorage::FindResponseForMainRequest(
+ const GURL& url, Delegate* delegate) {
+ // TODO(michaeln): write me
+ delegate->OnMainResponseFound(
+ url, kNoResponseId, false, kNoCacheId, GURL::EmptyGURL());
+}
+
+void MockAppCacheStorage::MarkEntryAsForeign(
+ const GURL& entry_url, int64 cache_id) {
+ // Update the working set.
+ AppCache* cache = working_set_.GetCache(cache_id);
+ if (cache) {
+ AppCacheEntry* entry = cache->GetEntry(entry_url);
+ DCHECK(entry);
+ if (entry)
+ entry->add_types(AppCacheEntry::FOREIGN);
+ }
+ // TODO(michaeln): actually update in storage, and if this cache is
+ // being loaded be sure to update the memory cache upon load completion.
+}
+
+void MockAppCacheStorage::MarkGroupAsObsolete(
+ AppCacheGroup* group, Delegate* delegate) {
+ // TODO(michaeln): write me
+}
+
+void MockAppCacheStorage::CancelDelegateCallbacks(Delegate* delegate) {
+ // TODO(michaeln): remove delegate from callback list
+}
+
+AppCacheResponseReader* MockAppCacheStorage::CreateResponseReader(
+ const GURL& origin, int64 response_id) {
+ return new AppCacheResponseReader(response_id, NULL);
+ // TODO(michaeln): use a disk_cache
+}
+
+AppCacheResponseWriter* MockAppCacheStorage::CreateResponseWriter(
+ const GURL& manifest_url) {
+ return new AppCacheResponseWriter(NewResponseId(), NULL);
+ // TODO(michaeln): use a disk_cache
+}
+
+void MockAppCacheStorage::DoomResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) {
+ // TODO(michaeln): write me
+}
+
+} // namespace appcache
diff --git a/webkit/appcache/mock_appcache_storage.h b/webkit/appcache/mock_appcache_storage.h
new file mode 100644
index 0000000..95cc082
--- /dev/null
+++ b/webkit/appcache/mock_appcache_storage.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_APPCACHE_MOCK_APPCACHE_STORAGE_H_
+#define WEBKIT_APPCACHE_MOCK_APPCACHE_STORAGE_H_
+
+#include "webkit/appcache/appcache_storage.h"
+
+namespace appcache {
+
+// For use in unit tests.
+// Note: This class is also being used to bootstrap our development efforts.
+// We can get layout tests up and running, and back fill with real storage
+// somewhat in parallel.
+class MockAppCacheStorage : public AppCacheStorage {
+ public:
+ explicit MockAppCacheStorage(AppCacheService* service);
+ virtual void LoadCache(int64 id, Delegate* delegate);
+ virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate);
+ virtual void LoadResponseInfo(
+ const GURL& manifest_url, int64 response_id, Delegate* delegate);
+ virtual void StoreGroupAndNewestCache(
+ AppCacheGroup* group, Delegate* delegate);
+ virtual void FindResponseForMainRequest(const GURL& url, Delegate* delegate);
+ virtual void CancelDelegateCallbacks(Delegate* delegate);
+ virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id);
+ virtual void MarkGroupAsObsolete(AppCacheGroup* group, Delegate* delegate);
+ virtual AppCacheResponseReader* CreateResponseReader(
+ const GURL& manifest_url, int64 response_id);
+ virtual AppCacheResponseWriter* CreateResponseWriter(const GURL& origin);
+ virtual void DoomResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids);
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_MOCK_APPCACHE_STORAGE_H_