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