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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "IDBFactoryBackendImpl.h" 31 32#include "DOMStringList.h" 33#include "IDBBackingStore.h" 34#include "IDBDatabaseBackendImpl.h" 35#include "IDBDatabaseException.h" 36#include "IDBTracing.h" 37#include "IDBTransactionCoordinator.h" 38#include "SecurityOrigin.h" 39 40#if ENABLE(INDEXED_DATABASE) 41 42namespace WebCore { 43 44template<typename K, typename M> 45static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map) 46{ 47 HashMap<K, WeakPtr<M> > other; 48 other.swap(map); 49 50 typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin(); 51 while (iter != other.end()) { 52 if (iter->value.get()) 53 map.set(iter->key, iter->value); 54 ++iter; 55 } 56} 57 58static String computeFileIdentifier(SecurityOrigin* securityOrigin) 59{ 60 static const char levelDBFileSuffix[] = "@1"; 61 return securityOrigin->databaseIdentifier() + levelDBFileSuffix; 62} 63 64static String computeUniqueIdentifier(const String& name, SecurityOrigin* securityOrigin) 65{ 66 return computeFileIdentifier(securityOrigin) + name; 67} 68 69IDBFactoryBackendImpl::IDBFactoryBackendImpl() 70{ 71} 72 73IDBFactoryBackendImpl::~IDBFactoryBackendImpl() 74{ 75} 76 77void IDBFactoryBackendImpl::removeIDBDatabaseBackend(const String& uniqueIdentifier) 78{ 79 ASSERT(m_databaseBackendMap.contains(uniqueIdentifier)); 80 m_databaseBackendMap.remove(uniqueIdentifier); 81} 82 83void IDBFactoryBackendImpl::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory) 84{ 85 IDB_TRACE("IDBFactoryBackendImpl::getDatabaseNames"); 86 RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory); 87 if (!backingStore) { 88 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.webkitGetDatabaseNames.")); 89 return; 90 } 91 92 RefPtr<DOMStringList> databaseNames = DOMStringList::create(); 93 94 Vector<String> foundNames = backingStore->getDatabaseNames(); 95 for (Vector<String>::const_iterator it = foundNames.begin(); it != foundNames.end(); ++it) 96 databaseNames->append(*it); 97 98 callbacks->onSuccess(databaseNames.release()); 99} 100 101void IDBFactoryBackendImpl::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory) 102{ 103 IDB_TRACE("IDBFactoryBackendImpl::deleteDatabase"); 104 const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get()); 105 106 IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier); 107 if (it != m_databaseBackendMap.end()) { 108 // If there are any connections to the database, directly delete the 109 // database. 110 it->value->deleteDatabase(callbacks); 111 return; 112 } 113 114 // FIXME: Everything from now on should be done on another thread. 115 RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory); 116 if (!backingStore) { 117 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.deleteDatabase.")); 118 return; 119 } 120 121 RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier); 122 if (databaseBackend) { 123 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); 124 databaseBackend->deleteDatabase(callbacks); 125 m_databaseBackendMap.remove(uniqueIdentifier); 126 } else 127 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase.")); 128} 129 130PassRefPtr<IDBBackingStore> IDBFactoryBackendImpl::openBackingStore(PassRefPtr<SecurityOrigin> securityOrigin, const String& dataDirectory) 131{ 132 const String fileIdentifier = computeFileIdentifier(securityOrigin.get()); 133 const bool openInMemory = dataDirectory.isEmpty(); 134 135 IDBBackingStoreMap::iterator it2 = m_backingStoreMap.find(fileIdentifier); 136 if (it2 != m_backingStoreMap.end() && it2->value.get()) 137 return it2->value.get(); 138 139 RefPtr<IDBBackingStore> backingStore; 140 if (openInMemory) 141 backingStore = IDBBackingStore::openInMemory(securityOrigin.get(), fileIdentifier); 142 else 143 backingStore = IDBBackingStore::open(securityOrigin.get(), dataDirectory, fileIdentifier); 144 145 if (backingStore) { 146 cleanWeakMap(m_backingStoreMap); 147 m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr()); 148 // If an in-memory database, bind lifetime to this factory instance. 149 if (openInMemory) 150 m_sessionOnlyBackingStores.add(backingStore); 151 152 // All backing stores associated with this factory should be of the same type. 153 ASSERT(m_sessionOnlyBackingStores.isEmpty() || openInMemory); 154 155 return backingStore.release(); 156 } 157 158 return 0; 159} 160 161void IDBFactoryBackendImpl::open(const String& name, int64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, PassRefPtr<SecurityOrigin> prpSecurityOrigin, ScriptExecutionContext*, const String& dataDirectory) 162{ 163 IDB_TRACE("IDBFactoryBackendImpl::open"); 164 RefPtr<SecurityOrigin> securityOrigin = prpSecurityOrigin; 165 const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get()); 166 167 RefPtr<IDBDatabaseBackendImpl> databaseBackend; 168 IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier); 169 if (it == m_databaseBackendMap.end()) { 170 RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory); 171 if (!backingStore) { 172 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open.")); 173 return; 174 } 175 176 databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), this, uniqueIdentifier); 177 if (databaseBackend) 178 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); 179 else { 180 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open.")); 181 return; 182 } 183 } else 184 databaseBackend = it->value; 185 186 databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version); 187} 188 189} // namespace WebCore 190 191#endif // ENABLE(INDEXED_DATABASE) 192