• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
manager()50 DatabaseManager& DatabaseManager::manager()
51 {
52     AtomicallyInitializedStatic(DatabaseManager*, dbManager = new DatabaseManager);
53     return *dbManager;
54 }
55 
DatabaseManager()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 
~DatabaseManager()66 DatabaseManager::~DatabaseManager()
67 {
68 }
69 
70 class DatabaseCreationCallbackTask FINAL : public ExecutionContextTask {
71 public:
create(PassRefPtrWillBeRawPtr<Database> database,PassOwnPtr<DatabaseCallback> creationCallback)72     static PassOwnPtr<DatabaseCreationCallbackTask> create(PassRefPtrWillBeRawPtr<Database> database, PassOwnPtr<DatabaseCallback> creationCallback)
73     {
74         return adoptPtr(new DatabaseCreationCallbackTask(database, creationCallback));
75     }
76 
performTask(ExecutionContext *)77     virtual void performTask(ExecutionContext*) OVERRIDE
78     {
79         m_creationCallback->handleEvent(m_database.get());
80     }
81 
82 private:
DatabaseCreationCallbackTask(PassRefPtrWillBeRawPtr<Database> database,PassOwnPtr<DatabaseCallback> callback)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 
existingDatabaseContextFor(ExecutionContext * context)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 
databaseContextFor(ExecutionContext * context)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 
registerDatabaseContext(DatabaseContext * databaseContext)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 
unregisterDatabaseContext(DatabaseContext * databaseContext)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
didConstructDatabaseContext()144 void DatabaseManager::didConstructDatabaseContext()
145 {
146     MutexLocker lock(m_contextMapLock);
147     m_databaseContextInstanceCount++;
148 }
149 
didDestructDatabaseContext()150 void DatabaseManager::didDestructDatabaseContext()
151 {
152     MutexLocker lock(m_contextMapLock);
153     m_databaseContextInstanceCount--;
154     ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount);
155 }
156 #endif
157 
throwExceptionForDatabaseError(DatabaseError error,const String & errorMessage,ExceptionState & exceptionState)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 
logOpenDatabaseError(ExecutionContext * context,const String & name)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 
openDatabaseBackend(ExecutionContext * context,DatabaseType type,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize,bool setVersionInNewDatabase,DatabaseError & error,String & errorMessage)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 
openDatabase(ExecutionContext * context,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize,PassOwnPtr<DatabaseCallback> creationCallback,DatabaseError & error,String & errorMessage)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 
openDatabaseSync(ExecutionContext * context,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize,PassOwnPtr<DatabaseCallback> creationCallback,DatabaseError & error,String & errorMessage)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 
fullPathForDatabase(SecurityOrigin * origin,const String & name,bool createIfDoesNotExist)262 String DatabaseManager::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfDoesNotExist)
263 {
264     return m_server->fullPathForDatabase(origin, name, createIfDoesNotExist);
265 }
266 
closeDatabasesImmediately(const String & originIdentifier,const String & name)267 void DatabaseManager::closeDatabasesImmediately(const String& originIdentifier, const String& name)
268 {
269     m_server->closeDatabasesImmediately(originIdentifier, name);
270 }
271 
interruptAllDatabasesForContext(DatabaseContext * databaseContext)272 void DatabaseManager::interruptAllDatabasesForContext(DatabaseContext* databaseContext)
273 {
274     m_server->interruptAllDatabasesForContext(databaseContext->backend());
275 }
276 
logErrorMessage(ExecutionContext * context,const String & message)277 void DatabaseManager::logErrorMessage(ExecutionContext* context, const String& message)
278 {
279     context->addConsoleMessage(StorageMessageSource, ErrorMessageLevel, message);
280 }
281 
282 } // namespace WebCore
283