Fix the builds with ENABLE_INDEX_DATABASE=OFF.
[WebKit-https.git] / Source / WebKit / Storage / StorageAreaImpl.cpp
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 "StorageAreaImpl.h"
27
28 #include "StorageAreaSync.h"
29 #include "StorageSyncManager.h"
30 #include "StorageTracker.h"
31 #include <WebCore/Frame.h>
32 #include <WebCore/SecurityOrigin.h>
33 #include <WebCore/StorageEventDispatcher.h>
34 #include <WebCore/StorageMap.h>
35 #include <wtf/MainThread.h>
36
37 namespace WebCore {
38
39 StorageAreaImpl::~StorageAreaImpl()
40 {
41     ASSERT(isMainThread());
42 }
43
44 inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
45     : m_storageType(storageType)
46     , m_securityOrigin(origin)
47     , m_storageMap(StorageMap::create(quota))
48     , m_storageSyncManager(syncManager)
49 #ifndef NDEBUG
50     , m_isShutdown(false)
51 #endif
52     , m_accessCount(0)
53     , m_closeDatabaseTimer(*this, &StorageAreaImpl::closeDatabaseTimerFired)
54 {
55     ASSERT(isMainThread());
56     ASSERT(m_securityOrigin);
57     ASSERT(m_storageMap);
58     
59     // Accessing the shared global StorageTracker when a StorageArea is created 
60     // ensures that the tracker is properly initialized before anyone actually needs to use it.
61     StorageTracker::tracker();
62 }
63
64 Ref<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
65 {
66     Ref<StorageAreaImpl> area = adoptRef(*new StorageAreaImpl(storageType, origin, syncManager, quota));
67
68     // FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing,
69     // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
70     if (area->m_storageSyncManager) {
71         area->m_storageAreaSync = StorageAreaSync::create(area->m_storageSyncManager, area.ptr(), area->m_securityOrigin->databaseIdentifier());
72         ASSERT(area->m_storageAreaSync);
73     }
74
75     return area;
76 }
77
78 PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy()
79 {
80     ASSERT(!m_isShutdown);
81     return adoptRef(new StorageAreaImpl(this));
82 }
83
84 StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area)
85     : m_storageType(area->m_storageType)
86     , m_securityOrigin(area->m_securityOrigin)
87     , m_storageMap(area->m_storageMap)
88     , m_storageSyncManager(area->m_storageSyncManager)
89 #ifndef NDEBUG
90     , m_isShutdown(area->m_isShutdown)
91 #endif
92     , m_accessCount(0)
93     , m_closeDatabaseTimer(*this, &StorageAreaImpl::closeDatabaseTimerFired)
94 {
95     ASSERT(isMainThread());
96     ASSERT(m_securityOrigin);
97     ASSERT(m_storageMap);
98     ASSERT(!m_isShutdown);
99 }
100
101 bool StorageAreaImpl::canAccessStorage(Frame* frame)
102 {
103     return frame && frame->page();
104 }
105
106 StorageType StorageAreaImpl::storageType() const
107 {
108     return m_storageType;
109 }
110
111 unsigned StorageAreaImpl::length()
112 {
113     ASSERT(!m_isShutdown);
114     blockUntilImportComplete();
115
116     return m_storageMap->length();
117 }
118
119 String StorageAreaImpl::key(unsigned index)
120 {
121     ASSERT(!m_isShutdown);
122     blockUntilImportComplete();
123
124     return m_storageMap->key(index);
125 }
126
127 String StorageAreaImpl::item(const String& key)
128 {
129     ASSERT(!m_isShutdown);
130     blockUntilImportComplete();
131
132     return m_storageMap->getItem(key);
133 }
134
135 void StorageAreaImpl::setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException)
136 {
137     ASSERT(!m_isShutdown);
138     ASSERT(!value.isNull());
139     blockUntilImportComplete();
140
141     String oldValue;
142     RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
143     if (newMap)
144         m_storageMap = newMap.release();
145
146     if (quotaException)
147         return;
148
149     if (oldValue == value)
150         return;
151
152     if (m_storageAreaSync)
153         m_storageAreaSync->scheduleItemForSync(key, value);
154
155     dispatchStorageEvent(key, oldValue, value, sourceFrame);
156 }
157
158 void StorageAreaImpl::removeItem(Frame* sourceFrame, const String& key)
159 {
160     ASSERT(!m_isShutdown);
161     blockUntilImportComplete();
162
163     String oldValue;
164     RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue);
165     if (newMap)
166         m_storageMap = newMap.release();
167
168     if (oldValue.isNull())
169         return;
170
171     if (m_storageAreaSync)
172         m_storageAreaSync->scheduleItemForSync(key, String());
173
174     dispatchStorageEvent(key, oldValue, String(), sourceFrame);
175 }
176
177 void StorageAreaImpl::clear(Frame* sourceFrame)
178 {
179     ASSERT(!m_isShutdown);
180     blockUntilImportComplete();
181
182     if (!m_storageMap->length())
183         return;
184
185     unsigned quota = m_storageMap->quota();
186     m_storageMap = StorageMap::create(quota);
187
188     if (m_storageAreaSync)
189         m_storageAreaSync->scheduleClear();
190
191     dispatchStorageEvent(String(), String(), String(), sourceFrame);
192 }
193
194 bool StorageAreaImpl::contains(const String& key)
195 {
196     ASSERT(!m_isShutdown);
197     blockUntilImportComplete();
198
199     return m_storageMap->contains(key);
200 }
201
202 void StorageAreaImpl::importItems(const HashMap<String, String>& items)
203 {
204     ASSERT(!m_isShutdown);
205
206     m_storageMap->importItems(items);
207 }
208
209 void StorageAreaImpl::close()
210 {
211     if (m_storageAreaSync)
212         m_storageAreaSync->scheduleFinalSync();
213
214 #ifndef NDEBUG
215     m_isShutdown = true;
216 #endif
217 }
218
219 void StorageAreaImpl::clearForOriginDeletion()
220 {
221     ASSERT(!m_isShutdown);
222     blockUntilImportComplete();
223     
224     if (m_storageMap->length()) {
225         unsigned quota = m_storageMap->quota();
226         m_storageMap = StorageMap::create(quota);
227     }
228
229     if (m_storageAreaSync) {
230         m_storageAreaSync->scheduleClear();
231         m_storageAreaSync->scheduleCloseDatabase();
232     }
233 }
234     
235 void StorageAreaImpl::sync()
236 {
237     ASSERT(!m_isShutdown);
238     blockUntilImportComplete();
239     
240     if (m_storageAreaSync)
241         m_storageAreaSync->scheduleSync();
242 }
243
244 void StorageAreaImpl::blockUntilImportComplete() const
245 {
246     if (m_storageAreaSync)
247         m_storageAreaSync->blockUntilImportComplete();
248 }
249
250 size_t StorageAreaImpl::memoryBytesUsedByCache()
251 {
252     return 0;
253 }
254
255 void StorageAreaImpl::incrementAccessCount()
256 {
257     m_accessCount++;
258
259     if (m_closeDatabaseTimer.isActive())
260         m_closeDatabaseTimer.stop();
261 }
262
263 void StorageAreaImpl::decrementAccessCount()
264 {
265     ASSERT(m_accessCount);
266     --m_accessCount;
267
268     if (!m_accessCount) {
269         if (m_closeDatabaseTimer.isActive())
270             m_closeDatabaseTimer.stop();
271         m_closeDatabaseTimer.startOneShot(StorageTracker::tracker().storageDatabaseIdleInterval());
272     }
273 }
274
275 void StorageAreaImpl::closeDatabaseTimerFired()
276 {
277     blockUntilImportComplete();
278     if (m_storageAreaSync)
279         m_storageAreaSync->scheduleCloseDatabase();
280 }
281
282 void StorageAreaImpl::closeDatabaseIfIdle()
283 {
284     if (m_closeDatabaseTimer.isActive()) {
285         ASSERT(!m_accessCount);
286         m_closeDatabaseTimer.stop();
287
288         closeDatabaseTimerFired();
289     }
290 }
291
292 void StorageAreaImpl::dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame)
293 {
294     if (m_storageType == LocalStorage)
295         StorageEventDispatcher::dispatchLocalStorageEvents(key, oldValue, newValue, m_securityOrigin.get(), sourceFrame);
296     else
297         StorageEventDispatcher::dispatchSessionStorageEvents(key, oldValue, newValue, m_securityOrigin.get(), sourceFrame);
298 }
299
300 } // namespace WebCore