Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / safe_browsing / incident_reporting / state_store.cc
blob51e125cea1c7754a2d27d211bca392215f7c5d5d
1 // Copyright 2015 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.
5 #include "chrome/browser/safe_browsing/incident_reporting/state_store.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/values.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
12 #include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h"
13 #include "chrome/common/pref_names.h"
15 namespace safe_browsing {
17 // StateStore::Transaction -----------------------------------------------------
19 StateStore::Transaction::Transaction(StateStore* store) : store_(store) {
20 #if DCHECK_IS_ON()
21 DCHECK(!store_->has_transaction_);
22 store_->has_transaction_ = true;
23 #endif
26 StateStore::Transaction::~Transaction() {
27 #if DCHECK_IS_ON()
28 store_->has_transaction_ = false;
29 #endif
30 if (pref_update_)
31 platform_state_store::Store(store_->profile_, store_->incidents_sent_);
34 void StateStore::Transaction::MarkAsReported(IncidentType type,
35 const std::string& key,
36 IncidentDigest digest) {
37 std::string type_string(base::IntToString(static_cast<int32_t>(type)));
38 base::DictionaryValue* incidents_sent = GetPrefDict();
39 base::DictionaryValue* type_dict = nullptr;
40 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
41 &type_dict)) {
42 type_dict = new base::DictionaryValue();
43 incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
45 type_dict->SetStringWithoutPathExpansion(key, base::UintToString(digest));
48 void StateStore::Transaction::ClearForType(IncidentType type) {
49 // Nothing to do if the pref dict does not exist.
50 if (!store_->incidents_sent_)
51 return;
53 // Use the read-only view on the preference to figure out if there is a value
54 // to remove before committing to making a change since any use of GetPrefDict
55 // will result in a full serialize-and-write operation on the preferences
56 // store.
57 std::string type_string(base::IntToString(static_cast<int32_t>(type)));
58 const base::DictionaryValue* type_dict = nullptr;
59 if (store_->incidents_sent_->GetDictionaryWithoutPathExpansion(type_string,
60 &type_dict)) {
61 GetPrefDict()->RemoveWithoutPathExpansion(type_string, nullptr);
65 void StateStore::Transaction::ClearAll() {
66 if (pref_update_)
67 pref_update_.reset();
68 if (store_->incidents_sent_) {
69 store_->incidents_sent_ = nullptr;
70 store_->profile_->GetPrefs()->ClearPref(prefs::kSafeBrowsingIncidentsSent);
74 base::DictionaryValue* StateStore::Transaction::GetPrefDict() {
75 if (!pref_update_) {
76 pref_update_.reset(new DictionaryPrefUpdate(
77 store_->profile_->GetPrefs(), prefs::kSafeBrowsingIncidentsSent));
78 // Getting the dict will cause it to be created if it doesn't exist.
79 // Unconditionally refresh the store's read-only view on the preference so
80 // that it will always be correct.
81 store_->incidents_sent_ = pref_update_->Get();
83 return pref_update_->Get();
86 void StateStore::Transaction::ReplacePrefDict(
87 scoped_ptr<base::DictionaryValue> pref_dict) {
88 GetPrefDict()->Swap(pref_dict.get());
92 // StateStore ------------------------------------------------------------------
94 StateStore::StateStore(Profile* profile)
95 : profile_(profile),
96 incidents_sent_(nullptr)
97 #if DCHECK_IS_ON()
99 has_transaction_(false)
100 #endif
102 // Cache a read-only view of the preference.
103 const base::Value* value =
104 profile_->GetPrefs()->GetUserPrefValue(prefs::kSafeBrowsingIncidentsSent);
105 if (value)
106 value->GetAsDictionary(&incidents_sent_);
108 // Apply the platform data.
109 Transaction transaction(this);
110 scoped_ptr<base::DictionaryValue> value_dict(
111 platform_state_store::Load(profile_));
112 if (value_dict) {
113 if (value_dict->empty())
114 transaction.ClearAll();
115 else if (!incidents_sent_ || !incidents_sent_->Equals(value_dict.get()))
116 transaction.ReplacePrefDict(value_dict.Pass());
119 if (incidents_sent_)
120 CleanLegacyValues(&transaction);
123 StateStore::~StateStore() {
124 #if DCHECK_IS_ON()
125 DCHECK(!has_transaction_);
126 #endif
129 bool StateStore::HasBeenReported(IncidentType type,
130 const std::string& key,
131 IncidentDigest digest) {
132 const base::DictionaryValue* type_dict = nullptr;
133 std::string digest_string;
134 return (incidents_sent_ &&
135 incidents_sent_->GetDictionaryWithoutPathExpansion(
136 base::IntToString(static_cast<int32_t>(type)), &type_dict) &&
137 type_dict->GetStringWithoutPathExpansion(key, &digest_string) &&
138 digest_string == base::UintToString(digest));
141 void StateStore::CleanLegacyValues(Transaction* transaction) {
142 static const IncidentType kLegacyTypes[] = {
143 // TODO(grt): remove in M44 (crbug.com/451173).
144 IncidentType::OMNIBOX_INTERACTION,
147 for (IncidentType type : kLegacyTypes)
148 transaction->ClearForType(type);
151 } // namespace safe_browsing