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