OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/reporting/reporting_cache.h" | 5 #include "net/reporting/reporting_cache.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <memory> | 8 #include <memory> |
9 #include <set> | 9 #include <set> |
10 #include <string> | 10 #include <string> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
15 #include "base/time/tick_clock.h" | |
15 #include "base/time/time.h" | 16 #include "base/time/time.h" |
16 #include "net/reporting/reporting_client.h" | 17 #include "net/reporting/reporting_client.h" |
17 #include "net/reporting/reporting_context.h" | 18 #include "net/reporting/reporting_context.h" |
18 #include "net/reporting/reporting_report.h" | 19 #include "net/reporting/reporting_report.h" |
19 #include "url/gurl.h" | 20 #include "url/gurl.h" |
20 | 21 |
21 namespace net { | 22 namespace net { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 } | 185 } |
185 } | 186 } |
186 | 187 |
187 void ReportingCache::SetClient(const url::Origin& origin, | 188 void ReportingCache::SetClient(const url::Origin& origin, |
188 const GURL& endpoint, | 189 const GURL& endpoint, |
189 ReportingClient::Subdomains subdomains, | 190 ReportingClient::Subdomains subdomains, |
190 const std::string& group, | 191 const std::string& group, |
191 base::TimeTicks expires) { | 192 base::TimeTicks expires) { |
192 DCHECK(endpoint.SchemeIsCryptographic()); | 193 DCHECK(endpoint.SchemeIsCryptographic()); |
193 | 194 |
194 // Since |subdomains| may differ from a previous call to SetClient for this | 195 base::TimeTicks last_used = tick_clock()->NowTicks(); |
195 // origin and endpoint, the cache needs to remove and re-add the client to the | 196 |
196 // index of wildcard clients, if applicable. | 197 const ReportingClient* old_client = |
197 if (base::ContainsKey(clients_, origin) && | 198 GetClientByOriginAndEndpoint(origin, endpoint); |
198 base::ContainsKey(clients_[origin], endpoint)) { | 199 if (old_client) { |
199 MaybeRemoveWildcardClient(clients_[origin][endpoint].get()); | 200 last_used = client_last_used_[old_client]; |
201 RemoveClient(old_client); | |
200 } | 202 } |
shivanisha
2017/05/03 19:00:00
May be not have old_client here at all.
AddClient
Julia Tuttle
2017/05/04 16:50:21
There's more going on in RemoveClient than just re
shivanisha
2017/05/05 19:24:48
Acknowledged.
| |
201 | 203 |
202 clients_[origin][endpoint] = base::MakeUnique<ReportingClient>( | 204 AddClient(base::MakeUnique<ReportingClient>(origin, endpoint, subdomains, |
203 origin, endpoint, subdomains, group, expires); | 205 group, expires), |
206 last_used); | |
204 | 207 |
205 MaybeAddWildcardClient(clients_[origin][endpoint].get()); | 208 if (client_last_used_.size() > context_->policy().max_client_count) { |
209 // There should only ever be one extra client, added above. | |
210 DCHECK_EQ(context_->policy().max_client_count + 1, | |
211 client_last_used_.size()); | |
212 // And that shouldn't happen if it was replaced, not added. | |
213 DCHECK(!old_client); | |
214 const ReportingClient* to_evict = | |
215 FindClientToEvict(tick_clock()->NowTicks()); | |
216 DCHECK(to_evict); | |
217 RemoveClient(FindClientToEvict(tick_clock()->NowTicks())); | |
shivanisha
2017/05/03 19:00:00
RemoveClient(to_evict)?
Julia Tuttle
2017/05/04 16:50:22
...oops, done.
| |
218 } | |
206 | 219 |
207 context_->NotifyCacheUpdated(); | 220 context_->NotifyCacheUpdated(); |
208 } | 221 } |
209 | 222 |
223 void ReportingCache::MarkClientUsed(const url::Origin& origin, | |
224 const GURL& endpoint) { | |
225 const ReportingClient* client = | |
226 GetClientByOriginAndEndpoint(origin, endpoint); | |
227 DCHECK(client); | |
228 client_last_used_[client] = tick_clock()->NowTicks(); | |
229 } | |
230 | |
210 void ReportingCache::RemoveClients( | 231 void ReportingCache::RemoveClients( |
211 const std::vector<const ReportingClient*>& clients_to_remove) { | 232 const std::vector<const ReportingClient*>& clients_to_remove) { |
212 for (const ReportingClient* client : clients_to_remove) { | 233 for (const ReportingClient* client : clients_to_remove) |
213 MaybeRemoveWildcardClient(client); | 234 RemoveClient(client); |
214 size_t erased = clients_[client->origin].erase(client->endpoint); | |
215 DCHECK_EQ(1u, erased); | |
216 } | |
217 | 235 |
218 context_->NotifyCacheUpdated(); | 236 context_->NotifyCacheUpdated(); |
219 } | 237 } |
220 | 238 |
221 void ReportingCache::RemoveClientForOriginAndEndpoint(const url::Origin& origin, | 239 void ReportingCache::RemoveClientForOriginAndEndpoint(const url::Origin& origin, |
222 const GURL& endpoint) { | 240 const GURL& endpoint) { |
223 MaybeRemoveWildcardClient(clients_[origin][endpoint].get()); | 241 const ReportingClient* client = |
224 size_t erased = clients_[origin].erase(endpoint); | 242 GetClientByOriginAndEndpoint(origin, endpoint); |
225 DCHECK_EQ(1u, erased); | 243 RemoveClient(client); |
226 | 244 |
227 context_->NotifyCacheUpdated(); | 245 context_->NotifyCacheUpdated(); |
228 } | 246 } |
229 | 247 |
230 void ReportingCache::RemoveClientsForEndpoint(const GURL& endpoint) { | 248 void ReportingCache::RemoveClientsForEndpoint(const GURL& endpoint) { |
231 for (auto& origin_and_endpoints : clients_) { | 249 std::vector<const ReportingClient*> clients_to_remove; |
232 if (base::ContainsKey(origin_and_endpoints.second, endpoint)) { | |
233 MaybeRemoveWildcardClient(origin_and_endpoints.second[endpoint].get()); | |
234 origin_and_endpoints.second.erase(endpoint); | |
235 } | |
236 } | |
237 | 250 |
238 context_->NotifyCacheUpdated(); | 251 for (auto& origin_and_endpoints : clients_) |
252 if (base::ContainsKey(origin_and_endpoints.second, endpoint)) | |
253 clients_to_remove.push_back(origin_and_endpoints.second[endpoint].get()); | |
254 | |
255 for (const ReportingClient* client : clients_to_remove) | |
256 RemoveClient(client); | |
257 | |
258 if (!clients_to_remove.empty()) | |
259 context_->NotifyCacheUpdated(); | |
239 } | 260 } |
240 | 261 |
241 void ReportingCache::RemoveAllClients() { | 262 void ReportingCache::RemoveAllClients() { |
242 clients_.clear(); | 263 clients_.clear(); |
243 wildcard_clients_.clear(); | 264 wildcard_clients_.clear(); |
265 client_last_used_.clear(); | |
244 | 266 |
245 context_->NotifyCacheUpdated(); | 267 context_->NotifyCacheUpdated(); |
246 } | 268 } |
247 | 269 |
248 const ReportingReport* ReportingCache::FindReportToEvict() const { | 270 const ReportingReport* ReportingCache::FindReportToEvict() const { |
249 const ReportingReport* earliest_queued = nullptr; | 271 const ReportingReport* earliest_queued = nullptr; |
250 | 272 |
251 for (const auto& it : reports_) { | 273 for (const auto& it : reports_) { |
252 const ReportingReport* report = it.first; | 274 const ReportingReport* report = it.first; |
253 if (base::ContainsKey(pending_reports_, report)) | 275 if (base::ContainsKey(pending_reports_, report)) |
254 continue; | 276 continue; |
255 if (!earliest_queued || report->queued < earliest_queued->queued) { | 277 if (!earliest_queued || report->queued < earliest_queued->queued) { |
256 earliest_queued = report; | 278 earliest_queued = report; |
257 } | 279 } |
258 } | 280 } |
259 | 281 |
260 return earliest_queued; | 282 return earliest_queued; |
261 } | 283 } |
262 | 284 |
263 void ReportingCache::MaybeAddWildcardClient(const ReportingClient* client) { | 285 void ReportingCache::AddClient(std::unique_ptr<ReportingClient> client, |
264 if (client->subdomains != ReportingClient::Subdomains::INCLUDE) | 286 base::TimeTicks last_used) { |
265 return; | 287 DCHECK(client); |
266 | 288 |
267 const std::string& domain = client->origin.host(); | 289 url::Origin origin = client->origin; |
268 auto inserted = wildcard_clients_[domain].insert(client); | 290 GURL endpoint = client->endpoint; |
269 DCHECK(inserted.second); | 291 |
292 auto inserted_last_used = | |
293 client_last_used_.insert(std::make_pair(client.get(), last_used)); | |
294 DCHECK(inserted_last_used.second); | |
295 | |
296 if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { | |
297 const std::string& domain = origin.host(); | |
298 auto inserted_wildcard_client = | |
299 wildcard_clients_[domain].insert(client.get()); | |
300 DCHECK(inserted_wildcard_client.second); | |
301 } | |
302 | |
303 auto inserted_client = | |
304 clients_[origin].insert(std::make_pair(endpoint, std::move(client))); | |
305 DCHECK(inserted_client.second); | |
270 } | 306 } |
271 | 307 |
272 void ReportingCache::MaybeRemoveWildcardClient(const ReportingClient* client) { | 308 void ReportingCache::RemoveClient(const ReportingClient* client) { |
273 if (client->subdomains != ReportingClient::Subdomains::INCLUDE) | 309 DCHECK(client); |
274 return; | |
275 | 310 |
276 const std::string& domain = client->origin.host(); | 311 url::Origin origin = client->origin; |
277 size_t erased = wildcard_clients_[domain].erase(client); | 312 GURL endpoint = client->endpoint; |
278 DCHECK_EQ(1u, erased); | 313 |
314 if (client->subdomains == ReportingClient::Subdomains::INCLUDE) { | |
315 const std::string& domain = origin.host(); | |
316 size_t erased_wildcard_client = wildcard_clients_[domain].erase(client); | |
317 DCHECK_EQ(1u, erased_wildcard_client); | |
318 if (wildcard_clients_[domain].empty()) { | |
319 size_t erased_wildcard_domain = wildcard_clients_.erase(domain); | |
320 DCHECK_EQ(1u, erased_wildcard_domain); | |
321 } | |
322 } | |
323 | |
324 size_t erased_last_used = client_last_used_.erase(client); | |
325 DCHECK_EQ(1u, erased_last_used); | |
326 | |
327 size_t erased_endpoint = clients_[origin].erase(endpoint); | |
328 DCHECK_EQ(1u, erased_endpoint); | |
329 if (clients_[origin].empty()) { | |
330 size_t erased_origin = clients_.erase(origin); | |
331 DCHECK_EQ(1u, erased_origin); | |
332 } | |
333 } | |
334 | |
335 const ReportingClient* ReportingCache::GetClientByOriginAndEndpoint( | |
336 const url::Origin& origin, | |
337 const GURL& endpoint) const { | |
338 const auto& origin_it = clients_.find(origin); | |
339 if (origin_it == clients_.end()) | |
340 return nullptr; | |
341 | |
342 const auto& endpoint_it = origin_it->second.find(endpoint); | |
343 if (endpoint_it == origin_it->second.end()) | |
344 return nullptr; | |
345 | |
346 return endpoint_it->second.get(); | |
279 } | 347 } |
280 | 348 |
281 void ReportingCache::GetWildcardClientsForDomainAndGroup( | 349 void ReportingCache::GetWildcardClientsForDomainAndGroup( |
282 const std::string& domain, | 350 const std::string& domain, |
283 const std::string& group, | 351 const std::string& group, |
284 std::vector<const ReportingClient*>* clients_out) const { | 352 std::vector<const ReportingClient*>* clients_out) const { |
285 clients_out->clear(); | 353 clients_out->clear(); |
286 | 354 |
287 auto it = wildcard_clients_.find(domain); | 355 auto it = wildcard_clients_.find(domain); |
288 if (it == wildcard_clients_.end()) | 356 if (it == wildcard_clients_.end()) |
289 return; | 357 return; |
290 | 358 |
291 for (const ReportingClient* client : it->second) { | 359 for (const ReportingClient* client : it->second) { |
292 DCHECK_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains); | 360 DCHECK_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains); |
293 if (client->group == group) | 361 if (client->group == group) |
294 clients_out->push_back(client); | 362 clients_out->push_back(client); |
295 } | 363 } |
296 } | 364 } |
297 | 365 |
366 const ReportingClient* ReportingCache::FindClientToEvict( | |
367 base::TimeTicks now) const { | |
368 DCHECK(!client_last_used_.empty()); | |
369 | |
370 const ReportingClient* earliest_used = nullptr; | |
371 base::TimeTicks earliest_used_last_used; | |
372 const ReportingClient* earliest_expired = nullptr; | |
373 | |
374 for (const auto& it : client_last_used_) { | |
shivanisha
2017/05/03 19:00:00
How does this ensure that clients which have pendi
Julia Tuttle
2017/05/04 16:50:21
It doesn't! The cache has no understanding of the
shivanisha
2017/05/05 19:24:48
Can we map the elements in pending_reports_ to the
Julia Tuttle
2017/05/08 14:15:55
We could do that, but that would make evicting a c
| |
375 const ReportingClient* client = it.first; | |
376 base::TimeTicks client_last_used = it.second; | |
377 if (earliest_used == nullptr || | |
378 client_last_used < earliest_used_last_used) { | |
379 earliest_used = client; | |
380 earliest_used_last_used = client_last_used; | |
381 } | |
382 if (earliest_expired == nullptr || | |
383 client->expires < earliest_expired->expires) { | |
384 earliest_expired = client; | |
385 } | |
386 } | |
387 | |
388 // If there are expired clients, return the earliest-expired. | |
389 if (earliest_expired->expires < now) | |
390 return earliest_expired; | |
391 else | |
392 return earliest_used; | |
393 } | |
394 | |
395 base::TickClock* ReportingCache::tick_clock() { | |
396 return context_->tick_clock(); | |
397 } | |
398 | |
298 } // namespace net | 399 } // namespace net |
OLD | NEW |