1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_url_filter.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/containers/hash_tables.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_file_value_serializer.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/sha1.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/task_runner_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/supervised_user/experimental/supervised_user_blacklist.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/policy/core/browser/url_blacklist_manager.h" 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/url_fixer/url_fixer.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/url_matcher/url_matcher.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES; 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES; 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using net::registry_controlled_domains::GetRegistryLength; 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using policy::URLBlacklist; 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcher; 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherConditionSet; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)struct SupervisedUserURLFilter::Contents { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLMatcher url_matcher; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<URLMatcherConditionSet::ID, int> matcher_site_map; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::hash_multimap<std::string, int> hash_site_map; 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<SupervisedUserSiteList::Site> sites; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// URL schemes not in this list (e.g., file:// and chrome://) will always be 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// allowed. 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kFilteredSchemes[] = { 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "http", 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "https", 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "ftp", 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "gopher", 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "ws", 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "wss" 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This class encapsulates all the state that is required during construction of 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// a new SupervisedUserURLFilter::Contents. 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FilterBuilder { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FilterBuilder(); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~FilterBuilder(); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds a single URL pattern for the site identified by |site_id|. 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool AddPattern(const std::string& pattern, int site_id); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds a single hostname SHA1 hash for the site identified by |site_id|. 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void AddHostnameHash(const std::string& hash, int site_id); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Adds all the sites in |site_list|, with URL patterns and hostname hashes. 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void AddSiteList(SupervisedUserSiteList* site_list); 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Finalizes construction of the SupervisedUserURLFilter::Contents and returns 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // them. This method should be called before this object is destroyed. 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<SupervisedUserURLFilter::Contents> Build(); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) scoped_ptr<SupervisedUserURLFilter::Contents> contents_; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLMatcherConditionSet::Vector all_conditions_; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) URLMatcherConditionSet::ID matcher_id_; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FilterBuilder::FilterBuilder() 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : contents_(new SupervisedUserURLFilter::Contents()), 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matcher_id_(0) {} 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FilterBuilder::~FilterBuilder() { 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!contents_.get()); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FilterBuilder::AddPattern(const std::string& pattern, int site_id) { 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string scheme; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string host; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint16 port; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string path; 93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string query; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool match_subdomains = true; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) URLBlacklist::SegmentURLCallback callback = 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) static_cast<URLBlacklist::SegmentURLCallback>(url_fixer::SegmentURL); 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!URLBlacklist::FilterToComponents( 98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch callback, pattern, 99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch &scheme, &host, &match_subdomains, &port, &path, &query)) { 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Invalid pattern " << pattern; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_refptr<URLMatcherConditionSet> condition_set = 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) URLBlacklist::CreateConditionSet( 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &contents_->url_matcher, ++matcher_id_, 107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scheme, host, match_subdomains, port, path, query, true); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_conditions_.push_back(condition_set); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->matcher_site_map[matcher_id_] = site_id; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FilterBuilder::AddHostnameHash(const std::string& hash, int site_id) { 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->hash_site_map.insert(std::make_pair(StringToUpperASCII(hash), 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) site_id)); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FilterBuilder::AddSiteList(SupervisedUserSiteList* site_list) { 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<SupervisedUserSiteList::Site> sites; 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) site_list->GetSites(&sites); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int site_id = contents_->sites.size(); 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (std::vector<SupervisedUserSiteList::Site>::const_iterator it = 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sites.begin(); it != sites.end(); ++it) { 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const SupervisedUserSiteList::Site& site = *it; 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->sites.push_back(site); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<std::string>::const_iterator pattern_it = 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) site.patterns.begin(); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pattern_it != site.patterns.end(); ++pattern_it) { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddPattern(*pattern_it, site_id); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::vector<std::string>::const_iterator hash_it = 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) site.hostname_hashes.begin(); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hash_it != site.hostname_hashes.end(); ++hash_it) { 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddHostnameHash(*hash_it, site_id); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) site_id++; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<SupervisedUserURLFilter::Contents> FilterBuilder::Build() { 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->url_matcher.AddConditionSets(all_conditions_); 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return contents_.Pass(); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<SupervisedUserURLFilter::Contents> CreateWhitelistFromPatterns( 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<std::string>& patterns) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FilterBuilder builder; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::const_iterator it = patterns.begin(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != patterns.end(); ++it) { 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(bauerb): We should create a fake site for the whitelist. 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) builder.AddPattern(*it, -1); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return builder.Build(); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<SupervisedUserURLFilter::Contents> 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)LoadWhitelistsOnBlockingPoolThread( 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ScopedVector<SupervisedUserSiteList> site_lists) { 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FilterBuilder builder; 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (ScopedVector<SupervisedUserSiteList>::iterator it = site_lists.begin(); 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != site_lists.end(); ++it) { 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) builder.AddSiteList(*it); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return builder.Build(); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::SupervisedUserURLFilter() 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : default_behavior_(ALLOW), 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci contents_(new Contents()), 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci blacklist_(NULL) { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Detach from the current thread so we can be constructed on a different 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread than the one where we're used. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DetachFromThread(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::~SupervisedUserURLFilter() { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::FilteringBehavior 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::BehaviorFromInt(int behavior_value) { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(behavior_value, ALLOW); 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LE(behavior_value, BLOCK); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return static_cast<FilteringBehavior>(behavior_value); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GURL SupervisedUserURLFilter::Normalize(const GURL& url) { 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL normalized_url = url; 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL::Replacements replacements; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Strip username, password, query, and ref. 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacements.ClearUsername(); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacements.ClearPassword(); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacements.ClearQuery(); 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) replacements.ClearRef(); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return url.ReplaceComponents(replacements); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SupervisedUserURLFilter::HasFilteredScheme(const GURL& url) { 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i < arraysize(kFilteredSchemes); ++i) { 2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (url.scheme() == kFilteredSchemes[i]) 2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string GetHostnameHash(const GURL& url) { 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string hash = base::SHA1HashString(url.host()); 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::HexEncode(hash.data(), hash.length()); 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SupervisedUserURLFilter::HostMatchesPattern(const std::string& host, 228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string& pattern) { 2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string trimmed_pattern = pattern; 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string trimmed_host = host; 2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (EndsWith(pattern, ".*", true)) { 2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) size_t registry_length = GetRegistryLength( 2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) trimmed_host, EXCLUDE_UNKNOWN_REGISTRIES, EXCLUDE_PRIVATE_REGISTRIES); 2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // A host without a known registry part does not match. 2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (registry_length == 0) 2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) trimmed_pattern.erase(trimmed_pattern.length() - 2); 2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) trimmed_host.erase(trimmed_host.length() - (registry_length + 1)); 2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (StartsWithASCII(trimmed_pattern, "*.", true)) { 2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) trimmed_pattern.erase(0, 2); 2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The remaining pattern should be non-empty, and it should not contain 2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // further stars. Also the trimmed host needs to end with the trimmed 2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // pattern. 2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (trimmed_pattern.empty() || 2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) trimmed_pattern.find('*') != std::string::npos || 2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) !EndsWith(trimmed_host, trimmed_pattern, true)) { 2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return false; 2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The trimmed host needs to have a dot separating the subdomain from the 2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // matched pattern piece, unless there is no subdomain. 2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int pos = trimmed_host.length() - trimmed_pattern.length(); 2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DCHECK_GE(pos, 0); 2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return (pos == 0) || (trimmed_host[pos - 1] == '.'); 2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return trimmed_host == trimmed_pattern; 2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::FilteringBehavior 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserURLFilter::GetFilteringBehaviorForURL(const GURL& url) const { 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // URLs with a non-standard scheme (e.g. chrome://) are always allowed. 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!HasFilteredScheme(url)) 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ALLOW; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check manual overrides for the exact URL. 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<GURL, bool>::const_iterator url_it = url_map_.find(Normalize(url)); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (url_it != url_map_.end()) 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return url_it->second ? ALLOW : BLOCK; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check manual overrides for the hostname. 2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string host = url.host(); 2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::map<std::string, bool>::const_iterator host_it = host_map_.find(host); 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (host_it != host_map_.end()) 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return host_it->second ? ALLOW : BLOCK; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Look for patterns matching the hostname, with a value that is different 2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // from the default (a value of true in the map meaning allowed). 2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (std::map<std::string, bool>::const_iterator host_it = 2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) host_map_.begin(); host_it != host_map_.end(); ++host_it) { 2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if ((host_it->second == (default_behavior_ == BLOCK)) && 2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HostMatchesPattern(host, host_it->first)) { 2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return host_it->second ? ALLOW : BLOCK; 2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If there's no blacklist and the default behavior is to allow, we don't need 2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // to check anything else. 2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!blacklist_ && default_behavior_ == ALLOW) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ALLOW; 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check the list of URL patterns. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<URLMatcherConditionSet::ID> matching_ids = 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->url_matcher.MatchURL(url); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!matching_ids.empty()) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ALLOW; 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check the list of hostname hashes. 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (contents_->hash_site_map.count(GetHostnameHash(url))) 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ALLOW; 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Check the static blacklist. 3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (blacklist_ && blacklist_->HasURL(url)) 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return BLOCK; 3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fall back to the default behavior. 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return default_behavior_; 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::GetSites( 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& url, 318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<SupervisedUserSiteList::Site*>* sites) const { 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::set<URLMatcherConditionSet::ID> matching_ids = 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->url_matcher.MatchURL(url); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::set<URLMatcherConditionSet::ID>::const_iterator it = 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matching_ids.begin(); it != matching_ids.end(); ++it) { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::map<URLMatcherConditionSet::ID, int>::const_iterator entry = 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->matcher_site_map.find(*it); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (entry == contents_->matcher_site_map.end()) { 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sites->push_back(&contents_->sites[entry->second]); 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef base::hash_multimap<std::string, int>::const_iterator 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hash_site_map_iterator; 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::pair<hash_site_map_iterator, hash_site_map_iterator> bounds = 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) contents_->hash_site_map.equal_range(GetHostnameHash(url)); 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (hash_site_map_iterator hash_it = bounds.first; 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hash_it != bounds.second; hash_it++) { 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sites->push_back(&contents_->sites[hash_it->second]); 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::SetDefaultFilteringBehavior( 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FilteringBehavior behavior) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default_behavior_ = behavior; 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::LoadWhitelists( 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ScopedVector<SupervisedUserSiteList> site_lists) { 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PostTaskAndReplyWithResult( 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::GetBlockingPool(), 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FROM_HERE, 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&LoadWhitelistsOnBlockingPoolThread, 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&site_lists)), 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&SupervisedUserURLFilter::SetContents, this)); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid SupervisedUserURLFilter::SetBlacklist(SupervisedUserBlacklist* blacklist) { 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci blacklist_ = blacklist; 3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::SetFromPatterns( 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<std::string>& patterns) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::PostTaskAndReplyWithResult( 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::GetBlockingPool(), 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&CreateWhitelistFromPatterns, patterns), 372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&SupervisedUserURLFilter::SetContents, this)); 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::SetManualHosts( 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::map<std::string, bool>* host_map) { 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_map_ = *host_map; 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_CUSTOM_COUNTS("ManagedMode.ManualHostsEntries", 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) host_map->size(), 1, 1000, 50); 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::SetManualURLs( 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::map<GURL, bool>* url_map) { 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_map_ = *url_map; 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_CUSTOM_COUNTS("ManagedMode.ManualURLsEntries", 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) url_map->size(), 1, 1000, 50); 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::AddObserver(Observer* observer) { 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::RemoveObserver(Observer* observer) { 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserURLFilter::SetContents(scoped_ptr<Contents> contents) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_ = contents.Pass(); 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observers_, OnSiteListUpdated()); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 404