caffd5f134b65aaf99c1d7b0b2c7dcc5ca160309
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / client / IDBConnectionProxy.cpp
1 /*
2  * Copyright (C) 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 "IDBConnectionProxy.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBCursorInfo.h"
32 #include "IDBDatabase.h"
33 #include "IDBGetRecordData.h"
34 #include "IDBIterateCursorData.h"
35 #include "IDBKeyRangeData.h"
36 #include "IDBOpenDBRequest.h"
37 #include "IDBRequestData.h"
38 #include "IDBResultData.h"
39 #include "ScriptExecutionContext.h"
40 #include "SecurityOrigin.h"
41 #include <wtf/MainThread.h>
42
43 namespace WebCore {
44 namespace IDBClient {
45
46 IDBConnectionProxy::IDBConnectionProxy(IDBConnectionToServer& connection)
47     : m_connectionToServer(connection)
48     , m_serverConnectionIdentifier(connection.identifier())
49 {
50     ASSERT(isMainThread());
51 }
52
53 void IDBConnectionProxy::ref()
54 {
55     m_connectionToServer.ref();
56 }
57
58 void IDBConnectionProxy::deref()
59 {
60     m_connectionToServer.deref();
61 }
62
63 Ref<IDBOpenDBRequest> IDBConnectionProxy::openDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier, uint64_t version)
64 {
65     RefPtr<IDBOpenDBRequest> request;
66     {
67         Locker<Lock> locker(m_openDBRequestMapLock);
68
69         request = IDBOpenDBRequest::createOpenRequest(context, *this, databaseIdentifier, version);
70         ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier()));
71         m_openDBRequestMap.set(request->resourceIdentifier(), request.get());
72     }
73
74     callConnectionOnMainThread(&IDBConnectionToServer::openDatabase, IDBRequestData(*this, *request));
75
76     return request.releaseNonNull();
77 }
78
79 Ref<IDBOpenDBRequest> IDBConnectionProxy::deleteDatabase(ScriptExecutionContext& context, const IDBDatabaseIdentifier& databaseIdentifier)
80 {
81     RefPtr<IDBOpenDBRequest> request;
82     {
83         Locker<Lock> locker(m_openDBRequestMapLock);
84
85         request = IDBOpenDBRequest::createDeleteRequest(context, *this, databaseIdentifier);
86         ASSERT(!m_openDBRequestMap.contains(request->resourceIdentifier()));
87         m_openDBRequestMap.set(request->resourceIdentifier(), request.get());
88     }
89
90     callConnectionOnMainThread(&IDBConnectionToServer::deleteDatabase, IDBRequestData(*this, *request));
91
92     return request.releaseNonNull();
93 }
94
95 void IDBConnectionProxy::didOpenDatabase(const IDBResultData& resultData)
96 {
97     completeOpenDBRequest(resultData);
98 }
99
100 void IDBConnectionProxy::didDeleteDatabase(const IDBResultData& resultData)
101 {
102     completeOpenDBRequest(resultData);
103 }
104
105 void IDBConnectionProxy::completeOpenDBRequest(const IDBResultData& resultData)
106 {
107     ASSERT(isMainThread());
108
109     RefPtr<IDBOpenDBRequest> request;
110     {
111         Locker<Lock> locker(m_openDBRequestMapLock);
112         request = m_openDBRequestMap.take(resultData.requestIdentifier());
113     }
114
115     if (!request)
116         return;
117
118     request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, resultData);
119 }
120
121 void IDBConnectionProxy::createObjectStore(TransactionOperation& operation, const IDBObjectStoreInfo& info)
122 {
123     const IDBRequestData requestData { operation };
124     saveOperation(operation);
125
126     callConnectionOnMainThread(&IDBConnectionToServer::createObjectStore, requestData, info);
127 }
128
129 void IDBConnectionProxy::renameObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& newName)
130 {
131     const IDBRequestData requestData { operation };
132     saveOperation(operation);
133
134     callConnectionOnMainThread(&IDBConnectionToServer::renameObjectStore, requestData, objectStoreIdentifier, newName);
135 }
136
137 void IDBConnectionProxy::renameIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
138 {
139     const IDBRequestData requestData { operation };
140     saveOperation(operation);
141
142     callConnectionOnMainThread(&IDBConnectionToServer::renameIndex, requestData, objectStoreIdentifier, indexIdentifier, newName);
143 }
144
145 void IDBConnectionProxy::deleteObjectStore(TransactionOperation& operation, const String& objectStoreName)
146 {
147     const IDBRequestData requestData { operation };
148     saveOperation(operation);
149
150     callConnectionOnMainThread(&IDBConnectionToServer::deleteObjectStore, requestData, objectStoreName);
151 }
152
153 void IDBConnectionProxy::clearObjectStore(TransactionOperation& operation, uint64_t objectStoreIdentifier)
154 {
155     const IDBRequestData requestData { operation };
156     saveOperation(operation);
157
158     callConnectionOnMainThread(&IDBConnectionToServer::clearObjectStore, requestData, objectStoreIdentifier);
159 }
160
161 void IDBConnectionProxy::createIndex(TransactionOperation& operation, const IDBIndexInfo& info)
162 {
163     const IDBRequestData requestData { operation };
164     saveOperation(operation);
165
166     callConnectionOnMainThread(&IDBConnectionToServer::createIndex, requestData, info);
167 }
168
169 void IDBConnectionProxy::deleteIndex(TransactionOperation& operation, uint64_t objectStoreIdentifier, const String& indexName)
170 {
171     const IDBRequestData requestData { operation };
172     saveOperation(operation);
173
174     callConnectionOnMainThread(&IDBConnectionToServer::deleteIndex, requestData, WTFMove(objectStoreIdentifier), indexName);
175 }
176
177 void IDBConnectionProxy::putOrAdd(TransactionOperation& operation, IDBKeyData&& keyData, const IDBValue& value, const IndexedDB::ObjectStoreOverwriteMode mode)
178 {
179     const IDBRequestData requestData { operation };
180     saveOperation(operation);
181
182     callConnectionOnMainThread(&IDBConnectionToServer::putOrAdd, requestData, keyData, value, mode);
183 }
184
185 void IDBConnectionProxy::getRecord(TransactionOperation& operation, const IDBGetRecordData& getRecordData)
186 {
187     const IDBRequestData requestData { operation };
188     saveOperation(operation);
189
190     callConnectionOnMainThread(&IDBConnectionToServer::getRecord, requestData, getRecordData);
191 }
192
193 void IDBConnectionProxy::getAllRecords(TransactionOperation& operation, const IDBGetAllRecordsData& getAllRecordsData)
194 {
195     const IDBRequestData requestData { operation };
196     saveOperation(operation);
197
198     callConnectionOnMainThread(&IDBConnectionToServer::getAllRecords, requestData, getAllRecordsData);
199 }
200
201 void IDBConnectionProxy::getCount(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
202 {
203     const IDBRequestData requestData { operation };
204     saveOperation(operation);
205
206     callConnectionOnMainThread(&IDBConnectionToServer::getCount, requestData, keyRange);
207 }
208
209 void IDBConnectionProxy::deleteRecord(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
210 {
211     const IDBRequestData requestData { operation };
212     saveOperation(operation);
213
214     callConnectionOnMainThread(&IDBConnectionToServer::deleteRecord, requestData, keyRange);
215 }
216
217 void IDBConnectionProxy::openCursor(TransactionOperation& operation, const IDBCursorInfo& info)
218 {
219     const IDBRequestData requestData { operation };
220     saveOperation(operation);
221
222     callConnectionOnMainThread(&IDBConnectionToServer::openCursor, requestData, info);
223 }
224
225 void IDBConnectionProxy::iterateCursor(TransactionOperation& operation, const IDBIterateCursorData& data)
226 {
227     const IDBRequestData requestData { operation };
228     saveOperation(operation);
229
230     callConnectionOnMainThread(&IDBConnectionToServer::iterateCursor, requestData, data);
231 }
232
233 void IDBConnectionProxy::saveOperation(TransactionOperation& operation)
234 {
235     Locker<Lock> locker(m_transactionOperationLock);
236
237     ASSERT(!m_activeOperations.contains(operation.identifier()));
238     m_activeOperations.set(operation.identifier(), &operation);
239 }
240
241 void IDBConnectionProxy::completeOperation(const IDBResultData& resultData)
242 {
243     RefPtr<TransactionOperation> operation;
244     {
245         Locker<Lock> locker(m_transactionOperationLock);
246         operation = m_activeOperations.take(resultData.requestIdentifier());
247     }
248
249     if (!operation)
250         return;
251
252     operation->performCompleteOnOriginThread(resultData, WTFMove(operation));
253 }
254
255 void IDBConnectionProxy::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier)
256 {
257     callConnectionOnMainThread(&IDBConnectionToServer::abortOpenAndUpgradeNeeded, databaseConnectionIdentifier, transactionIdentifier);
258 }
259
260 void IDBConnectionProxy::fireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier, uint64_t requestedVersion)
261 {
262     RefPtr<IDBDatabase> database;
263     {
264         Locker<Lock> locker(m_databaseConnectionMapLock);
265         database = m_databaseConnectionMap.get(databaseConnectionIdentifier);
266     }
267
268     if (!database)
269         return;
270
271     database->performCallbackOnOriginThread(*database, &IDBDatabase::fireVersionChangeEvent, requestIdentifier, requestedVersion);
272 }
273
274 void IDBConnectionProxy::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier)
275 {
276     callConnectionOnMainThread(&IDBConnectionToServer::didFireVersionChangeEvent, databaseConnectionIdentifier, requestIdentifier);
277 }
278
279 void IDBConnectionProxy::notifyOpenDBRequestBlocked(const IDBResourceIdentifier& requestIdentifier, uint64_t oldVersion, uint64_t newVersion)
280 {
281     ASSERT(isMainThread());
282
283     RefPtr<IDBOpenDBRequest> request;
284     {
285         Locker<Lock> locker(m_openDBRequestMapLock);
286         request = m_openDBRequestMap.get(requestIdentifier);
287     }
288
289     if (!request)
290         return;
291
292     request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestBlocked, oldVersion, newVersion);
293 }
294
295 void IDBConnectionProxy::openDBRequestCancelled(const IDBRequestData& requestData)
296 {
297     callConnectionOnMainThread(&IDBConnectionToServer::openDBRequestCancelled, requestData);
298 }
299
300 void IDBConnectionProxy::establishTransaction(IDBTransaction& transaction)
301 {
302     {
303         Locker<Lock> locker(m_transactionMapLock);
304         ASSERT(!hasRecordOfTransaction(transaction));
305         m_pendingTransactions.set(transaction.info().identifier(), &transaction);
306     }
307
308     callConnectionOnMainThread(&IDBConnectionToServer::establishTransaction, transaction.database().databaseConnectionIdentifier(), transaction.info());
309 }
310
311 void IDBConnectionProxy::didStartTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
312 {
313     RefPtr<IDBTransaction> transaction;
314     {
315         Locker<Lock> locker(m_transactionMapLock);
316         transaction = m_pendingTransactions.take(transactionIdentifier);
317     }
318
319     ASSERT(transaction);
320
321     transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didStart, error);
322 }
323
324 void IDBConnectionProxy::commitTransaction(IDBTransaction& transaction)
325 {
326     {
327         Locker<Lock> locker(m_transactionMapLock);
328         ASSERT(!m_committingTransactions.contains(transaction.info().identifier()));
329         m_committingTransactions.set(transaction.info().identifier(), &transaction);
330     }
331
332     callConnectionOnMainThread(&IDBConnectionToServer::commitTransaction, transaction.info().identifier());
333 }
334
335 void IDBConnectionProxy::didCommitTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
336 {
337     RefPtr<IDBTransaction> transaction;
338     {
339         Locker<Lock> locker(m_transactionMapLock);
340         transaction = m_committingTransactions.take(transactionIdentifier);
341     }
342
343     if (!transaction)
344         return;
345
346     transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didCommit, error);
347 }
348
349 void IDBConnectionProxy::abortTransaction(IDBTransaction& transaction)
350 {
351     {
352         Locker<Lock> locker(m_transactionMapLock);
353         ASSERT(!m_abortingTransactions.contains(transaction.info().identifier()));
354         m_abortingTransactions.set(transaction.info().identifier(), &transaction);
355     }
356
357     callConnectionOnMainThread(&IDBConnectionToServer::abortTransaction, transaction.info().identifier());
358 }
359
360 void IDBConnectionProxy::didAbortTransaction(const IDBResourceIdentifier& transactionIdentifier, const IDBError& error)
361 {
362     RefPtr<IDBTransaction> transaction;
363     {
364         Locker<Lock> locker(m_transactionMapLock);
365         transaction = m_abortingTransactions.take(transactionIdentifier);
366     }
367
368     if (!transaction)
369         return;
370
371     transaction->performCallbackOnOriginThread(*transaction, &IDBTransaction::didAbort, error);
372 }
373
374 bool IDBConnectionProxy::hasRecordOfTransaction(const IDBTransaction& transaction) const
375 {
376     ASSERT(m_transactionMapLock.isLocked());
377
378     auto identifier = transaction.info().identifier();
379     return m_pendingTransactions.contains(identifier) || m_committingTransactions.contains(identifier) || m_abortingTransactions.contains(identifier);
380 }
381
382 void IDBConnectionProxy::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, IDBTransaction& transaction)
383 {
384     callConnectionOnMainThread(&IDBConnectionToServer::didFinishHandlingVersionChangeTransaction, databaseConnectionIdentifier, transaction.info().identifier());
385 }
386
387 void IDBConnectionProxy::databaseConnectionClosed(IDBDatabase& database)
388 {
389     callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier());
390 }
391
392 void IDBConnectionProxy::didCloseFromServer(uint64_t databaseConnectionIdentifier, const IDBError& error)
393 {
394     RefPtr<IDBDatabase> database;
395     {
396         Locker<Lock> locker(m_databaseConnectionMapLock);
397         database = m_databaseConnectionMap.get(databaseConnectionIdentifier);
398     }
399
400     // If the IDBDatabase object is gone, message back to the server so it doesn't hang
401     // waiting for a reply that will never come.
402     if (!database) {
403         m_connectionToServer.confirmDidCloseFromServer(databaseConnectionIdentifier);
404         return;
405     }
406
407     database->performCallbackOnOriginThread(*database, &IDBDatabase::didCloseFromServer, error);
408 }
409
410 void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase& database)
411 {
412     callConnectionOnMainThread(&IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier());
413 }
414
415 void IDBConnectionProxy::connectionToServerLost(const IDBError& error)
416 {
417     Vector<uint64_t> databaseConnectionIdentifiers;
418     {
419         Locker<Lock> locker(m_databaseConnectionMapLock);
420         copyKeysToVector(m_databaseConnectionMap, databaseConnectionIdentifiers);
421     }
422
423     for (auto connectionIdentifier : databaseConnectionIdentifiers) {
424         RefPtr<IDBDatabase> database;
425         {
426             Locker<Lock> locker(m_databaseConnectionMapLock);
427             database = m_databaseConnectionMap.get(connectionIdentifier);
428         }
429
430         if (!database)
431             continue;
432
433         database->performCallbackOnOriginThread(*database, &IDBDatabase::connectionToServerLost, error);
434     }
435
436     Vector<IDBResourceIdentifier> openDBRequestIdentifiers;
437     {
438         Locker<Lock> locker(m_openDBRequestMapLock);
439         copyKeysToVector(m_openDBRequestMap, openDBRequestIdentifiers);
440     }
441
442     for (auto& requestIdentifier : openDBRequestIdentifiers) {
443         RefPtr<IDBOpenDBRequest> request;
444         {
445             Locker<Lock> locker(m_openDBRequestMapLock);
446             request = m_openDBRequestMap.get(requestIdentifier);
447         }
448
449         if (!request)
450             continue;
451
452         auto result = IDBResultData::error(requestIdentifier, error);
453         request->performCallbackOnOriginThread(*request, &IDBOpenDBRequest::requestCompleted, result);
454     }
455 }
456
457 void IDBConnectionProxy::scheduleMainThreadTasks()
458 {
459     Locker<Lock> locker(m_mainThreadTaskLock);
460     if (m_mainThreadProtector)
461         return;
462
463     m_mainThreadProtector = &m_connectionToServer;
464     callOnMainThread([this] {
465         handleMainThreadTasks();
466     });
467 }
468
469 void IDBConnectionProxy::handleMainThreadTasks()
470 {
471     RefPtr<IDBConnectionToServer> protector;
472     {
473         Locker<Lock> locker(m_mainThreadTaskLock);
474         ASSERT(m_mainThreadProtector);
475         protector = WTFMove(m_mainThreadProtector);
476     }
477
478     while (auto task = m_mainThreadQueue.tryGetMessage())
479         task->performTask();
480 }
481
482 void IDBConnectionProxy::getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, std::function<void (const Vector<String>&)> callback)
483 {
484     // This method is only meant to be called by the web inspector on the main thread.
485     RELEASE_ASSERT(isMainThread());
486
487     m_connectionToServer.getAllDatabaseNames(mainFrameOrigin, openingOrigin, callback);
488 }
489
490 void IDBConnectionProxy::registerDatabaseConnection(IDBDatabase& database)
491 {
492     Locker<Lock> locker(m_databaseConnectionMapLock);
493
494     ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()));
495     m_databaseConnectionMap.set(database.databaseConnectionIdentifier(), &database);
496 }
497
498 void IDBConnectionProxy::unregisterDatabaseConnection(IDBDatabase& database)
499 {
500     Locker<Lock> locker(m_databaseConnectionMapLock);
501
502     ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()) || m_databaseConnectionMap.get(database.databaseConnectionIdentifier()) == &database);
503     m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
504 }
505
506 void IDBConnectionProxy::forgetActiveOperations(const Vector<RefPtr<TransactionOperation>>& operations)
507 {
508     Locker<Lock> locker(m_transactionOperationLock);
509
510     for (auto& operation : operations)
511         m_activeOperations.remove(operation->identifier());
512 }
513
514 template<typename KeyType, typename ValueType>
515 void removeItemsMatchingCurrentThread(HashMap<KeyType, ValueType>& map)
516 {
517     auto currentThreadID = currentThread();
518
519     Vector<KeyType> keys;
520     keys.reserveInitialCapacity(map.size());
521     for (auto& iterator : map) {
522         if (iterator.value->originThreadID() == currentThreadID)
523             keys.uncheckedAppend(iterator.key);
524     }
525
526     for (auto& key : keys)
527         map.remove(key);
528 }
529
530 void IDBConnectionProxy::forgetActivityForCurrentThread()
531 {
532     ASSERT(!isMainThread());
533
534     {
535         Locker<Lock> lock(m_databaseConnectionMapLock);
536         removeItemsMatchingCurrentThread(m_databaseConnectionMap);
537     }
538     {
539         Locker<Lock> lock(m_openDBRequestMapLock);
540         removeItemsMatchingCurrentThread(m_openDBRequestMap);
541     }
542     {
543         Locker<Lock> lock(m_transactionMapLock);
544         removeItemsMatchingCurrentThread(m_pendingTransactions);
545         removeItemsMatchingCurrentThread(m_committingTransactions);
546         removeItemsMatchingCurrentThread(m_abortingTransactions);
547     }
548     {
549         Locker<Lock> lock(m_transactionOperationLock);
550         removeItemsMatchingCurrentThread(m_activeOperations);
551     }
552 }
553
554 } // namesapce IDBClient
555 } // namespace WebCore
556
557 #endif // ENABLE(INDEXED_DATABASE)