Home | History | Annotate | Download | only in webdatabase
      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