10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch/* 20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * Copyright (C) 2008 Apple Inc. All Rights Reserved. 30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * Redistribution and use in source and binary forms, with or without 50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * modification, are permitted provided that the following conditions 60bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * are met: 70bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 1. Redistributions of source code must retain the above copyright 80bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * notice, this list of conditions and the following disclaimer. 90bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 2. Redistributions in binary form must reproduce the above copyright 100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * notice, this list of conditions and the following disclaimer in the 110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * documentation and/or other materials provided with the distribution. 120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch */ 250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "config.h" 270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageNamespaceImpl.h" 280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#if ENABLE(DOM_STORAGE) 300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "SecurityOriginHash.h" 320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageAreaImpl.h" 33231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "StorageMap.h" 340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageSyncManager.h" 352bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "StorageTracker.h" 360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <wtf/StdLibExtras.h> 37f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include <wtf/text/StringHash.h> 380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 391d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch#ifdef ANDROID 401d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch#include "Page.h" 411d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch#endif 421d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch 430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochnamespace WebCore { 440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochtypedef HashMap<String, StorageNamespace*> LocalStorageNamespaceMap; 460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic LocalStorageNamespaceMap& localStorageNamespaceMap() 480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch DEFINE_STATIC_LOCAL(LocalStorageNamespaceMap, localStorageNamespaceMap, ()); 500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return localStorageNamespaceMap; 510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 53231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockPassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path, unsigned quota) 540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch const String lookupPath = path.isNull() ? String("") : path; 560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch LocalStorageNamespaceMap::iterator it = localStorageNamespaceMap().find(lookupPath); 570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (it == localStorageNamespaceMap().end()) { 58231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota)); 590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch localStorageNamespaceMap().set(lookupPath, storageNamespace.get()); 600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return storageNamespace.release(); 610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return it->second; 640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace(unsigned quota) 670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), quota)); 690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 71231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockStorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota) 720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch : m_storageType(storageType) 73231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_path(path.crossThreadString()) 740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch , m_syncManager(0) 75231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_quota(quota) 760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch , m_isShutdown(false) 770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (m_storageType == LocalStorage && !m_path.isEmpty()) 790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch m_syncManager = StorageSyncManager::create(m_path); 800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochStorageNamespaceImpl::~StorageNamespaceImpl() 830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(isMainThread()); 850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (m_storageType == LocalStorage) { 870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(localStorageNamespaceMap().get(m_path) == this); 880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch localStorageNamespaceMap().remove(m_path); 890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 90231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (!m_isShutdown) 920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch close(); 930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochPassRefPtr<StorageNamespace> StorageNamespaceImpl::copy() 960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(isMainThread()); 980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(!m_isShutdown); 990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(m_storageType == SessionStorage); 1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 101e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block RefPtr<StorageNamespaceImpl> newNamespace = adoptRef(new StorageNamespaceImpl(m_storageType, m_path, m_quota)); 1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch StorageAreaMap::iterator end = m_storageAreaMap.end(); 1040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i) 1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch newNamespace->m_storageAreaMap.set(i->first, i->second->copy()); 106e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return newNamespace.release(); 1070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 1080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 109231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockPassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin) 1100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(isMainThread()); 1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(!m_isShutdown); 1130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 114231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block RefPtr<SecurityOrigin> origin = prpOrigin; 1150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch RefPtr<StorageAreaImpl> storageArea; 11606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if ((storageArea = m_storageAreaMap.get(origin))) 1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return storageArea.release(); 1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 119231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota); 120231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_storageAreaMap.set(origin.release(), storageArea); 1210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return storageArea.release(); 1220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 1230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageNamespaceImpl::close() 1250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 1260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(isMainThread()); 127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (m_isShutdown) 129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return; 130231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 1310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // If we're session storage, we shouldn't need to do any work here. 1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (m_storageType == SessionStorage) { 1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(!m_syncManager); 1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return; 1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch StorageAreaMap::iterator end = m_storageAreaMap.end(); 1380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 1390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch it->second->close(); 140231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 1410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (m_syncManager) 1420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch m_syncManager->close(); 1430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch m_isShutdown = true; 1450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 1460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1471d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch#ifdef ANDROID 1481d7cc17ccbeabb654e416c598e2631ff691166caBen Murdochvoid StorageNamespaceImpl::clear(Page* page) 1491d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch{ 1501d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch ASSERT(isMainThread()); 1511d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch if (m_isShutdown) 1521d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch return; 1531d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch 1541d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch // Clear all the keys for each of the storage areas. 1551d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch StorageAreaMap::iterator end = m_storageAreaMap.end(); 1561d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) { 1571d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch // if there is no page provided, then the user tried to clear storage 1581d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch // with only pages in private browsing mode open. So we do not need to 1591d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch // provide a Frame* here (as the frame is only used to dispatch storage events 1601d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch // and private browsing pages won't be using them). 1611d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch it->second->clear(page ? page->mainFrame() : 0); 1621d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch } 1631d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch} 1641d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch#endif 1651d7cc17ccbeabb654e416c598e2631ff691166caBen Murdoch 166231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid StorageNamespaceImpl::unlock() 167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 168231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // Because there's a single event loop per-process, this is a no-op. 169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 170231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 1712bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid StorageNamespaceImpl::clearOriginForDeletion(SecurityOrigin* origin) 1722bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1732bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(isMainThread()); 1742bde8e466a4451c7319e3a072d118917957d6554Steve Block 1752bde8e466a4451c7319e3a072d118917957d6554Steve Block RefPtr<StorageAreaImpl> storageArea = m_storageAreaMap.get(origin); 1762bde8e466a4451c7319e3a072d118917957d6554Steve Block if (storageArea) 1772bde8e466a4451c7319e3a072d118917957d6554Steve Block storageArea->clearForOriginDeletion(); 1782bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1792bde8e466a4451c7319e3a072d118917957d6554Steve Block 1802bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid StorageNamespaceImpl::clearAllOriginsForDeletion() 1812bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1822bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(isMainThread()); 1832bde8e466a4451c7319e3a072d118917957d6554Steve Block 1842bde8e466a4451c7319e3a072d118917957d6554Steve Block StorageAreaMap::iterator end = m_storageAreaMap.end(); 1852bde8e466a4451c7319e3a072d118917957d6554Steve Block for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 1862bde8e466a4451c7319e3a072d118917957d6554Steve Block it->second->clearForOriginDeletion(); 1872bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1882bde8e466a4451c7319e3a072d118917957d6554Steve Block 1892bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid StorageNamespaceImpl::sync() 1902bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 1912bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(isMainThread()); 1922bde8e466a4451c7319e3a072d118917957d6554Steve Block StorageAreaMap::iterator end = m_storageAreaMap.end(); 1932bde8e466a4451c7319e3a072d118917957d6554Steve Block for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it) 1942bde8e466a4451c7319e3a072d118917957d6554Steve Block it->second->sync(); 1952bde8e466a4451c7319e3a072d118917957d6554Steve Block} 1962bde8e466a4451c7319e3a072d118917957d6554Steve Block 1970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} // namespace WebCore 1980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 1990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#endif // ENABLE(DOM_STORAGE) 200