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