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 PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) 48 { 49 return adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota)); 50 } 51 52 StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota) 53 : m_storageType(storageType) 54 , m_securityOrigin(origin) 55 , m_storageMap(StorageMap::create(quota)) 56 , m_storageSyncManager(syncManager) 57 #ifndef NDEBUG 58 , m_isShutdown(false) 59 #endif 60 { 61 ASSERT(isMainThread()); 62 ASSERT(m_securityOrigin); 63 ASSERT(m_storageMap); 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 (m_storageSyncManager) { 68 m_storageAreaSync = StorageAreaSync::create(m_storageSyncManager, this, m_securityOrigin->databaseIdentifier()); 69 ASSERT(m_storageAreaSync); 70 } 71 } 72 73 PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy() 74 { 75 ASSERT(!m_isShutdown); 76 return adoptRef(new StorageAreaImpl(this)); 77 } 78 79 StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area) 80 : m_storageType(area->m_storageType) 81 , m_securityOrigin(area->m_securityOrigin) 82 , m_storageMap(area->m_storageMap) 83 , m_storageSyncManager(area->m_storageSyncManager) 84 #ifndef NDEBUG 85 , m_isShutdown(area->m_isShutdown) 86 #endif 87 { 88 ASSERT(isMainThread()); 89 ASSERT(m_securityOrigin); 90 ASSERT(m_storageMap); 91 ASSERT(!m_isShutdown); 92 } 93 94 static bool privateBrowsingEnabled(Frame* frame) 95 { 96 #if PLATFORM(CHROMIUM) 97 // The frame pointer can be NULL in Chromium since this call is made in a different 98 // process from where the Frame object exists. Luckily, private browseing is 99 // implemented differently in Chromium, so it'd never return true anyway. 100 ASSERT(!frame); 101 return false; 102 #else 103 return frame->page()->settings()->privateBrowsingEnabled(); 104 #endif 105 } 106 107 unsigned StorageAreaImpl::length() const 108 { 109 ASSERT(!m_isShutdown); 110 blockUntilImportComplete(); 111 112 return m_storageMap->length(); 113 } 114 115 String StorageAreaImpl::key(unsigned index) const 116 { 117 ASSERT(!m_isShutdown); 118 blockUntilImportComplete(); 119 120 return m_storageMap->key(index); 121 } 122 123 String StorageAreaImpl::getItem(const String& key) const 124 { 125 ASSERT(!m_isShutdown); 126 blockUntilImportComplete(); 127 128 return m_storageMap->getItem(key); 129 } 130 131 String StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame) 132 { 133 ASSERT(!m_isShutdown); 134 ASSERT(!value.isNull()); 135 blockUntilImportComplete(); 136 137 if (privateBrowsingEnabled(frame)) { 138 ec = QUOTA_EXCEEDED_ERR; 139 return String(); 140 } 141 142 String oldValue; 143 bool quotaException; 144 RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException); 145 if (newMap) 146 m_storageMap = newMap.release(); 147 148 if (quotaException) { 149 ec = QUOTA_EXCEEDED_ERR; 150 return oldValue; 151 } 152 153 if (oldValue == value) 154 return oldValue; 155 156 if (m_storageAreaSync) 157 m_storageAreaSync->scheduleItemForSync(key, value); 158 StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame); 159 return oldValue; 160 } 161 162 String StorageAreaImpl::removeItem(const String& key, Frame* frame) 163 { 164 ASSERT(!m_isShutdown); 165 blockUntilImportComplete(); 166 167 if (privateBrowsingEnabled(frame)) 168 return String(); 169 170 String oldValue; 171 RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue); 172 if (newMap) 173 m_storageMap = newMap.release(); 174 175 if (oldValue.isNull()) 176 return oldValue; 177 178 if (m_storageAreaSync) 179 m_storageAreaSync->scheduleItemForSync(key, String()); 180 StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame); 181 return oldValue; 182 } 183 184 bool StorageAreaImpl::clear(Frame* frame) 185 { 186 ASSERT(!m_isShutdown); 187 blockUntilImportComplete(); 188 189 if (privateBrowsingEnabled(frame)) 190 return false; 191 192 if (!m_storageMap->length()) 193 return false; 194 195 unsigned quota = m_storageMap->quota(); 196 m_storageMap = StorageMap::create(quota); 197 198 if (m_storageAreaSync) 199 m_storageAreaSync->scheduleClear(); 200 StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame); 201 return true; 202 } 203 204 bool StorageAreaImpl::contains(const String& key) const 205 { 206 ASSERT(!m_isShutdown); 207 blockUntilImportComplete(); 208 209 return m_storageMap->contains(key); 210 } 211 212 void StorageAreaImpl::importItem(const String& key, const String& value) 213 { 214 ASSERT(!m_isShutdown); 215 m_storageMap->importItem(key, value); 216 } 217 218 void StorageAreaImpl::close() 219 { 220 if (m_storageAreaSync) 221 m_storageAreaSync->scheduleFinalSync(); 222 223 #ifndef NDEBUG 224 m_isShutdown = true; 225 #endif 226 } 227 228 void StorageAreaImpl::blockUntilImportComplete() const 229 { 230 if (m_storageAreaSync) 231 m_storageAreaSync->blockUntilImportComplete(); 232 } 233 234 } 235 236 #endif // ENABLE(DOM_STORAGE) 237