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_local_storage_helper.h"
6
7#include "base/file_util.h"
8#include "base/message_loop.h"
9#include "base/string_util.h"
10#include "base/utf_string_conversions.h"
11#include "chrome/browser/profiles/profile.h"
12#include "content/browser/browser_thread.h"
13#include "content/browser/in_process_webkit/webkit_context.h"
14#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
15#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
16#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
17#include "webkit/glue/webkit_glue.h"
18
19using WebKit::WebSecurityOrigin;
20
21BrowsingDataLocalStorageHelper::LocalStorageInfo::LocalStorageInfo()
22    : port(0),
23      size(0) {
24}
25
26BrowsingDataLocalStorageHelper::LocalStorageInfo::LocalStorageInfo(
27    const std::string& protocol,
28    const std::string& host,
29    unsigned short port,
30    const std::string& database_identifier,
31    const std::string& origin,
32    const FilePath& file_path,
33    int64 size,
34    base::Time last_modified)
35    : protocol(protocol),
36      host(host),
37      port(port),
38      database_identifier(database_identifier),
39      origin(origin),
40      file_path(file_path),
41      size(size),
42      last_modified(last_modified) {
43      }
44
45BrowsingDataLocalStorageHelper::LocalStorageInfo::~LocalStorageInfo() {}
46
47BrowsingDataLocalStorageHelper::BrowsingDataLocalStorageHelper(
48    Profile* profile)
49    : profile_(profile),
50      completion_callback_(NULL),
51      is_fetching_(false) {
52  DCHECK(profile_);
53}
54
55BrowsingDataLocalStorageHelper::~BrowsingDataLocalStorageHelper() {
56}
57
58void BrowsingDataLocalStorageHelper::StartFetching(
59    Callback1<const std::vector<LocalStorageInfo>& >::Type* callback) {
60  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
61  DCHECK(!is_fetching_);
62  DCHECK(callback);
63  is_fetching_ = true;
64  completion_callback_.reset(callback);
65  BrowserThread::PostTask(
66      BrowserThread::WEBKIT, FROM_HERE,
67      NewRunnableMethod(
68          this,
69          &BrowsingDataLocalStorageHelper::
70              FetchLocalStorageInfoInWebKitThread));
71}
72
73void BrowsingDataLocalStorageHelper::CancelNotification() {
74  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
75  completion_callback_.reset(NULL);
76}
77
78void BrowsingDataLocalStorageHelper::DeleteLocalStorageFile(
79    const FilePath& file_path) {
80  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81  BrowserThread::PostTask(
82      BrowserThread::WEBKIT, FROM_HERE,
83       NewRunnableMethod(
84           this,
85           &BrowsingDataLocalStorageHelper::
86              DeleteLocalStorageFileInWebKitThread,
87           file_path));
88}
89
90void BrowsingDataLocalStorageHelper::FetchLocalStorageInfoInWebKitThread() {
91  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
92  file_util::FileEnumerator file_enumerator(
93      profile_->GetWebKitContext()->data_path().Append(
94          DOMStorageContext::kLocalStorageDirectory),
95      false, file_util::FileEnumerator::FILES);
96  for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
97       file_path = file_enumerator.Next()) {
98    if (file_path.Extension() == DOMStorageContext::kLocalStorageExtension) {
99      WebSecurityOrigin web_security_origin =
100          WebSecurityOrigin::createFromDatabaseIdentifier(
101              webkit_glue::FilePathToWebString(file_path.BaseName()));
102      if (EqualsASCII(web_security_origin.protocol(),
103                      chrome::kExtensionScheme)) {
104        // Extension state is not considered browsing data.
105        continue;
106      }
107      base::PlatformFileInfo file_info;
108      bool ret = file_util::GetFileInfo(file_path, &file_info);
109      if (ret) {
110        local_storage_info_.push_back(LocalStorageInfo(
111            web_security_origin.protocol().utf8(),
112            web_security_origin.host().utf8(),
113            web_security_origin.port(),
114            web_security_origin.databaseIdentifier().utf8(),
115            web_security_origin.toString().utf8(),
116            file_path,
117            file_info.size,
118            file_info.last_modified));
119      }
120    }
121  }
122
123  BrowserThread::PostTask(
124      BrowserThread::UI, FROM_HERE,
125      NewRunnableMethod(
126          this, &BrowsingDataLocalStorageHelper::NotifyInUIThread));
127}
128
129void BrowsingDataLocalStorageHelper::NotifyInUIThread() {
130  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
131  DCHECK(is_fetching_);
132  // Note: completion_callback_ mutates only in the UI thread, so it's safe to
133  // test it here.
134  if (completion_callback_ != NULL) {
135    completion_callback_->Run(local_storage_info_);
136    completion_callback_.reset();
137  }
138  is_fetching_ = false;
139}
140
141void BrowsingDataLocalStorageHelper::DeleteLocalStorageFileInWebKitThread(
142    const FilePath& file_path) {
143  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
144  profile_->GetWebKitContext()->dom_storage_context()->DeleteLocalStorageFile(
145      file_path);
146}
147
148CannedBrowsingDataLocalStorageHelper::CannedBrowsingDataLocalStorageHelper(
149    Profile* profile)
150    : BrowsingDataLocalStorageHelper(profile),
151      profile_(profile) {
152}
153
154CannedBrowsingDataLocalStorageHelper*
155CannedBrowsingDataLocalStorageHelper::Clone() {
156  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157  CannedBrowsingDataLocalStorageHelper* clone =
158      new CannedBrowsingDataLocalStorageHelper(profile_);
159
160  base::AutoLock auto_lock(lock_);
161  clone->pending_local_storage_info_ = pending_local_storage_info_;
162  clone->local_storage_info_ = local_storage_info_;
163  return clone;
164}
165
166void CannedBrowsingDataLocalStorageHelper::AddLocalStorage(
167    const GURL& origin) {
168  base::AutoLock auto_lock(lock_);
169  pending_local_storage_info_.push_back(origin);
170}
171
172void CannedBrowsingDataLocalStorageHelper::Reset() {
173  base::AutoLock auto_lock(lock_);
174  local_storage_info_.clear();
175  pending_local_storage_info_.clear();
176}
177
178bool CannedBrowsingDataLocalStorageHelper::empty() const {
179  base::AutoLock auto_lock(lock_);
180  return local_storage_info_.empty() && pending_local_storage_info_.empty();
181}
182
183void CannedBrowsingDataLocalStorageHelper::StartFetching(
184    Callback1<const std::vector<LocalStorageInfo>& >::Type* callback) {
185  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186  DCHECK(!is_fetching_);
187  DCHECK(callback);
188  is_fetching_ = true;
189  completion_callback_.reset(callback);
190  BrowserThread::PostTask(
191      BrowserThread::WEBKIT, FROM_HERE,
192      NewRunnableMethod(
193          this,
194          &CannedBrowsingDataLocalStorageHelper::
195              ConvertPendingInfoInWebKitThread));
196}
197
198CannedBrowsingDataLocalStorageHelper::~CannedBrowsingDataLocalStorageHelper() {}
199
200void CannedBrowsingDataLocalStorageHelper::ConvertPendingInfoInWebKitThread() {
201  base::AutoLock auto_lock(lock_);
202  for (std::vector<GURL>::iterator info = pending_local_storage_info_.begin();
203       info != pending_local_storage_info_.end(); ++info) {
204    WebSecurityOrigin web_security_origin =
205        WebSecurityOrigin::createFromString(
206            UTF8ToUTF16(info->spec()));
207    std::string security_origin(web_security_origin.toString().utf8());
208
209    bool duplicate = false;
210    for (std::vector<LocalStorageInfo>::iterator
211         local_storage = local_storage_info_.begin();
212         local_storage != local_storage_info_.end(); ++local_storage) {
213      if (local_storage->origin == security_origin) {
214        duplicate = true;
215        break;
216      }
217    }
218    if (duplicate)
219      continue;
220
221    local_storage_info_.push_back(LocalStorageInfo(
222        web_security_origin.protocol().utf8(),
223        web_security_origin.host().utf8(),
224        web_security_origin.port(),
225        web_security_origin.databaseIdentifier().utf8(),
226        security_origin,
227        profile_->GetWebKitContext()->dom_storage_context()->
228            GetLocalStorageFilePath(web_security_origin.databaseIdentifier()),
229        0,
230        base::Time()));
231  }
232  pending_local_storage_info_.clear();
233
234  BrowserThread::PostTask(
235      BrowserThread::UI, FROM_HERE,
236      NewRunnableMethod(
237          this, &CannedBrowsingDataLocalStorageHelper::NotifyInUIThread));
238}
239