1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "testing/gtest/include/gtest/gtest.h"
9 #include "webkit/browser/appcache/manifest_parser.h"
13 class AppCacheManifestParserTest
: public testing::Test
{
16 TEST(AppCacheManifestParserTest
, NoData
) {
19 EXPECT_FALSE(ParseManifest(url
, "", 0, manifest
));
20 EXPECT_FALSE(ParseManifest(url
, "CACHE MANIFEST\r", 0, manifest
)); // 0 len
23 TEST(AppCacheManifestParserTest
, CheckSignature
) {
27 const std::string kBadSignatures
[] = {
29 "CACHE MANIFEST;V2\r", // not followed by whitespace
30 "CACHE MANIFEST#bad\r", // no whitespace before comment
31 "cache manifest ", // wrong case
32 "#CACHE MANIFEST\r", // comment
33 "xCACHE MANIFEST\n", // bad first char
34 " CACHE MANIFEST\r", // begins with whitespace
35 "\xEF\xBE\xBF" "CACHE MANIFEST\r", // bad UTF-8 BOM value
38 for (size_t i
= 0; i
< arraysize(kBadSignatures
); ++i
) {
39 const std::string bad
= kBadSignatures
[i
];
40 EXPECT_FALSE(ParseManifest(url
, bad
.c_str(), bad
.length(), manifest
));
43 const std::string kGoodSignatures
[] = {
49 "CACHE MANIFEST\t# ignore me\r",
50 "CACHE MANIFEST ignore\r\n",
51 "CHROMIUM CACHE MANIFEST\r\n",
52 "\xEF\xBB\xBF" "CACHE MANIFEST \r\n", // BOM present
55 for (size_t i
= 0; i
< arraysize(kGoodSignatures
); ++i
) {
56 const std::string good
= kGoodSignatures
[i
];
57 EXPECT_TRUE(ParseManifest(url
, good
.c_str(), good
.length(), manifest
));
61 TEST(AppCacheManifestParserTest
, NoManifestUrl
) {
63 const std::string
kData("CACHE MANIFEST\r"
64 "relative/tobase.com\r"
65 "http://absolute.com/addme.com");
67 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
68 EXPECT_TRUE(manifest
.explicit_urls
.empty());
69 EXPECT_TRUE(manifest
.fallback_namespaces
.empty());
70 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
71 EXPECT_FALSE(manifest
.online_whitelist_all
);
74 TEST(AppCacheManifestParserTest
, ExplicitUrls
) {
76 const GURL
kUrl("http://www.foo.com");
77 const std::string
kData("CACHE MANIFEST\r"
80 "http://www.foo.com/two#strip\r\n"
83 "HTTP://www.diff.com/three\r"
85 " \t # another comment with leading whitespace\n"
87 "http://www.foo.com/ignore\r"
90 "https://www.foo.com/diffscheme \t \r"
91 " \t relative/four#stripme\n\r"
94 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
95 EXPECT_TRUE(manifest
.fallback_namespaces
.empty());
96 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
97 EXPECT_FALSE(manifest
.online_whitelist_all
);
99 base::hash_set
<std::string
> urls
= manifest
.explicit_urls
;
100 const size_t kExpected
= 5;
101 ASSERT_EQ(kExpected
, urls
.size());
102 EXPECT_TRUE(urls
.find("http://www.foo.com/relative/one") != urls
.end());
103 EXPECT_TRUE(urls
.find("http://www.foo.com/two") != urls
.end());
104 EXPECT_TRUE(urls
.find("http://www.diff.com/three") != urls
.end());
105 EXPECT_TRUE(urls
.find("http://www.foo.com/relative/four") != urls
.end());
107 // Wildcard is treated as a relative URL in explicit section.
108 EXPECT_TRUE(urls
.find("http://www.foo.com/*") != urls
.end());
111 TEST(AppCacheManifestParserTest
, WhitelistUrls
) {
113 const GURL
kUrl("http://www.bar.com");
114 const std::string
kData("CACHE MANIFEST\r"
118 "http://www.bar.com/two\r"
119 "HTTP://www.diff.com/three#strip\n\r"
123 "http://www.bar.com/ignore\r"
126 "https://www.wrongscheme.com\n"
127 "relative/four#stripref \t \r"
128 "http://www.five.com\r\n"
131 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
132 EXPECT_TRUE(manifest
.explicit_urls
.empty());
133 EXPECT_TRUE(manifest
.fallback_namespaces
.empty());
134 EXPECT_TRUE(manifest
.intercept_namespaces
.empty());
135 EXPECT_FALSE(manifest
.online_whitelist_all
);
137 const NamespaceVector
& online
= manifest
.online_whitelist_namespaces
;
138 const size_t kExpected
= 6;
139 ASSERT_EQ(kExpected
, online
.size());
140 EXPECT_EQ(NETWORK_NAMESPACE
, online
[0].type
);
141 EXPECT_FALSE(online
[0].is_pattern
);
142 EXPECT_TRUE(online
[0].target_url
.is_empty());
143 EXPECT_EQ(GURL("http://www.bar.com/relative/one"), online
[0].namespace_url
);
144 EXPECT_EQ(GURL("http://www.bar.com/two"), online
[1].namespace_url
);
145 EXPECT_EQ(GURL("http://www.diff.com/three"), online
[2].namespace_url
);
146 EXPECT_EQ(GURL("http://www.bar.com/relative/four"), online
[3].namespace_url
);
147 EXPECT_EQ(GURL("http://www.five.com"), online
[4].namespace_url
);
148 EXPECT_EQ(GURL("http://www.bar.com/*foo"), online
[5].namespace_url
);
151 TEST(AppCacheManifestParserTest
, FallbackUrls
) {
153 const GURL
kUrl("http://glorp.com");
154 const std::string
kData("CACHE MANIFEST\r"
160 "relative/one \t \t http://glorp.com/onefb \t \r"
162 "https://glorp.com/wrong http://glorp.com/wrongfb\r"
163 "http://glorp.com/two#strip relative/twofb\r"
164 "HTTP://glorp.com/three relative/threefb#strip\n"
165 "http://glorp.com/three http://glorp.com/three-dup\r"
166 "http://glorp.com/solo \t \r\n"
167 "http://diff.com/ignore http://glorp.com/wronghost\r"
168 "http://glorp.com/wronghost http://diff.com/ohwell\r"
169 "relative/badscheme ftp://glorp.com/ignored\r"
172 "# only fallback urls in this test\r"
174 "relative/four#strip relative/fourfb#strip\r"
175 "http://www.glorp.com/notsame relative/skipped\r");
177 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
178 EXPECT_TRUE(manifest
.explicit_urls
.empty());
179 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
180 EXPECT_FALSE(manifest
.online_whitelist_all
);
182 const NamespaceVector
& fallbacks
= manifest
.fallback_namespaces
;
183 const size_t kExpected
= 5;
184 ASSERT_EQ(kExpected
, fallbacks
.size());
185 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[0].type
);
186 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[1].type
);
187 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[2].type
);
188 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[3].type
);
189 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[4].type
);
190 EXPECT_EQ(GURL("http://glorp.com/relative/one"),
191 fallbacks
[0].namespace_url
);
192 EXPECT_EQ(GURL("http://glorp.com/onefb"),
193 fallbacks
[0].target_url
);
194 EXPECT_EQ(GURL("http://glorp.com/two"),
195 fallbacks
[1].namespace_url
);
196 EXPECT_EQ(GURL("http://glorp.com/relative/twofb"),
197 fallbacks
[1].target_url
);
198 EXPECT_EQ(GURL("http://glorp.com/three"),
199 fallbacks
[2].namespace_url
);
200 EXPECT_EQ(GURL("http://glorp.com/relative/threefb"),
201 fallbacks
[2].target_url
);
202 EXPECT_EQ(GURL("http://glorp.com/three"), // duplicates are stored
203 fallbacks
[3].namespace_url
);
204 EXPECT_EQ(GURL("http://glorp.com/three-dup"),
205 fallbacks
[3].target_url
);
206 EXPECT_EQ(GURL("http://glorp.com/relative/four"),
207 fallbacks
[4].namespace_url
);
208 EXPECT_EQ(GURL("http://glorp.com/relative/fourfb"),
209 fallbacks
[4].target_url
);
211 EXPECT_TRUE(manifest
.intercept_namespaces
.empty());
214 TEST(AppCacheManifestParserTest
, FallbackUrlsWithPort
) {
216 const GURL
kUrl("http://www.portme.com:1234");
217 const std::string
kData("CACHE MANIFEST\r"
219 "http://www.portme.com:1234/one relative/onefb\r"
220 "HTTP://www.portme.com:9876/wrong http://www.portme.com:1234/ignore\r"
221 "http://www.portme.com:1234/stillwrong http://www.portme.com:42/boo\r"
222 "relative/two relative/twofb\r"
223 "http://www.portme.com:1234/three HTTP://www.portme.com:1234/threefb\r"
224 "http://www.portme.com/noport http://www.portme.com:1234/skipped\r"
225 "http://www.portme.com:1234/skipme http://www.portme.com/noport\r");
227 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
228 EXPECT_TRUE(manifest
.explicit_urls
.empty());
229 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
230 EXPECT_FALSE(manifest
.online_whitelist_all
);
232 const NamespaceVector
& fallbacks
= manifest
.fallback_namespaces
;
233 const size_t kExpected
= 3;
234 ASSERT_EQ(kExpected
, fallbacks
.size());
235 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[0].type
);
236 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[1].type
);
237 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[2].type
);
238 EXPECT_EQ(GURL("http://www.portme.com:1234/one"),
239 fallbacks
[0].namespace_url
);
240 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/onefb"),
241 fallbacks
[0].target_url
);
242 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"),
243 fallbacks
[1].namespace_url
);
244 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/twofb"),
245 fallbacks
[1].target_url
);
246 EXPECT_EQ(GURL("http://www.portme.com:1234/three"),
247 fallbacks
[2].namespace_url
);
248 EXPECT_EQ(GURL("http://www.portme.com:1234/threefb"),
249 fallbacks
[2].target_url
);
251 EXPECT_TRUE(manifest
.intercept_namespaces
.empty());
254 TEST(AppCacheManifestParserTest
, InterceptUrls
) {
256 const GURL
kUrl("http://www.portme.com:1234");
257 const std::string
kData("CHROMIUM CACHE MANIFEST\r"
258 "CHROMIUM-INTERCEPT:\r"
259 "http://www.portme.com:1234/one return relative/int1\r"
260 "HTTP://www.portme.com:9/wrong return http://www.portme.com:1234/ignore\r"
261 "http://www.portme.com:1234/wrong return http://www.portme.com:9/boo\r"
262 "relative/two return relative/int2\r"
263 "relative/three wrong relative/threefb\r"
264 "http://www.portme.com:1234/three return HTTP://www.portme.com:1234/int3\r"
265 "http://www.portme.com/noport return http://www.portme.com:1234/skipped\r"
266 "http://www.portme.com:1234/skipme return http://www.portme.com/noport\r"
267 "relative/wrong/again missing/intercept_type\r");
269 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
270 EXPECT_TRUE(manifest
.fallback_namespaces
.empty());
271 EXPECT_TRUE(manifest
.explicit_urls
.empty());
272 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
273 EXPECT_FALSE(manifest
.online_whitelist_all
);
275 const NamespaceVector
& intercepts
= manifest
.intercept_namespaces
;
276 const size_t kExpected
= 3;
277 ASSERT_EQ(kExpected
, intercepts
.size());
278 EXPECT_EQ(INTERCEPT_NAMESPACE
, intercepts
[0].type
);
279 EXPECT_EQ(INTERCEPT_NAMESPACE
, intercepts
[1].type
);
280 EXPECT_EQ(INTERCEPT_NAMESPACE
, intercepts
[2].type
);
281 EXPECT_EQ(GURL("http://www.portme.com:1234/one"),
282 intercepts
[0].namespace_url
);
283 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int1"),
284 intercepts
[0].target_url
);
285 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/two"),
286 intercepts
[1].namespace_url
);
287 EXPECT_EQ(GURL("http://www.portme.com:1234/relative/int2"),
288 intercepts
[1].target_url
);
289 EXPECT_EQ(GURL("http://www.portme.com:1234/three"),
290 intercepts
[2].namespace_url
);
291 EXPECT_EQ(GURL("http://www.portme.com:1234/int3"),
292 intercepts
[2].target_url
);
295 TEST(AppCacheManifestParserTest
, ComboUrls
) {
297 const GURL
kUrl("http://combo.com:42");
298 const std::string
kData("CACHE MANIFEST\r"
299 "relative/explicit-1\r"
301 "http://combo.com:99/explicit-2#strip\r"
303 "http://combo.com/whitelist-1\r"
304 "HTTP://www.diff.com/whitelist-2#strip\r"
307 "http://www.diff.com/explicit-3\r"
309 "http://combo.com:42/fallback-1 http://combo.com:42/fallback-1b\r"
310 "relative/fallback-2 relative/fallback-2b\r"
312 "http://combo.com/ignoreme\r"
313 "relative/still-ignored\r"
315 "relative/whitelist-3#strip\r"
316 "http://combo.com:99/whitelist-4\r");
317 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
318 EXPECT_TRUE(manifest
.online_whitelist_all
);
320 base::hash_set
<std::string
> urls
= manifest
.explicit_urls
;
322 ASSERT_EQ(expected
, urls
.size());
323 EXPECT_TRUE(urls
.find("http://combo.com:42/relative/explicit-1") !=
325 EXPECT_TRUE(urls
.find("http://combo.com:99/explicit-2") != urls
.end());
326 EXPECT_TRUE(urls
.find("http://www.diff.com/explicit-3") != urls
.end());
328 const NamespaceVector
& online
= manifest
.online_whitelist_namespaces
;
330 ASSERT_EQ(expected
, online
.size());
331 EXPECT_EQ(GURL("http://combo.com/whitelist-1"),
332 online
[0].namespace_url
);
333 EXPECT_EQ(GURL("http://www.diff.com/whitelist-2"),
334 online
[1].namespace_url
);
335 EXPECT_EQ(GURL("http://combo.com:42/relative/whitelist-3"),
336 online
[2].namespace_url
);
337 EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"),
338 online
[3].namespace_url
);
340 const NamespaceVector
& fallbacks
= manifest
.fallback_namespaces
;
342 ASSERT_EQ(expected
, fallbacks
.size());
343 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[0].type
);
344 EXPECT_EQ(FALLBACK_NAMESPACE
, fallbacks
[1].type
);
345 EXPECT_EQ(GURL("http://combo.com:42/fallback-1"),
346 fallbacks
[0].namespace_url
);
347 EXPECT_EQ(GURL("http://combo.com:42/fallback-1b"),
348 fallbacks
[0].target_url
);
349 EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2"),
350 fallbacks
[1].namespace_url
);
351 EXPECT_EQ(GURL("http://combo.com:42/relative/fallback-2b"),
352 fallbacks
[1].target_url
);
354 EXPECT_TRUE(manifest
.intercept_namespaces
.empty());
357 TEST(AppCacheManifestParserTest
, UnusualUtf8
) {
359 const GURL
kUrl("http://bad.com");
360 const std::string
kData("CACHE MANIFEST\r"
361 "\xC0" "invalidutf8\r"
362 "nonbmp" "\xF1\x84\xAB\xBC\r");
363 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
365 base::hash_set
<std::string
> urls
= manifest
.explicit_urls
;
366 EXPECT_TRUE(urls
.find("http://bad.com/%EF%BF%BDinvalidutf8") != urls
.end());
367 EXPECT_TRUE(urls
.find("http://bad.com/nonbmp%F1%84%AB%BC") != urls
.end());
370 TEST(AppCacheManifestParserTest
, IgnoreAfterSpace
) {
372 const GURL
kUrl("http://smorg.borg");
373 const std::string
kData(
375 "resource.txt this stuff after the white space should be ignored\r");
376 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
378 base::hash_set
<std::string
> urls
= manifest
.explicit_urls
;
379 EXPECT_TRUE(urls
.find("http://smorg.borg/resource.txt") != urls
.end());
382 TEST(AppCacheManifestParserTest
, DifferentOriginUrlWithSecureScheme
) {
384 const GURL
kUrl("https://www.foo.com");
385 const std::string
kData("CACHE MANIFEST\r"
387 "relative/secureschemesameorigin\r"
388 "https://www.foo.com/secureschemesameorigin\r"
389 "http://www.xyz.com/secureschemedifforigin\r"
390 "https://www.xyz.com/secureschemedifforigin\r");
392 EXPECT_TRUE(ParseManifest(kUrl
, kData
.c_str(), kData
.length(), manifest
));
393 EXPECT_TRUE(manifest
.fallback_namespaces
.empty());
394 EXPECT_TRUE(manifest
.online_whitelist_namespaces
.empty());
396 base::hash_set
<std::string
> urls
= manifest
.explicit_urls
;
397 const size_t kExpected
= 3;
398 ASSERT_EQ(kExpected
, urls
.size());
399 EXPECT_TRUE(urls
.find("https://www.foo.com/relative/secureschemesameorigin")
401 EXPECT_TRUE(urls
.find("https://www.foo.com/secureschemesameorigin") !=
403 EXPECT_FALSE(urls
.find("http://www.xyz.com/secureschemedifforigin") !=
405 EXPECT_TRUE(urls
.find("https://www.xyz.com/secureschemedifforigin") !=
409 TEST(AppCacheManifestParserTest
, PatternMatching
) {
410 const GURL
kUrl("http://foo.com/manifest");
411 const std::string
kManifestBody(
414 "http://foo.com/page.html\r"
415 "CHROMIUM-INTERCEPT:\r"
416 "http://foo.com/intercept_prefix return /prefix\r"
417 "http://foo.com/intercept_pattern return /pattern isPattern\r"
418 "http://foo.com/*/intercept_pattern?query return /pattern isPattern\r"
420 "http://foo.com/fallback_prefix /prefix wrongAnnotation\r"
421 "http://foo.com/fallback_pattern* /pattern\tisPattern \r"
424 "isPattern\r" // should not be interpretted as a pattern
425 "http://foo.com/network_pattern* isPattern\r");
429 EXPECT_TRUE(ParseManifest(kUrl
, kManifestBody
.c_str(),
430 kManifestBody
.length(), manifest
));
431 EXPECT_TRUE(manifest
.online_whitelist_all
);
432 EXPECT_EQ(1u, manifest
.explicit_urls
.size());
433 EXPECT_EQ(3u, manifest
.intercept_namespaces
.size());
434 EXPECT_EQ(2u, manifest
.fallback_namespaces
.size());
435 EXPECT_EQ(2u, manifest
.online_whitelist_namespaces
.size());
436 EXPECT_EQ(INTERCEPT_NAMESPACE
, manifest
.intercept_namespaces
[0].type
);
437 EXPECT_EQ(FALLBACK_NAMESPACE
, manifest
.fallback_namespaces
[0].type
);
438 EXPECT_EQ(NETWORK_NAMESPACE
, manifest
.online_whitelist_namespaces
[0].type
);
439 EXPECT_FALSE(manifest
.intercept_namespaces
[0].is_pattern
);
440 EXPECT_TRUE(manifest
.intercept_namespaces
[1].is_pattern
);
441 EXPECT_TRUE(manifest
.intercept_namespaces
[2].is_pattern
);
442 EXPECT_FALSE(manifest
.fallback_namespaces
[0].is_pattern
);
443 EXPECT_TRUE(manifest
.fallback_namespaces
[1].is_pattern
);
444 EXPECT_FALSE(manifest
.online_whitelist_namespaces
[0].is_pattern
);
445 EXPECT_TRUE(manifest
.online_whitelist_namespaces
[1].is_pattern
);
447 GURL("http://foo.com/*/intercept_pattern?query"),
448 manifest
.intercept_namespaces
[2].namespace_url
);
450 GURL("http://foo.com/pattern"),
451 manifest
.intercept_namespaces
[2].target_url
);
453 GURL("http://foo.com/fallback_pattern*"),
454 manifest
.fallback_namespaces
[1].namespace_url
);
456 GURL("http://foo.com/pattern"),
457 manifest
.fallback_namespaces
[1].target_url
);
459 GURL("http://foo.com/isPattern"),
460 manifest
.online_whitelist_namespaces
[0].namespace_url
);
463 manifest
.online_whitelist_namespaces
[0].target_url
);
465 GURL("http://foo.com/network_pattern*"),
466 manifest
.online_whitelist_namespaces
[1].namespace_url
);
469 manifest
.online_whitelist_namespaces
[1].target_url
);
472 } // namespace appcache