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 "StorageAreaImpl.h" 28 29#if ENABLE(DOM_STORAGE) 30 31#include "ExceptionCode.h" 32#include "Frame.h" 33#include "Page.h" 34#include "Settings.h" 35#include "StorageAreaSync.h" 36#include "StorageEventDispatcher.h" 37#include "StorageMap.h" 38#include "StorageSyncManager.h" 39 40namespace WebCore { 41 42StorageAreaImpl::~StorageAreaImpl() 43{ 44 ASSERT(isMainThread()); 45} 46 47inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) 48 : m_storageType(storageType) 49 , m_securityOrigin(origin) 50 , m_storageMap(StorageMap::create(quota)) 51 , m_storageSyncManager(syncManager) 52#ifndef NDEBUG 53 , m_isShutdown(false) 54#endif 55{ 56 ASSERT(isMainThread()); 57 ASSERT(m_securityOrigin); 58 ASSERT(m_storageMap); 59} 60 61PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) 62{ 63 RefPtr<StorageAreaImpl> area = adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota)); 64 65 // FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing, 66 // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894 67 if (area->m_storageSyncManager) { 68 area->m_storageAreaSync = StorageAreaSync::create(area->m_storageSyncManager, area.get(), area->m_securityOrigin->databaseIdentifier()); 69 ASSERT(area->m_storageAreaSync); 70 } 71 72 return area.release(); 73} 74 75PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy() 76{ 77 ASSERT(!m_isShutdown); 78 return adoptRef(new StorageAreaImpl(this)); 79} 80 81StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area) 82 : m_storageType(area->m_storageType) 83 , m_securityOrigin(area->m_securityOrigin) 84 , m_storageMap(area->m_storageMap) 85 , m_storageSyncManager(area->m_storageSyncManager) 86#ifndef NDEBUG 87 , m_isShutdown(area->m_isShutdown) 88#endif 89{ 90 ASSERT(isMainThread()); 91 ASSERT(m_securityOrigin); 92 ASSERT(m_storageMap); 93 ASSERT(!m_isShutdown); 94} 95 96static bool privateBrowsingEnabled(Frame* frame) 97{ 98#if PLATFORM(ANDROID) 99 if (!frame) 100 return false; 101#endif 102#if PLATFORM(CHROMIUM) 103 // The frame pointer can be NULL in Chromium since this call is made in a different 104 // process from where the Frame object exists. Luckily, private browseing is 105 // implemented differently in Chromium, so it'd never return true anyway. 106 ASSERT(!frame); 107 return false; 108#else 109 return frame->page() && frame->page()->settings()->privateBrowsingEnabled(); 110#endif 111} 112 113unsigned StorageAreaImpl::length() const 114{ 115 ASSERT(!m_isShutdown); 116 blockUntilImportComplete(); 117 118 return m_storageMap->length(); 119} 120 121String StorageAreaImpl::key(unsigned index) const 122{ 123 ASSERT(!m_isShutdown); 124 blockUntilImportComplete(); 125 126 return m_storageMap->key(index); 127} 128 129String StorageAreaImpl::getItem(const String& key) const 130{ 131 ASSERT(!m_isShutdown); 132 blockUntilImportComplete(); 133 134 return m_storageMap->getItem(key); 135} 136 137String StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame) 138{ 139 ASSERT(!m_isShutdown); 140 ASSERT(!value.isNull()); 141 blockUntilImportComplete(); 142 143 if (privateBrowsingEnabled(frame)) { 144 ec = QUOTA_EXCEEDED_ERR; 145 return String(); 146 } 147 148 String oldValue; 149 bool quotaException; 150 RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException); 151 if (newMap) 152 m_storageMap = newMap.release(); 153 154 if (quotaException) { 155 ec = QUOTA_EXCEEDED_ERR; 156 return oldValue; 157 } 158 159 if (oldValue == value) 160 return oldValue; 161 162 if (m_storageAreaSync) 163 m_storageAreaSync->scheduleItemForSync(key, value); 164 StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame); 165 return oldValue; 166} 167 168String StorageAreaImpl::removeItem(const String& key, Frame* frame) 169{ 170 ASSERT(!m_isShutdown); 171 blockUntilImportComplete(); 172 173 if (privateBrowsingEnabled(frame)) 174 return String(); 175 176 String oldValue; 177 RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue); 178 if (newMap) 179 m_storageMap = newMap.release(); 180 181 if (oldValue.isNull()) 182 return oldValue; 183 184 if (m_storageAreaSync) 185 m_storageAreaSync->scheduleItemForSync(key, String()); 186 StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame); 187 return oldValue; 188} 189 190bool StorageAreaImpl::clear(Frame* frame) 191{ 192 ASSERT(!m_isShutdown); 193 blockUntilImportComplete(); 194 195 if (privateBrowsingEnabled(frame)) 196 return false; 197 198 if (!m_storageMap->length()) 199 return false; 200 201 unsigned quota = m_storageMap->quota(); 202 m_storageMap = StorageMap::create(quota); 203 204 if (m_storageAreaSync) 205 m_storageAreaSync->scheduleClear(); 206 StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame); 207 return true; 208} 209 210bool StorageAreaImpl::contains(const String& key) const 211{ 212 ASSERT(!m_isShutdown); 213 blockUntilImportComplete(); 214 215 return m_storageMap->contains(key); 216} 217 218void StorageAreaImpl::importItem(const String& key, const String& value) 219{ 220 ASSERT(!m_isShutdown); 221 m_storageMap->importItem(key, value); 222} 223 224void StorageAreaImpl::close() 225{ 226 if (m_storageAreaSync) 227 m_storageAreaSync->scheduleFinalSync(); 228 229#ifndef NDEBUG 230 m_isShutdown = true; 231#endif 232} 233 234void StorageAreaImpl::clearForOriginDeletion() 235{ 236 ASSERT(!m_isShutdown); 237 blockUntilImportComplete(); 238 239 if (m_storageMap->length()) { 240 unsigned quota = m_storageMap->quota(); 241 m_storageMap = StorageMap::create(quota); 242 } 243 244 if (m_storageAreaSync) { 245 m_storageAreaSync->scheduleClear(); 246 m_storageAreaSync->scheduleCloseDatabase(); 247 } 248} 249 250void StorageAreaImpl::sync() 251{ 252 ASSERT(!m_isShutdown); 253 blockUntilImportComplete(); 254 255 if (m_storageAreaSync) 256 m_storageAreaSync->scheduleSync(); 257} 258 259void StorageAreaImpl::blockUntilImportComplete() const 260{ 261 if (m_storageAreaSync) 262 m_storageAreaSync->blockUntilImportComplete(); 263} 264 265} 266 267#endif // ENABLE(DOM_STORAGE) 268