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