diff options
Diffstat (limited to 'webkit/appcache')
-rw-r--r-- | webkit/appcache/appcache.cc | 84 | ||||
-rw-r--r-- | webkit/appcache/appcache.h | 18 | ||||
-rw-r--r-- | webkit/appcache/appcache_database.cc | 220 | ||||
-rw-r--r-- | webkit/appcache/appcache_database.h | 45 | ||||
-rw-r--r-- | webkit/appcache/appcache_database_unittest.cc | 345 | ||||
-rw-r--r-- | webkit/appcache/appcache_entry.h | 2 | ||||
-rw-r--r-- | webkit/appcache/appcache_interfaces.cc | 23 | ||||
-rw-r--r-- | webkit/appcache/appcache_interfaces.h | 18 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl.cc | 202 | ||||
-rw-r--r-- | webkit/appcache/appcache_storage_impl_unittest.cc | 124 | ||||
-rw-r--r-- | webkit/appcache/appcache_unittest.cc | 57 | ||||
-rw-r--r-- | webkit/appcache/appcache_update_job.cc | 14 | ||||
-rw-r--r-- | webkit/appcache/appcache_update_job_unittest.cc | 90 | ||||
-rw-r--r-- | webkit/appcache/manifest_parser.cc | 91 | ||||
-rw-r--r-- | webkit/appcache/manifest_parser.h | 6 | ||||
-rw-r--r-- | webkit/appcache/manifest_parser_unittest.cc | 130 | ||||
-rw-r--r-- | webkit/appcache/mock_appcache_storage_unittest.cc | 14 | ||||
-rw-r--r-- | webkit/appcache/view_appcache_internals_job.cc | 2 |
18 files changed, 1112 insertions, 373 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc index 3ba4a81..5a4e548 100644 --- a/webkit/appcache/appcache.cc +++ b/webkit/appcache/appcache.cc @@ -82,36 +82,40 @@ const AppCacheEntry* AppCache::GetEntryWithResponseId(int64 response_id) { GURL AppCache::GetFallbackEntryUrl(const GURL& namespace_url) const { size_t count = fallback_namespaces_.size(); for (size_t i = 0; i < count; ++i) { - if (fallback_namespaces_[i].first == namespace_url) - return fallback_namespaces_[i].second; + if (fallback_namespaces_[i].namespace_url == namespace_url) + return fallback_namespaces_[i].target_url; } NOTREACHED(); return GURL(); } namespace { -bool SortByLength( - const FallbackNamespace& lhs, const FallbackNamespace& rhs) { - return lhs.first.spec().length() > rhs.first.spec().length(); +bool SortNamespacesByLength( + const Namespace& lhs, const Namespace& rhs) { + return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length(); } } void AppCache::InitializeWithManifest(Manifest* manifest) { DCHECK(manifest); + intercept_namespaces_.swap(manifest->intercept_namespaces); 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, + // Sort the namespaces by url string length, longest to shortest, // since longer matches trump when matching a url to a namespace. + std::sort(intercept_namespaces_.begin(), intercept_namespaces_.end(), + SortNamespacesByLength); std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(), - SortByLength); + SortNamespacesByLength); } void AppCache::InitializeWithDatabaseRecords( const AppCacheDatabase::CacheRecord& cache_record, const std::vector<AppCacheDatabase::EntryRecord>& entries, - const std::vector<AppCacheDatabase::FallbackNameSpaceRecord>& fallbacks, + const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts, + const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks, const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists) { DCHECK(cache_id_ == cache_record.cache_id); online_whitelist_all_ = cache_record.online_wildcard; @@ -124,16 +128,28 @@ void AppCache::InitializeWithDatabaseRecords( } DCHECK(cache_size_ == cache_record.cache_size); + for (size_t i = 0; i < intercepts.size(); ++i) { + const AppCacheDatabase::NamespaceRecord& intercept = intercepts.at(i); + intercept_namespaces_.push_back( + Namespace(INTERCEPT_NAMESPACE, + intercept.namespace_url, + intercept.target_url)); + } + for (size_t i = 0; i < fallbacks.size(); ++i) { - const AppCacheDatabase::FallbackNameSpaceRecord& fallback = fallbacks.at(i); + const AppCacheDatabase::NamespaceRecord& fallback = fallbacks.at(i); fallback_namespaces_.push_back( - FallbackNamespace(fallback.namespace_url, fallback.fallback_entry_url)); + Namespace(FALLBACK_NAMESPACE, + fallback.namespace_url, + fallback.target_url)); } // Sort the fallback namespaces by url string length, longest to shortest, // since longer matches trump when matching a url to a namespace. + std::sort(intercept_namespaces_.begin(), intercept_namespaces_.end(), + SortNamespacesByLength); std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(), - SortByLength); + SortNamespacesByLength); if (!online_whitelist_all_) { for (size_t i = 0; i < whitelists.size(); ++i) { @@ -146,7 +162,8 @@ void AppCache::ToDatabaseRecords( const AppCacheGroup* group, AppCacheDatabase::CacheRecord* cache_record, std::vector<AppCacheDatabase::EntryRecord>* entries, - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>* fallbacks, + std::vector<AppCacheDatabase::NamespaceRecord>* intercepts, + std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks, std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists) { DCHECK(group && cache_record && entries && fallbacks && whitelists); DCHECK(entries->empty() && fallbacks->empty() && whitelists->empty()); @@ -171,13 +188,24 @@ void AppCache::ToDatabaseRecords( GURL origin = group->manifest_url().GetOrigin(); + for (size_t i = 0; i < intercept_namespaces_.size(); ++i) { + intercepts->push_back(AppCacheDatabase::NamespaceRecord()); + AppCacheDatabase::NamespaceRecord& record = intercepts->back(); + record.cache_id = cache_id_; + record.origin = origin; + record.type = INTERCEPT_NAMESPACE; + record.namespace_url = intercept_namespaces_[i].namespace_url; + record.target_url = intercept_namespaces_[i].target_url; + } + for (size_t i = 0; i < fallback_namespaces_.size(); ++i) { - fallbacks->push_back(AppCacheDatabase::FallbackNameSpaceRecord()); - AppCacheDatabase::FallbackNameSpaceRecord& record = fallbacks->back(); + fallbacks->push_back(AppCacheDatabase::NamespaceRecord()); + AppCacheDatabase::NamespaceRecord& record = fallbacks->back(); record.cache_id = cache_id_; record.origin = origin; - record.namespace_url = fallback_namespaces_[i].first; - record.fallback_entry_url = fallback_namespaces_[i].second; + record.type = FALLBACK_NAMESPACE; + record.namespace_url = fallback_namespaces_[i].namespace_url; + record.target_url = fallback_namespaces_[i].target_url; } if (!online_whitelist_all_) { @@ -216,12 +244,20 @@ bool AppCache::FindResponseForRequest(const GURL& url, return true; } - FallbackNamespace* fallback_namespace = FindFallbackNamespace(url_no_ref); + const Namespace* intercept_namespace = FindInterceptNamespace(url_no_ref); + if (intercept_namespace) { + entry = GetEntry(intercept_namespace->target_url); + DCHECK(entry); + *found_entry = *entry; + return true; + } + + const Namespace* fallback_namespace = FindFallbackNamespace(url_no_ref); if (fallback_namespace) { - entry = GetEntry(fallback_namespace->second); + entry = GetEntry(fallback_namespace->target_url); DCHECK(entry); *found_fallback_entry = *entry; - *found_fallback_namespace = fallback_namespace->first; + *found_fallback_namespace = fallback_namespace->namespace_url; return true; } @@ -229,12 +265,13 @@ bool AppCache::FindResponseForRequest(const GURL& url, return *found_network_namespace; } -FallbackNamespace* AppCache::FindFallbackNamespace(const GURL& url) { - size_t count = fallback_namespaces_.size(); +const Namespace* AppCache::FindNamespace( + const NamespaceVector& namespaces, const GURL& url) { + size_t count = namespaces.size(); for (size_t i = 0; i < count; ++i) { if (StartsWithASCII( - url.spec(), fallback_namespaces_[i].first.spec(), true)) { - return &fallback_namespaces_[i]; + url.spec(), namespaces[i].namespace_url.spec(), true)) { + return &namespaces[i]; } } return NULL; @@ -249,6 +286,7 @@ void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const { info.url = iter->first; info.is_master = iter->second.IsMaster(); info.is_manifest = iter->second.IsManifest(); + info.is_intercept = iter->second.IsIntercept(); info.is_fallback = iter->second.IsFallback(); info.is_foreign = iter->second.IsForeign(); info.is_explicit = iter->second.IsExplicit(); diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h index b273f97..bc42b5f 100644 --- a/webkit/appcache/appcache.h +++ b/webkit/appcache/appcache.h @@ -92,7 +92,8 @@ class APPCACHE_EXPORT AppCache : public base::RefCounted<AppCache> { void InitializeWithDatabaseRecords( const AppCacheDatabase::CacheRecord& cache_record, const std::vector<AppCacheDatabase::EntryRecord>& entries, - const std::vector<AppCacheDatabase::FallbackNameSpaceRecord>& fallbacks, + const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts, + const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks, const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists); // Returns the database records to be stored in the AppCacheDatabase @@ -101,7 +102,8 @@ class APPCACHE_EXPORT AppCache : public base::RefCounted<AppCache> { const AppCacheGroup* group, AppCacheDatabase::CacheRecord* cache_record, std::vector<AppCacheDatabase::EntryRecord>* entries, - std::vector<AppCacheDatabase::FallbackNameSpaceRecord>* fallbacks, + std::vector<AppCacheDatabase::NamespaceRecord>* intercepts, + std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks, std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists); bool FindResponseForRequest(const GURL& url, @@ -128,7 +130,14 @@ class APPCACHE_EXPORT AppCache : public base::RefCounted<AppCache> { void set_owning_group(AppCacheGroup* group) { owning_group_ = group; } // FindResponseForRequest helpers - FallbackNamespace* FindFallbackNamespace(const GURL& url); + const Namespace* FindInterceptNamespace(const GURL& url) { + return FindNamespace(intercept_namespaces_, url); + } + const Namespace* FindFallbackNamespace(const GURL& url) { + return FindNamespace(fallback_namespaces_, url); + } + const Namespace* FindNamespace(const NamespaceVector& namespaces, + const GURL& url); // Use AppCacheHost::Associate*Cache() to manipulate host association. void AssociateHost(AppCacheHost* host) { @@ -142,7 +151,8 @@ class APPCACHE_EXPORT AppCache : public base::RefCounted<AppCache> { EntryMap entries_; // contains entries of all types - std::vector<FallbackNamespace> fallback_namespaces_; + NamespaceVector intercept_namespaces_; + NamespaceVector fallback_namespaces_; std::vector<GURL> online_whitelist_namespaces_; bool online_whitelist_all_; diff --git a/webkit/appcache/appcache_database.cc b/webkit/appcache/appcache_database.cc index 0989259..ec49f88 100644 --- a/webkit/appcache/appcache_database.cc +++ b/webkit/appcache/appcache_database.cc @@ -19,20 +19,29 @@ // Schema ------------------------------------------------------------------- namespace { -const int kCurrentVersion = 3; -const int kCompatibleVersion = 3; +const int kCurrentVersion = 4; +const int kCompatibleVersion = 4; const char kGroupsTable[] = "Groups"; const char kCachesTable[] = "Caches"; const char kEntriesTable[] = "Entries"; -const char kFallbackNameSpacesTable[] = "FallbackNameSpaces"; +const char kNamespacesTable[] = "Namespaces"; const char kOnlineWhiteListsTable[] = "OnlineWhiteLists"; const char kDeletableResponseIdsTable[] = "DeletableResponseIds"; -const struct { +struct TableInfo { const char* table_name; const char* columns; -} kTables[] = { +}; + +struct IndexInfo { + const char* index_name; + const char* table_name; + const char* columns; + bool unique; +}; + +const TableInfo kTables[] = { { kGroupsTable, "(group_id INTEGER PRIMARY KEY," " origin TEXT," @@ -54,11 +63,12 @@ const struct { " response_id INTEGER," " response_size INTEGER)" }, - { kFallbackNameSpacesTable, + { kNamespacesTable, "(cache_id INTEGER," " origin TEXT," // intentionally not normalized + " type INTEGER," " namespace_url TEXT," - " fallback_entry_url TEXT)" }, + " target_url TEXT)" }, { kOnlineWhiteListsTable, "(cache_id INTEGER," @@ -68,12 +78,7 @@ const struct { "(response_id INTEGER NOT NULL)" }, }; -const struct { - const char* index_name; - const char* table_name; - const char* columns; - bool unique; -} kIndexes[] = { +const IndexInfo kIndexes[] = { { "GroupsOriginIndex", kGroupsTable, "(origin)", @@ -104,18 +109,18 @@ const struct { "(response_id)", true }, - { "FallbackNameSpacesCacheIndex", - kFallbackNameSpacesTable, + { "NamespacesCacheIndex", + kNamespacesTable, "(cache_id)", false }, - { "FallbackNameSpacesOriginIndex", - kFallbackNameSpacesTable, + { "NamespacesOriginIndex", + kNamespacesTable, "(origin)", false }, - { "FallbackNameSpacesCacheAndUrlIndex", - kFallbackNameSpacesTable, + { "NamespacesCacheAndUrlIndex", + kNamespacesTable, "(cache_id, namespace_url)", true }, @@ -142,6 +147,26 @@ sql::ErrorDelegate* GetErrorHandlerForAppCacheDb() { return new sql::DiagnosticErrorDelegate<HistogramUniquifier>(); } +bool CreateTable(sql::Connection* db, const TableInfo& info) { + std::string sql("CREATE TABLE "); + sql += info.table_name; + sql += info.columns; + return db->Execute(sql.c_str()); +} + +bool CreateIndex(sql::Connection* db, const IndexInfo& info) { + std::string sql; + if (info.unique) + sql += "CREATE UNIQUE INDEX "; + else + sql += "CREATE INDEX "; + sql += info.index_name; + sql += " ON "; + sql += info.table_name; + sql += info.columns; + return db->Execute(sql.c_str()); +} + } // anon namespace // AppCacheDatabase ---------------------------------------------------------- @@ -154,13 +179,14 @@ AppCacheDatabase::GroupRecord::GroupRecord() AppCacheDatabase::GroupRecord::~GroupRecord() { } -AppCacheDatabase::FallbackNameSpaceRecord::FallbackNameSpaceRecord() - : cache_id(0) { +AppCacheDatabase::NamespaceRecord::NamespaceRecord() + : cache_id(0), type(FALLBACK_NAMESPACE) { } -AppCacheDatabase::FallbackNameSpaceRecord::~FallbackNameSpaceRecord() { +AppCacheDatabase::NamespaceRecord::~NamespaceRecord() { } + AppCacheDatabase::AppCacheDatabase(const FilePath& path) : db_file_path_(path), is_disabled_(false), is_recreating_(false) { } @@ -655,61 +681,59 @@ bool AppCacheDatabase::AddEntryFlags( return statement.Run() && db_->GetLastChangeCount(); } -bool AppCacheDatabase::FindFallbackNameSpacesForOrigin( - const GURL& origin, std::vector<FallbackNameSpaceRecord>* records) { - DCHECK(records && records->empty()); +bool AppCacheDatabase::FindNamespacesForOrigin( + const GURL& origin, + std::vector<NamespaceRecord>* intercepts, + std::vector<NamespaceRecord>* fallbacks) { + DCHECK(intercepts && intercepts->empty()); + DCHECK(fallbacks && fallbacks->empty()); if (!LazyOpen(false)) return false; const char* kSql = - "SELECT cache_id, origin, namespace_url, fallback_entry_url" - " FROM FallbackNameSpaces WHERE origin = ?"; + "SELECT cache_id, origin, type, namespace_url, target_url" + " FROM Namespaces WHERE origin = ?"; sql::Statement statement; if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) return false; statement.BindString(0, origin.spec()); - while (statement.Step()) { - records->push_back(FallbackNameSpaceRecord()); - ReadFallbackNameSpaceRecord(statement, &records->back()); - DCHECK(records->back().origin == origin); - } + ReadNamespaceRecords(&statement, intercepts, fallbacks); return statement.Succeeded(); } -bool AppCacheDatabase::FindFallbackNameSpacesForCache( - int64 cache_id, std::vector<FallbackNameSpaceRecord>* records) { - DCHECK(records && records->empty()); +bool AppCacheDatabase::FindNamespacesForCache( + int64 cache_id, + std::vector<NamespaceRecord>* intercepts, + std::vector<NamespaceRecord>* fallbacks) { + DCHECK(intercepts && intercepts->empty()); + DCHECK(fallbacks && fallbacks->empty()); if (!LazyOpen(false)) return false; const char* kSql = - "SELECT cache_id, origin, namespace_url, fallback_entry_url" - " FROM FallbackNameSpaces WHERE cache_id = ?"; + "SELECT cache_id, origin, type, namespace_url, target_url" + " FROM Namespaces WHERE cache_id = ?"; sql::Statement statement; if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) return false; statement.BindInt64(0, cache_id); - while (statement.Step()) { - records->push_back(FallbackNameSpaceRecord()); - ReadFallbackNameSpaceRecord(statement, &records->back()); - DCHECK(records->back().cache_id == cache_id); - } + ReadNamespaceRecords(&statement, intercepts, fallbacks); return statement.Succeeded(); } -bool AppCacheDatabase::InsertFallbackNameSpace( - const FallbackNameSpaceRecord* record) { +bool AppCacheDatabase::InsertNamespace( + const NamespaceRecord* record) { if (!LazyOpen(true)) return false; const char* kSql = - "INSERT INTO FallbackNameSpaces" - " (cache_id, origin, namespace_url, fallback_entry_url)" - " VALUES (?, ?, ?, ?)"; + "INSERT INTO Namespaces" + " (cache_id, origin, type, namespace_url, target_url)" + " VALUES (?, ?, ?, ?, ?)"; sql::Statement statement; if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) @@ -717,33 +741,34 @@ bool AppCacheDatabase::InsertFallbackNameSpace( statement.BindInt64(0, record->cache_id); statement.BindString(1, record->origin.spec()); - statement.BindString(2, record->namespace_url.spec()); - statement.BindString(3, record->fallback_entry_url.spec()); + statement.BindInt(2, record->type); + statement.BindString(3, record->namespace_url.spec()); + statement.BindString(4, record->target_url.spec()); return statement.Run(); } -bool AppCacheDatabase::InsertFallbackNameSpaceRecords( - const std::vector<FallbackNameSpaceRecord>& records) { +bool AppCacheDatabase::InsertNamespaceRecords( + const std::vector<NamespaceRecord>& records) { if (records.empty()) return true; sql::Transaction transaction(db_.get()); if (!transaction.Begin()) return false; - std::vector<FallbackNameSpaceRecord>::const_iterator iter = records.begin(); + std::vector<NamespaceRecord>::const_iterator iter = records.begin(); while (iter != records.end()) { - if (!InsertFallbackNameSpace(&(*iter))) + if (!InsertNamespace(&(*iter))) return false; ++iter; } return transaction.Commit(); } -bool AppCacheDatabase::DeleteFallbackNameSpacesForCache(int64 cache_id) { +bool AppCacheDatabase::DeleteNamespacesForCache(int64 cache_id) { if (!LazyOpen(false)) return false; const char* kSql = - "DELETE FROM FallbackNameSpaces WHERE cache_id = ?"; + "DELETE FROM Namespaces WHERE cache_id = ?"; sql::Statement statement; if (!PrepareCachedStatement(SQL_FROM_HERE, kSql, &statement)) @@ -974,12 +999,26 @@ void AppCacheDatabase::ReadEntryRecord( record->response_size = statement.ColumnInt64(4); } -void AppCacheDatabase::ReadFallbackNameSpaceRecord( - const sql::Statement& statement, FallbackNameSpaceRecord* record) { - record->cache_id = statement.ColumnInt64(0); - record->origin = GURL(statement.ColumnString(1)); - record->namespace_url = GURL(statement.ColumnString(2)); - record->fallback_entry_url = GURL(statement.ColumnString(3)); +void AppCacheDatabase::ReadNamespaceRecords( + sql::Statement* statement, + NamespaceRecordVector* intercepts, + NamespaceRecordVector* fallbacks) { + while (statement->Step()) { + NamespaceType type = static_cast<NamespaceType>(statement->ColumnInt(2)); + NamespaceRecordVector* records = + (type == FALLBACK_NAMESPACE) ? fallbacks : intercepts; + records->push_back(NamespaceRecord()); + ReadNamespaceRecord(statement, &records->back()); + } +} + +void AppCacheDatabase::ReadNamespaceRecord( + const sql::Statement* statement, NamespaceRecord* record) { + record->cache_id = statement->ColumnInt64(0); + record->origin = GURL(statement->ColumnString(1)); + record->type = static_cast<NamespaceType>(statement->ColumnInt(2)); + record->namespace_url = GURL(statement->ColumnString(3)); + record->target_url = GURL(statement->ColumnString(4)); } void AppCacheDatabase::ReadOnlineWhiteListRecord( @@ -1060,6 +1099,9 @@ bool AppCacheDatabase::EnsureDatabaseVersion() { for (int i = 0; i < kTableCount; ++i) { DCHECK(db_->DoesTableExist(kTables[i].table_name)); } + for (int i = 0; i < kIndexCount; ++i) { + DCHECK(db_->DoesIndexExist(kIndexes[i].index_name)); + } #endif return true; @@ -1074,24 +1116,12 @@ bool AppCacheDatabase::CreateSchema() { return false; for (int i = 0; i < kTableCount; ++i) { - std::string sql("CREATE TABLE "); - sql += kTables[i].table_name; - sql += kTables[i].columns; - if (!db_->Execute(sql.c_str())) + if (!CreateTable(db_.get(), kTables[i])) return false; } for (int i = 0; i < kIndexCount; ++i) { - std::string sql; - if (kIndexes[i].unique) - sql += "CREATE UNIQUE INDEX "; - else - sql += "CREATE INDEX "; - sql += kIndexes[i].index_name; - sql += " ON "; - sql += kIndexes[i].table_name; - sql += kIndexes[i].columns; - if (!db_->Execute(sql.c_str())) + if (!CreateIndex(db_.get(), kIndexes[i])) return false; } @@ -1099,7 +1129,45 @@ bool AppCacheDatabase::CreateSchema() { } bool AppCacheDatabase::UpgradeSchema() { - // Upgrade logic goes here + if (meta_table_->GetVersionNumber() == 3) { + DCHECK_EQ(strcmp(kNamespacesTable, kTables[3].table_name), 0); + DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[6].table_name), 0); + DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[7].table_name), 0); + DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[8].table_name), 0); + + // Migrate from the old "FallbackNameSpaces" to the new "Namespaces" table. + sql::Transaction transaction(db_.get()); + if (!transaction.Begin() || + !CreateTable(db_.get(), kTables[3])) { + return false; + } + + // Move data from the old table to the new table, setting the + // 'type' for all current records to the value for FALLBACK_NAMESPACE. + DCHECK_EQ(0, static_cast<int>(FALLBACK_NAMESPACE)); + if (!db_->Execute( + "INSERT INTO Namespaces" + " SELECT cache_id, origin, 0, namespace_url, fallback_entry_url" + " FROM FallbackNameSpaces")) { + return false; + } + + // Drop the old table, indexes on that table are also removed by this. + if (!db_->Execute("DROP TABLE FallbackNameSpaces")) + return false; + + // Create new indexes. + if (!CreateIndex(db_.get(), kIndexes[6]) || + !CreateIndex(db_.get(), kIndexes[7]) || + !CreateIndex(db_.get(), kIndexes[8])) { + return false; + } + + // Finally bump the version numbers and commit it. + meta_table_->SetVersionNumber(4); + meta_table_->SetCompatibleVersionNumber(4); + return transaction.Commit(); + } // If there is no upgrade path for the version on disk to the current // version, nuke everything and start over. diff --git a/webkit/appcache/appcache_database.h b/webkit/appcache/appcache_database.h index c6a6c3f..7e1044d 100644 --- a/webkit/appcache/appcache_database.h +++ b/webkit/appcache/appcache_database.h @@ -16,6 +16,7 @@ #include "base/time.h" #include "googleurl/src/gurl.h" #include "webkit/appcache/appcache_export.h" +#include "webkit/appcache/appcache_interfaces.h" namespace sql { class Connection; @@ -60,16 +61,19 @@ class APPCACHE_EXPORT AppCacheDatabase { int64 response_size; }; - struct APPCACHE_EXPORT FallbackNameSpaceRecord { - FallbackNameSpaceRecord(); - ~FallbackNameSpaceRecord(); + struct APPCACHE_EXPORT NamespaceRecord { + NamespaceRecord(); + ~NamespaceRecord(); int64 cache_id; - GURL origin; // intentionally not normalized + GURL origin; + NamespaceType type; GURL namespace_url; - GURL fallback_entry_url; + GURL target_url; }; + typedef std::vector<NamespaceRecord> NamespaceRecordVector; + struct OnlineWhiteListRecord { OnlineWhiteListRecord() : cache_id(0) {} @@ -129,14 +133,18 @@ class APPCACHE_EXPORT AppCacheDatabase { return FindResponseIdsForCacheHelper(cache_id, NULL, response_ids); } - bool FindFallbackNameSpacesForOrigin( - const GURL& origin, std::vector<FallbackNameSpaceRecord>* records); - bool FindFallbackNameSpacesForCache( - int64 cache_id, std::vector<FallbackNameSpaceRecord>* records); - bool InsertFallbackNameSpace(const FallbackNameSpaceRecord* record); - bool InsertFallbackNameSpaceRecords( - const std::vector<FallbackNameSpaceRecord>& records); - bool DeleteFallbackNameSpacesForCache(int64 cache_id); + bool FindNamespacesForOrigin( + const GURL& origin, + NamespaceRecordVector* intercepts, + NamespaceRecordVector* fallbacks); + bool FindNamespacesForCache( + int64 cache_id, + NamespaceRecordVector* intercepts, + std::vector<NamespaceRecord>* fallbacks); + bool InsertNamespaceRecords( + const NamespaceRecordVector& records); + bool InsertNamespace(const NamespaceRecord* record); + bool DeleteNamespacesForCache(int64 cache_id); bool FindOnlineWhiteListForCache( int64 cache_id, std::vector<OnlineWhiteListRecord>* records); @@ -174,8 +182,12 @@ class APPCACHE_EXPORT AppCacheDatabase { void ReadGroupRecord(const sql::Statement& statement, GroupRecord* record); void ReadCacheRecord(const sql::Statement& statement, CacheRecord* record); void ReadEntryRecord(const sql::Statement& statement, EntryRecord* record); - void ReadFallbackNameSpaceRecord( - const sql::Statement& statement, FallbackNameSpaceRecord* record); + void ReadNamespaceRecords( + sql::Statement* statement, + NamespaceRecordVector* intercepts, + NamespaceRecordVector* fallbacks); + void ReadNamespaceRecord( + const sql::Statement* statement, NamespaceRecord* record); void ReadOnlineWhiteListRecord( const sql::Statement& statement, OnlineWhiteListRecord* record); @@ -200,13 +212,14 @@ class APPCACHE_EXPORT AppCacheDatabase { FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, CacheRecords); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, EntryRecords); - FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, FallbackNameSpaceRecords); + FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, NamespaceRecords); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, GroupRecords); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, LazyOpen); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, OnlineWhiteListRecords); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, ReCreate); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, DeletableResponseIds); FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, OriginUsage); + FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, UpgradeSchema3to4); DISALLOW_COPY_AND_ASSIGN(AppCacheDatabase); }; diff --git a/webkit/appcache/appcache_database_unittest.cc b/webkit/appcache/appcache_database_unittest.cc index 8f82314..014a569 100644 --- a/webkit/appcache/appcache_database_unittest.cc +++ b/webkit/appcache/appcache_database_unittest.cc @@ -6,7 +6,11 @@ #include "base/file_util.h" #include "base/scoped_temp_dir.h" +#include "base/stringprintf.h" #include "sql/connection.h" +#include "sql/meta_table.h" +#include "sql/statement.h" +#include "sql/transaction.h" #include "webkit/appcache/appcache_database.h" #include "webkit/appcache/appcache_entry.h" @@ -322,7 +326,7 @@ TEST(AppCacheDatabaseTest, GroupRecords) { EXPECT_EQ(kOrigin2, record.origin); } -TEST(AppCacheDatabaseTest, FallbackNameSpaceRecords) { +TEST(AppCacheDatabaseTest, NamespaceRecords) { const FilePath kEmptyPath; AppCacheDatabase db(kEmptyPath); EXPECT_TRUE(db.LazyOpen(true)); @@ -339,87 +343,88 @@ TEST(AppCacheDatabaseTest, FallbackNameSpaceRecords) { const GURL kBarFallbackEntry("http://bar/entry"); const GURL kBarOrigin(kBarNameSpace1.GetOrigin()); - const AppCacheDatabase::FallbackNameSpaceRecord kZeroRecord; - AppCacheDatabase::FallbackNameSpaceRecord record; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> records; + const AppCacheDatabase::NamespaceRecord kZeroRecord; + AppCacheDatabase::NamespaceRecord record; + std::vector<AppCacheDatabase::NamespaceRecord> intercepts; + std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; // Behavior with an empty table - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(1, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_TRUE(records.empty()); - EXPECT_TRUE(db.DeleteFallbackNameSpacesForCache(1)); + EXPECT_TRUE(db.FindNamespacesForCache(1, &intercepts, &fallbacks)); + EXPECT_TRUE(fallbacks.empty()); + EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); + EXPECT_TRUE(fallbacks.empty()); + EXPECT_TRUE(db.DeleteNamespacesForCache(1)); // Two records for two differenent caches in the Foo origin. record.cache_id = 1; record.origin = kFooOrigin; record.namespace_url = kFooNameSpace1; - record.fallback_entry_url = kFooFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - EXPECT_FALSE(db.InsertFallbackNameSpace(&record)); + record.target_url = kFooFallbackEntry; + EXPECT_TRUE(db.InsertNamespace(&record)); + EXPECT_FALSE(db.InsertNamespace(&record)); record.cache_id = 2; record.origin = kFooOrigin; record.namespace_url = kFooNameSpace2; - record.fallback_entry_url = kFooFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(1, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(1, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(2, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(2, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace2, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_EQ(2U, records.size()); - EXPECT_EQ(1, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); - EXPECT_EQ(2, records[1].cache_id); - EXPECT_EQ(kFooOrigin, records[1].origin); - EXPECT_EQ(kFooNameSpace2, records[1].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[1].fallback_entry_url); - - EXPECT_TRUE(db.DeleteFallbackNameSpacesForCache(1)); - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kFooOrigin, &records)); - EXPECT_EQ(1U, records.size()); - EXPECT_EQ(2, records[0].cache_id); - EXPECT_EQ(kFooOrigin, records[0].origin); - EXPECT_EQ(kFooNameSpace2, records[0].namespace_url); - EXPECT_EQ(kFooFallbackEntry, records[0].fallback_entry_url); + record.target_url = kFooFallbackEntry; + EXPECT_TRUE(db.InsertNamespace(&record)); + + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForCache(1, &intercepts, &fallbacks)); + EXPECT_EQ(1U, fallbacks.size()); + EXPECT_EQ(1, fallbacks[0].cache_id); + EXPECT_EQ(kFooOrigin, fallbacks[0].origin); + EXPECT_EQ(kFooNameSpace1, fallbacks[0].namespace_url); + EXPECT_EQ(kFooFallbackEntry, fallbacks[0].target_url); + + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForCache(2, &intercepts, &fallbacks)); + EXPECT_EQ(1U, fallbacks.size()); + EXPECT_EQ(2, fallbacks[0].cache_id); + EXPECT_EQ(kFooOrigin, fallbacks[0].origin); + EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_url); + EXPECT_EQ(kFooFallbackEntry, fallbacks[0].target_url); + + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); + EXPECT_EQ(2U, fallbacks.size()); + EXPECT_EQ(1, fallbacks[0].cache_id); + EXPECT_EQ(kFooOrigin, fallbacks[0].origin); + EXPECT_EQ(kFooNameSpace1, fallbacks[0].namespace_url); + EXPECT_EQ(kFooFallbackEntry, fallbacks[0].target_url); + EXPECT_EQ(2, fallbacks[1].cache_id); + EXPECT_EQ(kFooOrigin, fallbacks[1].origin); + EXPECT_EQ(kFooNameSpace2, fallbacks[1].namespace_url); + EXPECT_EQ(kFooFallbackEntry, fallbacks[1].target_url); + + EXPECT_TRUE(db.DeleteNamespacesForCache(1)); + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); + EXPECT_EQ(1U, fallbacks.size()); + EXPECT_EQ(2, fallbacks[0].cache_id); + EXPECT_EQ(kFooOrigin, fallbacks[0].origin); + EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_url); + EXPECT_EQ(kFooFallbackEntry, fallbacks[0].target_url); // Two more records for the same cache in the Bar origin. record.cache_id = 3; record.origin = kBarOrigin; record.namespace_url = kBarNameSpace1; - record.fallback_entry_url = kBarFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); + record.target_url = kBarFallbackEntry; + EXPECT_TRUE(db.InsertNamespace(&record)); record.cache_id = 3; record.origin = kBarOrigin; record.namespace_url = kBarNameSpace2; - record.fallback_entry_url = kBarFallbackEntry; - EXPECT_TRUE(db.InsertFallbackNameSpace(&record)); - - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForCache(3, &records)); - EXPECT_EQ(2U, records.size()); - records.clear(); - EXPECT_TRUE(db.FindFallbackNameSpacesForOrigin(kBarOrigin, &records)); - EXPECT_EQ(2U, records.size()); + record.target_url = kBarFallbackEntry; + EXPECT_TRUE(db.InsertNamespace(&record)); + + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForCache(3, &intercepts, &fallbacks)); + EXPECT_EQ(2U, fallbacks.size()); + fallbacks.clear(); + EXPECT_TRUE(db.FindNamespacesForOrigin(kBarOrigin, &intercepts, &fallbacks)); + EXPECT_EQ(2U, fallbacks.size()); } TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) { @@ -613,4 +618,220 @@ TEST(AppCacheDatabaseTest, OriginUsage) { EXPECT_EQ(5000, usage_map[kOtherOrigin]); } +TEST(AppCacheDatabaseTest, UpgradeSchema3to4) { + // Real file on disk for this test. + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + const FilePath kDbFile = temp_dir.path().AppendASCII("upgrade.db"); + + const GURL kMockOrigin("http://mockorigin/"); + const char kNamespaceUrlFormat[] = "namespace%d"; + const char kTargetUrlFormat[] = "target%d"; + const int kNumNamespaces = 10; + + // Create a v3 schema based database containing some fallback records. + { + const int kVersion3 = 3; + const char kGroupsTable[] = "Groups"; + const char kCachesTable[] = "Caches"; + const char kEntriesTable[] = "Entries"; + const char kFallbackNameSpacesTable[] = "FallbackNameSpaces"; + const char kOnlineWhiteListsTable[] = "OnlineWhiteLists"; + const char kDeletableResponseIdsTable[] = "DeletableResponseIds"; + + const struct { + const char* table_name; + const char* columns; + } kTables3[] = { + { kGroupsTable, + "(group_id INTEGER PRIMARY KEY," + " origin TEXT," + " manifest_url TEXT," + " creation_time INTEGER," + " last_access_time INTEGER)" }, + + { kCachesTable, + "(cache_id INTEGER PRIMARY KEY," + " group_id INTEGER," + " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1))," + " update_time INTEGER," + " cache_size INTEGER)" }, // intentionally not normalized + + { kEntriesTable, + "(cache_id INTEGER," + " url TEXT," + " flags INTEGER," + " response_id INTEGER," + " response_size INTEGER)" }, + + { kFallbackNameSpacesTable, + "(cache_id INTEGER," + " origin TEXT," // intentionally not normalized + " namespace_url TEXT," + " fallback_entry_url TEXT)" }, + + { kOnlineWhiteListsTable, + "(cache_id INTEGER," + " namespace_url TEXT)" }, + + { kDeletableResponseIdsTable, + "(response_id INTEGER NOT NULL)" }, + }; + + const struct { + const char* index_name; + const char* table_name; + const char* columns; + bool unique; + } kIndexes3[] = { + { "GroupsOriginIndex", + kGroupsTable, + "(origin)", + false }, + + { "GroupsManifestIndex", + kGroupsTable, + "(manifest_url)", + true }, + + { "CachesGroupIndex", + kCachesTable, + "(group_id)", + false }, + + { "EntriesCacheIndex", + kEntriesTable, + "(cache_id)", + false }, + + { "EntriesCacheAndUrlIndex", + kEntriesTable, + "(cache_id, url)", + true }, + + { "EntriesResponseIdIndex", + kEntriesTable, + "(response_id)", + true }, + + { "FallbackNameSpacesCacheIndex", + kFallbackNameSpacesTable, + "(cache_id)", + false }, + + { "FallbackNameSpacesOriginIndex", + kFallbackNameSpacesTable, + "(origin)", + false }, + + { "FallbackNameSpacesCacheAndUrlIndex", + kFallbackNameSpacesTable, + "(cache_id, namespace_url)", + true }, + + { "OnlineWhiteListCacheIndex", + kOnlineWhiteListsTable, + "(cache_id)", + false }, + + { "DeletableResponsesIdIndex", + kDeletableResponseIdsTable, + "(response_id)", + true }, + }; + + const int kTableCount3 = ARRAYSIZE_UNSAFE(kTables3); + const int kIndexCount3 = ARRAYSIZE_UNSAFE(kIndexes3); + + sql::Connection connection; + EXPECT_TRUE(connection.Open(kDbFile)); + + sql::Transaction transaction(&connection); + EXPECT_TRUE(transaction.Begin()); + + sql::MetaTable meta_table; + EXPECT_TRUE(meta_table.Init(&connection, kVersion3, kVersion3)); + + for (int i = 0; i < kTableCount3; ++i) { + std::string sql("CREATE TABLE "); + sql += kTables3[i].table_name; + sql += kTables3[i].columns; + EXPECT_TRUE(connection.Execute(sql.c_str())); + } + + for (int i = 0; i < kIndexCount3; ++i) { + std::string sql; + if (kIndexes3[i].unique) + sql += "CREATE UNIQUE INDEX "; + else + sql += "CREATE INDEX "; + sql += kIndexes3[i].index_name; + sql += " ON "; + sql += kIndexes3[i].table_name; + sql += kIndexes3[i].columns; + EXPECT_TRUE(connection.Execute(sql.c_str())); + } + + const char* kSql = + "INSERT INTO FallbackNameSpaces" + " (cache_id, origin, namespace_url, fallback_entry_url)" + " VALUES (?, ?, ?, ?)"; + + sql::Statement statement; + statement.Assign(connection.GetUniqueStatement(kSql)); + EXPECT_TRUE(statement.is_valid()); + for (int i = 0; i < kNumNamespaces; ++i) { + GURL namespace_url( + kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); + GURL target_url( + kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); + statement.BindInt64(0, i); + statement.BindString(1, kMockOrigin.spec().c_str()); + statement.BindString(2, namespace_url.spec().c_str()); + statement.BindString(3, target_url.spec().c_str()); + ASSERT_TRUE(statement.Run()); + statement.Reset(); + } + + EXPECT_TRUE(transaction.Commit()); + } + + // Open that database and verify that it got updated. + AppCacheDatabase db(kDbFile); + EXPECT_TRUE(db.LazyOpen(true)); + + EXPECT_FALSE(db.db_->DoesTableExist("FallbackNameSpaces")); + EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNamesSpacesCacheIndex")); + EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesOriginIndex")); + EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesCacheAndUrlIndex")); + + EXPECT_TRUE(db.db_->DoesTableExist("Namespaces")); + EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheIndex")); + EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesOriginIndex")); + EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheAndUrlIndex")); + + EXPECT_EQ(4, db.meta_table_->GetVersionNumber()); + EXPECT_EQ(4, db.meta_table_->GetCompatibleVersionNumber()); + + std::vector<AppCacheDatabase::NamespaceRecord> intercepts; + std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; + EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts, + &fallbacks)); + EXPECT_TRUE(intercepts.empty()); + EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size())); + + for (int i = 0; i < kNumNamespaces; ++i) { + GURL expected_namespace_url( + kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); + GURL expected_target_url( + kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); + + EXPECT_EQ(i, fallbacks[i].cache_id); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].type); + EXPECT_EQ(kMockOrigin, fallbacks[i].origin); + EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_url); + EXPECT_EQ(expected_target_url, fallbacks[i].target_url); + } +} + } // namespace appcache diff --git a/webkit/appcache/appcache_entry.h b/webkit/appcache/appcache_entry.h index 71239e2..2b38a25 100644 --- a/webkit/appcache/appcache_entry.h +++ b/webkit/appcache/appcache_entry.h @@ -22,6 +22,7 @@ class AppCacheEntry { EXPLICIT = 1 << 2, FOREIGN = 1 << 3, FALLBACK = 1 << 4, + INTERCEPT = 1 << 5, }; AppCacheEntry() @@ -43,6 +44,7 @@ class AppCacheEntry { bool IsExplicit() const { return (types_ & EXPLICIT) != 0; } bool IsForeign() const { return (types_ & FOREIGN) != 0; } bool IsFallback() const { return (types_ & FALLBACK) != 0; } + bool IsIntercept() const { return (types_ & INTERCEPT) != 0; } int64 response_id() const { return response_id_; } void set_response_id(int64 id) { response_id_ = id; } diff --git a/webkit/appcache/appcache_interfaces.cc b/webkit/appcache/appcache_interfaces.cc index e5cf2c4..aac9766 100644 --- a/webkit/appcache/appcache_interfaces.cc +++ b/webkit/appcache/appcache_interfaces.cc @@ -35,17 +35,30 @@ AppCacheInfo::~AppCacheInfo() { AppCacheResourceInfo::AppCacheResourceInfo() : url(), size(0), - is_master(0), - is_manifest(0), - is_fallback(0), - is_foreign(0), - is_explicit(0), + is_master(false), + is_manifest(false), + is_intercept(false), + is_fallback(false), + is_foreign(false), + is_explicit(false), response_id(kNoResponseId) { } AppCacheResourceInfo::~AppCacheResourceInfo() { } +Namespace::Namespace() + : type(FALLBACK_NAMESPACE) { +} + +Namespace::Namespace(NamespaceType type, const GURL& url, const GURL& target) + : type(type), namespace_url(url), target_url(target) { +} + +Namespace::~Namespace() { +} + + bool IsSchemeSupported(const GURL& url) { bool supported = url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme); #ifndef NDEBUG diff --git a/webkit/appcache/appcache_interfaces.h b/webkit/appcache/appcache_interfaces.h index 489d12f..113fe47 100644 --- a/webkit/appcache/appcache_interfaces.h +++ b/webkit/appcache/appcache_interfaces.h @@ -54,6 +54,11 @@ enum LogLevel { LOG_ERROR, }; +enum NamespaceType { + FALLBACK_NAMESPACE, + INTERCEPT_NAMESPACE +}; + struct APPCACHE_EXPORT AppCacheInfo { AppCacheInfo(); ~AppCacheInfo(); @@ -80,6 +85,7 @@ struct APPCACHE_EXPORT AppCacheResourceInfo { int64 size; bool is_master; bool is_manifest; + bool is_intercept; bool is_fallback; bool is_foreign; bool is_explicit; @@ -88,6 +94,18 @@ struct APPCACHE_EXPORT AppCacheResourceInfo { typedef std::vector<AppCacheResourceInfo> AppCacheResourceInfoVector; +struct APPCACHE_EXPORT Namespace { + Namespace(); // Type is set to FALLBACK_NAMESPACE by default. + Namespace(NamespaceType type, const GURL& url, const GURL& target); + ~Namespace(); + + NamespaceType type; + GURL namespace_url; + GURL target_url; +}; + +typedef std::vector<Namespace> NamespaceVector; + // Interface used by backend (browser-process) to talk to frontend (renderer). class APPCACHE_EXPORT AppCacheFrontend { public: diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc index 8363052..b374093 100644 --- a/webkit/appcache/appcache_storage_impl.cc +++ b/webkit/appcache/appcache_storage_impl.cc @@ -62,7 +62,7 @@ bool DeleteGroupAndRelatedRecords(AppCacheDatabase* database, database->DeleteGroup(group_id) && database->DeleteCache(cache_record.cache_id) && database->DeleteEntriesForCache(cache_record.cache_id) && - database->DeleteFallbackNameSpacesForCache(cache_record.cache_id) && + database->DeleteNamespacesForCache(cache_record.cache_id) && database->DeleteOnlineWhiteListForCache(cache_record.cache_id) && database->InsertDeletableResponseIds(*deletable_response_ids); } else { @@ -375,7 +375,9 @@ class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask { AppCacheDatabase::GroupRecord group_record_; AppCacheDatabase::CacheRecord cache_record_; std::vector<AppCacheDatabase::EntryRecord> entry_records_; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> + std::vector<AppCacheDatabase::NamespaceRecord> + intercept_namespace_records_; + std::vector<AppCacheDatabase::NamespaceRecord> fallback_namespace_records_; std::vector<AppCacheDatabase::OnlineWhiteListRecord> online_whitelist_records_; @@ -384,8 +386,9 @@ class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask { bool AppCacheStorageImpl::StoreOrLoadTask::FindRelatedCacheRecords( int64 cache_id) { return database_->FindEntriesForCache(cache_id, &entry_records_) && - database_->FindFallbackNameSpacesForCache( - cache_id, &fallback_namespace_records_) && + database_->FindNamespacesForCache( + cache_id, &intercept_namespace_records_, + &fallback_namespace_records_) && database_->FindOnlineWhiteListForCache( cache_id, &online_whitelist_records_); } @@ -405,7 +408,9 @@ void AppCacheStorageImpl::StoreOrLoadTask::CreateCacheAndGroupFromRecords( (*cache) = new AppCache(storage_->service_, cache_record_.cache_id); cache->get()->InitializeWithDatabaseRecords( - cache_record_, entry_records_, fallback_namespace_records_, + cache_record_, entry_records_, + intercept_namespace_records_, + fallback_namespace_records_, online_whitelist_records_); cache->get()->set_complete(true); @@ -554,7 +559,9 @@ AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask( group_record_.origin = group_record_.manifest_url.GetOrigin(); newest_cache->ToDatabaseRecords( group, - &cache_record_, &entry_records_, &fallback_namespace_records_, + &cache_record_, &entry_records_, + &intercept_namespace_records_, + &fallback_namespace_records_, &online_whitelist_records_); } @@ -644,7 +651,7 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { success_ = database_->DeleteCache(cache.cache_id) && database_->DeleteEntriesForCache(cache.cache_id) && - database_->DeleteFallbackNameSpacesForCache(cache.cache_id) && + database_->DeleteNamespacesForCache(cache.cache_id) && database_->DeleteOnlineWhiteListForCache(cache.cache_id) && database_->InsertDeletableResponseIds(newly_deletable_response_ids_); // TODO(michaeln): store group_id too with deletable ids @@ -657,7 +664,8 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() { success_ && database_->InsertCache(&cache_record_) && database_->InsertEntryRecords(entry_records_) && - database_->InsertFallbackNameSpaceRecords(fallback_namespace_records_)&& + database_->InsertNamespaceRecords(intercept_namespace_records_) && + database_->InsertNamespaceRecords(fallback_namespace_records_) && database_->InsertOnlineWhiteListRecords(online_whitelist_records_); if (!success_) @@ -726,49 +734,6 @@ void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() { // FindMainResponseTask ------- -class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { - public: - FindMainResponseTask(AppCacheStorageImpl* storage, - const GURL& url, - const GURL& preferred_manifest_url, - const AppCacheWorkingSet::GroupMap* groups_in_use) - : DatabaseTask(storage), url_(url), - preferred_manifest_url_(preferred_manifest_url), - cache_id_(kNoCacheId), group_id_(0) { - 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; - cache_ids_in_use_.insert(cache->cache_id()); - } - } - } - - 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_; - GURL fallback_url_; - int64 cache_id_; - int64 group_id_; - GURL manifest_url_; -}; - // Helpers for FindMainResponseTask::Run() namespace { class SortByCachePreference @@ -798,8 +763,8 @@ class SortByCachePreference }; bool SortByLength( - const AppCacheDatabase::FallbackNameSpaceRecord& lhs, - const AppCacheDatabase::FallbackNameSpaceRecord& rhs) { + const AppCacheDatabase::NamespaceRecord& lhs, + const AppCacheDatabase::NamespaceRecord& rhs) { return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length(); } @@ -843,6 +808,55 @@ class NetworkNamespaceHelper { } // namespace +class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask { + public: + FindMainResponseTask(AppCacheStorageImpl* storage, + const GURL& url, + const GURL& preferred_manifest_url, + const AppCacheWorkingSet::GroupMap* groups_in_use) + : DatabaseTask(storage), url_(url), + preferred_manifest_url_(preferred_manifest_url), + cache_id_(kNoCacheId), group_id_(0) { + 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; + cache_ids_in_use_.insert(cache->cache_id()); + } + } + } + + virtual void Run(); + virtual void RunCompleted(); + + private: + typedef std::vector<AppCacheDatabase::NamespaceRecord*> + NamespaceRecordPtrVector; + bool FindExactMatch(int64 preferred_id); + bool FindNamespaceMatch(int64 preferred_id); + bool FindNamespaceHelper( + int64 preferred_cache_id, + AppCacheDatabase::NamespaceRecordVector* namespaces, + NetworkNamespaceHelper* network_namespace_helper); + bool FindFirstValidNamespace(const NamespaceRecordPtrVector& namespaces); + + GURL url_; + GURL preferred_manifest_url_; + std::set<int64> cache_ids_in_use_; + AppCacheEntry entry_; + AppCacheEntry fallback_entry_; + GURL fallback_url_; + int64 cache_id_; + int64 group_id_; + GURL manifest_url_; +}; + + + void AppCacheStorageImpl::FindMainResponseTask::Run() { // NOTE: The heuristics around choosing amoungst multiple candidates // is underspecified, and just plain not fully understood. This needs @@ -868,10 +882,8 @@ void AppCacheStorageImpl::FindMainResponseTask::Run() { } } - // TODO(michaeln): Also lookup matches in intercept namespaces. - // http://code.google.com/p/chromium/issues/detail?id=101565 if (FindExactMatch(preferred_cache_id) || - FindFallback(preferred_cache_id)) { + FindNamespaceMatch(preferred_cache_id)) { // We found something. DCHECK(cache_id_ != kNoCacheId && !manifest_url_.is_empty() && group_id_ != 0); @@ -911,46 +923,62 @@ FindMainResponseTask::FindExactMatch(int64 preferred_cache_id) { } bool AppCacheStorageImpl:: -FindMainResponseTask::FindFallback(int64 preferred_cache_id) { - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> all_fallbacks; - if (!database_->FindFallbackNameSpacesForOrigin( - url_.GetOrigin(), &all_fallbacks) - || all_fallbacks.empty()) { +FindMainResponseTask::FindNamespaceMatch(int64 preferred_cache_id) { + AppCacheDatabase::NamespaceRecordVector all_intercepts; + AppCacheDatabase::NamespaceRecordVector all_fallbacks; + if (!database_->FindNamespacesForOrigin( + url_.GetOrigin(), &all_intercepts, &all_fallbacks) + || (all_intercepts.empty() && all_fallbacks.empty())) { return false; } + NetworkNamespaceHelper network_namespace_helper(database_); + if (FindNamespaceHelper(preferred_cache_id, + &all_intercepts, + &network_namespace_helper) || + FindNamespaceHelper(preferred_cache_id, + &all_fallbacks, + &network_namespace_helper)) { + return true; + } + return false; +} + +bool AppCacheStorageImpl:: +FindMainResponseTask::FindNamespaceHelper( + int64 preferred_cache_id, + AppCacheDatabase::NamespaceRecordVector* namespaces, + NetworkNamespaceHelper* network_namespace_helper) { // Sort them by length, longer matches within the same cache/bucket take // precedence. - std::sort(all_fallbacks.begin(), all_fallbacks.end(), SortByLength); + std::sort(namespaces->begin(), namespaces->end(), SortByLength); - // Filter the list and bin them into buckets. - NetworkNamespaceHelper network_namespace_helper(database_); - 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) { + NamespaceRecordPtrVector preferred_namespaces; + NamespaceRecordPtrVector inuse_namespaces; + NamespaceRecordPtrVector other_namespaces; + std::vector<AppCacheDatabase::NamespaceRecord>::iterator iter; + for (iter = namespaces->begin(); iter < namespaces->end(); ++iter) { // Skip those that aren't a prefix match. if (!StartsWithASCII(url_.spec(), iter->namespace_url.spec(), true)) continue; - // Skip fallback namespaces where the requested url falls into a network + // Skip namespaces where the requested url falls into a network // namespace of its containing appcache. - if (network_namespace_helper.IsInNetworkNamespace(url_, iter->cache_id)) + if (network_namespace_helper->IsInNetworkNamespace(url_, iter->cache_id)) continue; // Bin them into one of our three buckets. if (iter->cache_id == preferred_cache_id) - preferred_fallbacks.push_back(&(*iter)); + preferred_namespaces.push_back(&(*iter)); else if (cache_ids_in_use_.find(iter->cache_id) != cache_ids_in_use_.end()) - inuse_fallbacks.push_back(&(*iter)); + inuse_namespaces.push_back(&(*iter)); else - other_fallbacks.push_back(&(*iter)); + other_namespaces.push_back(&(*iter)); } - if (FindFirstValidFallback(preferred_fallbacks) || - FindFirstValidFallback(inuse_fallbacks) || - FindFirstValidFallback(other_fallbacks)) + if (FindFirstValidNamespace(preferred_namespaces) || + FindFirstValidNamespace(inuse_namespaces) || + FindFirstValidNamespace(other_namespaces)) return true; // We found one. // We didn't find anything. @@ -958,13 +986,13 @@ FindMainResponseTask::FindFallback(int64 preferred_cache_id) { } bool AppCacheStorageImpl:: -FindMainResponseTask::FindFirstValidFallback( - const FallbackNameSpaceVector& fallbacks) { +FindMainResponseTask::FindFirstValidNamespace( + const NamespaceRecordPtrVector& namespaces) { // Take the first with a valid, non-foreign entry. - FallbackNameSpaceVector::const_iterator iter; - for (iter = fallbacks.begin(); iter < fallbacks.end(); ++iter) { + NamespaceRecordPtrVector::const_iterator iter; + for (iter = namespaces.begin(); iter < namespaces.end(); ++iter) { AppCacheDatabase::EntryRecord entry_record; - if (database_->FindEntry((*iter)->cache_id, (*iter)->fallback_entry_url, + if (database_->FindEntry((*iter)->cache_id, (*iter)->target_url, &entry_record)) { AppCacheDatabase::GroupRecord group_record; if ((entry_record.flags & AppCacheEntry::FOREIGN) || @@ -974,9 +1002,13 @@ FindMainResponseTask::FindFirstValidFallback( manifest_url_ = group_record.manifest_url; group_id_ = group_record.group_id; cache_id_ = (*iter)->cache_id; - fallback_url_ = (*iter)->fallback_entry_url; - fallback_entry_ = AppCacheEntry( - entry_record.flags, entry_record.response_id); + if ((*iter)->type == FALLBACK_NAMESPACE) { + fallback_url_ = (*iter)->target_url; + fallback_entry_ = AppCacheEntry( + entry_record.flags, entry_record.response_id); + } else { + entry_ = AppCacheEntry(entry_record.flags, entry_record.response_id); + } return true; // We found one. } } diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc index c0540af..cfaabf2 100644 --- a/webkit/appcache/appcache_storage_impl_unittest.cc +++ b/webkit/appcache/appcache_storage_impl_unittest.cc @@ -36,6 +36,9 @@ const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test"); const GURL kOnlineNamespace("http://blah/online_namespace"); const GURL kOnlineNamespaceWithinFallback( "http://blah/fallback_namespace/online/"); +const GURL kInterceptNamespace("http://blah/intercept_namespace/"); +const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/"); +const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test"); const GURL kOrigin(kManifestUrl.GetOrigin()); const int kManifestEntryIdOffset = 100; @@ -668,13 +671,12 @@ class AppCacheStorageImplTest : public testing::Test { entry_record.url = kEntryUrl; EXPECT_TRUE(database()->InsertEntry(&entry_record)); - AppCacheDatabase::FallbackNameSpaceRecord fallback_namespace_record; + AppCacheDatabase::NamespaceRecord fallback_namespace_record; fallback_namespace_record.cache_id = 1; - fallback_namespace_record.fallback_entry_url = kEntryUrl; + fallback_namespace_record.target_url = kEntryUrl; fallback_namespace_record.namespace_url = kFallbackNamespace; fallback_namespace_record.origin = kManifestUrl.GetOrigin(); - EXPECT_TRUE( - database()->InsertFallbackNameSpace(&fallback_namespace_record)); + EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record)); AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record; online_whitelist_record.cache_id = 1; @@ -702,8 +704,10 @@ class AppCacheStorageImplTest : public testing::Test { std::vector<AppCacheDatabase::EntryRecord> entry_records; database()->FindEntriesForCache(1, &entry_records); EXPECT_TRUE(entry_records.empty()); - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallback_records; - database()->FindFallbackNameSpacesForCache(1, &fallback_records); + std::vector<AppCacheDatabase::NamespaceRecord> intercept_records; + std::vector<AppCacheDatabase::NamespaceRecord> fallback_records; + database()->FindNamespacesForCache( + 1, &intercept_records, &fallback_records); EXPECT_TRUE(fallback_records.empty()); std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records; database()->FindOnlineWhiteListForCache(1, &whitelist_records); @@ -889,26 +893,27 @@ class AppCacheStorageImplTest : public testing::Test { cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1)); cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2)); cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace2, kEntryUrl2)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2)); cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace, kEntryUrl)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl)); AppCacheDatabase::CacheRecord cache_record; std::vector<AppCacheDatabase::EntryRecord> entries; - std::vector<AppCacheDatabase::FallbackNameSpaceRecord> fallbacks; + std::vector<AppCacheDatabase::NamespaceRecord> intercepts; + std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; cache_->ToDatabaseRecords(group_, - &cache_record, &entries, &fallbacks, &whitelists); + &cache_record, &entries, &intercepts, &fallbacks, &whitelists); std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = entries.begin(); while (iter != entries.end()) { - // MakeCacheAndGroup has inserted the default entry record already + // MakeCacheAndGroup has inserted the default entry record already. if (iter->url != kDefaultEntryUrl) EXPECT_TRUE(database()->InsertEntry(&(*iter))); ++iter; } - EXPECT_TRUE(database()->InsertFallbackNameSpaceRecords(fallbacks)); + EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks)); EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); if (drop_from_working_set) { EXPECT_TRUE(cache_->HasOneRef()); @@ -935,6 +940,73 @@ class AppCacheStorageImplTest : public testing::Test { TestFinished(); } + // BasicFindMainInterceptResponse ------------------------------- + + void BasicFindMainInterceptResponseInDatabase() { + BasicFindMainInterceptResponse(true); + } + + void BasicFindMainInterceptResponseInWorkingSet() { + BasicFindMainInterceptResponse(false); + } + + void BasicFindMainInterceptResponse(bool drop_from_working_set) { + PushNextTask(base::Bind( + &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse, + base::Unretained(this))); + + // Setup some preconditions. Create a complete cache with an + // intercept namespace and entry. + MakeCacheAndGroup(kManifestUrl, 2, 1, true); + cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1)); + cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2)); + cache_->intercept_namespaces_.push_back( + Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2, kEntryUrl2)); + cache_->intercept_namespaces_.push_back( + Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace, kEntryUrl)); + AppCacheDatabase::CacheRecord cache_record; + std::vector<AppCacheDatabase::EntryRecord> entries; + std::vector<AppCacheDatabase::NamespaceRecord> intercepts; + std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; + std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; + cache_->ToDatabaseRecords(group_, + &cache_record, &entries, &intercepts, &fallbacks, &whitelists); + + std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter = + entries.begin(); + while (iter != entries.end()) { + // MakeCacheAndGroup has inserted the default entry record already + if (iter->url != kDefaultEntryUrl) + EXPECT_TRUE(database()->InsertEntry(&(*iter))); + ++iter; + } + + EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts)); + EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists)); + if (drop_from_working_set) { + EXPECT_TRUE(cache_->HasOneRef()); + cache_ = NULL; + EXPECT_TRUE(group_->HasOneRef()); + group_ = NULL; + } + + // Conduct the test. The test url is in both intercept namespaces, + // but should match the longer of the two. + storage()->FindResponseForMainRequest( + kInterceptTestUrl, GURL(), delegate()); + EXPECT_NE(kInterceptTestUrl, delegate()->found_url_); + } + + void Verify_BasicFindMainInterceptResponse() { + EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_); + EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_); + EXPECT_EQ(1, delegate()->found_cache_id_); + EXPECT_EQ(2, delegate()->found_group_id_); + EXPECT_EQ(2, delegate()->found_entry_.response_id()); + EXPECT_TRUE(delegate()->found_entry_.IsIntercept()); + EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id()); + TestFinished(); + } // FindMainResponseWithMultipleHits ------------------------------- void FindMainResponseWithMultipleHits() { @@ -988,15 +1060,14 @@ class AppCacheStorageImplTest : public testing::Test { cache_->AddEntry( entry_record.url, AppCacheEntry(entry_record.flags, entry_record.response_id)); - AppCacheDatabase::FallbackNameSpaceRecord fallback_namespace_record; + AppCacheDatabase::NamespaceRecord fallback_namespace_record; fallback_namespace_record.cache_id = id; - fallback_namespace_record.fallback_entry_url = entry_record.url; + fallback_namespace_record.target_url = entry_record.url; fallback_namespace_record.namespace_url = kFallbackNamespace; fallback_namespace_record.origin = manifest_url.GetOrigin(); - EXPECT_TRUE( - database()->InsertFallbackNameSpace(&fallback_namespace_record)); + EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record)); cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace, kEntryUrl2)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2)); } void Verify_FindMainResponseWithMultipleHits() { @@ -1109,7 +1180,7 @@ class AppCacheStorageImplTest : public testing::Test { cache_->online_whitelist_namespaces_.push_back(kOnlineNamespace); cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2)); cache_->fallback_namespaces_.push_back( - FallbackNamespace(kFallbackNamespace, kEntryUrl2)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2)); cache_->online_whitelist_namespaces_.push_back(kOnlineNamespace); cache_->online_whitelist_namespaces_.push_back( kOnlineNamespaceWithinFallback); @@ -1124,13 +1195,12 @@ class AppCacheStorageImplTest : public testing::Test { whitelist_record.cache_id = 1; whitelist_record.namespace_url = kOnlineNamespace; EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record)); - AppCacheDatabase::FallbackNameSpaceRecord fallback_namespace_record; + AppCacheDatabase::NamespaceRecord fallback_namespace_record; fallback_namespace_record.cache_id = 1; - fallback_namespace_record.fallback_entry_url = kEntryUrl2; + fallback_namespace_record.target_url = kEntryUrl2; fallback_namespace_record.namespace_url = kFallbackNamespace; fallback_namespace_record.origin = kManifestUrl.GetOrigin(); - EXPECT_TRUE( - database()->InsertFallbackNameSpace(&fallback_namespace_record)); + EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record)); whitelist_record.cache_id = 1; whitelist_record.namespace_url = kOnlineNamespaceWithinFallback; EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record)); @@ -1320,6 +1390,16 @@ TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) { &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet); } +TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) { + RunTestOnIOThread( + &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase); +} + +TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) { + RunTestOnIOThread( + &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet); +} + TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) { RunTestOnIOThread( &AppCacheStorageImplTest::FindMainResponseWithMultipleHits); diff --git a/webkit/appcache/appcache_unittest.cc b/webkit/appcache/appcache_unittest.cc index ecb29fe..2b1bb83 100644 --- a/webkit/appcache/appcache_unittest.cc +++ b/webkit/appcache/appcache_unittest.cc @@ -88,18 +88,19 @@ TEST(AppCacheTest, InitializeWithManifest) { manifest.explicit_urls.insert("http://one.com"); manifest.explicit_urls.insert("http://two.com"); manifest.fallback_namespaces.push_back( - FallbackNamespace(GURL("http://fb1.com"), GURL("http://fbone.com"))); + Namespace(FALLBACK_NAMESPACE, GURL("http://fb1.com"), + GURL("http://fbone.com"))); manifest.online_whitelist_namespaces.push_back(GURL("http://w1.com")); manifest.online_whitelist_namespaces.push_back(GURL("http://w2.com")); manifest.online_whitelist_all = true; cache->InitializeWithManifest(&manifest); - const std::vector<FallbackNamespace>& fallbacks = + const std::vector<Namespace>& fallbacks = cache->fallback_namespaces_; size_t expected = 1; EXPECT_EQ(expected, fallbacks.size()); - EXPECT_EQ(GURL("http://fb1.com"), fallbacks[0].first); - EXPECT_EQ(GURL("http://fbone.com"), fallbacks[0].second); + EXPECT_EQ(GURL("http://fb1.com"), fallbacks[0].namespace_url); + EXPECT_EQ(GURL("http://fbone.com"), fallbacks[0].target_url); const std::vector<GURL>& whitelist = cache->online_whitelist_namespaces_; expected = 2; EXPECT_EQ(expected, whitelist.size()); @@ -129,23 +130,36 @@ TEST(AppCacheTest, FindResponseForRequest) { "http://blah/online_namespace/explicit"); const GURL kFallbackTestUrl1("http://blah/fallback_namespace/1"); const GURL kFallbackTestUrl2("http://blah/fallback_namespace/longer2"); - const GURL kOnlineNamespaceWithinFallback( - "http://blah/fallback_namespace/1/online"); + const GURL kInterceptNamespace("http://blah/intercept_namespace/"); + const GURL kInterceptNamespaceWithinFallback( + "http://blah/fallback_namespace/intercept_namespace/"); + const GURL kInterceptNamespaceEntry("http://blah/intercept_entry"); + const GURL kOnlineNamespaceWithinOtherNamespaces( + "http://blah/fallback_namespace/intercept_namespace/1/online"); const int64 kFallbackResponseId1 = 1; const int64 kFallbackResponseId2 = 2; const int64 kManifestResponseId = 3; const int64 kForeignExplicitResponseId = 4; const int64 kExplicitInOnlineNamespaceResponseId = 5; + const int64 kInterceptResponseId = 6; Manifest manifest; manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl); manifest.online_whitelist_namespaces.push_back( - kOnlineNamespaceWithinFallback); + kOnlineNamespaceWithinOtherNamespaces); manifest.fallback_namespaces.push_back( - FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl1, + kFallbackEntryUrl1)); manifest.fallback_namespaces.push_back( - FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl2, + kFallbackEntryUrl2)); + manifest.intercept_namespaces.push_back( + Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace, + kInterceptNamespaceEntry)); + manifest.intercept_namespaces.push_back( + Namespace(INTERCEPT_NAMESPACE, kInterceptNamespaceWithinFallback, + kInterceptNamespaceEntry)); // Create a cache with some namespaces and entries. scoped_refptr<AppCache> cache(new AppCache(&service, 1234)); @@ -167,6 +181,9 @@ TEST(AppCacheTest, FindResponseForRequest) { kExplicitInOnlineNamespaceUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, kExplicitInOnlineNamespaceResponseId)); + cache->AddEntry( + kInterceptNamespaceEntry, + AppCacheEntry(AppCacheEntry::INTERCEPT, kInterceptResponseId)); cache->set_complete(true); // See that we get expected results from FindResponseForRequest @@ -239,7 +256,7 @@ TEST(AppCacheTest, FindResponseForRequest) { fallback_entry = AppCacheEntry(); // reset - found = cache->FindResponseForRequest(kOnlineNamespaceWithinFallback, + found = cache->FindResponseForRequest(kOnlineNamespaceWithinOtherNamespaces, &entry, &fallback_entry, &fallback_namespace, &network_namespace); EXPECT_TRUE(found); EXPECT_FALSE(entry.has_response_id()); @@ -249,12 +266,30 @@ TEST(AppCacheTest, FindResponseForRequest) { fallback_entry = AppCacheEntry(); // reset found = cache->FindResponseForRequest( - kOnlineNamespaceWithinFallback.Resolve("online_resource"), + kOnlineNamespaceWithinOtherNamespaces.Resolve("online_resource"), &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); + + found = cache->FindResponseForRequest( + kInterceptNamespace.Resolve("intercept_me"), + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_EQ(kInterceptResponseId, entry.response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_FALSE(network_namespace); + + entry = AppCacheEntry(); // reset + + found = cache->FindResponseForRequest( + kInterceptNamespaceWithinFallback.Resolve("intercept_me"), + &entry, &fallback_entry, &fallback_namespace, &network_namespace); + EXPECT_TRUE(found); + EXPECT_EQ(kInterceptResponseId, entry.response_id()); + EXPECT_FALSE(fallback_entry.has_response_id()); + EXPECT_FALSE(network_namespace); } } // namespace appacache diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc index d4a8ab6..572ba75 100644 --- a/webkit/appcache/appcache_update_job.cc +++ b/webkit/appcache/appcache_update_job.cc @@ -869,14 +869,18 @@ void AppCacheUpdateJob::BuildUrlFileList(const Manifest& manifest) { AddUrlToFileList(GURL(*it), AppCacheEntry::EXPLICIT); } - // TODO(michaeln): Add resources from intercept namepsaces too. - // http://code.google.com/p/chromium/issues/detail?id=101565 + const std::vector<Namespace>& intercepts = + manifest.intercept_namespaces; + for (std::vector<Namespace>::const_iterator it = intercepts.begin(); + it != intercepts.end(); ++it) { + AddUrlToFileList(it->target_url, AppCacheEntry::INTERCEPT); + } - const std::vector<FallbackNamespace>& fallbacks = + const std::vector<Namespace>& fallbacks = manifest.fallback_namespaces; - for (std::vector<FallbackNamespace>::const_iterator it = fallbacks.begin(); + for (std::vector<Namespace>::const_iterator it = fallbacks.begin(); it != fallbacks.end(); ++it) { - AddUrlToFileList(it->second, AppCacheEntry::FALLBACK); + AddUrlToFileList(it->target_url, AppCacheEntry::FALLBACK); } // Add all master entries from newest complete cache. diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc index 4a18caa..47b1d42 100644 --- a/webkit/appcache/appcache_update_job_unittest.cc +++ b/webkit/appcache/appcache_update_job_unittest.cc @@ -114,6 +114,9 @@ class MockHttpServer { } else if (path == "/files/fallback1a") { (*headers) = std::string(ok_headers, arraysize(ok_headers)); (*body) = "fallback1a"; + } else if (path == "/files/intercept1a") { + (*headers) = std::string(ok_headers, arraysize(ok_headers)); + (*body) = "intercept1a"; } else if (path == "/files/gone") { (*headers) = std::string(gone_headers, arraysize(gone_headers)); (*body) = ""; @@ -156,6 +159,11 @@ class MockHttpServer { "fallback1 fallback1a\n" "NETWORK:\n" "online1\n"; + } else if (path == "/files/manifest-with-intercept") { + (*headers) = std::string(manifest_headers, arraysize(manifest_headers)); + (*body) = "CACHE MANIFEST\n" + "CHROMIUM-INTERCEPT:\n" + "intercept1 return intercept1a\n"; } else if (path == "/files/notmodified") { (*headers) = std::string(not_modified_headers, arraysize(not_modified_headers)); @@ -191,6 +199,12 @@ class MockHttpServerJobFactory } }; +inline bool operator==(const Namespace& lhs, const Namespace& rhs) { + return lhs.type == rhs.type && + lhs.namespace_url == rhs.namespace_url && + lhs.target_url == rhs.target_url; +} + } // namespace class MockFrontend : public AppCacheFrontend { @@ -1012,6 +1026,33 @@ class AppCacheUpdateJobTest : public testing::Test, WaitForUpdateToFinish(); } + void DownloadInterceptEntriesTest() { + // Ensures we download intercept entries too. + ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()); + GURL manifest_url = MockHttpServer::GetMockUrl( + "files/manifest-with-intercept"); + MakeService(); + group_ = new AppCacheGroup( + service_.get(), manifest_url, + service_->storage()->NewGroupId()); + AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_); + group_->update_job_ = update; + + MockFrontend* frontend = MakeMockFrontend(); + AppCacheHost* host = MakeHost(1, frontend); + update->StartUpdate(host, GURL()); + + // Set up checks for when update job finishes. + do_checks_after_update_finished_ = true; + expect_group_obsolete_ = false; + expect_group_has_cache_ = true; + tested_manifest_ = MANIFEST_WITH_INTERCEPT; + frontend->AddExpectedEvent(MockFrontend::HostIds(1, host->host_id()), + CHECKING_EVENT); + + WaitForUpdateToFinish(); + } + void BasicUpgradeSuccessTest() { ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()); @@ -3010,6 +3051,9 @@ class AppCacheUpdateJobTest : public testing::Test, case PENDING_MASTER_NO_UPDATE: VerifyMasterEntryNoUpdate(cache); break; + case MANIFEST_WITH_INTERCEPT: + VerifyManifestWithIntercept(cache); + break; case NONE: default: break; @@ -3043,13 +3087,12 @@ class AppCacheUpdateJobTest : public testing::Test, } expected = 1; - EXPECT_EQ(expected, cache->fallback_namespaces_.size()); - EXPECT_TRUE(cache->fallback_namespaces_.end() != - std::find(cache->fallback_namespaces_.begin(), - cache->fallback_namespaces_.end(), - FallbackNamespace( - MockHttpServer::GetMockUrl("files/fallback1"), - MockHttpServer::GetMockUrl("files/fallback1a")))); + ASSERT_EQ(expected, cache->fallback_namespaces_.size()); + EXPECT_TRUE(cache->fallback_namespaces_[0] == + Namespace( + FALLBACK_NAMESPACE, + MockHttpServer::GetMockUrl("files/fallback1"), + MockHttpServer::GetMockUrl("files/fallback1a"))); EXPECT_TRUE(cache->online_whitelist_namespaces_.empty()); EXPECT_TRUE(cache->online_whitelist_all_); @@ -3071,13 +3114,12 @@ class AppCacheUpdateJobTest : public testing::Test, AppCacheEntry::MASTER, entry->types()); expected = 1; - EXPECT_EQ(expected, cache->fallback_namespaces_.size()); - EXPECT_TRUE(cache->fallback_namespaces_.end() != - std::find(cache->fallback_namespaces_.begin(), - cache->fallback_namespaces_.end(), - FallbackNamespace( - MockHttpServer::GetMockUrl("files/fallback1"), - MockHttpServer::GetMockUrl("files/explicit1")))); + ASSERT_EQ(expected, cache->fallback_namespaces_.size()); + EXPECT_TRUE(cache->fallback_namespaces_[0] == + Namespace( + FALLBACK_NAMESPACE, + MockHttpServer::GetMockUrl("files/fallback1"), + MockHttpServer::GetMockUrl("files/explicit1"))); EXPECT_EQ(expected, cache->online_whitelist_namespaces_.size()); EXPECT_TRUE(cache->online_whitelist_namespaces_.end() != @@ -3153,6 +3195,21 @@ class AppCacheUpdateJobTest : public testing::Test, EXPECT_TRUE(cache->update_time_ > base::Time()); } + void VerifyManifestWithIntercept(AppCache* cache) { + EXPECT_EQ(2u, cache->entries().size()); + const char* kManifestPath = "files/manifest-with-intercept"; + AppCacheEntry* entry = + cache->GetEntry(MockHttpServer::GetMockUrl(kManifestPath)); + ASSERT_TRUE(entry); + EXPECT_EQ(AppCacheEntry::MANIFEST, entry->types()); + entry = cache->GetEntry(MockHttpServer::GetMockUrl("files/intercept1a")); + ASSERT_TRUE(entry); + EXPECT_TRUE(entry->IsIntercept()); + EXPECT_TRUE(cache->online_whitelist_namespaces_.empty()); + EXPECT_FALSE(cache->online_whitelist_all_); + EXPECT_TRUE(cache->update_time_ > base::Time()); + } + private: // Various manifest files used in this test. enum TestedManifest { @@ -3162,6 +3219,7 @@ class AppCacheUpdateJobTest : public testing::Test, EMPTY_MANIFEST, EMPTY_FILE_MANIFEST, PENDING_MASTER_NO_UPDATE, + MANIFEST_WITH_INTERCEPT }; scoped_ptr<IOThread> io_thread_; @@ -3307,6 +3365,10 @@ TEST_F(AppCacheUpdateJobTest, BasicCacheAttemptSuccess) { RunTestOnIOThread(&AppCacheUpdateJobTest::BasicCacheAttemptSuccessTest); } +TEST_F(AppCacheUpdateJobTest, DownloadInterceptEntriesTest) { + RunTestOnIOThread(&AppCacheUpdateJobTest::DownloadInterceptEntriesTest); +} + TEST_F(AppCacheUpdateJobTest, BasicUpgradeSuccess) { RunTestOnIOThread(&AppCacheUpdateJobTest::BasicUpgradeSuccessTest); } diff --git a/webkit/appcache/manifest_parser.cc b/webkit/appcache/manifest_parser.cc index 07125b7..eb16d8b 100644 --- a/webkit/appcache/manifest_parser.cc +++ b/webkit/appcache/manifest_parser.cc @@ -40,6 +40,7 @@ namespace appcache { enum Mode { EXPLICIT, + INTERCEPT, FALLBACK, ONLINE_WHITELIST, UNKNOWN, @@ -60,6 +61,8 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, const wchar_t kSignature[] = L"CACHE MANIFEST"; const size_t kSignatureLength = arraysize(kSignature) - 1; + const wchar_t kChromiumSignature[] = L"CHROMIUM CACHE MANIFEST"; + const size_t kChromiumSignatureLength = arraysize(kChromiumSignature) - 1; DCHECK(manifest.explicit_urls.empty()); DCHECK(manifest.fallback_namespaces.empty()); @@ -89,12 +92,19 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, ++p; } - if (p >= end || - data_string.compare(bom_offset, kSignatureLength, kSignature)) { + if (p >= end) return false; - } - p += kSignatureLength; // Skip past "CACHE MANIFEST" + // Check for a supported signature and skip p past it. + if (0 == data_string.compare(bom_offset, kSignatureLength, + kSignature)) { + p += kSignatureLength; + } else if (0 == data_string.compare(bom_offset, kChromiumSignatureLength, + kChromiumSignature)) { + p += kChromiumSignatureLength; + } else { + return false; + } // Character after "CACHE MANIFEST" must be whitespace. if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') @@ -135,6 +145,8 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, mode = FALLBACK; } else if (line == L"NETWORK:") { mode = ONLINE_WHITELIST; + } else if (line == L"CHROMIUM-INTERCEPT:") { + mode = INTERCEPT; } else if (*(line.end() - 1) == ':') { mode = UNKNOWN; } else if (mode == UNKNOWN) { @@ -179,6 +191,75 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, } else { manifest.online_whitelist_namespaces.push_back(url); } + } else if (mode == INTERCEPT) { + // Lines of the form, + // <urlnamespace> <intercept_type> <targeturl> + const wchar_t* line_p = line.c_str(); + const wchar_t* line_end = line_p + line.length(); + + // Look for first whitespace separating the url namespace from + // the intercept type. + while (line_p < line_end && *line_p != '\t' && *line_p != ' ') + ++line_p; + + if (line_p == line_end) + continue; // There was no whitespace separating the URLs. + + string16 namespace_url16; + WideToUTF16(line.c_str(), line_p - line.c_str(), &namespace_url16); + GURL namespace_url = manifest_url.Resolve(namespace_url16); + if (!namespace_url.is_valid()) + continue; + if (namespace_url.has_ref()) { + GURL::Replacements replacements; + replacements.ClearRef(); + namespace_url = namespace_url.ReplaceComponents(replacements); + } + + // The namespace URL must have the same scheme, host and port + // as the manifest's URL. + if (manifest_url.GetOrigin() != namespace_url.GetOrigin()) + continue; + + // Skip whitespace separating namespace from the type. + while (line_p < line_end && (*line_p == '\t' || *line_p == ' ')) + ++line_p; + + // Look for whitespace separating the type from the target url. + const wchar_t* type_start = line_p; + while (line_p < line_end && *line_p != '\t' && *line_p != ' ') + ++line_p; + + // Look for a type value we understand, otherwise skip the line. + std::wstring type(type_start, line_p - type_start); + if (type != L"return") + continue; + + // Skip whitespace separating type from the target_url. + while (line_p < line_end && (*line_p == '\t' || *line_p == ' ')) + ++line_p; + + // Look for whitespace separating the URL from subsequent ignored tokens. + const wchar_t* target_url_start = line_p; + while (line_p < line_end && *line_p != '\t' && *line_p != ' ') + ++line_p; + + string16 target_url16; + WideToUTF16(target_url_start, line_p - target_url_start, &target_url16); + GURL target_url = manifest_url.Resolve(target_url16); + if (!target_url.is_valid()) + continue; + + if (target_url.has_ref()) { + GURL::Replacements replacements; + replacements.ClearRef(); + target_url = target_url.ReplaceComponents(replacements); + } + if (manifest_url.GetOrigin() != target_url.GetOrigin()) + continue; + + manifest.intercept_namespaces.push_back( + Namespace(INTERCEPT_NAMESPACE, namespace_url, target_url)); } else if (mode == FALLBACK) { const wchar_t* line_p = line.c_str(); const wchar_t* line_end = line_p + line.length(); @@ -238,7 +319,7 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length, // Store regardless of duplicate namespace URL. Only first match // will ever be used. manifest.fallback_namespaces.push_back( - FallbackNamespace(namespace_url, fallback_url)); + Namespace(FALLBACK_NAMESPACE, namespace_url, fallback_url)); } else { NOTREACHED(); } diff --git a/webkit/appcache/manifest_parser.h b/webkit/appcache/manifest_parser.h index cd1d569..a612e6a 100644 --- a/webkit/appcache/manifest_parser.h +++ b/webkit/appcache/manifest_parser.h @@ -37,19 +37,19 @@ #include "base/hash_tables.h" #include "webkit/appcache/appcache_export.h" +#include "webkit/appcache/appcache_interfaces.h" class GURL; namespace appcache { -typedef std::pair<GURL, GURL> FallbackNamespace; - struct APPCACHE_EXPORT Manifest { Manifest(); ~Manifest(); base::hash_set<std::string> explicit_urls; - std::vector<FallbackNamespace> fallback_namespaces; + NamespaceVector intercept_namespaces; + NamespaceVector fallback_namespaces; std::vector<GURL> online_whitelist_namespaces; bool online_whitelist_all; }; diff --git a/webkit/appcache/manifest_parser_unittest.cc b/webkit/appcache/manifest_parser_unittest.cc index 2e9c573..eaafffa 100644 --- a/webkit/appcache/manifest_parser_unittest.cc +++ b/webkit/appcache/manifest_parser_unittest.cc @@ -10,17 +10,17 @@ namespace appcache { -class ManifestParserTest : public testing::Test { +class AppCacheManifestParserTest : public testing::Test { }; -TEST(ManifestParserTest, NoData) { +TEST(AppCacheManifestParserTest, NoData) { GURL url; Manifest manifest; EXPECT_FALSE(ParseManifest(url, "", 0, manifest)); EXPECT_FALSE(ParseManifest(url, "CACHE MANIFEST\r", 0, manifest)); // 0 len } -TEST(ManifestParserTest, CheckSignature) { +TEST(AppCacheManifestParserTest, CheckSignature) { GURL url; Manifest manifest; @@ -48,6 +48,7 @@ TEST(ManifestParserTest, CheckSignature) { "CACHE MANIFEST\r\n", "CACHE MANIFEST\t# ignore me\r", "CACHE MANIFEST ignore\r\n", + "CHROMIUM CACHE MANIFEST\r\n", "\xEF\xBB\xBF" "CACHE MANIFEST \r\n", // BOM present }; @@ -57,7 +58,7 @@ TEST(ManifestParserTest, CheckSignature) { } } -TEST(ManifestParserTest, NoManifestUrl) { +TEST(AppCacheManifestParserTest, NoManifestUrl) { Manifest manifest; const std::string kData("CACHE MANIFEST\r" "relative/tobase.com\r" @@ -70,7 +71,7 @@ TEST(ManifestParserTest, NoManifestUrl) { EXPECT_FALSE(manifest.online_whitelist_all); } -TEST(ManifestParserTest, ExplicitUrls) { +TEST(AppCacheManifestParserTest, ExplicitUrls) { Manifest manifest; const GURL kUrl("http://www.foo.com"); const std::string kData("CACHE MANIFEST\r" @@ -107,7 +108,7 @@ TEST(ManifestParserTest, ExplicitUrls) { EXPECT_TRUE(urls.find("http://www.foo.com/*") != urls.end()); } -TEST(ManifestParserTest, WhitelistUrls) { +TEST(AppCacheManifestParserTest, WhitelistUrls) { Manifest manifest; const GURL kUrl("http://www.bar.com"); const std::string kData("CACHE MANIFEST\r" @@ -130,6 +131,7 @@ TEST(ManifestParserTest, WhitelistUrls) { EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(), manifest)); EXPECT_TRUE(manifest.explicit_urls.empty()); EXPECT_TRUE(manifest.fallback_namespaces.empty()); + EXPECT_TRUE(manifest.intercept_namespaces.empty()); EXPECT_FALSE(manifest.online_whitelist_all); std::vector<GURL> online = manifest.online_whitelist_namespaces; @@ -143,7 +145,7 @@ TEST(ManifestParserTest, WhitelistUrls) { EXPECT_EQ(GURL("http://www.bar.com/*foo"), online[5]); } -TEST(ManifestParserTest, FallbackUrls) { +TEST(AppCacheManifestParserTest, FallbackUrls) { Manifest manifest; const GURL kUrl("http://glorp.com"); const std::string kData("CACHE MANIFEST\r" @@ -174,32 +176,39 @@ TEST(ManifestParserTest, FallbackUrls) { EXPECT_TRUE(manifest.online_whitelist_namespaces.empty()); EXPECT_FALSE(manifest.online_whitelist_all); - std::vector<FallbackNamespace> fallbacks = manifest.fallback_namespaces; + const NamespaceVector& fallbacks = manifest.fallback_namespaces; const size_t kExpected = 5; ASSERT_EQ(kExpected, fallbacks.size()); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[0].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[1].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[2].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[3].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[4].type); EXPECT_EQ(GURL("http://glorp.com/relative/one"), - fallbacks[0].first); + fallbacks[0].namespace_url); EXPECT_EQ(GURL("http://glorp.com/onefb"), - fallbacks[0].second); + fallbacks[0].target_url); EXPECT_EQ(GURL("http://glorp.com/two"), - fallbacks[1].first); + fallbacks[1].namespace_url); EXPECT_EQ(GURL("http://glorp.com/relative/twofb"), - fallbacks[1].second); + fallbacks[1].target_url); EXPECT_EQ(GURL("http://glorp.com/three"), - fallbacks[2].first); + fallbacks[2].namespace_url); EXPECT_EQ(GURL("http://glorp.com/relative/threefb"), - fallbacks[2].second); + fallbacks[2].target_url); EXPECT_EQ(GURL("http://glorp.com/three"), // duplicates are stored - fallbacks[3].first); + fallbacks[3].namespace_url); EXPECT_EQ(GURL("http://glorp.com/three-dup"), - fallbacks[3].second); + fallbacks[3].target_url); EXPECT_EQ(GURL("http://glorp.com/relative/four"), - fallbacks[4].first); + fallbacks[4].namespace_url); EXPECT_EQ(GURL("http://glorp.com/relative/fourfb"), - fallbacks[4].second); + fallbacks[4].target_url); + + EXPECT_TRUE(manifest.intercept_namespaces.empty()); } -TEST(ManifestParserTest, FallbackUrlsWithPort) { +TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) { Manifest manifest; const GURL kUrl("http://www.portme.com:1234"); const std::string kData("CACHE MANIFEST\r" @@ -217,24 +226,70 @@ TEST(ManifestParserTest, FallbackUrlsWithPort) { EXPECT_TRUE(manifest.online_whitelist_namespaces.empty()); EXPECT_FALSE(manifest.online_whitelist_all); - std::vector<FallbackNamespace> fallbacks = manifest.fallback_namespaces; + const NamespaceVector& fallbacks = manifest.fallback_namespaces; const size_t kExpected = 3; ASSERT_EQ(kExpected, fallbacks.size()); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[0].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[1].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[2].type); EXPECT_EQ(GURL("http://www.portme.com:1234/one"), - fallbacks[0].first); + fallbacks[0].namespace_url); EXPECT_EQ(GURL("http://www.portme.com:1234/relative/onefb"), - fallbacks[0].second); + fallbacks[0].target_url); EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"), - fallbacks[1].first); + fallbacks[1].namespace_url); EXPECT_EQ(GURL("http://www.portme.com:1234/relative/twofb"), - fallbacks[1].second); + fallbacks[1].target_url); EXPECT_EQ(GURL("http://www.portme.com:1234/three"), - fallbacks[2].first); + fallbacks[2].namespace_url); EXPECT_EQ(GURL("http://www.portme.com:1234/threefb"), - fallbacks[2].second); + fallbacks[2].target_url); + + EXPECT_TRUE(manifest.intercept_namespaces.empty()); } -TEST(ManifestParserTest, ComboUrls) { +TEST(AppCacheManifestParserTest, InterceptUrls) { + Manifest manifest; + const GURL kUrl("http://www.portme.com:1234"); + const std::string kData("CHROMIUM CACHE MANIFEST\r" + "CHROMIUM-INTERCEPT:\r" + "http://www.portme.com:1234/one return relative/int1\r" + "HTTP://www.portme.com:9/wrong return http://www.portme.com:1234/ignore\r" + "http://www.portme.com:1234/wrong return http://www.portme.com:9/boo\r" + "relative/two return relative/int2\r" + "relative/three wrong relative/threefb\r" + "http://www.portme.com:1234/three return HTTP://www.portme.com:1234/int3\r" + "http://www.portme.com/noport return http://www.portme.com:1234/skipped\r" + "http://www.portme.com:1234/skipme return http://www.portme.com/noport\r" + "relative/wrong/again missing/intercept_type\r"); + + EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(), manifest)); + EXPECT_TRUE(manifest.fallback_namespaces.empty()); + EXPECT_TRUE(manifest.explicit_urls.empty()); + EXPECT_TRUE(manifest.online_whitelist_namespaces.empty()); + EXPECT_FALSE(manifest.online_whitelist_all); + + const NamespaceVector& intercepts = manifest.intercept_namespaces; + const size_t kExpected = 3; + ASSERT_EQ(kExpected, intercepts.size()); + EXPECT_EQ(INTERCEPT_NAMESPACE, intercepts[0].type); + EXPECT_EQ(INTERCEPT_NAMESPACE, intercepts[1].type); + EXPECT_EQ(INTERCEPT_NAMESPACE, intercepts[2].type); + EXPECT_EQ(GURL("http://www.portme.com:1234/one"), + intercepts[0].namespace_url); + EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int1"), + intercepts[0].target_url); + EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"), + intercepts[1].namespace_url); + EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int2"), + intercepts[1].target_url); + EXPECT_EQ(GURL("http://www.portme.com:1234/three"), + intercepts[2].namespace_url); + EXPECT_EQ(GURL("http://www.portme.com:1234/int3"), + intercepts[2].target_url); +} + +TEST(AppCacheManifestParserTest, ComboUrls) { Manifest manifest; const GURL kUrl("http://combo.com:42"); const std::string kData("CACHE MANIFEST\r" @@ -275,20 +330,24 @@ TEST(ManifestParserTest, ComboUrls) { EXPECT_EQ(GURL("http://combo.com:42/relative/whitelist-3"), online[2]); EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"), online[3]); - std::vector<FallbackNamespace> fallbacks = manifest.fallback_namespaces; + const NamespaceVector& fallbacks = manifest.fallback_namespaces; expected = 2; ASSERT_EQ(expected, fallbacks.size()); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[0].type); + EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[1].type); EXPECT_EQ(GURL("http://combo.com:42/fallback-1"), - fallbacks[0].first); + fallbacks[0].namespace_url); EXPECT_EQ(GURL("http://combo.com:42/fallback-1b"), - fallbacks[0].second); + fallbacks[0].target_url); EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2"), - fallbacks[1].first); + fallbacks[1].namespace_url); EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2b"), - fallbacks[1].second); + fallbacks[1].target_url); + + EXPECT_TRUE(manifest.intercept_namespaces.empty()); } -TEST(ManifestParserTest, UnusualUtf8) { +TEST(AppCacheManifestParserTest, UnusualUtf8) { Manifest manifest; const GURL kUrl("http://bad.com"); const std::string kData("CACHE MANIFEST\r" @@ -301,7 +360,7 @@ TEST(ManifestParserTest, UnusualUtf8) { EXPECT_TRUE(urls.find("http://bad.com/nonbmp%F1%84%AB%BC") != urls.end()); } -TEST(ManifestParserTest, IgnoreAfterSpace) { +TEST(AppCacheManifestParserTest, IgnoreAfterSpace) { Manifest manifest; const GURL kUrl("http://smorg.borg"); const std::string kData( @@ -313,7 +372,7 @@ TEST(ManifestParserTest, IgnoreAfterSpace) { EXPECT_TRUE(urls.find("http://smorg.borg/resource.txt") != urls.end()); } -TEST(ManifestParserTest, DifferentOriginUrlWithSecureScheme) { +TEST(AppCacheManifestParserTest, DifferentOriginUrlWithSecureScheme) { Manifest manifest; const GURL kUrl("https://www.foo.com"); const std::string kData("CACHE MANIFEST\r" @@ -341,4 +400,3 @@ TEST(ManifestParserTest, DifferentOriginUrlWithSecureScheme) { } } // namespace appcache - diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc index 2731ba8..cc37ef4 100644 --- a/webkit/appcache/mock_appcache_storage_unittest.cc +++ b/webkit/appcache/mock_appcache_storage_unittest.cc @@ -461,16 +461,18 @@ TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) { Manifest manifest; manifest.fallback_namespaces.push_back( - FallbackNamespace(kFallbackNamespaceUrl1, kFallbackEntryUrl1)); + Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl1, + kFallbackEntryUrl1)); manifest.fallback_namespaces.push_back( - FallbackNamespace(kFallbackNamespaceUrl2, kFallbackEntryUrl2)); + Namespace(FALLBACK_NAMESPACE, 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->AddEntry(kFallbackEntryUrl1, + AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId1)); + cache->AddEntry(kFallbackEntryUrl2, + AppCacheEntry(AppCacheEntry::FALLBACK, kResponseId2)); cache->set_complete(true); scoped_refptr<AppCacheGroup> group( diff --git a/webkit/appcache/view_appcache_internals_job.cc b/webkit/appcache/view_appcache_internals_job.cc index 025139b..3d51b4c 100644 --- a/webkit/appcache/view_appcache_internals_job.cc +++ b/webkit/appcache/view_appcache_internals_job.cc @@ -176,6 +176,8 @@ std::string FormFlagsString(const AppCacheResourceInfo& info) { str.append("Manifest, "); if (info.is_master) str.append("Master, "); + if (info.is_intercept) + str.append("Intercept, "); if (info.is_fallback) str.append("Fallback, "); if (info.is_explicit) |