1 // Copyright (c) 2012 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.
5 #include "chrome/browser/policy/url_blacklist_manager.h"
9 #include "base/basictypes.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "chrome/common/pref_names.h"
14 #include "content/public/test/test_browser_thread.h"
15 #include "google_apis/gaia/gaia_urls.h"
16 #include "net/base/request_priority.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
26 using content::BrowserThread;
28 class TestingURLBlacklistManager : public URLBlacklistManager {
30 explicit TestingURLBlacklistManager(PrefService* pref_service)
31 : URLBlacklistManager(pref_service),
33 set_blacklist_called_(false) {
36 virtual ~TestingURLBlacklistManager() {
39 // Make this method public for testing.
40 using URLBlacklistManager::ScheduleUpdate;
42 // Makes a direct call to UpdateOnIO during tests.
43 void UpdateOnIOForTesting() {
44 scoped_ptr<base::ListValue> block(new base::ListValue);
45 block->Append(new base::StringValue("example.com"));
46 scoped_ptr<base::ListValue> allow(new base::ListValue);
47 URLBlacklistManager::UpdateOnIO(block.Pass(), allow.Pass());
50 // URLBlacklistManager overrides:
51 virtual void SetBlacklist(scoped_ptr<URLBlacklist> blacklist) OVERRIDE {
52 set_blacklist_called_ = true;
53 URLBlacklistManager::SetBlacklist(blacklist.Pass());
56 virtual void Update() OVERRIDE {
58 URLBlacklistManager::Update();
61 int update_called() const { return update_called_; }
62 bool set_blacklist_called() const { return set_blacklist_called_; }
66 bool set_blacklist_called_;
68 DISALLOW_COPY_AND_ASSIGN(TestingURLBlacklistManager);
71 class URLBlacklistManagerTest : public testing::Test {
73 URLBlacklistManagerTest()
74 : loop_(base::MessageLoop::TYPE_IO),
75 ui_thread_(BrowserThread::UI, &loop_),
76 file_thread_(BrowserThread::FILE, &loop_),
77 io_thread_(BrowserThread::IO, &loop_) {
80 virtual void SetUp() OVERRIDE {
81 pref_service_.registry()->RegisterListPref(prefs::kUrlBlacklist);
82 pref_service_.registry()->RegisterListPref(prefs::kUrlWhitelist);
83 blacklist_manager_.reset(
84 new TestingURLBlacklistManager(&pref_service_));
88 virtual void TearDown() OVERRIDE {
89 if (blacklist_manager_.get())
90 blacklist_manager_->ShutdownOnUIThread();
92 // Delete |blacklist_manager_| while |io_thread_| is mapping IO to
94 blacklist_manager_.reset();
97 base::MessageLoop loop_;
98 TestingPrefServiceSimple pref_service_;
99 scoped_ptr<TestingURLBlacklistManager> blacklist_manager_;
102 content::TestBrowserThread ui_thread_;
103 content::TestBrowserThread file_thread_;
104 content::TestBrowserThread io_thread_;
106 DISALLOW_COPY_AND_ASSIGN(URLBlacklistManagerTest);
109 // Parameters for the FilterToComponents test.
110 struct FilterTestParams {
112 FilterTestParams(const std::string& filter, const std::string& scheme,
113 const std::string& host, bool match_subdomains, uint16 port,
114 const std::string& path)
115 : filter_(filter), scheme_(scheme), host_(host),
116 match_subdomains_(match_subdomains), port_(port), path_(path) {}
118 FilterTestParams(const FilterTestParams& params)
119 : filter_(params.filter_), scheme_(params.scheme_), host_(params.host_),
120 match_subdomains_(params.match_subdomains_), port_(params.port_),
121 path_(params.path_) {}
123 const FilterTestParams& operator=(const FilterTestParams& params) {
124 filter_ = params.filter_;
125 scheme_ = params.scheme_;
126 host_ = params.host_;
127 match_subdomains_ = params.match_subdomains_;
128 port_ = params.port_;
129 path_ = params.path_;
133 const std::string& filter() const { return filter_; }
134 const std::string& scheme() const { return scheme_; }
135 const std::string& host() const { return host_; }
136 bool match_subdomains() const { return match_subdomains_; }
137 uint16 port() const { return port_; }
138 const std::string& path() const { return path_; }
144 bool match_subdomains_;
149 // Make Valgrind happy. Without this function, a generic one will print the
150 // raw bytes in FilterTestParams, which due to some likely padding will access
151 // uninitialized memory.
152 void PrintTo(const FilterTestParams& params, std::ostream* os) {
153 *os << params.filter();
156 class URLBlacklistFilterToComponentsTest
157 : public testing::TestWithParam<FilterTestParams> {
159 URLBlacklistFilterToComponentsTest() {}
162 DISALLOW_COPY_AND_ASSIGN(URLBlacklistFilterToComponentsTest);
167 TEST_P(URLBlacklistFilterToComponentsTest, FilterToComponents) {
170 bool match_subdomains = true;
174 URLBlacklist::FilterToComponents(GetParam().filter(), &scheme, &host,
175 &match_subdomains, &port, &path);
176 EXPECT_EQ(GetParam().scheme(), scheme);
177 EXPECT_EQ(GetParam().host(), host);
178 EXPECT_EQ(GetParam().match_subdomains(), match_subdomains);
179 EXPECT_EQ(GetParam().port(), port);
180 EXPECT_EQ(GetParam().path(), path);
183 TEST_F(URLBlacklistManagerTest, SingleUpdateForTwoPrefChanges) {
184 ListValue* blacklist = new ListValue;
185 blacklist->Append(new StringValue("*.google.com"));
186 ListValue* whitelist = new ListValue;
187 whitelist->Append(new StringValue("mail.google.com"));
188 pref_service_.SetManagedPref(prefs::kUrlBlacklist, blacklist);
189 pref_service_.SetManagedPref(prefs::kUrlBlacklist, whitelist);
190 loop_.RunUntilIdle();
192 EXPECT_EQ(1, blacklist_manager_->update_called());
195 TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask0) {
196 // Post an update task to the UI thread.
197 blacklist_manager_->ScheduleUpdate();
198 // Shutdown comes before the task is executed.
199 blacklist_manager_->ShutdownOnUIThread();
200 blacklist_manager_.reset();
201 // Run the task after shutdown and deletion.
202 loop_.RunUntilIdle();
205 TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask1) {
206 // Post an update task.
207 blacklist_manager_->ScheduleUpdate();
208 // Shutdown comes before the task is executed.
209 blacklist_manager_->ShutdownOnUIThread();
210 // Run the task after shutdown, but before deletion.
211 loop_.RunUntilIdle();
213 EXPECT_EQ(0, blacklist_manager_->update_called());
214 blacklist_manager_.reset();
215 loop_.RunUntilIdle();
218 TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask2) {
219 // This posts a task to the FILE thread.
220 blacklist_manager_->UpdateOnIOForTesting();
221 // But shutdown happens before it is done.
222 blacklist_manager_->ShutdownOnUIThread();
224 EXPECT_FALSE(blacklist_manager_->set_blacklist_called());
225 blacklist_manager_.reset();
226 loop_.RunUntilIdle();
229 INSTANTIATE_TEST_CASE_P(
230 URLBlacklistFilterToComponentsTestInstance,
231 URLBlacklistFilterToComponentsTest,
233 FilterTestParams("google.com",
239 FilterTestParams(".google.com",
245 FilterTestParams("http://google.com",
251 FilterTestParams("google.com/",
257 FilterTestParams("http://google.com:8080/whatever",
263 FilterTestParams("http://user:pass@google.com:8080/whatever",
269 FilterTestParams("123.123.123.123",
275 FilterTestParams("https://123.123.123.123",
281 FilterTestParams("123.123.123.123/",
287 FilterTestParams("http://123.123.123.123:123/whatever",
293 FilterTestParams("*",
299 FilterTestParams("ftp://*",
305 FilterTestParams("http://*/whatever",
312 TEST_F(URLBlacklistManagerTest, Filtering) {
313 URLBlacklist blacklist;
315 // Block domain and all subdomains, for any filtered scheme.
316 scoped_ptr<base::ListValue> blocked(new base::ListValue);
317 blocked->Append(new base::StringValue("google.com"));
318 blacklist.Block(blocked.get());
319 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com")));
320 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com/")));
321 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com/whatever")));
322 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://google.com/")));
323 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("bogus://google.com/")));
324 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://notgoogle.com/")));
325 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://mail.google.com")));
326 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://x.mail.google.com")));
327 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://x.mail.google.com/")));
328 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://x.y.google.com/a/b")));
329 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://youtube.com/")));
331 // Filter only http, ftp and ws schemes.
332 blocked.reset(new base::ListValue);
333 blocked->Append(new base::StringValue("http://secure.com"));
334 blocked->Append(new base::StringValue("ftp://secure.com"));
335 blocked->Append(new base::StringValue("ws://secure.com"));
336 blacklist.Block(blocked.get());
337 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://secure.com")));
338 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://secure.com/whatever")));
339 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("ftp://secure.com/")));
340 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("ws://secure.com")));
341 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://secure.com/")));
342 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("wss://secure.com")));
343 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.secure.com")));
344 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://www.secure.com")));
345 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("wss://www.secure.com")));
347 // Filter only a certain path prefix.
348 blocked.reset(new base::ListValue);
349 blocked->Append(new base::StringValue("path.to/ruin"));
350 blacklist.Block(blocked.get());
351 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://path.to/ruin")));
352 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://path.to/ruin")));
353 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://path.to/ruins")));
354 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://path.to/ruin/signup")));
355 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.path.to/ruin")));
356 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://path.to/fortune")));
358 // Filter only a certain path prefix and scheme.
359 blocked.reset(new base::ListValue);
360 blocked->Append(new base::StringValue("https://s.aaa.com/path"));
361 blacklist.Block(blocked.get());
362 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://s.aaa.com/path")));
363 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://s.aaa.com/path/bbb")));
364 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.aaa.com/path")));
365 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://aaa.com/path")));
366 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://x.aaa.com/path")));
367 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.aaa.com/bbb")));
368 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.aaa.com/")));
370 // Filter only ws and wss schemes.
371 blocked.reset(new base::ListValue);
372 blocked->Append(new base::StringValue("ws://ws.aaa.com"));
373 blocked->Append(new base::StringValue("wss://ws.aaa.com"));
374 blacklist.Block(blocked.get());
375 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("ws://ws.aaa.com")));
376 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("wss://ws.aaa.com")));
377 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://ws.aaa.com")));
378 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://ws.aaa.com")));
379 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("ftp://ws.aaa.com")));
381 // Test exceptions to path prefixes, and most specific matches.
382 blocked.reset(new base::ListValue);
383 scoped_ptr<base::ListValue> allowed(new base::ListValue);
384 blocked->Append(new base::StringValue("s.xxx.com/a"));
385 allowed->Append(new base::StringValue("s.xxx.com/a/b"));
386 blocked->Append(new base::StringValue("https://s.xxx.com/a/b/c"));
387 allowed->Append(new base::StringValue("https://s.xxx.com/a/b/c/d"));
388 blacklist.Block(blocked.get());
389 blacklist.Allow(allowed.get());
390 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a")));
391 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/x")));
392 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/x")));
393 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/b")));
394 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/b")));
395 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/x")));
396 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c")));
397 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c")));
398 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/x")));
399 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d")));
400 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d")));
401 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d/x")));
402 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d/x")));
403 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://xxx.com/a")));
404 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://xxx.com/a/b")));
406 // Block an ip address.
407 blocked.reset(new base::ListValue);
408 blocked->Append(new base::StringValue("123.123.123.123"));
409 blacklist.Block(blocked.get());
410 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://123.123.123.123/")));
411 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://123.123.123.124/")));
413 // Open an exception.
414 allowed.reset(new base::ListValue);
415 allowed->Append(new base::StringValue("plus.google.com"));
416 blacklist.Allow(allowed.get());
417 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com/")));
418 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.google.com/")));
419 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://plus.google.com/")));
421 // Open an exception only when using https for mail.
422 allowed.reset(new base::ListValue);
423 allowed->Append(new base::StringValue("https://mail.google.com"));
424 blacklist.Allow(allowed.get());
425 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com/")));
426 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://mail.google.com/")));
427 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.google.com/")));
428 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://www.google.com/")));
429 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://mail.google.com/")));
431 // Match exactly "google.com", only for http. Subdomains without exceptions
432 // are still blocked.
433 allowed.reset(new base::ListValue);
434 allowed->Append(new base::StringValue("http://.google.com"));
435 blacklist.Allow(allowed.get());
436 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://google.com/")));
437 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://google.com/")));
438 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.google.com/")));
440 // A smaller path match in an exact host overrides a longer path for hosts
441 // that also match subdomains.
442 blocked.reset(new base::ListValue);
443 blocked->Append(new base::StringValue("yyy.com/aaa"));
444 blacklist.Block(blocked.get());
445 allowed.reset(new base::ListValue);
446 allowed->Append(new base::StringValue(".yyy.com/a"));
447 blacklist.Allow(allowed.get());
448 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://yyy.com")));
449 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://yyy.com/aaa")));
450 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://yyy.com/aaa2")));
451 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://www.yyy.com")));
452 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.yyy.com/aaa")));
453 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://www.yyy.com/aaa2")));
455 // If the exact entry is both allowed and blocked, allowing takes precedence.
456 blocked.reset(new base::ListValue);
457 blocked->Append(new base::StringValue("example.com"));
458 blacklist.Block(blocked.get());
459 allowed.reset(new base::ListValue);
460 allowed->Append(new base::StringValue("example.com"));
461 blacklist.Allow(allowed.get());
462 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://example.com")));
465 TEST_F(URLBlacklistManagerTest, BlockAllWithExceptions) {
466 URLBlacklist blacklist;
468 scoped_ptr<base::ListValue> blocked(new base::ListValue);
469 scoped_ptr<base::ListValue> allowed(new base::ListValue);
470 blocked->Append(new base::StringValue("*"));
471 allowed->Append(new base::StringValue(".www.google.com"));
472 allowed->Append(new base::StringValue("plus.google.com"));
473 allowed->Append(new base::StringValue("https://mail.google.com"));
474 allowed->Append(new base::StringValue("https://very.safe/path"));
475 blacklist.Block(blocked.get());
476 blacklist.Allow(allowed.get());
477 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://random.com")));
478 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://google.com")));
479 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://s.www.google.com")));
480 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://www.google.com")));
481 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://plus.google.com")));
482 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("http://s.plus.google.com")));
483 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://mail.google.com")));
484 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://mail.google.com")));
485 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://s.mail.google.com")));
486 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("https://very.safe/")));
487 EXPECT_TRUE(blacklist.IsURLBlocked(GURL("http://very.safe/path")));
488 EXPECT_FALSE(blacklist.IsURLBlocked(GURL("https://very.safe/path")));
491 TEST_F(URLBlacklistManagerTest, DontBlockResources) {
492 scoped_ptr<URLBlacklist> blacklist(new URLBlacklist());
493 scoped_ptr<base::ListValue> blocked(new base::ListValue);
494 blocked->Append(new base::StringValue("google.com"));
495 blacklist->Block(blocked.get());
496 blacklist_manager_->SetBlacklist(blacklist.Pass());
497 EXPECT_TRUE(blacklist_manager_->IsURLBlocked(GURL("http://google.com")));
499 net::TestURLRequestContext context;
500 net::URLRequest request(
501 GURL("http://google.com"), net::DEFAULT_PRIORITY, NULL, &context);
503 // Background requests aren't filtered.
504 EXPECT_FALSE(blacklist_manager_->IsRequestBlocked(request));
506 // Main frames are filtered.
507 request.set_load_flags(net::LOAD_MAIN_FRAME);
508 EXPECT_TRUE(blacklist_manager_->IsRequestBlocked(request));
510 // On most platforms, sync gets a free pass due to signin flows.
511 bool block_signin_urls = false;
512 #if defined(OS_CHROMEOS)
513 // There are no sync specific signin flows on Chrome OS, so no special
515 block_signin_urls = true;
518 GURL sync_url(GaiaUrls::GetInstance()->service_login_url().Resolve(
519 "?service=chromiumsync"));
520 net::URLRequest sync_request(sync_url, net::DEFAULT_PRIORITY, NULL, &context);
521 sync_request.set_load_flags(net::LOAD_MAIN_FRAME);
522 EXPECT_EQ(block_signin_urls,
523 blacklist_manager_->IsRequestBlocked(sync_request));
526 } // namespace policy