Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/dom_storage_context.h" | 5 #include "webkit/dom_storage/dom_storage_context.h" |
| 6 | |
| 7 #include <algorithm> | |
| 8 | 6 |
| 9 #include "base/bind.h" | 7 #include "base/bind.h" |
| 10 #include "base/file_path.h" | 8 #include "base/bind_helpers.h" |
| 11 #include "base/file_util.h" | 9 #include "base/time.h" |
| 12 #include "base/string_util.h" | 10 //#include "webkit/dom_storage/dom_storage_area.h" |
| 13 #include "content/browser/in_process_webkit/dom_storage_area.h" | 11 #include "webkit/dom_storage/dom_storage_namespace.h" |
| 14 #include "content/browser/in_process_webkit/dom_storage_namespace.h" | 12 #include "webkit/dom_storage/dom_storage_task_runner.h" |
| 15 #include "content/browser/in_process_webkit/webkit_context.h" | |
| 16 #include "content/common/dom_storage_common.h" | |
| 17 #include "content/public/browser/browser_thread.h" | |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" | |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | |
| 20 #include "webkit/glue/webkit_glue.h" | |
| 21 #include "webkit/quota/special_storage_policy.h" | 13 #include "webkit/quota/special_storage_policy.h" |
| 22 | 14 |
| 23 using content::BrowserThread; | 15 namespace dom_storage { |
| 24 | 16 |
| 25 using WebKit::WebSecurityOrigin; | 17 DomStorageContext::DomStorageContext( |
| 26 | 18 const FilePath& directory, |
| 27 namespace { | 19 quota::SpecialStoragePolicy* special_storage_policy, |
| 28 | 20 DomStorageTaskRunner* task_runner) |
| 29 void ClearLocalState(const FilePath& domstorage_path, | 21 : directory_(directory), |
| 30 quota::SpecialStoragePolicy* special_storage_policy, | 22 task_runner_(task_runner) { |
| 31 bool clear_all_databases) { | 23 // AtomicSequenceNum starts at 0 but we want to start at one. |
|
benm (inactive)
2012/02/02 16:23:19
... because of the local storage special id? Maybe
michaeln
2012/02/03 00:33:42
Done.
| |
| 32 file_util::FileEnumerator file_enumerator( | 24 session_id_sequence_.GetNext(); |
| 33 domstorage_path, false, file_util::FileEnumerator::FILES); | |
| 34 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); | |
| 35 file_path = file_enumerator.Next()) { | |
| 36 if (file_path.Extension() == DOMStorageContext::kLocalStorageExtension) { | |
| 37 GURL origin(WebSecurityOrigin::createFromDatabaseIdentifier( | |
| 38 webkit_glue::FilePathToWebString(file_path.BaseName())).toString()); | |
| 39 if (special_storage_policy->IsStorageProtected(origin)) | |
| 40 continue; | |
| 41 if (!clear_all_databases && | |
| 42 !special_storage_policy->IsStorageSessionOnly(origin)) { | |
| 43 continue; | |
| 44 } | |
| 45 file_util::Delete(file_path, false); | |
| 46 } | |
| 47 } | |
| 48 } | 25 } |
| 49 | 26 |
| 50 } // namespace | 27 DomStorageContext::~DomStorageContext() { |
| 51 | |
| 52 const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] = | |
| 53 FILE_PATH_LITERAL("Local Storage"); | |
| 54 | |
| 55 const FilePath::CharType DOMStorageContext::kLocalStorageExtension[] = | |
| 56 FILE_PATH_LITERAL(".localstorage"); | |
| 57 | |
| 58 DOMStorageContext::DOMStorageContext( | |
| 59 WebKitContext* webkit_context, | |
| 60 quota::SpecialStoragePolicy* special_storage_policy) | |
| 61 : last_storage_area_id_(0), | |
| 62 last_session_storage_namespace_id_on_ui_thread_(kLocalStorageNamespaceId), | |
| 63 last_session_storage_namespace_id_on_io_thread_(kLocalStorageNamespaceId), | |
| 64 clear_local_state_on_exit_(false), | |
| 65 save_session_state_(false), | |
| 66 special_storage_policy_(special_storage_policy) { | |
| 67 data_path_ = webkit_context->data_path(); | |
| 68 } | 28 } |
| 69 | 29 |
| 70 DOMStorageContext::~DOMStorageContext() { | 30 DomStorageNamespace* DomStorageContext::GetStorageNamespace( |
| 71 // This should not go away until all DOM Storage message filters have gone | 31 int64 namespace_id) { |
| 72 // away. And they remove themselves from this list. | 32 StorageNamespaceMap::iterator found = namespaces_.find(namespace_id); |
| 73 DCHECK(message_filter_set_.empty()); | 33 if (found == namespaces_.end()) { |
| 74 | 34 if (namespace_id == kLocalStorageNamespaceId) { |
| 75 for (StorageNamespaceMap::iterator iter(storage_namespace_map_.begin()); | 35 DomStorageNamespace* local = new DomStorageNamespace( |
| 76 iter != storage_namespace_map_.end(); ++iter) { | 36 kLocalStorageNamespaceId, directory_, task_runner_); |
| 77 delete iter->second; | 37 namespaces_[kLocalStorageNamespaceId] = local; |
| 38 return local; | |
| 39 } | |
| 40 return NULL; | |
| 78 } | 41 } |
| 79 | 42 return found->second; |
| 80 if (save_session_state_) | |
| 81 return; | |
| 82 | |
| 83 bool has_session_only_databases = | |
| 84 special_storage_policy_.get() && | |
| 85 special_storage_policy_->HasSessionOnlyOrigins(); | |
| 86 | |
| 87 // Clearning only session-only databases, and there are none. | |
| 88 if (!clear_local_state_on_exit_ && !has_session_only_databases) | |
| 89 return; | |
| 90 | |
| 91 // Not being on the WEBKIT thread here means we are running in a unit test | |
| 92 // where no clean up is needed. | |
| 93 if (BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)) { | |
| 94 ClearLocalState(data_path_.Append(kLocalStorageDirectory), | |
| 95 special_storage_policy_, | |
| 96 clear_local_state_on_exit_); | |
| 97 } | |
| 98 } | 43 } |
| 99 | 44 |
| 100 int64 DOMStorageContext::AllocateStorageAreaId() { | 45 void DomStorageContext::AddEventObserver(EventObserver* observer) { |
| 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 46 event_observers_.AddObserver(observer); |
| 102 return ++last_storage_area_id_; | |
| 103 } | 47 } |
| 104 | 48 |
| 105 int64 DOMStorageContext::AllocateSessionStorageNamespaceId() { | 49 void DomStorageContext::RemoveEventObserver(EventObserver* observer) { |
| 106 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) | 50 event_observers_.RemoveObserver(observer); |
| 107 return ++last_session_storage_namespace_id_on_ui_thread_; | |
| 108 return --last_session_storage_namespace_id_on_io_thread_; | |
| 109 } | 51 } |
| 110 | 52 |
| 111 int64 DOMStorageContext::CloneSessionStorage(int64 original_id) { | 53 void DomStorageContext::NotifyItemSet( |
| 112 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 54 const DomStorageArea* area, |
| 113 int64 clone_id = AllocateSessionStorageNamespaceId(); | 55 const string16& key, |
| 114 BrowserThread::PostTask( | 56 const string16& new_value, |
| 115 BrowserThread::WEBKIT_DEPRECATED, FROM_HERE, | 57 const NullableString16& old_value, |
| 116 base::Bind(&DOMStorageContext::CompleteCloningSessionStorage, this, | 58 const GURL& page_url) { |
| 117 original_id, clone_id)); | 59 FOR_EACH_OBSERVER( |
| 118 return clone_id; | 60 EventObserver, event_observers_, |
| 61 OnDomStorageItemSet(area, key, new_value, old_value, page_url)); | |
| 119 } | 62 } |
| 120 | 63 |
| 121 void DOMStorageContext::RegisterStorageArea(DOMStorageArea* storage_area) { | 64 void DomStorageContext::NotifyItemRemoved( |
| 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 65 const DomStorageArea* area, |
| 123 int64 id = storage_area->id(); | 66 const string16& key, |
| 124 DCHECK(!GetStorageArea(id)); | 67 const string16& old_value, |
| 125 storage_area_map_[id] = storage_area; | 68 const GURL& page_url) { |
| 69 FOR_EACH_OBSERVER( | |
| 70 EventObserver, event_observers_, | |
| 71 OnDomStorageItemRemoved(area, key, old_value, page_url)); | |
| 126 } | 72 } |
| 127 | 73 |
| 128 void DOMStorageContext::UnregisterStorageArea(DOMStorageArea* storage_area) { | 74 void DomStorageContext::NotifyAreaCleared( |
| 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 75 const DomStorageArea* area, |
| 130 int64 id = storage_area->id(); | 76 const GURL& page_url) { |
| 131 DCHECK(GetStorageArea(id)); | 77 FOR_EACH_OBSERVER( |
| 132 storage_area_map_.erase(id); | 78 EventObserver, event_observers_, |
| 79 OnDomStorageAreaCleared(area, page_url)); | |
| 133 } | 80 } |
| 134 | 81 |
| 135 DOMStorageArea* DOMStorageContext::GetStorageArea(int64 id) { | 82 void DomStorageContext::CreateSessionNamespace( |
| 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 83 int64 namespace_id) { |
| 137 StorageAreaMap::iterator iter = storage_area_map_.find(id); | 84 DCHECK(namespace_id != kLocalStorageNamespaceId); |
| 138 if (iter == storage_area_map_.end()) | 85 DCHECK(namespaces_.find(namespace_id) == namespaces_.end()); |
| 139 return NULL; | 86 namespaces_[namespace_id] = new DomStorageNamespace( |
| 140 return iter->second; | 87 namespace_id, FilePath(), task_runner_); |
| 141 } | 88 } |
| 142 | 89 |
| 143 void DOMStorageContext::DeleteSessionStorageNamespace(int64 namespace_id) { | 90 void DomStorageContext::DeleteSessionNamespace( |
| 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 91 int64 namespace_id) { |
| 145 StorageNamespaceMap::iterator iter = | 92 DCHECK_NE(kLocalStorageNamespaceId, namespace_id); |
| 146 storage_namespace_map_.find(namespace_id); | 93 namespaces_.erase(namespace_id); |
| 147 if (iter == storage_namespace_map_.end()) | |
| 148 return; | |
| 149 DCHECK(iter->second->dom_storage_type() == DOM_STORAGE_SESSION); | |
| 150 delete iter->second; | |
| 151 storage_namespace_map_.erase(iter); | |
| 152 } | 94 } |
| 153 | 95 |
| 154 DOMStorageNamespace* DOMStorageContext::GetStorageNamespace( | 96 void DomStorageContext::CloneSessionNamespace( |
| 155 int64 id, bool allocation_allowed) { | 97 int64 existing_id, int64 new_id) { |
| 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | 98 DCHECK_NE(kLocalStorageNamespaceId, existing_id); |
| 157 StorageNamespaceMap::iterator iter = storage_namespace_map_.find(id); | 99 DCHECK_NE(kLocalStorageNamespaceId, new_id); |
| 158 if (iter != storage_namespace_map_.end()) | 100 StorageNamespaceMap::iterator found = namespaces_.find(existing_id); |
| 159 return iter->second; | 101 if (found != namespaces_.end()) |
| 160 if (!allocation_allowed) | 102 namespaces_[new_id] = found->second->Clone(new_id); |
| 161 return NULL; | 103 else |
| 162 if (id == kLocalStorageNamespaceId) | 104 CreateSessionNamespace(new_id); |
| 163 return CreateLocalStorage(); | |
| 164 return CreateSessionStorage(id); | |
| 165 } | 105 } |
| 166 | 106 |
| 167 void DOMStorageContext::RegisterMessageFilter( | 107 } // namespace dom_storage |
| 168 DOMStorageMessageFilter* message_filter) { | |
| 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 170 DCHECK(message_filter_set_.find(message_filter) == | |
| 171 message_filter_set_.end()); | |
| 172 message_filter_set_.insert(message_filter); | |
| 173 } | |
| 174 | 108 |
| 175 void DOMStorageContext::UnregisterMessageFilter( | |
| 176 DOMStorageMessageFilter* message_filter) { | |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 178 DCHECK(message_filter_set_.find(message_filter) != | |
| 179 message_filter_set_.end()); | |
| 180 message_filter_set_.erase(message_filter); | |
| 181 } | |
| 182 | |
| 183 const DOMStorageContext::MessageFilterSet* | |
| 184 DOMStorageContext::GetMessageFilterSet() const { | |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 186 return &message_filter_set_; | |
| 187 } | |
| 188 | |
| 189 void DOMStorageContext::PurgeMemory() { | |
| 190 // It is only safe to purge the memory from the LocalStorage namespace, | |
| 191 // because it is backed by disk and can be reloaded later. If we purge a | |
| 192 // SessionStorage namespace, its data will be gone forever, because it isn't | |
| 193 // currently backed by disk. | |
| 194 DOMStorageNamespace* local_storage = | |
| 195 GetStorageNamespace(kLocalStorageNamespaceId, false); | |
| 196 if (local_storage) | |
| 197 local_storage->PurgeMemory(); | |
| 198 } | |
| 199 | |
| 200 void DOMStorageContext::DeleteDataModifiedSince(const base::Time& cutoff) { | |
| 201 // Make sure that we don't delete a database that's currently being accessed | |
| 202 // by unloading all of the databases temporarily. | |
| 203 PurgeMemory(); | |
| 204 | |
| 205 file_util::FileEnumerator file_enumerator( | |
| 206 data_path_.Append(kLocalStorageDirectory), false, | |
| 207 file_util::FileEnumerator::FILES); | |
| 208 for (FilePath path = file_enumerator.Next(); !path.value().empty(); | |
| 209 path = file_enumerator.Next()) { | |
| 210 GURL origin(WebSecurityOrigin::createFromDatabaseIdentifier( | |
| 211 webkit_glue::FilePathToWebString(path.BaseName())).toString()); | |
| 212 if (special_storage_policy_->IsStorageProtected(origin)) | |
| 213 continue; | |
| 214 | |
| 215 file_util::FileEnumerator::FindInfo find_info; | |
| 216 file_enumerator.GetFindInfo(&find_info); | |
| 217 if (file_util::HasFileBeenModifiedSince(find_info, cutoff)) | |
| 218 file_util::Delete(path, false); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) { | |
| 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
| 224 | |
| 225 // Make sure that we don't delete a database that's currently being accessed | |
| 226 // by unloading all of the databases temporarily. | |
| 227 // TODO(bulach): both this method and DeleteDataModifiedSince could purge | |
| 228 // only the memory used by the specific file instead of all memory at once. | |
| 229 // See http://crbug.com/32000 | |
| 230 PurgeMemory(); | |
| 231 file_util::Delete(file_path, false); | |
| 232 } | |
| 233 | |
| 234 void DOMStorageContext::DeleteLocalStorageForOrigin(const string16& origin_id) { | |
| 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
| 236 DeleteLocalStorageFile(GetLocalStorageFilePath(origin_id)); | |
| 237 } | |
| 238 | |
| 239 void DOMStorageContext::DeleteAllLocalStorageFiles() { | |
| 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
| 241 | |
| 242 // Make sure that we don't delete a database that's currently being accessed | |
| 243 // by unloading all of the databases temporarily. | |
| 244 PurgeMemory(); | |
| 245 | |
| 246 file_util::FileEnumerator file_enumerator( | |
| 247 data_path_.Append(kLocalStorageDirectory), false, | |
| 248 file_util::FileEnumerator::FILES); | |
| 249 for (FilePath file_path = file_enumerator.Next(); !file_path.empty(); | |
| 250 file_path = file_enumerator.Next()) { | |
| 251 if (file_path.Extension() == kLocalStorageExtension) | |
| 252 file_util::Delete(file_path, false); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 DOMStorageNamespace* DOMStorageContext::CreateLocalStorage() { | |
| 257 FilePath dir_path; | |
| 258 if (!data_path_.empty()) | |
| 259 dir_path = data_path_.Append(kLocalStorageDirectory); | |
| 260 DOMStorageNamespace* new_namespace = | |
| 261 DOMStorageNamespace::CreateLocalStorageNamespace(this, dir_path); | |
| 262 RegisterStorageNamespace(new_namespace); | |
| 263 return new_namespace; | |
| 264 } | |
| 265 | |
| 266 DOMStorageNamespace* DOMStorageContext::CreateSessionStorage( | |
| 267 int64 namespace_id) { | |
| 268 DOMStorageNamespace* new_namespace = | |
| 269 DOMStorageNamespace::CreateSessionStorageNamespace(this, namespace_id); | |
| 270 RegisterStorageNamespace(new_namespace); | |
| 271 return new_namespace; | |
| 272 } | |
| 273 | |
| 274 void DOMStorageContext::RegisterStorageNamespace( | |
| 275 DOMStorageNamespace* storage_namespace) { | |
| 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
| 277 int64 id = storage_namespace->id(); | |
| 278 DCHECK(!GetStorageNamespace(id, false)); | |
| 279 storage_namespace_map_[id] = storage_namespace; | |
| 280 } | |
| 281 | |
| 282 /* static */ | |
| 283 void DOMStorageContext::CompleteCloningSessionStorage( | |
| 284 DOMStorageContext* context, int64 existing_id, int64 clone_id) { | |
| 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED)); | |
| 286 DOMStorageNamespace* existing_namespace = | |
| 287 context->GetStorageNamespace(existing_id, false); | |
| 288 // If nothing exists, then there's nothing to clone. | |
| 289 if (existing_namespace) | |
| 290 context->RegisterStorageNamespace(existing_namespace->Copy(clone_id)); | |
| 291 } | |
| 292 | |
| 293 FilePath DOMStorageContext::GetLocalStorageFilePath( | |
| 294 const string16& origin_id) const { | |
| 295 FilePath storageDir = data_path_.Append( | |
| 296 DOMStorageContext::kLocalStorageDirectory); | |
| 297 FilePath::StringType id = | |
| 298 webkit_glue::WebStringToFilePathString(origin_id); | |
| 299 return storageDir.Append(id.append(kLocalStorageExtension)); | |
| 300 } | |
| OLD | NEW |