url_blacklist_manager.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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"
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/filename_util.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/load_flags.h"
21c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/base/net_errors.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcher;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherCondition;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherConditionFactory;
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherConditionSet;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherPortFilter;
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using url_matcher::URLMatcherSchemeFilter;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kFileScheme[] = "file";
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum filters per policy. Filters over this index are ignored.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxFiltersPerPolicy = 1000;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A task that builds the blacklist on a background thread.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<URLBlacklist> BuildBlacklist(
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> block,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> allow,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLBlacklist::SegmentURLCallback segment_url) {
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<URLBlacklist> blacklist(new URLBlacklist(segment_url));
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist->Block(block.get());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist->Allow(allow.get());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist.Pass();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct URLBlacklist::FilterComponents {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilterComponents() : port(0), match_subdomains(true), allow(true) {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~FilterComponents() {}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 port;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool match_subdomains;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool allow;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklist::URLBlacklist(SegmentURLCallback segment_url)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : segment_url_(segment_url), id_(0), url_matcher_(new URLMatcher) {}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklist::~URLBlacklist() {}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::AddFilters(bool allow,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::ListValue* list) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLMatcherConditionSet::Vector all_conditions;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = std::min(kMaxFiltersPerPolicy, list->GetSize());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < size; ++i) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string pattern;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success = list->GetString(i, &pattern);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(success);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilterComponents components;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    components.allow = allow;
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!FilterToComponents(segment_url_, pattern, &components.scheme,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            &components.host, &components.match_subdomains,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            &components.port, &components.path)) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Invalid pattern " << pattern;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_conditions.push_back(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateConditionSet(url_matcher_.get(), ++id_, components.scheme,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           components.host, components.match_subdomains,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           components.port, components.path));
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filters_[id_] = components;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_matcher_->AddConditionSets(all_conditions);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::Block(const base::ListValue* filters) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilters(false, filters);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklist::Allow(const base::ListValue* filters) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddFilters(true, filters);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklist::IsURLBlocked(const GURL& url) const {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLMatcherConditionSet::ID> matching_ids =
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_matcher_->MatchURL(url);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FilterComponents* max = NULL;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<URLMatcherConditionSet::ID>::iterator id = matching_ids.begin();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       id != matching_ids.end(); ++id) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<int, FilterComponents>::const_iterator it = filters_.find(*id);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(it != filters_.end());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FilterComponents& filter = it->second;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!max || FilterTakesPrecedence(filter, *max))
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max = &filter;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default to allow.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!max)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !max->allow;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t URLBlacklist::Size() const {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return filters_.size();
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool URLBlacklist::FilterToComponents(SegmentURLCallback segment_url,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const std::string& filter,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* scheme,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* host,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool* match_subdomains,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      uint16* port,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      std::string* path) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_parse::Parsed parsed;
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (segment_url(filter, &parsed) == kFileScheme) {
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::FilePath file_path;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!net::FileURLToFilePath(GURL(filter), &file_path))
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return false;
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *scheme = kFileScheme;
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    host->clear();
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *match_subdomains = true;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *port = 0;
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Special path when the |filter| is 'file://*'.
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *path = (filter == "file://*") ? "" : file_path.AsUTF8Unsafe();
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(FILE_PATH_USES_WIN_SEPARATORS)
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Separators have to be canonicalized on Windows.
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::replace(path->begin(), path->end(), '\\', '/');
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *path = "/" + *path;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return true;
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parsed.host.is_nonempty())
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.scheme.is_nonempty())
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme->assign(filter, parsed.scheme.begin, parsed.scheme.len);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme->clear();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host->assign(filter, parsed.host.begin, parsed.host.len);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Special '*' host, matches all hosts.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*host == "*") {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host->clear();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *match_subdomains = true;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if ((*host)[0] == '.') {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A leading dot in the pattern syntax means that we don't want to match
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // subdomains.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host->erase(0, 1);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *match_subdomains = false;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::RawCanonOutputT<char> output;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::CanonHostInfo host_info;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_canon::CanonicalizeHostVerbose(filter.c_str(), parsed.host,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &output, &host_info);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_info.family == url_canon::CanonHostInfo::NEUTRAL) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We want to match subdomains. Add a dot in front to make sure we only
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // match at domain component boundaries.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *host = "." + *host;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *match_subdomains = true;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *match_subdomains = false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.port.is_nonempty()) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int int_port;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::StringToInt(filter.substr(parsed.port.begin, parsed.port.len),
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &int_port)) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (int_port <= 0 || int_port > kuint16max)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *port = int_port;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Match any port.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *port = 0;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed.path.is_nonempty())
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path->assign(filter, parsed.path.begin, parsed.path.len);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path->clear();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_refptr<URLMatcherConditionSet> URLBlacklist::CreateConditionSet(
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLMatcher* url_matcher,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& scheme,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& host,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool match_subdomains,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint16 port,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& path) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLMatcherConditionFactory* condition_factory =
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_matcher->condition_factory();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<URLMatcherCondition> conditions;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  conditions.insert(match_subdomains ?
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      condition_factory->CreateHostSuffixPathPrefixCondition(host, path) :
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      condition_factory->CreateHostEqualsPathPrefixCondition(host, path));
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLMatcherSchemeFilter> scheme_filter;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!scheme.empty())
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme_filter.reset(new URLMatcherSchemeFilter(scheme));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<URLMatcherPortFilter> port_filter;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != 0) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<URLMatcherPortFilter::Range> ranges;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ranges.push_back(URLMatcherPortFilter::CreateRange(port));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_filter.reset(new URLMatcherPortFilter(ranges));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new URLMatcherConditionSet(id, conditions,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    scheme_filter.Pass(), port_filter.Pass());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklist::FilterTakesPrecedence(const FilterComponents& lhs,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const FilterComponents& rhs) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lhs.match_subdomains && !rhs.match_subdomains)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!lhs.match_subdomains && rhs.match_subdomains)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t host_length = lhs.host.length();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t other_host_length = rhs.host.length();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_length != other_host_length)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return host_length > other_host_length;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t path_length = lhs.path.length();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t other_path_length = rhs.path.length();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_length != other_path_length)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return path_length > other_path_length;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (lhs.allow && !rhs.allow)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)URLBlacklistManager::URLBlacklistManager(
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PrefService* pref_service,
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    URLBlacklist::SegmentURLCallback segment_url,
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OverrideBlacklistCallback override_blacklist)
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : ui_weak_ptr_factory_(this),
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_(pref_service),
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      background_task_runner_(background_task_runner),
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      io_task_runner_(io_task_runner),
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      segment_url_(segment_url),
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      override_blacklist_(override_blacklist),
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      io_weak_ptr_factory_(this),
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui_task_runner_(base::MessageLoopProxy::current()),
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      blacklist_(new URLBlacklist(segment_url)) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_change_registrar_.Init(pref_service_);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate,
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::Unretained(this));
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pref_change_registrar_.Add(policy_prefs::kUrlBlacklist, callback);
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pref_change_registrar_.Add(policy_prefs::kUrlWhitelist, callback);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start enforcing the policies without a delay when they are present at
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // startup.
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pref_service_->HasPrefPath(policy_prefs::kUrlBlacklist))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Update();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::ShutdownOnUIThread() {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel any pending updates, and stop listening for pref change updates.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_weak_ptr_factory_.InvalidateWeakPtrs();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_change_registrar_.RemoveAll();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLBlacklistManager::~URLBlacklistManager() {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::ScheduleUpdate() {
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cancel pending updates, if any. This can happen if two preferences that
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change the blacklist are updated in one message loop cycle. In those cases,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only rebuild the blacklist after all the preference updates are processed.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui_weak_ptr_factory_.InvalidateWeakPtrs();
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ui_task_runner_->PostTask(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLBlacklistManager::Update,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 ui_weak_ptr_factory_.GetWeakPtr()));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::Update() {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The preferences can only be read on the UI thread.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> block(
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_service_->GetList(policy_prefs::kUrlBlacklist)->DeepCopy());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> allow(
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_service_->GetList(policy_prefs::kUrlWhitelist)->DeepCopy());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through the IO thread to grab a WeakPtr to |this|. This is safe from
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here, since this task will always execute before a potential deletion of
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProfileIOData on IO.
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  io_task_runner_->PostTask(FROM_HERE,
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            base::Bind(&URLBlacklistManager::UpdateOnIO,
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Unretained(this),
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Passed(&block),
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::Passed(&allow)));
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::UpdateOnIO(scoped_ptr<base::ListValue> block,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     scoped_ptr<base::ListValue> allow) {
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The URLBlacklist is built on a worker thread. Once it's ready, it is passed
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the URLBlacklistManager on IO.
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      background_task_runner_,
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&BuildBlacklist,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Passed(&block),
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Passed(&allow),
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 segment_url_),
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLBlacklistManager::SetBlacklist,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 io_weak_ptr_factory_.GetWeakPtr()));
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLBlacklistManager::SetBlacklist(scoped_ptr<URLBlacklist> blacklist) {
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  blacklist_ = blacklist.Pass();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLBlacklistManager::IsURLBlocked(const GURL& url) const {
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return blacklist_->IsURLBlocked(url);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool URLBlacklistManager::IsRequestBlocked(
363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const net::URLRequest& request, int* reason) const {
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(OS_IOS)
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(joaodasilva): iOS doesn't set these flags. http://crbug.com/338283
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int filter_flags = net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME;
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((request.load_flags() & filter_flags) == 0)
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool block = false;
373c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (override_blacklist_.Run(request.url(), &block, reason))
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return block;
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  *reason = net::ERR_BLOCKED_BY_ADMINISTRATOR;
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return IsURLBlocked(request.url());
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid URLBlacklistManager::RegisterProfilePrefs(
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterListPref(policy_prefs::kUrlBlacklist,
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterListPref(policy_prefs::kUrlWhitelist,
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
390