| 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 |