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/Database.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 blink { 50 51 static void databaseClosed(Database* database) 52 { 53 if (Platform::current()->databaseObserver()) { 54 Platform::current()->databaseObserver()->databaseClosed( 55 createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin()), 56 database->stringIdentifier()); 57 } 58 } 59 60 DatabaseTracker& DatabaseTracker::tracker() 61 { 62 AtomicallyInitializedStatic(DatabaseTracker&, tracker = *new DatabaseTracker()); 63 return tracker; 64 } 65 66 DatabaseTracker::DatabaseTracker() 67 { 68 SQLiteFileSystem::registerSQLiteVFS(); 69 } 70 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 80 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool) 81 { 82 return createDatabaseIdentifierFromSecurityOrigin(origin) + "/" + name + "#"; 83 } 84 85 void DatabaseTracker::addOpenDatabase(Database* 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 FINAL : public ExecutionContextTask { 109 public: 110 static PassOwnPtr<NotifyDatabaseObserverOnCloseTask> create(PassRefPtrWillBeRawPtr<Database> database) 111 { 112 return adoptPtr(new NotifyDatabaseObserverOnCloseTask(database)); 113 } 114 115 virtual void performTask(ExecutionContext*) OVERRIDE 116 { 117 databaseClosed(m_database.get()); 118 } 119 120 virtual bool isCleanupTask() const OVERRIDE 121 { 122 return true; 123 } 124 125 private: 126 explicit NotifyDatabaseObserverOnCloseTask(PassRefPtrWillBeRawPtr<Database> database) 127 : m_database(database) 128 { 129 } 130 131 RefPtrWillBeCrossThreadPersistent<Database> m_database; 132 }; 133 134 void DatabaseTracker::removeOpenDatabase(Database* 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 169 void DatabaseTracker::prepareToOpenDatabase(Database* database) 170 { 171 ASSERT(database->databaseContext()->executionContext()->isContextThread()); 172 if (Platform::current()->databaseObserver()) { 173 Platform::current()->databaseObserver()->databaseOpened( 174 createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin()), 175 database->stringIdentifier(), 176 database->displayName(), 177 database->estimatedSize()); 178 } 179 } 180 181 void DatabaseTracker::failedToOpenDatabase(Database* 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 190 unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* 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 200 class DatabaseTracker::CloseOneDatabaseImmediatelyTask FINAL : public ExecutionContextTask { 201 public: 202 static PassOwnPtr<CloseOneDatabaseImmediatelyTask> create(const String& originIdentifier, const String& name, Database* database) 203 { 204 return adoptPtr(new CloseOneDatabaseImmediatelyTask(originIdentifier, name, database)); 205 } 206 207 virtual void performTask(ExecutionContext*) OVERRIDE 208 { 209 DatabaseTracker::tracker().closeOneDatabaseImmediately(m_originIdentifier, m_name, m_database); 210 } 211 212 private: 213 CloseOneDatabaseImmediatelyTask(const String& originIdentifier, const String& name, Database* database) 214 : m_originIdentifier(originIdentifier.isolatedCopy()) 215 , m_name(name.isolatedCopy()) 216 , m_database(database) 217 { 218 } 219 220 String m_originIdentifier; 221 String m_name; 222 Database* m_database; // Intentionally a raw pointer. 223 }; 224 225 void DatabaseTracker::closeDatabasesImmediately(const String& originIdentifier, const String& name) 226 { 227 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); 228 if (!m_openDatabaseMap) 229 return; 230 231 DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); 232 if (!nameMap) 233 return; 234 235 DatabaseSet* databaseSet = nameMap->get(name); 236 if (!databaseSet) 237 return; 238 239 // We have to call closeImmediately() on the context thread and we cannot safely add a reference to 240 // the database in our collection when not on the context thread (which is always the case given 241 // current usage). 242 for (DatabaseSet::iterator it = databaseSet->begin(); it != databaseSet->end(); ++it) 243 (*it)->databaseContext()->executionContext()->postTask(CloseOneDatabaseImmediatelyTask::create(originIdentifier, name, *it)); 244 } 245 246 void DatabaseTracker::closeOneDatabaseImmediately(const String& originIdentifier, const String& name, Database* database) 247 { 248 // First we have to confirm the 'database' is still in our collection. 249 { 250 MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard); 251 if (!m_openDatabaseMap) 252 return; 253 254 DatabaseNameMap* nameMap = m_openDatabaseMap->get(originIdentifier); 255 if (!nameMap) 256 return; 257 258 DatabaseSet* databaseSet = nameMap->get(name); 259 if (!databaseSet) 260 return; 261 262 DatabaseSet::iterator found = databaseSet->find(database); 263 if (found == databaseSet->end()) 264 return; 265 } 266 267 // And we have to call closeImmediately() without our collection lock being held. 268 database->closeImmediately(); 269 } 270 271 } // namespace blink 272