Add WTF::move()
[WebKit-https.git] / Source / WebKit2 / UIProcess / Storage / StorageManager.cpp
1 /*
2  * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "StorageManager.h"
28
29 #include "LocalStorageDatabase.h"
30 #include "LocalStorageDatabaseTracker.h"
31 #include "LocalStorageDetails.h"
32 #include "SecurityOriginData.h"
33 #include "StorageAreaMapMessages.h"
34 #include "StorageManagerMessages.h"
35 #include "WebProcessProxy.h"
36 #include "WorkQueue.h"
37 #include <WebCore/SecurityOriginHash.h>
38 #include <WebCore/StorageMap.h>
39 #include <WebCore/TextEncoding.h>
40 #include <memory>
41 #include <wtf/threads/BinarySemaphore.h>
42
43 using namespace WebCore;
44
45 namespace WebKit {
46
47 class StorageManager::StorageArea : public ThreadSafeRefCounted<StorageManager::StorageArea> {
48 public:
49     static PassRefPtr<StorageArea> create(LocalStorageNamespace*, PassRefPtr<SecurityOrigin>, unsigned quotaInBytes);
50     ~StorageArea();
51
52     SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); }
53
54     void addListener(IPC::Connection*, uint64_t storageMapID);
55     void removeListener(IPC::Connection*, uint64_t storageMapID);
56
57     PassRefPtr<StorageArea> clone() const;
58
59     void setItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException);
60     void removeItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString);
61     void clear(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& urlString);
62
63     const HashMap<String, String>& items();
64     void clear();
65
66 private:
67     explicit StorageArea(LocalStorageNamespace*, PassRefPtr<SecurityOrigin>, unsigned quotaInBytes);
68
69     void openDatabaseAndImportItemsIfNeeded();
70
71     void dispatchEvents(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const;
72
73     // Will be null if the storage area belongs to a session storage namespace.
74     LocalStorageNamespace* m_localStorageNamespace;
75     RefPtr<LocalStorageDatabase> m_localStorageDatabase;
76     bool m_didImportItemsFromDatabase;
77
78     RefPtr<SecurityOrigin> m_securityOrigin;
79     unsigned m_quotaInBytes;
80
81     RefPtr<StorageMap> m_storageMap;
82     HashSet<std::pair<RefPtr<IPC::Connection>, uint64_t>> m_eventListeners;
83 };
84
85 class StorageManager::LocalStorageNamespace : public ThreadSafeRefCounted<LocalStorageNamespace> {
86 public:
87     static PassRefPtr<LocalStorageNamespace> create(StorageManager*, uint64_t storageManagerID);
88     ~LocalStorageNamespace();
89
90     StorageManager* storageManager() const { return m_storageManager; }
91
92     PassRefPtr<StorageArea> getOrCreateStorageArea(PassRefPtr<SecurityOrigin>);
93     void didDestroyStorageArea(StorageArea*);
94
95     void clearStorageAreasMatchingOrigin(SecurityOrigin*);
96     void clearAllStorageAreas();
97
98 private:
99     explicit LocalStorageNamespace(StorageManager*, uint64_t storageManagerID);
100
101     StorageManager* m_storageManager;
102     uint64_t m_storageNamespaceID;
103     unsigned m_quotaInBytes;
104
105     // We don't hold an explicit reference to the StorageAreas; they are kept alive by the m_storageAreasByConnection map in StorageManager.
106     HashMap<RefPtr<SecurityOrigin>, StorageArea*> m_storageAreaMap;
107 };
108
109 PassRefPtr<StorageManager::StorageArea> StorageManager::StorageArea::create(LocalStorageNamespace* localStorageNamespace, PassRefPtr<SecurityOrigin> securityOrigin, unsigned quotaInBytes)
110 {
111     return adoptRef(new StorageArea(localStorageNamespace, securityOrigin, quotaInBytes));
112 }
113
114 StorageManager::StorageArea::StorageArea(LocalStorageNamespace* localStorageNamespace, PassRefPtr<SecurityOrigin> securityOrigin, unsigned quotaInBytes)
115     : m_localStorageNamespace(localStorageNamespace)
116     , m_didImportItemsFromDatabase(false)
117     , m_securityOrigin(securityOrigin)
118     , m_quotaInBytes(quotaInBytes)
119     , m_storageMap(StorageMap::create(m_quotaInBytes))
120 {
121 }
122
123 StorageManager::StorageArea::~StorageArea()
124 {
125     ASSERT(m_eventListeners.isEmpty());
126
127     if (m_localStorageDatabase)
128         m_localStorageDatabase->close();
129
130     if (m_localStorageNamespace)
131         m_localStorageNamespace->didDestroyStorageArea(this);
132 }
133
134 void StorageManager::StorageArea::addListener(IPC::Connection* connection, uint64_t storageMapID)
135 {
136     ASSERT(!m_eventListeners.contains(std::make_pair(connection, storageMapID)));
137     m_eventListeners.add(std::make_pair(connection, storageMapID));
138 }
139
140 void StorageManager::StorageArea::removeListener(IPC::Connection* connection, uint64_t storageMapID)
141 {
142     ASSERT(m_eventListeners.contains(std::make_pair(connection, storageMapID)));
143     m_eventListeners.remove(std::make_pair(connection, storageMapID));
144 }
145
146 PassRefPtr<StorageManager::StorageArea> StorageManager::StorageArea::clone() const
147 {
148     ASSERT(!m_localStorageNamespace);
149
150     RefPtr<StorageArea> storageArea = StorageArea::create(0, m_securityOrigin, m_quotaInBytes);
151     storageArea->m_storageMap = m_storageMap;
152
153     return storageArea.release();
154 }
155
156 void StorageManager::StorageArea::setItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException)
157 {
158     openDatabaseAndImportItemsIfNeeded();
159
160     String oldValue;
161
162     RefPtr<StorageMap> newStorageMap = m_storageMap->setItem(key, value, oldValue, quotaException);
163     if (newStorageMap)
164         m_storageMap = newStorageMap.release();
165
166     if (quotaException)
167         return;
168
169     if (m_localStorageDatabase)
170         m_localStorageDatabase->setItem(key, value);
171
172     dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, value, urlString);
173 }
174
175 void StorageManager::StorageArea::removeItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString)
176 {
177     openDatabaseAndImportItemsIfNeeded();
178
179     String oldValue;
180     RefPtr<StorageMap> newStorageMap = m_storageMap->removeItem(key, oldValue);
181     if (newStorageMap)
182         m_storageMap = newStorageMap.release();
183
184     if (oldValue.isNull())
185         return;
186
187     if (m_localStorageDatabase)
188         m_localStorageDatabase->removeItem(key);
189
190     dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, String(), urlString);
191 }
192
193 void StorageManager::StorageArea::clear(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& urlString)
194 {
195     openDatabaseAndImportItemsIfNeeded();
196
197     if (!m_storageMap->length())
198         return;
199
200     m_storageMap = StorageMap::create(m_quotaInBytes);
201
202     if (m_localStorageDatabase)
203         m_localStorageDatabase->clear();
204
205     dispatchEvents(sourceConnection, sourceStorageAreaID, String(), String(), String(), urlString);
206 }
207
208 const HashMap<String, String>& StorageManager::StorageArea::items()
209 {
210     openDatabaseAndImportItemsIfNeeded();
211
212     return m_storageMap->items();
213 }
214
215 void StorageManager::StorageArea::clear()
216 {
217     m_storageMap = StorageMap::create(m_quotaInBytes);
218
219     if (m_localStorageDatabase) {
220         m_localStorageDatabase->close();
221         m_localStorageDatabase = nullptr;
222     }
223
224     for (auto it = m_eventListeners.begin(), end = m_eventListeners.end(); it != end; ++it)
225         it->first->send(Messages::StorageAreaMap::ClearCache(), it->second);
226 }
227
228 void StorageManager::StorageArea::openDatabaseAndImportItemsIfNeeded()
229 {
230     if (!m_localStorageNamespace)
231         return;
232
233     // We open the database here even if we've already imported our items to ensure that the database is open if we need to write to it.
234     if (!m_localStorageDatabase)
235         m_localStorageDatabase = LocalStorageDatabase::create(m_localStorageNamespace->storageManager()->m_queue, m_localStorageNamespace->storageManager()->m_localStorageDatabaseTracker, m_securityOrigin.get());
236
237     if (m_didImportItemsFromDatabase)
238         return;
239
240     m_localStorageDatabase->importItems(*m_storageMap);
241     m_didImportItemsFromDatabase = true;
242 }
243
244 void StorageManager::StorageArea::dispatchEvents(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const
245 {
246     for (HashSet<std::pair<RefPtr<IPC::Connection>, uint64_t>>::const_iterator it = m_eventListeners.begin(), end = m_eventListeners.end(); it != end; ++it) {
247         uint64_t storageAreaID = it->first == sourceConnection ? sourceStorageAreaID : 0;
248
249         it->first->send(Messages::StorageAreaMap::DispatchStorageEvent(storageAreaID, key, oldValue, newValue, urlString), it->second);
250     }
251 }
252
253 PassRefPtr<StorageManager::LocalStorageNamespace> StorageManager::LocalStorageNamespace::create(StorageManager* storageManager, uint64_t storageNamespaceID)
254 {
255     return adoptRef(new LocalStorageNamespace(storageManager, storageNamespaceID));
256 }
257
258 // FIXME: The quota value is copied from GroupSettings.cpp.
259 // We should investigate a way to share it with WebCore.
260 StorageManager::LocalStorageNamespace::LocalStorageNamespace(StorageManager* storageManager, uint64_t storageNamespaceID)
261     : m_storageManager(storageManager)
262     , m_storageNamespaceID(storageNamespaceID)
263     , m_quotaInBytes(5 * 1024 * 1024)
264 {
265 }
266
267 StorageManager::LocalStorageNamespace::~LocalStorageNamespace()
268 {
269     ASSERT(m_storageAreaMap.isEmpty());
270 }
271
272 PassRefPtr<StorageManager::StorageArea> StorageManager::LocalStorageNamespace::getOrCreateStorageArea(PassRefPtr<SecurityOrigin> securityOrigin)
273 {
274     auto result = m_storageAreaMap.add(securityOrigin, nullptr);
275     if (!result.isNewEntry)
276         return result.iterator->value;
277
278     RefPtr<StorageArea> storageArea = StorageArea::create(this, result.iterator->key, m_quotaInBytes);
279     result.iterator->value = storageArea.get();
280
281     return storageArea.release();
282 }
283
284 void StorageManager::LocalStorageNamespace::didDestroyStorageArea(StorageArea* storageArea)
285 {
286     ASSERT(m_storageAreaMap.contains(storageArea->securityOrigin()));
287
288     m_storageAreaMap.remove(storageArea->securityOrigin());
289     if (!m_storageAreaMap.isEmpty())
290         return;
291
292     ASSERT(m_storageManager->m_localStorageNamespaces.contains(m_storageNamespaceID));
293     m_storageManager->m_localStorageNamespaces.remove(m_storageNamespaceID);
294 }
295
296 void StorageManager::LocalStorageNamespace::clearStorageAreasMatchingOrigin(SecurityOrigin* securityOrigin)
297 {
298     for (auto it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it) {
299         if (it->key->equal(securityOrigin))
300             it->value->clear();
301     }
302 }
303
304 void StorageManager::LocalStorageNamespace::clearAllStorageAreas()
305 {
306     for (auto it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it)
307         it->value->clear();
308 }
309
310 class StorageManager::SessionStorageNamespace : public ThreadSafeRefCounted<SessionStorageNamespace> {
311 public:
312     static PassRefPtr<SessionStorageNamespace> create(IPC::Connection* allowedConnection, unsigned quotaInBytes);
313     ~SessionStorageNamespace();
314
315     bool isEmpty() const { return m_storageAreaMap.isEmpty(); }
316
317     IPC::Connection* allowedConnection() const { return m_allowedConnection.get(); }
318     void setAllowedConnection(IPC::Connection*);
319
320     PassRefPtr<StorageArea> getOrCreateStorageArea(PassRefPtr<SecurityOrigin>);
321
322     void cloneTo(SessionStorageNamespace& newSessionStorageNamespace);
323
324 private:
325     SessionStorageNamespace(IPC::Connection* allowedConnection, unsigned quotaInBytes);
326
327     RefPtr<IPC::Connection> m_allowedConnection;
328     unsigned m_quotaInBytes;
329
330     HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageArea>> m_storageAreaMap;
331 };
332
333 PassRefPtr<StorageManager::SessionStorageNamespace> StorageManager::SessionStorageNamespace::create(IPC::Connection* allowedConnection, unsigned quotaInBytes)
334 {
335     return adoptRef(new SessionStorageNamespace(allowedConnection, quotaInBytes));
336 }
337
338 StorageManager::SessionStorageNamespace::SessionStorageNamespace(IPC::Connection* allowedConnection, unsigned quotaInBytes)
339     : m_allowedConnection(allowedConnection)
340     , m_quotaInBytes(quotaInBytes)
341 {
342 }
343
344 StorageManager::SessionStorageNamespace::~SessionStorageNamespace()
345 {
346 }
347
348 void StorageManager::SessionStorageNamespace::setAllowedConnection(IPC::Connection* allowedConnection)
349 {
350     ASSERT(!allowedConnection || !m_allowedConnection);
351
352     m_allowedConnection = allowedConnection;
353 }
354
355 PassRefPtr<StorageManager::StorageArea> StorageManager::SessionStorageNamespace::getOrCreateStorageArea(PassRefPtr<SecurityOrigin> securityOrigin)
356 {
357     auto result = m_storageAreaMap.add(securityOrigin, nullptr);
358     if (result.isNewEntry)
359         result.iterator->value = StorageArea::create(0, result.iterator->key, m_quotaInBytes);
360
361     return result.iterator->value;
362 }
363
364 void StorageManager::SessionStorageNamespace::cloneTo(SessionStorageNamespace& newSessionStorageNamespace)
365 {
366     ASSERT_UNUSED(newSessionStorageNamespace, newSessionStorageNamespace.isEmpty());
367
368     for (HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageArea>>::const_iterator it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it)
369         newSessionStorageNamespace.m_storageAreaMap.add(it->key, it->value->clone());
370 }
371
372 PassRefPtr<StorageManager> StorageManager::create(const String& localStorageDirectory)
373 {
374     return adoptRef(new StorageManager(localStorageDirectory));
375 }
376
377 StorageManager::StorageManager(const String& localStorageDirectory)
378     : m_queue(WorkQueue::create("com.apple.WebKit.StorageManager"))
379     , m_localStorageDatabaseTracker(LocalStorageDatabaseTracker::create(m_queue, localStorageDirectory))
380 {
381     // Make sure the encoding is initialized before we start dispatching things to the queue.
382     UTF8Encoding();
383 }
384
385 StorageManager::~StorageManager()
386 {
387 }
388
389 void StorageManager::createSessionStorageNamespace(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes)
390 {
391     m_queue->dispatch(bind(&StorageManager::createSessionStorageNamespaceInternal, this, storageNamespaceID, RefPtr<IPC::Connection>(allowedConnection), quotaInBytes));
392 }
393
394 void StorageManager::destroySessionStorageNamespace(uint64_t storageNamespaceID)
395 {
396     m_queue->dispatch(bind(&StorageManager::destroySessionStorageNamespaceInternal, this, storageNamespaceID));
397 }
398
399 void StorageManager::setAllowedSessionStorageNamespaceConnection(uint64_t storageNamespaceID, IPC::Connection* allowedConnection)
400 {
401     m_queue->dispatch(bind(&StorageManager::setAllowedSessionStorageNamespaceConnectionInternal, this, storageNamespaceID, RefPtr<IPC::Connection>(allowedConnection)));
402 }
403
404 void StorageManager::cloneSessionStorageNamespace(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID)
405 {
406     m_queue->dispatch(bind(&StorageManager::cloneSessionStorageNamespaceInternal, this, storageNamespaceID, newStorageNamespaceID));
407 }
408
409 void StorageManager::processWillOpenConnection(WebProcessProxy* webProcessProxy)
410 {
411     webProcessProxy->connection()->addWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName(), m_queue.get(), this);
412 }
413
414 void StorageManager::processWillCloseConnection(WebProcessProxy* webProcessProxy)
415 {
416     webProcessProxy->connection()->removeWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName());
417
418     m_queue->dispatch(bind(&StorageManager::invalidateConnectionInternal, this, RefPtr<IPC::Connection>(webProcessProxy->connection())));
419 }
420
421 void StorageManager::getOrigins(FunctionDispatcher& callbackDispatcher, void* context, void (*callback)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context))
422 {
423     m_queue->dispatch(bind(&StorageManager::getOriginsInternal, this, RefPtr<FunctionDispatcher>(&callbackDispatcher), context, callback));
424 }
425
426 void StorageManager::getStorageDetailsByOrigin(FunctionDispatcher& callbackDispatcher, void* context, void (*callback)(const Vector<LocalStorageDetails>& storageDetails, void* context))
427 {
428     m_queue->dispatch(bind(&StorageManager::getStorageDetailsByOriginInternal, this, RefPtr<FunctionDispatcher>(&callbackDispatcher), context, callback));
429 }
430
431 void StorageManager::deleteEntriesForOrigin(const SecurityOrigin& securityOrigin)
432 {
433     m_queue->dispatch(bind(&StorageManager::deleteEntriesForOriginInternal, this, RefPtr<SecurityOrigin>(const_cast<SecurityOrigin*>(&securityOrigin))));
434 }
435
436 void StorageManager::deleteAllEntries()
437 {
438     m_queue->dispatch(bind(&StorageManager::deleteAllEntriesInternal, this));
439 }
440
441 void StorageManager::createLocalStorageMap(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData& securityOriginData)
442 {
443     std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID);
444
445     // FIXME: This should be a message check.
446     ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair)));
447
448     HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::AddResult result = m_storageAreasByConnection.add(connectionAndStorageMapIDPair, nullptr);
449
450     // FIXME: These should be a message checks.
451     ASSERT(result.isNewEntry);
452     ASSERT((HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::isValidKey(storageNamespaceID)));
453
454     LocalStorageNamespace* localStorageNamespace = getOrCreateLocalStorageNamespace(storageNamespaceID);
455
456     // FIXME: This should be a message check.
457     ASSERT(localStorageNamespace);
458
459     RefPtr<StorageArea> storageArea = localStorageNamespace->getOrCreateStorageArea(securityOriginData.securityOrigin());
460     storageArea->addListener(connection, storageMapID);
461
462     result.iterator->value = storageArea.release();
463 }
464
465 void StorageManager::createSessionStorageMap(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData& securityOriginData)
466 {
467     // FIXME: This should be a message check.
468     ASSERT((HashMap<uint64_t, RefPtr<SessionStorageNamespace>>::isValidKey(storageNamespaceID)));
469     SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID);
470     if (!sessionStorageNamespace) {
471         // We're getting an incoming message from the web process that's for session storage for a web page
472         // that has already been closed, just ignore it.
473         return;
474     }
475
476     std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID);
477
478     // FIXME: This should be a message check.
479     ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair)));
480
481     HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::AddResult result = m_storageAreasByConnection.add(connectionAndStorageMapIDPair, nullptr);
482
483     // FIXME: This should be a message check.
484     ASSERT(result.isNewEntry);
485
486     // FIXME: This should be a message check.
487     ASSERT(connection == sessionStorageNamespace->allowedConnection());
488
489     RefPtr<StorageArea> storageArea = sessionStorageNamespace->getOrCreateStorageArea(securityOriginData.securityOrigin());
490     storageArea->addListener(connection, storageMapID);
491
492     result.iterator->value = storageArea.release();
493 }
494
495 void StorageManager::destroyStorageMap(IPC::Connection* connection, uint64_t storageMapID)
496 {
497     std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID);
498
499     // FIXME: This should be a message check.
500     ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair)));
501
502     HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::iterator it = m_storageAreasByConnection.find(connectionAndStorageMapIDPair);
503     if (it == m_storageAreasByConnection.end()) {
504         // The connection has been removed because the last page was closed.
505         return;
506     }
507
508     it->value->removeListener(connection, storageMapID);
509     m_storageAreasByConnection.remove(connectionAndStorageMapIDPair);
510 }
511
512 void StorageManager::getValues(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values)
513 {
514     StorageArea* storageArea = findStorageArea(connection, storageMapID);
515     if (!storageArea) {
516         // This is a session storage area for a page that has already been closed. Ignore it.
517         return;
518     }
519
520     values = storageArea->items();
521     connection->send(Messages::StorageAreaMap::DidGetValues(storageMapSeed), storageMapID);
522 }
523
524 void StorageManager::setItem(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString)
525 {
526     StorageArea* storageArea = findStorageArea(connection, storageMapID);
527     if (!storageArea) {
528         // This is a session storage area for a page that has already been closed. Ignore it.
529         return;
530     }
531
532     bool quotaError;
533     storageArea->setItem(connection, sourceStorageAreaID, key, value, urlString, quotaError);
534     connection->send(Messages::StorageAreaMap::DidSetItem(storageMapSeed, key, quotaError), storageMapID);
535 }
536
537 void StorageManager::removeItem(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString)
538 {
539     StorageArea* storageArea = findStorageArea(connection, storageMapID);
540     if (!storageArea) {
541         // This is a session storage area for a page that has already been closed. Ignore it.
542         return;
543     }
544
545     storageArea->removeItem(connection, sourceStorageAreaID, key, urlString);
546     connection->send(Messages::StorageAreaMap::DidRemoveItem(storageMapSeed, key), storageMapID);
547 }
548
549 void StorageManager::clear(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString)
550 {
551     StorageArea* storageArea = findStorageArea(connection, storageMapID);
552     if (!storageArea) {
553         // This is a session storage area for a page that has already been closed. Ignore it.
554         return;
555     }
556
557     storageArea->clear(connection, sourceStorageAreaID, urlString);
558     connection->send(Messages::StorageAreaMap::DidClear(storageMapSeed), storageMapID);
559 }
560
561 void StorageManager::createSessionStorageNamespaceInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes)
562 {
563     ASSERT(!m_sessionStorageNamespaces.contains(storageNamespaceID));
564
565     m_sessionStorageNamespaces.set(storageNamespaceID, SessionStorageNamespace::create(allowedConnection, quotaInBytes));
566 }
567
568 void StorageManager::destroySessionStorageNamespaceInternal(uint64_t storageNamespaceID)
569 {
570     ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID));
571     m_sessionStorageNamespaces.remove(storageNamespaceID);
572 }
573
574 void StorageManager::setAllowedSessionStorageNamespaceConnectionInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection)
575 {
576     ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID));
577
578     m_sessionStorageNamespaces.get(storageNamespaceID)->setAllowedConnection(allowedConnection);
579 }
580
581 void StorageManager::cloneSessionStorageNamespaceInternal(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID)
582 {
583     SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID);
584     ASSERT(sessionStorageNamespace);
585
586     SessionStorageNamespace* newSessionStorageNamespace = m_sessionStorageNamespaces.get(newStorageNamespaceID);
587     ASSERT(newSessionStorageNamespace);
588
589     sessionStorageNamespace->cloneTo(*newSessionStorageNamespace);
590 }
591
592 void StorageManager::applicationWillTerminate()
593 {
594     BinarySemaphore semaphore;
595     m_queue->dispatch([this, &semaphore] {
596         Vector<std::pair<RefPtr<IPC::Connection>, uint64_t>> connectionAndStorageMapIDPairsToRemove;
597         for (auto& connectionStorageAreaPair : m_storageAreasByConnection) {
598             connectionStorageAreaPair.value->removeListener(connectionStorageAreaPair.key.first.get(), connectionStorageAreaPair.key.second);
599             connectionAndStorageMapIDPairsToRemove.append(connectionStorageAreaPair.key);
600         }
601
602         for (auto& connectionStorageAreaPair : connectionAndStorageMapIDPairsToRemove)
603             m_storageAreasByConnection.remove(connectionStorageAreaPair);
604
605         semaphore.signal();
606     });
607     semaphore.wait(std::numeric_limits<double>::max());
608 }
609
610 void StorageManager::invalidateConnectionInternal(IPC::Connection* connection)
611 {
612     Vector<std::pair<RefPtr<IPC::Connection>, uint64_t>> connectionAndStorageMapIDPairsToRemove;
613     HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>> storageAreasByConnection = m_storageAreasByConnection;
614     for (HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::const_iterator it = storageAreasByConnection.begin(), end = storageAreasByConnection.end(); it != end; ++it) {
615         if (it->key.first != connection)
616             continue;
617
618         it->value->removeListener(it->key.first.get(), it->key.second);
619         connectionAndStorageMapIDPairsToRemove.append(it->key);
620     }
621
622     for (size_t i = 0; i < connectionAndStorageMapIDPairsToRemove.size(); ++i)
623         m_storageAreasByConnection.remove(connectionAndStorageMapIDPairsToRemove[i]);
624 }
625
626 StorageManager::StorageArea* StorageManager::findStorageArea(IPC::Connection* connection, uint64_t storageMapID) const
627 {
628     std::pair<IPC::Connection*, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID);
629     if (!HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair))
630         return 0;
631
632     return m_storageAreasByConnection.get(connectionAndStorageMapIDPair);
633 }
634
635 StorageManager::LocalStorageNamespace* StorageManager::getOrCreateLocalStorageNamespace(uint64_t storageNamespaceID)
636 {
637     if (!HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::isValidKey(storageNamespaceID))
638         return 0;
639
640     HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::AddResult result = m_localStorageNamespaces.add(storageNamespaceID, nullptr);
641     if (result.isNewEntry)
642         result.iterator->value = LocalStorageNamespace::create(this, storageNamespaceID);
643
644     return result.iterator->value.get();
645 }
646
647 static void callCallbackFunction(void* context, void (*callbackFunction)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context), Vector<RefPtr<WebCore::SecurityOrigin>>* securityOriginsPtr)
648 {
649     std::unique_ptr<Vector<RefPtr<WebCore::SecurityOrigin>>> securityOrigins(securityOriginsPtr);
650     callbackFunction(*securityOrigins, context);
651 }
652
653 void StorageManager::getOriginsInternal(FunctionDispatcher* dispatcher, void* context, void (*callbackFunction)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context))
654 {
655     auto securityOrigins = std::make_unique<Vector<RefPtr<WebCore::SecurityOrigin>>>(m_localStorageDatabaseTracker->origins());
656     dispatcher->dispatch(bind(callCallbackFunction, context, callbackFunction, securityOrigins.release()));
657 }
658
659 void StorageManager::getStorageDetailsByOriginInternal(FunctionDispatcher* dispatcher, void* context, void (*callbackFunction)(const Vector<LocalStorageDetails>& storageDetails, void* context))
660 {
661     Vector<LocalStorageDetails> storageDetails = m_localStorageDatabaseTracker->details();
662     dispatcher->dispatch(bind(callbackFunction, WTF::move(storageDetails), context));
663 }
664
665 void StorageManager::deleteEntriesForOriginInternal(SecurityOrigin* securityOrigin)
666 {
667     for (auto it = m_localStorageNamespaces.begin(), end = m_localStorageNamespaces.end(); it != end; ++it)
668         it->value->clearStorageAreasMatchingOrigin(securityOrigin);
669
670     m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(securityOrigin);
671 }
672
673 void StorageManager::deleteAllEntriesInternal()
674 {
675     for (auto it = m_localStorageNamespaces.begin(), end = m_localStorageNamespaces.end(); it != end; ++it)
676         it->value->clearAllStorageAreas();
677
678     m_localStorageDatabaseTracker->deleteAllDatabases();
679 }
680
681
682 } // namespace WebKit