1 // Copyright 2013 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 "webkit/browser/quota/usage_tracker.h" 6 7 #include <algorithm> 8 #include <deque> 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/bind.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "base/stl_util.h" 16 #include "net/base/net_util.h" 17 18 namespace quota { 19 20 namespace { 21 22 typedef ClientUsageTracker::OriginUsageAccumulator OriginUsageAccumulator; 23 typedef ClientUsageTracker::OriginSetByHost OriginSetByHost; 24 25 void DidGetOriginUsage(const OriginUsageAccumulator& accumulator, 26 const GURL& origin, 27 int64 usage) { 28 accumulator.Run(origin, usage); 29 } 30 31 void DidGetHostUsage(const UsageCallback& callback, 32 int64 limited_usage, 33 int64 unlimited_usage) { 34 DCHECK_GE(limited_usage, 0); 35 DCHECK_GE(unlimited_usage, 0); 36 callback.Run(limited_usage + unlimited_usage); 37 } 38 39 void NoopHostUsageCallback(int64 usage) {} 40 41 bool EraseOriginFromOriginSet(OriginSetByHost* origins_by_host, 42 const std::string& host, 43 const GURL& origin) { 44 OriginSetByHost::iterator found = origins_by_host->find(host); 45 if (found == origins_by_host->end()) 46 return false; 47 48 if (!found->second.erase(origin)) 49 return false; 50 51 if (found->second.empty()) 52 origins_by_host->erase(host); 53 return true; 54 } 55 56 bool OriginSetContainsOrigin(const OriginSetByHost& origins, 57 const std::string& host, 58 const GURL& origin) { 59 OriginSetByHost::const_iterator itr = origins.find(host); 60 return itr != origins.end() && ContainsKey(itr->second, origin); 61 } 62 63 void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, 64 int64 total_global_usage, 65 int64 global_unlimited_usage) { 66 callback.Run(total_global_usage - global_unlimited_usage); 67 } 68 69 } // namespace 70 71 // UsageTracker ---------------------------------------------------------- 72 73 UsageTracker::UsageTracker(const QuotaClientList& clients, 74 StorageType type, 75 SpecialStoragePolicy* special_storage_policy) 76 : type_(type), 77 weak_factory_(this) { 78 for (QuotaClientList::const_iterator iter = clients.begin(); 79 iter != clients.end(); 80 ++iter) { 81 if ((*iter)->DoesSupport(type)) { 82 client_tracker_map_[(*iter)->id()] = 83 new ClientUsageTracker(this, *iter, type, special_storage_policy); 84 } 85 } 86 } 87 88 UsageTracker::~UsageTracker() { 89 STLDeleteValues(&client_tracker_map_); 90 } 91 92 ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) { 93 ClientTrackerMap::iterator found = client_tracker_map_.find(client_id); 94 if (found != client_tracker_map_.end()) 95 return found->second; 96 return NULL; 97 } 98 99 void UsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) { 100 if (global_usage_callbacks_.HasCallbacks()) { 101 global_usage_callbacks_.Add(base::Bind( 102 &DidGetGlobalUsageForLimitedGlobalUsage, callback)); 103 return; 104 } 105 106 if (!global_limited_usage_callbacks_.Add(callback)) 107 return; 108 109 AccumulateInfo* info = new AccumulateInfo; 110 // Calling GetGlobalLimitedUsage(accumulator) may synchronously 111 // return if the usage is cached, which may in turn dispatch 112 // the completion callback before we finish looping over 113 // all clients (because info->pending_clients may reach 0 114 // during the loop). 115 // To avoid this, we add one more pending client as a sentinel 116 // and fire the sentinel callback at the end. 117 info->pending_clients = client_tracker_map_.size() + 1; 118 UsageCallback accumulator = base::Bind( 119 &UsageTracker::AccumulateClientGlobalLimitedUsage, 120 weak_factory_.GetWeakPtr(), base::Owned(info)); 121 122 for (ClientTrackerMap::iterator iter = client_tracker_map_.begin(); 123 iter != client_tracker_map_.end(); 124 ++iter) 125 iter->second->GetGlobalLimitedUsage(accumulator); 126 127 // Fire the sentinel as we've now called GetGlobalUsage for all clients. 128 accumulator.Run(0); 129 } 130 131 void UsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) { 132 if (!global_usage_callbacks_.Add(callback)) 133 return; 134 135 AccumulateInfo* info = new AccumulateInfo; 136 // Calling GetGlobalUsage(accumulator) may synchronously 137 // return if the usage is cached, which may in turn dispatch 138 // the completion callback before we finish looping over 139 // all clients (because info->pending_clients may reach 0 140 // during the loop). 141 // To avoid this, we add one more pending client as a sentinel 142 // and fire the sentinel callback at the end. 143 info->pending_clients = client_tracker_map_.size() + 1; 144 GlobalUsageCallback accumulator = base::Bind( 145 &UsageTracker::AccumulateClientGlobalUsage, weak_factory_.GetWeakPtr(), 146 base::Owned(info)); 147 148 for (ClientTrackerMap::iterator iter = client_tracker_map_.begin(); 149 iter != client_tracker_map_.end(); 150 ++iter) 151 iter->second->GetGlobalUsage(accumulator); 152 153 // Fire the sentinel as we've now called GetGlobalUsage for all clients. 154 accumulator.Run(0, 0); 155 } 156 157 void UsageTracker::GetHostUsage(const std::string& host, 158 const UsageCallback& callback) { 159 if (!host_usage_callbacks_.Add(host, callback)) 160 return; 161 162 AccumulateInfo* info = new AccumulateInfo; 163 // Calling GetHostUsage(accumulator) may synchronously 164 // return if the usage is cached, which may in turn dispatch 165 // the completion callback before we finish looping over 166 // all clients (because info->pending_clients may reach 0 167 // during the loop). 168 // To avoid this, we add one more pending client as a sentinel 169 // and fire the sentinel callback at the end. 170 info->pending_clients = client_tracker_map_.size() + 1; 171 UsageCallback accumulator = base::Bind( 172 &UsageTracker::AccumulateClientHostUsage, weak_factory_.GetWeakPtr(), 173 base::Owned(info), host); 174 175 for (ClientTrackerMap::iterator iter = client_tracker_map_.begin(); 176 iter != client_tracker_map_.end(); 177 ++iter) 178 iter->second->GetHostUsage(host, accumulator); 179 180 // Fire the sentinel as we've now called GetHostUsage for all clients. 181 accumulator.Run(0); 182 } 183 184 void UsageTracker::UpdateUsageCache( 185 QuotaClient::ID client_id, const GURL& origin, int64 delta) { 186 ClientUsageTracker* client_tracker = GetClientTracker(client_id); 187 DCHECK(client_tracker); 188 client_tracker->UpdateUsageCache(origin, delta); 189 } 190 191 void UsageTracker::GetCachedHostsUsage( 192 std::map<std::string, int64>* host_usage) const { 193 DCHECK(host_usage); 194 host_usage->clear(); 195 for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin(); 196 iter != client_tracker_map_.end(); ++iter) { 197 iter->second->GetCachedHostsUsage(host_usage); 198 } 199 } 200 201 void UsageTracker::GetCachedOrigins(std::set<GURL>* origins) const { 202 DCHECK(origins); 203 origins->clear(); 204 for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin(); 205 iter != client_tracker_map_.end(); ++iter) { 206 iter->second->GetCachedOrigins(origins); 207 } 208 } 209 210 void UsageTracker::SetUsageCacheEnabled(QuotaClient::ID client_id, 211 const GURL& origin, 212 bool enabled) { 213 ClientUsageTracker* client_tracker = GetClientTracker(client_id); 214 DCHECK(client_tracker); 215 216 client_tracker->SetUsageCacheEnabled(origin, enabled); 217 } 218 219 void UsageTracker::AccumulateClientGlobalLimitedUsage(AccumulateInfo* info, 220 int64 limited_usage) { 221 info->usage += limited_usage; 222 if (--info->pending_clients) 223 return; 224 225 // All the clients have returned their usage data. Dispatch the 226 // pending callbacks. 227 global_limited_usage_callbacks_.Run(MakeTuple(info->usage)); 228 } 229 230 void UsageTracker::AccumulateClientGlobalUsage(AccumulateInfo* info, 231 int64 usage, 232 int64 unlimited_usage) { 233 info->usage += usage; 234 info->unlimited_usage += unlimited_usage; 235 if (--info->pending_clients) 236 return; 237 238 // Defend against confusing inputs from clients. 239 if (info->usage < 0) 240 info->usage = 0; 241 242 // TODO(michaeln): The unlimited number is not trustworthy, it 243 // can get out of whack when apps are installed or uninstalled. 244 if (info->unlimited_usage > info->usage) 245 info->unlimited_usage = info->usage; 246 else if (info->unlimited_usage < 0) 247 info->unlimited_usage = 0; 248 249 // All the clients have returned their usage data. Dispatch the 250 // pending callbacks. 251 global_usage_callbacks_.Run(MakeTuple(info->usage, info->unlimited_usage)); 252 } 253 254 void UsageTracker::AccumulateClientHostUsage(AccumulateInfo* info, 255 const std::string& host, 256 int64 usage) { 257 info->usage += usage; 258 if (--info->pending_clients) 259 return; 260 261 // Defend against confusing inputs from clients. 262 if (info->usage < 0) 263 info->usage = 0; 264 265 // All the clients have returned their usage data. Dispatch the 266 // pending callbacks. 267 host_usage_callbacks_.Run(host, MakeTuple(info->usage)); 268 } 269 270 // ClientUsageTracker ---------------------------------------------------- 271 272 ClientUsageTracker::ClientUsageTracker( 273 UsageTracker* tracker, QuotaClient* client, StorageType type, 274 SpecialStoragePolicy* special_storage_policy) 275 : tracker_(tracker), 276 client_(client), 277 type_(type), 278 global_limited_usage_(0), 279 global_unlimited_usage_(0), 280 global_usage_retrieved_(false), 281 special_storage_policy_(special_storage_policy) { 282 DCHECK(tracker_); 283 DCHECK(client_); 284 if (special_storage_policy_.get()) 285 special_storage_policy_->AddObserver(this); 286 } 287 288 ClientUsageTracker::~ClientUsageTracker() { 289 if (special_storage_policy_.get()) 290 special_storage_policy_->RemoveObserver(this); 291 } 292 293 void ClientUsageTracker::GetGlobalLimitedUsage(const UsageCallback& callback) { 294 if (!global_usage_retrieved_) { 295 GetGlobalUsage(base::Bind(&DidGetGlobalUsageForLimitedGlobalUsage, 296 callback)); 297 return; 298 } 299 300 if (non_cached_limited_origins_by_host_.empty()) { 301 callback.Run(global_limited_usage_); 302 return; 303 } 304 305 AccumulateInfo* info = new AccumulateInfo; 306 info->pending_jobs = non_cached_limited_origins_by_host_.size() + 1; 307 UsageCallback accumulator = base::Bind( 308 &ClientUsageTracker::AccumulateLimitedOriginUsage, AsWeakPtr(), 309 base::Owned(info), callback); 310 311 for (OriginSetByHost::iterator host_itr = 312 non_cached_limited_origins_by_host_.begin(); 313 host_itr != non_cached_limited_origins_by_host_.end(); ++host_itr) { 314 for (std::set<GURL>::iterator origin_itr = host_itr->second.begin(); 315 origin_itr != host_itr->second.end(); ++origin_itr) 316 client_->GetOriginUsage(*origin_itr, type_, accumulator); 317 } 318 319 accumulator.Run(global_limited_usage_); 320 } 321 322 void ClientUsageTracker::GetGlobalUsage(const GlobalUsageCallback& callback) { 323 if (global_usage_retrieved_ && 324 non_cached_limited_origins_by_host_.empty() && 325 non_cached_unlimited_origins_by_host_.empty()) { 326 callback.Run(global_limited_usage_ + global_unlimited_usage_, 327 global_unlimited_usage_); 328 return; 329 } 330 331 client_->GetOriginsForType(type_, base::Bind( 332 &ClientUsageTracker::DidGetOriginsForGlobalUsage, AsWeakPtr(), 333 callback)); 334 } 335 336 void ClientUsageTracker::GetHostUsage( 337 const std::string& host, const UsageCallback& callback) { 338 if (ContainsKey(cached_hosts_, host) && 339 !ContainsKey(non_cached_limited_origins_by_host_, host) && 340 !ContainsKey(non_cached_unlimited_origins_by_host_, host)) { 341 // TODO(kinuko): Drop host_usage_map_ cache periodically. 342 callback.Run(GetCachedHostUsage(host)); 343 return; 344 } 345 346 if (!host_usage_accumulators_.Add( 347 host, base::Bind(&DidGetHostUsage, callback))) 348 return; 349 client_->GetOriginsForHost(type_, host, base::Bind( 350 &ClientUsageTracker::DidGetOriginsForHostUsage, AsWeakPtr(), host)); 351 } 352 353 void ClientUsageTracker::UpdateUsageCache( 354 const GURL& origin, int64 delta) { 355 std::string host = net::GetHostOrSpecFromURL(origin); 356 if (cached_hosts_.find(host) != cached_hosts_.end()) { 357 if (!IsUsageCacheEnabledForOrigin(origin)) 358 return; 359 360 cached_usage_by_host_[host][origin] += delta; 361 if (IsStorageUnlimited(origin)) 362 global_unlimited_usage_ += delta; 363 else 364 global_limited_usage_ += delta; 365 DCHECK_GE(cached_usage_by_host_[host][origin], 0); 366 DCHECK_GE(global_limited_usage_, 0); 367 return; 368 } 369 370 // We don't know about this host yet, so populate our cache for it. 371 GetHostUsage(host, base::Bind(&NoopHostUsageCallback)); 372 } 373 374 void ClientUsageTracker::GetCachedHostsUsage( 375 std::map<std::string, int64>* host_usage) const { 376 DCHECK(host_usage); 377 for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); 378 host_iter != cached_usage_by_host_.end(); host_iter++) { 379 const std::string& host = host_iter->first; 380 (*host_usage)[host] += GetCachedHostUsage(host); 381 } 382 } 383 384 void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const { 385 DCHECK(origins); 386 for (HostUsageMap::const_iterator host_iter = cached_usage_by_host_.begin(); 387 host_iter != cached_usage_by_host_.end(); host_iter++) { 388 const UsageMap& origin_map = host_iter->second; 389 for (UsageMap::const_iterator origin_iter = origin_map.begin(); 390 origin_iter != origin_map.end(); origin_iter++) { 391 origins->insert(origin_iter->first); 392 } 393 } 394 } 395 396 void ClientUsageTracker::SetUsageCacheEnabled(const GURL& origin, 397 bool enabled) { 398 std::string host = net::GetHostOrSpecFromURL(origin); 399 if (!enabled) { 400 // Erase |origin| from cache and subtract its usage. 401 HostUsageMap::iterator found_host = cached_usage_by_host_.find(host); 402 if (found_host != cached_usage_by_host_.end()) { 403 UsageMap& cached_usage_for_host = found_host->second; 404 405 UsageMap::iterator found = cached_usage_for_host.find(origin); 406 if (found != cached_usage_for_host.end()) { 407 int64 usage = found->second; 408 UpdateUsageCache(origin, -usage); 409 cached_usage_for_host.erase(found); 410 if (cached_usage_for_host.empty()) { 411 cached_usage_by_host_.erase(found_host); 412 cached_hosts_.erase(host); 413 } 414 } 415 } 416 417 if (IsStorageUnlimited(origin)) 418 non_cached_unlimited_origins_by_host_[host].insert(origin); 419 else 420 non_cached_limited_origins_by_host_[host].insert(origin); 421 } else { 422 // Erase |origin| from |non_cached_origins_| and invalidate the usage cache 423 // for the host. 424 if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, 425 host, origin) || 426 EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, 427 host, origin)) { 428 cached_hosts_.erase(host); 429 global_usage_retrieved_ = false; 430 } 431 } 432 } 433 434 void ClientUsageTracker::AccumulateLimitedOriginUsage( 435 AccumulateInfo* info, 436 const UsageCallback& callback, 437 int64 usage) { 438 info->limited_usage += usage; 439 if (--info->pending_jobs) 440 return; 441 442 callback.Run(info->limited_usage); 443 } 444 445 void ClientUsageTracker::DidGetOriginsForGlobalUsage( 446 const GlobalUsageCallback& callback, 447 const std::set<GURL>& origins) { 448 OriginSetByHost origins_by_host; 449 for (std::set<GURL>::const_iterator itr = origins.begin(); 450 itr != origins.end(); ++itr) 451 origins_by_host[net::GetHostOrSpecFromURL(*itr)].insert(*itr); 452 453 AccumulateInfo* info = new AccumulateInfo; 454 // Getting host usage may synchronously return the result if the usage is 455 // cached, which may in turn dispatch the completion callback before we finish 456 // looping over all hosts (because info->pending_jobs may reach 0 during the 457 // loop). To avoid this, we add one more pending host as a sentinel and 458 // fire the sentinel callback at the end. 459 info->pending_jobs = origins_by_host.size() + 1; 460 HostUsageAccumulator accumulator = 461 base::Bind(&ClientUsageTracker::AccumulateHostUsage, AsWeakPtr(), 462 base::Owned(info), callback); 463 464 for (OriginSetByHost::iterator itr = origins_by_host.begin(); 465 itr != origins_by_host.end(); ++itr) { 466 if (host_usage_accumulators_.Add(itr->first, accumulator)) 467 GetUsageForOrigins(itr->first, itr->second); 468 } 469 470 // Fire the sentinel as we've now called GetUsageForOrigins for all clients. 471 accumulator.Run(0, 0); 472 } 473 474 void ClientUsageTracker::AccumulateHostUsage( 475 AccumulateInfo* info, 476 const GlobalUsageCallback& callback, 477 int64 limited_usage, 478 int64 unlimited_usage) { 479 info->limited_usage += limited_usage; 480 info->unlimited_usage += unlimited_usage; 481 if (--info->pending_jobs) 482 return; 483 484 DCHECK_GE(info->limited_usage, 0); 485 DCHECK_GE(info->unlimited_usage, 0); 486 487 global_usage_retrieved_ = true; 488 callback.Run(info->limited_usage + info->unlimited_usage, 489 info->unlimited_usage); 490 } 491 492 void ClientUsageTracker::DidGetOriginsForHostUsage( 493 const std::string& host, 494 const std::set<GURL>& origins) { 495 GetUsageForOrigins(host, origins); 496 } 497 498 void ClientUsageTracker::GetUsageForOrigins( 499 const std::string& host, 500 const std::set<GURL>& origins) { 501 AccumulateInfo* info = new AccumulateInfo; 502 // Getting origin usage may synchronously return the result if the usage is 503 // cached, which may in turn dispatch the completion callback before we finish 504 // looping over all origins (because info->pending_jobs may reach 0 during the 505 // loop). To avoid this, we add one more pending origin as a sentinel and 506 // fire the sentinel callback at the end. 507 info->pending_jobs = origins.size() + 1; 508 OriginUsageAccumulator accumulator = 509 base::Bind(&ClientUsageTracker::AccumulateOriginUsage, AsWeakPtr(), 510 base::Owned(info), host); 511 512 for (std::set<GURL>::const_iterator itr = origins.begin(); 513 itr != origins.end(); ++itr) { 514 DCHECK_EQ(host, net::GetHostOrSpecFromURL(*itr)); 515 516 int64 origin_usage = 0; 517 if (GetCachedOriginUsage(*itr, &origin_usage)) { 518 accumulator.Run(*itr, origin_usage); 519 } else { 520 client_->GetOriginUsage(*itr, type_, base::Bind( 521 &DidGetOriginUsage, accumulator, *itr)); 522 } 523 } 524 525 // Fire the sentinel as we've now called GetOriginUsage for all clients. 526 accumulator.Run(GURL(), 0); 527 } 528 529 void ClientUsageTracker::AccumulateOriginUsage(AccumulateInfo* info, 530 const std::string& host, 531 const GURL& origin, 532 int64 usage) { 533 if (!origin.is_empty()) { 534 if (usage < 0) 535 usage = 0; 536 537 if (IsStorageUnlimited(origin)) 538 info->unlimited_usage += usage; 539 else 540 info->limited_usage += usage; 541 if (IsUsageCacheEnabledForOrigin(origin)) 542 AddCachedOrigin(origin, usage); 543 } 544 if (--info->pending_jobs) 545 return; 546 547 AddCachedHost(host); 548 host_usage_accumulators_.Run( 549 host, MakeTuple(info->limited_usage, info->unlimited_usage)); 550 } 551 552 void ClientUsageTracker::AddCachedOrigin( 553 const GURL& origin, int64 new_usage) { 554 DCHECK(IsUsageCacheEnabledForOrigin(origin)); 555 556 std::string host = net::GetHostOrSpecFromURL(origin); 557 int64* usage = &cached_usage_by_host_[host][origin]; 558 int64 delta = new_usage - *usage; 559 *usage = new_usage; 560 if (delta) { 561 if (IsStorageUnlimited(origin)) 562 global_unlimited_usage_ += delta; 563 else 564 global_limited_usage_ += delta; 565 } 566 DCHECK_GE(*usage, 0); 567 DCHECK_GE(global_limited_usage_, 0); 568 } 569 570 void ClientUsageTracker::AddCachedHost(const std::string& host) { 571 cached_hosts_.insert(host); 572 } 573 574 int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) const { 575 HostUsageMap::const_iterator found = cached_usage_by_host_.find(host); 576 if (found == cached_usage_by_host_.end()) 577 return 0; 578 579 int64 usage = 0; 580 const UsageMap& map = found->second; 581 for (UsageMap::const_iterator iter = map.begin(); 582 iter != map.end(); ++iter) { 583 usage += iter->second; 584 } 585 return usage; 586 } 587 588 bool ClientUsageTracker::GetCachedOriginUsage( 589 const GURL& origin, 590 int64* usage) const { 591 std::string host = net::GetHostOrSpecFromURL(origin); 592 HostUsageMap::const_iterator found_host = cached_usage_by_host_.find(host); 593 if (found_host == cached_usage_by_host_.end()) 594 return false; 595 596 UsageMap::const_iterator found = found_host->second.find(origin); 597 if (found == found_host->second.end()) 598 return false; 599 600 DCHECK(IsUsageCacheEnabledForOrigin(origin)); 601 *usage = found->second; 602 return true; 603 } 604 605 bool ClientUsageTracker::IsUsageCacheEnabledForOrigin( 606 const GURL& origin) const { 607 std::string host = net::GetHostOrSpecFromURL(origin); 608 return !OriginSetContainsOrigin(non_cached_limited_origins_by_host_, 609 host, origin) && 610 !OriginSetContainsOrigin(non_cached_unlimited_origins_by_host_, 611 host, origin); 612 } 613 614 void ClientUsageTracker::OnGranted(const GURL& origin, 615 int change_flags) { 616 DCHECK(CalledOnValidThread()); 617 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { 618 int64 usage = 0; 619 if (GetCachedOriginUsage(origin, &usage)) { 620 global_unlimited_usage_ += usage; 621 global_limited_usage_ -= usage; 622 } 623 624 std::string host = net::GetHostOrSpecFromURL(origin); 625 if (EraseOriginFromOriginSet(&non_cached_limited_origins_by_host_, 626 host, origin)) 627 non_cached_unlimited_origins_by_host_[host].insert(origin); 628 } 629 } 630 631 void ClientUsageTracker::OnRevoked(const GURL& origin, 632 int change_flags) { 633 DCHECK(CalledOnValidThread()); 634 if (change_flags & SpecialStoragePolicy::STORAGE_UNLIMITED) { 635 int64 usage = 0; 636 if (GetCachedOriginUsage(origin, &usage)) { 637 global_unlimited_usage_ -= usage; 638 global_limited_usage_ += usage; 639 } 640 641 std::string host = net::GetHostOrSpecFromURL(origin); 642 if (EraseOriginFromOriginSet(&non_cached_unlimited_origins_by_host_, 643 host, origin)) 644 non_cached_limited_origins_by_host_[host].insert(origin); 645 } 646 } 647 648 void ClientUsageTracker::OnCleared() { 649 DCHECK(CalledOnValidThread()); 650 global_limited_usage_ += global_unlimited_usage_; 651 global_unlimited_usage_ = 0; 652 653 for (OriginSetByHost::const_iterator host_itr = 654 non_cached_unlimited_origins_by_host_.begin(); 655 host_itr != non_cached_unlimited_origins_by_host_.end(); 656 ++host_itr) { 657 for (std::set<GURL>::const_iterator origin_itr = host_itr->second.begin(); 658 origin_itr != host_itr->second.end(); 659 ++origin_itr) 660 non_cached_limited_origins_by_host_[host_itr->first].insert(*origin_itr); 661 } 662 non_cached_unlimited_origins_by_host_.clear(); 663 } 664 665 bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const { 666 if (type_ == kStorageTypeSyncable) 667 return false; 668 return special_storage_policy_.get() && 669 special_storage_policy_->IsStorageUnlimited(origin); 670 } 671 672 } // namespace quota 673