15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/appcache/appcache_manifest_parser.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "url/gurl.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AppCacheManifestParserTest : public testing::Test {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(AppCacheManifestParserTest, NoData) {
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GURL url;
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AppCacheManifest manifest;
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(ParseManifest(url, "", 0,
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(ParseManifest(url, "CACHE MANIFEST\r", 0,  // Len is 0.
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                             PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)TEST(AppCacheManifestParserTest, CheckSignature) {
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  GURL url;
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AppCacheManifest manifest;
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const std::string kBadSignatures[] = {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "foo",
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST;V2\r",          // not followed by whitespace
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST#bad\r",         // no whitespace before comment
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "cache manifest ",              // wrong case
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "#CACHE MANIFEST\r",            // comment
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "xCACHE MANIFEST\n",            // bad first char
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    " CACHE MANIFEST\r",            // begins with whitespace
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\xEF\xBE\xBF" "CACHE MANIFEST\r",  // bad UTF-8 BOM value
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kBadSignatures); ++i) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string bad = kBadSignatures[i];
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_FALSE(ParseManifest(url, bad.c_str(), bad.length(),
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const std::string kGoodSignatures[] = {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST",
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "CACHE MANIFEST ",
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "CACHE MANIFEST\r",
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST\n",
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST\r\n",
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST\t# ignore me\r",
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE MANIFEST ignore\r\n",
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CHROMIUM CACHE MANIFEST\r\n",
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "\xEF\xBB\xBF" "CACHE MANIFEST \r\n",   // BOM present
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kGoodSignatures); ++i) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string good = kGoodSignatures[i];
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(ParseManifest(url, good.c_str(), good.length(),
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                              PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)TEST(AppCacheManifestParserTest, NoManifestUrl) {
668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  AppCacheManifest manifest;
678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const std::string kData("CACHE MANIFEST\r"
688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    "relative/tobase.com\r"
698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    "http://absolute.com/addme.com");
708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const GURL kUrl;
718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.explicit_urls.empty());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.fallback_namespaces.empty());
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(manifest.online_whitelist_all);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(AppCacheManifestParserTest, ExplicitUrls) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppCacheManifest manifest;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL kUrl("http://www.foo.com");
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string kData("CACHE MANIFEST\r"
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "relative/one\r"
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "# some comment\r"
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "http://www.foo.com/two#strip\r\n"
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "NETWORK:\r"
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "  \t CACHE:\r"
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "HTTP://www.diff.com/three\r"
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "FALLBACK:\r"
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    " \t # another comment with leading whitespace\n"
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "IGNORE:\r"
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "http://www.foo.com/ignore\r"
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "CACHE: \r"
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "garbage:#!@\r"
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "https://www.foo.com/diffscheme \t \r"
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "  \t relative/four#stripme\n\r"
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "*\r");
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.fallback_namespaces.empty());
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(manifest.online_whitelist_all);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::hash_set<std::string> urls = manifest.explicit_urls;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const size_t kExpected = 5;
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(kExpected, urls.size());
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/relative/one") != urls.end());
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/two") != urls.end());
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.diff.com/three") != urls.end());
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/relative/four") != urls.end());
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Wildcard is treated as a relative URL in explicit section.
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/*") != urls.end());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should get the same results with intercepts disallowed.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manifest = AppCacheManifest();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            PARSE_MANIFEST_PER_STANDARD, manifest));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.fallback_namespaces.empty());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(manifest.online_whitelist_all);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  urls = manifest.explicit_urls;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(kExpected, urls.size());
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/relative/one") != urls.end());
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/two") != urls.end());
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.diff.com/three") != urls.end());
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/relative/four") != urls.end());
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Wildcard is treated as a relative URL in explicit section.
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(urls.find("http://www.foo.com/*") != urls.end());
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST(AppCacheManifestParserTest, WhitelistUrls) {
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AppCacheManifest manifest;
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const GURL kUrl("http://www.bar.com");
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string kData("CACHE MANIFEST\r"
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "NETWORK:\r"
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "relative/one\r"
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "# a comment\r"
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "http://www.bar.com/two\r"
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "HTTP://www.diff.com/three#strip\n\r"
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "FALLBACK:\r"
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "garbage\r"
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "UNKNOWN:\r"
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    "http://www.bar.com/ignore\r"
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE:\r"
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "NETWORK:\r"
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "https://www.wrongscheme.com\n"
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    "relative/four#stripref \t \r"
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "http://www.five.com\r\n"
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "*foo\r");
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_TRUE(manifest.explicit_urls.empty());
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXPECT_TRUE(manifest.fallback_namespaces.empty());
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(manifest.intercept_namespaces.empty());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(manifest.online_whitelist_all);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kExpected = 6;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(kExpected, online.size());
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(APPCACHE_NETWORK_NAMESPACE, online[0].type);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(online[0].is_pattern);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(online[0].target_url.is_empty());
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(GURL("http://www.bar.com/relative/one"), online[0].namespace_url);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(GURL("http://www.bar.com/two"), online[1].namespace_url);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(GURL("http://www.diff.com/three"), online[2].namespace_url);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(GURL("http://www.bar.com/relative/four"), online[3].namespace_url);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(GURL("http://www.five.com"), online[4].namespace_url);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(GURL("http://www.bar.com/*foo"), online[5].namespace_url);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(AppCacheManifestParserTest, FallbackUrls) {
1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AppCacheManifest manifest;
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const GURL kUrl("http://glorp.com");
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string kData("CACHE MANIFEST\r"
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "# a comment\r"
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "CACHE:\r"
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "NETWORK:\r"
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "UNKNOWN:\r"
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "FALLBACK:\r"
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "relative/one \t \t http://glorp.com/onefb  \t \r"
186    "*\r"
187    "https://glorp.com/wrong http://glorp.com/wrongfb\r"
188    "http://glorp.com/two#strip relative/twofb\r"
189    "HTTP://glorp.com/three relative/threefb#strip\n"
190    "http://glorp.com/three http://glorp.com/three-dup\r"
191    "http://glorp.com/solo \t \r\n"
192    "http://diff.com/ignore http://glorp.com/wronghost\r"
193    "http://glorp.com/wronghost http://diff.com/ohwell\r"
194    "relative/badscheme ftp://glorp.com/ignored\r"
195    "garbage\r\n"
196    "CACHE:\r"
197    "# only fallback urls in this test\r"
198    "FALLBACK:\n"
199    "relative/four#strip relative/fourfb#strip\r"
200    "http://www.glorp.com/notsame relative/skipped\r");
201
202  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
203                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
204  EXPECT_TRUE(manifest.explicit_urls.empty());
205  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
206  EXPECT_FALSE(manifest.online_whitelist_all);
207
208  const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
209  const size_t kExpected = 5;
210  ASSERT_EQ(kExpected, fallbacks.size());
211  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
212  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[1].type);
213  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[2].type);
214  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[3].type);
215  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[4].type);
216  EXPECT_EQ(GURL("http://glorp.com/relative/one"),
217            fallbacks[0].namespace_url);
218  EXPECT_EQ(GURL("http://glorp.com/onefb"),
219            fallbacks[0].target_url);
220  EXPECT_EQ(GURL("http://glorp.com/two"),
221            fallbacks[1].namespace_url);
222  EXPECT_EQ(GURL("http://glorp.com/relative/twofb"),
223            fallbacks[1].target_url);
224  EXPECT_EQ(GURL("http://glorp.com/three"),
225            fallbacks[2].namespace_url);
226  EXPECT_EQ(GURL("http://glorp.com/relative/threefb"),
227            fallbacks[2].target_url);
228  EXPECT_EQ(GURL("http://glorp.com/three"),       // duplicates are stored
229            fallbacks[3].namespace_url);
230  EXPECT_EQ(GURL("http://glorp.com/three-dup"),
231            fallbacks[3].target_url);
232  EXPECT_EQ(GURL("http://glorp.com/relative/four"),
233            fallbacks[4].namespace_url);
234  EXPECT_EQ(GURL("http://glorp.com/relative/fourfb"),
235            fallbacks[4].target_url);
236
237  EXPECT_TRUE(manifest.intercept_namespaces.empty());
238}
239
240TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) {
241  AppCacheManifest manifest;
242  const GURL kUrl("http://www.portme.com:1234");
243  const std::string kData("CACHE MANIFEST\r"
244    "FALLBACK:\r"
245    "http://www.portme.com:1234/one relative/onefb\r"
246    "HTTP://www.portme.com:9876/wrong http://www.portme.com:1234/ignore\r"
247    "http://www.portme.com:1234/stillwrong http://www.portme.com:42/boo\r"
248    "relative/two relative/twofb\r"
249    "http://www.portme.com:1234/three HTTP://www.portme.com:1234/threefb\r"
250    "http://www.portme.com/noport http://www.portme.com:1234/skipped\r"
251    "http://www.portme.com:1234/skipme http://www.portme.com/noport\r");
252
253  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
254                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
255  EXPECT_TRUE(manifest.explicit_urls.empty());
256  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
257  EXPECT_FALSE(manifest.online_whitelist_all);
258
259  const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
260  const size_t kExpected = 3;
261  ASSERT_EQ(kExpected, fallbacks.size());
262  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
263  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[1].type);
264  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[2].type);
265  EXPECT_EQ(GURL("http://www.portme.com:1234/one"),
266            fallbacks[0].namespace_url);
267  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/onefb"),
268            fallbacks[0].target_url);
269  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"),
270            fallbacks[1].namespace_url);
271  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/twofb"),
272            fallbacks[1].target_url);
273  EXPECT_EQ(GURL("http://www.portme.com:1234/three"),
274            fallbacks[2].namespace_url);
275  EXPECT_EQ(GURL("http://www.portme.com:1234/threefb"),
276            fallbacks[2].target_url);
277
278  EXPECT_TRUE(manifest.intercept_namespaces.empty());
279}
280
281TEST(AppCacheManifestParserTest, InterceptUrls) {
282  AppCacheManifest manifest;
283  const GURL kUrl("http://www.portme.com:1234");
284  const std::string kData("CHROMIUM CACHE MANIFEST\r"
285    "CHROMIUM-INTERCEPT:\r"
286    "http://www.portme.com:1234/one return relative/int1\r"
287    "HTTP://www.portme.com:9/wrong return http://www.portme.com:1234/ignore\r"
288    "http://www.portme.com:1234/wrong return http://www.portme.com:9/boo\r"
289    "relative/two return relative/int2\r"
290    "relative/three wrong relative/threefb\r"
291    "http://www.portme.com:1234/three return HTTP://www.portme.com:1234/int3\r"
292    "http://www.portme.com/noport return http://www.portme.com:1234/skipped\r"
293    "http://www.portme.com:1234/skipme return http://www.portme.com/noport\r"
294    "relative/wrong/again missing/intercept_type\r");
295
296  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
297                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
298  EXPECT_TRUE(manifest.fallback_namespaces.empty());
299  EXPECT_TRUE(manifest.explicit_urls.empty());
300  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
301  EXPECT_FALSE(manifest.online_whitelist_all);
302
303  const AppCacheNamespaceVector& intercepts = manifest.intercept_namespaces;
304  const size_t kExpected = 3;
305  ASSERT_EQ(kExpected, intercepts.size());
306  EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE, intercepts[0].type);
307  EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE, intercepts[1].type);
308  EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE, intercepts[2].type);
309  EXPECT_EQ(GURL("http://www.portme.com:1234/one"),
310            intercepts[0].namespace_url);
311  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int1"),
312            intercepts[0].target_url);
313  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"),
314            intercepts[1].namespace_url);
315  EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int2"),
316            intercepts[1].target_url);
317  EXPECT_EQ(GURL("http://www.portme.com:1234/three"),
318            intercepts[2].namespace_url);
319  EXPECT_EQ(GURL("http://www.portme.com:1234/int3"),
320            intercepts[2].target_url);
321
322  // Disallow intercepts ths time.
323  manifest = AppCacheManifest();
324  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
325                            PARSE_MANIFEST_PER_STANDARD, manifest));
326  EXPECT_TRUE(manifest.fallback_namespaces.empty());
327  EXPECT_TRUE(manifest.explicit_urls.empty());
328  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
329  EXPECT_TRUE(manifest.intercept_namespaces.empty());
330  EXPECT_FALSE(manifest.online_whitelist_all);
331}
332
333TEST(AppCacheManifestParserTest, ComboUrls) {
334  AppCacheManifest manifest;
335  const GURL kUrl("http://combo.com:42");
336  const std::string kData("CACHE MANIFEST\r"
337    "relative/explicit-1\r"
338    "# some comment\r"
339    "http://combo.com:99/explicit-2#strip\r"
340    "NETWORK:\r"
341    "http://combo.com/whitelist-1\r"
342    "HTTP://www.diff.com/whitelist-2#strip\r"
343    "*\r"
344    "CACHE:\n\r"
345    "http://www.diff.com/explicit-3\r"
346    "FALLBACK:\r"
347    "http://combo.com:42/fallback-1 http://combo.com:42/fallback-1b\r"
348    "relative/fallback-2 relative/fallback-2b\r"
349    "UNKNOWN:\r\n"
350    "http://combo.com/ignoreme\r"
351    "relative/still-ignored\r"
352    "NETWORK:\r\n"
353    "relative/whitelist-3#strip\r"
354    "http://combo.com:99/whitelist-4\r");
355  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
356                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
357  EXPECT_TRUE(manifest.online_whitelist_all);
358
359  base::hash_set<std::string> urls = manifest.explicit_urls;
360  size_t expected = 3;
361  ASSERT_EQ(expected, urls.size());
362  EXPECT_TRUE(urls.find("http://combo.com:42/relative/explicit-1") !=
363              urls.end());
364  EXPECT_TRUE(urls.find("http://combo.com:99/explicit-2") != urls.end());
365  EXPECT_TRUE(urls.find("http://www.diff.com/explicit-3") != urls.end());
366
367  const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
368  expected = 4;
369  ASSERT_EQ(expected, online.size());
370  EXPECT_EQ(GURL("http://combo.com/whitelist-1"),
371                 online[0].namespace_url);
372  EXPECT_EQ(GURL("http://www.diff.com/whitelist-2"),
373                 online[1].namespace_url);
374  EXPECT_EQ(GURL("http://combo.com:42/relative/whitelist-3"),
375                 online[2].namespace_url);
376  EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"),
377                 online[3].namespace_url);
378
379  const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
380  expected = 2;
381  ASSERT_EQ(expected, fallbacks.size());
382  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
383  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[1].type);
384  EXPECT_EQ(GURL("http://combo.com:42/fallback-1"),
385            fallbacks[0].namespace_url);
386  EXPECT_EQ(GURL("http://combo.com:42/fallback-1b"),
387            fallbacks[0].target_url);
388  EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2"),
389            fallbacks[1].namespace_url);
390  EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2b"),
391            fallbacks[1].target_url);
392
393  EXPECT_TRUE(manifest.intercept_namespaces.empty());
394}
395
396TEST(AppCacheManifestParserTest, UnusualUtf8) {
397  AppCacheManifest manifest;
398  const GURL kUrl("http://bad.com");
399  const std::string kData("CACHE MANIFEST\r"
400    "\xC0" "invalidutf8\r"
401    "nonbmp" "\xF1\x84\xAB\xBC\r");
402  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
403                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
404  base::hash_set<std::string> urls = manifest.explicit_urls;
405  EXPECT_TRUE(urls.find("http://bad.com/%EF%BF%BDinvalidutf8") != urls.end());
406  EXPECT_TRUE(urls.find("http://bad.com/nonbmp%F1%84%AB%BC") != urls.end());
407}
408
409TEST(AppCacheManifestParserTest, IgnoreAfterSpace) {
410  AppCacheManifest manifest;
411  const GURL kUrl("http://smorg.borg");
412  const std::string kData(
413    "CACHE MANIFEST\r"
414    "resource.txt this stuff after the white space should be ignored\r");
415  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
416                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
417
418  base::hash_set<std::string> urls = manifest.explicit_urls;
419  EXPECT_TRUE(urls.find("http://smorg.borg/resource.txt") != urls.end());
420}
421
422TEST(AppCacheManifestParserTest, DifferentOriginUrlWithSecureScheme) {
423  AppCacheManifest manifest;
424  const GURL kUrl("https://www.foo.com");
425  const std::string kData("CACHE MANIFEST\r"
426    "CACHE: \r"
427    "relative/secureschemesameorigin\r"
428    "https://www.foo.com/secureschemesameorigin\r"
429    "http://www.xyz.com/secureschemedifforigin\r"
430    "https://www.xyz.com/secureschemedifforigin\r");
431
432  EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
433                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
434  EXPECT_TRUE(manifest.fallback_namespaces.empty());
435  EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
436
437  base::hash_set<std::string> urls = manifest.explicit_urls;
438  const size_t kExpected = 3;
439  ASSERT_EQ(kExpected, urls.size());
440  EXPECT_TRUE(urls.find("https://www.foo.com/relative/secureschemesameorigin")
441      != urls.end());
442  EXPECT_TRUE(urls.find("https://www.foo.com/secureschemesameorigin") !=
443      urls.end());
444  EXPECT_FALSE(urls.find("http://www.xyz.com/secureschemedifforigin") !=
445      urls.end());
446  EXPECT_TRUE(urls.find("https://www.xyz.com/secureschemedifforigin") !=
447      urls.end());
448}
449
450TEST(AppCacheManifestParserTest, PatternMatching) {
451  const GURL kUrl("http://foo.com/manifest");
452  const std::string kManifestBody(
453      "CACHE MANIFEST\r"
454      "CACHE: \r"
455      "http://foo.com/page.html\r"
456      "CHROMIUM-INTERCEPT:\r"
457      "http://foo.com/intercept_prefix return /prefix\r"
458      "http://foo.com/intercept_pattern return /pattern isPattern\r"
459      "http://foo.com/*/intercept_pattern?query return /pattern isPattern\r"
460      "FALLBACK:\r"
461      "http://foo.com/fallback_prefix  /prefix wrongAnnotation\r"
462      "http://foo.com/fallback_pattern* /pattern\tisPattern    \r"
463      "NETWORK:\r"
464      "*\r"
465      "isPattern\r"  // should not be interpretted as a pattern
466      "http://foo.com/network_pattern* isPattern\r");
467
468
469  AppCacheManifest manifest;
470  EXPECT_TRUE(ParseManifest(kUrl, kManifestBody.c_str(),
471                            kManifestBody.length(),
472                            PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
473  EXPECT_TRUE(manifest.online_whitelist_all);
474  EXPECT_EQ(1u, manifest.explicit_urls.size());
475  EXPECT_EQ(3u, manifest.intercept_namespaces.size());
476  EXPECT_EQ(2u, manifest.fallback_namespaces.size());
477  EXPECT_EQ(2u, manifest.online_whitelist_namespaces.size());
478  EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE,
479            manifest.intercept_namespaces[0].type);
480  EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, manifest.fallback_namespaces[0].type);
481  EXPECT_EQ(APPCACHE_NETWORK_NAMESPACE,
482            manifest.online_whitelist_namespaces[0].type);
483  EXPECT_FALSE(manifest.intercept_namespaces[0].is_pattern);
484  EXPECT_TRUE(manifest.intercept_namespaces[1].is_pattern);
485  EXPECT_TRUE(manifest.intercept_namespaces[2].is_pattern);
486  EXPECT_FALSE(manifest.fallback_namespaces[0].is_pattern);
487  EXPECT_TRUE(manifest.fallback_namespaces[1].is_pattern);
488  EXPECT_FALSE(manifest.online_whitelist_namespaces[0].is_pattern);
489  EXPECT_TRUE(manifest.online_whitelist_namespaces[1].is_pattern);
490  EXPECT_EQ(
491      GURL("http://foo.com/*/intercept_pattern?query"),
492      manifest.intercept_namespaces[2].namespace_url);
493  EXPECT_EQ(
494      GURL("http://foo.com/pattern"),
495      manifest.intercept_namespaces[2].target_url);
496  EXPECT_EQ(
497      GURL("http://foo.com/fallback_pattern*"),
498      manifest.fallback_namespaces[1].namespace_url);
499  EXPECT_EQ(
500      GURL("http://foo.com/pattern"),
501      manifest.fallback_namespaces[1].target_url);
502  EXPECT_EQ(
503      GURL("http://foo.com/isPattern"),
504      manifest.online_whitelist_namespaces[0].namespace_url);
505  EXPECT_EQ(
506      GURL(),
507      manifest.online_whitelist_namespaces[0].target_url);
508  EXPECT_EQ(
509      GURL("http://foo.com/network_pattern*"),
510      manifest.online_whitelist_namespaces[1].namespace_url);
511  EXPECT_EQ(
512      GURL(),
513      manifest.online_whitelist_namespaces[1].target_url);
514}
515
516}  // namespace content
517