OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/in_process_webkit/indexed_db_context.h" | 5 #include "content/browser/in_process_webkit/indexed_db_context.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/task.h" |
11 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
12 #include "content/browser/browser_thread.h" | 13 #include "content/browser/browser_thread.h" |
13 #include "content/browser/in_process_webkit/indexed_db_quota_client.h" | 14 #include "content/browser/in_process_webkit/indexed_db_quota_client.h" |
14 #include "content/browser/in_process_webkit/webkit_context.h" | 15 #include "content/browser/in_process_webkit/webkit_context.h" |
15 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h" | 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h" |
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h" | 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h" |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h" | 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h" |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" | 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" |
| 22 #include "webkit/database/database_util.h" |
21 #include "webkit/glue/webkit_glue.h" | 23 #include "webkit/glue/webkit_glue.h" |
22 #include "webkit/quota/quota_manager.h" | 24 #include "webkit/quota/quota_manager.h" |
23 #include "webkit/quota/special_storage_policy.h" | 25 #include "webkit/quota/special_storage_policy.h" |
24 | 26 |
| 27 using webkit_database::DatabaseUtil; |
25 using WebKit::WebIDBDatabase; | 28 using WebKit::WebIDBDatabase; |
26 using WebKit::WebIDBFactory; | 29 using WebKit::WebIDBFactory; |
27 using WebKit::WebSecurityOrigin; | 30 using WebKit::WebSecurityOrigin; |
28 | 31 |
29 namespace { | 32 namespace { |
30 | 33 |
31 void ClearLocalState( | 34 void ClearLocalState( |
32 const FilePath& indexeddb_path, | 35 const FilePath& indexeddb_path, |
33 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) { | 36 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) { |
34 file_util::FileEnumerator file_enumerator( | 37 file_util::FileEnumerator file_enumerator( |
(...skipping 14 matching lines...) Expand all Loading... |
49 } | 52 } |
50 | 53 |
51 } // namespace | 54 } // namespace |
52 | 55 |
53 const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] = | 56 const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] = |
54 FILE_PATH_LITERAL("IndexedDB"); | 57 FILE_PATH_LITERAL("IndexedDB"); |
55 | 58 |
56 const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] = | 59 const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] = |
57 FILE_PATH_LITERAL(".leveldb"); | 60 FILE_PATH_LITERAL(".leveldb"); |
58 | 61 |
| 62 class IndexedDBContext::IndexedDBGetUsageAndQuotaCallback : |
| 63 public quota::QuotaManager::GetUsageAndQuotaCallback { |
| 64 public: |
| 65 IndexedDBGetUsageAndQuotaCallback(IndexedDBContext* context, |
| 66 const GURL& origin_url) |
| 67 : context_(context), |
| 68 origin_url_(origin_url) { |
| 69 } |
| 70 |
| 71 void Run(quota::QuotaStatusCode status, int64 usage, int64 quota) { |
| 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 73 DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort) |
| 74 << "status was " << status; |
| 75 if (status == quota::kQuotaErrorAbort) { |
| 76 // We seem to no longer care to wait around for the answer. |
| 77 return; |
| 78 } |
| 79 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, |
| 80 NewRunnableMethod(context_.get(), |
| 81 &IndexedDBContext::GotUpdatedQuota, |
| 82 origin_url_, |
| 83 usage, |
| 84 quota)); |
| 85 } |
| 86 |
| 87 virtual void RunWithParams( |
| 88 const Tuple3<quota::QuotaStatusCode, int64, int64>& params) { |
| 89 Run(params.a, params.b, params.c); |
| 90 } |
| 91 |
| 92 private: |
| 93 scoped_refptr<IndexedDBContext> context_; |
| 94 const GURL origin_url_; |
| 95 }; |
| 96 |
59 IndexedDBContext::IndexedDBContext( | 97 IndexedDBContext::IndexedDBContext( |
60 WebKitContext* webkit_context, | 98 WebKitContext* webkit_context, |
61 quota::SpecialStoragePolicy* special_storage_policy, | 99 quota::SpecialStoragePolicy* special_storage_policy, |
62 quota::QuotaManagerProxy* quota_manager_proxy, | 100 quota::QuotaManagerProxy* quota_manager_proxy, |
63 base::MessageLoopProxy* webkit_thread_loop) | 101 base::MessageLoopProxy* webkit_thread_loop) |
64 : clear_local_state_on_exit_(false), | 102 : clear_local_state_on_exit_(false), |
65 special_storage_policy_(special_storage_policy), | 103 special_storage_policy_(special_storage_policy), |
66 quota_manager_proxy_(quota_manager_proxy) { | 104 quota_manager_proxy_(quota_manager_proxy) { |
67 data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory); | 105 data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory); |
68 if (quota_manager_proxy) { | 106 if (quota_manager_proxy) { |
(...skipping 24 matching lines...) Expand all Loading... |
93 } | 131 } |
94 | 132 |
95 FilePath IndexedDBContext::GetIndexedDBFilePath( | 133 FilePath IndexedDBContext::GetIndexedDBFilePath( |
96 const string16& origin_id) const { | 134 const string16& origin_id) const { |
97 FilePath::StringType id = | 135 FilePath::StringType id = |
98 webkit_glue::WebStringToFilePathString(origin_id).append( | 136 webkit_glue::WebStringToFilePathString(origin_id).append( |
99 FILE_PATH_LITERAL(".indexeddb")); | 137 FILE_PATH_LITERAL(".indexeddb")); |
100 return data_path_.Append(id.append(kIndexedDBExtension)); | 138 return data_path_.Append(id.append(kIndexedDBExtension)); |
101 } | 139 } |
102 | 140 |
103 void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) { | 141 // Note: This is not called in response to a UI action in Content Settings. Only |
| 142 // extension data deleter and quota manager currently call this. |
| 143 void IndexedDBContext::DeleteIndexedDBForOrigin(const GURL& origin_url) { |
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
105 // TODO(pastarmovj): Close all database connections that use that file. | 145 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); |
106 file_util::Delete(file_path, false); | 146 FilePath idb_directory = GetIndexedDBFilePath(origin_id); |
107 } | 147 if (idb_directory.BaseName().value().substr(0, strlen("chrome-extension")) == |
108 | 148 FILE_PATH_LITERAL("chrome-extension") || |
109 void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) { | 149 connection_count_.find(origin_url) == connection_count_.end()) { |
110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 150 EnsureDiskUsageCacheInitialized(origin_url); |
111 // TODO(pastarmovj): Remove this check once we are safe to delete any time. | 151 file_util::Delete(idb_directory, true /*recursive*/); |
112 FilePath idb_file = GetIndexedDBFilePath(origin_id); | 152 QueryDiskAndUpdateQuotaUsage(origin_url); |
113 DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")), | 153 } |
114 FILE_PATH_LITERAL("chrome-extension")); | |
115 DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id)); | |
116 } | 154 } |
117 | 155 |
118 bool IndexedDBContext::IsUnlimitedStorageGranted( | 156 bool IndexedDBContext::IsUnlimitedStorageGranted( |
119 const GURL& origin) const { | 157 const GURL& origin) const { |
120 return special_storage_policy_->IsStorageUnlimited(origin); | 158 return special_storage_policy_->IsStorageUnlimited(origin); |
121 } | 159 } |
122 | 160 |
123 // TODO(dgrogan): Merge this code with the similar loop in | 161 // TODO(dgrogan): Merge this code with the similar loop in |
124 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread. | 162 // BrowsingDataIndexedDBHelperImpl::FetchIndexedDBInfoInWebKitThread. |
125 void IndexedDBContext::GetAllOriginIdentifiers( | 163 void IndexedDBContext::GetAllOriginIdentifiers( |
126 std::vector<string16>* origin_ids) { | 164 std::vector<string16>* origin_ids) { |
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
128 file_util::FileEnumerator file_enumerator(data_path_, | 166 file_util::FileEnumerator file_enumerator(data_path_, |
129 false, file_util::FileEnumerator::DIRECTORIES); | 167 false, file_util::FileEnumerator::DIRECTORIES); |
130 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); | 168 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); |
131 file_path = file_enumerator.Next()) { | 169 file_path = file_enumerator.Next()) { |
132 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) { | 170 if (file_path.Extension() == IndexedDBContext::kIndexedDBExtension) { |
133 WebKit::WebString origin_id_webstring = | 171 WebKit::WebString origin_id_webstring = |
134 webkit_glue::FilePathToWebString(file_path.BaseName()); | 172 webkit_glue::FilePathToWebString(file_path.BaseName()); |
135 origin_ids->push_back(origin_id_webstring); | 173 origin_ids->push_back(origin_id_webstring); |
136 } | 174 } |
137 } | 175 } |
138 } | 176 } |
139 | 177 |
| 178 int64 IndexedDBContext::GetOriginDiskUsage(const GURL& origin_url) { |
| 179 return ResetDiskUsageCache(origin_url); |
| 180 } |
| 181 |
| 182 void IndexedDBContext::ConnectionOpened(const GURL& origin_url) { |
| 183 if (quota_manager_proxy()) { |
| 184 quota_manager_proxy()->NotifyStorageAccessed( |
| 185 quota::QuotaClient::kIndexedDatabase, origin_url, |
| 186 quota::kStorageTypeTemporary); |
| 187 } |
| 188 connection_count_[origin_url]++; |
| 189 QueryAvailableQuota(origin_url); |
| 190 EnsureDiskUsageCacheInitialized(origin_url); |
| 191 } |
| 192 |
| 193 void IndexedDBContext::ConnectionClosed(const GURL& origin_url) { |
| 194 DCHECK(connection_count_[origin_url] > 0); |
| 195 if (quota_manager_proxy()) { |
| 196 quota_manager_proxy()->NotifyStorageAccessed( |
| 197 quota::QuotaClient::kIndexedDatabase, origin_url, |
| 198 quota::kStorageTypeTemporary); |
| 199 } |
| 200 connection_count_[origin_url]--; |
| 201 if (connection_count_[origin_url] == 0) { |
| 202 QueryDiskAndUpdateQuotaUsage(origin_url); |
| 203 connection_count_.erase(origin_url); |
| 204 } |
| 205 } |
| 206 |
| 207 void IndexedDBContext::TransactionComplete(const GURL& origin_url) { |
| 208 DCHECK(connection_count_[origin_url] > 0); |
| 209 QueryDiskAndUpdateQuotaUsage(origin_url); |
| 210 QueryAvailableQuota(origin_url); |
| 211 } |
| 212 |
| 213 bool IndexedDBContext::WouldBeOverQuota(const GURL& origin_url, |
| 214 int64 additional_bytes) { |
| 215 if (space_available_map_.find(origin_url) == space_available_map_.end()) { |
| 216 // We haven't heard back from the QuotaManager yet, just let it through. |
| 217 return false; |
| 218 } |
| 219 bool over_quota = additional_bytes > space_available_map_[origin_url]; |
| 220 return over_quota; |
| 221 } |
| 222 |
| 223 bool IndexedDBContext::IsOverQuota(const GURL& origin_url) { |
| 224 const int kOneAdditionalByte = 1; |
| 225 return WouldBeOverQuota(origin_url, kOneAdditionalByte); |
| 226 } |
| 227 |
140 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { | 228 quota::QuotaManagerProxy* IndexedDBContext::quota_manager_proxy() { |
141 return quota_manager_proxy_; | 229 return quota_manager_proxy_; |
142 } | 230 } |
| 231 |
| 232 int64 IndexedDBContext::ReadUsageFromDisk(const GURL& origin_url) const { |
| 233 string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url); |
| 234 FilePath file_path = GetIndexedDBFilePath(origin_id); |
| 235 return file_util::ComputeDirectorySize(file_path); |
| 236 } |
| 237 |
| 238 void IndexedDBContext::EnsureDiskUsageCacheInitialized(const GURL& origin_url) { |
| 239 if (origin_size_map_.find(origin_url) == origin_size_map_.end()) |
| 240 ResetDiskUsageCache(origin_url); |
| 241 } |
| 242 |
| 243 void IndexedDBContext::QueryDiskAndUpdateQuotaUsage(const GURL& origin_url) { |
| 244 int64 former_disk_usage = origin_size_map_[origin_url]; |
| 245 int64 current_disk_usage = ReadUsageFromDisk(origin_url); |
| 246 int64 difference = current_disk_usage - former_disk_usage; |
| 247 if (difference) { |
| 248 origin_size_map_[origin_url] = current_disk_usage; |
| 249 // quota_manager_proxy() is NULL in unit tests. |
| 250 if (quota_manager_proxy()) |
| 251 quota_manager_proxy()->NotifyStorageModified( |
| 252 quota::QuotaClient::kIndexedDatabase, |
| 253 origin_url, |
| 254 quota::kStorageTypeTemporary, |
| 255 difference); |
| 256 } |
| 257 } |
| 258 |
| 259 void IndexedDBContext::GotUpdatedQuota(const GURL& origin_url, int64 usage, |
| 260 int64 quota) { |
| 261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
| 262 space_available_map_[origin_url] = quota - usage; |
| 263 } |
| 264 |
| 265 void IndexedDBContext::QueryAvailableQuota(const GURL& origin_url) { |
| 266 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); |
| 268 if (quota_manager_proxy()) |
| 269 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 270 NewRunnableMethod(this, &IndexedDBContext::QueryAvailableQuota, |
| 271 origin_url)); |
| 272 return; |
| 273 } |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 275 if (!quota_manager_proxy()->quota_manager()) |
| 276 return; |
| 277 IndexedDBGetUsageAndQuotaCallback* callback = |
| 278 new IndexedDBGetUsageAndQuotaCallback(this, origin_url); |
| 279 quota_manager_proxy()->quota_manager()->GetUsageAndQuota( |
| 280 origin_url, |
| 281 quota::kStorageTypeTemporary, |
| 282 callback); |
| 283 } |
| 284 |
| 285 int64 IndexedDBContext::ResetDiskUsageCache(const GURL& origin_url) { |
| 286 origin_size_map_[origin_url] = ReadUsageFromDisk(origin_url); |
| 287 return origin_size_map_[origin_url]; |
| 288 } |
OLD | NEW |