Chromium Code Reviews| 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..9025ae372fd4d85dd57d98d5df03099c8d396799 |
| --- /dev/null |
| +++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc |
| @@ -0,0 +1,178 @@ |
| +// 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. |
| + |
| +#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 |
|
Cait (Slow)
2015/08/18 18:19:45
It might be helpful to explain at the beginning of
|
| +// values) to the |incidents| protobuf. |
| +void KeysAndDigestsToProtobuf( |
| + const base::DictionaryValue& keys_and_digests, |
| + RepeatedPtrField<StateStoreData::Incident>* incidents) { |
| + 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::Incident* incident = incidents->Add(); |
| + incident->set_key(iter.key()); |
| + incident->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::TypedIncidents>* typed_incidents) { |
| + 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::TypedIncidents* incidents = typed_incidents->Add(); |
| + incidents->set_type(incident_type); |
| + KeysAndDigestsToProtobuf(*keys_and_digests, incidents->mutable_incident()); |
| + } |
| +} |
| + |
| +// Copies the (key, digest) pairs for a specific incident type into |type_dict| |
| +// (a dict of string values). |
| +void RestoreOfTypeFromProtobuf( |
| + const RepeatedPtrField<StateStoreData::Incident>& incidents, |
| + base::DictionaryValue* type_dict) { |
| + for (const auto& incident : incidents) { |
| + if (!incident.has_key() || !incident.has_digest()) |
| + continue; |
| + type_dict->SetStringWithoutPathExpansion( |
| + incident.key(), base::UintToString(incident.digest())); |
| + } |
| +} |
| + |
| +// Copies the (type, dict) pairs into |value_dict| (a dict of dict values). |
| +void RestoreFromProtobuf( |
| + const RepeatedPtrField<StateStoreData::TypedIncidents>& typed_incidents, |
| + base::DictionaryValue* value_dict) { |
| + for (const auto& incidents : typed_incidents) { |
| + if (!incidents.has_type() || incidents.incident_size() == 0) |
| + continue; |
| + std::string type_string(base::IntToString(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(incidents.incident(), 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_typed_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.typed_incidents(), value_dict); |
| + return PlatformStateStoreLoadResult::SUCCESS; |
| +} |
| + |
| +#endif // USE_PLATFORM_STATE_STORE |
| + |
| +} // namespace platform_state_store |
| +} // namespace safe_browsing |