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 |