Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Unified Diff: net/reporting/reporting_persister.cc

Issue 2751883003: Reporting: Implement serializer. (Closed)
Patch Set: rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/reporting/reporting_persister.h ('k') | net/reporting/reporting_persister_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/reporting/reporting_persister.cc
diff --git a/net/reporting/reporting_persister.cc b/net/reporting/reporting_persister.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ec2a37b7e48c633b9b3dda03da8d936d582378a0
--- /dev/null
+++ b/net/reporting/reporting_persister.cc
@@ -0,0 +1,358 @@
+// Copyright 2017 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 "net/reporting/reporting_persister.h"
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/values.h"
+#include "net/reporting/reporting_cache.h"
+#include "net/reporting/reporting_client.h"
+#include "net/reporting/reporting_context.h"
+#include "net/reporting/reporting_delegate.h"
+#include "net/reporting/reporting_observer.h"
+#include "net/reporting/reporting_policy.h"
+#include "net/reporting/reporting_report.h"
+
+namespace net {
+namespace {
+
+std::unique_ptr<base::Value> SerializeOrigin(const url::Origin& origin) {
+ auto serialized = base::MakeUnique<base::DictionaryValue>();
+
+ serialized->SetString("scheme", origin.scheme());
+ serialized->SetString("host", origin.host());
+ serialized->SetInteger("port", origin.port());
+ serialized->SetString("suborigin", origin.suborigin());
+
+ return std::move(serialized);
+}
+
+bool DeserializeOrigin(const base::DictionaryValue& serialized,
+ url::Origin* origin_out) {
+ std::string scheme;
+ if (!serialized.GetString("scheme", &scheme))
+ return false;
+
+ std::string host;
+ if (!serialized.GetString("host", &host))
+ return false;
+
+ int port_int;
+ if (!serialized.GetInteger("port", &port_int))
+ return false;
+ uint16_t port = static_cast<uint16_t>(port_int);
+ if (port_int != port)
+ return false;
+
+ std::string suborigin;
+ if (!serialized.GetString("suborigin", &suborigin))
+ return false;
+
+ *origin_out = url::Origin::CreateFromNormalizedTupleWithSuborigin(
+ scheme, host, port, suborigin);
+ return true;
+}
+
+class ReportingPersisterImpl : public ReportingPersister,
+ public ReportingObserver {
+ public:
+ ReportingPersisterImpl(ReportingContext* context)
+ : context_(context), timer_(base::MakeUnique<base::OneShotTimer>()) {}
+
+ // ReportingPersister implementation:
+
+ ~ReportingPersisterImpl() override {
+ DCHECK(context_->initialized());
+ context_->RemoveObserver(this);
+ }
+
+ void Initialize() override {
+ std::unique_ptr<const base::Value> persisted_data =
+ context_->delegate()->GetPersistedData();
+ if (persisted_data)
+ Deserialize(*persisted_data);
+ context_->AddObserver(this);
+ }
+
+ void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override {
+ DCHECK(!context_->initialized());
+ timer_ = std::move(timer);
+ }
+
+ // ReportingObserver implementation:
+
+ void OnCacheUpdated() override {
+ DCHECK(context_->initialized());
+ if (!timer_->IsRunning())
+ StartTimer();
+ }
+
+ private:
+ void StartTimer() {
+ timer_->Start(
+ FROM_HERE, context_->policy().persistence_interval,
+ base::Bind(&ReportingPersisterImpl::Persist, base::Unretained(this)));
+ }
+
+ void Persist() { delegate()->PersistData(Serialize()); }
+
+ std::string SerializeTicks(base::TimeTicks time_ticks) {
+ base::Time time = time_ticks - tick_clock()->NowTicks() + clock()->Now();
+ return base::Int64ToString(time.ToInternalValue());
+ }
+
+ bool DeserializeTicks(const std::string& serialized,
+ base::TimeTicks* time_ticks_out) {
+ int64_t internal;
+ if (!base::StringToInt64(serialized, &internal))
+ return false;
+
+ base::Time time = base::Time::FromInternalValue(internal);
+ *time_ticks_out = time - clock()->Now() + tick_clock()->NowTicks();
+ return true;
+ }
+
+ std::unique_ptr<base::Value> SerializeReport(const ReportingReport& report) {
+ auto serialized = base::MakeUnique<base::DictionaryValue>();
+
+ serialized->SetString("url", report.url.spec());
+ serialized->SetString("group", report.group);
+ serialized->SetString("type", report.type);
+ serialized->Set("body", report.body->CreateDeepCopy());
+ serialized->SetString("queued", SerializeTicks(report.queued));
+ serialized->SetInteger("attempts", report.attempts);
+
+ return std::move(serialized);
+ }
+
+ bool DeserializeReport(const base::DictionaryValue& report) {
+ std::string url_string;
+ if (!report.GetString("url", &url_string))
+ return false;
+ GURL url(url_string);
+ if (!url.is_valid())
+ return false;
+
+ std::string group;
+ if (!report.GetString("group", &group))
+ return false;
+
+ std::string type;
+ if (!report.GetString("type", &type))
+ return false;
+
+ const base::Value* body_original;
+ if (!report.Get("body", &body_original))
+ return false;
+ std::unique_ptr<base::Value> body = body_original->CreateDeepCopy();
+
+ std::string queued_string;
+ if (!report.GetString("queued", &queued_string))
+ return false;
+ base::TimeTicks queued;
+ if (!DeserializeTicks(queued_string, &queued))
+ return false;
+
+ int attempts;
+ if (!report.GetInteger("attempts", &attempts))
+ return false;
+ if (attempts < 0)
+ return false;
+
+ cache()->AddReport(url, group, type, std::move(body), queued, attempts);
+ return true;
+ }
+
+ std::unique_ptr<base::Value> SerializeReports() {
+ std::vector<const ReportingReport*> reports;
+ cache()->GetReports(&reports);
+
+ auto serialized = base::MakeUnique<base::ListValue>();
+ for (const ReportingReport* report : reports)
+ serialized->Append(SerializeReport(*report));
+
+ return std::move(serialized);
+ }
+
+ bool DeserializeReports(const base::ListValue& reports) {
+ for (size_t i = 0; i < reports.GetSize(); ++i) {
+ const base::DictionaryValue* report;
+ if (!reports.GetDictionary(i, &report))
+ return false;
+ if (!DeserializeReport(*report))
+ return false;
+ }
+
+ return true;
+ }
+
+ std::unique_ptr<base::Value> SerializeClient(const ReportingClient& client) {
+ auto serialized = base::MakeUnique<base::DictionaryValue>();
+
+ serialized->Set("origin", SerializeOrigin(client.origin));
+ serialized->SetString("endpoint", client.endpoint.spec());
+ serialized->SetBoolean(
+ "subdomains",
+ client.subdomains == ReportingClient::Subdomains::INCLUDE);
+ serialized->SetString("group", client.group);
+ serialized->SetString("expires", SerializeTicks(client.expires));
+
+ return std::move(serialized);
+ }
+
+ bool DeserializeClient(const base::DictionaryValue& client) {
+ const base::DictionaryValue* origin_value;
+ if (!client.GetDictionary("origin", &origin_value))
+ return false;
+ url::Origin origin;
+ if (!DeserializeOrigin(*origin_value, &origin))
+ return false;
+
+ std::string endpoint_string;
+ if (!client.GetString("endpoint", &endpoint_string))
+ return false;
+ GURL endpoint(endpoint_string);
+ if (!endpoint.is_valid())
+ return false;
+
+ bool subdomains_bool;
+ if (!client.GetBoolean("subdomains", &subdomains_bool))
+ return false;
+ ReportingClient::Subdomains subdomains =
+ subdomains_bool ? ReportingClient::Subdomains::INCLUDE
+ : ReportingClient::Subdomains::EXCLUDE;
+
+ std::string group;
+ if (!client.GetString("group", &group))
+ return false;
+
+ std::string expires_string;
+ if (!client.GetString("expires", &expires_string))
+ return false;
+ base::TimeTicks expires;
+ if (!DeserializeTicks(expires_string, &expires))
+ return false;
+
+ cache()->SetClient(origin, endpoint, subdomains, group, expires);
+ return true;
+ }
+
+ std::unique_ptr<base::Value> SerializeClients() {
+ std::vector<const ReportingClient*> clients;
+ cache()->GetClients(&clients);
+
+ auto serialized = base::MakeUnique<base::ListValue>();
+ for (const ReportingClient* client : clients)
+ serialized->Append(SerializeClient(*client));
+
+ return std::move(serialized);
+ }
+
+ bool DeserializeClients(const base::ListValue& clients) {
+ for (size_t i = 0; i < clients.GetSize(); ++i) {
+ const base::DictionaryValue* client;
+ if (!clients.GetDictionary(i, &client))
+ return false;
+ if (!DeserializeClient(*client))
+ return false;
+ }
+
+ return true;
+ }
+
+ static const int kSupportedVersion = 1;
+
+ std::unique_ptr<base::Value> Serialize() {
+ auto serialized = base::MakeUnique<base::DictionaryValue>();
+
+ serialized->SetInteger("reporting_serialized_cache_version",
+ kSupportedVersion);
+
+ bool persist_reports = policy().persist_reports_across_restarts;
+ serialized->SetBoolean("includes_reports", persist_reports);
+ if (persist_reports)
+ serialized->Set("reports", SerializeReports());
+
+ bool persist_clients = policy().persist_clients_across_restarts;
+ serialized->SetBoolean("includes_clients", persist_clients);
+ if (persist_clients)
+ serialized->Set("clients", SerializeClients());
+
+ return std::move(serialized);
+ }
+
+ bool Deserialize(const base::Value& serialized_value) {
+ std::vector<const ReportingReport*> reports;
+ cache()->GetReports(&reports);
+ DCHECK(reports.empty());
+
+ std::vector<const ReportingClient*> clients;
+ cache()->GetClients(&clients);
+ DCHECK(clients.empty());
+
+ int version;
+
+ const base::DictionaryValue* serialized;
+ if (!serialized_value.GetAsDictionary(&serialized))
+ return false;
+
+ if (!serialized->GetInteger("reporting_serialized_cache_version", &version))
+ return false;
+ if (version != kSupportedVersion)
+ return false;
+
+ bool includes_reports;
+ bool includes_clients;
+ if (!serialized->GetBoolean("includes_reports", &includes_reports) ||
+ !serialized->GetBoolean("includes_clients", &includes_clients)) {
+ return false;
+ }
+
+ if (includes_reports) {
+ const base::ListValue* reports;
+ if (!serialized->GetList("reports", &reports))
+ return false;
+ if (!DeserializeReports(*reports))
+ return false;
+ }
+
+ if (includes_clients) {
+ const base::ListValue* clients;
+ if (!serialized->GetList("clients", &clients))
+ return false;
+ if (!DeserializeClients(*clients))
+ return false;
+ }
+
+ return true;
+ }
+
+ const ReportingPolicy& policy() { return context_->policy(); }
+ ReportingDelegate* delegate() { return context_->delegate(); }
+ base::Clock* clock() { return context_->clock(); }
+ base::TickClock* tick_clock() { return context_->tick_clock(); }
+ ReportingCache* cache() { return context_->cache(); }
+
+ ReportingContext* context_;
+ std::unique_ptr<base::Timer> timer_;
+};
+
+} // namespace
+
+// static
+std::unique_ptr<ReportingPersister> ReportingPersister::Create(
+ ReportingContext* context) {
+ return base::MakeUnique<ReportingPersisterImpl>(context);
+}
+
+ReportingPersister::~ReportingPersister() {}
+
+} // namespace net
« no previous file with comments | « net/reporting/reporting_persister.h ('k') | net/reporting/reporting_persister_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698