• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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_indexed_db_helper.h"
6 
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
16 #include "content/browser/browser_thread.h"
17 #include "content/browser/in_process_webkit/webkit_context.h"
18 #include "webkit/glue/webkit_glue.h"
19 
20 using WebKit::WebSecurityOrigin;
21 
22 namespace {
23 
24 class BrowsingDataIndexedDBHelperImpl : public BrowsingDataIndexedDBHelper {
25  public:
26   explicit BrowsingDataIndexedDBHelperImpl(Profile* profile);
27 
28   virtual void StartFetching(
29       Callback1<const std::vector<IndexedDBInfo>& >::Type* callback);
30   virtual void CancelNotification();
31   virtual void DeleteIndexedDBFile(const FilePath& file_path);
32 
33  private:
34   virtual ~BrowsingDataIndexedDBHelperImpl();
35 
36   // Enumerates all indexed database files in the WEBKIT thread.
37   void FetchIndexedDBInfoInWebKitThread();
38   // Notifies the completion callback in the UI thread.
39   void NotifyInUIThread();
40   // Delete a single indexed database file in the WEBKIT thread.
41   void DeleteIndexedDBFileInWebKitThread(const FilePath& file_path);
42 
43   Profile* profile_;
44 
45   // This only mutates in the WEBKIT thread.
46   std::vector<IndexedDBInfo> indexed_db_info_;
47 
48   // This only mutates on the UI thread.
49   scoped_ptr<Callback1<const std::vector<IndexedDBInfo>& >::Type >
50       completion_callback_;
51   // Indicates whether or not we're currently fetching information:
52   // it's true when StartFetching() is called in the UI thread, and it's reset
53   // after we notified the callback in the UI thread.
54   // This only mutates on the UI thread.
55   bool is_fetching_;
56 
57   DISALLOW_COPY_AND_ASSIGN(BrowsingDataIndexedDBHelperImpl);
58 };
59 
BrowsingDataIndexedDBHelperImpl(Profile * profile)60 BrowsingDataIndexedDBHelperImpl::BrowsingDataIndexedDBHelperImpl(
61     Profile* profile)
62     : profile_(profile),
63       completion_callback_(NULL),
64       is_fetching_(false) {
65   DCHECK(profile_);
66 }
67 
~BrowsingDataIndexedDBHelperImpl()68 BrowsingDataIndexedDBHelperImpl::~BrowsingDataIndexedDBHelperImpl() {
69 }
70 
StartFetching(Callback1<const std::vector<IndexedDBInfo> &>::Type * callback)71 void BrowsingDataIndexedDBHelperImpl::StartFetching(
72     Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) {
73   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74   DCHECK(!is_fetching_);
75   DCHECK(callback);
76   is_fetching_ = true;
77   completion_callback_.reset(callback);
78   BrowserThread::PostTask(
79       BrowserThread::WEBKIT, FROM_HERE,
80       NewRunnableMethod(
81           this,
82           &BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread));
83 }
84 
CancelNotification()85 void BrowsingDataIndexedDBHelperImpl::CancelNotification() {
86   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87   completion_callback_.reset(NULL);
88 }
89 
DeleteIndexedDBFile(const FilePath & file_path)90 void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBFile(
91     const FilePath& file_path) {
92   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93   BrowserThread::PostTask(
94       BrowserThread::WEBKIT, FROM_HERE,
95        NewRunnableMethod(
96            this,
97            &BrowsingDataIndexedDBHelperImpl::
98               DeleteIndexedDBFileInWebKitThread,
99            file_path));
100 }
101 
FetchIndexedDBInfoInWebKitThread()102 void BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread() {
103   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
104   file_util::FileEnumerator file_enumerator(
105       profile_->GetWebKitContext()->data_path().Append(
106           IndexedDBContext::kIndexedDBDirectory),
107       false, file_util::FileEnumerator::FILES);
108   for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
109        file_path = file_enumerator.Next()) {
110     if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) {
111       WebSecurityOrigin web_security_origin =
112           WebSecurityOrigin::createFromDatabaseIdentifier(
113               webkit_glue::FilePathToWebString(file_path.BaseName()));
114       if (EqualsASCII(web_security_origin.protocol(),
115                       chrome::kExtensionScheme)) {
116         // Extension state is not considered browsing data.
117         continue;
118       }
119       base::PlatformFileInfo file_info;
120       bool ret = file_util::GetFileInfo(file_path, &file_info);
121       if (ret) {
122         indexed_db_info_.push_back(IndexedDBInfo(
123             web_security_origin.protocol().utf8(),
124             web_security_origin.host().utf8(),
125             web_security_origin.port(),
126             web_security_origin.databaseIdentifier().utf8(),
127             web_security_origin.toString().utf8(),
128             file_path,
129             file_info.size,
130             file_info.last_modified));
131       }
132     }
133   }
134 
135   BrowserThread::PostTask(
136       BrowserThread::UI, FROM_HERE,
137       NewRunnableMethod(
138           this, &BrowsingDataIndexedDBHelperImpl::NotifyInUIThread));
139 }
140 
NotifyInUIThread()141 void BrowsingDataIndexedDBHelperImpl::NotifyInUIThread() {
142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143   DCHECK(is_fetching_);
144   // Note: completion_callback_ mutates only in the UI thread, so it's safe to
145   // test it here.
146   if (completion_callback_ != NULL) {
147     completion_callback_->Run(indexed_db_info_);
148     completion_callback_.reset();
149   }
150   is_fetching_ = false;
151 }
152 
DeleteIndexedDBFileInWebKitThread(const FilePath & file_path)153 void BrowsingDataIndexedDBHelperImpl::DeleteIndexedDBFileInWebKitThread(
154     const FilePath& file_path) {
155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
156   // TODO(jochen): implement this once it's possible to delete indexed DBs.
157 }
158 
159 }  // namespace
160 
IndexedDBInfo(const std::string & protocol,const std::string & host,unsigned short port,const std::string & database_identifier,const std::string & origin,const FilePath & file_path,int64 size,base::Time last_modified)161 BrowsingDataIndexedDBHelper::IndexedDBInfo::IndexedDBInfo(
162     const std::string& protocol,
163     const std::string& host,
164     unsigned short port,
165     const std::string& database_identifier,
166     const std::string& origin,
167     const FilePath& file_path,
168     int64 size,
169     base::Time last_modified)
170     : protocol(protocol),
171       host(host),
172       port(port),
173       database_identifier(database_identifier),
174       origin(origin),
175       file_path(file_path),
176       size(size),
177       last_modified(last_modified) {
178 }
179 
~IndexedDBInfo()180 BrowsingDataIndexedDBHelper::IndexedDBInfo::~IndexedDBInfo() {}
181 
182 // static
Create(Profile * profile)183 BrowsingDataIndexedDBHelper* BrowsingDataIndexedDBHelper::Create(
184     Profile* profile) {
185   return new BrowsingDataIndexedDBHelperImpl(profile);
186 }
187 
188 CannedBrowsingDataIndexedDBHelper::
PendingIndexedDBInfo()189 PendingIndexedDBInfo::PendingIndexedDBInfo() {
190 }
191 
192 CannedBrowsingDataIndexedDBHelper::
PendingIndexedDBInfo(const GURL & origin,const string16 & description)193 PendingIndexedDBInfo::PendingIndexedDBInfo(const GURL& origin,
194                                            const string16& description)
195     : origin(origin),
196       description(description) {
197 }
198 
199 CannedBrowsingDataIndexedDBHelper::
~PendingIndexedDBInfo()200 PendingIndexedDBInfo::~PendingIndexedDBInfo() {
201 }
202 
CannedBrowsingDataIndexedDBHelper(Profile * profile)203 CannedBrowsingDataIndexedDBHelper::CannedBrowsingDataIndexedDBHelper(
204     Profile* profile)
205     : profile_(profile),
206       completion_callback_(NULL),
207       is_fetching_(false) {
208   DCHECK(profile);
209 }
210 
Clone()211 CannedBrowsingDataIndexedDBHelper* CannedBrowsingDataIndexedDBHelper::Clone() {
212   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213   CannedBrowsingDataIndexedDBHelper* clone =
214       new CannedBrowsingDataIndexedDBHelper(profile_);
215 
216   base::AutoLock auto_lock(lock_);
217   clone->pending_indexed_db_info_ = pending_indexed_db_info_;
218   clone->indexed_db_info_ = indexed_db_info_;
219   return clone;
220 }
221 
AddIndexedDB(const GURL & origin,const string16 & description)222 void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(
223     const GURL& origin, const string16& description) {
224   base::AutoLock auto_lock(lock_);
225   pending_indexed_db_info_.push_back(PendingIndexedDBInfo(origin, description));
226 }
227 
Reset()228 void CannedBrowsingDataIndexedDBHelper::Reset() {
229   base::AutoLock auto_lock(lock_);
230   indexed_db_info_.clear();
231   pending_indexed_db_info_.clear();
232 }
233 
empty() const234 bool CannedBrowsingDataIndexedDBHelper::empty() const {
235   base::AutoLock auto_lock(lock_);
236   return indexed_db_info_.empty() && pending_indexed_db_info_.empty();
237 }
238 
StartFetching(Callback1<const std::vector<IndexedDBInfo> &>::Type * callback)239 void CannedBrowsingDataIndexedDBHelper::StartFetching(
240     Callback1<const std::vector<IndexedDBInfo>& >::Type* callback) {
241   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
242   DCHECK(!is_fetching_);
243   DCHECK(callback);
244   is_fetching_ = true;
245   completion_callback_.reset(callback);
246   BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
247       this,
248       &CannedBrowsingDataIndexedDBHelper::ConvertPendingInfoInWebKitThread));
249 }
250 
~CannedBrowsingDataIndexedDBHelper()251 CannedBrowsingDataIndexedDBHelper::~CannedBrowsingDataIndexedDBHelper() {}
252 
ConvertPendingInfoInWebKitThread()253 void CannedBrowsingDataIndexedDBHelper::ConvertPendingInfoInWebKitThread() {
254   base::AutoLock auto_lock(lock_);
255   for (std::vector<PendingIndexedDBInfo>::const_iterator
256        info = pending_indexed_db_info_.begin();
257        info != pending_indexed_db_info_.end(); ++info) {
258     WebSecurityOrigin web_security_origin =
259         WebSecurityOrigin::createFromString(
260             UTF8ToUTF16(info->origin.spec()));
261     std::string security_origin(web_security_origin.toString().utf8());
262 
263     bool duplicate = false;
264     for (std::vector<IndexedDBInfo>::iterator
265          indexed_db = indexed_db_info_.begin();
266          indexed_db != indexed_db_info_.end(); ++indexed_db) {
267       if (indexed_db->origin == security_origin) {
268         duplicate = true;
269         break;
270       }
271     }
272     if (duplicate)
273       continue;
274 
275     indexed_db_info_.push_back(IndexedDBInfo(
276         web_security_origin.protocol().utf8(),
277         web_security_origin.host().utf8(),
278         web_security_origin.port(),
279         web_security_origin.databaseIdentifier().utf8(),
280         security_origin,
281         profile_->GetWebKitContext()->indexed_db_context()->
282             GetIndexedDBFilePath(web_security_origin.databaseIdentifier()),
283         0,
284         base::Time()));
285   }
286   pending_indexed_db_info_.clear();
287 
288   BrowserThread::PostTask(
289       BrowserThread::UI, FROM_HERE,
290       NewRunnableMethod(
291           this, &CannedBrowsingDataIndexedDBHelper::NotifyInUIThread));
292 }
293 
NotifyInUIThread()294 void CannedBrowsingDataIndexedDBHelper::NotifyInUIThread() {
295   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
296   DCHECK(is_fetching_);
297   // Note: completion_callback_ mutates only in the UI thread, so it's safe to
298   // test it here.
299   if (completion_callback_ != NULL) {
300     completion_callback_->Run(indexed_db_info_);
301     completion_callback_.reset();
302   }
303   is_fetching_ = false;
304 }
305