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#if ENABLE(DOM_STORAGE) 30 31#include "SecurityOriginHash.h" 32#include "StorageAreaImpl.h" 33#include "StorageMap.h" 34#include "StorageSyncManager.h" 35#include "StorageTracker.h" 36#include <wtf/StdLibExtras.h> 37#include <wtf/text/StringHash.h> 38 39#ifdef ANDROID 40#include "Page.h" 41#endif 42 43namespace WebCore { 44 45typedef HashMap<String, StorageNamespace*> LocalStorageNamespaceMap; 46 47static LocalStorageNamespaceMap& localStorageNamespaceMap() 48{ 49 DEFINE_STATIC_LOCAL(LocalStorageNamespaceMap, localStorageNamespaceMap, ()); 50 return localStorageNamespaceMap; 51} 52 53PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path, unsigned quota) 54{ 55 const String lookupPath = path.isNull() ? String("") : path; 56 LocalStorageNamespaceMap::iterator it = localStorageNamespaceMap().find(lookupPath); 57 if (it == localStorageNamespaceMap().end()) { 58 RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota)); 59 localStorageNamespaceMap().set(lookupPath, storageNamespace.get()); 60 return storageNamespace.release(); 61 } 62 63 return it->second; 64} 65 66PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(unsigned quota) 67{ 68 return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), quota)); 69} 70 71StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota) 72 : m_storageType(storageType) 73 , m_path(path.crossThreadString()) 74 , m_syncManager(0) 75 , m_quota(quota) 76 , m_isShutdown(false) 77{ 78 if (m_storageType == LocalStorage && !m_path.isEmpty()) 79 m_syncManager = StorageSyncManager::create(m_path); 80} 81 82StorageNamespaceImpl::~StorageNamespaceImpl() 83{ 84 ASSERT(isMainThread()); 85 86 if (m_storageType == LocalStorage) { 87 ASSERT(localStorageNamespaceMap().get(m_path) == this); 88 localStorageNamespaceMap().remove(m_path); 89 } 90 91 if (!m_isShutdown) 92 close(); 93} 94 95PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy() 96{ 97 ASSERT(isMainThread()); 98 ASSERT(!m_isShutdown); 99 ASSERT(m_storageType == SessionStorage); 100 101 RefPtr<StorageNamespaceImpl> newNamespace = adoptRef(new StorageNamespaceImpl(m_storageType, m_path, m_quota)); 102 103 StorageAreaMap::iterator end = m_storageAreaMap.end(); 104 for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i) 105 newNamespace->m_storageAreaMap.set(i->first, i->second->copy()); 106 return newNamespace.release(); 107} 108 109PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin) 110{ 111 ASSERT(isMainThread()); 112 ASSERT(!m_isShutdown); 113 114 RefPtr<SecurityOrigin> origin = prpOrigin; 115 RefPtr<StorageAreaImpl> storageArea; 116 if ((storageArea = m_storageAreaMap.get(origin))) 117 return storageArea.release(); 118 119 storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota); 120 m_storageAreaMap.set(origin.release(), storageArea); 121 return storageArea.release(); 122} 123 124void StorageNamespaceImpl::close() 125{ 126 ASSERT(isMainThread()); 127 128 if (m_isShutdown) 129 return; 130 131 // If we're session storage, we shouldn't need to do any work here. 132 if (m_storageType == SessionStorage) { 133 ASSERT(!m_syncManager); 134 return; 135 } 136 137 StorageAreaMap::iterator end = m_storageAreaMap.end(); 138 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 139 it->second->close(); 140 141 if (m_syncManager) 142 m_syncManager->close(); 143 144 m_isShutdown = true; 145} 146 147#ifdef ANDROID 148void StorageNamespaceImpl::clear(Page* page) 149{ 150 ASSERT(isMainThread()); 151 if (m_isShutdown) 152 return; 153 154 // Clear all the keys for each of the storage areas. 155 StorageAreaMap::iterator end = m_storageAreaMap.end(); 156 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) { 157 // if there is no page provided, then the user tried to clear storage 158 // with only pages in private browsing mode open. So we do not need to 159 // provide a Frame* here (as the frame is only used to dispatch storage events 160 // and private browsing pages won't be using them). 161 it->second->clear(page ? page->mainFrame() : 0); 162 } 163} 164#endif 165 166void StorageNamespaceImpl::unlock() 167{ 168 // Because there's a single event loop per-process, this is a no-op. 169} 170 171void StorageNamespaceImpl::clearOriginForDeletion(SecurityOrigin* origin) 172{ 173 ASSERT(isMainThread()); 174 175 RefPtr<StorageAreaImpl> storageArea = m_storageAreaMap.get(origin); 176 if (storageArea) 177 storageArea->clearForOriginDeletion(); 178} 179 180void StorageNamespaceImpl::clearAllOriginsForDeletion() 181{ 182 ASSERT(isMainThread()); 183 184 StorageAreaMap::iterator end = m_storageAreaMap.end(); 185 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 186 it->second->clearForOriginDeletion(); 187} 188 189void StorageNamespaceImpl::sync() 190{ 191 ASSERT(isMainThread()); 192 StorageAreaMap::iterator end = m_storageAreaMap.end(); 193 for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 194 it->second->sync(); 195} 196 197} // namespace WebCore 198 199#endif // ENABLE(DOM_STORAGE) 200