summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-30 00:32:42 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-30 00:32:42 +0000
commit34e7dc62ff6abe114ec521cf735c2c7592cb16e5 (patch)
treec47066e8b9d47ac496afcfd8641159d5ffc35801
parent13ac535324e020859ea18654a2b9f614fdcd20dc (diff)
downloadchromium_src-34e7dc62ff6abe114ec521cf735c2c7592cb16e5.zip
chromium_src-34e7dc62ff6abe114ec521cf735c2c7592cb16e5.tar.gz
chromium_src-34e7dc62ff6abe114ec521cf735c2c7592cb16e5.tar.bz2
Chromium appcache pattern matching. Allow the INTERCEPT, FALLBACK, and NETWORK namespaces
to optionally be defined with glob matching semantics. To enable the new feature, entries in those sections must be annotated with a trailing 'isPattern'. Up to 16 * characters in the path or query parts of the <patternurl> will match zero or more characters of requested urls. Without the 'isPattern' annotation, entries in those sections are interpreted as prefixes (as usual). FALLBACK: <patternurl> <targeturl> isPattern CHROMIUM-INTERCEPT: <patternurl> return <targeturl> isPattern NETWORK: <patternurl> isPattern # examples FALLBACK: /userpics/*.jpg /userpics/unavailablepic.jpg isPattern /userpics?userid=*&size=120x120 /userpics_static/unavailablepic120x120.jpg isPattern BUG=224426 Review URL: https://codereview.chromium.org/12628006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191480 0039d316-1c4b-4281-b951-d872f2087c98
-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(