| 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
|
|
|