diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 20:56:47 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 20:56:47 +0000 |
commit | ea2a7b919337fb796c8602f1701b60d8fa2d7f42 (patch) | |
tree | 61ab4cb64a4aa0c64e94a5280a7d7f4e35062855 /webkit/appcache | |
parent | c468f9498bcb426edb87cb803a03a63e793e8222 (diff) | |
download | chromium_src-ea2a7b919337fb796c8602f1701b60d8fa2d7f42.zip chromium_src-ea2a7b919337fb796c8602f1701b60d8fa2d7f42.tar.gz chromium_src-ea2a7b919337fb796c8602f1701b60d8fa2d7f42.tar.bz2 |
Select a more appropiate appcache based on the opener or the parent or the target frame of the new document. The change determines a 'preferred manifest url' in these cases:
* <iframe> loading, we prefer the parent frame's manifest url
* window.open() loading, we prefer the opener frame's manifest url
* href clicking to navigate a frame in place, we prefer the manifest url of the document in the frame when the navigation starts
BUG=68479
Review URL: http://codereview.chromium.org/6727006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81801 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache_backend_impl.cc | 3 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.cc | 20 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.h | 23 | ||||
-rw-r--r-- | webkit/appcache/appcache_host_unittest.cc | 1 | ||||
-rw-r--r-- | webkit/appcache/appcache_request_handler.cc | 11 | ||||
-rw-r--r-- | webkit/appcache/appcache_request_handler_unittest.cc | 11 | ||||
-rw-r--r-- | webkit/appcache/appcache_service.cc | 4 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage.h | 4 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.cc | 288 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.h | 5 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl_unittest.cc | 161 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.cc | 4 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage.h | 3 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage_unittest.cc | 14 | ||||
-rw-r--r-- | webkit/appcache/web_application_cache_host_impl.cc | 15 | ||||
-rw-r--r-- | webkit/appcache/web_application_cache_host_impl.h | 2 |
16 files changed, 428 insertions, 141 deletions
diff --git a/webkit/appcache/appcache_backend_impl.cc b/webkit/appcache/appcache_backend_impl.cc index 8ada332..cbe557b 100644 --- a/webkit/appcache/appcache_backend_impl.cc +++ b/webkit/appcache/appcache_backend_impl.cc @@ -59,8 +59,7 @@ bool AppCacheBackendImpl::SetSpawningHostId( AppCacheHost* host = GetHost(host_id); if (!host) return false; - // TODO(michaeln): Write me, see the bug for details. - // http://code.google.com/p/chromium/issues/detail?id=68479 + host->SetSpawningHostId(process_id_, spawning_host_id); return true; } diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc index 2bc463f..18809790 100644 --- a/webkit/appcache/appcache_host.cc +++ b/webkit/appcache/appcache_host.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -33,7 +33,9 @@ void FillCacheInfo( AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend, AppCacheService* service) - : host_id_(host_id), parent_host_id_(kNoHostId), parent_process_id_(0), + : host_id_(host_id), + spawning_host_id_(kNoHostId), spawning_process_id_(0), + parent_host_id_(kNoHostId), parent_process_id_(0), pending_main_resource_cache_id_(kNoCacheId), pending_selected_cache_id_(kNoCacheId), frontend_(frontend), service_(service), @@ -89,6 +91,7 @@ void AppCacheHost::SelectCache(const GURL& document_url, // Note: The client detects if the document was not loaded using HTTP GET // and invokes SelectCache without a manifest url, so that detection step // is also skipped here. See WebApplicationCacheHostImpl.cc + set_preferred_manifest_url(manifest_url); new_master_entry_url_ = document_url; LoadOrCreateGroup(manifest_url); return; @@ -230,6 +233,17 @@ void AppCacheHost::DoPendingSwapCache() { pending_callback_param_ = NULL; } +void AppCacheHost::SetSpawningHostId( + int spawning_process_id, int spawning_host_id) { + spawning_process_id_ = spawning_process_id; + spawning_host_id_ = spawning_host_id; +} + +const AppCacheHost* AppCacheHost::GetSpawningHost() const { + AppCacheBackendImpl* backend = service_->GetBackend(spawning_process_id_); + return backend ? backend->GetHost(spawning_host_id_) : NULL; +} + AppCacheHost* AppCacheHost::GetParentAppCacheHost() const { DCHECK(is_for_dedicated_worker()); AppCacheBackendImpl* backend = service_->GetBackend(parent_process_id_); @@ -338,6 +352,7 @@ void AppCacheHost::FinishCacheSelection( // context being navigated. DCHECK(cache->owning_group()); DCHECK(new_master_entry_url_.is_empty()); + DCHECK_EQ(cache->owning_group()->manifest_url(), preferred_manifest_url_); AppCacheGroup* owing_group = cache->owning_group(); const char* kFormatString = "Document was loaded from Application Cache with manifest %s"; @@ -358,6 +373,7 @@ void AppCacheHost::FinishCacheSelection( // resource from which document was loaded as the new master resourse. DCHECK(!group->is_obsolete()); DCHECK(new_master_entry_url_.is_valid()); + DCHECK_EQ(group->manifest_url(), preferred_manifest_url_); const char* kFormatString = group->HasCache() ? "Adding master entry to Application Cache with manifest %s" : "Creating Application Cache with manifest %s"; diff --git a/webkit/appcache/appcache_host.h b/webkit/appcache/appcache_host.h index c449982..6f25a57 100644 --- a/webkit/appcache/appcache_host.h +++ b/webkit/appcache/appcache_host.h @@ -71,6 +71,22 @@ class AppCacheHost : public AppCacheStorage::Delegate, void SwapCacheWithCallback(SwapCacheCallback* callback, void* callback_param); + // Called prior to the main resource load. When the system contains multiple + // candidates for a main resource load, the appcache preferred by the host + // that created this host is used to break ties. + void SetSpawningHostId(int spawning_process_id, int spawning_host_id); + + // May return NULL if the spawning host context has been closed, or if a + // spawning host context was never identified. + const AppCacheHost* GetSpawningHost() const; + + const GURL& preferred_manifest_url() const { + return preferred_manifest_url_; + } + void set_preferred_manifest_url(const GURL& url) { + preferred_manifest_url_ = url; + } + // Support for loading resources out of the appcache. // May return NULL if the request isn't subject to retrieval from an appache. AppCacheRequestHandler* CreateRequestHandler( @@ -149,6 +165,13 @@ class AppCacheHost : public AppCacheStorage::Delegate, // Identifies the corresponding appcache host in the child process. int host_id_; + // Information about the host that created this one; the manifest + // preferred by our creator influences which cache our main resource + // should be loaded from. + int spawning_host_id_; + int spawning_process_id_; + GURL preferred_manifest_url_; + // Hosts for dedicated workers are special cased to shunt // request handling off to the dedicated worker's parent. // The scriptable api is not accessible in dedicated workers diff --git a/webkit/appcache/appcache_host_unittest.cc b/webkit/appcache/appcache_host_unittest.cc index 2e36728..d648e07 100644 --- a/webkit/appcache/appcache_host_unittest.cc +++ b/webkit/appcache/appcache_host_unittest.cc @@ -156,6 +156,7 @@ TEST_F(AppCacheHostTest, SelectNoCache) { EXPECT_EQ(&mock_frontend_, host.frontend()); EXPECT_EQ(NULL, host.associated_cache()); EXPECT_FALSE(host.is_selection_pending()); + EXPECT_TRUE(host.preferred_manifest_url().is_empty()); } TEST_F(AppCacheHostTest, ForeignEntry) { diff --git a/webkit/appcache/appcache_request_handler.cc b/webkit/appcache/appcache_request_handler.cc index a514517..064b378 100644 --- a/webkit/appcache/appcache_request_handler.cc +++ b/webkit/appcache/appcache_request_handler.cc @@ -188,11 +188,19 @@ void AppCacheRequestHandler::DeliverNetworkResponse() { void AppCacheRequestHandler::MaybeLoadMainResource(net::URLRequest* request) { DCHECK(!job_); + DCHECK(host_); + + const AppCacheHost* spawning_host = + ResourceType::IsSharedWorker(resource_type_) ? + host_ : host_->GetSpawningHost(); + GURL preferred_manifest_url = spawning_host ? + spawning_host->preferred_manifest_url() : GURL(); // We may have to wait for our storage query to complete, but // this query can also complete syncrhonously. job_ = new AppCacheURLRequestJob(request, storage()); - storage()->FindResponseForMainRequest(request->url(), this); + storage()->FindResponseForMainRequest( + request->url(), preferred_manifest_url, this); } void AppCacheRequestHandler::OnMainResponseFound( @@ -216,6 +224,7 @@ void AppCacheRequestHandler::OnMainResponseFound( // in advance of subresource loads happening, secondly to prevent the // AppCache from falling out of the working set on frame navigations. host_->LoadMainResourceCache(cache_id); + host_->set_preferred_manifest_url(manifest_url); } } else { DCHECK(ResourceType::IsSharedWorker(resource_type_)); diff --git a/webkit/appcache/appcache_request_handler_unittest.cc b/webkit/appcache/appcache_request_handler_unittest.cc index 0c41b00..c9fbe0e 100644 --- a/webkit/appcache/appcache_request_handler_unittest.cc +++ b/webkit/appcache/appcache_request_handler_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -223,6 +223,8 @@ class AppCacheRequestHandlerTest : public testing::Test { fallback_job = handler_->MaybeLoadFallbackForResponse(request_.get()); EXPECT_FALSE(fallback_job); + EXPECT_TRUE(host_->preferred_manifest_url().is_empty()); + TestFinished(); } @@ -264,6 +266,9 @@ class AppCacheRequestHandlerTest : public testing::Test { fallback_job = handler_->MaybeLoadFallbackForResponse(request_.get()); EXPECT_FALSE(fallback_job); + EXPECT_EQ(GURL("http://blah/manifest/"), + host_->preferred_manifest_url()); + TestFinished(); } @@ -317,6 +322,9 @@ class AppCacheRequestHandlerTest : public testing::Test { EXPECT_TRUE(host_->main_resource_was_fallback_); EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->fallback_url_); + EXPECT_EQ(GURL("http://blah/manifest/"), + host_->preferred_manifest_url()); + TestFinished(); } @@ -366,6 +374,7 @@ class AppCacheRequestHandlerTest : public testing::Test { // Precondition, the host is waiting on cache selection. scoped_refptr<AppCache> cache(MakeNewCache()); host_->pending_selected_cache_id_ = cache->cache_id(); + host_->set_preferred_manifest_url(cache->owning_group()->manifest_url()); request_.reset(new MockURLRequest(GURL("http://blah/"))); handler_.reset(host_->CreateRequestHandler(request_.get(), diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc index e748434..5e477ac 100644 --- a/webkit/appcache/appcache_service.cc +++ b/webkit/appcache/appcache_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -73,7 +73,7 @@ class AppCacheService::CanHandleOfflineHelper : AsyncHelper { } virtual void Start() { - service_->storage()->FindResponseForMainRequest(url_, this); + service_->storage()->FindResponseForMainRequest(url_, GURL(), this); } private: diff --git a/webkit/appcache/appcache_storage.h b/webkit/appcache/appcache_storage.h index 7d64d31..5672546 100644 --- a/webkit/appcache/appcache_storage.h +++ b/webkit/appcache/appcache_storage.h @@ -114,7 +114,9 @@ class AppCacheStorage { // 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; + const GURL& url, + const GURL& preferred_manifest_url, + Delegate* delegate) = 0; // Performs an immediate lookup of the in-memory cache to // identify a response for a sub resource request. diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 0f78b77..fe325a1 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -509,12 +509,13 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() { if (success_) { - // TODO(kkanetkar): Add to creation time when that's enabled. storage_->origins_with_groups_.insert(group_->manifest_url().GetOrigin()); if (cache_ != group_->newest_complete_cache()) { cache_->set_complete(true); group_->AddCache(cache_); } + if (group_->creation_time().is_null()) + group_->set_creation_time(group_record_.creation_time); group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_); } FOR_EACH_DELEGATE(delegates_, @@ -536,9 +537,13 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() { class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { public: - FindMainResponseTask(AppCacheStorageImpl* storage, const GURL& url, + FindMainResponseTask(AppCacheStorageImpl* storage, + const GURL& url, + const GURL& preferred_manifest_url, const AppCacheWorkingSet::GroupMap* groups_in_use) - : DatabaseTask(storage), url_(url), cache_id_(kNoCacheId) { + : DatabaseTask(storage), url_(url), + preferred_manifest_url_(preferred_manifest_url), + cache_id_(kNoCacheId) { if (groups_in_use) { for (AppCacheWorkingSet::GroupMap::const_iterator it = groups_in_use->begin(); @@ -555,7 +560,15 @@ class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { virtual void Run(); virtual void RunCompleted(); + private: + typedef std::vector<AppCacheDatabase::FallbackNameSpaceRecord*> + FallbackNameSpaceVector; + bool FindExactMatch(int64 preferred_id); + bool FindFallback(int64 preferred_id); + bool FindFirstValidFallback(const FallbackNameSpaceVector& fallbacks); + GURL url_; + GURL preferred_manifest_url_; std::set<int64> cache_ids_in_use_; AppCacheEntry entry_; AppCacheEntry fallback_entry_; @@ -566,6 +579,32 @@ class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { // Helpers for FindMainResponseTask::Run() namespace { +class SortByCachePreference + : public std::binary_function< + AppCacheDatabase::EntryRecord, + AppCacheDatabase::EntryRecord, + bool> { + public: + SortByCachePreference(int64 preferred_id, const std::set<int64>& in_use_ids) + : preferred_id_(preferred_id), in_use_ids_(in_use_ids) { + } + bool operator()( + const AppCacheDatabase::EntryRecord& lhs, + const AppCacheDatabase::EntryRecord& rhs) { + return compute_value(lhs) > compute_value(rhs); + } + private: + int compute_value(const AppCacheDatabase::EntryRecord& entry) { + if (entry.cache_id == preferred_id_) + return 100; + else if (in_use_ids_.find(entry.cache_id) != in_use_ids_.end()) + return 50; + return 0; + } + int64 preferred_id_; + const std::set<int64>& in_use_ids_; +}; + bool SortByLength( const AppCacheDatabase::FallbackNameSpaceRecord& lhs, const AppCacheDatabase::FallbackNameSpaceRecord& rhs) { @@ -609,99 +648,150 @@ class NetworkNamespaceHelper { WhiteListMap namespaces_map_; AppCacheDatabase* database_; }; + +bool FindManifestForEntry( + const AppCacheDatabase::EntryRecord& entry_record, + AppCacheDatabase* database, + GURL* manifest_url_out) { + AppCacheDatabase::GroupRecord group_record; + if (!database->FindGroupForCache(entry_record.cache_id, &group_record)) { + NOTREACHED() << "A cache without a group is not expected."; + return false; + } + *manifest_url_out = group_record.manifest_url; + return true; +} + } // namespace void AppCacheStorageImpl::FindMainResponseTask::Run() { - // We have a bias for hits from caches that are in use. - - // 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 - - // First look for an exact match. We don't worry about whether - // the containing cache is in-use in this loop because the - // storage class's FindResponseForMainRequest method does that - // as a pre-optimization. + // NOTE: The heuristics around choosing amoungst multiple candidates + // is underspecified, and just plain not fully understood. This needs + // to be refined. + + // The 'preferred_manifest_url' is the url of the manifest associated + // with the page that opened or embedded the page being loaded now. + // We have a strong preference to use resources from that cache. + // We also have a lesser bias to use resources from caches that are currently + // being used by other unrelated pages. + // TODO(michaeln): come up with a 'preferred_manifest_url' in more cases + // - when navigating a frame whose current contents are from an appcache + // - when clicking an href in a frame that is appcached + int64 preferred_cache_id = kNoCacheId; + if (!preferred_manifest_url_.is_empty()) { + AppCacheDatabase::GroupRecord preferred_group; + AppCacheDatabase::CacheRecord preferred_cache; + if (database_->FindGroupForManifestUrl( + preferred_manifest_url_, &preferred_group) && + database_->FindCacheForGroup( + preferred_group.group_id, &preferred_cache)) { + preferred_cache_id = preferred_cache.cache_id; + } + } + + if (FindExactMatch(preferred_cache_id) || + FindFallback(preferred_cache_id)) { + // We found something. + DCHECK(cache_id_ != kNoCacheId && !manifest_url_.is_empty()); + return; + } + + // We didn't find anything. + DCHECK(cache_id_ == kNoCacheId && manifest_url_.is_empty()); +} + +bool AppCacheStorageImpl:: +FindMainResponseTask::FindExactMatch(int64 preferred_cache_id) { std::vector<AppCacheDatabase::EntryRecord> entries; if (database_->FindEntriesForUrl(url_, &entries) && !entries.empty()) { + // Sort them in order of preference, from the preferred_cache first, + // followed by hits from caches that are 'in use', then the rest. + std::sort(entries.begin(), entries.end(), + SortByCachePreference(preferred_cache_id, cache_ids_in_use_)); + + // Take the first with a valid, non-foreign entry. std::vector<AppCacheDatabase::EntryRecord>::iterator iter; for (iter = entries.begin(); iter < entries.end(); ++iter) { - if (iter->flags & AppCacheEntry::FOREIGN) - continue; - - AppCacheDatabase::GroupRecord group_record; - if (!database_->FindGroupForCache(iter->cache_id, &group_record)) { - NOTREACHED() << "A cache without a group is not expected."; + if ((iter->flags & AppCacheEntry::FOREIGN) || + !FindManifestForEntry(*iter, database_, &manifest_url_)) { continue; } entry_ = AppCacheEntry(iter->flags, iter->response_id); cache_id_ = iter->cache_id; - manifest_url_ = group_record.manifest_url; - return; + return true; // We found an exact match. } } + return false; +} - // No exact matches, look at the fallback namespaces for this origin. - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallbacks; - if (!database_->FindFallbackNameSpacesForOrigin(url_.GetOrigin(), &fallbacks) - || fallbacks.empty()) { - return; +bool AppCacheStorageImpl:: +FindMainResponseTask::FindFallback(int64 preferred_cache_id) { + std::vector<AppCacheDatabase::FallbackNameSpaceRecord> all_fallbacks; + if (!database_->FindFallbackNameSpacesForOrigin( + url_.GetOrigin(), &all_fallbacks) + || all_fallbacks.empty()) { + return false; } - // Sort by namespace url string length, longest to shortest, - // since longer matches trump when matching a url to a namespace. - std::sort(fallbacks.begin(), fallbacks.end(), SortByLength); + // Sort them by length, longer matches within the same cache/bucket take + // precedence. + std::sort(all_fallbacks.begin(), all_fallbacks.end(), SortByLength); - bool has_candidate = false; - GURL candidate_fallback_namespace; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>::iterator iter; + // Filter the list and bin them into buckets. NetworkNamespaceHelper network_namespace_helper(database_); - for (iter = fallbacks.begin(); iter < fallbacks.end(); ++iter) { - // Skip this fallback namespace if the requested url falls into a network - // namespace of the containing appcache. - if (network_namespace_helper.IsInNetworkNamespace(url_, iter->cache_id)) + FallbackNameSpaceVector preferred_fallbacks; + FallbackNameSpaceVector inuse_fallbacks; + FallbackNameSpaceVector other_fallbacks; + std::vector<AppCacheDatabase::FallbackNameSpaceRecord>::iterator iter; + for (iter = all_fallbacks.begin(); iter < all_fallbacks.end(); ++iter) { + // Skip those that aren't a prefix match. + if (!StartsWithASCII(url_.spec(), iter->namespace_url.spec(), true)) continue; - if (has_candidate && - (candidate_fallback_namespace.spec().length() > - iter->namespace_url.spec().length())) { - break; // Stop iterating since longer namespace prefix matches win. - } - - if (StartsWithASCII(url_.spec(), iter->namespace_url.spec(), true)) { - bool is_cache_in_use = cache_ids_in_use_.find(iter->cache_id) != - cache_ids_in_use_.end(); + // Skip fallback namespaces where the requested url falls into a network + // namespace of its containing appcache. + if (network_namespace_helper.IsInNetworkNamespace(url_, iter->cache_id)) + continue; - bool take_new_candidate = !has_candidate || is_cache_in_use; + // Bin them into one of our three buckets. + if (iter->cache_id == preferred_cache_id) + preferred_fallbacks.push_back(&(*iter)); + else if (cache_ids_in_use_.find(iter->cache_id) != cache_ids_in_use_.end()) + inuse_fallbacks.push_back(&(*iter)); + else + other_fallbacks.push_back(&(*iter)); + } - AppCacheDatabase::EntryRecord entry_record; - if (take_new_candidate && - database_->FindEntry(iter->cache_id, iter->fallback_entry_url, - &entry_record)) { - if (entry_record.flags & AppCacheEntry::FOREIGN) - continue; - AppCacheDatabase::GroupRecord group_record; - if (!database_->FindGroupForCache(iter->cache_id, &group_record)) { - NOTREACHED() << "A cache without a group is not expected."; - continue; - } - cache_id_ = iter->cache_id; - fallback_url_ = iter->fallback_entry_url; - manifest_url_ = group_record.manifest_url; - fallback_entry_ = AppCacheEntry( - entry_record.flags, entry_record.response_id); - if (is_cache_in_use) - break; // Stop iterating since we favor hits from in-use caches. - candidate_fallback_namespace = iter->namespace_url; - has_candidate = true; + if (FindFirstValidFallback(preferred_fallbacks) || + FindFirstValidFallback(inuse_fallbacks) || + FindFirstValidFallback(other_fallbacks)) + return true; // We found one. + + // We didn't find anything. + return false; +} + +bool AppCacheStorageImpl:: +FindMainResponseTask::FindFirstValidFallback( + const FallbackNameSpaceVector& fallbacks) { + // Take the first with a valid, non-foreign entry. + FallbackNameSpaceVector::const_iterator iter; + for (iter = fallbacks.begin(); iter < fallbacks.end(); ++iter) { + AppCacheDatabase::EntryRecord entry_record; + if (database_->FindEntry((*iter)->cache_id, (*iter)->fallback_entry_url, + &entry_record)) { + if ((entry_record.flags & AppCacheEntry::FOREIGN) || + !FindManifestForEntry(entry_record, database_, &manifest_url_)) { + continue; } + cache_id_ = (*iter)->cache_id; + fallback_url_ = (*iter)->fallback_entry_url; + fallback_entry_ = AppCacheEntry( + entry_record.flags, entry_record.response_id); + return true; // We found one. } } + return false; // We didn't find a match. } void AppCacheStorageImpl::FindMainResponseTask::RunCompleted() { @@ -1038,7 +1128,8 @@ void AppCacheStorageImpl::StoreGroupAndNewestCache( } void AppCacheStorageImpl::FindResponseForMainRequest( - const GURL& url, Delegate* delegate) { + const GURL& url, const GURL& preferred_manifest_url, + Delegate* delegate) { DCHECK(delegate); const GURL* url_ptr = &url; @@ -1057,21 +1148,22 @@ void AppCacheStorageImpl::FindResponseForMainRequest( const AppCacheWorkingSet::GroupMap* groups_in_use = working_set()->GetGroupsInOrigin(origin); if (groups_in_use) { - for (AppCacheWorkingSet::GroupMap::const_iterator it = - groups_in_use->begin(); - it != groups_in_use->end(); ++it) { - AppCacheGroup* group = it->second; - AppCache* cache = group->newest_complete_cache(); - if (group->is_obsolete() || !cache) - continue; - - AppCacheEntry* entry = cache->GetEntry(*url_ptr); - if (entry && !entry->IsForeign()) { - ScheduleSimpleTask(method_factory_.NewRunnableMethod( - &AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse, - url, *entry, make_scoped_refptr(group), make_scoped_refptr(cache), - make_scoped_refptr(GetOrCreateDelegateReference(delegate)))); - return; + if (!preferred_manifest_url.is_empty()) { + AppCacheWorkingSet::GroupMap::const_iterator found = + groups_in_use->find(preferred_manifest_url); + if (found != groups_in_use->end() && + FindResponseForMainRequestInGroup( + found->second, *url_ptr, delegate)) { + return; + } + } else { + for (AppCacheWorkingSet::GroupMap::const_iterator it = + groups_in_use->begin(); + it != groups_in_use->end(); ++it) { + if (FindResponseForMainRequestInGroup( + it->second, *url_ptr, delegate)) { + return; + } } } } @@ -1091,11 +1183,29 @@ void AppCacheStorageImpl::FindResponseForMainRequest( // We have to query the database, schedule a database task to do so. scoped_refptr<FindMainResponseTask> task( - new FindMainResponseTask(this, *url_ptr, groups_in_use)); + new FindMainResponseTask(this, *url_ptr, preferred_manifest_url, + groups_in_use)); task->AddDelegate(GetOrCreateDelegateReference(delegate)); task->Schedule(); } +bool AppCacheStorageImpl::FindResponseForMainRequestInGroup( + AppCacheGroup* group, const GURL& url, Delegate* delegate) { + AppCache* cache = group->newest_complete_cache(); + if (group->is_obsolete() || !cache) + return false; + + AppCacheEntry* entry = cache->GetEntry(url); + if (!entry || entry->IsForeign()) + return false; + + ScheduleSimpleTask(method_factory_.NewRunnableMethod( + &AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse, + url, *entry, make_scoped_refptr(group), make_scoped_refptr(cache), + make_scoped_refptr(GetOrCreateDelegateReference(delegate)))); + return true; +} + void AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse( const GURL& url, AppCacheEntry found_entry, scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> cache, diff --git a/webkit/appcache/appcache_storage_impl.h b/webkit/appcache/appcache_storage_impl.h index dc49053d..cd54a86 100644 --- a/webkit/appcache/appcache_storage_impl.h +++ b/webkit/appcache/appcache_storage_impl.h @@ -35,7 +35,8 @@ class AppCacheStorageImpl : public AppCacheStorage { virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate); virtual void StoreGroupAndNewestCache( AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate); - virtual void FindResponseForMainRequest(const GURL& url, Delegate* delegate); + virtual void FindResponseForMainRequest( + const GURL& url, const GURL& preferred_manifest_url, Delegate* delegate); virtual void FindResponseForSubRequest( AppCache* cache, const GURL& url, AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, @@ -101,6 +102,8 @@ class AppCacheStorageImpl : public AppCacheStorage { void OnDiskCacheInitialized(int rv); // Sometimes we can respond without having to query the database. + bool FindResponseForMainRequestInGroup( + AppCacheGroup* group, const GURL& url, Delegate* delegate); void DeliverShortCircuitedFindMainResponse( const GURL& url, AppCacheEntry found_entry, scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> newest_cache, diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc index 1d874bc..af87b08 100644 --- a/webkit/appcache/appcache_storage_impl_unittest.cc +++ b/webkit/appcache/appcache_storage_impl_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -25,6 +25,7 @@ namespace { const base::Time kZeroTime; const GURL kManifestUrl("http://blah/manifest"); const GURL kManifestUrl2("http://blah/manifest2"); +const GURL kManifestUrl3("http://blah/manifest3"); const GURL kEntryUrl("http://blah/entry"); const GURL kEntryUrl2("http://blah/entry2"); const GURL kFallbackNamespace("http://blah/fallback_namespace/"); @@ -34,6 +35,9 @@ const GURL kOnlineNamespace("http://blah/online_namespace"); const GURL kOnlineNamespaceWithinFallback( "http://blah/fallback_namespace/online/"); +const int kManifestEntryIdOffset = 100; +const int kFallbackEntryIdOffset = 1000; + // For the duration of this test case, we hijack the AppCacheThread API // calls and implement them in terms of the io and db threads created here. @@ -723,7 +727,7 @@ class AppCacheStorageImplTest : public testing::Test { this, &AppCacheStorageImplTest::Verify_FindNoMainResponse)); // Conduct the test. - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); + storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); EXPECT_NE(kEntryUrl, delegate()->found_url_); } @@ -783,7 +787,7 @@ class AppCacheStorageImplTest : public testing::Test { } // Conduct the test. - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); + storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); EXPECT_NE(kEntryUrl, delegate()->found_url_); } @@ -844,7 +848,7 @@ class AppCacheStorageImplTest : public testing::Test { // Conduct the test. The test url is in both fallback namespace urls, // but should match the longer of the two. - storage()->FindResponseForMainRequest(kFallbackTestUrl, delegate()); + storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate()); EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); } @@ -866,37 +870,98 @@ class AppCacheStorageImplTest : public testing::Test { PushNextTask(NewRunnableMethod(this, &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits)); - // Setup some preconditions. Create 2 complete caches with an entry - // for the same url. + // Setup some preconditions, create a few caches with an identical set + // of entries and fallback namespaces. Only the last one remains in + // the working set to simulate appearing as "in use". + MakeMultipleHitCacheAndGroup(kManifestUrl, 1); + MakeMultipleHitCacheAndGroup(kManifestUrl2, 2); + MakeMultipleHitCacheAndGroup(kManifestUrl3, 3); - // The first cache, in the database but not in the working set. - MakeCacheAndGroup(kManifestUrl, 1, 1, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1)); + // Conduct the test, we should find the response from the last cache + // since it's "in use". + storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); + EXPECT_NE(kEntryUrl, delegate()->found_url_); + } + + void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) { + MakeCacheAndGroup(manifest_url, id, id, true); AppCacheDatabase::EntryRecord entry_record; - entry_record.cache_id = 1; + + // Add an entry for kEntryUrl + entry_record.cache_id = id; entry_record.url = kEntryUrl; entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 1; + entry_record.response_id = id; EXPECT_TRUE(database()->InsertEntry(&entry_record)); - cache_ = NULL; - group_ = NULL; + cache_->AddEntry( + entry_record.url, + AppCacheEntry(entry_record.flags, entry_record.response_id)); + + // Add an entry for the manifestUrl + entry_record.cache_id = id; + entry_record.url = manifest_url; + entry_record.flags = AppCacheEntry::MANIFEST; + entry_record.response_id = id + kManifestEntryIdOffset; + EXPECT_TRUE(database()->InsertEntry(&entry_record)); + cache_->AddEntry( + entry_record.url, + AppCacheEntry(entry_record.flags, entry_record.response_id)); - // The second cache, in the database and working set. - MakeCacheAndGroup(kManifestUrl2, 2, 2, true); - cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 2)); - entry_record.cache_id = 2; - entry_record.url = kEntryUrl; - entry_record.flags = AppCacheEntry::EXPLICIT; - entry_record.response_id = 2; + // Add a fallback entry and namespace + entry_record.cache_id = id; + entry_record.url = kEntryUrl2; + entry_record.flags = AppCacheEntry::FALLBACK; + entry_record.response_id = id + kFallbackEntryIdOffset; EXPECT_TRUE(database()->InsertEntry(&entry_record)); + cache_->AddEntry( + entry_record.url, + AppCacheEntry(entry_record.flags, entry_record.response_id)); + AppCacheDatabase::FallbackNameSpaceRecord fallback_namespace_record; + fallback_namespace_record.cache_id = id; + fallback_namespace_record.fallback_entry_url = entry_record.url; + fallback_namespace_record.namespace_url = kFallbackNamespace; + fallback_namespace_record.origin = manifest_url.GetOrigin(); + EXPECT_TRUE( + database()->InsertFallbackNameSpace(&fallback_namespace_record)); + cache_->fallback_namespaces_.push_back( + FallbackNamespace(kFallbackNamespace, kEntryUrl2)); + } - // Conduct the test, we should find the response from the second cache - // since it's "in use". - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); + void Verify_FindMainResponseWithMultipleHits() { + EXPECT_EQ(kEntryUrl, delegate()->found_url_); + EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_); + EXPECT_FALSE(delegate()->found_blocked_by_policy_); + EXPECT_EQ(3, delegate()->found_cache_id_); + EXPECT_EQ(3, delegate()->found_entry_.response_id()); + EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); + EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); + + // Conduct another test perferring kManifestUrl + delegate_.reset(new MockStorageDelegate(this)); + PushNextTask(NewRunnableMethod(this, + &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2)); + storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate()); EXPECT_NE(kEntryUrl, delegate()->found_url_); } - void Verify_FindMainResponseWithMultipleHits() { + void Verify_FindMainResponseWithMultipleHits2() { + EXPECT_EQ(kEntryUrl, delegate()->found_url_); + EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); + EXPECT_FALSE(delegate()->found_blocked_by_policy_); + EXPECT_EQ(1, delegate()->found_cache_id_); + EXPECT_EQ(1, delegate()->found_entry_.response_id()); + EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); + EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); + + // Conduct the another test perferring kManifestUrl2 + delegate_.reset(new MockStorageDelegate(this)); + PushNextTask(NewRunnableMethod(this, + &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3)); + storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate()); + EXPECT_NE(kEntryUrl, delegate()->found_url_); + } + + void Verify_FindMainResponseWithMultipleHits3() { EXPECT_EQ(kEntryUrl, delegate()->found_url_); EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_); EXPECT_FALSE(delegate()->found_blocked_by_policy_); @@ -904,6 +969,47 @@ class AppCacheStorageImplTest : public testing::Test { EXPECT_EQ(2, delegate()->found_entry_.response_id()); EXPECT_TRUE(delegate()->found_entry_.IsExplicit()); EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); + + // Conduct another test with no preferred manifest that hits the fallback. + delegate_.reset(new MockStorageDelegate(this)); + PushNextTask(NewRunnableMethod(this, + &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4)); + storage()->FindResponseForMainRequest( + kFallbackTestUrl, GURL(), delegate()); + EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); + } + + void Verify_FindMainResponseWithMultipleHits4() { + EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); + EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_); + EXPECT_FALSE(delegate()->found_blocked_by_policy_); + EXPECT_EQ(3, delegate()->found_cache_id_); + EXPECT_FALSE(delegate()->found_entry_.has_response_id()); + EXPECT_EQ(3 + kFallbackEntryIdOffset, + delegate()->found_fallback_entry_.response_id()); + EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); + EXPECT_EQ(kEntryUrl2, delegate()->found_fallback_url_); + + // Conduct another test preferring kManifestUrl2 that hits the fallback. + delegate_.reset(new MockStorageDelegate(this)); + PushNextTask(NewRunnableMethod(this, + &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5)); + storage()->FindResponseForMainRequest( + kFallbackTestUrl, kManifestUrl2, delegate()); + EXPECT_NE(kFallbackTestUrl, delegate()->found_url_); + } + + void Verify_FindMainResponseWithMultipleHits5() { + EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_); + EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_); + EXPECT_FALSE(delegate()->found_blocked_by_policy_); + EXPECT_EQ(2, delegate()->found_cache_id_); + EXPECT_FALSE(delegate()->found_entry_.has_response_id()); + EXPECT_EQ(2 + kFallbackEntryIdOffset, + delegate()->found_fallback_entry_.response_id()); + EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback()); + EXPECT_EQ(kEntryUrl2, delegate()->found_fallback_url_); + TestFinished(); } @@ -961,7 +1067,7 @@ class AppCacheStorageImplTest : public testing::Test { PushNextTask(NewRunnableMethod( this, &AppCacheStorageImplTest::Verify_ExclusionNotFound, kEntryUrl, 1)); - storage()->FindResponseForMainRequest(kEntryUrl, delegate()); + storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate()); } void Verify_ExclusionNotFound(GURL expected_url, int phase) { @@ -980,7 +1086,8 @@ class AppCacheStorageImplTest : public testing::Test { PushNextTask(NewRunnableMethod(this, &AppCacheStorageImplTest::Verify_ExclusionNotFound, kOnlineNamespace, 2)); - storage()->FindResponseForMainRequest(kOnlineNamespace, delegate()); + storage()->FindResponseForMainRequest( + kOnlineNamespace, GURL(), delegate()); return; } if (phase == 2) { @@ -990,7 +1097,7 @@ class AppCacheStorageImplTest : public testing::Test { &AppCacheStorageImplTest::Verify_ExclusionNotFound, kOnlineNamespaceWithinFallback, 3)); storage()->FindResponseForMainRequest( - kOnlineNamespaceWithinFallback, delegate()); + kOnlineNamespaceWithinFallback, GURL(), delegate()); return; } diff --git a/webkit/appcache/mock_appcache_storage.cc b/webkit/appcache/mock_appcache_storage.cc index 73ae6c9..98af9bf 100644 --- a/webkit/appcache/mock_appcache_storage.cc +++ b/webkit/appcache/mock_appcache_storage.cc @@ -83,9 +83,11 @@ void MockAppCacheStorage::StoreGroupAndNewestCache( } void MockAppCacheStorage::FindResponseForMainRequest( - const GURL& url, Delegate* delegate) { + const GURL& url, const GURL& preferred_manifest_url, Delegate* delegate) { DCHECK(delegate); + // Note: MockAppCacheStorage does not respect the preferred_manifest_url. + // Always make this operation look async. ScheduleTask(method_factory_.NewRunnableMethod( &MockAppCacheStorage::ProcessFindResponseForMainRequest, diff --git a/webkit/appcache/mock_appcache_storage.h b/webkit/appcache/mock_appcache_storage.h index c808610..ea3ca1f 100644 --- a/webkit/appcache/mock_appcache_storage.h +++ b/webkit/appcache/mock_appcache_storage.h @@ -34,7 +34,8 @@ class MockAppCacheStorage : public AppCacheStorage { virtual void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate); virtual void StoreGroupAndNewestCache( AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate); - virtual void FindResponseForMainRequest(const GURL& url, Delegate* delegate); + virtual void FindResponseForMainRequest( + const GURL& url, const GURL& preferred_manifest_url, Delegate* delegate); virtual void FindResponseForSubRequest( AppCache* cache, const GURL& url, AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc index 2be8642..d04a896 100644 --- a/webkit/appcache/mock_appcache_storage_unittest.cc +++ b/webkit/appcache/mock_appcache_storage_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. @@ -394,7 +394,7 @@ TEST_F(MockAppCacheStorageTest, FindNoMainResponse) { MockStorageDelegate delegate; GURL url("http://blah/some_url"); EXPECT_NE(url, delegate.found_url_); - storage->FindResponseForMainRequest(url, &delegate); + storage->FindResponseForMainRequest(url, GURL(), &delegate); EXPECT_NE(url, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(url, delegate.found_url_); @@ -431,7 +431,7 @@ TEST_F(MockAppCacheStorageTest, BasicFindMainResponse) { // Conduct the test. MockStorageDelegate delegate; EXPECT_NE(kEntryUrl, delegate.found_url_); - storage->FindResponseForMainRequest(kEntryUrl, &delegate); + storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); EXPECT_NE(kEntryUrl, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(kEntryUrl, delegate.found_url_); @@ -486,7 +486,7 @@ TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) { // Conduct the test. MockStorageDelegate delegate; EXPECT_NE(kTestUrl, delegate.found_url_); - storage->FindResponseForMainRequest(kTestUrl, &delegate); + storage->FindResponseForMainRequest(kTestUrl, GURL(), &delegate); EXPECT_NE(kTestUrl, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(kTestUrl, delegate.found_url_); @@ -543,7 +543,7 @@ TEST_F(MockAppCacheStorageTest, FindMainResponseWithMultipleCandidates) { // since it's "in use". MockStorageDelegate delegate; EXPECT_NE(kEntryUrl, delegate.found_url_); - storage->FindResponseForMainRequest(kEntryUrl, &delegate); + storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); EXPECT_NE(kEntryUrl, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(kEntryUrl, delegate.found_url_); @@ -589,7 +589,7 @@ TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) { // We should not find anything for the foreign entry. EXPECT_NE(kEntryUrl, delegate.found_url_); - storage->FindResponseForMainRequest(kEntryUrl, &delegate); + storage->FindResponseForMainRequest(kEntryUrl, GURL(), &delegate); EXPECT_NE(kEntryUrl, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(kEntryUrl, delegate.found_url_); @@ -603,7 +603,7 @@ TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) { // We should not find anything for the online namespace. EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_); - storage->FindResponseForMainRequest(kOnlineNamespaceUrl, &delegate); + storage->FindResponseForMainRequest(kOnlineNamespaceUrl, GURL(), &delegate); EXPECT_NE(kOnlineNamespaceUrl, delegate.found_url_); MessageLoop::current()->RunAllPending(); // Do async task execution. EXPECT_EQ(kOnlineNamespaceUrl, delegate.found_url_); diff --git a/webkit/appcache/web_application_cache_host_impl.cc b/webkit/appcache/web_application_cache_host_impl.cc index 981894d..4fbcc21 100644 --- a/webkit/appcache/web_application_cache_host_impl.cc +++ b/webkit/appcache/web_application_cache_host_impl.cc @@ -53,7 +53,7 @@ WebApplicationCacheHostImpl* WebApplicationCacheHostImpl::FromId(int id) { } WebApplicationCacheHostImpl* WebApplicationCacheHostImpl::FromFrame( - WebFrame* frame) { + const WebFrame* frame) { if (!frame) return NULL; WebDataSource* data_source = frame->dataSource(); @@ -166,10 +166,15 @@ void WebApplicationCacheHostImpl::willStartMainResourceRequest( DCHECK(method == StringToUpperASCII(method)); if (frame) { - if (WebApplicationCacheHostImpl* parent = FromFrame(frame->parent())) - backend_->SetSpawningHostId(host_id_, parent->host_id()); - else if (WebApplicationCacheHostImpl* opener = FromFrame(frame->opener())) - backend_->SetSpawningHostId(host_id_, opener->host_id()); + const WebFrame* spawning_frame = frame->parent(); + if (!spawning_frame) + spawning_frame = frame->opener(); + if (!spawning_frame) + spawning_frame = frame; + + WebApplicationCacheHostImpl* spawning_host = FromFrame(spawning_frame); + if (spawning_host && (spawning_host != this)) + backend_->SetSpawningHostId(host_id_, spawning_host->host_id()); } } diff --git a/webkit/appcache/web_application_cache_host_impl.h b/webkit/appcache/web_application_cache_host_impl.h index 03020f0..7b6789a 100644 --- a/webkit/appcache/web_application_cache_host_impl.h +++ b/webkit/appcache/web_application_cache_host_impl.h @@ -25,7 +25,7 @@ class WebApplicationCacheHostImpl : public WebKit::WebApplicationCacheHost { static WebApplicationCacheHostImpl* FromId(int id); // Returns the host associated with the current document in frame. - static WebApplicationCacheHostImpl* FromFrame(WebKit::WebFrame* frame); + static WebApplicationCacheHostImpl* FromFrame(const WebKit::WebFrame* frame); WebApplicationCacheHostImpl(WebKit::WebApplicationCacheHostClient* client, AppCacheBackend* backend); |