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 "DatabaseContext.h" 30 31#if ENABLE(SQL_DATABASE) 32 33#include "Chrome.h" 34#include "ChromeClient.h" 35#include "Database.h" 36#include "DatabaseBackendContext.h" 37#include "DatabaseManager.h" 38#include "DatabaseTask.h" 39#include "DatabaseThread.h" 40#include "Document.h" 41#include "Page.h" 42#include "SchemeRegistry.h" 43#include "ScriptExecutionContext.h" 44#include "SecurityOrigin.h" 45#include "Settings.h" 46 47namespace WebCore { 48 49// How the DatabaseContext Life-Cycle works? 50// ======================================== 51// ... in other words, who's keeping the DatabaseContext alive and how long does 52// it need to stay alive? 53// 54// The DatabaseContext is referenced from RefPtrs in: 55// 1. ScriptExecutionContext 56// 2. Database 57// 58// At Birth: 59// ======== 60// We create a DatabaseContext only when there is a need i.e. the script tries to 61// open a Database via DatabaseManager::openDatabase(). 62// 63// The DatabaseContext constructor will call setDatabaseContext() on the 64// the ScriptExecutionContext. This sets the RefPtr in the ScriptExecutionContext 65// for keeping the DatabaseContext alive. Since the DatabaseContext is only 66// created from the script thread, it is safe for the constructor to call 67// ScriptExecutionContext::setDatabaseContext(). 68// 69// Once a DatabaseContext is associated with a ScriptExecutionContext, it will 70// live until after the ScriptExecutionContext destructs. This is true even if 71// we don't succeed in opening any Databases for that context. When we do 72// succeed in opening Databases for this ScriptExecutionContext, the Database 73// will re-use the same DatabaseContext. 74// 75// At Shutdown: 76// =========== 77// During shutdown, the DatabaseContext needs to: 78// 1. "outlive" the ScriptExecutionContext. 79// - This is needed because the DatabaseContext needs to remove itself from the 80// ScriptExecutionContext's ActiveDOMObject list and ContextDestructionObserver 81// list. This removal needs to be executed on the script's thread. Hence, we 82// rely on the ScriptExecutionContext's shutdown process to call 83// stop() and contextDestroyed() to give us a chance to clean these up from 84// the script thread. 85// 86// 2. "outlive" the Databases. 87// - This is because they may make use of the DatabaseContext to execute a close 88// task and shutdown in an orderly manner. When the Databases are destructed, 89// they will deref the DatabaseContext from the DatabaseThread. 90// 91// During shutdown, the ScriptExecutionContext is shutting down on the script thread 92// while the Databases are shutting down on the DatabaseThread. Hence, there can be 93// a race condition as to whether the ScriptExecutionContext or the Databases 94// destruct first. 95// 96// The RefPtrs in the Databases and ScriptExecutionContext will ensure that the 97// DatabaseContext will outlive both regardless of which of the 2 destructs first. 98 99 100DatabaseContext::DatabaseContext(ScriptExecutionContext* context) 101 : ActiveDOMObject(context) 102 , m_hasOpenDatabases(false) 103 , m_isRegistered(true) // will register on construction below. 104 , m_hasRequestedTermination(false) 105{ 106 // ActiveDOMObject expects this to be called to set internal flags. 107 suspendIfNeeded(); 108 109 context->setDatabaseContext(this); 110 111 // For debug accounting only. We must do this before we register the 112 // instance. The assertions assume this. 113 DatabaseManager::manager().didConstructDatabaseContext(); 114 115 DatabaseManager::manager().registerDatabaseContext(this); 116} 117 118DatabaseContext::~DatabaseContext() 119{ 120 stopDatabases(); 121 ASSERT(!m_databaseThread || m_databaseThread->terminationRequested()); 122 123 // For debug accounting only. We must call this last. The assertions assume 124 // this. 125 DatabaseManager::manager().didDestructDatabaseContext(); 126} 127 128// This is called if the associated ScriptExecutionContext is destructing while 129// we're still associated with it. That's our cue to disassociate and shutdown. 130// To do this, we stop the database and let everything shutdown naturally 131// because the database closing process may still make use of this context. 132// It is not safe to just delete the context here. 133void DatabaseContext::contextDestroyed() 134{ 135 stopDatabases(); 136 137 // Normally, willDestroyActiveDOMObject() is called in ~ActiveDOMObject(). 138 // However, we're here because the destructor hasn't been called, and the 139 // ScriptExecutionContext we're associated with is about to be destructed. 140 // So, go ahead an unregister self from the ActiveDOMObject list, and 141 // set m_scriptExecutionContext to 0 so that ~ActiveDOMObject() doesn't 142 // try to do so again. 143 m_scriptExecutionContext->willDestroyActiveDOMObject(this); 144 m_scriptExecutionContext = 0; 145} 146 147// stop() is from stopActiveDOMObjects() which indicates that the owner Frame 148// or WorkerThread is shutting down. Initiate the orderly shutdown by stopping 149// the associated databases. 150void DatabaseContext::stop() 151{ 152 stopDatabases(); 153} 154 155PassRefPtr<DatabaseBackendContext> DatabaseContext::backend() 156{ 157 DatabaseBackendContext* backend = static_cast<DatabaseBackendContext*>(this); 158 return backend; 159} 160 161DatabaseThread* DatabaseContext::databaseThread() 162{ 163 if (!m_databaseThread && !m_hasOpenDatabases) { 164 // It's OK to ask for the m_databaseThread after we've requested 165 // termination because we're still using it to execute the closing 166 // of the database. However, it is NOT OK to create a new thread 167 // after we've requested termination. 168 ASSERT(!m_hasRequestedTermination); 169 170 // Create the database thread on first request - but not if at least one database was already opened, 171 // because in that case we already had a database thread and terminated it and should not create another. 172 m_databaseThread = DatabaseThread::create(); 173 if (!m_databaseThread->start()) 174 m_databaseThread = 0; 175 } 176 177 return m_databaseThread.get(); 178} 179 180bool DatabaseContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync) 181{ 182 if (m_isRegistered) { 183 DatabaseManager::manager().unregisterDatabaseContext(this); 184 m_isRegistered = false; 185 } 186 187 // Though we initiate termination of the DatabaseThread here in 188 // stopDatabases(), we can't clear the m_databaseThread ref till we get to 189 // the destructor. This is because the Databases that are managed by 190 // DatabaseThread still rely on this ref between the context and the thread 191 // to execute the task for closing the database. By the time we get to the 192 // destructor, we're guaranteed that the databases are destructed (which is 193 // why our ref count is 0 then and we're destructing). Then, the 194 // m_databaseThread RefPtr destructor will deref and delete the 195 // DatabaseThread. 196 197 if (m_databaseThread && !m_hasRequestedTermination) { 198 m_databaseThread->requestTermination(cleanupSync); 199 m_hasRequestedTermination = true; 200 return true; 201 } 202 return false; 203} 204 205bool DatabaseContext::allowDatabaseAccess() const 206{ 207 if (m_scriptExecutionContext->isDocument()) { 208 Document* document = toDocument(m_scriptExecutionContext); 209 if (!document->page() || (document->page()->settings()->privateBrowsingEnabled() && !SchemeRegistry::allowsDatabaseAccessInPrivateBrowsing(document->securityOrigin()->protocol()))) 210 return false; 211 return true; 212 } 213 ASSERT(m_scriptExecutionContext->isWorkerContext()); 214 // allowDatabaseAccess is not yet implemented for workers. 215 return true; 216} 217 218void DatabaseContext::databaseExceededQuota(const String& name, DatabaseDetails details) 219{ 220 if (m_scriptExecutionContext->isDocument()) { 221 Document* document = toDocument(m_scriptExecutionContext); 222 if (Page* page = document->page()) 223 page->chrome().client()->exceededDatabaseQuota(document->frame(), name, details); 224 return; 225 } 226 ASSERT(m_scriptExecutionContext->isWorkerContext()); 227 // FIXME: This needs a real implementation; this is a temporary solution for testing. 228 const unsigned long long defaultQuota = 5 * 1024 * 1024; 229 DatabaseManager::manager().setQuota(m_scriptExecutionContext->securityOrigin(), defaultQuota); 230} 231 232} // namespace WebCore 233 234#endif // ENABLE(SQL_DATABASE) 235