1/* 2 * Copyright (C) 2013 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. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27#include "config.h" 28#include "WebIDBFactoryBackend.h" 29 30#include "IDBUtilities.h" 31#include "Logging.h" 32#include "WebIDBServerConnection.h" 33#include "WebProcess.h" 34#include "WebToDatabaseProcessConnection.h" 35#include <WebCore/DOMStringList.h> 36#include <WebCore/IDBCallbacks.h> 37#include <WebCore/IDBCursorBackend.h> 38#include <WebCore/IDBDatabaseCallbacks.h> 39#include <WebCore/IDBTransactionBackend.h> 40#include <WebCore/SecurityOrigin.h> 41#include <wtf/MainThread.h> 42#include <wtf/NeverDestroyed.h> 43 44#if ENABLE(INDEXED_DATABASE) 45#if ENABLE(DATABASE_PROCESS) 46 47using namespace WebCore; 48 49namespace WebKit { 50 51typedef HashMap<String, IDBDatabaseBackend*> IDBDatabaseBackendMap; 52 53static IDBDatabaseBackendMap& sharedDatabaseBackendMap() 54{ 55 static NeverDestroyed<IDBDatabaseBackendMap> databaseBackendMap; 56 return databaseBackendMap; 57} 58 59static HashMap<String, HashSet<String>>& sharedRecentDatabaseNameMap() 60{ 61 static NeverDestroyed<HashMap<String, HashSet<String>>> recentDatabaseNameMap; 62 return recentDatabaseNameMap; 63} 64 65static String combinedSecurityOriginIdentifier(const WebCore::SecurityOrigin& openingOrigin, const WebCore::SecurityOrigin& mainFrameOrigin) 66{ 67 StringBuilder stringBuilder; 68 69 String originString = openingOrigin.toString(); 70 if (originString == "null") 71 return String(); 72 stringBuilder.append(originString); 73 stringBuilder.append("_"); 74 75 originString = mainFrameOrigin.toString(); 76 if (originString == "null") 77 return String(); 78 stringBuilder.append(originString); 79 80 return stringBuilder.toString(); 81} 82 83WebIDBFactoryBackend::WebIDBFactoryBackend(const String&) 84{ 85} 86 87WebIDBFactoryBackend::~WebIDBFactoryBackend() 88{ 89} 90 91void WebIDBFactoryBackend::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin& mainFrameOrigin, ScriptExecutionContext* context, const String&) 92{ 93 LOG(IDB, "WebIDBFactoryBackend::getDatabaseNames"); 94 95 String securityOriginIdentifier = combinedSecurityOriginIdentifier(openingOrigin, mainFrameOrigin); 96 if (securityOriginIdentifier.isEmpty()) { 97 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::InvalidAccessError, ASCIILiteral("Document is not allowed to use Indexed Databases"))); 98 return; 99 } 100 101 auto recentNameIterator = sharedRecentDatabaseNameMap().find(securityOriginIdentifier); 102 if (recentNameIterator == sharedRecentDatabaseNameMap().end()) 103 return; 104 105 RefPtr<DOMStringList> databaseNames = DOMStringList::create(); 106 107 HashSet<String>& foundNames = recentNameIterator->value; 108 for (const String& name : foundNames) 109 databaseNames->append(name); 110 111 callbacks->onSuccess(databaseNames.release()); 112} 113 114void WebIDBFactoryBackend::open(const String& databaseName, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin& mainFrameOrigin) 115{ 116 ASSERT(RunLoop::isMain()); 117 LOG(IDB, "WebIDBFactoryBackend::open"); 118 119 String databaseIdentifier = uniqueDatabaseIdentifier(databaseName, openingOrigin, mainFrameOrigin); 120 if (databaseIdentifier.isNull()) { 121 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::InvalidAccessError, "Document is not allowed to use Indexed Databases")); 122 return; 123 } 124 125 String securityOriginIdentifier = combinedSecurityOriginIdentifier(openingOrigin, mainFrameOrigin); 126 ASSERT(!securityOriginIdentifier.isEmpty()); 127 128 auto recentNameIterator = sharedRecentDatabaseNameMap().find(securityOriginIdentifier); 129 if (recentNameIterator == sharedRecentDatabaseNameMap().end()) { 130 HashSet<String> names; 131 names.add(databaseName); 132 sharedRecentDatabaseNameMap().set(securityOriginIdentifier, names); 133 } else 134 recentNameIterator->value.add(databaseName); 135 136 IDBDatabaseBackendMap::iterator it = sharedDatabaseBackendMap().find(databaseIdentifier); 137 138 RefPtr<IDBDatabaseBackend> databaseBackend; 139 if (it == sharedDatabaseBackendMap().end()) { 140 RefPtr<IDBServerConnection> serverConnection = WebIDBServerConnection::create(databaseName, openingOrigin, mainFrameOrigin); 141 databaseBackend = IDBDatabaseBackend::create(databaseName, databaseIdentifier, this, *serverConnection); 142 sharedDatabaseBackendMap().set(databaseIdentifier, databaseBackend.get()); 143 } else 144 databaseBackend = it->value; 145 146 databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version); 147} 148 149void WebIDBFactoryBackend::deleteDatabase(const String& databaseName, const SecurityOrigin& openingOrigin, const SecurityOrigin& mainFrameOrigin, PassRefPtr<IDBCallbacks> callbacks, ScriptExecutionContext*, const String&) 150{ 151 ASSERT(RunLoop::isMain()); 152 LOG(IDB, "WebIDBFactoryBackend::deleteDatabase"); 153 154 String databaseIdentifier = uniqueDatabaseIdentifier(databaseName, openingOrigin, mainFrameOrigin); 155 if (databaseIdentifier.isNull()) { 156 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::InvalidAccessError, "Document is not allowed to use Indexed Databases")); 157 return; 158 } 159 160 String securityOriginIdentifier = combinedSecurityOriginIdentifier(openingOrigin, mainFrameOrigin); 161 ASSERT(!securityOriginIdentifier.isEmpty()); 162 163 auto recentNameIterator = sharedRecentDatabaseNameMap().find(securityOriginIdentifier); 164 if (recentNameIterator != sharedRecentDatabaseNameMap().end()) { 165 recentNameIterator->value.remove(databaseName); 166 if (recentNameIterator->value.isEmpty()) 167 sharedRecentDatabaseNameMap().remove(recentNameIterator); 168 } 169 170 // If there's already a connection to the database, delete it directly. 171 IDBDatabaseBackendMap::iterator it = sharedDatabaseBackendMap().find(databaseIdentifier); 172 if (it != sharedDatabaseBackendMap().end()) { 173 it->value->deleteDatabase(callbacks); 174 return; 175 } 176 177 RefPtr<IDBServerConnection> serverConnection = WebIDBServerConnection::create(databaseName, openingOrigin, mainFrameOrigin); 178 RefPtr<IDBDatabaseBackend> databaseBackend = IDBDatabaseBackend::create(databaseName, databaseIdentifier, this, *serverConnection); 179 180 sharedDatabaseBackendMap().set(databaseIdentifier, databaseBackend.get()); 181 databaseBackend->deleteDatabase(callbacks); 182 sharedDatabaseBackendMap().remove(databaseIdentifier); 183} 184 185void WebIDBFactoryBackend::removeIDBDatabaseBackend(const String& identifier) 186{ 187 sharedDatabaseBackendMap().remove(identifier); 188} 189 190} // namespace WebKit 191 192#endif // ENABLE(DATABASE_PROCESS) 193#endif // ENABLE(INDEXED_DATABASE) 194