Home | History | Annotate | Download | only in webdatabase
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2011 Google, Inc. All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  *
     26  */
     27 
     28 #include "config.h"
     29 #include "modules/webdatabase/DatabaseContext.h"
     30 
     31 #include "core/dom/Document.h"
     32 #include "core/dom/ScriptExecutionContext.h"
     33 #include "core/page/Chrome.h"
     34 #include "core/page/ChromeClient.h"
     35 #include "core/page/Page.h"
     36 #include "core/page/Settings.h"
     37 #include "modules/webdatabase/Database.h"
     38 #include "modules/webdatabase/DatabaseBackendContext.h"
     39 #include "modules/webdatabase/DatabaseManager.h"
     40 #include "modules/webdatabase/DatabaseTask.h"
     41 #include "modules/webdatabase/DatabaseThread.h"
     42 #include "weborigin/SchemeRegistry.h"
     43 #include "weborigin/SecurityOrigin.h"
     44 
     45 namespace WebCore {
     46 
     47 // How the DatabaseContext Life-Cycle works?
     48 // ========================================
     49 // ... in other words, who's keeping the DatabaseContext alive and how long does
     50 // it need to stay alive?
     51 //
     52 // The DatabaseContext is referenced from RefPtrs in:
     53 // 1. ScriptExecutionContext
     54 // 2. Database
     55 //
     56 // At Birth:
     57 // ========
     58 // We create a DatabaseContext only when there is a need i.e. the script tries to
     59 // open a Database via DatabaseManager::openDatabase().
     60 //
     61 // The DatabaseContext constructor will call setDatabaseContext() on the
     62 // the ScriptExecutionContext. This sets the RefPtr in the ScriptExecutionContext
     63 // for keeping the DatabaseContext alive. Since the DatabaseContext is only
     64 // created from the script thread, it is safe for the constructor to call
     65 // ScriptExecutionContext::setDatabaseContext().
     66 //
     67 // Once a DatabaseContext is associated with a ScriptExecutionContext, it will
     68 // live until after the ScriptExecutionContext destructs. This is true even if
     69 // we don't succeed in opening any Databases for that context. When we do
     70 // succeed in opening Databases for this ScriptExecutionContext, the Database
     71 // will re-use the same DatabaseContext.
     72 //
     73 // At Shutdown:
     74 // ===========
     75 // During shutdown, the DatabaseContext needs to:
     76 // 1. "outlive" the ScriptExecutionContext.
     77 //    - This is needed because the DatabaseContext needs to remove itself from the
     78 //      ScriptExecutionContext's ActiveDOMObject list and ContextLifecycleObserver
     79 //      list. This removal needs to be executed on the script's thread. Hence, we
     80 //      rely on the ScriptExecutionContext's shutdown process to call
     81 //      stop() and contextDestroyed() to give us a chance to clean these up from
     82 //      the script thread.
     83 //
     84 // 2. "outlive" the Databases.
     85 //    - This is because they may make use of the DatabaseContext to execute a close
     86 //      task and shutdown in an orderly manner. When the Databases are destructed,
     87 //      they will deref the DatabaseContext from the DatabaseThread.
     88 //
     89 // During shutdown, the ScriptExecutionContext is shutting down on the script thread
     90 // while the Databases are shutting down on the DatabaseThread. Hence, there can be
     91 // a race condition as to whether the ScriptExecutionContext or the Databases
     92 // destruct first.
     93 //
     94 // The RefPtrs in the Databases and ScriptExecutionContext will ensure that the
     95 // DatabaseContext will outlive both regardless of which of the 2 destructs first.
     96 
     97 
     98 DatabaseContext::DatabaseContext(ScriptExecutionContext* context)
     99     : ActiveDOMObject(context)
    100     , m_hasOpenDatabases(false)
    101     , m_isRegistered(true) // will register on construction below.
    102     , m_hasRequestedTermination(false)
    103 {
    104     // ActiveDOMObject expects this to be called to set internal flags.
    105     suspendIfNeeded();
    106 
    107     context->setDatabaseContext(this);
    108 
    109     // For debug accounting only. We must do this before we register the
    110     // instance. The assertions assume this.
    111     DatabaseManager::manager().didConstructDatabaseContext();
    112 
    113     DatabaseManager::manager().registerDatabaseContext(this);
    114 }
    115 
    116 DatabaseContext::~DatabaseContext()
    117 {
    118     stopDatabases();
    119     ASSERT(!m_databaseThread || m_databaseThread->terminationRequested());
    120 
    121     // For debug accounting only. We must call this last. The assertions assume
    122     // this.
    123     DatabaseManager::manager().didDestructDatabaseContext();
    124 }
    125 
    126 // This is called if the associated ScriptExecutionContext is destructing while
    127 // we're still associated with it. That's our cue to disassociate and shutdown.
    128 // To do this, we stop the database and let everything shutdown naturally
    129 // because the database closing process may still make use of this context.
    130 // It is not safe to just delete the context here.
    131 void DatabaseContext::contextDestroyed()
    132 {
    133     stopDatabases();
    134     ActiveDOMObject::contextDestroyed();
    135 }
    136 
    137 // stop() is from stopActiveDOMObjects() which indicates that the owner Frame
    138 // or WorkerThread is shutting down. Initiate the orderly shutdown by stopping
    139 // the associated databases.
    140 void DatabaseContext::stop()
    141 {
    142     stopDatabases();
    143 }
    144 
    145 PassRefPtr<DatabaseBackendContext> DatabaseContext::backend()
    146 {
    147     DatabaseBackendContext* backend = static_cast<DatabaseBackendContext*>(this);
    148     return backend;
    149 }
    150 
    151 DatabaseThread* DatabaseContext::databaseThread()
    152 {
    153     if (!m_databaseThread && !m_hasOpenDatabases) {
    154         // It's OK to ask for the m_databaseThread after we've requested
    155         // termination because we're still using it to execute the closing
    156         // of the database. However, it is NOT OK to create a new thread
    157         // after we've requested termination.
    158         ASSERT(!m_hasRequestedTermination);
    159 
    160         // Create the database thread on first request - but not if at least one database was already opened,
    161         // because in that case we already had a database thread and terminated it and should not create another.
    162         m_databaseThread = DatabaseThread::create();
    163         if (!m_databaseThread->start())
    164             m_databaseThread = 0;
    165     }
    166 
    167     return m_databaseThread.get();
    168 }
    169 
    170 bool DatabaseContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
    171 {
    172     if (m_isRegistered) {
    173         DatabaseManager::manager().unregisterDatabaseContext(this);
    174         m_isRegistered = false;
    175     }
    176 
    177     // Though we initiate termination of the DatabaseThread here in
    178     // stopDatabases(), we can't clear the m_databaseThread ref till we get to
    179     // the destructor. This is because the Databases that are managed by
    180     // DatabaseThread still rely on this ref between the context and the thread
    181     // to execute the task for closing the database. By the time we get to the
    182     // destructor, we're guaranteed that the databases are destructed (which is
    183     // why our ref count is 0 then and we're destructing). Then, the
    184     // m_databaseThread RefPtr destructor will deref and delete the
    185     // DatabaseThread.
    186 
    187     if (m_databaseThread && !m_hasRequestedTermination) {
    188         m_databaseThread->requestTermination(cleanupSync);
    189         m_hasRequestedTermination = true;
    190         return true;
    191     }
    192     return false;
    193 }
    194 
    195 bool DatabaseContext::allowDatabaseAccess() const
    196 {
    197     if (scriptExecutionContext()->isDocument()) {
    198         Document* document = toDocument(scriptExecutionContext());
    199         return document->page();
    200     }
    201     ASSERT(scriptExecutionContext()->isWorkerGlobalScope());
    202     // allowDatabaseAccess is not yet implemented for workers.
    203     return true;
    204 }
    205 
    206 } // namespace WebCore
    207