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 |