• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "modules/webdatabase/DatabaseTracker.h"
33 
34 #include "core/dom/ExecutionContext.h"
35 #include "core/dom/ExecutionContextTask.h"
36 #include "modules/webdatabase/DatabaseBackendBase.h"
37 #include "modules/webdatabase/DatabaseClient.h"
38 #include "modules/webdatabase/DatabaseContext.h"
39 #include "modules/webdatabase/QuotaTracker.h"
40 #include "modules/webdatabase/sqlite/SQLiteFileSystem.h"
41 #include "platform/weborigin/DatabaseIdentifier.h"
42 #include "platform/weborigin/SecurityOrigin.h"
43 #include "platform/weborigin/SecurityOriginHash.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebDatabaseObserver.h"
46 #include "wtf/Assertions.h"
47 #include "wtf/StdLibExtras.h"
48 
49 namespace WebCore {
50 
databaseClosed(DatabaseBackendBase * database)51 static void databaseClosed(DatabaseBackendBase* database)
52 {
53     if (blink::Platform::current()->databaseObserver()) {
54         blink::Platform::current()->databaseObserver()->databaseClosed(
55             createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin()),
56             database->stringIdentifier());
57     }
58 }
59 
tracker()60 DatabaseTracker& DatabaseTracker::tracker()
61 {
62     AtomicallyInitializedStatic(DatabaseTracker&, tracker = *new DatabaseTracker());
63     return tracker;
64 }
65 
DatabaseTracker()66 DatabaseTracker::DatabaseTracker()
67 {
68     SQLiteFileSystem::registerSQLiteVFS();
69 }
70 
canEstablishDatabase(DatabaseContext * databaseContext,const String & name,const String & displayName,unsigned long estimatedSize,DatabaseError & error)71 bool DatabaseTracker::canEstablishDatabase(DatabaseContext* databaseContext, const String& name, const String& displayName, unsigned long estimatedSize, DatabaseError& error)
72 {
73     ExecutionContext* executionContext = databaseContext->executionContext();
74     bool success = DatabaseClient::from(executionContext)->allowDatabase(executionContext, name, displayName, estimatedSize);
75     if (!success)
76         error = DatabaseError::GenericSecurityError;
77     return success;
78 }
79 
fullPathForDatabase(SecurityOrigin * origin,const String & name,bool)80 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool)
81 {
82     return createDatabaseIdentifierFromSecurityOrigin(origin) + "/" + name + "#";
83 }
84 
addOpenDatabase(DatabaseBackendBase * database)85 void DatabaseTracker::addOpenDatabase(DatabaseBackendBase* database)
86 {
87     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
88     if (!m_openDatabaseMap)
89         m_openDatabaseMap = adoptPtr(new DatabaseOriginMap);
90 
91     String originIdentifier = createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin());
92     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
93     if (!nameMap) {
94         nameMap = new DatabaseNameMap();
95         m_openDatabaseMap->set(originIdentifier, nameMap);
96     }
97 
98     String name(database->stringIdentifier());
99     DatabaseSet* databaseSet = nameMap->get(name);
100     if (!databaseSet) {
101         databaseSet = new DatabaseSet();
102         nameMap->set(name, databaseSet);
103     }
104 
105     databaseSet->add(database);
106 }
107 
108 class NotifyDatabaseObserverOnCloseTask : public ExecutionContextTask {
109 public:
create(PassRefPtr<DatabaseBackendBase> database)110     static PassOwnPtr<NotifyDatabaseObserverOnCloseTask> create(PassRefPtr<DatabaseBackendBase> database)
111     {
112         return adoptPtr(new NotifyDatabaseObserverOnCloseTask(database));
113     }
114 
performTask(ExecutionContext * context)115     virtual void performTask(ExecutionContext* context)
116     {
117         databaseClosed(m_database.get());
118     }
119 
isCleanupTask() const120     virtual bool isCleanupTask() const
121     {
122         return true;
123     }
124 
125 private:
NotifyDatabaseObserverOnCloseTask(PassRefPtr<DatabaseBackendBase> database)126     NotifyDatabaseObserverOnCloseTask(PassRefPtr<DatabaseBackendBase> database)
127         : m_database(database)
128     {
129     }
130 
131     RefPtr<DatabaseBackendBase> m_database;
132 };
133 
removeOpenDatabase(DatabaseBackendBase * database)134 void DatabaseTracker::removeOpenDatabase(DatabaseBackendBase* database)
135 {
136     String originIdentifier = createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin());
137     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
138     ASSERT(m_openDatabaseMap);
139     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
140     if (!nameMap)
141         return;
142 
143     String name(database->stringIdentifier());
144     DatabaseSet* databaseSet = nameMap->get(name);
145     if (!databaseSet)
146         return;
147 
148     DatabaseSet::iterator found = databaseSet->find(database);
149     if (found == databaseSet->end())
150         return;
151 
152     databaseSet->remove(found);
153     if (databaseSet->isEmpty()) {
154         nameMap->remove(name);
155         delete databaseSet;
156         if (nameMap->isEmpty()) {
157             m_openDatabaseMap->remove(originIdentifier);
158             delete nameMap;
159         }
160     }
161 
162     ExecutionContext* executionContext = database->databaseContext()->executionContext();
163     if (!executionContext->isContextThread())
164         executionContext->postTask(NotifyDatabaseObserverOnCloseTask::create(database));
165     else
166         databaseClosed(database);
167 }
168 
prepareToOpenDatabase(DatabaseBackendBase * database)169 void DatabaseTracker::prepareToOpenDatabase(DatabaseBackendBase* database)
170 {
171     ASSERT(database->databaseContext()->executionContext()->isContextThread());
172     if (blink::Platform::current()->databaseObserver()) {
173         blink::Platform::current()->databaseObserver()->databaseOpened(
174             createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin()),
175             database->stringIdentifier(),
176             database->displayName(),
177             database->estimatedSize());
178     }
179 }
180 
failedToOpenDatabase(DatabaseBackendBase * database)181 void DatabaseTracker::failedToOpenDatabase(DatabaseBackendBase* database)
182 {
183     ExecutionContext* executionContext = database->databaseContext()->executionContext();
184     if (!executionContext->isContextThread())
185         executionContext->postTask(NotifyDatabaseObserverOnCloseTask::create(database));
186     else
187         databaseClosed(database);
188 }
189 
getMaxSizeForDatabase(const DatabaseBackendBase * database)190 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const DatabaseBackendBase* database)
191 {
192     unsigned long long spaceAvailable = 0;
193     unsigned long long databaseSize = 0;
194     QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin(
195         createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin()),
196         database->stringIdentifier(), &databaseSize, &spaceAvailable);
197     return databaseSize + spaceAvailable;
198 }
199 
interruptAllDatabasesForContext(const DatabaseContext * context)200 void DatabaseTracker::interruptAllDatabasesForContext(const DatabaseContext* context)
201 {
202     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
203 
204     if (!m_openDatabaseMap)
205         return;
206 
207     DatabaseNameMap* nameMap = m_openDatabaseMap->get(createDatabaseIdentifierFromSecurityOrigin(context->securityOrigin()));
208     if (!nameMap)
209         return;
210 
211     DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
212     for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
213         DatabaseSet* databaseSet = dbNameMapIt->value;
214         DatabaseSet::const_iterator end = databaseSet->end();
215         for (DatabaseSet::const_iterator it = databaseSet->begin(); it != end; ++it) {
216             if ((*it)->databaseContext() == context)
217                 (*it)->interrupt();
218         }
219     }
220 }
221 
222 class DatabaseTracker::CloseOneDatabaseImmediatelyTask : public ExecutionContextTask {
223 public:
create(const String & originIdentifier,const String & name,DatabaseBackendBase * database)224     static PassOwnPtr<CloseOneDatabaseImmediatelyTask> create(const String& originIdentifier, const String& name, DatabaseBackendBase* database)
225     {
226         return adoptPtr(new CloseOneDatabaseImmediatelyTask(originIdentifier, name, database));
227     }
228 
performTask(ExecutionContext * context)229     virtual void performTask(ExecutionContext* context)
230     {
231         DatabaseTracker::tracker().closeOneDatabaseImmediately(m_originIdentifier, m_name, m_database);
232     }
233 
234 private:
CloseOneDatabaseImmediatelyTask(const String & originIdentifier,const String & name,DatabaseBackendBase * database)235     CloseOneDatabaseImmediatelyTask(const String& originIdentifier, const String& name, DatabaseBackendBase* database)
236         : m_originIdentifier(originIdentifier.isolatedCopy())
237         , m_name(name.isolatedCopy())
238         , m_database(database)
239     {
240     }
241 
242     String m_originIdentifier;
243     String m_name;
244     DatabaseBackendBase* m_database; // Intentionally a raw pointer.
245 };
246 
closeDatabasesImmediately(const String & originIdentifier,const String & name)247 void DatabaseTracker::closeDatabasesImmediately(const String& originIdentifier, const String& name)
248 {
249     MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
250     if (!m_openDatabaseMap)
251         return;
252 
253     DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
254     if (!nameMap)
255         return;
256 
257     DatabaseSet* databaseSet = nameMap->get(name);
258     if (!databaseSet)
259         return;
260 
261     // We have to call closeImmediately() on the context thread and we cannot safely add a reference to
262     // the database in our collection when not on the context thread (which is always the case given
263     // current usage).
264     for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it)
265         (*it)->databaseContext()->executionContext()->postTask(CloseOneDatabaseImmediatelyTask::create(originIdentifier, name, *it));
266 }
267 
closeOneDatabaseImmediately(const String & originIdentifier,const String & name,DatabaseBackendBase * database)268 void DatabaseTracker::closeOneDatabaseImmediately(const String& originIdentifier, const String& name, DatabaseBackendBase* database)
269 {
270     // First we have to confirm the 'database' is still in our collection.
271     {
272         MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
273         if (!m_openDatabaseMap)
274             return;
275 
276         DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier);
277         if (!nameMap)
278             return;
279 
280         DatabaseSet* databaseSet = nameMap->get(name);
281         if (!databaseSet)
282             return;
283 
284         DatabaseSet::iterator found = databaseSet->find(database);
285         if (found == databaseSet->end())
286             return;
287     }
288 
289     // And we have to call closeImmediately() without our collection lock being held.
290     database->closeImmediately();
291 }
292 
293 }
294