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