summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 02:10:27 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-12 02:10:27 +0000
commit2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6 (patch)
tree42b0e45b16affe458cc051c7bdd282e2e43546cf /webkit/appcache
parentd32e75740a892b8578c825b9b5fb850ee5f41269 (diff)
downloadchromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.zip
chromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.tar.gz
chromium_src-2bfc5c14f395ef247a5980e1a6dcc0f26893f2d6.tar.bz2
Lookup appcached responses given a request URL.
TEST=new cases in mock_appcache_storage_unittest.cc and appcache_unittest.cc BUG=none Review URL: http://codereview.chromium.org/372070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31757 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r--webkit/appcache/appcache.cc66
-rw-r--r--webkit/appcache/appcache.h11
-rw-r--r--webkit/appcache/appcache_unittest.cc117
-rw-r--r--webkit/appcache/mock_appcache_storage.cc152
-rw-r--r--webkit/appcache/mock_appcache_storage.h12
-rw-r--r--webkit/appcache/mock_appcache_storage_unittest.cc208
6 files changed, 538 insertions, 28 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc
index 41c3f54..6a943c8b 100644
--- a/webkit/appcache/appcache.cc
+++ b/webkit/appcache/appcache.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
+
#include "webkit/appcache/appcache.h"
#include "base/logging.h"
+#include "base/string_util.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_interfaces.h"
@@ -55,11 +58,74 @@ AppCacheEntry* AppCache::GetEntry(const GURL& url) {
return (it != entries_.end()) ? &(it->second) : NULL;
}
+namespace {
+
+bool SortByLength(
+ const FallbackNamespace& lhs, const FallbackNamespace& rhs) {
+ return lhs.first.spec().length() > rhs.first.spec().length();
+}
+
+}
+
void AppCache::InitializeWithManifest(Manifest* manifest) {
DCHECK(manifest);
fallback_namespaces_.swap(manifest->fallback_namespaces);
online_whitelist_namespaces_.swap(manifest->online_whitelist_namespaces);
online_whitelist_all_ = manifest->online_whitelist_all;
+
+ // Sort the fallback namespaces by url string length, longest to shortest,
+ // since longer matches trump when matching a url to a namespace.
+ std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(),
+ SortByLength);
+}
+
+bool AppCache::FindResponseForRequest(const GURL& url,
+ AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
+ GURL* found_fallback_namespace, bool* found_network_namespace) {
+ AppCacheEntry* entry = GetEntry(url);
+ if (entry) {
+ *found_entry = *entry;
+ return true;
+ }
+
+ FallbackNamespace* fallback_namespace = FindFallbackNamespace(url);
+ if (fallback_namespace) {
+ entry = GetEntry(fallback_namespace->second);
+ DCHECK(entry);
+ *found_fallback_entry = *entry;
+ *found_fallback_namespace = fallback_namespace->first;
+ return true;
+ }
+
+ *found_network_namespace = IsInNetworkNamespace(url);
+ return *found_network_namespace;
+}
+
+FallbackNamespace* AppCache::FindFallbackNamespace(const GURL& url) {
+ size_t count = fallback_namespaces_.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (StartsWithASCII(
+ url.spec(), fallback_namespaces_[i].first.spec(), true)) {
+ return &fallback_namespaces_[i];
+ }
+ }
+ return NULL;
+}
+
+bool AppCache::IsInNetworkNamespace(const GURL& url) {
+ if (online_whitelist_all_)
+ return true;
+
+ // TODO(michaeln): There are certainly better 'prefix matching'
+ // structures and algorithms that can be applied here and above.
+ size_t count = online_whitelist_namespaces_.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (StartsWithASCII(
+ url.spec(), online_whitelist_namespaces_[i].spec(), true)) {
+ return true;
+ }
+ }
+ return false;
}
} // namespace appcache
diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h
index b601fcc..6e43a85 100644
--- a/webkit/appcache/appcache.h
+++ b/webkit/appcache/appcache.h
@@ -75,11 +75,10 @@ class AppCache : public base::RefCounted<AppCache> {
// Do not use the manifest after this call.
void InitializeWithManifest(Manifest* manifest);
- void FindResponseForRequest(const GURL& url,
+ bool FindResponseForRequest(const GURL& url,
AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
- bool* found_network_namespace) {
- return; // TODO(michaeln): write me
- }
+ GURL* found_fallback_namespace, bool* found_network_namespace);
+
private:
friend class AppCacheGroup;
friend class AppCacheHost;
@@ -91,6 +90,10 @@ class AppCache : public base::RefCounted<AppCache> {
// Use AppCacheGroup::Add/RemoveCache() to manipulate owning group.
void set_owning_group(AppCacheGroup* group) { owning_group_ = group; }
+ // FindResponseForRequest helpers
+ FallbackNamespace* FindFallbackNamespace(const GURL& url);
+ bool IsInNetworkNamespace(const GURL& url);
+
// Use AppCacheHost::AssociateCache() to manipulate host association.
void AssociateHost(AppCacheHost* host) {
associated_hosts_.insert(host);
diff --git a/webkit/appcache/appcache_unittest.cc b/webkit/appcache/appcache_unittest.cc
index d188550..5f95f9d 100644
--- a/webkit/appcache/appcache_unittest.cc
+++ b/webkit/appcache/appcache_unittest.cc
@@ -90,5 +90,122 @@ TEST(AppCacheTest, InitializeWithManifest) {
EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
}
+TEST(AppCacheTest, FindResponseForRequest) {
+ MockAppCacheService service;
+
+ const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
+ const GURL kFallbackEntryUrl1("http://blah/fallback_entry1");
+ const GURL kFallbackNamespaceUrl1("http://blah/fallback_namespace/");
+ const GURL kFallbackEntryUrl2("http://blah/fallback_entry2");
+ const GURL kFallbackNamespaceUrl2("http://blah/fallback_namespace/longer");
+ const GURL kManifestUrl("http://blah/manifest");
+ const GURL kForeignExplicitEntryUrl("http://blah/foreign");
+ const GURL kInOnlineNamespaceUrl(
+ "http://blah/online_namespace/network");
+ const GURL kExplicitInOnlineNamespaceUrl(
+ "http://blah/online_namespace/explicit");
+ const GURL kFallbackTestUrl1("http://blah/fallback_namespace/1");
+ const GURL kFallbackTestUrl2("http://blah/fallback_namespace/longer2");
+
+ const int64 kFallbackResponseId1 = 1;
+ const int64 kFallbackResponseId2 = 2;
+ const int64 kManifestResponseId = 3;
+ const int64 kForeignExplicitResponseId = 4;
+ const int64 kExplicitInOnlineNamespaceResponseId = 5;
+
+ Manifest manifest;
+ manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl);
+ manifest.fallback_namespaces.push_back(
+ FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1));
+ manifest.fallback_namespaces.push_back(
+ FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2));
+
+ // Create a cache with some namespaces and entries.
+ scoped_refptr<AppCache> cache = new AppCache(&service, 1234);
+ cache->InitializeWithManifest(&manifest);
+ cache->AddEntry(
+ kFallbackEntryUrl1,
+ AppCacheEntry(AppCacheEntry::FALLBACK, kFallbackResponseId1));
+ cache->AddEntry(
+ kFallbackEntryUrl2,
+ AppCacheEntry(AppCacheEntry::FALLBACK, kFallbackResponseId2));
+ cache->AddEntry(
+ kManifestUrl,
+ AppCacheEntry(AppCacheEntry::MANIFEST, kManifestResponseId));
+ cache->AddEntry(
+ kForeignExplicitEntryUrl,
+ AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
+ kForeignExplicitResponseId));
+ cache->AddEntry(
+ kExplicitInOnlineNamespaceUrl,
+ AppCacheEntry(AppCacheEntry::EXPLICIT,
+ kExplicitInOnlineNamespaceResponseId));
+ cache->set_complete(true);
+
+ // See that we get expected results from FindResponseForRequest
+
+ bool found = false;
+ AppCacheEntry entry;
+ AppCacheEntry fallback_entry;
+ GURL fallback_namespace;
+ bool network_namespace = false;
+
+ found = cache->FindResponseForRequest(GURL("http://blah/miss"),
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(kForeignExplicitEntryUrl,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_EQ(kForeignExplicitResponseId, entry.response_id());
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_FALSE(network_namespace);
+
+ entry = AppCacheEntry(); // reset
+
+ found = cache->FindResponseForRequest(kManifestUrl,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_EQ(kManifestResponseId, entry.response_id());
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_FALSE(network_namespace);
+
+ entry = AppCacheEntry(); // reset
+
+ found = cache->FindResponseForRequest(kInOnlineNamespaceUrl,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_TRUE(network_namespace);
+
+ network_namespace = false; // reset
+
+ found = cache->FindResponseForRequest(kExplicitInOnlineNamespaceUrl,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_EQ(kExplicitInOnlineNamespaceResponseId, entry.response_id());
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_FALSE(network_namespace);
+
+ entry = AppCacheEntry(); // reset
+
+ found = cache->FindResponseForRequest(kFallbackTestUrl1,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_EQ(kFallbackResponseId1, fallback_entry.response_id());
+ EXPECT_FALSE(network_namespace);
+
+ fallback_entry = AppCacheEntry(); // reset
+
+ found = cache->FindResponseForRequest(kFallbackTestUrl2,
+ &entry, &fallback_entry, &fallback_namespace, &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_EQ(kFallbackResponseId2, fallback_entry.response_id());
+ EXPECT_FALSE(network_namespace);
+}
+
} // namespace appacache
diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc
index 919e5f1..bc4a385 100644
--- a/webkit/appcache/mock_appcache_storage.cc
+++ b/webkit/appcache/mock_appcache_storage.cc
@@ -106,8 +106,10 @@ void MockAppCacheStorage::FindResponseForSubRequest(
return;
}
- cache->FindResponseForRequest(url, found_entry, found_fallback_entry,
- found_network_namespace);
+ GURL fallback_namespace_not_used;
+ cache->FindResponseForRequest(
+ url, found_entry, found_fallback_entry,
+ &fallback_namespace_not_used, found_network_namespace);
}
void MockAppCacheStorage::MarkEntryAsForeign(
@@ -205,32 +207,140 @@ void MockAppCacheStorage::ProcessStoreGroupAndNewestCache(
// DoomResponses(group->manifest_url(), doomed_responses_);
}
+namespace {
+
+struct FoundCandidate {
+ AppCacheEntry entry;
+ int64 cache_id;
+ GURL manifest_url;
+ bool is_cache_in_use;
+
+ FoundCandidate() : cache_id(kNoCacheId), is_cache_in_use(false) {}
+};
+
+} // namespace
+
void MockAppCacheStorage::ProcessFindResponseForMainRequest(
const GURL& url, scoped_refptr<DelegateReference> delegate_ref) {
- // TODO(michaeln): write me when doing AppCacheRequestHandler
- // foreach(stored_group) {
- // if (group->manifest_url()->origin() != url.GetOrigin())
- // continue;
- // look for an entry
- // look for a fallback namespace
- // look for a online namespace
- // }
- AppCacheEntry found_entry;
- AppCacheEntry found_fallback_entry;
- int64 found_cache_id = kNoCacheId;
- GURL found_manifest_url = GURL();
if (simulate_find_main_resource_) {
- found_entry = simulated_found_entry_;
- found_fallback_entry = simulated_found_fallback_entry_;
- found_cache_id = simulated_found_cache_id_;
- found_manifest_url = simulated_found_manifest_url_;
simulate_find_main_resource_ = false;
+ if (delegate_ref->delegate) {
+ delegate_ref->delegate->OnMainResponseFound(
+ url, simulated_found_entry_, simulated_found_fallback_entry_,
+ simulated_found_cache_id_, simulated_found_manifest_url_);
+ }
+ return;
+ }
+
+ // This call has no persistent side effects, if the delegate has gone
+ // away, we can just bail out early.
+ if (!delegate_ref->delegate)
+ return;
+
+ // TODO(michaeln): The heuristics around choosing amoungst
+ // multiple candidates is under specified, and just plain
+ // not fully understood. Refine these over time. In particular,
+ // * prefer candidates from newer caches
+ // * take into account the cache associated with the document
+ // that initiated the navigation
+ // * take into account the cache associated with the document
+ // currently residing in the frame being navigated
+ FoundCandidate found_candidate;
+ FoundCandidate found_fallback_candidate;
+ GURL found_fallback_candidate_namespace;
+
+ for (StoredGroupMap::const_iterator it = stored_groups_.begin();
+ it != stored_groups_.end(); ++it) {
+ AppCacheGroup* group = it->second.get();
+ AppCache* cache = group->newest_complete_cache();
+ if (group->is_obsolete() || !cache ||
+ (url.GetOrigin() != group->manifest_url().GetOrigin())) {
+ continue;
+ }
+
+ AppCacheEntry found_entry;
+ AppCacheEntry found_fallback_entry;
+ GURL found_fallback_namespace;
+ bool ignore_found_network_namespace = false;
+ bool found = cache->FindResponseForRequest(
+ url, &found_entry, &found_fallback_entry,
+ &found_fallback_namespace,
+ &ignore_found_network_namespace);
+
+ // 6.11.1 Navigating across documents, Step 10.
+ // Network namespacing doesn't apply to main resource loads,
+ // and foreign entries are excluded.
+ if (!found || ignore_found_network_namespace ||
+ (found_entry.has_response_id() && found_entry.IsForeign()) ||
+ (found_fallback_entry.has_response_id() &&
+ found_fallback_entry.IsForeign())) {
+ continue;
+ }
+
+ // We have a bias for hits from caches that are in use.
+ bool is_in_use = IsCacheStored(cache) && !cache->HasOneRef();
+
+ if (found_entry.has_response_id()) {
+ found_candidate.entry = found_entry;
+ found_candidate.cache_id = cache->cache_id();
+ found_candidate.manifest_url = group->manifest_url();
+ found_candidate.is_cache_in_use = is_in_use;
+ if (is_in_use)
+ break; // We break out of the loop with this direct hit.
+ } else {
+ DCHECK(found_fallback_entry.has_response_id());
+
+ bool take_new_candidate = true;
+
+ // Does the newly found entry trump our current candidate?
+ if (found_fallback_candidate.entry.has_response_id()) {
+ // Longer namespace prefix matches win.
+ size_t found_length =
+ found_fallback_namespace.spec().length();
+ size_t candidate_length =
+ found_fallback_candidate_namespace.spec().length();
+
+ if (found_length > candidate_length) {
+ take_new_candidate = true;
+ } else if (found_length == candidate_length &&
+ is_in_use && !found_fallback_candidate.is_cache_in_use) {
+ take_new_candidate = true;
+ } else {
+ take_new_candidate = false;
+ }
+ }
+
+ if (take_new_candidate) {
+ found_fallback_candidate.entry = found_fallback_entry;
+ found_fallback_candidate.cache_id = cache->cache_id();
+ found_fallback_candidate.manifest_url = group->manifest_url();
+ found_fallback_candidate.is_cache_in_use = is_in_use;
+ found_fallback_candidate_namespace = found_fallback_namespace;
+ }
+ }
+ }
+
+ // Found a direct hit.
+ if (found_candidate.entry.has_response_id()) {
+ delegate_ref->delegate->OnMainResponseFound(
+ url, found_candidate.entry, AppCacheEntry(),
+ found_candidate.cache_id, found_candidate.manifest_url);
+ return;
}
- if (delegate_ref->delegate) {
+
+ // Found a fallback namespace.
+ if (found_fallback_candidate.entry.has_response_id()) {
delegate_ref->delegate->OnMainResponseFound(
- url, found_entry, found_fallback_entry,
- found_cache_id, found_manifest_url);
+ url, AppCacheEntry(), found_fallback_candidate.entry,
+ found_fallback_candidate.cache_id,
+ found_fallback_candidate.manifest_url);
+ return;
}
+
+ // Didn't find anything.
+ delegate_ref->delegate->OnMainResponseFound(
+ url, AppCacheEntry(), AppCacheEntry(),
+ kNoCacheId, GURL::EmptyGURL());
}
void MockAppCacheStorage::ProcessMakeGroupObsolete(
diff --git a/webkit/appcache/mock_appcache_storage.h b/webkit/appcache/mock_appcache_storage.h
index 9f352bd..bf70fc6 100644
--- a/webkit/appcache/mock_appcache_storage.h
+++ b/webkit/appcache/mock_appcache_storage.h
@@ -97,7 +97,8 @@ class MockAppCacheStorage : public AppCacheStorage {
return disk_cache_.get();
}
- // Simulate failures for testing.
+ // Simulate failures for testing. Once set all subsequent calls
+ // to MakeGroupObsolete or StorageGroupAndNewestCache will fail.
void SimulateMakeGroupObsoleteFailure() {
simulate_make_group_obsolete_failure_ = true;
}
@@ -105,7 +106,10 @@ class MockAppCacheStorage : public AppCacheStorage {
simulate_store_group_and_newest_cache_failure_ = true;
}
- // Simulate FindResponseFor results for testing.
+ // Simulate FindResponseFor results for testing. These
+ // provided values will be return on the next call to
+ // the corresponding Find method, subsequent calls are
+ // unaffected.
void SimulateFindMainResource(
const AppCacheEntry& entry,
const AppCacheEntry& fallback_entry,
@@ -149,7 +153,11 @@ class MockAppCacheStorage : public AppCacheStorage {
GURL simulated_found_manifest_url_;
bool simulated_found_network_namespace_;
+ FRIEND_TEST(MockAppCacheStorageTest, BasicFindMainResponse);
+ FRIEND_TEST(MockAppCacheStorageTest, BasicFindMainFallbackResponse);
FRIEND_TEST(MockAppCacheStorageTest, CreateGroup);
+ FRIEND_TEST(MockAppCacheStorageTest, FindMainResponseExclusions);
+ FRIEND_TEST(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates);
FRIEND_TEST(MockAppCacheStorageTest, LoadCache_FarHit);
FRIEND_TEST(MockAppCacheStorageTest, LoadGroupAndCache_FarHit);
FRIEND_TEST(MockAppCacheStorageTest, MakeGroupObsolete);
diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc
index 404df50..39fc445 100644
--- a/webkit/appcache/mock_appcache_storage_unittest.cc
+++ b/webkit/appcache/mock_appcache_storage_unittest.cc
@@ -323,7 +323,7 @@ TEST_F(MockAppCacheStorageTest, MarkEntryAsForeign) {
reinterpret_cast<MockAppCacheStorage*>(service.storage());
// Setup some preconditions. Create a cache with an entry.
- GURL entry_url("http://blan/entry");
+ GURL entry_url("http://blah/entry");
int64 cache_id = storage->NewCacheId();
scoped_refptr<AppCache> cache = new AppCache(&service, cache_id);
cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::EXPLICIT));
@@ -358,5 +358,211 @@ TEST_F(MockAppCacheStorageTest, FindNoMainResponse) {
EXPECT_EQ(0, delegate.found_fallback_entry_.types());
}
+TEST_F(MockAppCacheStorageTest, BasicFindMainResponse) {
+ // Should complete asyncly.
+ MockAppCacheService service;
+ MockAppCacheStorage* storage =
+ reinterpret_cast<MockAppCacheStorage*>(service.storage());
+
+ // Setup some preconditions. Create a complete cache with an entry.
+ const int64 kCacheId = storage->NewCacheId();
+ const GURL kEntryUrl("http://blah/entry");
+ const GURL kManifestUrl("http://blah/manifest");
+ const int64 kResponseId = 1;
+ scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId);
+ cache->AddEntry(
+ kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId));
+ cache->set_complete(true);
+ scoped_refptr<AppCacheGroup> group =
+ new AppCacheGroup(&service, kManifestUrl);
+ group->AddCache(cache);
+ storage->AddStoredGroup(group);
+ storage->AddStoredCache(cache);
+
+ // Conduct the test.
+ MockStorageDelegate delegate;
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ storage->FindResponseForMainRequest(kEntryUrl, &delegate);
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ MessageLoop::current()->RunAllPending(); // Do async task execution.
+ EXPECT_EQ(kEntryUrl, delegate.found_url_);
+ EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
+ EXPECT_EQ(kCacheId, delegate.found_cache_id_);
+ EXPECT_EQ(kResponseId, delegate.found_entry_.response_id());
+ EXPECT_TRUE(delegate.found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
+}
+
+TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) {
+ // Should complete asyncly.
+ MockAppCacheService service;
+ MockAppCacheStorage* storage =
+ reinterpret_cast<MockAppCacheStorage*>(service.storage());
+
+ // Setup some preconditions. Create a complete cache with a
+ // fallback namespace and entry.
+ const int64 kCacheId = storage->NewCacheId();
+ const GURL kFallbackEntryUrl1("http://blah/fallback_entry1");
+ const GURL kFallbackNamespaceUrl1("http://blah/fallback_namespace/");
+ const GURL kFallbackEntryUrl2("http://blah/fallback_entry2");
+ const GURL kFallbackNamespaceUrl2("http://blah/fallback_namespace/longer");
+ const GURL kManifestUrl("http://blah/manifest");
+ const int64 kResponseId1 = 1;
+ const int64 kResponseId2 = 2;
+
+ Manifest manifest;
+ manifest.fallback_namespaces.push_back(
+ FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1));
+ manifest.fallback_namespaces.push_back(
+ FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2));
+
+ scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId);
+ cache->InitializeWithManifest(&manifest);
+ cache->AddEntry(
+ kFallbackEntryUrl1, AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId1));
+ cache->AddEntry(
+ kFallbackEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId2));
+ cache->set_complete(true);
+
+ scoped_refptr<AppCacheGroup> group =
+ new AppCacheGroup(&service, kManifestUrl);
+ group->AddCache(cache);
+ storage->AddStoredGroup(group);
+ storage->AddStoredCache(cache);
+
+ // The test url is in both fallback namespace urls, but should match
+ // the longer of the two.
+ const GURL kTestUrl("http://blah/fallback_namespace/longer/test");
+
+ // Conduct the test.
+ MockStorageDelegate delegate;
+ EXPECT_NE(kTestUrl, delegate.found_url_);
+ storage->FindResponseForMainRequest(kTestUrl, &delegate);
+ EXPECT_NE(kTestUrl, delegate.found_url_);
+ MessageLoop::current()->RunAllPending(); // Do async task execution.
+ EXPECT_EQ(kTestUrl, delegate.found_url_);
+ EXPECT_EQ(kManifestUrl, delegate.found_manifest_url_);
+ EXPECT_EQ(kCacheId, delegate.found_cache_id_);
+ EXPECT_FALSE(delegate.found_entry_.has_response_id());
+ EXPECT_EQ(kResponseId2, delegate.found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate.found_fallback_entry_.IsFallback());
+}
+
+TEST_F(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates) {
+ // Should complete asyncly.
+ MockAppCacheService service;
+ MockAppCacheStorage* storage =
+ reinterpret_cast<MockAppCacheStorage*>(service.storage());
+
+ // Setup some preconditions. Create 2 complete caches with an entry
+ // for the same url.
+
+ const GURL kEntryUrl("http://blah/entry");
+ const int64 kCacheId1 = storage->NewCacheId();
+ const int64 kCacheId2 = storage->NewCacheId();
+ const GURL kManifestUrl1("http://blah/manifest1");
+ const GURL kManifestUrl2("http://blah/manifest2");
+ const int64 kResponseId1 = 1;
+ const int64 kResponseId2 = 2;
+
+ // The first cache.
+ scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId1);
+ cache->AddEntry(
+ kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId1));
+ cache->set_complete(true);
+ scoped_refptr<AppCacheGroup> group =
+ new AppCacheGroup(&service, kManifestUrl1);
+ group->AddCache(cache);
+ storage->AddStoredGroup(group);
+ storage->AddStoredCache(cache);
+ // Drop our references to cache1 so it appears as "not in use".
+ cache = NULL;
+ group = NULL;
+
+ // The second cache.
+ cache = new AppCache(&service, kCacheId2);
+ cache->AddEntry(
+ kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kResponseId2));
+ cache->set_complete(true);
+ group = new AppCacheGroup(&service, kManifestUrl2);
+ group->AddCache(cache);
+ storage->AddStoredGroup(group);
+ storage->AddStoredCache(cache);
+
+ // Conduct the test, we should find the response from the second cache
+ // since it's "in use".
+ MockStorageDelegate delegate;
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ storage->FindResponseForMainRequest(kEntryUrl, &delegate);
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ MessageLoop::current()->RunAllPending(); // Do async task execution.
+ EXPECT_EQ(kEntryUrl, delegate.found_url_);
+ EXPECT_EQ(kManifestUrl2, delegate.found_manifest_url_);
+ EXPECT_EQ(kCacheId2, delegate.found_cache_id_);
+ EXPECT_EQ(kResponseId2, delegate.found_entry_.response_id());
+ EXPECT_TRUE(delegate.found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate.found_fallback_entry_.has_response_id());
+}
+
+TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) {
+ // Should complete asyncly.
+ MockAppCacheService service;
+ MockAppCacheStorage* storage =
+ reinterpret_cast<MockAppCacheStorage*>(service.storage());
+
+ // Setup some preconditions. Create a complete cache with a
+ // foreign entry and an online namespace.
+
+ const int64 kCacheId = storage->NewCacheId();
+ const GURL kEntryUrl("http://blah/entry");
+ const GURL kManifestUrl("http://blah/manifest");
+ const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
+ const int64 kResponseId = 1;
+
+ Manifest manifest;
+ manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl);
+
+ scoped_refptr<AppCache> cache = new AppCache(&service, kCacheId);
+ cache->InitializeWithManifest(&manifest);
+ cache->AddEntry(
+ kEntryUrl,
+ AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
+ kResponseId));
+ cache->set_complete(true);
+ scoped_refptr<AppCacheGroup> group =
+ new AppCacheGroup(&service, kManifestUrl);
+ group->AddCache(cache);
+ storage->AddStoredGroup(group);
+ storage->AddStoredCache(cache);
+
+ MockStorageDelegate delegate;
+
+ // We should not find anything for the foreign entry.
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ storage->FindResponseForMainRequest(kEntryUrl, &delegate);
+ EXPECT_NE(kEntryUrl, delegate.found_url_);
+ MessageLoop::current()->RunAllPending(); // Do async task execution.
+ EXPECT_EQ(kEntryUrl, delegate.found_url_);
+ EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate.found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id());
+ EXPECT_EQ(0, delegate.found_entry_.types());
+ EXPECT_EQ(0, delegate.found_fallback_entry_.types());
+
+ // We should not find anything for the online namespace.
+ EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
+ storage->FindResponseForMainRequest(kOnlineNamespaceUrl, &delegate);
+ EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_);
+ MessageLoop::current()->RunAllPending(); // Do async task execution.
+ EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_);
+ EXPECT_TRUE(delegate.found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate.found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate.found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate.found_fallback_entry_.response_id());
+ EXPECT_EQ(0, delegate.found_entry_.types());
+ EXPECT_EQ(0, delegate.found_fallback_entry_.types());
+}
+
} // namespace appcache