summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/appcache')
-rw-r--r--webkit/appcache/appcache.cc84
-rw-r--r--webkit/appcache/appcache.h18
-rw-r--r--webkit/appcache/appcache_database.cc220
-rw-r--r--webkit/appcache/appcache_database.h45
-rw-r--r--webkit/appcache/appcache_database_unittest.cc345
-rw-r--r--webkit/appcache/appcache_entry.h2
-rw-r--r--webkit/appcache/appcache_interfaces.cc23
-rw-r--r--webkit/appcache/appcache_interfaces.h18
-rw-r--r--webkit/appcache/appcache_storage_impl.cc202
-rw-r--r--webkit/appcache/appcache_storage_impl_unittest.cc124
-rw-r--r--webkit/appcache/appcache_unittest.cc57
-rw-r--r--webkit/appcache/appcache_update_job.cc14
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc90
-rw-r--r--webkit/appcache/manifest_parser.cc91
-rw-r--r--webkit/appcache/manifest_parser.h6
-rw-r--r--webkit/appcache/manifest_parser_unittest.cc130
-rw-r--r--webkit/appcache/mock_appcache_storage_unittest.cc14
-rw-r--r--webkit/appcache/view_appcache_internals_job.cc2
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)