Home | History | Annotate | Download | only in storage
      1 /*
      2  * Copyright (C) 2008 Apple 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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "StorageAreaImpl.h"
     28 
     29 #if ENABLE(DOM_STORAGE)
     30 
     31 #include "ExceptionCode.h"
     32 #include "Frame.h"
     33 #include "Page.h"
     34 #include "Settings.h"
     35 #include "StorageAreaSync.h"
     36 #include "StorageEventDispatcher.h"
     37 #include "StorageMap.h"
     38 #include "StorageSyncManager.h"
     39 
     40 namespace WebCore {
     41 
     42 StorageAreaImpl::~StorageAreaImpl()
     43 {
     44     ASSERT(isMainThread());
     45 }
     46 
     47 inline StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
     48     : m_storageType(storageType)
     49     , m_securityOrigin(origin)
     50     , m_storageMap(StorageMap::create(quota))
     51     , m_storageSyncManager(syncManager)
     52 #ifndef NDEBUG
     53     , m_isShutdown(false)
     54 #endif
     55 {
     56     ASSERT(isMainThread());
     57     ASSERT(m_securityOrigin);
     58     ASSERT(m_storageMap);
     59 }
     60 
     61 PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
     62 {
     63     RefPtr<StorageAreaImpl> area = adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota));
     64 
     65     // FIXME: If there's no backing storage for LocalStorage, the default WebKit behavior should be that of private browsing,
     66     // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
     67     if (area->m_storageSyncManager) {
     68         area->m_storageAreaSync = StorageAreaSync::create(area->m_storageSyncManager, area.get(), area->m_securityOrigin->databaseIdentifier());
     69         ASSERT(area->m_storageAreaSync);
     70     }
     71 
     72     return area.release();
     73 }
     74 
     75 PassRefPtr<StorageAreaImpl> StorageAreaImpl::copy()
     76 {
     77     ASSERT(!m_isShutdown);
     78     return adoptRef(new StorageAreaImpl(this));
     79 }
     80 
     81 StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area)
     82     : m_storageType(area->m_storageType)
     83     , m_securityOrigin(area->m_securityOrigin)
     84     , m_storageMap(area->m_storageMap)
     85     , m_storageSyncManager(area->m_storageSyncManager)
     86 #ifndef NDEBUG
     87     , m_isShutdown(area->m_isShutdown)
     88 #endif
     89 {
     90     ASSERT(isMainThread());
     91     ASSERT(m_securityOrigin);
     92     ASSERT(m_storageMap);
     93     ASSERT(!m_isShutdown);
     94 }
     95 
     96 static bool privateBrowsingEnabled(Frame* frame)
     97 {
     98 #if PLATFORM(ANDROID)
     99     if (!frame)
    100         return false;
    101 #endif
    102 #if PLATFORM(CHROMIUM)
    103     // The frame pointer can be NULL in Chromium since this call is made in a different
    104     // process from where the Frame object exists.  Luckily, private browseing is
    105     // implemented differently in Chromium, so it'd never return true anyway.
    106     ASSERT(!frame);
    107     return false;
    108 #else
    109     return frame->page() && frame->page()->settings()->privateBrowsingEnabled();
    110 #endif
    111 }
    112 
    113 unsigned StorageAreaImpl::length() const
    114 {
    115     ASSERT(!m_isShutdown);
    116     blockUntilImportComplete();
    117 
    118     return m_storageMap->length();
    119 }
    120 
    121 String StorageAreaImpl::key(unsigned index) const
    122 {
    123     ASSERT(!m_isShutdown);
    124     blockUntilImportComplete();
    125 
    126     return m_storageMap->key(index);
    127 }
    128 
    129 String StorageAreaImpl::getItem(const String& key) const
    130 {
    131     ASSERT(!m_isShutdown);
    132     blockUntilImportComplete();
    133 
    134     return m_storageMap->getItem(key);
    135 }
    136 
    137 String StorageAreaImpl::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
    138 {
    139     ASSERT(!m_isShutdown);
    140     ASSERT(!value.isNull());
    141     blockUntilImportComplete();
    142 
    143     if (privateBrowsingEnabled(frame)) {
    144         ec = QUOTA_EXCEEDED_ERR;
    145         return String();
    146     }
    147 
    148     String oldValue;
    149     bool quotaException;
    150     RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
    151     if (newMap)
    152         m_storageMap = newMap.release();
    153 
    154     if (quotaException) {
    155         ec = QUOTA_EXCEEDED_ERR;
    156         return oldValue;
    157     }
    158 
    159     if (oldValue == value)
    160         return oldValue;
    161 
    162     if (m_storageAreaSync)
    163         m_storageAreaSync->scheduleItemForSync(key, value);
    164     StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame);
    165     return oldValue;
    166 }
    167 
    168 String StorageAreaImpl::removeItem(const String& key, Frame* frame)
    169 {
    170     ASSERT(!m_isShutdown);
    171     blockUntilImportComplete();
    172 
    173     if (privateBrowsingEnabled(frame))
    174         return String();
    175 
    176     String oldValue;
    177     RefPtr<StorageMap> newMap = m_storageMap->removeItem(key, oldValue);
    178     if (newMap)
    179         m_storageMap = newMap.release();
    180 
    181     if (oldValue.isNull())
    182         return oldValue;
    183 
    184     if (m_storageAreaSync)
    185         m_storageAreaSync->scheduleItemForSync(key, String());
    186     StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame);
    187     return oldValue;
    188 }
    189 
    190 bool StorageAreaImpl::clear(Frame* frame)
    191 {
    192     ASSERT(!m_isShutdown);
    193     blockUntilImportComplete();
    194 
    195     if (privateBrowsingEnabled(frame))
    196         return false;
    197 
    198     if (!m_storageMap->length())
    199         return false;
    200 
    201     unsigned quota = m_storageMap->quota();
    202     m_storageMap = StorageMap::create(quota);
    203 
    204     if (m_storageAreaSync)
    205         m_storageAreaSync->scheduleClear();
    206     StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame);
    207     return true;
    208 }
    209 
    210 bool StorageAreaImpl::contains(const String& key) const
    211 {
    212     ASSERT(!m_isShutdown);
    213     blockUntilImportComplete();
    214 
    215     return m_storageMap->contains(key);
    216 }
    217 
    218 void StorageAreaImpl::importItem(const String& key, const String& value)
    219 {
    220     ASSERT(!m_isShutdown);
    221     m_storageMap->importItem(key, value);
    222 }
    223 
    224 void StorageAreaImpl::close()
    225 {
    226     if (m_storageAreaSync)
    227         m_storageAreaSync->scheduleFinalSync();
    228 
    229 #ifndef NDEBUG
    230     m_isShutdown = true;
    231 #endif
    232 }
    233 
    234 void StorageAreaImpl::clearForOriginDeletion()
    235 {
    236     ASSERT(!m_isShutdown);
    237     blockUntilImportComplete();
    238 
    239     if (m_storageMap->length()) {
    240         unsigned quota = m_storageMap->quota();
    241         m_storageMap = StorageMap::create(quota);
    242     }
    243 
    244     if (m_storageAreaSync) {
    245         m_storageAreaSync->scheduleClear();
    246         m_storageAreaSync->scheduleCloseDatabase();
    247     }
    248 }
    249 
    250 void StorageAreaImpl::sync()
    251 {
    252     ASSERT(!m_isShutdown);
    253     blockUntilImportComplete();
    254 
    255     if (m_storageAreaSync)
    256         m_storageAreaSync->scheduleSync();
    257 }
    258 
    259 void StorageAreaImpl::blockUntilImportComplete() const
    260 {
    261     if (m_storageAreaSync)
    262         m_storageAreaSync->blockUntilImportComplete();
    263 }
    264 
    265 }
    266 
    267 #endif // ENABLE(DOM_STORAGE)
    268