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 } |
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(to_evict); |
| 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_) { |
| 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 |