Home | History | Annotate | Download | only in storage
      1 /*
      2  * Copyright (C) 2009 Google Inc. All Rights Reserved.
      3  *           (C) 2008 Apple Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      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  *
     14  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/storage/StorageArea.h"
     29 
     30 #include "bindings/core/v8/ExceptionState.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/ExceptionCode.h"
     33 #include "core/frame/LocalDOMWindow.h"
     34 #include "core/frame/LocalFrame.h"
     35 #include "core/inspector/InspectorInstrumentation.h"
     36 #include "core/page/Page.h"
     37 #include "core/page/StorageClient.h"
     38 #include "core/storage/Storage.h"
     39 #include "core/storage/StorageEvent.h"
     40 #include "core/storage/StorageNamespace.h"
     41 #include "platform/weborigin/SecurityOrigin.h"
     42 #include "public/platform/WebStorageArea.h"
     43 #include "public/platform/WebString.h"
     44 #include "public/platform/WebURL.h"
     45 
     46 namespace blink {
     47 
     48 PassOwnPtrWillBeRawPtr<StorageArea> StorageArea::create(PassOwnPtr<WebStorageArea> storageArea, StorageType storageType)
     49 {
     50     return adoptPtrWillBeNoop(new StorageArea(storageArea, storageType));
     51 }
     52 
     53 StorageArea::StorageArea(PassOwnPtr<WebStorageArea> storageArea, StorageType storageType)
     54     : FrameDestructionObserver(nullptr)
     55     , m_storageArea(storageArea)
     56     , m_storageType(storageType)
     57     , m_canAccessStorageCachedResult(false)
     58 {
     59 }
     60 
     61 StorageArea::~StorageArea()
     62 {
     63 }
     64 
     65 void StorageArea::trace(Visitor* visitor)
     66 {
     67     FrameDestructionObserver::trace(visitor);
     68 }
     69 
     70 unsigned StorageArea::length(ExceptionState& exceptionState, LocalFrame* frame)
     71 {
     72     if (!canAccessStorage(frame)) {
     73         exceptionState.throwSecurityError("access is denied for this document.");
     74         return 0;
     75     }
     76     return m_storageArea->length();
     77 }
     78 
     79 String StorageArea::key(unsigned index, ExceptionState& exceptionState, LocalFrame* frame)
     80 {
     81     if (!canAccessStorage(frame)) {
     82         exceptionState.throwSecurityError("access is denied for this document.");
     83         return String();
     84     }
     85     return m_storageArea->key(index);
     86 }
     87 
     88 String StorageArea::getItem(const String& key, ExceptionState& exceptionState, LocalFrame* frame)
     89 {
     90     if (!canAccessStorage(frame)) {
     91         exceptionState.throwSecurityError("access is denied for this document.");
     92         return String();
     93     }
     94     return m_storageArea->getItem(key);
     95 }
     96 
     97 void StorageArea::setItem(const String& key, const String& value, ExceptionState& exceptionState, LocalFrame* frame)
     98 {
     99     if (!canAccessStorage(frame)) {
    100         exceptionState.throwSecurityError("access is denied for this document.");
    101         return;
    102     }
    103     WebStorageArea::Result result = WebStorageArea::ResultOK;
    104     m_storageArea->setItem(key, value, frame->document()->url(), result);
    105     if (result != WebStorageArea::ResultOK)
    106         exceptionState.throwDOMException(QuotaExceededError, "Setting the value of '" + key + "' exceeded the quota.");
    107 }
    108 
    109 void StorageArea::removeItem(const String& key, ExceptionState& exceptionState, LocalFrame* frame)
    110 {
    111     if (!canAccessStorage(frame)) {
    112         exceptionState.throwSecurityError("access is denied for this document.");
    113         return;
    114     }
    115     m_storageArea->removeItem(key, frame->document()->url());
    116 }
    117 
    118 void StorageArea::clear(ExceptionState& exceptionState, LocalFrame* frame)
    119 {
    120     if (!canAccessStorage(frame)) {
    121         exceptionState.throwSecurityError("access is denied for this document.");
    122         return;
    123     }
    124     m_storageArea->clear(frame->document()->url());
    125 }
    126 
    127 bool StorageArea::contains(const String& key, ExceptionState& exceptionState, LocalFrame* frame)
    128 {
    129     if (!canAccessStorage(frame)) {
    130         exceptionState.throwSecurityError("access is denied for this document.");
    131         return false;
    132     }
    133     return !getItem(key, exceptionState, frame).isNull();
    134 }
    135 
    136 bool StorageArea::canAccessStorage(LocalFrame* frame)
    137 {
    138     if (!frame || !frame->page())
    139         return false;
    140 
    141     // FrameDestructionObserver is used to safely keep the cached
    142     // reference to the LocalFrame. Should the LocalFrame die before
    143     // this StorageArea does, that cached reference will be cleared.
    144     if (m_frame == frame)
    145         return m_canAccessStorageCachedResult;
    146     bool result = frame->page()->storageClient().canAccessStorage(frame, m_storageType);
    147     // Move attention to the new LocalFrame.
    148     observeFrame(frame);
    149     m_canAccessStorageCachedResult = result;
    150     return result;
    151 }
    152 
    153 size_t StorageArea::memoryBytesUsedByCache()
    154 {
    155     return m_storageArea->memoryBytesUsedByCache();
    156 }
    157 
    158 void StorageArea::dispatchLocalStorageEvent(const String& key, const String& oldValue, const String& newValue, SecurityOrigin* securityOrigin, const KURL& pageURL, WebStorageArea* sourceAreaInstance, bool originatedInProcess)
    159 {
    160     // FIXME: This looks suspicious. Why doesn't this use allPages instead?
    161     const HashSet<Page*>& pages = Page::ordinaryPages();
    162     for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
    163         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    164             // FIXME: We do not yet have a way to dispatch events to out-of-process frames.
    165             if (!frame->isLocalFrame())
    166                 continue;
    167             Storage* storage = frame->domWindow()->optionalLocalStorage();
    168             if (storage && toLocalFrame(frame)->document()->securityOrigin()->canAccess(securityOrigin) && !isEventSource(storage, sourceAreaInstance))
    169                 frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage));
    170         }
    171         InspectorInstrumentation::didDispatchDOMStorageEvent(*it, key, oldValue, newValue, LocalStorage, securityOrigin);
    172     }
    173 }
    174 
    175 static Page* findPageWithSessionStorageNamespace(const WebStorageNamespace& sessionNamespace)
    176 {
    177     // FIXME: This looks suspicious. Why doesn't this use allPages instead?
    178     const HashSet<Page*>& pages = Page::ordinaryPages();
    179     for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
    180         const bool dontCreateIfMissing = false;
    181         StorageNamespace* storageNamespace = (*it)->sessionStorage(dontCreateIfMissing);
    182         if (storageNamespace && storageNamespace->isSameNamespace(sessionNamespace))
    183             return *it;
    184     }
    185     return 0;
    186 }
    187 
    188 void StorageArea::dispatchSessionStorageEvent(const String& key, const String& oldValue, const String& newValue, SecurityOrigin* securityOrigin, const KURL& pageURL, const WebStorageNamespace& sessionNamespace, WebStorageArea* sourceAreaInstance, bool originatedInProcess)
    189 {
    190     Page* page = findPageWithSessionStorageNamespace(sessionNamespace);
    191     if (!page)
    192         return;
    193 
    194     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    195         // FIXME: We do not yet have a way to dispatch events to out-of-process frames.
    196         if (!frame->isLocalFrame())
    197             continue;
    198         Storage* storage = frame->domWindow()->optionalSessionStorage();
    199         if (storage && toLocalFrame(frame)->document()->securityOrigin()->canAccess(securityOrigin) && !isEventSource(storage, sourceAreaInstance))
    200             frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage));
    201     }
    202     InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, SessionStorage, securityOrigin);
    203 }
    204 
    205 bool StorageArea::isEventSource(Storage* storage, WebStorageArea* sourceAreaInstance)
    206 {
    207     ASSERT(storage);
    208     StorageArea* area = storage->area();
    209     return area->m_storageArea == sourceAreaInstance;
    210 }
    211 
    212 } // namespace blink
    213