2 * Copyright (C) 2013, 2014, 2015, 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "StorageProcess.h"
29 #include "StorageProcessCreationParameters.h"
30 #include "StorageProcessMessages.h"
31 #include "StorageProcessProxyMessages.h"
32 #include "StorageToWebProcessConnection.h"
33 #include "WebCoreArgumentCoders.h"
34 #include "WebSWOriginStore.h"
35 #include "WebSWServerConnection.h"
36 #include "WebsiteData.h"
37 #include <WebCore/FileSystem.h>
38 #include <WebCore/IDBKeyData.h>
39 #include <WebCore/NotImplemented.h>
40 #include <WebCore/SecurityOrigin.h>
41 #include <WebCore/TextEncoding.h>
42 #include <pal/SessionID.h>
43 #include <wtf/CrossThreadTask.h>
44 #include <wtf/MainThread.h>
46 using namespace WebCore;
50 StorageProcess& StorageProcess::singleton()
52 static NeverDestroyed<StorageProcess> process;
56 StorageProcess::StorageProcess()
57 : m_queue(WorkQueue::create("com.apple.WebKit.StorageProcess"))
59 // Make sure the UTF8Encoding encoding and the text encoding maps have been built on the main thread before a background thread needs it.
60 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=135365 - Need a more explicit way of doing this besides accessing the UTF8Encoding.
64 StorageProcess::~StorageProcess()
68 void StorageProcess::initializeConnection(IPC::Connection* connection)
70 ChildProcess::initializeConnection(connection);
73 bool StorageProcess::shouldTerminate()
78 void StorageProcess::didClose(IPC::Connection&)
83 void StorageProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
85 if (messageReceiverMap().dispatchMessage(connection, decoder))
88 if (decoder.messageReceiverName() == Messages::StorageProcess::messageReceiverName()) {
89 didReceiveStorageProcessMessage(connection, decoder);
94 #if ENABLE(INDEXED_DATABASE)
95 IDBServer::IDBServer& StorageProcess::idbServer(PAL::SessionID sessionID)
97 auto addResult = m_idbServers.add(sessionID, nullptr);
98 if (!addResult.isNewEntry) {
99 ASSERT(addResult.iterator->value);
100 return *addResult.iterator->value;
103 auto path = m_idbDatabasePaths.get(sessionID);
104 // There should already be a registered path for this PAL::SessionID.
105 // If there's not, then where did this PAL::SessionID come from?
106 ASSERT(!path.isEmpty());
108 addResult.iterator->value = IDBServer::IDBServer::create(path, StorageProcess::singleton());
109 return *addResult.iterator->value;
113 void StorageProcess::initializeWebsiteDataStore(const StorageProcessCreationParameters& parameters)
115 #if ENABLE(INDEXED_DATABASE)
117 // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
120 auto addResult = m_idbDatabasePaths.add(parameters.sessionID, String());
121 if (!addResult.isNewEntry)
124 addResult.iterator->value = parameters.indexedDatabaseDirectory;
125 SandboxExtension::consumePermanently(parameters.indexedDatabaseDirectoryExtensionHandle);
127 postStorageTask(createCrossThreadTask(*this, &StorageProcess::ensurePathExists, parameters.indexedDatabaseDirectory));
131 void StorageProcess::ensurePathExists(const String& path)
133 ASSERT(!RunLoop::isMain());
135 if (!makeAllDirectories(path))
136 LOG_ERROR("Failed to make all directories for path '%s'", path.utf8().data());
139 void StorageProcess::postStorageTask(CrossThreadTask&& task)
141 ASSERT(RunLoop::isMain());
143 LockHolder locker(m_storageTaskMutex);
145 m_storageTasks.append(WTFMove(task));
147 m_queue->dispatch([this] {
148 performNextStorageTask();
152 void StorageProcess::performNextStorageTask()
154 ASSERT(!RunLoop::isMain());
156 CrossThreadTask task;
158 LockHolder locker(m_storageTaskMutex);
159 ASSERT(!m_storageTasks.isEmpty());
160 task = m_storageTasks.takeFirst();
166 void StorageProcess::createStorageToWebProcessConnection()
168 #if USE(UNIX_DOMAIN_SOCKETS)
169 IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
170 m_storageToWebProcessConnections.append(StorageToWebProcessConnection::create(socketPair.server));
171 parentProcessConnection()->send(Messages::StorageProcessProxy::DidCreateStorageToWebProcessConnection(IPC::Attachment(socketPair.client)), 0);
173 // Create the listening port.
174 mach_port_t listeningPort;
175 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
177 // Create a listening connection.
178 m_storageToWebProcessConnections.append(StorageToWebProcessConnection::create(IPC::Connection::Identifier(listeningPort)));
180 IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
181 parentProcessConnection()->send(Messages::StorageProcessProxy::DidCreateStorageToWebProcessConnection(clientPort), 0);
187 void StorageProcess::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, uint64_t callbackID)
189 auto completionHandler = [this, callbackID](const WebsiteData& websiteData) {
190 parentProcessConnection()->send(Messages::StorageProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
193 #if ENABLE(SERVICE_WORKER)
194 if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations))
198 #if ENABLE(INDEXED_DATABASE)
199 String path = m_idbDatabasePaths.get(sessionID);
200 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
201 // FIXME: Pick the right database store based on the session ID.
202 postStorageTask(CrossThreadTask([this, completionHandler = WTFMove(completionHandler), path = WTFMove(path)]() mutable {
203 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), securityOrigins = indexedDatabaseOrigins(path)] {
204 WebsiteData websiteData;
205 for (const auto& securityOrigin : securityOrigins)
206 websiteData.entries.append({ securityOrigin, WebsiteDataType::IndexedDBDatabases, 0 });
208 completionHandler(websiteData);
215 completionHandler({ });
218 void StorageProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
220 auto completionHandler = [this, callbackID]() {
221 parentProcessConnection()->send(Messages::StorageProcessProxy::DidDeleteWebsiteData(callbackID), 0);
224 #if ENABLE(SERVICE_WORKER)
225 if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
226 if (auto* store = swOriginStoreForSession(sessionID))
231 #if ENABLE(INDEXED_DATABASE)
232 if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
233 idbServer(sessionID).closeAndDeleteDatabasesModifiedSince(modifiedSince, WTFMove(completionHandler));
241 void StorageProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, const Vector<SecurityOriginData>& securityOriginDatas, uint64_t callbackID)
243 auto completionHandler = [this, callbackID]() {
244 parentProcessConnection()->send(Messages::StorageProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
247 #if ENABLE(SERVICE_WORKER)
248 if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
249 if (auto* store = swOriginStoreForSession(sessionID)) {
250 for (auto& originData : securityOriginDatas)
251 store->remove(originData.securityOrigin());
256 #if ENABLE(INDEXED_DATABASE)
257 if (!websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
258 idbServer(sessionID).closeAndDeleteDatabasesForOrigins(securityOriginDatas, WTFMove(completionHandler));
266 #if ENABLE(SANDBOX_EXTENSIONS)
267 void StorageProcess::grantSandboxExtensionsForBlobs(const Vector<String>& paths, const SandboxExtension::HandleArray& handles)
269 ASSERT(paths.size() == handles.size());
271 for (size_t i = 0; i < paths.size(); ++i) {
272 auto result = m_blobTemporaryFileSandboxExtensions.add(paths[i], SandboxExtension::create(handles[i]));
273 ASSERT_UNUSED(result, result.isNewEntry);
278 #if ENABLE(INDEXED_DATABASE)
279 void StorageProcess::prepareForAccessToTemporaryFile(const String& path)
281 if (auto extension = m_blobTemporaryFileSandboxExtensions.get(path))
282 extension->consume();
285 void StorageProcess::accessToTemporaryFileComplete(const String& path)
287 // We've either hard linked the temporary blob file to the database directory, copied it there,
288 // or the transaction is being aborted.
289 // In any of those cases, we can delete the temporary blob file now.
292 if (auto extension = m_blobTemporaryFileSandboxExtensions.take(path))
296 Vector<WebCore::SecurityOriginData> StorageProcess::indexedDatabaseOrigins(const String& path)
301 Vector<WebCore::SecurityOriginData> securityOrigins;
302 for (auto& originPath : listDirectory(path, "*")) {
303 String databaseIdentifier = pathGetFileName(originPath);
305 if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
306 securityOrigins.append(WTFMove(*securityOrigin));
309 return securityOrigins;
314 #if ENABLE(SANDBOX_EXTENSIONS)
315 void StorageProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, WTF::Function<void (SandboxExtension::HandleArray&&)>&& completionHandler)
317 static uint64_t lastRequestID;
319 uint64_t requestID = ++lastRequestID;
320 m_sandboxExtensionForBlobsCompletionHandlers.set(requestID, WTFMove(completionHandler));
321 parentProcessConnection()->send(Messages::StorageProcessProxy::GetSandboxExtensionsForBlobFiles(requestID, filenames), 0);
324 void StorageProcess::didGetSandboxExtensionsForBlobFiles(uint64_t requestID, SandboxExtension::HandleArray&& handles)
326 if (auto handler = m_sandboxExtensionForBlobsCompletionHandlers.take(requestID))
327 handler(WTFMove(handles));
331 #if ENABLE(SERVICE_WORKER)
332 SWServer& StorageProcess::swServerForSession(PAL::SessionID sessionID)
334 auto result = m_swServers.add(sessionID, nullptr);
335 if (result.isNewEntry)
336 result.iterator->value = std::make_unique<SWServer>();
338 ASSERT(result.iterator->value);
339 return *result.iterator->value;
342 IPC::Connection* StorageProcess::workerContextProcessConnection()
344 return m_workerContextProcessConnection.get();
347 void StorageProcess::createWorkerContextProcessConnection()
349 if (m_waitingForWorkerContextProcessConnection)
352 m_waitingForWorkerContextProcessConnection = true;
353 parentProcessConnection()->send(Messages::StorageProcessProxy::GetWorkerContextProcessConnection(), 0);
356 WebSWOriginStore& StorageProcess::ensureSWOriginStoreForSession(PAL::SessionID sessionID)
358 return *m_swOriginStores.ensure(sessionID, [] {
359 return std::make_unique<WebSWOriginStore>();
363 WebSWOriginStore* StorageProcess::swOriginStoreForSession(PAL::SessionID sessionID) const
365 auto it = m_swOriginStores.find(sessionID);
366 if (it == m_swOriginStores.end())
368 return it->value.get();
371 void StorageProcess::didGetWorkerContextProcessConnection(const IPC::Attachment& encodedConnectionIdentifier)
373 ASSERT(m_waitingForWorkerContextProcessConnection);
374 m_waitingForWorkerContextProcessConnection = false;
376 #if USE(UNIX_DOMAIN_SOCKETS)
377 IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
379 IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
381 ASSERT_NOT_REACHED();
384 if (IPC::Connection::identifierIsNull(connectionIdentifier)) {
385 LOG_ERROR("StorageProcess::didGetWorkerContextProcessConnection - Received null connection identifier");
389 m_workerContextProcessConnection = IPC::Connection::createClientConnection(connectionIdentifier, *this);
390 m_workerContextProcessConnection->open();
392 for (auto& connection : m_storageToWebProcessConnections)
393 connection->workerContextProcessConnectionCreated();
396 void StorageProcess::serviceWorkerContextFailedToStart(uint64_t serverConnectionIdentifier, const ServiceWorkerRegistrationKey& registrationKey, const String& workerID, const String& message)
398 if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
399 connection->scriptContextFailedToStart(registrationKey, workerID, message);
402 void StorageProcess::serviceWorkerContextStarted(uint64_t serverConnectionIdentifier, const ServiceWorkerRegistrationKey& registrationKey, uint64_t identifier, const String& workerID)
404 if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
405 connection->scriptContextStarted(registrationKey, identifier, workerID);
408 void StorageProcess::registerSWServerConnection(WebSWServerConnection& connection)
410 ASSERT(!m_swServerConnections.contains(connection.identifier()));
411 m_swServerConnections.add(connection.identifier(), &connection);
412 ensureSWOriginStoreForSession(connection.sessionID()).registerSWServerConnection(connection);
415 void StorageProcess::unregisterSWServerConnection(WebSWServerConnection& connection)
417 ASSERT(m_swServerConnections.get(connection.identifier()) == &connection);
418 m_swServerConnections.remove(connection.identifier());
419 if (auto* originStore = swOriginStoreForSession(connection.sessionID()))
420 originStore->unregisterSWServerConnection(connection);
425 void StorageProcess::initializeProcess(const ChildProcessInitializationParameters&)
429 void StorageProcess::initializeProcessName(const ChildProcessInitializationParameters&)
433 void StorageProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
438 } // namespace WebKit