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 40 namespace WebCore { 41 42 StorageAreaImpl::~StorageAreaImpl() 43 { 44 ASSERT(isMainThread()); 45 } 46 47 inline 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 61 PassRefPtr<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 75 PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy() 76 { 77 ASSERT(!m_isShutdown); 78 return adoptRef(new StorageAreaImpl(this)); 79 } 80 81 StorageAreaImpl::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 96 static 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 113 unsigned StorageAreaImpl::length() const 114 { 115 ASSERT(!m_isShutdown); 116 blockUntilImportComplete(); 117 118 return m_storageMap->length(); 119 } 120 121 String StorageAreaImpl::key(unsigned index) const 122 { 123 ASSERT(!m_isShutdown); 124 blockUntilImportComplete(); 125 126 return m_storageMap->key(index); 127 } 128 129 String StorageAreaImpl::getItem(const String& key) const 130 { 131 ASSERT(!m_isShutdown); 132 blockUntilImportComplete(); 133 134 return m_storageMap->getItem(key); 135 } 136 137 String 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 168 String 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 190 bool 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 210 bool StorageAreaImpl::contains(const String& key) const 211 { 212 ASSERT(!m_isShutdown); 213 blockUntilImportComplete(); 214 215 return m_storageMap->contains(key); 216 } 217 218 void StorageAreaImpl::importItem(const String& key, const String& value) 219 { 220 ASSERT(!m_isShutdown); 221 m_storageMap->importItem(key, value); 222 } 223 224 void StorageAreaImpl::close() 225 { 226 if (m_storageAreaSync) 227 m_storageAreaSync->scheduleFinalSync(); 228 229 #ifndef NDEBUG 230 m_isShutdown = true; 231 #endif 232 } 233 234 void 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 250 void StorageAreaImpl::sync() 251 { 252 ASSERT(!m_isShutdown); 253 blockUntilImportComplete(); 254 255 if (m_storageAreaSync) 256 m_storageAreaSync->scheduleSync(); 257 } 258 259 void StorageAreaImpl::blockUntilImportComplete() const 260 { 261 if (m_storageAreaSync) 262 m_storageAreaSync->blockUntilImportComplete(); 263 } 264 265 } 266 267 #endif // ENABLE(DOM_STORAGE) 268