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