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