1 /* 2 * Copyright (C) 2012 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 #include "config.h" 27 #include "modules/webdatabase/DatabaseManager.h" 28 29 #include "bindings/v8/ExceptionMessages.h" 30 #include "bindings/v8/ExceptionState.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/dom/ExecutionContext.h" 33 #include "core/dom/ExecutionContextTask.h" 34 #include "platform/Logging.h" 35 #include "modules/webdatabase/AbstractDatabaseServer.h" 36 #include "modules/webdatabase/Database.h" 37 #include "modules/webdatabase/DatabaseBackend.h" 38 #include "modules/webdatabase/DatabaseBackendBase.h" 39 #include "modules/webdatabase/DatabaseBackendSync.h" 40 #include "modules/webdatabase/DatabaseCallback.h" 41 #include "modules/webdatabase/DatabaseClient.h" 42 #include "modules/webdatabase/DatabaseContext.h" 43 #include "modules/webdatabase/DatabaseServer.h" 44 #include "modules/webdatabase/DatabaseSync.h" 45 #include "modules/webdatabase/DatabaseTask.h" 46 #include "platform/weborigin/SecurityOrigin.h" 47 48 namespace WebCore { 49 50 DatabaseManager& DatabaseManager::manager() 51 { 52 AtomicallyInitializedStatic(DatabaseManager*, dbManager = new DatabaseManager); 53 return *dbManager; 54 } 55 56 DatabaseManager::DatabaseManager() 57 #if ASSERT_ENABLED 58 : m_databaseContextRegisteredCount(0) 59 , m_databaseContextInstanceCount(0) 60 #endif 61 { 62 m_server = new DatabaseServer; 63 ASSERT(m_server); // We should always have a server to work with. 64 } 65 66 DatabaseManager::~DatabaseManager() 67 { 68 } 69 70 class DatabaseCreationCallbackTask FINAL : public ExecutionContextTask { 71 public: 72 static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtrWillBeRawPtr<Database> database, PassOwnPtr<DatabaseCallback> creationCallback) 73 { 74 return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback)); 75 } 76 77 virtual void performTask(ExecutionContext*) OVERRIDE 78 { 79 m_creationCallback->handleEvent(m_database.get()); 80 } 81 82 private: 83 DatabaseCreationCallbackTask(PassRefPtrWillBeRawPtr<Database> database, PassOwnPtr<DatabaseCallback> callback) 84 : m_database(database) 85 , m_creationCallback(callback) 86 { 87 } 88 89 RefPtrWillBePersistent<Database> m_database; 90 OwnPtr<DatabaseCallback> m_creationCallback; 91 }; 92 93 DatabaseContext* DatabaseManager::existingDatabaseContextFor(ExecutionContext* context) 94 { 95 MutexLocker locker(m_contextMapLock); 96 97 ASSERT(m_databaseContextRegisteredCount >= 0); 98 ASSERT(m_databaseContextInstanceCount >= 0); 99 ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount); 100 #if ENABLE(OILPAN) 101 const Persistent<DatabaseContext>* databaseContext = m_contextMap.get(context); 102 return databaseContext ? databaseContext->get() : 0; 103 #else 104 return m_contextMap.get(context); 105 #endif 106 } 107 108 DatabaseContext* DatabaseManager::databaseContextFor(ExecutionContext* context) 109 { 110 if (DatabaseContext* databaseContext = existingDatabaseContextFor(context)) 111 return databaseContext; 112 // We don't need to hold a reference returned by DatabaseContext::create 113 // because DatabaseContext::create calls registerDatabaseContext, and the 114 // DatabaseManager holds a reference. 115 return DatabaseContext::create(context).get(); 116 } 117 118 void DatabaseManager::registerDatabaseContext(DatabaseContext* databaseContext) 119 { 120 MutexLocker locker(m_contextMapLock); 121 ExecutionContext* context = databaseContext->executionContext(); 122 #if ENABLE(OILPAN) 123 m_contextMap.set(context, adoptPtr(new Persistent<DatabaseContext>(databaseContext))); 124 #else 125 m_contextMap.set(context, databaseContext); 126 #endif 127 #if ASSERT_ENABLED 128 m_databaseContextRegisteredCount++; 129 #endif 130 } 131 132 void DatabaseManager::unregisterDatabaseContext(DatabaseContext* databaseContext) 133 { 134 MutexLocker locker(m_contextMapLock); 135 ExecutionContext* context = databaseContext->executionContext(); 136 ASSERT(m_contextMap.get(context)); 137 #if ASSERT_ENABLED 138 m_databaseContextRegisteredCount--; 139 #endif 140 m_contextMap.remove(context); 141 } 142 143 #if ASSERT_ENABLED 144 void DatabaseManager::didConstructDatabaseContext() 145 { 146 MutexLocker lock(m_contextMapLock); 147 m_databaseContextInstanceCount++; 148 } 149 150 void DatabaseManager::didDestructDatabaseContext() 151 { 152 MutexLocker lock(m_contextMapLock); 153 m_databaseContextInstanceCount--; 154 ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount); 155 } 156 #endif 157 158 void DatabaseManager::throwExceptionForDatabaseError(DatabaseError error, const String& errorMessage, ExceptionState& exceptionState) 159 { 160 switch (error) { 161 case DatabaseError::None: 162 return; 163 case DatabaseError::GenericSecurityError: 164 exceptionState.throwSecurityError(errorMessage); 165 return; 166 case DatabaseError::InvalidDatabaseState: 167 exceptionState.throwDOMException(InvalidStateError, errorMessage); 168 return; 169 default: 170 ASSERT_NOT_REACHED(); 171 } 172 } 173 174 static void logOpenDatabaseError(ExecutionContext* context, const String& name) 175 { 176 WTF_LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), 177 context->securityOrigin()->toString().ascii().data()); 178 } 179 180 PassRefPtrWillBeRawPtr<DatabaseBackendBase> DatabaseManager::openDatabaseBackend(ExecutionContext* context, 181 DatabaseType type, const String& name, const String& expectedVersion, const String& displayName, 182 unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 183 { 184 ASSERT(error == DatabaseError::None); 185 186 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = m_server->openDatabase( 187 databaseContextFor(context)->backend(), type, name, expectedVersion, 188 displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage); 189 190 if (!backend) { 191 ASSERT(error != DatabaseError::None); 192 193 switch (error) { 194 case DatabaseError::GenericSecurityError: 195 logOpenDatabaseError(context, name); 196 return nullptr; 197 198 case DatabaseError::InvalidDatabaseState: 199 logErrorMessage(context, errorMessage); 200 return nullptr; 201 202 default: 203 ASSERT_NOT_REACHED(); 204 } 205 } 206 207 return backend.release(); 208 } 209 210 PassRefPtrWillBeRawPtr<Database> DatabaseManager::openDatabase(ExecutionContext* context, 211 const String& name, const String& expectedVersion, const String& displayName, 212 unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback, 213 DatabaseError& error, String& errorMessage) 214 { 215 ASSERT(error == DatabaseError::None); 216 217 bool setVersionInNewDatabase = !creationCallback; 218 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = openDatabaseBackend(context, DatabaseType::Async, name, 219 expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage); 220 if (!backend) 221 return nullptr; 222 223 RefPtrWillBeRawPtr<Database> database = Database::create(context, backend); 224 225 databaseContextFor(context)->setHasOpenDatabases(); 226 DatabaseClient::from(context)->didOpenDatabase(database, context->securityOrigin()->host(), name, expectedVersion); 227 228 if (backend->isNew() && creationCallback.get()) { 229 WTF_LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get()); 230 database->executionContext()->postTask(DatabaseCreationCallbackTask::create(database, creationCallback)); 231 } 232 233 ASSERT(database); 234 return database.release(); 235 } 236 237 PassRefPtrWillBeRawPtr<DatabaseSync> DatabaseManager::openDatabaseSync(ExecutionContext* context, 238 const String& name, const String& expectedVersion, const String& displayName, 239 unsigned long estimatedSize, PassOwnPtr<DatabaseCallback> creationCallback, 240 DatabaseError& error, String& errorMessage) 241 { 242 ASSERT(context->isContextThread()); 243 ASSERT(error == DatabaseError::None); 244 245 bool setVersionInNewDatabase = !creationCallback; 246 RefPtrWillBeRawPtr<DatabaseBackendBase> backend = openDatabaseBackend(context, DatabaseType::Sync, name, 247 expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage); 248 if (!backend) 249 return nullptr; 250 251 RefPtrWillBeRawPtr<DatabaseSync> database = DatabaseSync::create(context, backend); 252 253 if (backend->isNew() && creationCallback.get()) { 254 WTF_LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get()); 255 creationCallback->handleEvent(database.get()); 256 } 257 258 ASSERT(database); 259 return database.release(); 260 } 261 262 String DatabaseManager::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfDoesNotExist) 263 { 264 return m_server->fullPathForDatabase(origin, name, createIfDoesNotExist); 265 } 266 267 void DatabaseManager::closeDatabasesImmediately(const String& originIdentifier, const String& name) 268 { 269 m_server->closeDatabasesImmediately(originIdentifier, name); 270 } 271 272 void DatabaseManager::interruptAllDatabasesForContext(DatabaseContext* databaseContext) 273 { 274 m_server->interruptAllDatabasesForContext(databaseContext->backend()); 275 } 276 277 void DatabaseManager::logErrorMessage(ExecutionContext* context, const String& message) 278 { 279 context->addConsoleMessage(StorageMessageSource, ErrorMessageLevel, message); 280 } 281 282 } // namespace WebCore 283