1/*
2 * Copyright (C) 2011, 2013, 2019 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 "LocalStorageDatabaseTracker.h"
28
29#include "Logging.h"
30#include <WebCore/SQLiteFileSystem.h>
31#include <WebCore/SQLiteStatement.h>
32#include <WebCore/TextEncoding.h>
33#include <wtf/FileSystem.h>
34#include <wtf/MainThread.h>
35#include <wtf/RunLoop.h>
36#include <wtf/WorkQueue.h>
37#include <wtf/text/CString.h>
38
39namespace WebKit {
40using namespace WebCore;
41
42Ref<LocalStorageDatabaseTracker> LocalStorageDatabaseTracker::create(Ref<WorkQueue>&& queue, const String& localStorageDirectory)
43{
44 return adoptRef(*new LocalStorageDatabaseTracker(WTFMove(queue), localStorageDirectory));
45}
46
47LocalStorageDatabaseTracker::LocalStorageDatabaseTracker(Ref<WorkQueue>&& queue, const String& localStorageDirectory)
48 : m_queue(WTFMove(queue))
49 , m_localStorageDirectory(localStorageDirectory.isolatedCopy())
50{
51 // Make sure the encoding is initialized before we start dispatching things to the queue.
52 UTF8Encoding();
53
54 m_queue->dispatch([protectedThis = makeRef(*this)]() mutable {
55 // Delete legacy storageTracker database file.
56 SQLiteFileSystem::deleteDatabaseFile(protectedThis->databasePath("StorageTracker.db"));
57 });
58}
59
60LocalStorageDatabaseTracker::~LocalStorageDatabaseTracker()
61{
62}
63
64String LocalStorageDatabaseTracker::databasePath(const SecurityOriginData& securityOrigin) const
65{
66 return databasePath(securityOrigin.databaseIdentifier() + ".localstorage");
67}
68
69void LocalStorageDatabaseTracker::didOpenDatabaseWithOrigin(const SecurityOriginData& securityOrigin)
70{
71 // FIXME: Tell clients that the origin was added.
72}
73
74void LocalStorageDatabaseTracker::deleteDatabaseWithOrigin(const SecurityOriginData& securityOrigin)
75{
76 auto path = databasePath(securityOrigin);
77 if (!path.isEmpty())
78 SQLiteFileSystem::deleteDatabaseFile(path);
79
80 // FIXME: Tell clients that the origin was removed.
81}
82
83void LocalStorageDatabaseTracker::deleteAllDatabases()
84{
85 auto paths = FileSystem::listDirectory(m_localStorageDirectory, "*.localstorage");
86 for (const auto& path : paths) {
87 SQLiteFileSystem::deleteDatabaseFile(path);
88
89 // FIXME: Call out to the client.
90 }
91
92 SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_localStorageDirectory);
93}
94
95Vector<SecurityOriginData> LocalStorageDatabaseTracker::databasesModifiedSince(WallTime time)
96{
97 Vector<SecurityOriginData> databaseOriginsModified;
98 auto databaseOrigins = origins();
99
100 for (auto origin : databaseOrigins) {
101 auto path = databasePath(origin);
102
103 auto modificationTime = SQLiteFileSystem::databaseModificationTime(path);
104 if (!modificationTime)
105 continue;
106
107 if (modificationTime.value() >= time)
108 databaseOriginsModified.append(origin);
109 }
110
111 return databaseOriginsModified;
112}
113
114Vector<SecurityOriginData> LocalStorageDatabaseTracker::origins() const
115{
116 Vector<SecurityOriginData> databaseOrigins;
117 auto paths = FileSystem::listDirectory(m_localStorageDirectory, "*.localstorage");
118
119 for (const auto& path : paths) {
120 auto filename = FileSystem::pathGetFileName(path);
121 auto originIdentifier = filename.substring(0, filename.length() - strlen(".localstorage"));
122 auto origin = SecurityOriginData::fromDatabaseIdentifier(originIdentifier);
123 if (origin)
124 databaseOrigins.append(origin.value());
125 else
126 RELEASE_LOG_ERROR(LocalStorageDatabaseTracker, "Unable to extract origin from path %s", path.utf8().data());
127 }
128
129 return databaseOrigins;
130}
131
132Vector<LocalStorageDatabaseTracker::OriginDetails> LocalStorageDatabaseTracker::originDetails()
133{
134 Vector<OriginDetails> result;
135 auto databaseOrigins = origins();
136 result.reserveInitialCapacity(databaseOrigins.size());
137
138 for (const auto& origin : databaseOrigins) {
139 String path = databasePath(origin);
140
141 OriginDetails details;
142 details.originIdentifier = origin.databaseIdentifier();
143 details.creationTime = SQLiteFileSystem::databaseCreationTime(path);
144 details.modificationTime = SQLiteFileSystem::databaseModificationTime(path);
145 result.uncheckedAppend(details);
146 }
147
148 return result;
149}
150
151String LocalStorageDatabaseTracker::databasePath(const String& filename) const
152{
153 if (!SQLiteFileSystem::ensureDatabaseDirectoryExists(m_localStorageDirectory)) {
154 if (!m_localStorageDirectory.isNull())
155 LOG_ERROR("Unable to create LocalStorage database path %s", m_localStorageDirectory.utf8().data());
156 return String();
157 }
158
159#if PLATFORM(IOS_FAMILY)
160 RunLoop::main().dispatch([this, protectedThis = makeRef(*this)]() mutable {
161 platformMaybeExcludeFromBackup();
162 });
163#endif
164
165 return SQLiteFileSystem::appendDatabaseFileNameToPath(m_localStorageDirectory, filename);
166}
167
168} // namespace WebKit
169