1// Copyright (c) 2012 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 "chrome/browser/browsing_data/browsing_data_quota_helper_impl.h"
6
7#include <map>
8#include <set>
9
10#include "base/bind.h"
11#include "base/logging.h"
12#include "chrome/browser/browsing_data/browsing_data_helper.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/common/url_constants.h"
15#include "content/public/browser/browser_context.h"
16#include "content/public/browser/browser_thread.h"
17#include "content/public/browser/storage_partition.h"
18#include "storage/browser/quota/quota_manager.h"
19
20using content::BrowserThread;
21using content::BrowserContext;
22
23// static
24BrowsingDataQuotaHelper* BrowsingDataQuotaHelper::Create(Profile* profile) {
25  return new BrowsingDataQuotaHelperImpl(
26      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI).get(),
27      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
28      BrowserContext::GetDefaultStoragePartition(profile)->GetQuotaManager());
29}
30
31void BrowsingDataQuotaHelperImpl::StartFetching(
32    const FetchResultCallback& callback) {
33  DCHECK(!callback.is_null());
34  DCHECK(callback_.is_null());
35  DCHECK(!is_fetching_);
36  callback_ = callback;
37  quota_info_.clear();
38  is_fetching_ = true;
39
40  FetchQuotaInfo();
41}
42
43void BrowsingDataQuotaHelperImpl::RevokeHostQuota(const std::string& host) {
44  if (!io_thread_->BelongsToCurrentThread()) {
45    io_thread_->PostTask(
46        FROM_HERE,
47        base::Bind(&BrowsingDataQuotaHelperImpl::RevokeHostQuota, this, host));
48    return;
49  }
50
51  quota_manager_->SetPersistentHostQuota(
52      host, 0,
53      base::Bind(&BrowsingDataQuotaHelperImpl::DidRevokeHostQuota,
54                 weak_factory_.GetWeakPtr()));
55}
56
57BrowsingDataQuotaHelperImpl::BrowsingDataQuotaHelperImpl(
58    base::MessageLoopProxy* ui_thread,
59    base::MessageLoopProxy* io_thread,
60    storage::QuotaManager* quota_manager)
61    : BrowsingDataQuotaHelper(io_thread),
62      quota_manager_(quota_manager),
63      is_fetching_(false),
64      ui_thread_(ui_thread),
65      io_thread_(io_thread),
66      weak_factory_(this) {
67  DCHECK(quota_manager);
68}
69
70BrowsingDataQuotaHelperImpl::~BrowsingDataQuotaHelperImpl() {}
71
72void BrowsingDataQuotaHelperImpl::FetchQuotaInfo() {
73  if (!io_thread_->BelongsToCurrentThread()) {
74    io_thread_->PostTask(
75        FROM_HERE,
76        base::Bind(&BrowsingDataQuotaHelperImpl::FetchQuotaInfo, this));
77    return;
78  }
79
80  quota_manager_->GetOriginsModifiedSince(
81      storage::kStorageTypeTemporary,
82      base::Time(),
83      base::Bind(&BrowsingDataQuotaHelperImpl::GotOrigins,
84                 weak_factory_.GetWeakPtr()));
85}
86
87void BrowsingDataQuotaHelperImpl::GotOrigins(const std::set<GURL>& origins,
88                                             storage::StorageType type) {
89  for (std::set<GURL>::const_iterator itr = origins.begin();
90       itr != origins.end();
91       ++itr)
92    if (BrowsingDataHelper::HasWebScheme(*itr))
93      pending_hosts_.insert(std::make_pair(itr->host(), type));
94
95  DCHECK(type == storage::kStorageTypeTemporary ||
96         type == storage::kStorageTypePersistent ||
97         type == storage::kStorageTypeSyncable);
98
99  // Calling GetOriginsModifiedSince() for all types by chaining callbacks.
100  if (type == storage::kStorageTypeTemporary) {
101    quota_manager_->GetOriginsModifiedSince(
102        storage::kStorageTypePersistent,
103        base::Time(),
104        base::Bind(&BrowsingDataQuotaHelperImpl::GotOrigins,
105                   weak_factory_.GetWeakPtr()));
106  } else if (type == storage::kStorageTypePersistent) {
107    quota_manager_->GetOriginsModifiedSince(
108        storage::kStorageTypeSyncable,
109        base::Time(),
110        base::Bind(&BrowsingDataQuotaHelperImpl::GotOrigins,
111                   weak_factory_.GetWeakPtr()));
112  } else {
113    DCHECK(type == storage::kStorageTypeSyncable);
114    ProcessPendingHosts();
115  }
116}
117
118void BrowsingDataQuotaHelperImpl::ProcessPendingHosts() {
119  if (pending_hosts_.empty()) {
120    OnComplete();
121    return;
122  }
123
124  PendingHosts::iterator itr = pending_hosts_.begin();
125  std::string host = itr->first;
126  storage::StorageType type = itr->second;
127  pending_hosts_.erase(itr);
128  GetHostUsage(host, type);
129}
130
131void BrowsingDataQuotaHelperImpl::GetHostUsage(const std::string& host,
132                                               storage::StorageType type) {
133  DCHECK(quota_manager_.get());
134  quota_manager_->GetHostUsage(
135      host, type,
136      base::Bind(&BrowsingDataQuotaHelperImpl::GotHostUsage,
137                 weak_factory_.GetWeakPtr(), host, type));
138}
139
140void BrowsingDataQuotaHelperImpl::GotHostUsage(const std::string& host,
141                                               storage::StorageType type,
142                                               int64 usage) {
143  switch (type) {
144    case storage::kStorageTypeTemporary:
145      quota_info_[host].temporary_usage = usage;
146      break;
147    case storage::kStorageTypePersistent:
148      quota_info_[host].persistent_usage = usage;
149      break;
150    case storage::kStorageTypeSyncable:
151      quota_info_[host].syncable_usage = usage;
152      break;
153    default:
154      NOTREACHED();
155  }
156  ProcessPendingHosts();
157}
158
159void BrowsingDataQuotaHelperImpl::OnComplete() {
160  if (!ui_thread_->BelongsToCurrentThread()) {
161    ui_thread_->PostTask(
162        FROM_HERE,
163        base::Bind(&BrowsingDataQuotaHelperImpl::OnComplete, this));
164    return;
165  }
166
167  is_fetching_ = false;
168
169  QuotaInfoArray result;
170
171  for (std::map<std::string, QuotaInfo>::iterator itr = quota_info_.begin();
172       itr != quota_info_.end();
173       ++itr) {
174    QuotaInfo* info = &itr->second;
175    // Skip unused entries
176    if (info->temporary_usage <= 0 &&
177        info->persistent_usage <= 0 &&
178        info->syncable_usage <= 0)
179      continue;
180
181    info->host = itr->first;
182    result.push_back(*info);
183  }
184
185  callback_.Run(result);
186  callback_.Reset();
187}
188
189void BrowsingDataQuotaHelperImpl::DidRevokeHostQuota(
190    storage::QuotaStatusCode status_unused,
191    int64 quota_unused) {
192}
193