Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/reporting/reporting_serializer.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/memory/ptr_util.h" | |
| 10 #include "base/strings/string_number_conversions.h" | |
| 11 #include "base/time/clock.h" | |
| 12 #include "base/time/tick_clock.h" | |
| 13 #include "base/time/time.h" | |
| 14 #include "base/values.h" | |
| 15 #include "net/reporting/reporting_cache.h" | |
| 16 #include "net/reporting/reporting_client.h" | |
| 17 #include "net/reporting/reporting_context.h" | |
| 18 #include "net/reporting/reporting_policy.h" | |
| 19 #include "net/reporting/reporting_report.h" | |
| 20 | |
| 21 namespace net { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 std::string SerializeTicks(base::TimeTicks time_ticks, | |
| 26 ReportingContext* context) { | |
| 27 base::Time time = | |
| 28 time_ticks - context->tick_clock()->NowTicks() + context->clock()->Now(); | |
| 29 return base::Int64ToString(time.ToInternalValue()); | |
| 30 } | |
| 31 | |
| 32 bool DeserializeTicks(const std::string& serialized, | |
| 33 base::TimeTicks* time_ticks_out, | |
| 34 ReportingContext* context) { | |
| 35 int64_t internal; | |
| 36 if (!base::StringToInt64(serialized, &internal)) | |
| 37 return false; | |
| 38 | |
| 39 base::Time time = base::Time::FromInternalValue(internal); | |
| 40 *time_ticks_out = | |
| 41 time - context->clock()->Now() + context->tick_clock()->NowTicks(); | |
| 42 return true; | |
| 43 } | |
| 44 | |
| 45 std::unique_ptr<base::Value> SerializeReport(const ReportingReport& report, | |
| 46 ReportingContext* context) { | |
| 47 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 48 | |
| 49 serialized->SetString("url", report.url.spec()); | |
| 50 serialized->SetString("group", report.group); | |
| 51 serialized->SetString("type", report.type); | |
| 52 serialized->Set("body", report.body->CreateDeepCopy()); | |
| 53 serialized->SetString("queued", SerializeTicks(report.queued, context)); | |
| 54 serialized->SetInteger("attempts", report.attempts); | |
| 55 | |
| 56 return std::move(serialized); | |
| 57 } | |
| 58 | |
| 59 bool DeserializeReport(const base::DictionaryValue& report, | |
| 60 ReportingContext* context) { | |
| 61 std::string url_string; | |
| 62 if (!report.GetString("url", &url_string)) | |
| 63 return false; | |
| 64 GURL url(url_string); | |
| 65 if (!url.is_valid()) | |
| 66 return false; | |
| 67 | |
| 68 std::string group; | |
| 69 if (!report.GetString("group", &group)) | |
| 70 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
| |
| 71 | |
| 72 std::string type; | |
| 73 if (!report.GetString("type", &type)) | |
| 74 return false; | |
| 75 | |
| 76 const base::Value* body; | |
| 77 if (!report.Get("body", &body)) | |
| 78 return false; | |
| 79 | |
| 80 std::string queued_string; | |
| 81 if (!report.GetString("queued", &queued_string)) | |
| 82 return false; | |
| 83 base::TimeTicks queued; | |
| 84 if (!DeserializeTicks(queued_string, &queued, context)) | |
| 85 return false; | |
| 86 | |
| 87 int attempts; | |
| 88 if (!report.GetInteger("attempts", &attempts)) | |
| 89 return false; | |
| 90 if (attempts < 0) | |
| 91 return false; | |
| 92 | |
| 93 context->cache()->AddReport(url, group, type, body->CreateDeepCopy(), queued, | |
| 94 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
| |
| 95 return true; | |
| 96 } | |
| 97 | |
| 98 std::unique_ptr<base::Value> SerializeReports(ReportingContext* context) { | |
| 99 std::vector<const ReportingReport*> reports; | |
| 100 context->cache()->GetReports(&reports); | |
| 101 | |
| 102 auto serialized = base::MakeUnique<base::ListValue>(); | |
| 103 for (const ReportingReport* report : reports) | |
| 104 serialized->Append(SerializeReport(*report, context)); | |
| 105 | |
| 106 return std::move(serialized); | |
| 107 } | |
| 108 | |
| 109 bool DeserializeReports(const base::ListValue& reports, | |
| 110 ReportingContext* context) { | |
| 111 for (size_t i = 0; i < reports.GetSize(); ++i) { | |
| 112 const base::DictionaryValue* report; | |
| 113 if (!reports.GetDictionary(i, &report)) | |
| 114 return false; | |
| 115 if (!DeserializeReport(*report, context)) | |
| 116 return false; | |
| 117 } | |
| 118 | |
| 119 return true; | |
| 120 } | |
| 121 | |
| 122 std::unique_ptr<base::Value> SerializeOrigin(const url::Origin& origin) { | |
| 123 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 124 | |
| 125 serialized->SetString("scheme", origin.scheme()); | |
| 126 serialized->SetString("host", origin.host()); | |
| 127 serialized->SetInteger("port", origin.port()); | |
| 128 serialized->SetString("suborigin", origin.suborigin()); | |
| 129 | |
| 130 return std::move(serialized); | |
| 131 } | |
| 132 | |
| 133 bool DeserializeOrigin(const base::DictionaryValue& serialized, | |
| 134 url::Origin* origin_out) { | |
| 135 std::string scheme; | |
| 136 if (!serialized.GetString("scheme", &scheme)) | |
| 137 return false; | |
| 138 | |
| 139 std::string host; | |
| 140 if (!serialized.GetString("host", &host)) | |
| 141 return false; | |
| 142 | |
| 143 int port_int; | |
| 144 if (!serialized.GetInteger("port", &port_int)) | |
| 145 return false; | |
| 146 uint16_t port = static_cast<uint16_t>(port_int); | |
| 147 if (port_int != port) | |
| 148 return false; | |
| 149 | |
| 150 std::string suborigin; | |
| 151 if (!serialized.GetString("suborigin", &suborigin)) | |
| 152 return false; | |
| 153 | |
| 154 *origin_out = url::Origin::CreateFromNormalizedTupleWithSuborigin( | |
| 155 scheme, host, port, suborigin); | |
| 156 return true; | |
| 157 } | |
| 158 | |
| 159 std::unique_ptr<base::Value> SerializeClient(const ReportingClient& client, | |
| 160 ReportingContext* context) { | |
| 161 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 162 | |
| 163 serialized->Set("origin", SerializeOrigin(client.origin)); | |
| 164 serialized->SetString("endpoint", client.endpoint.spec()); | |
| 165 serialized->SetBoolean( | |
| 166 "subdomains", client.subdomains == ReportingClient::Subdomains::INCLUDE); | |
| 167 serialized->SetString("group", client.group); | |
| 168 serialized->SetString("expires", SerializeTicks(client.expires, context)); | |
| 169 | |
| 170 return std::move(serialized); | |
| 171 } | |
| 172 | |
| 173 bool DeserializeClient(const base::DictionaryValue& client, | |
| 174 ReportingContext* context) { | |
| 175 const base::DictionaryValue* origin_value; | |
| 176 if (!client.GetDictionary("origin", &origin_value)) | |
| 177 return false; | |
| 178 url::Origin origin; | |
| 179 if (!DeserializeOrigin(*origin_value, &origin)) | |
| 180 return false; | |
| 181 | |
| 182 std::string endpoint_string; | |
| 183 if (!client.GetString("endpoint", &endpoint_string)) | |
| 184 return false; | |
| 185 GURL endpoint(endpoint_string); | |
| 186 if (!endpoint.is_valid()) | |
| 187 return false; | |
| 188 | |
| 189 bool subdomains_bool; | |
| 190 if (!client.GetBoolean("subdomains", &subdomains_bool)) | |
| 191 return false; | |
| 192 ReportingClient::Subdomains subdomains = | |
| 193 subdomains_bool ? ReportingClient::Subdomains::INCLUDE | |
| 194 : ReportingClient::Subdomains::EXCLUDE; | |
| 195 | |
| 196 std::string group; | |
| 197 if (!client.GetString("group", &group)) | |
| 198 return false; | |
| 199 | |
| 200 std::string expires_string; | |
| 201 if (!client.GetString("expires", &expires_string)) | |
| 202 return false; | |
| 203 base::TimeTicks expires; | |
| 204 if (!DeserializeTicks(expires_string, &expires, context)) | |
| 205 return false; | |
| 206 | |
| 207 context->cache()->SetClient(origin, endpoint, subdomains, group, expires); | |
| 208 return true; | |
| 209 } | |
| 210 | |
| 211 std::unique_ptr<base::Value> SerializeClients(ReportingContext* context) { | |
| 212 std::vector<const ReportingClient*> clients; | |
| 213 context->cache()->GetClients(&clients); | |
| 214 | |
| 215 auto serialized = base::MakeUnique<base::ListValue>(); | |
| 216 for (const ReportingClient* client : clients) | |
| 217 serialized->Append(SerializeClient(*client, context)); | |
| 218 | |
| 219 return std::move(serialized); | |
| 220 } | |
| 221 | |
| 222 bool DeserializeClients(const base::ListValue& clients, | |
| 223 ReportingContext* context) { | |
| 224 for (size_t i = 0; i < clients.GetSize(); ++i) { | |
| 225 const base::DictionaryValue* client; | |
| 226 if (!clients.GetDictionary(i, &client)) | |
| 227 return false; | |
| 228 if (!DeserializeClient(*client, context)) | |
| 229 return false; | |
| 230 } | |
| 231 | |
| 232 return true; | |
| 233 } | |
| 234 | |
| 235 } // namespace | |
| 236 | |
| 237 // static | |
| 238 std::unique_ptr<base::Value> ReportingSerializer::SerializeToValue( | |
| 239 ReportingContext* context) { | |
| 240 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 241 | |
| 242 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.
| |
| 243 | |
| 244 bool persist_reports = context->policy().persist_reports_across_restarts; | |
| 245 serialized->SetBoolean("includes_reports", persist_reports); | |
| 246 if (persist_reports) | |
| 247 serialized->Set("reports", SerializeReports(context)); | |
| 248 | |
| 249 bool persist_clients = context->policy().persist_clients_across_restarts; | |
| 250 serialized->SetBoolean("includes_clients", persist_clients); | |
| 251 if (persist_clients) | |
| 252 serialized->Set("clients", SerializeClients(context)); | |
| 253 | |
| 254 return std::move(serialized); | |
| 255 } | |
| 256 | |
| 257 // static | |
| 258 bool ReportingSerializer::DeserializeFromValue( | |
| 259 const base::Value& serialized_value, | |
| 260 ReportingContext* context) { | |
| 261 int version; | |
| 262 | |
| 263 const base::DictionaryValue* serialized; | |
| 264 if (!serialized_value.GetAsDictionary(&serialized)) | |
| 265 return false; | |
| 266 | |
| 267 if (!serialized->GetInteger("reporting_serialized_cache_version", &version)) | |
| 268 return false; | |
| 269 if (version != 1) | |
| 270 return false; | |
| 271 | |
| 272 bool includes_reports; | |
| 273 bool includes_clients; | |
| 274 if (!serialized->GetBoolean("includes_reports", &includes_reports) || | |
| 275 !serialized->GetBoolean("includes_clients", &includes_clients)) { | |
| 276 return false; | |
| 277 } | |
| 278 | |
|
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.
| |
| 279 if (includes_reports) { | |
| 280 const base::ListValue* reports; | |
| 281 if (!serialized->GetList("reports", &reports)) | |
| 282 return false; | |
| 283 if (!DeserializeReports(*reports, context)) | |
| 284 return false; | |
| 285 } | |
| 286 | |
| 287 if (includes_clients) { | |
| 288 const base::ListValue* clients; | |
| 289 if (!serialized->GetList("clients", &clients)) | |
| 290 return false; | |
| 291 if (!DeserializeClients(*clients, context)) | |
| 292 return false; | |
| 293 } | |
| 294 | |
| 295 return true; | |
| 296 } | |
| 297 | |
| 298 } // namespace net | |
| OLD | NEW |