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