Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / chrome / browser / safe_browsing / incident_reporting / state_store.cc
blob8d44d30aaa9253b8df65147feeff36274b603144
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/metrics/histogram_macros.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/values.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
13 #include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h"
14 #include "chrome/common/pref_names.h"
16 namespace safe_browsing {
18 // StateStore::Transaction -----------------------------------------------------
20 StateStore::Transaction::Transaction(StateStore* store) : store_(store) {
21 #if DCHECK_IS_ON()
22 DCHECK(!store_->has_transaction_);
23 store_->has_transaction_ = true;
24 #endif
27 StateStore::Transaction::~Transaction() {
28 #if DCHECK_IS_ON()
29 store_->has_transaction_ = false;
30 #endif
31 if (pref_update_)
32 platform_state_store::Store(store_->profile_, store_->incidents_sent_);
35 void StateStore::Transaction::MarkAsReported(IncidentType type,
36 const std::string& key,
37 IncidentDigest digest) {
38 std::string type_string(base::IntToString(static_cast<int32_t>(type)));
39 base::DictionaryValue* incidents_sent = GetPrefDict();
40 base::DictionaryValue* type_dict = nullptr;
41 if (!incidents_sent->GetDictionaryWithoutPathExpansion(type_string,
42 &type_dict)) {
43 type_dict = new base::DictionaryValue();
44 incidents_sent->SetWithoutPathExpansion(type_string, type_dict);
46 type_dict->SetStringWithoutPathExpansion(key, base::UintToString(digest));
49 void StateStore::Transaction::ClearForType(IncidentType type) {
50 // Nothing to do if the pref dict does not exist.
51 if (!store_->incidents_sent_)
52 return;
54 // Use the read-only view on the preference to figure out if there is a value
55 // to remove before committing to making a change since any use of GetPrefDict
56 // will result in a full serialize-and-write operation on the preferences
57 // store.
58 std::string type_string(base::IntToString(static_cast<int32_t>(type)));
59 const base::DictionaryValue* type_dict = nullptr;
60 if (store_->incidents_sent_->GetDictionaryWithoutPathExpansion(type_string,
61 &type_dict)) {
62 GetPrefDict()->RemoveWithoutPathExpansion(type_string, nullptr);
66 void StateStore::Transaction::ClearAll() {
67 // Clear the preference if it exists and contains any values.
68 if (store_->incidents_sent_ && !store_->incidents_sent_->empty())
69 GetPrefDict()->Clear();
72 base::DictionaryValue* StateStore::Transaction::GetPrefDict() {
73 if (!pref_update_) {
74 pref_update_.reset(new DictionaryPrefUpdate(
75 store_->profile_->GetPrefs(), prefs::kSafeBrowsingIncidentsSent));
76 // Getting the dict will cause it to be created if it doesn't exist.
77 // Unconditionally refresh the store's read-only view on the preference so
78 // that it will always be correct.
79 store_->incidents_sent_ = pref_update_->Get();
81 return pref_update_->Get();
84 void StateStore::Transaction::ReplacePrefDict(
85 scoped_ptr<base::DictionaryValue> pref_dict) {
86 GetPrefDict()->Swap(pref_dict.get());
90 // StateStore ------------------------------------------------------------------
92 StateStore::StateStore(Profile* profile)
93 : profile_(profile),
94 incidents_sent_(nullptr)
95 #if DCHECK_IS_ON()
97 has_transaction_(false)
98 #endif
100 // Cache a read-only view of the preference.
101 const base::Value* value =
102 profile_->GetPrefs()->GetUserPrefValue(prefs::kSafeBrowsingIncidentsSent);
103 if (value)
104 value->GetAsDictionary(&incidents_sent_);
106 // Apply the platform data.
107 Transaction transaction(this);
108 scoped_ptr<base::DictionaryValue> value_dict(
109 platform_state_store::Load(profile_));
111 InitializationResult state_store_init_result = PSS_MATCHES;
112 if (!value_dict) {
113 state_store_init_result = PSS_NULL;
114 } else if (value_dict->empty()) {
115 if (incidents_sent_ && !incidents_sent_->empty())
116 state_store_init_result = PSS_EMPTY;
117 transaction.ClearAll();
118 } else if (!incidents_sent_ || !incidents_sent_->Equals(value_dict.get())) {
119 state_store_init_result = PSS_DIFFERS;
120 transaction.ReplacePrefDict(value_dict.Pass());
122 UMA_HISTOGRAM_ENUMERATION("SBIRS.StateStoreInit", state_store_init_result,
123 NUM_INITIALIZATION_RESULTS);
124 if (incidents_sent_)
125 CleanLegacyValues(&transaction);
128 StateStore::~StateStore() {
129 #if DCHECK_IS_ON()
130 DCHECK(!has_transaction_);
131 #endif
134 bool StateStore::HasBeenReported(IncidentType type,
135 const std::string& key,
136 IncidentDigest digest) {
137 const base::DictionaryValue* type_dict = nullptr;
138 std::string digest_string;
139 return (incidents_sent_ &&
140 incidents_sent_->GetDictionaryWithoutPathExpansion(
141 base::IntToString(static_cast<int32_t>(type)), &type_dict) &&
142 type_dict->GetStringWithoutPathExpansion(key, &digest_string) &&
143 digest_string == base::UintToString(digest));
146 void StateStore::CleanLegacyValues(Transaction* transaction) {
147 static const IncidentType kLegacyTypes[] = {
148 // TODO(grt): remove in M44 (crbug.com/451173).
149 IncidentType::OMNIBOX_INTERACTION,
152 for (IncidentType type : kLegacyTypes)
153 transaction->ClearForType(type);
156 } // namespace safe_browsing