1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "StorageNamespaceImpl.h" 28 29#include "GroupSettings.h" 30#include "Page.h" 31#include "PageGroup.h" 32#include "SecurityOriginHash.h" 33#include "Settings.h" 34#include "StorageAreaImpl.h" 35#include "StorageMap.h" 36#include "StorageSyncManager.h" 37#include "StorageTracker.h" 38#include <wtf/MainThread.h> 39#include <wtf/StdLibExtras.h> 40#include <wtf/text/StringHash.h> 41 42namespace WebCore { 43 44typedef HashMap<String, StorageNamespace*> LocalStorageNamespaceMap; 45 46static LocalStorageNamespaceMap& localStorageNamespaceMap() 47{ 48 DEPRECATED_DEFINE_STATIC_LOCAL(LocalStorageNamespaceMap, localStorageNamespaceMap, ()); 49 return localStorageNamespaceMap; 50} 51 52PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(PageGroup* pageGroup) 53{ 54 // Need a page in this page group to query the settings for the local storage database path. 55 // Having these parameters attached to the page settings is unfortunate since these settings are 56 // not per-page (and, in fact, we simply grab the settings from some page at random), but 57 // at this point we're stuck with it. 58 Page* page = *pageGroup->pages().begin(); 59 const String& path = page->settings().localStorageDatabasePath(); 60 unsigned quota = pageGroup->groupSettings().localStorageQuotaBytes(); 61 const String lookupPath = path.isNull() ? emptyString() : path; 62 63 LocalStorageNamespaceMap::AddResult result = localStorageNamespaceMap().add(lookupPath, nullptr); 64 if (!result.isNewEntry) 65 return result.iterator->value; 66 67 RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota)); 68 69 result.iterator->value = storageNamespace.get(); 70 return storageNamespace.release(); 71} 72 73PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(Page* page) 74{ 75 return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), page->settings().sessionStorageQuota())); 76} 77 78PassRefPtr<StorageNamespace> StorageNamespaceImpl::transientLocalStorageNamespace(PageGroup* pageGroup, SecurityOrigin*) 79{ 80 // FIXME: A smarter implementation would create a special namespace type instead of just piggy-backing off 81 // SessionStorageNamespace here. 82 return StorageNamespaceImpl::sessionStorageNamespace(*pageGroup->pages().begin()); 83} 84 85StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota) 86 : m_storageType(storageType) 87 , m_path(path.isolatedCopy()) 88 , m_syncManager(0) 89 , m_quota(quota) 90 , m_isShutdown(false) 91{ 92 if (m_storageType == LocalStorage && !m_path.isEmpty()) 93 m_syncManager = StorageSyncManager::create(m_path); 94} 95 96StorageNamespaceImpl::~StorageNamespaceImpl() 97{ 98 ASSERT(isMainThread()); 99 100 if (m_storageType == LocalStorage) { 101 ASSERT(localStorageNamespaceMap().get(m_path) == this); 102 localStorageNamespaceMap().remove(m_path); 103 } 104 105 if (!m_isShutdown) 106 close(); 107} 108 109PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy(Page*) 110{ 111 ASSERT(isMainThread()); 112 ASSERT(!m_isShutdown); 113 ASSERT(m_storageType == SessionStorage); 114 115 RefPtr<StorageNamespaceImpl> newNamespace = adoptRef(new StorageNamespaceImpl(m_storageType, m_path, m_quota)); 116 117 StorageAreaMap::iterator end = m_storageAreaMap.end(); 118 for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i) 119 newNamespace->m_storageAreaMap.set(i->key, i->value->copy()); 120 return newNamespace.release(); 121} 122 123PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin) 124{ 125 ASSERT(isMainThread()); 126 ASSERT(!m_isShutdown); 127 128 RefPtr<SecurityOrigin> origin = prpOrigin; 129 RefPtr<StorageAreaImpl> storageArea; 130 if ((storageArea = m_storageAreaMap.get(origin))) 131 return storageArea.release(); 132 133 storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota); 134 m_storageAreaMap.set(origin.release(), storageArea); 135 return storageArea.release(); 136} 137 138void StorageNamespaceImpl::close() 139{ 140 ASSERT(isMainThread()); 141 142 if (m_isShutdown) 143 return; 144 145 // If we're session storage, we shouldn't need to do any work here. 146 if (m_storageType == SessionStorage) { 147 ASSERT(!m_syncManager); 148 return; 149 } 150 151 StorageAreaMap::iterator end = m_storageAreaMap.end(); 152 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 153 it->value->close(); 154 155 if (m_syncManager) 156 m_syncManager->close(); 157 158 m_isShutdown = true; 159} 160 161void StorageNamespaceImpl::clearOriginForDeletion(SecurityOrigin* origin) 162{ 163 ASSERT(isMainThread()); 164 165 RefPtr<StorageAreaImpl> storageArea = m_storageAreaMap.get(origin); 166 if (storageArea) 167 storageArea->clearForOriginDeletion(); 168} 169 170void StorageNamespaceImpl::clearAllOriginsForDeletion() 171{ 172 ASSERT(isMainThread()); 173 174 StorageAreaMap::iterator end = m_storageAreaMap.end(); 175 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 176 it->value->clearForOriginDeletion(); 177} 178 179void StorageNamespaceImpl::sync() 180{ 181 ASSERT(isMainThread()); 182 StorageAreaMap::iterator end = m_storageAreaMap.end(); 183 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 184 it->value->sync(); 185} 186 187void StorageNamespaceImpl::closeIdleLocalStorageDatabases() 188{ 189 ASSERT(isMainThread()); 190 StorageAreaMap::iterator end = m_storageAreaMap.end(); 191 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 192 it->value->closeDatabaseIfIdle(); 193} 194 195} // namespace WebCore 196