2152ed7d8020f0ac5f26ca0a20ddfa6e86b3c5b7
[WebKit-https.git] / Source / WebKit / UIProcess / WebStorage / StorageManager.cpp
1 /*
2  * Copyright (C) 2013-2016 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 "StorageAreaMapMessages.h"
32 #include "StorageManagerMessages.h"
33 #include "WebProcessProxy.h"
34 #include <WebCore/SecurityOriginData.h>
35 #include <WebCore/SecurityOriginHash.h>
36 #include <WebCore/StorageMap.h>
37 #include <WebCore/TextEncoding.h>
38 #include <memory>
39 #include <wtf/WorkQueue.h>
40 #include <wtf/threads/BinarySemaphore.h>
41
42 namespace WebKit {
43 using namespace WebCore;
44
45 class StorageManager::StorageArea : public ThreadSafeRefCounted<StorageManager::StorageArea> {
46 public:
47     static Ref<StorageArea> create(LocalStorageNamespace*, const SecurityOriginData&, unsigned quotaInBytes);
48     ~StorageArea();
49
50     const WebCore::SecurityOriginData& securityOrigin() const { return m_securityOrigin; }
51
52     void addListener(IPC::Connection::UniqueID, uint64_t storageMapID);
53     void removeListener(IPC::Connection::UniqueID, uint64_t storageMapID);
54     bool hasListener(IPC::Connection::UniqueID, uint64_t storageMapID) const;
55
56     Ref<StorageArea> clone() const;
57
58     void setItem(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException);
59     void removeItem(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString);
60     void clear(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& urlString);
61
62     const HashMap<String, String>& items() const;
63     void clear();
64
65     bool isSessionStorage() const { return !m_localStorageNamespace; }
66
67 private:
68     explicit StorageArea(LocalStorageNamespace*, const SecurityOriginData&, unsigned quotaInBytes);
69
70     void openDatabaseAndImportItemsIfNeeded() const;
71
72     void dispatchEvents(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const;
73
74     // Will be null if the storage area belongs to a session storage namespace.
75     LocalStorageNamespace* m_localStorageNamespace;
76     mutable RefPtr<LocalStorageDatabase> m_localStorageDatabase;
77     mutable bool m_didImportItemsFromDatabase { false };
78
79     SecurityOriginData m_securityOrigin;
80     unsigned m_quotaInBytes;
81
82     RefPtr<StorageMap> m_storageMap;
83     HashSet<std::pair<IPC::Connection::UniqueID, uint64_t>> m_eventListeners;
84 };
85
86 class StorageManager::LocalStorageNamespace : public ThreadSafeRefCounted<LocalStorageNamespace> {
87 public:
88     static Ref<LocalStorageNamespace> create(StorageManager*, uint64_t storageManagerID);
89     ~LocalStorageNamespace();
90
91     StorageManager* storageManager() const { return m_storageManager; }
92
93     Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&&);
94     void didDestroyStorageArea(StorageArea*);
95
96     void clearStorageAreasMatchingOrigin(const SecurityOriginData&);
97     void clearAllStorageAreas();
98
99 private:
100     explicit LocalStorageNamespace(StorageManager*, uint64_t storageManagerID);
101
102     StorageManager* m_storageManager;
103     uint64_t m_storageNamespaceID;
104     unsigned m_quotaInBytes;
105
106     // We don't hold an explicit reference to the StorageAreas; they are kept alive by the m_storageAreasByConnection map in StorageManager.
107     HashMap<SecurityOriginData, StorageArea*> m_storageAreaMap;
108 };
109
110 class StorageManager::TransientLocalStorageNamespace : public ThreadSafeRefCounted<TransientLocalStorageNamespace> {
111 public:
112     static Ref<TransientLocalStorageNamespace> create()
113     {
114         return adoptRef(*new TransientLocalStorageNamespace());
115     }
116
117     ~TransientLocalStorageNamespace()
118     {
119     }
120
121     Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&& securityOrigin)
122     {
123         return *m_storageAreaMap.ensure(securityOrigin, [this, securityOrigin]() mutable {
124             return StorageArea::create(nullptr, WTFMove(securityOrigin), m_quotaInBytes);
125         }).iterator->value.copyRef();
126     }
127
128     Vector<SecurityOriginData> origins() const
129     {
130         Vector<SecurityOriginData> origins;
131
132         for (const auto& storageArea : m_storageAreaMap.values()) {
133             if (!storageArea->items().isEmpty())
134                 origins.append(storageArea->securityOrigin());
135         }
136
137         return origins;
138     }
139
140     void clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin)
141     {
142         for (auto& storageArea : m_storageAreaMap.values()) {
143             if (storageArea->securityOrigin() == securityOrigin)
144                 storageArea->clear();
145         }
146     }
147
148     void clearAllStorageAreas()
149     {
150         for (auto& storageArea : m_storageAreaMap.values())
151             storageArea->clear();
152     }
153
154 private:
155     explicit TransientLocalStorageNamespace()
156     {
157     }
158
159     const unsigned m_quotaInBytes = 5 * 1024 * 1024;
160
161     HashMap<SecurityOriginData, RefPtr<StorageArea>> m_storageAreaMap;
162 };
163
164 auto StorageManager::StorageArea::create(LocalStorageNamespace* localStorageNamespace, const SecurityOriginData& securityOrigin, unsigned quotaInBytes) -> Ref<StorageManager::StorageArea>
165 {
166     return adoptRef(*new StorageArea(localStorageNamespace, securityOrigin, quotaInBytes));
167 }
168
169 StorageManager::StorageArea::StorageArea(LocalStorageNamespace* localStorageNamespace, const SecurityOriginData& securityOrigin, unsigned quotaInBytes)
170     : m_localStorageNamespace(localStorageNamespace)
171     , m_securityOrigin(securityOrigin)
172     , m_quotaInBytes(quotaInBytes)
173     , m_storageMap(StorageMap::create(m_quotaInBytes))
174 {
175 }
176
177 StorageManager::StorageArea::~StorageArea()
178 {
179     ASSERT(m_eventListeners.isEmpty());
180
181     if (m_localStorageDatabase)
182         m_localStorageDatabase->close();
183
184     if (m_localStorageNamespace)
185         m_localStorageNamespace->didDestroyStorageArea(this);
186 }
187
188 void StorageManager::StorageArea::addListener(IPC::Connection::UniqueID connectionID, uint64_t storageMapID)
189 {
190     ASSERT(!m_eventListeners.contains(std::make_pair(connectionID, storageMapID)));
191     m_eventListeners.add(std::make_pair(connectionID, storageMapID));
192 }
193
194 void StorageManager::StorageArea::removeListener(IPC::Connection::UniqueID connectionID, uint64_t storageMapID)
195 {
196     ASSERT(isSessionStorage() || m_eventListeners.contains(std::make_pair(connectionID, storageMapID)));
197     m_eventListeners.remove(std::make_pair(connectionID, storageMapID));
198 }
199
200 bool StorageManager::StorageArea::hasListener(IPC::Connection::UniqueID connectionID, uint64_t storageMapID) const
201 {
202     return m_eventListeners.contains(std::make_pair(connectionID, storageMapID));
203 }
204
205 Ref<StorageManager::StorageArea> StorageManager::StorageArea::clone() const
206 {
207     ASSERT(!m_localStorageNamespace);
208
209     auto storageArea = StorageArea::create(nullptr, m_securityOrigin, m_quotaInBytes);
210     storageArea->m_storageMap = m_storageMap;
211
212     return storageArea;
213 }
214
215 void StorageManager::StorageArea::setItem(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException)
216 {
217     openDatabaseAndImportItemsIfNeeded();
218
219     String oldValue;
220
221     auto newStorageMap = m_storageMap->setItem(key, value, oldValue, quotaException);
222     if (newStorageMap)
223         m_storageMap = WTFMove(newStorageMap);
224
225     if (quotaException)
226         return;
227
228     if (m_localStorageDatabase)
229         m_localStorageDatabase->setItem(key, value);
230
231     dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, value, urlString);
232 }
233
234 void StorageManager::StorageArea::removeItem(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString)
235 {
236     openDatabaseAndImportItemsIfNeeded();
237
238     String oldValue;
239     auto newStorageMap = m_storageMap->removeItem(key, oldValue);
240     if (newStorageMap)
241         m_storageMap = WTFMove(newStorageMap);
242
243     if (oldValue.isNull())
244         return;
245
246     if (m_localStorageDatabase)
247         m_localStorageDatabase->removeItem(key);
248
249     dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, String(), urlString);
250 }
251
252 void StorageManager::StorageArea::clear(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& urlString)
253 {
254     openDatabaseAndImportItemsIfNeeded();
255
256     if (!m_storageMap->length())
257         return;
258
259     m_storageMap = StorageMap::create(m_quotaInBytes);
260
261     if (m_localStorageDatabase)
262         m_localStorageDatabase->clear();
263
264     dispatchEvents(sourceConnection, sourceStorageAreaID, String(), String(), String(), urlString);
265 }
266
267 const HashMap<String, String>& StorageManager::StorageArea::items() const
268 {
269     openDatabaseAndImportItemsIfNeeded();
270
271     return m_storageMap->items();
272 }
273
274 void StorageManager::StorageArea::clear()
275 {
276     m_storageMap = StorageMap::create(m_quotaInBytes);
277
278     if (m_localStorageDatabase) {
279         m_localStorageDatabase->close();
280         m_localStorageDatabase = nullptr;
281     }
282
283     for (auto it = m_eventListeners.begin(), end = m_eventListeners.end(); it != end; ++it) {
284         RunLoop::main().dispatch([connectionID = it->first, destinationStorageAreaID = it->second] {
285             if (auto* connection = IPC::Connection::connection(connectionID))
286                 connection->send(Messages::StorageAreaMap::ClearCache(), destinationStorageAreaID);
287         });
288     }
289 }
290
291 void StorageManager::StorageArea::openDatabaseAndImportItemsIfNeeded() const
292 {
293     if (!m_localStorageNamespace)
294         return;
295
296     // 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.
297     if (!m_localStorageDatabase)
298         m_localStorageDatabase = LocalStorageDatabase::create(m_localStorageNamespace->storageManager()->m_queue.copyRef(), m_localStorageNamespace->storageManager()->m_localStorageDatabaseTracker.copyRef(), m_securityOrigin);
299
300     if (m_didImportItemsFromDatabase)
301         return;
302
303     m_localStorageDatabase->importItems(*m_storageMap);
304     m_didImportItemsFromDatabase = true;
305 }
306
307 void StorageManager::StorageArea::dispatchEvents(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const
308 {
309     for (auto it = m_eventListeners.begin(), end = m_eventListeners.end(); it != end; ++it) {
310         sourceStorageAreaID = it->first == sourceConnection ? sourceStorageAreaID : 0;
311
312         RunLoop::main().dispatch([connectionID = it->first, sourceStorageAreaID, destinationStorageAreaID = it->second, key = key.isolatedCopy(), oldValue = oldValue.isolatedCopy(), newValue = newValue.isolatedCopy(), urlString = urlString.isolatedCopy()] {
313             if (auto* connection = IPC::Connection::connection(connectionID))
314                 connection->send(Messages::StorageAreaMap::DispatchStorageEvent(sourceStorageAreaID, key, oldValue, newValue, urlString), destinationStorageAreaID);
315         });
316     }
317 }
318
319 Ref<StorageManager::LocalStorageNamespace> StorageManager::LocalStorageNamespace::create(StorageManager* storageManager, uint64_t storageNamespaceID)
320 {
321     return adoptRef(*new LocalStorageNamespace(storageManager, storageNamespaceID));
322 }
323
324 // FIXME: The quota value is copied from GroupSettings.cpp.
325 // We should investigate a way to share it with WebCore.
326 StorageManager::LocalStorageNamespace::LocalStorageNamespace(StorageManager* storageManager, uint64_t storageNamespaceID)
327     : m_storageManager(storageManager)
328     , m_storageNamespaceID(storageNamespaceID)
329     , m_quotaInBytes(5 * 1024 * 1024)
330 {
331 }
332
333 StorageManager::LocalStorageNamespace::~LocalStorageNamespace()
334 {
335     ASSERT(m_storageAreaMap.isEmpty());
336 }
337
338 auto StorageManager::LocalStorageNamespace::getOrCreateStorageArea(SecurityOriginData&& securityOrigin) -> Ref<StorageArea>
339 {
340     auto& slot = m_storageAreaMap.add(securityOrigin, nullptr).iterator->value;
341     if (slot)
342         return *slot;
343
344     auto storageArea = StorageArea::create(this, WTFMove(securityOrigin), m_quotaInBytes);
345     slot = &storageArea.get();
346
347     return storageArea;
348 }
349
350 void StorageManager::LocalStorageNamespace::didDestroyStorageArea(StorageArea* storageArea)
351 {
352     ASSERT(m_storageAreaMap.contains(storageArea->securityOrigin()));
353
354     m_storageAreaMap.remove(storageArea->securityOrigin());
355     if (!m_storageAreaMap.isEmpty())
356         return;
357
358     ASSERT(m_storageManager->m_localStorageNamespaces.contains(m_storageNamespaceID));
359     m_storageManager->m_localStorageNamespaces.remove(m_storageNamespaceID);
360 }
361
362 void StorageManager::LocalStorageNamespace::clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin)
363 {
364     for (const auto& originAndStorageArea : m_storageAreaMap) {
365         if (originAndStorageArea.key == securityOrigin)
366             originAndStorageArea.value->clear();
367     }
368 }
369
370 void StorageManager::LocalStorageNamespace::clearAllStorageAreas()
371 {
372     for (auto* storageArea : m_storageAreaMap.values())
373         storageArea->clear();
374 }
375
376 class StorageManager::SessionStorageNamespace : public ThreadSafeRefCounted<SessionStorageNamespace> {
377 public:
378     static Ref<SessionStorageNamespace> create(unsigned quotaInBytes);
379     ~SessionStorageNamespace();
380
381     bool isEmpty() const { return m_storageAreaMap.isEmpty(); }
382
383     IPC::Connection::UniqueID allowedConnection() const { return m_allowedConnection; }
384     void setAllowedConnection(IPC::Connection::UniqueID);
385
386     Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&&);
387
388     void cloneTo(SessionStorageNamespace& newSessionStorageNamespace);
389
390     Vector<SecurityOriginData> origins() const
391     {
392         Vector<SecurityOriginData> origins;
393
394         for (const auto& storageArea : m_storageAreaMap.values()) {
395             if (!storageArea->items().isEmpty())
396                 origins.append(storageArea->securityOrigin());
397         }
398
399         return origins;
400     }
401
402     void clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin)
403     {
404         for (auto& storageArea : m_storageAreaMap.values()) {
405             if (storageArea->securityOrigin() == securityOrigin)
406                 storageArea->clear();
407         }
408     }
409
410     void clearAllStorageAreas()
411     {
412         for (auto& storageArea : m_storageAreaMap.values())
413             storageArea->clear();
414     }
415
416 private:
417     explicit SessionStorageNamespace(unsigned quotaInBytes);
418
419     IPC::Connection::UniqueID m_allowedConnection;
420     unsigned m_quotaInBytes;
421
422     HashMap<SecurityOriginData, RefPtr<StorageArea>> m_storageAreaMap;
423 };
424
425 Ref<StorageManager::SessionStorageNamespace> StorageManager::SessionStorageNamespace::create(unsigned quotaInBytes)
426 {
427     return adoptRef(*new SessionStorageNamespace(quotaInBytes));
428 }
429
430 StorageManager::SessionStorageNamespace::SessionStorageNamespace(unsigned quotaInBytes)
431     : m_quotaInBytes(quotaInBytes)
432 {
433 }
434
435 StorageManager::SessionStorageNamespace::~SessionStorageNamespace()
436 {
437 }
438
439 void StorageManager::SessionStorageNamespace::setAllowedConnection(IPC::Connection::UniqueID allowedConnection)
440 {
441     m_allowedConnection = allowedConnection;
442 }
443
444 auto StorageManager::SessionStorageNamespace::getOrCreateStorageArea(SecurityOriginData&& securityOrigin) -> Ref<StorageArea>
445 {
446     return *m_storageAreaMap.ensure(securityOrigin, [this, securityOrigin]() mutable {
447         return StorageArea::create(nullptr, WTFMove(securityOrigin), m_quotaInBytes);
448     }).iterator->value.copyRef();
449 }
450
451 void StorageManager::SessionStorageNamespace::cloneTo(SessionStorageNamespace& newSessionStorageNamespace)
452 {
453     ASSERT_UNUSED(newSessionStorageNamespace, newSessionStorageNamespace.isEmpty());
454
455     for (auto& pair : m_storageAreaMap)
456         newSessionStorageNamespace.m_storageAreaMap.add(pair.key, pair.value->clone());
457 }
458
459 Ref<StorageManager> StorageManager::create(const String& localStorageDirectory)
460 {
461     return adoptRef(*new StorageManager(localStorageDirectory));
462 }
463
464 StorageManager::StorageManager(const String& localStorageDirectory)
465     : m_queue(WorkQueue::create("com.apple.WebKit.StorageManager"))
466     , m_localStorageDatabaseTracker(LocalStorageDatabaseTracker::create(m_queue.copyRef(), localStorageDirectory))
467 {
468     // Make sure the encoding is initialized before we start dispatching things to the queue.
469     UTF8Encoding();
470 }
471
472 StorageManager::~StorageManager()
473 {
474 }
475
476 void StorageManager::createSessionStorageNamespace(uint64_t storageNamespaceID, unsigned quotaInBytes)
477 {
478     m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID, quotaInBytes]() mutable {
479         ASSERT(!m_sessionStorageNamespaces.contains(storageNamespaceID));
480
481         m_sessionStorageNamespaces.set(storageNamespaceID, SessionStorageNamespace::create(quotaInBytes));
482     });
483 }
484
485 void StorageManager::destroySessionStorageNamespace(uint64_t storageNamespaceID)
486 {
487     m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID] {
488         ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID));
489         m_sessionStorageNamespaces.remove(storageNamespaceID);
490     });
491 }
492
493 void StorageManager::setAllowedSessionStorageNamespaceConnection(uint64_t storageNamespaceID, IPC::Connection* allowedConnection)
494 {
495     auto allowedConnectionID = allowedConnection ? allowedConnection->uniqueID() : IPC::Connection::UniqueID { };
496     m_queue->dispatch([this, protectedThis = makeRef(*this), allowedConnectionID, storageNamespaceID]() mutable {
497         ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID));
498
499         m_sessionStorageNamespaces.get(storageNamespaceID)->setAllowedConnection(allowedConnectionID);
500     });
501 }
502
503 void StorageManager::cloneSessionStorageNamespace(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID)
504 {
505     m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID, newStorageNamespaceID] {
506         SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID);
507         if (!sessionStorageNamespace) {
508             // FIXME: We can get into this situation if someone closes the originating page from within a
509             // createNewPage callback. We bail for now, but we should really find a way to keep the session storage alive
510             // so we we'll clone the session storage correctly.
511             return;
512         }
513
514         SessionStorageNamespace* newSessionStorageNamespace = m_sessionStorageNamespaces.get(newStorageNamespaceID);
515         ASSERT(newSessionStorageNamespace);
516
517         sessionStorageNamespace->cloneTo(*newSessionStorageNamespace);
518     });
519 }
520
521 void StorageManager::processWillOpenConnection(WebProcessProxy&, IPC::Connection& connection)
522 {
523     connection.addWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName(), m_queue.get(), this);
524 }
525
526 void StorageManager::processDidCloseConnection(WebProcessProxy&, IPC::Connection& connection)
527 {
528     connection.removeWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName());
529
530     m_queue->dispatch([this, protectedThis = makeRef(*this), connectionID = connection.uniqueID()]() mutable {
531         Vector<std::pair<IPC::Connection::UniqueID, uint64_t>> connectionAndStorageMapIDPairsToRemove;
532         for (auto& storageArea : m_storageAreasByConnection) {
533             if (storageArea.key.first != connectionID)
534                 continue;
535
536             storageArea.value->removeListener(storageArea.key.first, storageArea.key.second);
537             connectionAndStorageMapIDPairsToRemove.append(storageArea.key);
538         }
539
540         for (auto& pair : connectionAndStorageMapIDPairsToRemove)
541             m_storageAreasByConnection.remove(pair);
542     });
543 }
544
545 void StorageManager::getSessionStorageOrigins(Function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler)
546 {
547     m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
548         HashSet<SecurityOriginData> origins;
549
550         for (const auto& sessionStorageNamespace : m_sessionStorageNamespaces.values()) {
551             for (auto& origin : sessionStorageNamespace->origins())
552                 origins.add(origin);
553         }
554
555         RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable {
556             completionHandler(WTFMove(origins));
557         });
558     });
559 }
560
561 void StorageManager::deleteSessionStorageOrigins(Function<void()>&& completionHandler)
562 {
563     m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
564         for (auto& sessionStorageNamespace : m_sessionStorageNamespaces.values())
565             sessionStorageNamespace->clearAllStorageAreas();
566
567         RunLoop::main().dispatch(WTFMove(completionHandler));
568     });
569 }
570
571 void StorageManager::deleteSessionStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>& origins, Function<void()>&& completionHandler)
572 {
573     Vector<WebCore::SecurityOriginData> copiedOrigins;
574     copiedOrigins.reserveInitialCapacity(origins.size());
575
576     for (auto& origin : origins)
577         copiedOrigins.uncheckedAppend(origin.isolatedCopy());
578
579     m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigins = WTFMove(copiedOrigins), completionHandler = WTFMove(completionHandler)]() mutable {
580         for (auto& origin : copiedOrigins) {
581             for (auto& sessionStorageNamespace : m_sessionStorageNamespaces.values())
582                 sessionStorageNamespace->clearStorageAreasMatchingOrigin(origin);
583         }
584
585         RunLoop::main().dispatch(WTFMove(completionHandler));
586     });
587 }
588
589 void StorageManager::getLocalStorageOrigins(Function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler)
590 {
591     m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
592         HashSet<SecurityOriginData> origins;
593
594         for (auto& origin : m_localStorageDatabaseTracker->origins())
595             origins.add(origin);
596
597         for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values()) {
598             for (auto& origin : transientLocalStorageNamespace->origins())
599                 origins.add(origin);
600         }
601
602         RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable {
603             completionHandler(WTFMove(origins));
604         });
605     });
606 }
607
608 void StorageManager::getLocalStorageOriginDetails(Function<void (Vector<LocalStorageDatabaseTracker::OriginDetails>)>&& completionHandler)
609 {
610     m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
611         auto originDetails = m_localStorageDatabaseTracker->originDetails();
612
613         RunLoop::main().dispatch([originDetails = WTFMove(originDetails), completionHandler = WTFMove(completionHandler)]() mutable {
614             completionHandler(WTFMove(originDetails));
615         });
616     });
617 }
618
619 void StorageManager::deleteLocalStorageEntriesForOrigin(const SecurityOriginData& securityOrigin)
620 {
621     m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigin = securityOrigin.isolatedCopy()]() mutable {
622         for (auto& localStorageNamespace : m_localStorageNamespaces.values())
623             localStorageNamespace->clearStorageAreasMatchingOrigin(copiedOrigin);
624
625         for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values())
626             transientLocalStorageNamespace->clearStorageAreasMatchingOrigin(copiedOrigin);
627
628         m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(copiedOrigin);
629     });
630 }
631
632 void StorageManager::deleteLocalStorageOriginsModifiedSince(WallTime time, Function<void()>&& completionHandler)
633 {
634     m_queue->dispatch([this, protectedThis = makeRef(*this), time, completionHandler = WTFMove(completionHandler)]() mutable {
635         auto originsToDelete = m_localStorageDatabaseTracker->databasesModifiedSince(time);
636         
637         for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values())
638             transientLocalStorageNamespace->clearAllStorageAreas();
639
640         for (const auto& origin : originsToDelete) {
641             for (auto& localStorageNamespace : m_localStorageNamespaces.values())
642                 localStorageNamespace->clearStorageAreasMatchingOrigin(origin);
643             
644             m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(origin);
645         }
646
647         RunLoop::main().dispatch(WTFMove(completionHandler));
648     });
649 }
650
651 void StorageManager::deleteLocalStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>& origins, Function<void()>&& completionHandler)
652 {
653     Vector<SecurityOriginData> copiedOrigins;
654     copiedOrigins.reserveInitialCapacity(origins.size());
655
656     for (auto& origin : origins)
657         copiedOrigins.uncheckedAppend(origin.isolatedCopy());
658
659     m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigins = WTFMove(copiedOrigins), completionHandler = WTFMove(completionHandler)]() mutable {
660         for (auto& origin : copiedOrigins) {
661             for (auto& localStorageNamespace : m_localStorageNamespaces.values())
662                 localStorageNamespace->clearStorageAreasMatchingOrigin(origin);
663
664             for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values())
665                 transientLocalStorageNamespace->clearStorageAreasMatchingOrigin(origin);
666
667             m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(origin);
668         }
669
670         RunLoop::main().dispatch(WTFMove(completionHandler));
671     });
672 }
673
674 void StorageManager::createLocalStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData)
675 {
676     std::pair<IPC::Connection::UniqueID, uint64_t> connectionAndStorageMapIDPair(connection.uniqueID(), storageMapID);
677
678     // FIXME: This should be a message check.
679     ASSERT((HashMap<std::pair<IPC::Connection::UniqueID, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair)));
680
681     auto result = m_storageAreasByConnection.add(connectionAndStorageMapIDPair, nullptr);
682
683     // FIXME: These should be a message checks.
684     ASSERT(result.isNewEntry);
685     ASSERT((HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::isValidKey(storageNamespaceID)));
686
687     LocalStorageNamespace* localStorageNamespace = getOrCreateLocalStorageNamespace(storageNamespaceID);
688
689     // FIXME: This should be a message check.
690     ASSERT(localStorageNamespace);
691
692     auto storageArea = localStorageNamespace->getOrCreateStorageArea(WTFMove(securityOriginData));
693     storageArea->addListener(connection.uniqueID(), storageMapID);
694
695     result.iterator->value = WTFMove(storageArea);
696 }
697
698 void StorageManager::createTransientLocalStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& topLevelOriginData, SecurityOriginData&& origin)
699 {
700     // FIXME: This should be a message check.
701     ASSERT(m_storageAreasByConnection.isValidKey({ connection.uniqueID(), storageMapID }));
702
703     // See if we already have session storage for this connection/origin combo.
704     // If so, update the map with the new ID, otherwise keep on trucking.
705     for (auto it = m_storageAreasByConnection.begin(), end = m_storageAreasByConnection.end(); it != end; ++it) {
706         if (it->key.first != connection.uniqueID())
707             continue;
708         Ref<StorageArea> area = *it->value;
709         if (!area->isSessionStorage())
710             continue;
711         if (!origin.securityOrigin()->isSameSchemeHostPort(area->securityOrigin().securityOrigin().get()))
712             continue;
713         area->addListener(connection.uniqueID(), storageMapID);
714         // If the storageMapID used as key in m_storageAreasByConnection is no longer one of the StorageArea's listeners, then this means
715         // that destroyStorageMap() was already called for that storageMapID but it decided not to remove it from m_storageAreasByConnection
716         // so that we could reuse it later on for the same connection/origin combo. In this case, it is safe to remove the previous
717         // storageMapID from m_storageAreasByConnection.
718         if (!area->hasListener(connection.uniqueID(), it->key.second))
719             m_storageAreasByConnection.remove(it);
720         m_storageAreasByConnection.add({ connection.uniqueID(), storageMapID }, WTFMove(area));
721         return;
722     }
723
724     auto& slot = m_storageAreasByConnection.add({ connection.uniqueID(), storageMapID }, nullptr).iterator->value;
725
726     // FIXME: This should be a message check.
727     ASSERT(!slot);
728
729     TransientLocalStorageNamespace* transientLocalStorageNamespace = getOrCreateTransientLocalStorageNamespace(storageNamespaceID, WTFMove(topLevelOriginData));
730
731     auto storageArea = transientLocalStorageNamespace->getOrCreateStorageArea(WTFMove(origin));
732     storageArea->addListener(connection.uniqueID(), storageMapID);
733
734     slot = WTFMove(storageArea);
735 }
736
737 void StorageManager::createSessionStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData)
738 {
739     // FIXME: This should be a message check.
740     ASSERT(m_sessionStorageNamespaces.isValidKey(storageNamespaceID));
741
742     SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID);
743     if (!sessionStorageNamespace) {
744         // We're getting an incoming message from the web process that's for session storage for a web page
745         // that has already been closed, just ignore it.
746         return;
747     }
748
749     // FIXME: This should be a message check.
750     ASSERT(m_storageAreasByConnection.isValidKey({ connection.uniqueID(), storageMapID }));
751
752     auto& slot = m_storageAreasByConnection.add({ connection.uniqueID(), storageMapID }, nullptr).iterator->value;
753
754     // FIXME: This should be a message check.
755     ASSERT(!slot);
756
757     // FIXME: This should be a message check.
758     ASSERT(connection.uniqueID() == sessionStorageNamespace->allowedConnection());
759
760     auto storageArea = sessionStorageNamespace->getOrCreateStorageArea(WTFMove(securityOriginData));
761     storageArea->addListener(connection.uniqueID(), storageMapID);
762
763     slot = WTFMove(storageArea);
764 }
765
766 void StorageManager::destroyStorageMap(IPC::Connection& connection, uint64_t storageMapID)
767 {
768     std::pair<IPC::Connection::UniqueID, uint64_t> connectionAndStorageMapIDPair(connection.uniqueID(), storageMapID);
769
770     // FIXME: This should be a message check.
771     ASSERT(m_storageAreasByConnection.isValidKey(connectionAndStorageMapIDPair));
772
773     auto it = m_storageAreasByConnection.find(connectionAndStorageMapIDPair);
774     if (it == m_storageAreasByConnection.end()) {
775         // The connection has been removed because the last page was closed.
776         return;
777     }
778
779     it->value->removeListener(connection.uniqueID(), storageMapID);
780
781     // Don't remove session storage maps. The web process may reconnect and expect the data to still be around.
782     if (it->value->isSessionStorage())
783         return;
784
785     m_storageAreasByConnection.remove(connectionAndStorageMapIDPair);
786 }
787
788 void StorageManager::getValues(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values)
789 {
790     StorageArea* storageArea = findStorageArea(connection, storageMapID);
791     if (!storageArea) {
792         // This is a session storage area for a page that has already been closed. Ignore it.
793         return;
794     }
795
796     values = storageArea->items();
797     connection.send(Messages::StorageAreaMap::DidGetValues(storageMapSeed), storageMapID);
798 }
799
800 void StorageManager::setItem(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString)
801 {
802     StorageArea* storageArea = findStorageArea(connection, storageMapID);
803     if (!storageArea) {
804         // This is a session storage area for a page that has already been closed. Ignore it.
805         return;
806     }
807
808     bool quotaError;
809     storageArea->setItem(connection.uniqueID(), sourceStorageAreaID, key, value, urlString, quotaError);
810     connection.send(Messages::StorageAreaMap::DidSetItem(storageMapSeed, key, quotaError), storageMapID);
811 }
812
813 void StorageManager::removeItem(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString)
814 {
815     StorageArea* storageArea = findStorageArea(connection, storageMapID);
816     if (!storageArea) {
817         // This is a session storage area for a page that has already been closed. Ignore it.
818         return;
819     }
820
821     storageArea->removeItem(connection.uniqueID(), sourceStorageAreaID, key, urlString);
822     connection.send(Messages::StorageAreaMap::DidRemoveItem(storageMapSeed, key), storageMapID);
823 }
824
825 void StorageManager::clear(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString)
826 {
827     StorageArea* storageArea = findStorageArea(connection, storageMapID);
828     if (!storageArea) {
829         // This is a session storage area for a page that has already been closed. Ignore it.
830         return;
831     }
832
833     storageArea->clear(connection.uniqueID(), sourceStorageAreaID, urlString);
834     connection.send(Messages::StorageAreaMap::DidClear(storageMapSeed), storageMapID);
835 }
836
837 void StorageManager::applicationWillTerminate()
838 {
839     BinarySemaphore semaphore;
840     m_queue->dispatch([this, &semaphore] {
841         Vector<std::pair<IPC::Connection::UniqueID, uint64_t>> connectionAndStorageMapIDPairsToRemove;
842         for (auto& connectionStorageAreaPair : m_storageAreasByConnection) {
843             connectionStorageAreaPair.value->removeListener(connectionStorageAreaPair.key.first, connectionStorageAreaPair.key.second);
844             connectionAndStorageMapIDPairsToRemove.append(connectionStorageAreaPair.key);
845         }
846
847         for (auto& connectionStorageAreaPair : connectionAndStorageMapIDPairsToRemove)
848             m_storageAreasByConnection.remove(connectionStorageAreaPair);
849
850         semaphore.signal();
851     });
852     semaphore.wait(WallTime::infinity());
853 }
854
855 StorageManager::StorageArea* StorageManager::findStorageArea(IPC::Connection& connection, uint64_t storageMapID) const
856 {
857     std::pair<IPC::Connection::UniqueID, uint64_t> connectionAndStorageMapIDPair(connection.uniqueID(), storageMapID);
858
859     if (!m_storageAreasByConnection.isValidKey(connectionAndStorageMapIDPair))
860         return nullptr;
861
862     return m_storageAreasByConnection.get(connectionAndStorageMapIDPair);
863 }
864
865 StorageManager::LocalStorageNamespace* StorageManager::getOrCreateLocalStorageNamespace(uint64_t storageNamespaceID)
866 {
867     if (!m_localStorageNamespaces.isValidKey(storageNamespaceID))
868         return nullptr;
869
870     auto& slot = m_localStorageNamespaces.add(storageNamespaceID, nullptr).iterator->value;
871     if (!slot)
872         slot = LocalStorageNamespace::create(this, storageNamespaceID);
873
874     return slot.get();
875 }
876
877 StorageManager::TransientLocalStorageNamespace* StorageManager::getOrCreateTransientLocalStorageNamespace(uint64_t storageNamespaceID, WebCore::SecurityOriginData&& topLevelOrigin)
878 {
879     if (!m_transientLocalStorageNamespaces.isValidKey({ storageNamespaceID, topLevelOrigin }))
880         return nullptr;
881
882     auto& slot = m_transientLocalStorageNamespaces.add({ storageNamespaceID, WTFMove(topLevelOrigin) }, nullptr).iterator->value;
883     if (!slot)
884         slot = TransientLocalStorageNamespace::create();
885
886     return slot.get();
887 }
888
889 } // namespace WebKit