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_persister.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/timer/timer.h" | |
| 15 #include "base/values.h" | |
| 16 #include "net/reporting/reporting_cache.h" | |
| 17 #include "net/reporting/reporting_client.h" | |
| 18 #include "net/reporting/reporting_context.h" | |
| 19 #include "net/reporting/reporting_delegate.h" | |
| 20 #include "net/reporting/reporting_observer.h" | |
| 21 #include "net/reporting/reporting_policy.h" | |
| 22 #include "net/reporting/reporting_report.h" | |
| 23 | |
| 24 namespace net { | |
| 25 namespace { | |
| 26 | |
| 27 std::unique_ptr<base::Value> SerializeOrigin(const url::Origin& origin) { | |
| 28 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 29 | |
| 30 serialized->SetString("scheme", origin.scheme()); | |
| 31 serialized->SetString("host", origin.host()); | |
| 32 serialized->SetInteger("port", origin.port()); | |
| 33 serialized->SetString("suborigin", origin.suborigin()); | |
| 34 | |
| 35 return std::move(serialized); | |
| 36 } | |
| 37 | |
| 38 bool DeserializeOrigin(const base::DictionaryValue& serialized, | |
| 39 url::Origin* origin_out) { | |
| 40 std::string scheme; | |
| 41 if (!serialized.GetString("scheme", &scheme)) | |
| 42 return false; | |
| 43 | |
| 44 std::string host; | |
| 45 if (!serialized.GetString("host", &host)) | |
| 46 return false; | |
| 47 | |
| 48 int port_int; | |
| 49 if (!serialized.GetInteger("port", &port_int)) | |
| 50 return false; | |
| 51 uint16_t port = static_cast<uint16_t>(port_int); | |
| 52 if (port_int != port) | |
| 53 return false; | |
| 54 | |
| 55 std::string suborigin; | |
| 56 if (!serialized.GetString("suborigin", &suborigin)) | |
| 57 return false; | |
| 58 | |
| 59 *origin_out = url::Origin::CreateFromNormalizedTupleWithSuborigin( | |
| 60 scheme, host, port, suborigin); | |
| 61 return true; | |
| 62 } | |
| 63 | |
| 64 class ReportingPersisterImpl : public ReportingPersister, | |
| 65 public ReportingObserver { | |
| 66 public: | |
| 67 ReportingPersisterImpl(ReportingContext* context) | |
| 68 : context_(context), timer_(base::MakeUnique<base::OneShotTimer>()) { | |
| 69 context_->AddObserver(this); | |
| 70 } | |
| 71 | |
| 72 // ReportingPersister implementation: | |
| 73 | |
| 74 ~ReportingPersisterImpl() override { context_->RemoveObserver(this); } | |
| 75 | |
| 76 void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override { | |
| 77 DCHECK(!timer_->IsRunning()); | |
| 78 timer_ = std::move(timer); | |
| 79 } | |
| 80 | |
| 81 // ReportingObserver implementation: | |
| 82 | |
| 83 void OnContextInitializing() override { | |
| 84 std::unique_ptr<const base::Value> persisted_data = | |
| 85 context_->delegate()->GetPersistedData(); | |
| 86 if (persisted_data) | |
| 87 Deserialize(*persisted_data); | |
| 88 } | |
| 89 | |
| 90 void OnCacheUpdated() override { | |
|
shivanisha
2017/04/10 18:29:29
dcheck that context is initialized. Also in Report
Julia Tuttle
2017/04/11 19:20:46
Done.
| |
| 91 if (!timer_->IsRunning()) | |
| 92 StartTimer(); | |
| 93 } | |
| 94 | |
| 95 private: | |
| 96 void StartTimer() { | |
| 97 timer_->Start( | |
| 98 FROM_HERE, context_->policy().persistence_interval, | |
| 99 base::Bind(&ReportingPersisterImpl::Persist, base::Unretained(this))); | |
| 100 } | |
| 101 | |
| 102 void Persist() { delegate()->PersistData(Serialize()); } | |
| 103 | |
| 104 std::string SerializeTicks(base::TimeTicks time_ticks) { | |
| 105 base::Time time = time_ticks - tick_clock()->NowTicks() + clock()->Now(); | |
| 106 return base::Int64ToString(time.ToInternalValue()); | |
| 107 } | |
| 108 | |
| 109 bool DeserializeTicks(const std::string& serialized, | |
| 110 base::TimeTicks* time_ticks_out) { | |
| 111 int64_t internal; | |
| 112 if (!base::StringToInt64(serialized, &internal)) | |
| 113 return false; | |
| 114 | |
| 115 base::Time time = base::Time::FromInternalValue(internal); | |
| 116 *time_ticks_out = time - clock()->Now() + tick_clock()->NowTicks(); | |
| 117 return true; | |
| 118 } | |
| 119 | |
| 120 std::unique_ptr<base::Value> SerializeReport(const ReportingReport& report) { | |
| 121 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 122 | |
| 123 serialized->SetString("url", report.url.spec()); | |
| 124 serialized->SetString("group", report.group); | |
| 125 serialized->SetString("type", report.type); | |
| 126 serialized->Set("body", report.body->CreateDeepCopy()); | |
| 127 serialized->SetString("queued", SerializeTicks(report.queued)); | |
| 128 serialized->SetInteger("attempts", report.attempts); | |
| 129 | |
| 130 return std::move(serialized); | |
| 131 } | |
| 132 | |
| 133 bool DeserializeReport(const base::DictionaryValue& report) { | |
| 134 std::string url_string; | |
| 135 if (!report.GetString("url", &url_string)) | |
| 136 return false; | |
| 137 GURL url(url_string); | |
| 138 if (!url.is_valid()) | |
| 139 return false; | |
| 140 | |
| 141 std::string group; | |
| 142 if (!report.GetString("group", &group)) | |
| 143 return false; | |
| 144 | |
| 145 std::string type; | |
| 146 if (!report.GetString("type", &type)) | |
| 147 return false; | |
| 148 | |
| 149 const base::Value* body_original; | |
| 150 if (!report.Get("body", &body_original)) | |
| 151 return false; | |
| 152 std::unique_ptr<base::Value> body = body_original->CreateDeepCopy(); | |
| 153 | |
| 154 std::string queued_string; | |
| 155 if (!report.GetString("queued", &queued_string)) | |
| 156 return false; | |
| 157 base::TimeTicks queued; | |
| 158 if (!DeserializeTicks(queued_string, &queued)) | |
| 159 return false; | |
| 160 | |
| 161 int attempts; | |
| 162 if (!report.GetInteger("attempts", &attempts)) | |
| 163 return false; | |
| 164 if (attempts < 0) | |
| 165 return false; | |
| 166 | |
| 167 cache()->AddReport(url, group, type, std::move(body), queued, attempts); | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 std::unique_ptr<base::Value> SerializeReports() { | |
| 172 std::vector<const ReportingReport*> reports; | |
| 173 cache()->GetReports(&reports); | |
| 174 | |
| 175 auto serialized = base::MakeUnique<base::ListValue>(); | |
| 176 for (const ReportingReport* report : reports) | |
| 177 serialized->Append(SerializeReport(*report)); | |
| 178 | |
| 179 return std::move(serialized); | |
| 180 } | |
| 181 | |
| 182 bool DeserializeReports(const base::ListValue& reports) { | |
| 183 for (size_t i = 0; i < reports.GetSize(); ++i) { | |
| 184 const base::DictionaryValue* report; | |
| 185 if (!reports.GetDictionary(i, &report)) | |
| 186 return false; | |
| 187 if (!DeserializeReport(*report)) | |
| 188 return false; | |
| 189 } | |
| 190 | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 std::unique_ptr<base::Value> SerializeClient(const ReportingClient& client) { | |
| 195 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 196 | |
| 197 serialized->Set("origin", SerializeOrigin(client.origin)); | |
| 198 serialized->SetString("endpoint", client.endpoint.spec()); | |
| 199 serialized->SetBoolean( | |
| 200 "subdomains", | |
| 201 client.subdomains == ReportingClient::Subdomains::INCLUDE); | |
| 202 serialized->SetString("group", client.group); | |
| 203 serialized->SetString("expires", SerializeTicks(client.expires)); | |
| 204 | |
| 205 return std::move(serialized); | |
| 206 } | |
| 207 | |
| 208 bool DeserializeClient(const base::DictionaryValue& client) { | |
| 209 const base::DictionaryValue* origin_value; | |
| 210 if (!client.GetDictionary("origin", &origin_value)) | |
| 211 return false; | |
| 212 url::Origin origin; | |
| 213 if (!DeserializeOrigin(*origin_value, &origin)) | |
| 214 return false; | |
| 215 | |
| 216 std::string endpoint_string; | |
| 217 if (!client.GetString("endpoint", &endpoint_string)) | |
| 218 return false; | |
| 219 GURL endpoint(endpoint_string); | |
| 220 if (!endpoint.is_valid()) | |
| 221 return false; | |
| 222 | |
| 223 bool subdomains_bool; | |
| 224 if (!client.GetBoolean("subdomains", &subdomains_bool)) | |
| 225 return false; | |
| 226 ReportingClient::Subdomains subdomains = | |
| 227 subdomains_bool ? ReportingClient::Subdomains::INCLUDE | |
| 228 : ReportingClient::Subdomains::EXCLUDE; | |
| 229 | |
| 230 std::string group; | |
| 231 if (!client.GetString("group", &group)) | |
| 232 return false; | |
| 233 | |
| 234 std::string expires_string; | |
| 235 if (!client.GetString("expires", &expires_string)) | |
| 236 return false; | |
| 237 base::TimeTicks expires; | |
| 238 if (!DeserializeTicks(expires_string, &expires)) | |
| 239 return false; | |
| 240 | |
| 241 cache()->SetClient(origin, endpoint, subdomains, group, expires); | |
| 242 return true; | |
| 243 } | |
| 244 | |
| 245 std::unique_ptr<base::Value> SerializeClients() { | |
| 246 std::vector<const ReportingClient*> clients; | |
| 247 cache()->GetClients(&clients); | |
| 248 | |
| 249 auto serialized = base::MakeUnique<base::ListValue>(); | |
| 250 for (const ReportingClient* client : clients) | |
| 251 serialized->Append(SerializeClient(*client)); | |
| 252 | |
| 253 return std::move(serialized); | |
| 254 } | |
| 255 | |
| 256 bool DeserializeClients(const base::ListValue& clients) { | |
| 257 for (size_t i = 0; i < clients.GetSize(); ++i) { | |
| 258 const base::DictionaryValue* client; | |
| 259 if (!clients.GetDictionary(i, &client)) | |
| 260 return false; | |
| 261 if (!DeserializeClient(*client)) | |
| 262 return false; | |
| 263 } | |
| 264 | |
| 265 return true; | |
| 266 } | |
| 267 | |
| 268 static const int kSupportedVersion = 1; | |
| 269 | |
| 270 std::unique_ptr<base::Value> Serialize() { | |
| 271 auto serialized = base::MakeUnique<base::DictionaryValue>(); | |
| 272 | |
| 273 serialized->SetInteger("reporting_serialized_cache_version", | |
| 274 kSupportedVersion); | |
| 275 | |
| 276 bool persist_reports = policy().persist_reports_across_restarts; | |
| 277 serialized->SetBoolean("includes_reports", persist_reports); | |
| 278 if (persist_reports) | |
| 279 serialized->Set("reports", SerializeReports()); | |
| 280 | |
| 281 bool persist_clients = policy().persist_clients_across_restarts; | |
| 282 serialized->SetBoolean("includes_clients", persist_clients); | |
| 283 if (persist_clients) | |
| 284 serialized->Set("clients", SerializeClients()); | |
| 285 | |
| 286 return std::move(serialized); | |
| 287 } | |
| 288 | |
| 289 bool Deserialize(const base::Value& serialized_value) { | |
| 290 std::vector<const ReportingReport*> reports; | |
| 291 cache()->GetReports(&reports); | |
| 292 DCHECK(reports.empty()); | |
| 293 | |
| 294 std::vector<const ReportingClient*> clients; | |
| 295 cache()->GetClients(&clients); | |
| 296 DCHECK(clients.empty()); | |
| 297 | |
| 298 int version; | |
| 299 | |
| 300 const base::DictionaryValue* serialized; | |
| 301 if (!serialized_value.GetAsDictionary(&serialized)) | |
| 302 return false; | |
| 303 | |
| 304 if (!serialized->GetInteger("reporting_serialized_cache_version", &version)) | |
| 305 return false; | |
| 306 if (version != kSupportedVersion) | |
| 307 return false; | |
| 308 | |
| 309 bool includes_reports; | |
| 310 bool includes_clients; | |
| 311 if (!serialized->GetBoolean("includes_reports", &includes_reports) || | |
| 312 !serialized->GetBoolean("includes_clients", &includes_clients)) { | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 if (includes_reports) { | |
| 317 const base::ListValue* reports; | |
| 318 if (!serialized->GetList("reports", &reports)) | |
| 319 return false; | |
| 320 if (!DeserializeReports(*reports)) | |
| 321 return false; | |
| 322 } | |
| 323 | |
| 324 if (includes_clients) { | |
| 325 const base::ListValue* clients; | |
| 326 if (!serialized->GetList("clients", &clients)) | |
| 327 return false; | |
| 328 if (!DeserializeClients(*clients)) | |
| 329 return false; | |
| 330 } | |
| 331 | |
| 332 return true; | |
| 333 } | |
| 334 | |
| 335 const ReportingPolicy& policy() { return context_->policy(); } | |
| 336 ReportingDelegate* delegate() { return context_->delegate(); } | |
| 337 base::Clock* clock() { return context_->clock(); } | |
| 338 base::TickClock* tick_clock() { return context_->tick_clock(); } | |
| 339 ReportingCache* cache() { return context_->cache(); } | |
| 340 | |
| 341 ReportingContext* context_; | |
| 342 std::unique_ptr<base::Timer> timer_; | |
| 343 }; | |
| 344 | |
| 345 } // namespace | |
| 346 | |
| 347 // static | |
| 348 std::unique_ptr<ReportingPersister> ReportingPersister::Create( | |
| 349 ReportingContext* context) { | |
| 350 return base::MakeUnique<ReportingPersisterImpl>(context); | |
| 351 } | |
| 352 | |
| 353 ReportingPersister::~ReportingPersister() {} | |
| 354 | |
| 355 } // namespace net | |
| OLD | NEW |