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 "components/policy/core/browser/url_blacklist_manager.h"
9 #include "base/basictypes.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "chrome/browser/policy/policy_helpers.h"
15 #include "chrome/common/net/url_fixer_upper.h"
16 #include "components/policy/core/common/policy_pref_names.h"
17 #include "google_apis/gaia/gaia_urls.h"
18 #include "net/base/request_priority.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
24 // TODO(joaodasilva): this file should be moved next to
25 // components/policy/core/browser/url_blacklist_manager.(cc|h).
26 // However, url_fixer_upper.h can't be included from the component. Rather
27 // than having it mocked out, the actual URLFixerUpper::SegmentURL call is used
28 // to make sure that the parsing of URL filters is correct.
34 // Helper to get the disambiguated SegmentURL() function.
35 URLBlacklist::SegmentURLCallback
GetSegmentURLCallback() {
36 return URLFixerUpper::SegmentURL
;
39 class TestingURLBlacklistManager
: public URLBlacklistManager
{
41 explicit TestingURLBlacklistManager(PrefService
* pref_service
)
42 : URLBlacklistManager(pref_service
,
43 base::MessageLoopProxy::current(),
44 base::MessageLoopProxy::current(),
45 GetSegmentURLCallback(),
48 set_blacklist_called_(false) {}
50 virtual ~TestingURLBlacklistManager() {
53 // Make this method public for testing.
54 using URLBlacklistManager::ScheduleUpdate
;
56 // Makes a direct call to UpdateOnIO during tests.
57 void UpdateOnIOForTesting() {
58 scoped_ptr
<base::ListValue
> block(new base::ListValue
);
59 block
->Append(new base::StringValue("example.com"));
60 scoped_ptr
<base::ListValue
> allow(new base::ListValue
);
61 URLBlacklistManager::UpdateOnIO(block
.Pass(), allow
.Pass());
64 // URLBlacklistManager overrides:
65 virtual void SetBlacklist(scoped_ptr
<URLBlacklist
> blacklist
) OVERRIDE
{
66 set_blacklist_called_
= true;
67 URLBlacklistManager::SetBlacklist(blacklist
.Pass());
70 virtual void Update() OVERRIDE
{
72 URLBlacklistManager::Update();
75 int update_called() const { return update_called_
; }
76 bool set_blacklist_called() const { return set_blacklist_called_
; }
80 bool set_blacklist_called_
;
82 DISALLOW_COPY_AND_ASSIGN(TestingURLBlacklistManager
);
85 class URLBlacklistManagerTest
: public testing::Test
{
87 URLBlacklistManagerTest() {}
89 virtual void SetUp() OVERRIDE
{
90 pref_service_
.registry()->RegisterListPref(policy_prefs::kUrlBlacklist
);
91 pref_service_
.registry()->RegisterListPref(policy_prefs::kUrlWhitelist
);
92 blacklist_manager_
.reset(new TestingURLBlacklistManager(&pref_service_
));
96 virtual void TearDown() OVERRIDE
{
97 if (blacklist_manager_
.get())
98 blacklist_manager_
->ShutdownOnUIThread();
100 // Delete |blacklist_manager_| while |io_thread_| is mapping IO to
102 blacklist_manager_
.reset();
105 base::MessageLoopForIO loop_
;
106 TestingPrefServiceSimple pref_service_
;
107 scoped_ptr
<TestingURLBlacklistManager
> blacklist_manager_
;
110 // Parameters for the FilterToComponents test.
111 struct FilterTestParams
{
113 FilterTestParams(const std::string
& filter
, const std::string
& scheme
,
114 const std::string
& host
, bool match_subdomains
, uint16 port
,
115 const std::string
& path
)
116 : filter_(filter
), scheme_(scheme
), host_(host
),
117 match_subdomains_(match_subdomains
), port_(port
), path_(path
) {}
119 FilterTestParams(const FilterTestParams
& params
)
120 : filter_(params
.filter_
), scheme_(params
.scheme_
), host_(params
.host_
),
121 match_subdomains_(params
.match_subdomains_
), port_(params
.port_
),
122 path_(params
.path_
) {}
124 const FilterTestParams
& operator=(const FilterTestParams
& params
) {
125 filter_
= params
.filter_
;
126 scheme_
= params
.scheme_
;
127 host_
= params
.host_
;
128 match_subdomains_
= params
.match_subdomains_
;
129 port_
= params
.port_
;
130 path_
= params
.path_
;
134 const std::string
& filter() const { return filter_
; }
135 const std::string
& scheme() const { return scheme_
; }
136 const std::string
& host() const { return host_
; }
137 bool match_subdomains() const { return match_subdomains_
; }
138 uint16
port() const { return port_
; }
139 const std::string
& path() const { return path_
; }
145 bool match_subdomains_
;
150 // Make Valgrind happy. Without this function, a generic one will print the
151 // raw bytes in FilterTestParams, which due to some likely padding will access
152 // uninitialized memory.
153 void PrintTo(const FilterTestParams
& params
, std::ostream
* os
) {
154 *os
<< params
.filter();
157 class URLBlacklistFilterToComponentsTest
158 : public testing::TestWithParam
<FilterTestParams
> {
160 URLBlacklistFilterToComponentsTest() {}
163 DISALLOW_COPY_AND_ASSIGN(URLBlacklistFilterToComponentsTest
);
168 TEST_P(URLBlacklistFilterToComponentsTest
, FilterToComponents
) {
171 bool match_subdomains
= true;
175 URLBlacklist::FilterToComponents(GetSegmentURLCallback(), GetParam().filter(),
176 &scheme
, &host
, &match_subdomains
, &port
,
178 EXPECT_EQ(GetParam().scheme(), scheme
);
179 EXPECT_EQ(GetParam().host(), host
);
180 EXPECT_EQ(GetParam().match_subdomains(), match_subdomains
);
181 EXPECT_EQ(GetParam().port(), port
);
182 EXPECT_EQ(GetParam().path(), path
);
185 TEST_F(URLBlacklistManagerTest
, SingleUpdateForTwoPrefChanges
) {
186 base::ListValue
* blacklist
= new base::ListValue
;
187 blacklist
->Append(new base::StringValue("*.google.com"));
188 base::ListValue
* whitelist
= new base::ListValue
;
189 whitelist
->Append(new base::StringValue("mail.google.com"));
190 pref_service_
.SetManagedPref(policy_prefs::kUrlBlacklist
, blacklist
);
191 pref_service_
.SetManagedPref(policy_prefs::kUrlBlacklist
, whitelist
);
192 loop_
.RunUntilIdle();
194 EXPECT_EQ(1, blacklist_manager_
->update_called());
197 TEST_F(URLBlacklistManagerTest
, ShutdownWithPendingTask0
) {
198 // Post an update task to the UI thread.
199 blacklist_manager_
->ScheduleUpdate();
200 // Shutdown comes before the task is executed.
201 blacklist_manager_
->ShutdownOnUIThread();
202 blacklist_manager_
.reset();
203 // Run the task after shutdown and deletion.
204 loop_
.RunUntilIdle();
207 TEST_F(URLBlacklistManagerTest
, ShutdownWithPendingTask1
) {
208 // Post an update task.
209 blacklist_manager_
->ScheduleUpdate();
210 // Shutdown comes before the task is executed.
211 blacklist_manager_
->ShutdownOnUIThread();
212 // Run the task after shutdown, but before deletion.
213 loop_
.RunUntilIdle();
215 EXPECT_EQ(0, blacklist_manager_
->update_called());
216 blacklist_manager_
.reset();
217 loop_
.RunUntilIdle();
220 TEST_F(URLBlacklistManagerTest
, ShutdownWithPendingTask2
) {
221 // This posts a task to the FILE thread.
222 blacklist_manager_
->UpdateOnIOForTesting();
223 // But shutdown happens before it is done.
224 blacklist_manager_
->ShutdownOnUIThread();
226 EXPECT_FALSE(blacklist_manager_
->set_blacklist_called());
227 blacklist_manager_
.reset();
228 loop_
.RunUntilIdle();
231 INSTANTIATE_TEST_CASE_P(
232 URLBlacklistFilterToComponentsTestInstance
,
233 URLBlacklistFilterToComponentsTest
,
235 FilterTestParams("google.com",
241 FilterTestParams(".google.com",
247 FilterTestParams("http://google.com",
253 FilterTestParams("google.com/",
259 FilterTestParams("http://google.com:8080/whatever",
265 FilterTestParams("http://user:pass@google.com:8080/whatever",
271 FilterTestParams("123.123.123.123",
277 FilterTestParams("https://123.123.123.123",
283 FilterTestParams("123.123.123.123/",
289 FilterTestParams("http://123.123.123.123:123/whatever",
295 FilterTestParams("*",
301 FilterTestParams("ftp://*",
307 FilterTestParams("http://*/whatever",
314 TEST_F(URLBlacklistManagerTest
, Filtering
) {
315 URLBlacklist
blacklist(GetSegmentURLCallback());
317 // Block domain and all subdomains, for any filtered scheme.
318 scoped_ptr
<base::ListValue
> blocked(new base::ListValue
);
319 blocked
->Append(new base::StringValue("google.com"));
320 blacklist
.Block(blocked
.get());
321 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com")));
322 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com/")));
323 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com/whatever")));
324 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://google.com/")));
325 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("bogus://google.com/")));
326 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://notgoogle.com/")));
327 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://mail.google.com")));
328 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://x.mail.google.com")));
329 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://x.mail.google.com/")));
330 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://x.y.google.com/a/b")));
331 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://youtube.com/")));
333 // Filter only http, ftp and ws schemes.
334 blocked
.reset(new base::ListValue
);
335 blocked
->Append(new base::StringValue("http://secure.com"));
336 blocked
->Append(new base::StringValue("ftp://secure.com"));
337 blocked
->Append(new base::StringValue("ws://secure.com"));
338 blacklist
.Block(blocked
.get());
339 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://secure.com")));
340 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://secure.com/whatever")));
341 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("ftp://secure.com/")));
342 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("ws://secure.com")));
343 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://secure.com/")));
344 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("wss://secure.com")));
345 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.secure.com")));
346 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://www.secure.com")));
347 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("wss://www.secure.com")));
349 // Filter only a certain path prefix.
350 blocked
.reset(new base::ListValue
);
351 blocked
->Append(new base::StringValue("path.to/ruin"));
352 blacklist
.Block(blocked
.get());
353 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://path.to/ruin")));
354 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://path.to/ruin")));
355 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://path.to/ruins")));
356 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://path.to/ruin/signup")));
357 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.path.to/ruin")));
358 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://path.to/fortune")));
360 // Filter only a certain path prefix and scheme.
361 blocked
.reset(new base::ListValue
);
362 blocked
->Append(new base::StringValue("https://s.aaa.com/path"));
363 blacklist
.Block(blocked
.get());
364 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://s.aaa.com/path")));
365 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://s.aaa.com/path/bbb")));
366 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.aaa.com/path")));
367 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://aaa.com/path")));
368 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://x.aaa.com/path")));
369 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.aaa.com/bbb")));
370 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.aaa.com/")));
372 // Filter only ws and wss schemes.
373 blocked
.reset(new base::ListValue
);
374 blocked
->Append(new base::StringValue("ws://ws.aaa.com"));
375 blocked
->Append(new base::StringValue("wss://ws.aaa.com"));
376 blacklist
.Block(blocked
.get());
377 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("ws://ws.aaa.com")));
378 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("wss://ws.aaa.com")));
379 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://ws.aaa.com")));
380 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://ws.aaa.com")));
381 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("ftp://ws.aaa.com")));
383 // Test exceptions to path prefixes, and most specific matches.
384 blocked
.reset(new base::ListValue
);
385 scoped_ptr
<base::ListValue
> allowed(new base::ListValue
);
386 blocked
->Append(new base::StringValue("s.xxx.com/a"));
387 allowed
->Append(new base::StringValue("s.xxx.com/a/b"));
388 blocked
->Append(new base::StringValue("https://s.xxx.com/a/b/c"));
389 allowed
->Append(new base::StringValue("https://s.xxx.com/a/b/c/d"));
390 blacklist
.Block(blocked
.get());
391 blacklist
.Allow(allowed
.get());
392 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a")));
393 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/x")));
394 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/x")));
395 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/b")));
396 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/b")));
397 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/b/x")));
398 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/b/c")));
399 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/b/c")));
400 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/x")));
401 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d")));
402 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d")));
403 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.xxx.com/a/b/c/d/x")));
404 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.xxx.com/a/b/c/d/x")));
405 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://xxx.com/a")));
406 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://xxx.com/a/b")));
408 // Block an ip address.
409 blocked
.reset(new base::ListValue
);
410 blocked
->Append(new base::StringValue("123.123.123.123"));
411 blacklist
.Block(blocked
.get());
412 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://123.123.123.123/")));
413 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://123.123.123.124/")));
415 // Open an exception.
416 allowed
.reset(new base::ListValue
);
417 allowed
->Append(new base::StringValue("plus.google.com"));
418 blacklist
.Allow(allowed
.get());
419 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com/")));
420 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.google.com/")));
421 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://plus.google.com/")));
423 // Open an exception only when using https for mail.
424 allowed
.reset(new base::ListValue
);
425 allowed
->Append(new base::StringValue("https://mail.google.com"));
426 blacklist
.Allow(allowed
.get());
427 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com/")));
428 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://mail.google.com/")));
429 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.google.com/")));
430 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://www.google.com/")));
431 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://mail.google.com/")));
433 // Match exactly "google.com", only for http. Subdomains without exceptions
434 // are still blocked.
435 allowed
.reset(new base::ListValue
);
436 allowed
->Append(new base::StringValue("http://.google.com"));
437 blacklist
.Allow(allowed
.get());
438 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://google.com/")));
439 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://google.com/")));
440 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.google.com/")));
442 // A smaller path match in an exact host overrides a longer path for hosts
443 // that also match subdomains.
444 blocked
.reset(new base::ListValue
);
445 blocked
->Append(new base::StringValue("yyy.com/aaa"));
446 blacklist
.Block(blocked
.get());
447 allowed
.reset(new base::ListValue
);
448 allowed
->Append(new base::StringValue(".yyy.com/a"));
449 blacklist
.Allow(allowed
.get());
450 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://yyy.com")));
451 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://yyy.com/aaa")));
452 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://yyy.com/aaa2")));
453 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://www.yyy.com")));
454 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.yyy.com/aaa")));
455 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://www.yyy.com/aaa2")));
457 // If the exact entry is both allowed and blocked, allowing takes precedence.
458 blocked
.reset(new base::ListValue
);
459 blocked
->Append(new base::StringValue("example.com"));
460 blacklist
.Block(blocked
.get());
461 allowed
.reset(new base::ListValue
);
462 allowed
->Append(new base::StringValue("example.com"));
463 blacklist
.Allow(allowed
.get());
464 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://example.com")));
467 TEST_F(URLBlacklistManagerTest
, BlockAllWithExceptions
) {
468 URLBlacklist
blacklist(GetSegmentURLCallback());
470 scoped_ptr
<base::ListValue
> blocked(new base::ListValue
);
471 scoped_ptr
<base::ListValue
> allowed(new base::ListValue
);
472 blocked
->Append(new base::StringValue("*"));
473 allowed
->Append(new base::StringValue(".www.google.com"));
474 allowed
->Append(new base::StringValue("plus.google.com"));
475 allowed
->Append(new base::StringValue("https://mail.google.com"));
476 allowed
->Append(new base::StringValue("https://very.safe/path"));
477 blacklist
.Block(blocked
.get());
478 blacklist
.Allow(allowed
.get());
479 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://random.com")));
480 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://google.com")));
481 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://s.www.google.com")));
482 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://www.google.com")));
483 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://plus.google.com")));
484 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("http://s.plus.google.com")));
485 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://mail.google.com")));
486 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://mail.google.com")));
487 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://s.mail.google.com")));
488 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("https://very.safe/")));
489 EXPECT_TRUE(blacklist
.IsURLBlocked(GURL("http://very.safe/path")));
490 EXPECT_FALSE(blacklist
.IsURLBlocked(GURL("https://very.safe/path")));
493 TEST_F(URLBlacklistManagerTest
, DontBlockResources
) {
494 scoped_ptr
<URLBlacklist
> blacklist(new URLBlacklist(GetSegmentURLCallback()));
495 scoped_ptr
<base::ListValue
> blocked(new base::ListValue
);
496 blocked
->Append(new base::StringValue("google.com"));
497 blacklist
->Block(blocked
.get());
498 blacklist_manager_
->SetBlacklist(blacklist
.Pass());
499 EXPECT_TRUE(blacklist_manager_
->IsURLBlocked(GURL("http://google.com")));
501 net::TestURLRequestContext context
;
502 net::URLRequest
request(
503 GURL("http://google.com"), net::DEFAULT_PRIORITY
, NULL
, &context
);
505 // Background requests aren't filtered.
506 EXPECT_FALSE(blacklist_manager_
->IsRequestBlocked(request
));
508 // Main frames are filtered.
509 request
.SetLoadFlags(net::LOAD_MAIN_FRAME
);
510 EXPECT_TRUE(blacklist_manager_
->IsRequestBlocked(request
));
512 // On most platforms, sync gets a free pass due to signin flows.
513 bool block_signin_urls
= false;
514 #if defined(OS_CHROMEOS)
515 // There are no sync specific signin flows on Chrome OS, so no special
517 block_signin_urls
= true;
520 GURL
sync_url(GaiaUrls::GetInstance()->service_login_url().Resolve(
521 "?service=chromiumsync"));
522 net::URLRequest
sync_request(sync_url
, net::DEFAULT_PRIORITY
, NULL
, &context
);
523 sync_request
.SetLoadFlags(net::LOAD_MAIN_FRAME
);
524 EXPECT_EQ(block_signin_urls
,
525 blacklist_manager_
->IsRequestBlocked(sync_request
));
528 } // namespace policy