summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webkit/appcache/appcache.cc68
-rw-r--r--webkit/appcache/appcache.h13
-rw-r--r--webkit/appcache/appcache_database.cc81
-rw-r--r--webkit/appcache/appcache_database.h10
-rw-r--r--webkit/appcache/appcache_database_unittest.cc306
-rw-r--r--webkit/appcache/appcache_interfaces.cc23
-rw-r--r--webkit/appcache/appcache_interfaces.h9
-rw-r--r--webkit/appcache/appcache_storage_impl.cc28
-rw-r--r--webkit/appcache/appcache_storage_impl_unittest.cc229
-rw-r--r--webkit/appcache/appcache_unittest.cc299
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc15
-rw-r--r--webkit/appcache/manifest_parser.cc30
-rw-r--r--webkit/appcache/manifest_parser.h2
-rw-r--r--webkit/appcache/manifest_parser_unittest.cc94
-rw-r--r--webkit/appcache/mock_appcache_storage_unittest.cc9
15 files changed, 1042 insertions, 174 deletions
diff --git a/webkit/appcache/appcache.cc b/webkit/appcache/appcache.cc
index c77320d..92d688d 100644
--- a/webkit/appcache/appcache.cc
+++ b/webkit/appcache/appcache.cc
@@ -128,21 +128,11 @@ 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 < intercepts.size(); ++i)
+ intercept_namespaces_.push_back(intercepts.at(i).namespace_);
- for (size_t i = 0; i < fallbacks.size(); ++i) {
- const AppCacheDatabase::NamespaceRecord& fallback = fallbacks.at(i);
- fallback_namespaces_.push_back(
- Namespace(FALLBACK_NAMESPACE,
- fallback.namespace_url,
- fallback.target_url));
- }
+ for (size_t i = 0; i < fallbacks.size(); ++i)
+ fallback_namespaces_.push_back(fallbacks.at(i).namespace_);
// Sort the fallback namespaces by url string length, longest to shortest,
// since longer matches trump when matching a url to a namespace.
@@ -151,8 +141,14 @@ void AppCache::InitializeWithDatabaseRecords(
std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(),
SortNamespacesByLength);
- for (size_t i = 0; i < whitelists.size(); ++i)
- online_whitelist_namespaces_.push_back(whitelists.at(i).namespace_url);
+ for (size_t i = 0; i < whitelists.size(); ++i) {
+ const AppCacheDatabase::OnlineWhiteListRecord& record = whitelists.at(i);
+ online_whitelist_namespaces_.push_back(
+ Namespace(NETWORK_NAMESPACE,
+ record.namespace_url,
+ GURL(),
+ record.is_pattern));
+ }
}
void AppCache::ToDatabaseRecords(
@@ -190,9 +186,7 @@ void AppCache::ToDatabaseRecords(
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;
+ record.namespace_ = intercept_namespaces_[i];
}
for (size_t i = 0; i < fallback_namespaces_.size(); ++i) {
@@ -200,16 +194,15 @@ void AppCache::ToDatabaseRecords(
AppCacheDatabase::NamespaceRecord& record = fallbacks->back();
record.cache_id = cache_id_;
record.origin = origin;
- record.type = FALLBACK_NAMESPACE;
- record.namespace_url = fallback_namespaces_[i].namespace_url;
- record.target_url = fallback_namespaces_[i].target_url;
+ record.namespace_ = fallback_namespaces_[i];
}
for (size_t i = 0; i < online_whitelist_namespaces_.size(); ++i) {
whitelists->push_back(AppCacheDatabase::OnlineWhiteListRecord());
AppCacheDatabase::OnlineWhiteListRecord& record = whitelists->back();
record.cache_id = cache_id_;
- record.namespace_url = online_whitelist_namespaces_[i];
+ record.namespace_url = online_whitelist_namespaces_[i].namespace_url;
+ record.is_pattern = online_whitelist_namespaces_[i].is_pattern;
}
}
@@ -235,10 +228,8 @@ bool AppCache::FindResponseForRequest(const GURL& url,
return true;
}
- if ((*found_network_namespace =
- IsInNetworkNamespace(url_no_ref, online_whitelist_namespaces_))) {
+ if ((*found_network_namespace = IsInNetworkNamespace(url_no_ref)))
return true;
- }
const Namespace* intercept_namespace = FindInterceptNamespace(url_no_ref);
if (intercept_namespace) {
@@ -262,17 +253,6 @@ bool AppCache::FindResponseForRequest(const GURL& url,
return *found_network_namespace;
}
-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(), namespaces[i].namespace_url.spec(), true)) {
- return &namespaces[i];
- }
- }
- return NULL;
-}
void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
DCHECK(infos && infos->empty());
@@ -293,17 +273,15 @@ void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
}
// static
-bool AppCache::IsInNetworkNamespace(
- const GURL& url,
- const std::vector<GURL> &namespaces) {
- // TODO(michaeln): There are certainly better 'prefix matching'
- // structures and algorithms that can be applied here and above.
+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(), namespaces[i].spec(), true))
- return true;
+ if (namespaces[i].IsMatch(url))
+ return &namespaces[i];
}
- return false;
+ return NULL;
}
} // namespace appcache
diff --git a/webkit/appcache/appcache.h b/webkit/appcache/appcache.h
index bfc40ab..fee3169 100644
--- a/webkit/appcache/appcache.h
+++ b/webkit/appcache/appcache.h
@@ -117,9 +117,9 @@ class WEBKIT_STORAGE_EXPORT AppCache : public base::RefCounted<AppCache> {
// Populates the 'infos' vector with an element per entry in the appcache.
void ToResourceInfoVector(AppCacheResourceInfoVector* infos) const;
- static bool IsInNetworkNamespace(
- const GURL& url,
- const std::vector<GURL> &namespaces);
+ static const Namespace* FindNamespace(
+ const NamespaceVector& namespaces,
+ const GURL& url);
private:
friend class AppCacheGroup;
@@ -140,8 +140,9 @@ class WEBKIT_STORAGE_EXPORT AppCache : public base::RefCounted<AppCache> {
const Namespace* FindFallbackNamespace(const GURL& url) {
return FindNamespace(fallback_namespaces_, url);
}
- const Namespace* FindNamespace(const NamespaceVector& namespaces,
- const GURL& url);
+ bool IsInNetworkNamespace(const GURL& url) {
+ return FindNamespace(online_whitelist_namespaces_, url) != NULL;
+ }
GURL GetNamespaceEntryUrl(const NamespaceVector& namespaces,
const GURL& namespace_url) const;
@@ -160,7 +161,7 @@ class WEBKIT_STORAGE_EXPORT AppCache : public base::RefCounted<AppCache> {
NamespaceVector intercept_namespaces_;
NamespaceVector fallback_namespaces_;
- std::vector<GURL> online_whitelist_namespaces_;
+ NamespaceVector online_whitelist_namespaces_;
bool online_whitelist_all_;
bool is_complete_;
diff --git a/webkit/appcache/appcache_database.cc b/webkit/appcache/appcache_database.cc
index 95b4309..3911831 100644
--- a/webkit/appcache/appcache_database.cc
+++ b/webkit/appcache/appcache_database.cc
@@ -18,8 +18,8 @@
// Schema -------------------------------------------------------------------
namespace {
-const int kCurrentVersion = 4;
-const int kCompatibleVersion = 4;
+const int kCurrentVersion = 5;
+const int kCompatibleVersion = 5;
const char kGroupsTable[] = "Groups";
const char kCachesTable[] = "Caches";
@@ -67,11 +67,13 @@ const TableInfo kTables[] = {
" origin TEXT," // intentionally not normalized
" type INTEGER,"
" namespace_url TEXT,"
- " target_url TEXT)" },
+ " target_url TEXT,"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
{ kOnlineWhiteListsTable,
"(cache_id INTEGER,"
- " namespace_url TEXT)" },
+ " namespace_url TEXT,"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
{ kDeletableResponseIdsTable,
"(response_id INTEGER NOT NULL)" },
@@ -170,7 +172,7 @@ AppCacheDatabase::GroupRecord::~GroupRecord() {
}
AppCacheDatabase::NamespaceRecord::NamespaceRecord()
- : cache_id(0), type(FALLBACK_NAMESPACE) {
+ : cache_id(0) {
}
AppCacheDatabase::NamespaceRecord::~NamespaceRecord() {
@@ -645,7 +647,7 @@ bool AppCacheDatabase::FindNamespacesForOrigin(
return false;
const char* kSql =
- "SELECT cache_id, origin, type, namespace_url, target_url"
+ "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
" FROM Namespaces WHERE origin = ?";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -666,7 +668,7 @@ bool AppCacheDatabase::FindNamespacesForCache(
return false;
const char* kSql =
- "SELECT cache_id, origin, type, namespace_url, target_url"
+ "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
" FROM Namespaces WHERE cache_id = ?";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -684,16 +686,16 @@ bool AppCacheDatabase::InsertNamespace(
const char* kSql =
"INSERT INTO Namespaces"
- " (cache_id, origin, type, namespace_url, target_url)"
- " VALUES (?, ?, ?, ?, ?)";
+ " (cache_id, origin, type, namespace_url, target_url, is_pattern)"
+ " VALUES (?, ?, ?, ?, ?, ?)";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, record->cache_id);
statement.BindString(1, record->origin.spec());
- statement.BindInt(2, record->type);
- statement.BindString(3, record->namespace_url.spec());
- statement.BindString(4, record->target_url.spec());
-
+ statement.BindInt(2, record->namespace_.type);
+ statement.BindString(3, record->namespace_.namespace_url.spec());
+ statement.BindString(4, record->namespace_.target_url.spec());
+ statement.BindBool(5, record->namespace_.is_pattern);
return statement.Run();
}
@@ -733,7 +735,7 @@ bool AppCacheDatabase::FindOnlineWhiteListForCache(
return false;
const char* kSql =
- "SELECT cache_id, namespace_url FROM OnlineWhiteLists"
+ "SELECT cache_id, namespace_url, is_pattern FROM OnlineWhiteLists"
" WHERE cache_id = ?";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
@@ -753,11 +755,13 @@ bool AppCacheDatabase::InsertOnlineWhiteList(
return false;
const char* kSql =
- "INSERT INTO OnlineWhiteLists (cache_id, namespace_url) VALUES (?, ?)";
+ "INSERT INTO OnlineWhiteLists (cache_id, namespace_url, is_pattern)"
+ " VALUES (?, ?, ?)";
sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
statement.BindInt64(0, record->cache_id);
statement.BindString(1, record->namespace_url.spec());
+ statement.BindBool(2, record->is_pattern);
return statement.Run();
}
@@ -932,15 +936,17 @@ 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));
+ record->namespace_.type = static_cast<NamespaceType>(statement->ColumnInt(2));
+ record->namespace_.namespace_url = GURL(statement->ColumnString(3));
+ record->namespace_.target_url = GURL(statement->ColumnString(4));
+ record->namespace_.is_pattern = statement->ColumnBool(5);
}
void AppCacheDatabase::ReadOnlineWhiteListRecord(
const sql::Statement& statement, OnlineWhiteListRecord* record) {
record->cache_id = statement.ColumnInt64(0);
record->namespace_url = GURL(statement.ColumnString(1));
+ record->is_pattern = statement.ColumnBool(2);
}
bool AppCacheDatabase::LazyOpen(bool create_if_needed) {
@@ -1046,15 +1052,26 @@ bool AppCacheDatabase::CreateSchema() {
bool AppCacheDatabase::UpgradeSchema() {
if (meta_table_->GetVersionNumber() == 3) {
+ // version 3 was pre 12/17/2011
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.
+ const TableInfo kNamespaceTable_v4 = {
+ kNamespacesTable,
+ "(cache_id INTEGER,"
+ " origin TEXT," // intentionally not normalized
+ " type INTEGER,"
+ " namespace_url TEXT,"
+ " target_url TEXT)"
+ };
+
+ // Migrate from the old FallbackNameSpaces to the newer Namespaces table,
+ // but without the is_pattern column added in v5.
sql::Transaction transaction(db_.get());
if (!transaction.Begin() ||
- !CreateTable(db_.get(), kTables[3])) {
+ !CreateTable(db_.get(), kNamespaceTable_v4)) {
return false;
}
@@ -1079,9 +1096,31 @@ bool AppCacheDatabase::UpgradeSchema() {
return false;
}
- // Finally bump the version numbers and commit it.
meta_table_->SetVersionNumber(4);
meta_table_->SetCompatibleVersionNumber(4);
+ if (!transaction.Commit())
+ return false;
+ }
+
+ if (meta_table_->GetVersionNumber() == 4) {
+ // version 4 pre 3/30/2013
+ // Add the is_pattern column to the Namespaces and OnlineWhitelists tables.
+ DCHECK_EQ(strcmp(kNamespacesTable, "Namespaces"), 0);
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ if (!db_->Execute(
+ "ALTER TABLE Namespaces ADD COLUMN"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
+ return false;
+ }
+ if (!db_->Execute(
+ "ALTER TABLE OnlineWhitelists ADD COLUMN"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
+ return false;
+ }
+ meta_table_->SetVersionNumber(5);
+ meta_table_->SetCompatibleVersionNumber(5);
return transaction.Commit();
}
diff --git a/webkit/appcache/appcache_database.h b/webkit/appcache/appcache_database.h
index 0eb0948..99154df 100644
--- a/webkit/appcache/appcache_database.h
+++ b/webkit/appcache/appcache_database.h
@@ -67,18 +67,17 @@ class WEBKIT_STORAGE_EXPORT AppCacheDatabase {
int64 cache_id;
GURL origin;
- NamespaceType type;
- GURL namespace_url;
- GURL target_url;
+ Namespace namespace_;
};
typedef std::vector<NamespaceRecord> NamespaceRecordVector;
struct OnlineWhiteListRecord {
- OnlineWhiteListRecord() : cache_id(0) {}
+ OnlineWhiteListRecord() : cache_id(0), is_pattern(false) {}
int64 cache_id;
GURL namespace_url;
+ bool is_pattern;
};
explicit AppCacheDatabase(const base::FilePath& path);
@@ -215,7 +214,8 @@ class WEBKIT_STORAGE_EXPORT AppCacheDatabase {
FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, ReCreate);
FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, DeletableResponseIds);
FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, OriginUsage);
- FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, UpgradeSchema3to4);
+ FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, UpgradeSchema3to5);
+ FRIEND_TEST_ALL_PREFIXES(AppCacheDatabaseTest, UpgradeSchema4to5);
DISALLOW_COPY_AND_ASSIGN(AppCacheDatabase);
};
diff --git a/webkit/appcache/appcache_database_unittest.cc b/webkit/appcache/appcache_database_unittest.cc
index 4c7affb..96627c7 100644
--- a/webkit/appcache/appcache_database_unittest.cc
+++ b/webkit/appcache/appcache_database_unittest.cc
@@ -360,15 +360,15 @@ TEST(AppCacheDatabaseTest, NamespaceRecords) {
// Two records for two differenent caches in the Foo origin.
record.cache_id = 1;
record.origin = kFooOrigin;
- record.namespace_url = kFooNameSpace1;
- record.target_url = kFooFallbackEntry;
+ record.namespace_.namespace_url = kFooNameSpace1;
+ record.namespace_.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.target_url = kFooFallbackEntry;
+ record.namespace_.namespace_url = kFooNameSpace2;
+ record.namespace_.target_url = kFooFallbackEntry;
EXPECT_TRUE(db.InsertNamespace(&record));
fallbacks.clear();
@@ -376,28 +376,32 @@ TEST(AppCacheDatabaseTest, NamespaceRecords) {
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);
+ EXPECT_EQ(kFooNameSpace1, fallbacks[0].namespace_.namespace_url);
+ EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[0].namespace_.is_pattern);
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);
+ EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_.namespace_url);
+ EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[0].namespace_.is_pattern);
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(kFooNameSpace1, fallbacks[0].namespace_.namespace_url);
+ EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[0].namespace_.is_pattern);
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_EQ(kFooNameSpace2, fallbacks[1].namespace_.namespace_url);
+ EXPECT_EQ(kFooFallbackEntry, fallbacks[1].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[1].namespace_.is_pattern);
EXPECT_TRUE(db.DeleteNamespacesForCache(1));
fallbacks.clear();
@@ -405,28 +409,36 @@ TEST(AppCacheDatabaseTest, NamespaceRecords) {
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);
+ EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_.namespace_url);
+ EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[0].namespace_.is_pattern);
// Two more records for the same cache in the Bar origin.
record.cache_id = 3;
record.origin = kBarOrigin;
- record.namespace_url = kBarNameSpace1;
- record.target_url = kBarFallbackEntry;
+ record.namespace_.namespace_url = kBarNameSpace1;
+ record.namespace_.target_url = kBarFallbackEntry;
+ record.namespace_.is_pattern = true;
EXPECT_TRUE(db.InsertNamespace(&record));
record.cache_id = 3;
record.origin = kBarOrigin;
- record.namespace_url = kBarNameSpace2;
- record.target_url = kBarFallbackEntry;
+ record.namespace_.namespace_url = kBarNameSpace2;
+ record.namespace_.target_url = kBarFallbackEntry;
+ record.namespace_.is_pattern = true;
EXPECT_TRUE(db.InsertNamespace(&record));
fallbacks.clear();
EXPECT_TRUE(db.FindNamespacesForCache(3, &intercepts, &fallbacks));
EXPECT_EQ(2U, fallbacks.size());
+ EXPECT_TRUE(fallbacks[0].namespace_.is_pattern);
+ EXPECT_TRUE(fallbacks[1].namespace_.is_pattern);
+
fallbacks.clear();
EXPECT_TRUE(db.FindNamespacesForOrigin(kBarOrigin, &intercepts, &fallbacks));
EXPECT_EQ(2U, fallbacks.size());
+ EXPECT_TRUE(fallbacks[0].namespace_.is_pattern);
+ EXPECT_TRUE(fallbacks[1].namespace_.is_pattern);
}
TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) {
@@ -453,14 +465,17 @@ TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) {
record.namespace_url = kFooNameSpace1;
EXPECT_TRUE(db.InsertOnlineWhiteList(&record));
record.namespace_url = kFooNameSpace2;
+ record.is_pattern = true;
EXPECT_TRUE(db.InsertOnlineWhiteList(&record));
records.clear();
EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records));
EXPECT_EQ(2U, records.size());
EXPECT_EQ(1, records[0].cache_id);
EXPECT_EQ(kFooNameSpace1, records[0].namespace_url);
+ EXPECT_FALSE(records[0].is_pattern);
EXPECT_EQ(1, records[1].cache_id);
EXPECT_EQ(kFooNameSpace2, records[1].namespace_url);
+ EXPECT_TRUE(records[1].is_pattern);
record.cache_id = 2;
record.namespace_url = kBarNameSpace1;
@@ -617,11 +632,11 @@ TEST(AppCacheDatabaseTest, OriginUsage) {
EXPECT_EQ(5000, usage_map[kOtherOrigin]);
}
-TEST(AppCacheDatabaseTest, UpgradeSchema3to4) {
+TEST(AppCacheDatabaseTest, UpgradeSchema3to5) {
// Real file on disk for this test.
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade.db");
+ const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade3.db");
const GURL kMockOrigin("http://mockorigin/");
const char kNamespaceUrlFormat[] = "namespace%d";
@@ -808,9 +823,11 @@ TEST(AppCacheDatabaseTest, UpgradeSchema3to4) {
EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheIndex"));
EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesOriginIndex"));
EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheAndUrlIndex"));
+ EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern"));
+ EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern"));
- EXPECT_EQ(4, db.meta_table_->GetVersionNumber());
- EXPECT_EQ(4, db.meta_table_->GetCompatibleVersionNumber());
+ EXPECT_EQ(5, db.meta_table_->GetVersionNumber());
+ EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber());
std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
@@ -826,10 +843,249 @@ TEST(AppCacheDatabaseTest, UpgradeSchema3to4) {
kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i)));
EXPECT_EQ(i, fallbacks[i].cache_id);
- EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].type);
+ EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].namespace_.type);
+ EXPECT_EQ(kMockOrigin, fallbacks[i].origin);
+ EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url);
+ EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[i].namespace_.is_pattern);
+ }
+}
+
+TEST(AppCacheDatabaseTest, UpgradeSchema4to5) {
+ // Real file on disk for this test.
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade4.db");
+
+ const GURL kMockOrigin("http://mockorigin/");
+ const char kNamespaceUrlFormat[] = "namespace%d";
+ const char kWhitelistUrlFormat[] = "whitelist%d";
+ const char kTargetUrlFormat[] = "target%d";
+ const int kNumNamespaces = 10;
+ const int kWhitelistCacheId = 1;
+
+ // Create a v4 schema based database containing some fallback records.
+ {
+ const int kVersion4 = 4;
+ const char kGroupsTable[] = "Groups";
+ const char kCachesTable[] = "Caches";
+ const char kEntriesTable[] = "Entries";
+ const char kNamespacesTable[] = "Namespaces";
+ const char kOnlineWhiteListsTable[] = "OnlineWhiteLists";
+ const char kDeletableResponseIdsTable[] = "DeletableResponseIds";
+
+ struct TableInfo {
+ const char* table_name;
+ const char* columns;
+ };
+
+ struct IndexInfo {
+ const char* index_name;
+ const char* table_name;
+ const char* columns;
+ bool unique;
+ };
+
+ const TableInfo kTables4[] = {
+ { 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)" },
+
+ { kNamespacesTable,
+ "(cache_id INTEGER,"
+ " origin TEXT," // intentionally not normalized
+ " type INTEGER,"
+ " namespace_url TEXT,"
+ " target_url TEXT)" },
+
+ { kOnlineWhiteListsTable,
+ "(cache_id INTEGER,"
+ " namespace_url TEXT)" },
+
+ { kDeletableResponseIdsTable,
+ "(response_id INTEGER NOT NULL)" },
+ };
+
+ const IndexInfo kIndexes4[] = {
+ { "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 },
+
+ { "NamespacesCacheIndex",
+ kNamespacesTable,
+ "(cache_id)",
+ false },
+
+ { "NamespacesOriginIndex",
+ kNamespacesTable,
+ "(origin)",
+ false },
+
+ { "NamespacesCacheAndUrlIndex",
+ kNamespacesTable,
+ "(cache_id, namespace_url)",
+ true },
+
+ { "OnlineWhiteListCacheIndex",
+ kOnlineWhiteListsTable,
+ "(cache_id)",
+ false },
+
+ { "DeletableResponsesIdIndex",
+ kDeletableResponseIdsTable,
+ "(response_id)",
+ true },
+ };
+
+ const int kTableCount4 = ARRAYSIZE_UNSAFE(kTables4);
+ const int kIndexCount4 = ARRAYSIZE_UNSAFE(kIndexes4);
+
+ 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, kVersion4, kVersion4));
+
+ for (int i = 0; i < kTableCount4; ++i) {
+ std::string sql("CREATE TABLE ");
+ sql += kTables4[i].table_name;
+ sql += kTables4[i].columns;
+ EXPECT_TRUE(connection.Execute(sql.c_str()));
+ }
+
+ for (int i = 0; i < kIndexCount4; ++i) {
+ std::string sql;
+ if (kIndexes4[i].unique)
+ sql += "CREATE UNIQUE INDEX ";
+ else
+ sql += "CREATE INDEX ";
+ sql += kIndexes4[i].index_name;
+ sql += " ON ";
+ sql += kIndexes4[i].table_name;
+ sql += kIndexes4[i].columns;
+ EXPECT_TRUE(connection.Execute(sql.c_str()));
+ }
+
+ const char* kNamespacesSql =
+ "INSERT INTO Namespaces"
+ " (cache_id, origin, type, namespace_url, target_url)"
+ " VALUES (?, ?, ?, ?, ?)";
+ sql::Statement statement;
+ statement.Assign(connection.GetUniqueStatement(kNamespacesSql));
+ 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.BindInt(2, FALLBACK_NAMESPACE);
+ statement.BindString(3, namespace_url.spec().c_str());
+ statement.BindString(4, target_url.spec().c_str());
+ ASSERT_TRUE(statement.Run());
+ statement.Reset(true);
+ }
+
+ const char* kWhitelistsSql =
+ "INSERT INTO OnlineWhiteLists"
+ " (cache_id, namespace_url)"
+ " VALUES (?, ?)";
+ statement.Assign(connection.GetUniqueStatement(kWhitelistsSql));
+ EXPECT_TRUE(statement.is_valid());
+ for (int i = 0; i < kNumNamespaces; ++i) {
+ GURL namespace_url(
+ kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i)));
+ statement.BindInt64(0, kWhitelistCacheId);
+ statement.BindString(1, namespace_url.spec().c_str());
+ ASSERT_TRUE(statement.Run());
+ statement.Reset(true);
+ }
+
+ EXPECT_TRUE(transaction.Commit());
+ }
+
+ // Open that database and verify that it got upgraded to v5.
+ AppCacheDatabase db(kDbFile);
+ EXPECT_TRUE(db.LazyOpen(true));
+ EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern"));
+ EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern"));
+ EXPECT_EQ(5, db.meta_table_->GetVersionNumber());
+ EXPECT_EQ(5, 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()));
+
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
+ EXPECT_TRUE(db.FindOnlineWhiteListForCache(kWhitelistCacheId, &whitelists));
+ EXPECT_EQ(kNumNamespaces, static_cast<int>(whitelists.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)));
+ GURL expected_whitelist_url(
+ kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i)));
+
+ EXPECT_EQ(i, fallbacks[i].cache_id);
+ EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].namespace_.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);
+ EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url);
+ EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url);
+ EXPECT_FALSE(fallbacks[i].namespace_.is_pattern);
+ EXPECT_EQ(expected_whitelist_url, whitelists[i].namespace_url);
+ EXPECT_FALSE(whitelists[i].is_pattern);
}
}
diff --git a/webkit/appcache/appcache_interfaces.cc b/webkit/appcache/appcache_interfaces.cc
index bbc222c..a3b6f31 100644
--- a/webkit/appcache/appcache_interfaces.cc
+++ b/webkit/appcache/appcache_interfaces.cc
@@ -4,6 +4,7 @@
#include "webkit/appcache/appcache_interfaces.h"
+#include "base/string_util.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebApplicationCacheHost.h"
@@ -49,16 +50,32 @@ AppCacheResourceInfo::~AppCacheResourceInfo() {
}
Namespace::Namespace()
- : type(FALLBACK_NAMESPACE) {
+ : type(FALLBACK_NAMESPACE),
+ is_pattern(false) {
}
-Namespace::Namespace(NamespaceType type, const GURL& url, const GURL& target)
- : type(type), namespace_url(url), target_url(target) {
+Namespace::Namespace(
+ NamespaceType type, const GURL& url, const GURL& target, bool is_pattern)
+ : type(type),
+ namespace_url(url),
+ target_url(target),
+ is_pattern(is_pattern) {
}
Namespace::~Namespace() {
}
+bool Namespace::IsMatch(const GURL& url) const {
+ if (is_pattern) {
+ // We have to escape '?' characters since MatchPattern also treats those
+ // as wildcards which we don't want here, we only do '*'s.
+ std::string pattern = namespace_url.spec();
+ if (namespace_url.has_query())
+ ReplaceSubstringsAfterOffset(&pattern, 0, "?", "\\?");
+ return MatchPattern(url.spec(), pattern);
+ }
+ return StartsWithASCII(url.spec(), namespace_url.spec(), true);
+}
bool IsSchemeSupported(const GURL& url) {
bool supported = url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme);
diff --git a/webkit/appcache/appcache_interfaces.h b/webkit/appcache/appcache_interfaces.h
index 4fc7a56..b45ee8f 100644
--- a/webkit/appcache/appcache_interfaces.h
+++ b/webkit/appcache/appcache_interfaces.h
@@ -57,7 +57,8 @@ enum LogLevel {
enum NamespaceType {
FALLBACK_NAMESPACE,
- INTERCEPT_NAMESPACE
+ INTERCEPT_NAMESPACE,
+ NETWORK_NAMESPACE
};
struct WEBKIT_STORAGE_EXPORT AppCacheInfo {
@@ -97,12 +98,16 @@ typedef std::vector<AppCacheResourceInfo> AppCacheResourceInfoVector;
struct WEBKIT_STORAGE_EXPORT Namespace {
Namespace(); // Type is set to FALLBACK_NAMESPACE by default.
- Namespace(NamespaceType type, const GURL& url, const GURL& target);
+ Namespace(NamespaceType type, const GURL& url, const GURL& target,
+ bool is_pattern);
~Namespace();
+ bool IsMatch(const GURL& url) const;
+
NamespaceType type;
GURL namespace_url;
GURL target_url;
+ bool is_pattern;
};
typedef std::vector<Namespace> NamespaceVector;
diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc
index 688542e..8fe803c 100644
--- a/webkit/appcache/appcache_storage_impl.cc
+++ b/webkit/appcache/appcache_storage_impl.cc
@@ -811,7 +811,8 @@ class SortByCachePreference
bool SortByLength(
const AppCacheDatabase::NamespaceRecord& lhs,
const AppCacheDatabase::NamespaceRecord& rhs) {
- return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length();
+ return lhs.namespace_.namespace_url.spec().length() >
+ rhs.namespace_.namespace_url.spec().length();
}
class NetworkNamespaceHelper {
@@ -821,19 +822,18 @@ class NetworkNamespaceHelper {
}
bool IsInNetworkNamespace(const GURL& url, int64 cache_id) {
- const std::vector<GURL> kEmptyVector;
typedef std::pair<WhiteListMap::iterator, bool> InsertResult;
InsertResult result = namespaces_map_.insert(
- WhiteListMap::value_type(cache_id, kEmptyVector));
+ WhiteListMap::value_type(cache_id, NamespaceVector()));
if (result.second)
GetOnlineWhiteListForCache(cache_id, &result.first->second);
- return AppCache::IsInNetworkNamespace(url, result.first->second);
+ return AppCache::FindNamespace(result.first->second, url) != NULL;
}
private:
void GetOnlineWhiteListForCache(
- int64 cache_id, std::vector<GURL>* urls) {
- DCHECK(urls && urls->empty());
+ int64 cache_id, NamespaceVector* namespaces) {
+ DCHECK(namespaces && namespaces->empty());
typedef std::vector<AppCacheDatabase::OnlineWhiteListRecord>
WhiteListVector;
WhiteListVector records;
@@ -841,13 +841,15 @@ class NetworkNamespaceHelper {
return;
WhiteListVector::const_iterator iter = records.begin();
while (iter != records.end()) {
- urls->push_back(iter->namespace_url);
+ namespaces->push_back(
+ Namespace(NETWORK_NAMESPACE, iter->namespace_url, GURL(),
+ iter->is_pattern));
++iter;
}
}
// Key is cache id
- typedef std::map<int64, std::vector<GURL> > WhiteListMap;
+ typedef std::map<int64, NamespaceVector> WhiteListMap;
WhiteListMap namespaces_map_;
AppCacheDatabase* database_;
};
@@ -1009,8 +1011,8 @@ FindMainResponseTask::FindNamespaceHelper(
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))
+ // Skip those that aren't a match.
+ if (!iter->namespace_.IsMatch(url_))
continue;
// Skip namespaces where the requested url falls into a network
@@ -1043,7 +1045,7 @@ FindMainResponseTask::FindFirstValidNamespace(
NamespaceRecordPtrVector::const_iterator iter;
for (iter = namespaces.begin(); iter < namespaces.end(); ++iter) {
AppCacheDatabase::EntryRecord entry_record;
- if (database_->FindEntry((*iter)->cache_id, (*iter)->target_url,
+ if (database_->FindEntry((*iter)->cache_id, (*iter)->namespace_.target_url,
&entry_record)) {
AppCacheDatabase::GroupRecord group_record;
if ((entry_record.flags & AppCacheEntry::FOREIGN) ||
@@ -1053,8 +1055,8 @@ FindMainResponseTask::FindFirstValidNamespace(
manifest_url_ = group_record.manifest_url;
group_id_ = group_record.group_id;
cache_id_ = (*iter)->cache_id;
- namespace_entry_url_ = (*iter)->target_url;
- if ((*iter)->type == FALLBACK_NAMESPACE)
+ namespace_entry_url_ = (*iter)->namespace_.target_url;
+ if ((*iter)->namespace_.type == FALLBACK_NAMESPACE)
fallback_entry_ = AppCacheEntry(entry_record.flags,
entry_record.response_id);
else
diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc
index d419794..1c6d976 100644
--- a/webkit/appcache/appcache_storage_impl_unittest.cc
+++ b/webkit/appcache/appcache_storage_impl_unittest.cc
@@ -39,6 +39,16 @@ const GURL kOnlineNamespaceWithinFallback(
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 kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
+const GURL kInterceptPatternTestPositiveUrl(
+ "http://blah/intercept_pattern/foo/bar");
+const GURL kInterceptPatternTestNegativeUrl(
+ "http://blah/intercept_pattern/foo/not_bar");
+const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
+const GURL kFallbackPatternTestPositiveUrl(
+ "http://blah/fallback_pattern/foo/bar");
+const GURL kFallbackPatternTestNegativeUrl(
+ "http://blah/fallback_pattern/foo/not_bar");
const GURL kOrigin(kManifestUrl.GetOrigin());
const int kManifestEntryIdOffset = 100;
@@ -676,8 +686,8 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheDatabase::NamespaceRecord fallback_namespace_record;
fallback_namespace_record.cache_id = 1;
- fallback_namespace_record.target_url = kEntryUrl;
- fallback_namespace_record.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.namespace_.target_url = kEntryUrl;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
fallback_namespace_record.origin = kManifestUrl.GetOrigin();
EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
@@ -896,9 +906,9 @@ class AppCacheStorageImplTest : public testing::Test {
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
cache_->fallback_namespaces_.push_back(
- Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2));
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2, false));
cache_->fallback_namespaces_.push_back(
- Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl));
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl, false));
AppCacheDatabase::CacheRecord cache_record;
std::vector<AppCacheDatabase::EntryRecord> entries;
std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
@@ -964,9 +974,11 @@ class AppCacheStorageImplTest : public testing::Test {
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
cache_->intercept_namespaces_.push_back(
- Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2, kEntryUrl2));
+ Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2,
+ kEntryUrl2, false));
cache_->intercept_namespaces_.push_back(
- Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace, kEntryUrl));
+ Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace,
+ kEntryUrl, false));
AppCacheDatabase::CacheRecord cache_record;
std::vector<AppCacheDatabase::EntryRecord> entries;
std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
@@ -1011,6 +1023,171 @@ class AppCacheStorageImplTest : public testing::Test {
EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
TestFinished();
}
+
+ // FindInterceptPatternMatch ----------------------------------------
+
+ void FindInterceptPatternMatchInDatabase() {
+ FindInterceptPatternMatch(true);
+ }
+
+ void FindInterceptPatternMatchInWorkingSet() {
+ FindInterceptPatternMatch(false);
+ }
+
+ void FindInterceptPatternMatch(bool drop_from_working_set) {
+ // Setup some preconditions. Create a complete cache with an
+ // pattern matching intercept namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
+ cache_->intercept_namespaces_.push_back(
+ Namespace(INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
+ kEntryUrl, true));
+ 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));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // First test something that does not match the pattern.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kInterceptPatternTestNegativeUrl, GURL(), delegate());
+ EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
+ }
+
+ void Verify_FindInterceptPatternMatchNegative() {
+ EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+
+ // Then test something that matches.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kInterceptPatternTestPositiveUrl, GURL(), delegate());
+ }
+
+ void Verify_FindInterceptPatternMatchPositive() {
+ EXPECT_EQ(kInterceptPatternTestPositiveUrl, 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(1, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
+ EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+ TestFinished();
+ }
+
+ // FindFallbackPatternMatch -------------------------------
+
+ void FindFallbackPatternMatchInDatabase() {
+ FindFallbackPatternMatch(true);
+ }
+
+ void FindFallbackPatternMatchInWorkingSet() {
+ FindFallbackPatternMatch(false);
+ }
+
+ void FindFallbackPatternMatch(bool drop_from_working_set) {
+ // Setup some preconditions. Create a complete cache with a
+ // pattern matching fallback namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackPatternNamespace,
+ kEntryUrl, true));
+ 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(fallbacks));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // First test something that does not match the pattern.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackPatternTestNegativeUrl, GURL(), delegate());
+ EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
+ }
+
+ void Verify_FindFallbackPatternMatchNegative() {
+ EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+
+ // Then test something that matches.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackPatternTestPositiveUrl, GURL(), delegate());
+ }
+
+ void Verify_FindFallbackPatternMatchPositive() {
+ EXPECT_EQ(kFallbackPatternTestPositiveUrl, 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(1, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
+ EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
+ EXPECT_FALSE(delegate()->found_entry_.has_response_id());
+ TestFinished();
+ }
+
// FindMainResponseWithMultipleHits -------------------------------
void FindMainResponseWithMultipleHits() {
@@ -1066,12 +1243,12 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheEntry(entry_record.flags, entry_record.response_id));
AppCacheDatabase::NamespaceRecord fallback_namespace_record;
fallback_namespace_record.cache_id = id;
- fallback_namespace_record.target_url = entry_record.url;
- fallback_namespace_record.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.namespace_.target_url = entry_record.url;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
fallback_namespace_record.origin = manifest_url.GetOrigin();
EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
cache_->fallback_namespaces_.push_back(
- Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2));
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
}
void Verify_FindMainResponseWithMultipleHits() {
@@ -1181,13 +1358,15 @@ class AppCacheStorageImplTest : public testing::Test {
MakeCacheAndGroup(kManifestUrl, 1, 1, true);
cache_->AddEntry(kEntryUrl,
AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
- cache_->online_whitelist_namespaces_.push_back(kOnlineNamespace);
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
cache_->fallback_namespaces_.push_back(
- Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2));
- cache_->online_whitelist_namespaces_.push_back(kOnlineNamespace);
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
cache_->online_whitelist_namespaces_.push_back(
- kOnlineNamespaceWithinFallback);
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespace,
+ GURL(), false));
+ cache_->online_whitelist_namespaces_.push_back(
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
+ GURL(), false));
AppCacheDatabase::EntryRecord entry_record;
entry_record.cache_id = 1;
@@ -1201,8 +1380,8 @@ class AppCacheStorageImplTest : public testing::Test {
EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
AppCacheDatabase::NamespaceRecord fallback_namespace_record;
fallback_namespace_record.cache_id = 1;
- fallback_namespace_record.target_url = kEntryUrl2;
- fallback_namespace_record.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.namespace_.target_url = kEntryUrl2;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
fallback_namespace_record.origin = kManifestUrl.GetOrigin();
EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
whitelist_record.cache_id = 1;
@@ -1419,6 +1598,26 @@ TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
&AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
}
+TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
+}
+
// That's all folks!
} // namespace appcache
diff --git a/webkit/appcache/appcache_unittest.cc b/webkit/appcache/appcache_unittest.cc
index 2fbf607..d097a45 100644
--- a/webkit/appcache/appcache_unittest.cc
+++ b/webkit/appcache/appcache_unittest.cc
@@ -89,9 +89,11 @@ TEST(AppCacheTest, InitializeWithManifest) {
manifest.explicit_urls.insert("http://two.com");
manifest.fallback_namespaces.push_back(
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"));
+ GURL("http://fbone.com"), true));
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, GURL("http://w1.com"), GURL(), false));
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, GURL("http://w2.com"), GURL(), false));
manifest.online_whitelist_all = true;
cache->InitializeWithManifest(&manifest);
@@ -101,11 +103,12 @@ TEST(AppCacheTest, InitializeWithManifest) {
EXPECT_EQ(expected, fallbacks.size());
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_;
+ EXPECT_TRUE(fallbacks[0].is_pattern);
+ const NamespaceVector& whitelist = cache->online_whitelist_namespaces_;
expected = 2;
EXPECT_EQ(expected, whitelist.size());
- EXPECT_EQ(GURL("http://w1.com"), whitelist[0]);
- EXPECT_EQ(GURL("http://w2.com"), whitelist[1]);
+ EXPECT_EQ(GURL("http://w1.com"), whitelist[0].namespace_url);
+ EXPECT_EQ(GURL("http://w2.com"), whitelist[1].namespace_url);
EXPECT_TRUE(cache->online_whitelist_all_);
// Ensure collections in manifest were taken over by the cache rather than
@@ -145,21 +148,24 @@ TEST(AppCacheTest, FindResponseForRequest) {
const int64 kInterceptResponseId = 6;
Manifest manifest;
- manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl);
manifest.online_whitelist_namespaces.push_back(
- kOnlineNamespaceWithinOtherNamespaces);
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespaceUrl,
+ GURL(), false));
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinOtherNamespaces,
+ GURL(), false));
manifest.fallback_namespaces.push_back(
Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
- kFallbackEntryUrl1));
+ kFallbackEntryUrl1, false));
manifest.fallback_namespaces.push_back(
Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
- kFallbackEntryUrl2));
+ kFallbackEntryUrl2, false));
manifest.intercept_namespaces.push_back(
Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace,
- kInterceptNamespaceEntry));
+ kInterceptNamespaceEntry, false));
manifest.intercept_namespaces.push_back(
Namespace(INTERCEPT_NAMESPACE, kInterceptNamespaceWithinFallback,
- kInterceptNamespaceEntry));
+ kInterceptNamespaceEntry, false));
// Create a cache with some namespaces and entries.
scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
@@ -323,6 +329,191 @@ TEST(AppCacheTest, FindResponseForRequest) {
EXPECT_FALSE(network_namespace);
}
+TEST(AppCacheTest, FindInterceptPatternResponseForRequest) {
+ MockAppCacheService service;
+
+ // Setup an appcache with an intercept namespace that uses pattern matching.
+ const GURL kInterceptNamespaceBase("http://blah/intercept_namespace/");
+ const GURL kInterceptPatternNamespace(
+ kInterceptNamespaceBase.Resolve("*.hit*"));
+ const GURL kInterceptNamespaceEntry("http://blah/intercept_resource");
+ const int64 kInterceptResponseId = 1;
+ Manifest manifest;
+ manifest.intercept_namespaces.push_back(
+ Namespace(INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
+ kInterceptNamespaceEntry, true));
+ scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
+ cache->InitializeWithManifest(&manifest);
+ cache->AddEntry(
+ kInterceptNamespaceEntry,
+ AppCacheEntry(AppCacheEntry::INTERCEPT, kInterceptResponseId));
+ cache->set_complete(true);
+
+ // See that the pattern match works.
+ bool found = false;
+ AppCacheEntry entry;
+ AppCacheEntry fallback_entry;
+ GURL intercept_namespace;
+ GURL fallback_namespace;
+ bool network_namespace = false;
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/miss"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/intercept_namespace/another_miss"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/intercept_namespace/path.hit"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_EQ(kInterceptResponseId, entry.response_id());
+ EXPECT_EQ(kInterceptNamespaceEntry,
+ cache->GetInterceptEntryUrl(intercept_namespace));
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_TRUE(fallback_namespace.is_empty());
+ EXPECT_FALSE(network_namespace);
+
+ entry = AppCacheEntry(); // reset
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/intercept_namespace/longer/path.hit?arg=ok"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_EQ(kInterceptResponseId, entry.response_id());
+ EXPECT_EQ(kInterceptNamespaceEntry,
+ cache->GetInterceptEntryUrl(intercept_namespace));
+ EXPECT_FALSE(fallback_entry.has_response_id());
+ EXPECT_TRUE(fallback_namespace.is_empty());
+ EXPECT_FALSE(network_namespace);
+}
+
+TEST(AppCacheTest, FindFallbackPatternResponseForRequest) {
+ MockAppCacheService service;
+
+ // Setup an appcache with a fallback namespace that uses pattern matching.
+ const GURL kFallbackNamespaceBase("http://blah/fallback_namespace/");
+ const GURL kFallbackPatternNamespace(
+ kFallbackNamespaceBase.Resolve("*.hit*"));
+ const GURL kFallbackNamespaceEntry("http://blah/fallback_resource");
+ const int64 kFallbackResponseId = 1;
+ Manifest manifest;
+ manifest.fallback_namespaces.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackPatternNamespace,
+ kFallbackNamespaceEntry, true));
+ scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
+ cache->InitializeWithManifest(&manifest);
+ cache->AddEntry(
+ kFallbackNamespaceEntry,
+ AppCacheEntry(AppCacheEntry::FALLBACK, kFallbackResponseId));
+ cache->set_complete(true);
+
+ // See that the pattern match works.
+ bool found = false;
+ AppCacheEntry entry;
+ AppCacheEntry fallback_entry;
+ GURL intercept_namespace;
+ GURL fallback_namespace;
+ bool network_namespace = false;
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/miss"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/fallback_namespace/another_miss"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/fallback_namespace/path.hit"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_EQ(kFallbackResponseId, fallback_entry.response_id());
+ EXPECT_EQ(kFallbackNamespaceEntry,
+ cache->GetFallbackEntryUrl(fallback_namespace));
+ EXPECT_FALSE(network_namespace);
+
+ fallback_entry = AppCacheEntry();
+ fallback_namespace = GURL();
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/fallback_namespace/longer/path.hit?arg=ok"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_EQ(kFallbackResponseId, fallback_entry.response_id());
+ EXPECT_EQ(kFallbackNamespaceEntry,
+ cache->GetFallbackEntryUrl(fallback_namespace));
+ EXPECT_TRUE(intercept_namespace.is_empty());
+ EXPECT_FALSE(network_namespace);
+}
+
+
+TEST(AppCacheTest, FindNetworkNamespacePatternResponseForRequest) {
+ MockAppCacheService service;
+
+ // Setup an appcache with a network namespace that uses pattern matching.
+ const GURL kNetworkNamespaceBase("http://blah/network_namespace/");
+ const GURL kNetworkPatternNamespace(
+ kNetworkNamespaceBase.Resolve("*.hit*"));
+ Manifest manifest;
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, kNetworkPatternNamespace,
+ GURL(), true));
+ manifest.online_whitelist_all = false;
+ scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
+ cache->InitializeWithManifest(&manifest);
+ cache->set_complete(true);
+
+ // See that the pattern match works.
+ bool found = false;
+ AppCacheEntry entry;
+ AppCacheEntry fallback_entry;
+ GURL intercept_namespace;
+ GURL fallback_namespace;
+ bool network_namespace = false;
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/miss"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_FALSE(found);
+
+ found = cache->FindResponseForRequest(
+ GURL("http://blah/network_namespace/path.hit"),
+ &entry, &intercept_namespace,
+ &fallback_entry, &fallback_namespace,
+ &network_namespace);
+ EXPECT_TRUE(found);
+ EXPECT_TRUE(network_namespace);
+ EXPECT_FALSE(entry.has_response_id());
+ EXPECT_FALSE(fallback_entry.has_response_id());
+}
+
TEST(AppCacheTest, ToFromDatabaseRecords) {
// Setup a cache with some entries.
const int64 kCacheId = 1234;
@@ -330,6 +521,7 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
const GURL kManifestUrl("http://foo.com/manifest");
const GURL kInterceptUrl("http://foo.com/intercept.html");
const GURL kFallbackUrl("http://foo.com/fallback.html");
+ const GURL kWhitelistUrl("http://foo.com/whitelist*");
const std::string kData(
"CACHE MANIFEST\r"
"CHROMIUM-INTERCEPT:\r"
@@ -337,7 +529,7 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
"FALLBACK:\r"
"/ /fallback.html\r"
"NETWORK:\r"
- "/whitelist\r"
+ "/whitelist* isPattern\r"
"*\r");
MockAppCacheService service;
scoped_refptr<AppCacheGroup> group =
@@ -347,6 +539,10 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
EXPECT_TRUE(
ParseManifest(kManifestUrl, kData.c_str(), kData.length(), manifest));
cache->InitializeWithManifest(&manifest);
+ EXPECT_EQ(NETWORK_NAMESPACE, cache->online_whitelist_namespaces_[0].type);
+ EXPECT_TRUE(cache->online_whitelist_namespaces_[0].is_pattern);
+ EXPECT_EQ(kWhitelistUrl,
+ cache->online_whitelist_namespaces_[0].namespace_url);
cache->AddEntry(
kManifestUrl,
AppCacheEntry(AppCacheEntry::MANIFEST, 1, 1));
@@ -391,6 +587,83 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
EXPECT_EQ(kFallbackUrl,
cache->GetFallbackEntryUrl(GURL("http://foo.com/")));
EXPECT_EQ(1 + 2 + 3, cache->cache_size());
+ EXPECT_EQ(NETWORK_NAMESPACE, cache->online_whitelist_namespaces_[0].type);
+ EXPECT_TRUE(cache->online_whitelist_namespaces_[0].is_pattern);
+ EXPECT_EQ(kWhitelistUrl,
+ cache->online_whitelist_namespaces_[0].namespace_url);
+}
+
+TEST(AppCacheTest, IsNamespaceMatch) {
+ Namespace prefix;
+ prefix.namespace_url = GURL("http://foo.com/prefix");
+ prefix.is_pattern = false;
+ EXPECT_TRUE(prefix.IsMatch(
+ GURL("http://foo.com/prefix_and_anothing_goes")));
+ EXPECT_FALSE(prefix.IsMatch(
+ GURL("http://foo.com/nope")));
+
+ Namespace bar_no_star;
+ bar_no_star.namespace_url = GURL("http://foo.com/bar");
+ bar_no_star.is_pattern = true;
+ EXPECT_TRUE(bar_no_star.IsMatch(
+ GURL("http://foo.com/bar")));
+ EXPECT_FALSE(bar_no_star.IsMatch(
+ GURL("http://foo.com/bar/nope")));
+
+ Namespace bar_star;
+ bar_star.namespace_url = GURL("http://foo.com/bar/*");
+ bar_star.is_pattern = true;
+ EXPECT_TRUE(bar_star.IsMatch(
+ GURL("http://foo.com/bar/")));
+ EXPECT_TRUE(bar_star.IsMatch(
+ GURL("http://foo.com/bar/should_match")));
+ EXPECT_FALSE(bar_star.IsMatch(
+ GURL("http://foo.com/not_bar/should_not_match")));
+
+ Namespace star_bar_star;
+ star_bar_star.namespace_url = GURL("http://foo.com/*/bar/*");
+ star_bar_star.is_pattern = true;
+ EXPECT_TRUE(star_bar_star.IsMatch(
+ GURL("http://foo.com/any/bar/should_match")));
+ EXPECT_TRUE(star_bar_star.IsMatch(
+ GURL("http://foo.com/any/bar/")));
+ EXPECT_FALSE(star_bar_star.IsMatch(
+ GURL("http://foo.com/any/not_bar/no_match")));
+
+ Namespace query_star_edit;
+ query_star_edit.namespace_url = GURL("http://foo.com/query?id=*&verb=edit*");
+ query_star_edit.is_pattern = true;
+ EXPECT_TRUE(query_star_edit.IsMatch(
+ GURL("http://foo.com/query?id=1234&verb=edit&option=blue")));
+ EXPECT_TRUE(query_star_edit.IsMatch(
+ GURL("http://foo.com/query?id=12345&option=blue&verb=edit")));
+ EXPECT_FALSE(query_star_edit.IsMatch(
+ GURL("http://foo.com/query?id=12345&option=blue&verb=print")));
+ EXPECT_TRUE(query_star_edit.IsMatch(
+ GURL("http://foo.com/query?id=123&verb=print&verb=edit")));
+
+ Namespace star_greediness;
+ star_greediness.namespace_url = GURL("http://foo.com/*/b");
+ star_greediness.is_pattern = true;
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/wxy/z/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/b/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/b/b/b/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/b/b/a/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/01234567890abcdef/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/01234567890abcdef/b01234567890abcdef/b")));
+ EXPECT_TRUE(star_greediness.IsMatch(
+ GURL("http://foo.com/a/b/01234567890abcdef_eat_some_more_characters_"
+ "/and_even_more_for_the_heck_of_it/01234567890abcdef/b")));
}
} // namespace appacache
diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc
index a7a2667..86b3df6 100644
--- a/webkit/appcache/appcache_update_job_unittest.cc
+++ b/webkit/appcache/appcache_update_job_unittest.cc
@@ -3192,7 +3192,8 @@ class AppCacheUpdateJobTest : public testing::Test,
Namespace(
FALLBACK_NAMESPACE,
MockHttpServer::GetMockUrl("files/fallback1"),
- MockHttpServer::GetMockUrl("files/fallback1a")));
+ MockHttpServer::GetMockUrl("files/fallback1a"),
+ false));
EXPECT_TRUE(cache->online_whitelist_namespaces_.empty());
EXPECT_TRUE(cache->online_whitelist_all_);
@@ -3219,13 +3220,15 @@ class AppCacheUpdateJobTest : public testing::Test,
Namespace(
FALLBACK_NAMESPACE,
MockHttpServer::GetMockUrl("files/fallback1"),
- MockHttpServer::GetMockUrl("files/explicit1")));
+ MockHttpServer::GetMockUrl("files/explicit1"),
+ false));
EXPECT_EQ(expected, cache->online_whitelist_namespaces_.size());
- EXPECT_TRUE(cache->online_whitelist_namespaces_.end() !=
- std::find(cache->online_whitelist_namespaces_.begin(),
- cache->online_whitelist_namespaces_.end(),
- MockHttpServer::GetMockUrl("files/online1")));
+ EXPECT_TRUE(cache->online_whitelist_namespaces_[0] ==
+ Namespace(
+ NETWORK_NAMESPACE,
+ MockHttpServer::GetMockUrl("files/online1"),
+ GURL(), false));
EXPECT_FALSE(cache->online_whitelist_all_);
EXPECT_TRUE(cache->update_time_ > base::Time());
diff --git a/webkit/appcache/manifest_parser.cc b/webkit/appcache/manifest_parser.cc
index 0d98d1e..3afbad7 100644
--- a/webkit/appcache/manifest_parser.cc
+++ b/webkit/appcache/manifest_parser.cc
@@ -38,6 +38,23 @@
namespace appcache {
+namespace {
+
+// Helper function used to identify 'isPattern' annotations.
+bool HasPatternMatchingAnnotation(const wchar_t* line_p,
+ const wchar_t* line_end) {
+ // Skip whitespace separating the resource url from the annotation.
+ // Note: trailing whitespace has already been trimmed from the line.
+ while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
+ ++line_p;
+ if (line_p == line_end)
+ return false;
+ std::wstring annotation(line_p, line_end - line_p);
+ return annotation == L"isPattern";
+}
+
+}
+
enum Mode {
EXPLICIT,
INTERCEPT,
@@ -189,7 +206,9 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length,
if (mode == EXPLICIT) {
manifest.explicit_urls.insert(url.spec());
} else {
- manifest.online_whitelist_namespaces.push_back(url);
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, url, GURL(), is_pattern));
}
} else if (mode == INTERCEPT) {
// Lines of the form,
@@ -258,8 +277,10 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length,
if (manifest_url.GetOrigin() != target_url.GetOrigin())
continue;
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
manifest.intercept_namespaces.push_back(
- Namespace(INTERCEPT_NAMESPACE, namespace_url, target_url));
+ Namespace(INTERCEPT_NAMESPACE, namespace_url,
+ target_url, is_pattern));
} else if (mode == FALLBACK) {
const wchar_t* line_p = line.c_str();
const wchar_t* line_end = line_p + line.length();
@@ -316,10 +337,13 @@ bool ParseManifest(const GURL& manifest_url, const char* data, int length,
continue;
}
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
+
// Store regardless of duplicate namespace URL. Only first match
// will ever be used.
manifest.fallback_namespaces.push_back(
- Namespace(FALLBACK_NAMESPACE, namespace_url, fallback_url));
+ Namespace(FALLBACK_NAMESPACE, namespace_url,
+ fallback_url, is_pattern));
} else {
NOTREACHED();
}
diff --git a/webkit/appcache/manifest_parser.h b/webkit/appcache/manifest_parser.h
index 47ebe77..25fde8c 100644
--- a/webkit/appcache/manifest_parser.h
+++ b/webkit/appcache/manifest_parser.h
@@ -50,7 +50,7 @@ struct WEBKIT_STORAGE_EXPORT Manifest {
base::hash_set<std::string> explicit_urls;
NamespaceVector intercept_namespaces;
NamespaceVector fallback_namespaces;
- std::vector<GURL> online_whitelist_namespaces;
+ NamespaceVector online_whitelist_namespaces;
bool online_whitelist_all;
};
diff --git a/webkit/appcache/manifest_parser_unittest.cc b/webkit/appcache/manifest_parser_unittest.cc
index eaafffa..84cf7cd 100644
--- a/webkit/appcache/manifest_parser_unittest.cc
+++ b/webkit/appcache/manifest_parser_unittest.cc
@@ -134,15 +134,18 @@ TEST(AppCacheManifestParserTest, WhitelistUrls) {
EXPECT_TRUE(manifest.intercept_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- std::vector<GURL> online = manifest.online_whitelist_namespaces;
+ const NamespaceVector& online = manifest.online_whitelist_namespaces;
const size_t kExpected = 6;
ASSERT_EQ(kExpected, online.size());
- EXPECT_EQ(GURL("http://www.bar.com/relative/one"), online[0]);
- EXPECT_EQ(GURL("http://www.bar.com/two"), online[1]);
- EXPECT_EQ(GURL("http://www.diff.com/three"), online[2]);
- EXPECT_EQ(GURL("http://www.bar.com/relative/four"), online[3]);
- EXPECT_EQ(GURL("http://www.five.com"), online[4]);
- EXPECT_EQ(GURL("http://www.bar.com/*foo"), online[5]);
+ EXPECT_EQ(NETWORK_NAMESPACE, online[0].type);
+ EXPECT_FALSE(online[0].is_pattern);
+ EXPECT_TRUE(online[0].target_url.is_empty());
+ EXPECT_EQ(GURL("http://www.bar.com/relative/one"), online[0].namespace_url);
+ EXPECT_EQ(GURL("http://www.bar.com/two"), online[1].namespace_url);
+ EXPECT_EQ(GURL("http://www.diff.com/three"), online[2].namespace_url);
+ EXPECT_EQ(GURL("http://www.bar.com/relative/four"), online[3].namespace_url);
+ EXPECT_EQ(GURL("http://www.five.com"), online[4].namespace_url);
+ EXPECT_EQ(GURL("http://www.bar.com/*foo"), online[5].namespace_url);
}
TEST(AppCacheManifestParserTest, FallbackUrls) {
@@ -322,13 +325,17 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
EXPECT_TRUE(urls.find("http://combo.com:99/explicit-2") != urls.end());
EXPECT_TRUE(urls.find("http://www.diff.com/explicit-3") != urls.end());
- std::vector<GURL> online = manifest.online_whitelist_namespaces;
+ const NamespaceVector& online = manifest.online_whitelist_namespaces;
expected = 4;
ASSERT_EQ(expected, online.size());
- EXPECT_EQ(GURL("http://combo.com/whitelist-1"), online[0]);
- EXPECT_EQ(GURL("http://www.diff.com/whitelist-2"), online[1]);
- EXPECT_EQ(GURL("http://combo.com:42/relative/whitelist-3"), online[2]);
- EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"), online[3]);
+ EXPECT_EQ(GURL("http://combo.com/whitelist-1"),
+ online[0].namespace_url);
+ EXPECT_EQ(GURL("http://www.diff.com/whitelist-2"),
+ online[1].namespace_url);
+ EXPECT_EQ(GURL("http://combo.com:42/relative/whitelist-3"),
+ online[2].namespace_url);
+ EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"),
+ online[3].namespace_url);
const NamespaceVector& fallbacks = manifest.fallback_namespaces;
expected = 2;
@@ -399,4 +406,67 @@ TEST(AppCacheManifestParserTest, DifferentOriginUrlWithSecureScheme) {
urls.end());
}
+TEST(AppCacheManifestParserTest, PatternMatching) {
+ const GURL kUrl("http://foo.com/manifest");
+ const std::string kManifestBody(
+ "CACHE MANIFEST\r"
+ "CACHE: \r"
+ "http://foo.com/page.html\r"
+ "CHROMIUM-INTERCEPT:\r"
+ "http://foo.com/intercept_prefix return /prefix\r"
+ "http://foo.com/intercept_pattern return /pattern isPattern\r"
+ "http://foo.com/*/intercept_pattern?query return /pattern isPattern\r"
+ "FALLBACK:\r"
+ "http://foo.com/fallback_prefix /prefix wrongAnnotation\r"
+ "http://foo.com/fallback_pattern* /pattern\tisPattern \r"
+ "NETWORK:\r"
+ "*\r"
+ "isPattern\r" // should not be interpretted as a pattern
+ "http://foo.com/network_pattern* isPattern\r");
+
+
+ Manifest manifest;
+ EXPECT_TRUE(ParseManifest(kUrl, kManifestBody.c_str(),
+ kManifestBody.length(), manifest));
+ EXPECT_TRUE(manifest.online_whitelist_all);
+ EXPECT_EQ(1u, manifest.explicit_urls.size());
+ EXPECT_EQ(3u, manifest.intercept_namespaces.size());
+ EXPECT_EQ(2u, manifest.fallback_namespaces.size());
+ EXPECT_EQ(2u, manifest.online_whitelist_namespaces.size());
+ EXPECT_EQ(INTERCEPT_NAMESPACE, manifest.intercept_namespaces[0].type);
+ EXPECT_EQ(FALLBACK_NAMESPACE, manifest.fallback_namespaces[0].type);
+ EXPECT_EQ(NETWORK_NAMESPACE, manifest.online_whitelist_namespaces[0].type);
+ EXPECT_FALSE(manifest.intercept_namespaces[0].is_pattern);
+ EXPECT_TRUE(manifest.intercept_namespaces[1].is_pattern);
+ EXPECT_TRUE(manifest.intercept_namespaces[2].is_pattern);
+ EXPECT_FALSE(manifest.fallback_namespaces[0].is_pattern);
+ EXPECT_TRUE(manifest.fallback_namespaces[1].is_pattern);
+ EXPECT_FALSE(manifest.online_whitelist_namespaces[0].is_pattern);
+ EXPECT_TRUE(manifest.online_whitelist_namespaces[1].is_pattern);
+ EXPECT_EQ(
+ GURL("http://foo.com/*/intercept_pattern?query"),
+ manifest.intercept_namespaces[2].namespace_url);
+ EXPECT_EQ(
+ GURL("http://foo.com/pattern"),
+ manifest.intercept_namespaces[2].target_url);
+ EXPECT_EQ(
+ GURL("http://foo.com/fallback_pattern*"),
+ manifest.fallback_namespaces[1].namespace_url);
+ EXPECT_EQ(
+ GURL("http://foo.com/pattern"),
+ manifest.fallback_namespaces[1].target_url);
+ EXPECT_EQ(
+ GURL("http://foo.com/isPattern"),
+ manifest.online_whitelist_namespaces[0].namespace_url);
+ EXPECT_EQ(
+ GURL(),
+ manifest.online_whitelist_namespaces[0].target_url);
+ EXPECT_EQ(
+ GURL("http://foo.com/network_pattern*"),
+ manifest.online_whitelist_namespaces[1].namespace_url);
+ EXPECT_EQ(
+ GURL(),
+ manifest.online_whitelist_namespaces[1].target_url);
+}
+
} // namespace appcache
diff --git a/webkit/appcache/mock_appcache_storage_unittest.cc b/webkit/appcache/mock_appcache_storage_unittest.cc
index cb898e7..351e340 100644
--- a/webkit/appcache/mock_appcache_storage_unittest.cc
+++ b/webkit/appcache/mock_appcache_storage_unittest.cc
@@ -471,10 +471,10 @@ TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) {
Manifest manifest;
manifest.fallback_namespaces.push_back(
Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
- kFallbackEntryUrl1));
+ kFallbackEntryUrl1, false));
manifest.fallback_namespaces.push_back(
Namespace(FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
- kFallbackEntryUrl2));
+ kFallbackEntryUrl2, false));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
cache->InitializeWithManifest(&manifest);
@@ -581,8 +581,9 @@ TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) {
const int64 kResponseId = 1;
Manifest manifest;
- manifest.online_whitelist_namespaces.push_back(kOnlineNamespaceUrl);
-
+ manifest.online_whitelist_namespaces.push_back(
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespaceUrl,
+ GURL(), false));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
cache->InitializeWithManifest(&manifest);
cache->AddEntry(