Home | History | Annotate | Download | only in suggestions
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/suggestions/blacklist_store.h"
      6 
      7 #include <set>
      8 #include <string>
      9 
     10 #include "base/base64.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "components/pref_registry/pref_registry_syncable.h"
     14 #include "components/suggestions/suggestions_pref_names.h"
     15 
     16 namespace suggestions {
     17 
     18 namespace {
     19 
     20 void PopulateBlacklistSet(const SuggestionsBlacklist& blacklist_proto,
     21                           std::set<std::string>* blacklist_set) {
     22   blacklist_set->clear();
     23   for (int i = 0; i < blacklist_proto.urls_size(); ++i) {
     24     blacklist_set->insert(blacklist_proto.urls(i));
     25   }
     26 }
     27 
     28 void PopulateBlacklistProto(const std::set<std::string>& blacklist_set,
     29                             SuggestionsBlacklist* blacklist_proto) {
     30   blacklist_proto->Clear();
     31   for (std::set<std::string>::const_iterator it = blacklist_set.begin();
     32        it != blacklist_set.end(); ++it) {
     33     blacklist_proto->add_urls(*it);
     34   }
     35 }
     36 
     37 }  // namespace
     38 
     39 BlacklistStore::BlacklistStore(PrefService* profile_prefs)
     40     : pref_service_(profile_prefs) {
     41   DCHECK(pref_service_);
     42 
     43   // Log the blacklist's size. A single BlacklistStore is created for the
     44   // SuggestionsService; this will run once.
     45   SuggestionsBlacklist blacklist_proto;
     46   LoadBlacklist(&blacklist_proto);
     47   UMA_HISTOGRAM_COUNTS_10000("Suggestions.LocalBlacklistSize",
     48                              blacklist_proto.urls_size());
     49 }
     50 
     51 BlacklistStore::~BlacklistStore() {}
     52 
     53 bool BlacklistStore::BlacklistUrl(const GURL& url) {
     54   if (!url.is_valid()) return false;
     55 
     56   SuggestionsBlacklist blacklist_proto;
     57   LoadBlacklist(&blacklist_proto);
     58 
     59   std::set<std::string> blacklist_set;
     60   PopulateBlacklistSet(blacklist_proto, &blacklist_set);
     61 
     62   if (!blacklist_set.insert(url.spec()).second) {
     63     // |url| was already in the blacklist.
     64     return true;
     65   }
     66 
     67   PopulateBlacklistProto(blacklist_set, &blacklist_proto);
     68   return StoreBlacklist(blacklist_proto);
     69 }
     70 
     71 bool BlacklistStore::GetFirstUrlFromBlacklist(GURL* url) {
     72   SuggestionsBlacklist blacklist;
     73   LoadBlacklist(&blacklist);
     74   if (!blacklist.urls_size()) return false;
     75   GURL blacklisted(blacklist.urls(0));
     76   url->Swap(&blacklisted);
     77   return true;
     78 }
     79 
     80 bool BlacklistStore::RemoveUrl(const GURL& url) {
     81   if (!url.is_valid()) return false;
     82   const std::string removal_candidate = url.spec();
     83 
     84   SuggestionsBlacklist blacklist;
     85   LoadBlacklist(&blacklist);
     86 
     87   SuggestionsBlacklist updated_blacklist;
     88   for (int i = 0; i < blacklist.urls_size(); ++i) {
     89     if (blacklist.urls(i) != removal_candidate)
     90       updated_blacklist.add_urls(blacklist.urls(i));
     91   }
     92 
     93   return StoreBlacklist(updated_blacklist);
     94 }
     95 
     96 void BlacklistStore::FilterSuggestions(SuggestionsProfile* profile) {
     97   if (!profile->suggestions_size())
     98     return;  // Empty profile, nothing to filter.
     99 
    100   SuggestionsBlacklist blacklist_proto;
    101   if (!LoadBlacklist(&blacklist_proto)) {
    102     // There was an error loading the blacklist. The blacklist was cleared and
    103     // there's nothing to be done about it.
    104     return;
    105   }
    106   if (!blacklist_proto.urls_size())
    107     return;  // Empty blacklist, nothing to filter.
    108 
    109   std::set<std::string> blacklist_set;
    110   PopulateBlacklistSet(blacklist_proto, &blacklist_set);
    111 
    112   // Populate the filtered suggestions.
    113   SuggestionsProfile filtered_profile;
    114   for (int i = 0; i < profile->suggestions_size(); ++i) {
    115     if (blacklist_set.find(profile->suggestions(i).url()) ==
    116         blacklist_set.end()) {
    117       // This suggestion is not blacklisted.
    118       ChromeSuggestion* suggestion = filtered_profile.add_suggestions();
    119       // Note: swapping!
    120       suggestion->Swap(profile->mutable_suggestions(i));
    121     }
    122   }
    123 
    124   // Swap |profile| and |filtered_profile|.
    125   profile->Swap(&filtered_profile);
    126 }
    127 
    128 // static
    129 void BlacklistStore::RegisterProfilePrefs(
    130     user_prefs::PrefRegistrySyncable* registry) {
    131   registry->RegisterStringPref(
    132       prefs::kSuggestionsBlacklist, std::string(),
    133       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    134 }
    135 
    136 bool BlacklistStore::LoadBlacklist(SuggestionsBlacklist* blacklist) {
    137   DCHECK(blacklist);
    138 
    139   const std::string base64_blacklist_data =
    140       pref_service_->GetString(prefs::kSuggestionsBlacklist);
    141   if (base64_blacklist_data.empty()) {
    142     blacklist->Clear();
    143     return false;
    144   }
    145 
    146   // If the decode process fails, assume the pref value is corrupt and clear it.
    147   std::string blacklist_data;
    148   if (!base::Base64Decode(base64_blacklist_data, &blacklist_data) ||
    149       !blacklist->ParseFromString(blacklist_data)) {
    150     VLOG(1) << "Suggestions blacklist data in profile pref is corrupt, "
    151             << " clearing it.";
    152     blacklist->Clear();
    153     ClearBlacklist();
    154     return false;
    155   }
    156 
    157   return true;
    158 }
    159 
    160 bool BlacklistStore::StoreBlacklist(const SuggestionsBlacklist& blacklist) {
    161   std::string blacklist_data;
    162   if (!blacklist.SerializeToString(&blacklist_data)) return false;
    163 
    164   std::string base64_blacklist_data;
    165   base::Base64Encode(blacklist_data, &base64_blacklist_data);
    166 
    167   pref_service_->SetString(prefs::kSuggestionsBlacklist, base64_blacklist_data);
    168   return true;
    169 }
    170 
    171 void BlacklistStore::ClearBlacklist() {
    172   pref_service_->ClearPref(prefs::kSuggestionsBlacklist);
    173 }
    174 
    175 }  // namespace suggestions
    176