Home | History | Annotate | Download | only in web
      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 "StorageAreaProxy.h"
     29 
     30 #include "StorageNamespaceProxy.h"
     31 #include "bindings/v8/ExceptionState.h"
     32 #include "core/dom/Document.h"
     33 #include "core/dom/ExceptionCode.h"
     34 #include "core/events/ThreadLocalEventNames.h"
     35 #include "core/inspector/InspectorInstrumentation.h"
     36 #include "core/frame/DOMWindow.h"
     37 #include "core/frame/Frame.h"
     38 #include "core/page/Page.h"
     39 #include "core/page/PageGroup.h"
     40 #include "core/storage/Storage.h"
     41 #include "core/storage/StorageEvent.h"
     42 #include "platform/weborigin/SecurityOrigin.h"
     43 
     44 #include "WebFrameImpl.h"
     45 #include "WebPermissionClient.h"
     46 #include "WebViewImpl.h"
     47 #include "public/platform/WebStorageArea.h"
     48 #include "public/platform/WebString.h"
     49 #include "public/platform/WebURL.h"
     50 
     51 namespace WebCore {
     52 
     53 StorageAreaProxy::StorageAreaProxy(PassOwnPtr<blink::WebStorageArea> storageArea, StorageType storageType)
     54     : m_storageArea(storageArea)
     55     , m_storageType(storageType)
     56     , m_canAccessStorageCachedResult(false)
     57     , m_canAccessStorageCachedFrame(0)
     58 {
     59 }
     60 
     61 StorageAreaProxy::~StorageAreaProxy()
     62 {
     63 }
     64 
     65 unsigned StorageAreaProxy::length(ExceptionState& exceptionState, Frame* frame)
     66 {
     67     if (!canAccessStorage(frame)) {
     68         exceptionState.throwSecurityError("access is denied for this document.");
     69         return 0;
     70     }
     71     return m_storageArea->length();
     72 }
     73 
     74 String StorageAreaProxy::key(unsigned index, ExceptionState& exceptionState, Frame* frame)
     75 {
     76     if (!canAccessStorage(frame)) {
     77         exceptionState.throwSecurityError("access is denied for this document.");
     78         return String();
     79     }
     80     return m_storageArea->key(index);
     81 }
     82 
     83 String StorageAreaProxy::getItem(const String& key, ExceptionState& exceptionState, Frame* frame)
     84 {
     85     if (!canAccessStorage(frame)) {
     86         exceptionState.throwSecurityError("access is denied for this document.");
     87         return String();
     88     }
     89     return m_storageArea->getItem(key);
     90 }
     91 
     92 void StorageAreaProxy::setItem(const String& key, const String& value, ExceptionState& exceptionState, Frame* frame)
     93 {
     94     if (!canAccessStorage(frame)) {
     95         exceptionState.throwSecurityError("access is denied for this document.");
     96         return;
     97     }
     98     blink::WebStorageArea::Result result = blink::WebStorageArea::ResultOK;
     99     m_storageArea->setItem(key, value, frame->document()->url(), result);
    100     if (result != blink::WebStorageArea::ResultOK)
    101         exceptionState.throwDOMException(QuotaExceededError, "Setting the value of '" + key + "' exceeded the quota.");
    102 }
    103 
    104 void StorageAreaProxy::removeItem(const String& key, ExceptionState& exceptionState, Frame* frame)
    105 {
    106     if (!canAccessStorage(frame)) {
    107         exceptionState.throwSecurityError("access is denied for this document.");
    108         return;
    109     }
    110     m_storageArea->removeItem(key, frame->document()->url());
    111 }
    112 
    113 void StorageAreaProxy::clear(ExceptionState& exceptionState, Frame* frame)
    114 {
    115     if (!canAccessStorage(frame)) {
    116         exceptionState.throwSecurityError("access is denied for this document.");
    117         return;
    118     }
    119     m_storageArea->clear(frame->document()->url());
    120 }
    121 
    122 bool StorageAreaProxy::contains(const String& key, ExceptionState& exceptionState, Frame* frame)
    123 {
    124     if (!canAccessStorage(frame)) {
    125         exceptionState.throwSecurityError("access is denied for this document.");
    126         return false;
    127     }
    128     return !getItem(key, exceptionState, frame).isNull();
    129 }
    130 
    131 bool StorageAreaProxy::canAccessStorage(Frame* frame)
    132 {
    133     if (!frame || !frame->page())
    134         return false;
    135     if (m_canAccessStorageCachedFrame == frame)
    136         return m_canAccessStorageCachedResult;
    137     blink::WebFrameImpl* webFrame = blink::WebFrameImpl::fromFrame(frame);
    138     bool result;
    139     if (webFrame->permissionClient()) {
    140         result = webFrame->permissionClient()->allowStorage(webFrame, m_storageType == LocalStorage);
    141     } else {
    142         blink::WebViewImpl* webView = webFrame->viewImpl();
    143         result = !webView->permissionClient() || webView->permissionClient()->allowStorage(webFrame, m_storageType == LocalStorage);
    144     }
    145 
    146     m_canAccessStorageCachedFrame = frame;
    147     m_canAccessStorageCachedResult = result;
    148     return result;
    149 }
    150 
    151 size_t StorageAreaProxy::memoryBytesUsedByCache()
    152 {
    153     return m_storageArea->memoryBytesUsedByCache();
    154 }
    155 
    156 void StorageAreaProxy::dispatchLocalStorageEvent(const String& key, const String& oldValue, const String& newValue,
    157                                                  SecurityOrigin* securityOrigin, const KURL& pageURL, blink::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
    158 {
    159     // FIXME: This looks suspicious. Why doesn't this use allPages instead?
    160     const HashSet<Page*>& pages = PageGroup::sharedGroup()->pages();
    161     for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
    162         for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    163             Storage* storage = frame->domWindow()->optionalLocalStorage();
    164             if (storage && frame->document()->securityOrigin()->equal(securityOrigin) && !isEventSource(storage, sourceAreaInstance))
    165                 frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage));
    166         }
    167         InspectorInstrumentation::didDispatchDOMStorageEvent(*it, key, oldValue, newValue, LocalStorage, securityOrigin);
    168     }
    169 }
    170 
    171 static Page* findPageWithSessionStorageNamespace(const blink::WebStorageNamespace& sessionNamespace)
    172 {
    173     // FIXME: This looks suspicious. Why doesn't this use allPages instead?
    174     const HashSet<Page*>& pages = PageGroup::sharedGroup()->pages();
    175     for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
    176         const bool dontCreateIfMissing = false;
    177         StorageNamespaceProxy* proxy = static_cast<StorageNamespaceProxy*>((*it)->sessionStorage(dontCreateIfMissing));
    178         if (proxy && proxy->isSameNamespace(sessionNamespace))
    179             return *it;
    180     }
    181     return 0;
    182 }
    183 
    184 void StorageAreaProxy::dispatchSessionStorageEvent(const String& key, const String& oldValue, const String& newValue,
    185                                                    SecurityOrigin* securityOrigin, const KURL& pageURL, const blink::WebStorageNamespace& sessionNamespace,
    186                                                    blink::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
    187 {
    188     Page* page = findPageWithSessionStorageNamespace(sessionNamespace);
    189     if (!page)
    190         return;
    191 
    192     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    193         Storage* storage = frame->domWindow()->optionalSessionStorage();
    194         if (storage && frame->document()->securityOrigin()->equal(securityOrigin) && !isEventSource(storage, sourceAreaInstance))
    195             frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage));
    196     }
    197     InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, SessionStorage, securityOrigin);
    198 }
    199 
    200 bool StorageAreaProxy::isEventSource(Storage* storage, blink::WebStorageArea* sourceAreaInstance)
    201 {
    202     ASSERT(storage);
    203     StorageAreaProxy* areaProxy = static_cast<StorageAreaProxy*>(storage->area());
    204     return areaProxy->m_storageArea == sourceAreaInstance;
    205 }
    206 
    207 } // namespace WebCore
    208