Home | History | Annotate | Download | only in webdatabase
      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