url_blacklist_manager.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/policy/core/browser/url_blacklist_manager.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_path.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/location.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sequenced_task_runner.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task_runner_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/policy/core/common/policy_pref_names.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/base/net_util.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcher;
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherCondition;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherConditionFactory;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherConditionSet;
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherPortFilter;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherSchemeFilter;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kFileScheme[] = "file";
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum filters per policy. Filters over this index are ignored.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxFiltersPerPolicy = 1000;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A task that builds the blacklist on a background thread.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<URLBlacklist> BuildBlacklist(
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> block,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> allow,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLBlacklist::SegmentURLCallback segment_url) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<URLBlacklist> blacklist(new URLBlacklist(segment_url));
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist->Block(block.get());
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist->Allow(allow.get());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist.Pass();
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct URLBlacklist::FilterComponents {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilterComponents() : port(0), match_subdomains(true), allow(true) {}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~FilterComponents() {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 port;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool match_subdomains;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool allow;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklist::URLBlacklist(SegmentURLCallback segment_url)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : segment_url_(segment_url), id_(0), url_matcher_(new URLMatcher) {}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklist::~URLBlacklist() {}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::AddFilters(bool allow,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::ListValue* list) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLMatcherConditionSet::Vector all_conditions;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = std::min(kMaxFiltersPerPolicy, list->GetSize());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < size; ++i) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string pattern;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success = list->GetString(i, &pattern);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(success);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilterComponents components;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    components.allow = allow;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!FilterToComponents(segment_url_, pattern, &components.scheme,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            &components.host, &components.match_subdomains,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            &components.port, &components.path)) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Invalid pattern " << pattern;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_conditions.push_back(
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateConditionSet(url_matcher_.get(), ++id_, components.scheme,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           components.host, components.match_subdomains,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           components.port, components.path));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filters_[id_] = components;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_matcher_->AddConditionSets(all_conditions);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::Block(const base::ListValue* filters) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilters(false, filters);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::Allow(const base::ListValue* filters) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilters(true, filters);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklist::IsURLBlocked(const GURL& url) const {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLMatcherConditionSet::ID> matching_ids =
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_matcher_->MatchURL(url);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FilterComponents* max = NULL;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<URLMatcherConditionSet::ID>::iterator id = matching_ids.begin();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       id != matching_ids.end(); ++id) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<int, FilterComponents>::const_iterator it = filters_.find(*id);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it != filters_.end());
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FilterComponents& filter = it->second;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!max || FilterTakesPrecedence(filter, *max))
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max = &filter;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default to allow.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!max)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !max->allow;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t URLBlacklist::Size() const {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return filters_.size();
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool URLBlacklist::FilterToComponents(SegmentURLCallback segment_url,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const std::string& filter,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* scheme,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* host,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool* match_subdomains,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      uint16* port,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* path) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_parse::Parsed parsed;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (segment_url(filter, &parsed) == kFileScheme) {
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::FilePath file_path;
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!net::FileURLToFilePath(GURL(filter), &file_path))
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return false;
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *scheme = kFileScheme;
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    host->clear();
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *match_subdomains = true;
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *port = 0;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Special path when the |filter| is 'file://*'.
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *path = (filter == "file://*") ? "" : file_path.AsUTF8Unsafe();
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(FILE_PATH_USES_WIN_SEPARATORS)
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Separators have to be canonicalized on Windows.
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::replace(path->begin(), path->end(), '\\', '/');
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *path = "/" + *path;
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return true;
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parsed.host.is_nonempty())
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.scheme.is_nonempty())
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme->assign(filter, parsed.scheme.begin, parsed.scheme.len);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme->clear();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host->assign(filter, parsed.host.begin, parsed.host.len);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Special '*' host, matches all hosts.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*host == "*") {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host->clear();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *match_subdomains = true;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if ((*host)[0] == '.') {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A leading dot in the pattern syntax means that we don't want to match
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // subdomains.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host->erase(0, 1);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *match_subdomains = false;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::RawCanonOutputT<char> output;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::CanonHostInfo host_info;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::CanonicalizeHostVerbose(filter.c_str(), parsed.host,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &output, &host_info);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_info.family == url_canon::CanonHostInfo::NEUTRAL) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We want to match subdomains. Add a dot in front to make sure we only
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // match at domain component boundaries.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *host = "." + *host;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *match_subdomains = true;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *match_subdomains = false;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.port.is_nonempty()) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int int_port;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::StringToInt(filter.substr(parsed.port.begin, parsed.port.len),
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &int_port)) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (int_port <= 0 || int_port > kuint16max)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *port = int_port;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Match any port.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *port = 0;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.path.is_nonempty())
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path->assign(filter, parsed.path.begin, parsed.path.len);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path->clear();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<URLMatcherConditionSet> URLBlacklist::CreateConditionSet(
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLMatcher* url_matcher,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool match_subdomains,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint16 port,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& path) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLMatcherConditionFactory* condition_factory =
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_matcher->condition_factory();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLMatcherCondition> conditions;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  conditions.insert(match_subdomains ?
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      condition_factory->CreateHostSuffixPathPrefixCondition(host, path) :
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      condition_factory->CreateHostEqualsPathPrefixCondition(host, path));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLMatcherSchemeFilter> scheme_filter;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!scheme.empty())
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme_filter.reset(new URLMatcherSchemeFilter(scheme));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLMatcherPortFilter> port_filter;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != 0) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<URLMatcherPortFilter::Range> ranges;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ranges.push_back(URLMatcherPortFilter::CreateRange(port));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_filter.reset(new URLMatcherPortFilter(ranges));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new URLMatcherConditionSet(id, conditions,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    scheme_filter.Pass(), port_filter.Pass());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklist::FilterTakesPrecedence(const FilterComponents& lhs,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const FilterComponents& rhs) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lhs.match_subdomains && !rhs.match_subdomains)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!lhs.match_subdomains && rhs.match_subdomains)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t host_length = lhs.host.length();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t other_host_length = rhs.host.length();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_length != other_host_length)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return host_length > other_host_length;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t path_length = lhs.path.length();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t other_path_length = rhs.path.length();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_length != other_path_length)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return path_length > other_path_length;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lhs.allow && !rhs.allow)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklistManager::URLBlacklistManager(
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PrefService* pref_service,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLBlacklist::SegmentURLCallback segment_url,
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OverrideBlacklistCallback override_blacklist)
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : ui_weak_ptr_factory_(this),
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_(pref_service),
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      background_task_runner_(background_task_runner),
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      io_task_runner_(io_task_runner),
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      segment_url_(segment_url),
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      override_blacklist_(override_blacklist),
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      io_weak_ptr_factory_(this),
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui_task_runner_(base::MessageLoopProxy::current()),
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blacklist_(new URLBlacklist(segment_url)) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_change_registrar_.Init(pref_service_);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::Unretained(this));
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pref_change_registrar_.Add(policy_prefs::kUrlBlacklist, callback);
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pref_change_registrar_.Add(policy_prefs::kUrlWhitelist, callback);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start enforcing the policies without a delay when they are present at
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // startup.
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service_->HasPrefPath(policy_prefs::kUrlBlacklist))
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Update();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::ShutdownOnUIThread() {
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel any pending updates, and stop listening for pref change updates.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_weak_ptr_factory_.InvalidateWeakPtrs();
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_change_registrar_.RemoveAll();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLBlacklistManager::~URLBlacklistManager() {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::ScheduleUpdate() {
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel pending updates, if any. This can happen if two preferences that
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the blacklist are updated in one message loop cycle. In those cases,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only rebuild the blacklist after all the preference updates are processed.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_weak_ptr_factory_.InvalidateWeakPtrs();
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui_task_runner_->PostTask(
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLBlacklistManager::Update,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 ui_weak_ptr_factory_.GetWeakPtr()));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::Update() {
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The preferences can only be read on the UI thread.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> block(
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_service_->GetList(policy_prefs::kUrlBlacklist)->DeepCopy());
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> allow(
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_service_->GetList(policy_prefs::kUrlWhitelist)->DeepCopy());
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through the IO thread to grab a WeakPtr to |this|. This is safe from
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here, since this task will always execute before a potential deletion of
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProfileIOData on IO.
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  io_task_runner_->PostTask(FROM_HERE,
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            base::Bind(&URLBlacklistManager::UpdateOnIO,
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Unretained(this),
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Passed(&block),
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Passed(&allow)));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::UpdateOnIO(scoped_ptr<base::ListValue> block,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     scoped_ptr<base::ListValue> allow) {
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The URLBlacklist is built on a worker thread. Once it's ready, it is passed
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the URLBlacklistManager on IO.
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      background_task_runner_,
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BuildBlacklist,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Passed(&block),
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Passed(&allow),
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 segment_url_),
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLBlacklistManager::SetBlacklist,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 io_weak_ptr_factory_.GetWeakPtr()));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::SetBlacklist(scoped_ptr<URLBlacklist> blacklist) {
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist_ = blacklist.Pass();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklistManager::IsURLBlocked(const GURL& url) const {
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist_->IsURLBlocked(url);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool URLBlacklistManager::IsRequestBlocked(
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::URLRequest& request) const {
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(OS_IOS)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(joaodasilva): iOS doesn't set these flags. http://crbug.com/338283
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int filter_flags = net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME;
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((request.load_flags() & filter_flags) == 0)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool block = false;
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (override_blacklist_(request.url(), &block))
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return block;
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return IsURLBlocked(request.url());
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid URLBlacklistManager::RegisterProfilePrefs(
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterListPref(policy_prefs::kUrlBlacklist,
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterListPref(policy_prefs::kUrlWhitelist,
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
388