OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/policy/url_blacklist_manager.h" | 5 #include "chrome/browser/policy/url_blacklist_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/location.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" |
10 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
11 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/threading/worker_pool.h" |
13 #include "base/values.h" | 15 #include "base/values.h" |
14 #include "chrome/browser/chrome_notification_types.h" | 16 #include "components/policy/core/common/policy_pref_names.h" |
15 #include "chrome/common/net/url_fixer_upper.h" | |
16 #include "chrome/common/pref_names.h" | |
17 #include "components/user_prefs/pref_registry_syncable.h" | 17 #include "components/user_prefs/pref_registry_syncable.h" |
18 #include "content/public/browser/browser_thread.h" | |
19 #include "content/public/browser/notification_details.h" | |
20 #include "content/public/browser/notification_source.h" | |
21 #include "content/public/common/url_constants.h" | |
22 #include "google_apis/gaia/gaia_urls.h" | |
23 #include "net/base/load_flags.h" | 18 #include "net/base/load_flags.h" |
24 #include "net/base/net_util.h" | 19 #include "net/base/net_util.h" |
25 #include "net/url_request/url_request.h" | 20 #include "net/url_request/url_request.h" |
26 #include "url/gurl.h" | |
27 | 21 |
28 #if !defined(OS_CHROMEOS) | |
29 #include "chrome/browser/signin/signin_manager.h" | |
30 #endif | |
31 | |
32 using content::BrowserThread; | |
33 using url_matcher::URLMatcher; | 22 using url_matcher::URLMatcher; |
34 using url_matcher::URLMatcherCondition; | 23 using url_matcher::URLMatcherCondition; |
35 using url_matcher::URLMatcherConditionFactory; | 24 using url_matcher::URLMatcherConditionFactory; |
36 using url_matcher::URLMatcherConditionSet; | 25 using url_matcher::URLMatcherConditionSet; |
37 using url_matcher::URLMatcherPortFilter; | 26 using url_matcher::URLMatcherPortFilter; |
38 using url_matcher::URLMatcherSchemeFilter; | 27 using url_matcher::URLMatcherSchemeFilter; |
39 | 28 |
40 namespace policy { | 29 namespace policy { |
41 | 30 |
42 namespace { | 31 namespace { |
43 | 32 |
| 33 const char kFileScheme[] = "file"; |
| 34 |
44 // Maximum filters per policy. Filters over this index are ignored. | 35 // Maximum filters per policy. Filters over this index are ignored. |
45 const size_t kMaxFiltersPerPolicy = 1000; | 36 const size_t kMaxFiltersPerPolicy = 1000; |
46 | 37 |
47 #if !defined(OS_CHROMEOS) | 38 // A task that builds the blacklist on a background thread. |
48 | 39 void BuildBlacklist(scoped_ptr<base::ListValue> block, |
49 const char kServiceLoginAuth[] = "/ServiceLoginAuth"; | 40 scoped_ptr<base::ListValue> allow, |
50 | 41 URLBlacklist* blacklist) { |
51 bool IsSigninFlowURL(const GURL& url) { | |
52 // Whitelist all the signin flow URLs flagged by the SigninManager. | |
53 if (SigninManager::IsWebBasedSigninFlowURL(url)) | |
54 return true; | |
55 | |
56 // Additionally whitelist /ServiceLoginAuth. | |
57 if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin()) | |
58 return false; | |
59 return url.path() == kServiceLoginAuth; | |
60 } | |
61 | |
62 #endif // !defined(OS_CHROMEOS) | |
63 | |
64 // A task that builds the blacklist on the FILE thread. | |
65 scoped_ptr<URLBlacklist> BuildBlacklist(scoped_ptr<base::ListValue> block, | |
66 scoped_ptr<base::ListValue> allow) { | |
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
68 | |
69 scoped_ptr<URLBlacklist> blacklist(new URLBlacklist); | |
70 blacklist->Block(block.get()); | 42 blacklist->Block(block.get()); |
71 blacklist->Allow(allow.get()); | 43 blacklist->Allow(allow.get()); |
72 return blacklist.Pass(); | |
73 } | 44 } |
74 | 45 |
75 } // namespace | 46 } // namespace |
76 | 47 |
77 struct URLBlacklist::FilterComponents { | 48 struct URLBlacklist::FilterComponents { |
78 FilterComponents() : port(0), match_subdomains(true), allow(true) {} | 49 FilterComponents() : port(0), match_subdomains(true), allow(true) {} |
79 ~FilterComponents() {} | 50 ~FilterComponents() {} |
80 | 51 |
81 std::string scheme; | 52 std::string scheme; |
82 std::string host; | 53 std::string host; |
83 uint16 port; | 54 uint16 port; |
84 std::string path; | 55 std::string path; |
85 bool match_subdomains; | 56 bool match_subdomains; |
86 bool allow; | 57 bool allow; |
87 }; | 58 }; |
88 | 59 |
89 URLBlacklist::URLBlacklist() : id_(0), | 60 URLBlacklist::URLBlacklist(SegmentURLCallback segment_url) |
90 url_matcher_(new URLMatcher) { | 61 : segment_url_(segment_url), id_(0), url_matcher_(new URLMatcher) {} |
91 } | |
92 | 62 |
93 URLBlacklist::~URLBlacklist() { | 63 URLBlacklist::~URLBlacklist() { |
94 } | 64 } |
95 | 65 |
96 void URLBlacklist::AddFilters(bool allow, | 66 void URLBlacklist::AddFilters(bool allow, |
97 const base::ListValue* list) { | 67 const base::ListValue* list) { |
98 URLMatcherConditionSet::Vector all_conditions; | 68 URLMatcherConditionSet::Vector all_conditions; |
99 size_t size = std::min(kMaxFiltersPerPolicy, list->GetSize()); | 69 size_t size = std::min(kMaxFiltersPerPolicy, list->GetSize()); |
100 for (size_t i = 0; i < size; ++i) { | 70 for (size_t i = 0; i < size; ++i) { |
101 std::string pattern; | 71 std::string pattern; |
102 bool success = list->GetString(i, &pattern); | 72 bool success = list->GetString(i, &pattern); |
103 DCHECK(success); | 73 DCHECK(success); |
104 FilterComponents components; | 74 FilterComponents components; |
105 components.allow = allow; | 75 components.allow = allow; |
106 if (!FilterToComponents(pattern, &components.scheme, &components.host, | 76 if (!FilterToComponents(segment_url_, pattern, &components.scheme, |
107 &components.match_subdomains, &components.port, | 77 &components.host, &components.match_subdomains, |
108 &components.path)) { | 78 &components.port, &components.path)) { |
109 LOG(ERROR) << "Invalid pattern " << pattern; | 79 LOG(ERROR) << "Invalid pattern " << pattern; |
110 continue; | 80 continue; |
111 } | 81 } |
112 | 82 |
113 all_conditions.push_back( | 83 all_conditions.push_back( |
114 CreateConditionSet(url_matcher_.get(), ++id_, components.scheme, | 84 CreateConditionSet(url_matcher_.get(), ++id_, components.scheme, |
115 components.host, components.match_subdomains, | 85 components.host, components.match_subdomains, |
116 components.port, components.path)); | 86 components.port, components.path)); |
117 filters_[id_] = components; | 87 filters_[id_] = components; |
118 } | 88 } |
(...skipping 27 matching lines...) Expand all Loading... |
146 return false; | 116 return false; |
147 | 117 |
148 return !max->allow; | 118 return !max->allow; |
149 } | 119 } |
150 | 120 |
151 size_t URLBlacklist::Size() const { | 121 size_t URLBlacklist::Size() const { |
152 return filters_.size(); | 122 return filters_.size(); |
153 } | 123 } |
154 | 124 |
155 // static | 125 // static |
156 bool URLBlacklist::FilterToComponents(const std::string& filter, | 126 bool URLBlacklist::FilterToComponents(SegmentURLCallback segment_url, |
| 127 const std::string& filter, |
157 std::string* scheme, | 128 std::string* scheme, |
158 std::string* host, | 129 std::string* host, |
159 bool* match_subdomains, | 130 bool* match_subdomains, |
160 uint16* port, | 131 uint16* port, |
161 std::string* path) { | 132 std::string* path) { |
162 url_parse::Parsed parsed; | 133 url_parse::Parsed parsed; |
163 | 134 |
164 if (URLFixerUpper::SegmentURL(filter, &parsed) == chrome::kFileScheme) { | 135 if (segment_url(filter, &parsed) == kFileScheme) { |
165 base::FilePath file_path; | 136 base::FilePath file_path; |
166 if (!net::FileURLToFilePath(GURL(filter), &file_path)) | 137 if (!net::FileURLToFilePath(GURL(filter), &file_path)) |
167 return false; | 138 return false; |
168 | 139 |
169 *scheme = chrome::kFileScheme; | 140 *scheme = kFileScheme; |
170 host->clear(); | 141 host->clear(); |
171 *match_subdomains = true; | 142 *match_subdomains = true; |
172 *port = 0; | 143 *port = 0; |
173 // Special path when the |filter| is 'file://*'. | 144 // Special path when the |filter| is 'file://*'. |
174 *path = (filter == "file://*") ? "" : file_path.AsUTF8Unsafe(); | 145 *path = (filter == "file://*") ? "" : file_path.AsUTF8Unsafe(); |
175 #if defined(FILE_PATH_USES_WIN_SEPARATORS) | 146 #if defined(FILE_PATH_USES_WIN_SEPARATORS) |
176 // Separators have to be canonicalized on Windows. | 147 // Separators have to be canonicalized on Windows. |
177 std::replace(path->begin(), path->end(), '\\', '/'); | 148 std::replace(path->begin(), path->end(), '\\', '/'); |
178 *path = "/" + *path; | 149 *path = "/" + *path; |
179 #endif | 150 #endif |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 size_t other_path_length = rhs.path.length(); | 254 size_t other_path_length = rhs.path.length(); |
284 if (path_length != other_path_length) | 255 if (path_length != other_path_length) |
285 return path_length > other_path_length; | 256 return path_length > other_path_length; |
286 | 257 |
287 if (lhs.allow && !rhs.allow) | 258 if (lhs.allow && !rhs.allow) |
288 return true; | 259 return true; |
289 | 260 |
290 return false; | 261 return false; |
291 } | 262 } |
292 | 263 |
293 URLBlacklistManager::URLBlacklistManager(PrefService* pref_service) | 264 URLBlacklistManager::URLBlacklistManager( |
| 265 PrefService* pref_service, |
| 266 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner, |
| 267 URLBlacklist::SegmentURLCallback segment_url, |
| 268 SkipBlacklistCallback skip_blacklist) |
294 : ui_weak_ptr_factory_(this), | 269 : ui_weak_ptr_factory_(this), |
295 pref_service_(pref_service), | 270 pref_service_(pref_service), |
| 271 io_task_runner_(io_task_runner), |
| 272 segment_url_(segment_url), |
| 273 skip_blacklist_(skip_blacklist), |
296 io_weak_ptr_factory_(this), | 274 io_weak_ptr_factory_(this), |
297 blacklist_(new URLBlacklist) { | 275 ui_task_runner_(base::MessageLoopProxy::current()), |
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 276 blacklist_(new URLBlacklist(segment_url)) { |
299 | |
300 pref_change_registrar_.Init(pref_service_); | 277 pref_change_registrar_.Init(pref_service_); |
301 base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate, | 278 base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate, |
302 base::Unretained(this)); | 279 base::Unretained(this)); |
303 pref_change_registrar_.Add(prefs::kUrlBlacklist, callback); | 280 pref_change_registrar_.Add(policy_prefs::kUrlBlacklist, callback); |
304 pref_change_registrar_.Add(prefs::kUrlWhitelist, callback); | 281 pref_change_registrar_.Add(policy_prefs::kUrlWhitelist, callback); |
305 | 282 |
306 // Start enforcing the policies without a delay when they are present at | 283 // Start enforcing the policies without a delay when they are present at |
307 // startup. | 284 // startup. |
308 if (pref_service_->HasPrefPath(prefs::kUrlBlacklist)) | 285 if (pref_service_->HasPrefPath(policy_prefs::kUrlBlacklist)) |
309 Update(); | 286 Update(); |
310 } | 287 } |
311 | 288 |
312 void URLBlacklistManager::ShutdownOnUIThread() { | 289 void URLBlacklistManager::ShutdownOnUIThread() { |
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 290 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
314 // Cancel any pending updates, and stop listening for pref change updates. | 291 // Cancel any pending updates, and stop listening for pref change updates. |
315 ui_weak_ptr_factory_.InvalidateWeakPtrs(); | 292 ui_weak_ptr_factory_.InvalidateWeakPtrs(); |
316 pref_change_registrar_.RemoveAll(); | 293 pref_change_registrar_.RemoveAll(); |
317 } | 294 } |
318 | 295 |
319 URLBlacklistManager::~URLBlacklistManager() { | 296 URLBlacklistManager::~URLBlacklistManager() { |
320 } | 297 } |
321 | 298 |
322 void URLBlacklistManager::ScheduleUpdate() { | 299 void URLBlacklistManager::ScheduleUpdate() { |
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 300 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
324 // Cancel pending updates, if any. This can happen if two preferences that | 301 // Cancel pending updates, if any. This can happen if two preferences that |
325 // change the blacklist are updated in one message loop cycle. In those cases, | 302 // change the blacklist are updated in one message loop cycle. In those cases, |
326 // only rebuild the blacklist after all the preference updates are processed. | 303 // only rebuild the blacklist after all the preference updates are processed. |
327 ui_weak_ptr_factory_.InvalidateWeakPtrs(); | 304 ui_weak_ptr_factory_.InvalidateWeakPtrs(); |
328 base::MessageLoop::current()->PostTask( | 305 ui_task_runner_->PostTask( |
329 FROM_HERE, | 306 FROM_HERE, |
330 base::Bind(&URLBlacklistManager::Update, | 307 base::Bind(&URLBlacklistManager::Update, |
331 ui_weak_ptr_factory_.GetWeakPtr())); | 308 ui_weak_ptr_factory_.GetWeakPtr())); |
332 } | 309 } |
333 | 310 |
334 void URLBlacklistManager::Update() { | 311 void URLBlacklistManager::Update() { |
335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 312 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
336 | 313 |
337 // The preferences can only be read on the UI thread. | 314 // The preferences can only be read on the UI thread. |
338 scoped_ptr<base::ListValue> block( | 315 scoped_ptr<base::ListValue> block( |
339 pref_service_->GetList(prefs::kUrlBlacklist)->DeepCopy()); | 316 pref_service_->GetList(policy_prefs::kUrlBlacklist)->DeepCopy()); |
340 scoped_ptr<base::ListValue> allow( | 317 scoped_ptr<base::ListValue> allow( |
341 pref_service_->GetList(prefs::kUrlWhitelist)->DeepCopy()); | 318 pref_service_->GetList(policy_prefs::kUrlWhitelist)->DeepCopy()); |
342 | 319 |
343 // Go through the IO thread to grab a WeakPtr to |this|. This is safe from | 320 // Go through the IO thread to grab a WeakPtr to |this|. This is safe from |
344 // here, since this task will always execute before a potential deletion of | 321 // here, since this task will always execute before a potential deletion of |
345 // ProfileIOData on IO. | 322 // ProfileIOData on IO. |
346 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 323 io_task_runner_->PostTask(FROM_HERE, |
347 base::Bind(&URLBlacklistManager::UpdateOnIO, | 324 base::Bind(&URLBlacklistManager::UpdateOnIO, |
348 base::Unretained(this), | 325 base::Unretained(this), |
349 base::Passed(&block), | 326 base::Passed(&block), |
350 base::Passed(&allow))); | 327 base::Passed(&allow))); |
351 } | 328 } |
352 | 329 |
353 void URLBlacklistManager::UpdateOnIO(scoped_ptr<base::ListValue> block, | 330 void URLBlacklistManager::UpdateOnIO(scoped_ptr<base::ListValue> block, |
354 scoped_ptr<base::ListValue> allow) { | 331 scoped_ptr<base::ListValue> allow) { |
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 332 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
356 // The URLBlacklist is built on the FILE thread. Once it's ready, it is passed | 333 // The URLBlacklist is built on the FILE thread. Once it's ready, it is passed |
357 // to the URLBlacklistManager on IO. | 334 // to the URLBlacklistManager on IO. |
358 BrowserThread::PostTaskAndReplyWithResult( | 335 scoped_ptr<URLBlacklist> blacklist(new URLBlacklist(segment_url_)); |
359 BrowserThread::FILE, FROM_HERE, | 336 URLBlacklist* raw_blacklist = blacklist.get(); |
| 337 const bool task_is_slow = false; |
| 338 base::WorkerPool::PostTaskAndReply( |
| 339 FROM_HERE, |
360 base::Bind(&BuildBlacklist, | 340 base::Bind(&BuildBlacklist, |
361 base::Passed(&block), | 341 base::Passed(&block), |
362 base::Passed(&allow)), | 342 base::Passed(&allow), |
| 343 base::Unretained(raw_blacklist)), |
363 base::Bind(&URLBlacklistManager::SetBlacklist, | 344 base::Bind(&URLBlacklistManager::SetBlacklist, |
364 io_weak_ptr_factory_.GetWeakPtr())); | 345 io_weak_ptr_factory_.GetWeakPtr(), |
| 346 base::Passed(&blacklist)), |
| 347 task_is_slow); |
365 } | 348 } |
366 | 349 |
367 void URLBlacklistManager::SetBlacklist(scoped_ptr<URLBlacklist> blacklist) { | 350 void URLBlacklistManager::SetBlacklist(scoped_ptr<URLBlacklist> blacklist) { |
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 351 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
369 blacklist_ = blacklist.Pass(); | 352 blacklist_ = blacklist.Pass(); |
370 } | 353 } |
371 | 354 |
372 bool URLBlacklistManager::IsURLBlocked(const GURL& url) const { | 355 bool URLBlacklistManager::IsURLBlocked(const GURL& url) const { |
373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 356 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
374 return blacklist_->IsURLBlocked(url); | 357 return blacklist_->IsURLBlocked(url); |
375 } | 358 } |
376 | 359 |
377 bool URLBlacklistManager::IsRequestBlocked( | 360 bool URLBlacklistManager::IsRequestBlocked( |
378 const net::URLRequest& request) const { | 361 const net::URLRequest& request) const { |
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 362 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
380 int filter_flags = net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME; | 363 int filter_flags = net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME; |
381 if ((request.load_flags() & filter_flags) == 0) | 364 if ((request.load_flags() & filter_flags) == 0) |
382 return false; | 365 return false; |
383 | 366 |
384 #if !defined(OS_CHROMEOS) | 367 if (skip_blacklist_(request.url())) |
385 if (IsSigninFlowURL(request.url())) | |
386 return false; | 368 return false; |
387 #endif | |
388 | 369 |
389 return IsURLBlocked(request.url()); | 370 return IsURLBlocked(request.url()); |
390 } | 371 } |
391 | 372 |
392 // static | 373 // static |
393 void URLBlacklistManager::RegisterProfilePrefs( | 374 void URLBlacklistManager::RegisterProfilePrefs( |
394 user_prefs::PrefRegistrySyncable* registry) { | 375 user_prefs::PrefRegistrySyncable* registry) { |
395 registry->RegisterListPref(prefs::kUrlBlacklist, | 376 registry->RegisterListPref(policy_prefs::kUrlBlacklist, |
396 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 377 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
397 registry->RegisterListPref(prefs::kUrlWhitelist, | 378 registry->RegisterListPref(policy_prefs::kUrlWhitelist, |
398 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 379 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
399 } | 380 } |
400 | 381 |
401 } // namespace policy | 382 } // namespace policy |
OLD | NEW |