Chromium Code Reviews| 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 |