Index: chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc |
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c657c6587918a955a5a2fda6a55777df1d73bc4 |
--- /dev/null |
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc |
@@ -0,0 +1,200 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// This file implements the platform-neutral Load() and Store() functions for a |
+// profile's safebrowsing.incidents_sent preference dictionary. The preference |
+// dict is converted to a protocol buffer message which is then serialized into |
+// a byte array. This serialized data is written to or read from some |
+// platform-specific storage via {Read,Write}StoreData implemented elsewhere. |
+// |
+// A pref dict like so: |
+// { "0": {"key1": "1235"}, {"key2": "6789"}}} |
+// is converted to an identical protocol buffer message, where the top-level |
+// mapping's keys are of type int, and the nested mappings' values are of type |
+// uint32_t. |
+ |
+#include "chrome/browser/safe_browsing/incident_reporting/platform_state_store.h" |
+ |
+#include "base/values.h" |
+ |
+#if defined(USE_PLATFORM_STATE_STORE) |
+ |
+#include "base/metrics/histogram_macros.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "chrome/browser/safe_browsing/incident_reporting/state_store_data.pb.h" |
+#include "third_party/protobuf/src/google/protobuf/repeated_field.h" |
+ |
+#endif // USE_PLATFORM_STATE_STORE |
+ |
+namespace safe_browsing { |
+namespace platform_state_store { |
+ |
+#if defined(USE_PLATFORM_STATE_STORE) |
+ |
+namespace { |
+ |
+using google::protobuf::RepeatedPtrField; |
+ |
+// Copies the (key, digest) pairs from |keys_and_digests| (a dict of string |
+// values) to the |key_digest_pairs| protobuf. |
+void KeysAndDigestsToProtobuf( |
+ const base::DictionaryValue& keys_and_digests, |
+ RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>* |
+ key_digest_pairs) { |
+ for (base::DictionaryValue::Iterator iter(keys_and_digests); !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ const base::StringValue* digest_value = nullptr; |
+ if (!iter.value().GetAsString(&digest_value)) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ uint32_t digest = 0; |
+ if (!base::StringToUint(digest_value->GetString(), &digest)) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ StateStoreData::Incidents::KeyDigestMapFieldEntry* key_digest = |
+ key_digest_pairs->Add(); |
+ key_digest->set_key(iter.key()); |
+ key_digest->set_digest(digest); |
+ } |
+} |
+ |
+// Copies the (type, dict) pairs from |incidents_sent| (a dict of dict values) |
+// to the |typed_incidents| protobuf. |
+void IncidentsSentToProtobuf( |
+ const base::DictionaryValue& incidents_sent, |
+ RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>* |
+ type_incidents_pairs) { |
+ for (base::DictionaryValue::Iterator iter(incidents_sent); !iter.IsAtEnd(); |
+ iter.Advance()) { |
+ const base::DictionaryValue* keys_and_digests = nullptr; |
+ if (!iter.value().GetAsDictionary(&keys_and_digests)) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ if (keys_and_digests->empty()) |
+ continue; |
+ int incident_type = 0; |
+ if (!base::StringToInt(iter.key(), &incident_type)) { |
+ NOTREACHED(); |
+ continue; |
+ } |
+ StateStoreData::TypeIncidentsMapFieldEntry* entry = |
+ type_incidents_pairs->Add(); |
+ entry->set_type(incident_type); |
+ KeysAndDigestsToProtobuf( |
+ *keys_and_digests, entry->mutable_incidents()->mutable_key_to_digest()); |
+ } |
+} |
+ |
+// Copies the (key, digest) pairs for a specific incident type into |type_dict| |
+// (a dict of string values). |
+void RestoreOfTypeFromProtobuf( |
+ const RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>& |
+ key_digest_pairs, |
+ base::DictionaryValue* type_dict) { |
+ for (const auto& key_digest : key_digest_pairs) { |
+ if (!key_digest.has_key() || !key_digest.has_digest()) |
+ continue; |
+ type_dict->SetStringWithoutPathExpansion( |
+ key_digest.key(), base::UintToString(key_digest.digest())); |
+ } |
+} |
+ |
+// Copies the (type, dict) pairs into |value_dict| (a dict of dict values). |
+void RestoreFromProtobuf( |
+ const RepeatedPtrField<StateStoreData::TypeIncidentsMapFieldEntry>& |
+ type_incidents_pairs, |
+ base::DictionaryValue* value_dict) { |
+ for (const auto& type_incidents : type_incidents_pairs) { |
+ if (!type_incidents.has_type() || !type_incidents.has_incidents() || |
+ type_incidents.incidents().key_to_digest_size() == 0) { |
+ continue; |
+ } |
+ std::string type_string(base::IntToString(type_incidents.type())); |
+ base::DictionaryValue* type_dict = nullptr; |
+ if (!value_dict->GetDictionaryWithoutPathExpansion(type_string, |
+ &type_dict)) { |
+ type_dict = new base::DictionaryValue(); |
+ value_dict->SetWithoutPathExpansion(type_string, type_dict); |
+ } |
+ RestoreOfTypeFromProtobuf(type_incidents.incidents().key_to_digest(), |
+ type_dict); |
+ } |
+} |
+ |
+} // namespace |
+ |
+#endif // USE_PLATFORM_STATE_STORE |
+ |
+scoped_ptr<base::DictionaryValue> Load(Profile* profile) { |
+#if defined(USE_PLATFORM_STATE_STORE) |
+ scoped_ptr<base::DictionaryValue> value_dict(new base::DictionaryValue()); |
+ std::string data; |
+ PlatformStateStoreLoadResult result = ReadStoreData(profile, &data); |
+ if (result == PlatformStateStoreLoadResult::SUCCESS) |
+ result = DeserializeIncidentsSent(data, value_dict.get()); |
+ switch (result) { |
+ case PlatformStateStoreLoadResult::SUCCESS: |
+ case PlatformStateStoreLoadResult::CLEARED_DATA: |
+ case PlatformStateStoreLoadResult::CLEARED_NO_DATA: |
+ // Return a (possibly empty) dictionary for the success cases. |
+ break; |
+ case PlatformStateStoreLoadResult::DATA_CLEAR_FAILED: |
+ case PlatformStateStoreLoadResult::OPEN_FAILED: |
+ case PlatformStateStoreLoadResult::READ_FAILED: |
+ case PlatformStateStoreLoadResult::PARSE_ERROR: |
+ // Return null for all error cases. |
+ value_dict.reset(); |
+ break; |
+ } |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "SBIRS.PSSLoadResult", static_cast<uint32_t>(result), |
+ static_cast<uint32_t>(PlatformStateStoreLoadResult::NUM_RESULTS)); |
+ return value_dict.Pass(); |
+#else |
+ return scoped_ptr<base::DictionaryValue>(); |
+#endif |
+} |
+ |
+void Store(Profile* profile, const base::DictionaryValue* incidents_sent) { |
+#if defined(USE_PLATFORM_STATE_STORE) |
+ std::string data; |
+ SerializeIncidentsSent(incidents_sent, &data); |
+ UMA_HISTOGRAM_COUNTS("SBIRS.PSSDataStoreSize", data.size()); |
+ WriteStoreData(profile, data); |
+#endif |
+} |
+ |
+#if defined(USE_PLATFORM_STATE_STORE) |
+ |
+void SerializeIncidentsSent(const base::DictionaryValue* incidents_sent, |
+ std::string* data) { |
+ StateStoreData store_data; |
+ |
+ IncidentsSentToProtobuf(*incidents_sent, |
+ store_data.mutable_type_to_incidents()); |
+ store_data.SerializeToString(data); |
+} |
+ |
+PlatformStateStoreLoadResult DeserializeIncidentsSent( |
+ const std::string& data, |
+ base::DictionaryValue* value_dict) { |
+ StateStoreData store_data; |
+ if (data.empty()) { |
+ value_dict->Clear(); |
+ return PlatformStateStoreLoadResult::SUCCESS; |
+ } |
+ if (!store_data.ParseFromString(data)) |
+ return PlatformStateStoreLoadResult::PARSE_ERROR; |
+ value_dict->Clear(); |
+ RestoreFromProtobuf(store_data.type_to_incidents(), value_dict); |
+ return PlatformStateStoreLoadResult::SUCCESS; |
+} |
+ |
+#endif // USE_PLATFORM_STATE_STORE |
+ |
+} // namespace platform_state_store |
+} // namespace safe_browsing |