2c97accc9c7ec3641de2c5674fdb7541fcc47ef5
[WebKit-https.git] / Source / WebKit / StorageProcess / StorageProcess.cpp
1 /*
2  * Copyright (C) 2013, 2014, 2015, 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 "StorageProcess.h"
28
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>
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 StorageProcess& StorageProcess::singleton()
51 {
52     static NeverDestroyed<StorageProcess> process;
53     return process;
54 }
55
56 StorageProcess::StorageProcess()
57     : m_queue(WorkQueue::create("com.apple.WebKit.StorageProcess"))
58 {
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.
61     UTF8Encoding();
62 }
63
64 StorageProcess::~StorageProcess()
65 {
66 }
67
68 void StorageProcess::initializeConnection(IPC::Connection* connection)
69 {
70     ChildProcess::initializeConnection(connection);
71 }
72
73 bool StorageProcess::shouldTerminate()
74 {
75     return true;
76 }
77
78 void StorageProcess::didClose(IPC::Connection&)
79 {
80     stopRunLoop();
81 }
82
83 void StorageProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
84 {
85     if (messageReceiverMap().dispatchMessage(connection, decoder))
86         return;
87
88     if (decoder.messageReceiverName() == Messages::StorageProcess::messageReceiverName()) {
89         didReceiveStorageProcessMessage(connection, decoder);
90         return;
91     }
92 }
93
94 #if ENABLE(INDEXED_DATABASE)
95 IDBServer::IDBServer& StorageProcess::idbServer(PAL::SessionID sessionID)
96 {
97     auto addResult = m_idbServers.add(sessionID, nullptr);
98     if (!addResult.isNewEntry) {
99         ASSERT(addResult.iterator->value);
100         return *addResult.iterator->value;
101     }
102
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());
107
108     addResult.iterator->value = IDBServer::IDBServer::create(path, StorageProcess::singleton());
109     return *addResult.iterator->value;
110 }
111 #endif
112
113 void StorageProcess::initializeWebsiteDataStore(const StorageProcessCreationParameters& parameters)
114 {
115 #if ENABLE(INDEXED_DATABASE)
116     // *********
117     // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
118     // *********
119
120     auto addResult = m_idbDatabasePaths.add(parameters.sessionID, String());
121     if (!addResult.isNewEntry)
122         return;
123
124     addResult.iterator->value = parameters.indexedDatabaseDirectory;
125     SandboxExtension::consumePermanently(parameters.indexedDatabaseDirectoryExtensionHandle);
126
127     postStorageTask(createCrossThreadTask(*this, &StorageProcess::ensurePathExists, parameters.indexedDatabaseDirectory));
128 #endif
129 }
130
131 void StorageProcess::ensurePathExists(const String& path)
132 {
133     ASSERT(!RunLoop::isMain());
134
135     if (!makeAllDirectories(path))
136         LOG_ERROR("Failed to make all directories for path '%s'", path.utf8().data());
137 }
138
139 void StorageProcess::postStorageTask(CrossThreadTask&& task)
140 {
141     ASSERT(RunLoop::isMain());
142
143     LockHolder locker(m_storageTaskMutex);
144
145     m_storageTasks.append(WTFMove(task));
146
147     m_queue->dispatch([this] {
148         performNextStorageTask();
149     });
150 }
151
152 void StorageProcess::performNextStorageTask()
153 {
154     ASSERT(!RunLoop::isMain());
155
156     CrossThreadTask task;
157     {
158         LockHolder locker(m_storageTaskMutex);
159         ASSERT(!m_storageTasks.isEmpty());
160         task = m_storageTasks.takeFirst();
161     }
162
163     task.performTask();
164 }
165
166 void StorageProcess::createStorageToWebProcessConnection()
167 {
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);
172 #elif OS(DARWIN)
173     // Create the listening port.
174     mach_port_t listeningPort;
175     mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
176
177     // Create a listening connection.
178     m_storageToWebProcessConnections.append(StorageToWebProcessConnection::create(IPC::Connection::Identifier(listeningPort)));
179
180     IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
181     parentProcessConnection()->send(Messages::StorageProcessProxy::DidCreateStorageToWebProcessConnection(clientPort), 0);
182 #else
183     notImplemented();
184 #endif
185 }
186
187 void StorageProcess::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, uint64_t callbackID)
188 {
189     auto completionHandler = [this, callbackID](const WebsiteData& websiteData) {
190         parentProcessConnection()->send(Messages::StorageProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
191     };
192
193 #if ENABLE(SERVICE_WORKER)
194     if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations))
195         notImplemented();
196 #endif
197
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 });
207
208                 completionHandler(websiteData);
209             });
210         }));
211         return;
212     }
213 #endif
214
215     completionHandler({ });
216 }
217
218 void StorageProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
219 {
220     auto completionHandler = [this, callbackID]() {
221         parentProcessConnection()->send(Messages::StorageProcessProxy::DidDeleteWebsiteData(callbackID), 0);
222     };
223
224 #if ENABLE(SERVICE_WORKER)
225     if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
226         if (auto* store = swOriginStoreForSession(sessionID))
227             store->clear();
228     }
229 #endif
230
231 #if ENABLE(INDEXED_DATABASE)
232     if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
233         idbServer(sessionID).closeAndDeleteDatabasesModifiedSince(modifiedSince, WTFMove(completionHandler));
234         return;
235     }
236 #endif
237
238     completionHandler();
239 }
240
241 void StorageProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, const Vector<SecurityOriginData>& securityOriginDatas, uint64_t callbackID)
242 {
243     auto completionHandler = [this, callbackID]() {
244         parentProcessConnection()->send(Messages::StorageProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
245     };
246
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());
252         }
253     }
254 #endif
255
256 #if ENABLE(INDEXED_DATABASE)
257     if (!websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
258         idbServer(sessionID).closeAndDeleteDatabasesForOrigins(securityOriginDatas, WTFMove(completionHandler));
259         return;
260     }
261 #endif
262
263     completionHandler();
264 }
265
266 #if ENABLE(SANDBOX_EXTENSIONS)
267 void StorageProcess::grantSandboxExtensionsForBlobs(const Vector<String>& paths, const SandboxExtension::HandleArray& handles)
268 {
269     ASSERT(paths.size() == handles.size());
270
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);
274     }
275 }
276 #endif
277
278 #if ENABLE(INDEXED_DATABASE)
279 void StorageProcess::prepareForAccessToTemporaryFile(const String& path)
280 {
281     if (auto extension = m_blobTemporaryFileSandboxExtensions.get(path))
282         extension->consume();
283 }
284
285 void StorageProcess::accessToTemporaryFileComplete(const String& path)
286 {
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.
290     deleteFile(path);
291
292     if (auto extension = m_blobTemporaryFileSandboxExtensions.take(path))
293         extension->revoke();
294 }
295
296 Vector<WebCore::SecurityOriginData> StorageProcess::indexedDatabaseOrigins(const String& path)
297 {
298     if (path.isEmpty())
299         return { };
300
301     Vector<WebCore::SecurityOriginData> securityOrigins;
302     for (auto& originPath : listDirectory(path, "*")) {
303         String databaseIdentifier = pathGetFileName(originPath);
304
305         if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
306             securityOrigins.append(WTFMove(*securityOrigin));
307     }
308
309     return securityOrigins;
310 }
311
312 #endif
313
314 #if ENABLE(SANDBOX_EXTENSIONS)
315 void StorageProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, WTF::Function<void (SandboxExtension::HandleArray&&)>&& completionHandler)
316 {
317     static uint64_t lastRequestID;
318
319     uint64_t requestID = ++lastRequestID;
320     m_sandboxExtensionForBlobsCompletionHandlers.set(requestID, WTFMove(completionHandler));
321     parentProcessConnection()->send(Messages::StorageProcessProxy::GetSandboxExtensionsForBlobFiles(requestID, filenames), 0);
322 }
323
324 void StorageProcess::didGetSandboxExtensionsForBlobFiles(uint64_t requestID, SandboxExtension::HandleArray&& handles)
325 {
326     if (auto handler = m_sandboxExtensionForBlobsCompletionHandlers.take(requestID))
327         handler(WTFMove(handles));
328 }
329 #endif
330
331 #if ENABLE(SERVICE_WORKER)
332 SWServer& StorageProcess::swServerForSession(PAL::SessionID sessionID)
333 {
334     auto result = m_swServers.add(sessionID, nullptr);
335     if (result.isNewEntry)
336         result.iterator->value = std::make_unique<SWServer>();
337
338     ASSERT(result.iterator->value);
339     return *result.iterator->value;
340 }
341
342 IPC::Connection* StorageProcess::workerContextProcessConnection()
343 {
344     return m_workerContextProcessConnection.get();
345 }
346
347 void StorageProcess::createWorkerContextProcessConnection()
348 {
349     if (m_waitingForWorkerContextProcessConnection)
350         return;
351     
352     m_waitingForWorkerContextProcessConnection = true;
353     parentProcessConnection()->send(Messages::StorageProcessProxy::GetWorkerContextProcessConnection(), 0);
354 }
355
356 WebSWOriginStore& StorageProcess::ensureSWOriginStoreForSession(PAL::SessionID sessionID)
357 {
358     return *m_swOriginStores.ensure(sessionID, [] {
359         return std::make_unique<WebSWOriginStore>();
360     }).iterator->value;
361 }
362
363 WebSWOriginStore* StorageProcess::swOriginStoreForSession(PAL::SessionID sessionID) const
364 {
365     auto it = m_swOriginStores.find(sessionID);
366     if (it == m_swOriginStores.end())
367         return nullptr;
368     return it->value.get();
369 }
370
371 void StorageProcess::didGetWorkerContextProcessConnection(const IPC::Attachment& encodedConnectionIdentifier)
372 {
373     ASSERT(m_waitingForWorkerContextProcessConnection);
374     m_waitingForWorkerContextProcessConnection = false;
375
376 #if USE(UNIX_DOMAIN_SOCKETS)
377     IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
378 #elif OS(DARWIN)
379     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
380 #else
381     ASSERT_NOT_REACHED();
382 #endif
383
384     if (IPC::Connection::identifierIsNull(connectionIdentifier)) {
385         LOG_ERROR("StorageProcess::didGetWorkerContextProcessConnection - Received null connection identifier");
386         return;
387     }
388
389     m_workerContextProcessConnection = IPC::Connection::createClientConnection(connectionIdentifier, *this);
390     m_workerContextProcessConnection->open();
391     
392     for (auto& connection : m_storageToWebProcessConnections)
393         connection->workerContextProcessConnectionCreated();
394 }
395
396 void StorageProcess::serviceWorkerContextFailedToStart(uint64_t serverConnectionIdentifier, const ServiceWorkerRegistrationKey& registrationKey, const String& workerID, const String& message)
397 {
398     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
399         connection->scriptContextFailedToStart(registrationKey, workerID, message);
400 }
401
402 void StorageProcess::serviceWorkerContextStarted(uint64_t serverConnectionIdentifier, const ServiceWorkerRegistrationKey& registrationKey, uint64_t identifier, const String& workerID)
403 {
404     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
405         connection->scriptContextStarted(registrationKey, identifier, workerID);
406 }
407
408 void StorageProcess::didFailFetch(uint64_t serverConnectionIdentifier, uint64_t fetchIdentifier)
409 {
410     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
411         connection->didFailFetch(fetchIdentifier);
412 }
413
414 void StorageProcess::didReceiveFetchResponse(uint64_t serverConnectionIdentifier, uint64_t fetchIdentifier, const WebCore::ResourceResponse& response)
415 {
416     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
417         connection->didReceiveFetchResponse(fetchIdentifier, response);
418 }
419
420 void StorageProcess::didReceiveFetchData(uint64_t serverConnectionIdentifier, uint64_t fetchIdentifier, const IPC::DataReference& data, int64_t encodedDataLength)
421 {
422     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
423         connection->didReceiveFetchData(fetchIdentifier, data, encodedDataLength);
424 }
425
426 void StorageProcess::didFinishFetch(uint64_t serverConnectionIdentifier, uint64_t fetchIdentifier)
427 {
428     if (auto* connection = m_swServerConnections.get(serverConnectionIdentifier))
429         connection->didFinishFetch(fetchIdentifier);
430 }
431
432 void StorageProcess::registerSWServerConnection(WebSWServerConnection& connection)
433 {
434     ASSERT(!m_swServerConnections.contains(connection.identifier()));
435     m_swServerConnections.add(connection.identifier(), &connection);
436     ensureSWOriginStoreForSession(connection.sessionID()).registerSWServerConnection(connection);
437 }
438
439 void StorageProcess::unregisterSWServerConnection(WebSWServerConnection& connection)
440 {
441     ASSERT(m_swServerConnections.get(connection.identifier()) == &connection);
442     m_swServerConnections.remove(connection.identifier());
443     if (auto* originStore = swOriginStoreForSession(connection.sessionID()))
444         originStore->unregisterSWServerConnection(connection);
445 }
446 #endif
447
448 #if !PLATFORM(COCOA)
449 void StorageProcess::initializeProcess(const ChildProcessInitializationParameters&)
450 {
451 }
452
453 void StorageProcess::initializeProcessName(const ChildProcessInitializationParameters&)
454 {
455 }
456
457 void StorageProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
458 {
459 }
460 #endif
461
462 } // namespace WebKit