Index: net/reporting/reporting_serializer.cc |
diff --git a/net/reporting/reporting_serializer.cc b/net/reporting/reporting_serializer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..157cd97fc920a8c9edfc36b9e659be9cde8d222f |
--- /dev/null |
+++ b/net/reporting/reporting_serializer.cc |
@@ -0,0 +1,298 @@ |
+// 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_serializer.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/values.h" |
+#include "net/reporting/reporting_cache.h" |
+#include "net/reporting/reporting_client.h" |
+#include "net/reporting/reporting_context.h" |
+#include "net/reporting/reporting_policy.h" |
+#include "net/reporting/reporting_report.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+std::string SerializeTicks(base::TimeTicks time_ticks, |
+ ReportingContext* context) { |
+ base::Time time = |
+ time_ticks - context->tick_clock()->NowTicks() + context->clock()->Now(); |
+ return base::Int64ToString(time.ToInternalValue()); |
+} |
+ |
+bool DeserializeTicks(const std::string& serialized, |
+ base::TimeTicks* time_ticks_out, |
+ ReportingContext* context) { |
+ int64_t internal; |
+ if (!base::StringToInt64(serialized, &internal)) |
+ return false; |
+ |
+ base::Time time = base::Time::FromInternalValue(internal); |
+ *time_ticks_out = |
+ time - context->clock()->Now() + context->tick_clock()->NowTicks(); |
+ return true; |
+} |
+ |
+std::unique_ptr<base::Value> SerializeReport(const ReportingReport& report, |
+ ReportingContext* context) { |
+ 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, context)); |
+ serialized->SetInteger("attempts", report.attempts); |
+ |
+ return std::move(serialized); |
+} |
+ |
+bool DeserializeReport(const base::DictionaryValue& report, |
+ ReportingContext* context) { |
+ 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; |
shivanisha
2017/04/05 18:47:31
dcheck group is not empty. Also type and body belo
Julia Tuttle
2017/04/06 20:20:55
There's nothing actually disallowing those members
|
+ |
+ std::string type; |
+ if (!report.GetString("type", &type)) |
+ return false; |
+ |
+ const base::Value* body; |
+ if (!report.Get("body", &body)) |
+ return false; |
+ |
+ std::string queued_string; |
+ if (!report.GetString("queued", &queued_string)) |
+ return false; |
+ base::TimeTicks queued; |
+ if (!DeserializeTicks(queued_string, &queued, context)) |
+ return false; |
+ |
+ int attempts; |
+ if (!report.GetInteger("attempts", &attempts)) |
+ return false; |
+ if (attempts < 0) |
+ return false; |
+ |
+ context->cache()->AddReport(url, group, type, body->CreateDeepCopy(), queued, |
+ attempts); |
shivanisha
2017/04/05 18:47:31
I believe the invocation of this call will only be
Julia Tuttle
2017/04/06 20:20:55
Yeah, I'll check in DeserializeFromValue that ther
|
+ return true; |
+} |
+ |
+std::unique_ptr<base::Value> SerializeReports(ReportingContext* context) { |
+ std::vector<const ReportingReport*> reports; |
+ context->cache()->GetReports(&reports); |
+ |
+ auto serialized = base::MakeUnique<base::ListValue>(); |
+ for (const ReportingReport* report : reports) |
+ serialized->Append(SerializeReport(*report, context)); |
+ |
+ return std::move(serialized); |
+} |
+ |
+bool DeserializeReports(const base::ListValue& reports, |
+ ReportingContext* context) { |
+ for (size_t i = 0; i < reports.GetSize(); ++i) { |
+ const base::DictionaryValue* report; |
+ if (!reports.GetDictionary(i, &report)) |
+ return false; |
+ if (!DeserializeReport(*report, context)) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+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; |
+} |
+ |
+std::unique_ptr<base::Value> SerializeClient(const ReportingClient& client, |
+ ReportingContext* context) { |
+ 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, context)); |
+ |
+ return std::move(serialized); |
+} |
+ |
+bool DeserializeClient(const base::DictionaryValue& client, |
+ ReportingContext* context) { |
+ 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, context)) |
+ return false; |
+ |
+ context->cache()->SetClient(origin, endpoint, subdomains, group, expires); |
+ return true; |
+} |
+ |
+std::unique_ptr<base::Value> SerializeClients(ReportingContext* context) { |
+ std::vector<const ReportingClient*> clients; |
+ context->cache()->GetClients(&clients); |
+ |
+ auto serialized = base::MakeUnique<base::ListValue>(); |
+ for (const ReportingClient* client : clients) |
+ serialized->Append(SerializeClient(*client, context)); |
+ |
+ return std::move(serialized); |
+} |
+ |
+bool DeserializeClients(const base::ListValue& clients, |
+ ReportingContext* context) { |
+ for (size_t i = 0; i < clients.GetSize(); ++i) { |
+ const base::DictionaryValue* client; |
+ if (!clients.GetDictionary(i, &client)) |
+ return false; |
+ if (!DeserializeClient(*client, context)) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+// static |
+std::unique_ptr<base::Value> ReportingSerializer::SerializeToValue( |
+ ReportingContext* context) { |
+ auto serialized = base::MakeUnique<base::DictionaryValue>(); |
+ |
+ serialized->SetInteger("reporting_serialized_cache_version", 1); |
shivanisha
2017/04/05 18:47:31
May be have a static const as the version instead
Julia Tuttle
2017/04/06 20:20:55
Done.
|
+ |
+ bool persist_reports = context->policy().persist_reports_across_restarts; |
+ serialized->SetBoolean("includes_reports", persist_reports); |
+ if (persist_reports) |
+ serialized->Set("reports", SerializeReports(context)); |
+ |
+ bool persist_clients = context->policy().persist_clients_across_restarts; |
+ serialized->SetBoolean("includes_clients", persist_clients); |
+ if (persist_clients) |
+ serialized->Set("clients", SerializeClients(context)); |
+ |
+ return std::move(serialized); |
+} |
+ |
+// static |
+bool ReportingSerializer::DeserializeFromValue( |
+ const base::Value& serialized_value, |
+ ReportingContext* context) { |
+ 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 != 1) |
+ return false; |
+ |
+ bool includes_reports; |
+ bool includes_clients; |
+ if (!serialized->GetBoolean("includes_reports", &includes_reports) || |
+ !serialized->GetBoolean("includes_clients", &includes_clients)) { |
+ return false; |
+ } |
+ |
shivanisha
2017/04/05 18:47:31
DCHECK that the cache does not contain any reports
Julia Tuttle
2017/04/06 20:20:55
Done.
|
+ if (includes_reports) { |
+ const base::ListValue* reports; |
+ if (!serialized->GetList("reports", &reports)) |
+ return false; |
+ if (!DeserializeReports(*reports, context)) |
+ return false; |
+ } |
+ |
+ if (includes_clients) { |
+ const base::ListValue* clients; |
+ if (!serialized->GetList("clients", &clients)) |
+ return false; |
+ if (!DeserializeClients(*clients, context)) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace net |