This repository has been archived by the owner on Apr 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Platform-specific prune state storage.
BUG=496744 [email protected] Review URL: https://codereview.chromium.org/1243293003 Cr-Commit-Position: refs/heads/master@{#347571}
- Loading branch information
Showing
15 changed files
with
835 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# 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. | ||
|
||
import("//third_party/protobuf/proto_library.gni") | ||
|
||
# GYP version: chrome/chrome_browser.gypi:incident_reporting_state_store_data_proto | ||
proto_library("state_store_data_proto") { | ||
sources = [ | ||
"state_store_data.proto", | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
85 changes: 85 additions & 0 deletions
85
chrome/browser/safe_browsing/incident_reporting/platform_state_store.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// 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. | ||
|
||
// An interface to platform-specific storage of IncidentReportingService prune | ||
// state. | ||
|
||
#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_ | ||
#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_ | ||
|
||
#include <stdint.h> | ||
#include <string> | ||
|
||
#include "base/memory/scoped_ptr.h" | ||
#include "build/build_config.h" | ||
|
||
// Certain platforms provide their own storage of protobuf-serialized prune | ||
// state. On platforms where it is not supported, Load() and Store() are noops. | ||
#if defined(OS_WIN) | ||
// Store the state in the registry on Windows. | ||
#define USE_PLATFORM_STATE_STORE | ||
#endif | ||
|
||
class Profile; | ||
|
||
namespace base { | ||
class DictionaryValue; | ||
} | ||
|
||
namespace safe_browsing { | ||
namespace platform_state_store { | ||
|
||
// Loads the platform-specific storage for |profile|. Returns null if there is | ||
// no such storage for the current platform or in case of error; otherwise, a | ||
// (possibly empty) dictionary. | ||
scoped_ptr<base::DictionaryValue> Load(Profile* profile); | ||
|
||
// Stores the state for |profile| in |incidents_sent| into platform-specific | ||
// storage if there is such for the current platform. | ||
void Store(Profile* profile, const base::DictionaryValue* incidents_sent); | ||
|
||
#if defined(USE_PLATFORM_STATE_STORE) | ||
|
||
// All declarations and definitions from this point forward are for use by | ||
// implementations in platform-specific source files, or are exposed for the | ||
// sake of testing. | ||
|
||
// The result of loading platform-specific state. This is a histogram type; do | ||
// not reorder. | ||
enum class PlatformStateStoreLoadResult : int32_t { | ||
SUCCESS = 0, | ||
CLEARED_DATA = 1, | ||
CLEARED_NO_DATA = 2, | ||
DATA_CLEAR_FAILED = 3, | ||
OPEN_FAILED = 4, | ||
READ_FAILED = 5, | ||
PARSE_ERROR = 6, | ||
NUM_RESULTS | ||
}; | ||
|
||
// A platform-specific function to read store data for |profile| into |data|. | ||
// Returns SUCCESS if |data| was populated, or a load result value indicating | ||
// why no data was read. | ||
PlatformStateStoreLoadResult ReadStoreData(Profile* profile, std::string* data); | ||
|
||
// A platform-specific function to write store data for |profile| from |data|. | ||
void WriteStoreData(Profile* profile, const std::string& data); | ||
|
||
// Serializes the |incidents_sent| preference into |data|, replacing its | ||
// contents. Exposed for testing. | ||
void SerializeIncidentsSent(const base::DictionaryValue* incidents_sent, | ||
std::string* data); | ||
|
||
// Deserializes |data| into |value_dict|. Returns SUCCESS if |data| is empty or | ||
// fully processed. Exposed for testing. | ||
PlatformStateStoreLoadResult DeserializeIncidentsSent( | ||
const std::string& data, | ||
base::DictionaryValue* value_dict); | ||
|
||
#endif // USE_PLATFORM_STATE_STORE | ||
|
||
} // namespace platform_state_store | ||
} // namespace safe_browsing | ||
|
||
#endif // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PLATFORM_STATE_STORE_H_ |
Oops, something went wrong.