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/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 WebCore { 47 48 StorageArea::StorageArea(PassOwnPtr<blink::WebStorageArea> storageArea, StorageType storageType) 49 : m_storageArea(storageArea) 50 , m_storageType(storageType) 51 , m_canAccessStorageCachedResult(false) 52 , m_canAccessStorageCachedFrame(0) 53 { 54 } 55 56 StorageArea::~StorageArea() 57 { 58 } 59 60 unsigned StorageArea::length(ExceptionState& exceptionState, LocalFrame* frame) 61 { 62 if (!canAccessStorage(frame)) { 63 exceptionState.throwSecurityError("access is denied for this document."); 64 return 0; 65 } 66 return m_storageArea->length(); 67 } 68 69 String StorageArea::key(unsigned index, ExceptionState& exceptionState, LocalFrame* frame) 70 { 71 if (!canAccessStorage(frame)) { 72 exceptionState.throwSecurityError("access is denied for this document."); 73 return String(); 74 } 75 return m_storageArea->key(index); 76 } 77 78 String StorageArea::getItem(const String& key, ExceptionState& exceptionState, LocalFrame* frame) 79 { 80 if (!canAccessStorage(frame)) { 81 exceptionState.throwSecurityError("access is denied for this document."); 82 return String(); 83 } 84 return m_storageArea->getItem(key); 85 } 86 87 void StorageArea::setItem(const String& key, const String& value, ExceptionState& exceptionState, LocalFrame* frame) 88 { 89 if (!canAccessStorage(frame)) { 90 exceptionState.throwSecurityError("access is denied for this document."); 91 return; 92 } 93 blink::WebStorageArea::Result result = blink::WebStorageArea::ResultOK; 94 m_storageArea->setItem(key, value, frame->document()->url(), result); 95 if (result != blink::WebStorageArea::ResultOK) 96 exceptionState.throwDOMException(QuotaExceededError, "Setting the value of '" + key + "' exceeded the quota."); 97 } 98 99 void StorageArea::removeItem(const String& key, ExceptionState& exceptionState, LocalFrame* frame) 100 { 101 if (!canAccessStorage(frame)) { 102 exceptionState.throwSecurityError("access is denied for this document."); 103 return; 104 } 105 m_storageArea->removeItem(key, frame->document()->url()); 106 } 107 108 void StorageArea::clear(ExceptionState& exceptionState, LocalFrame* frame) 109 { 110 if (!canAccessStorage(frame)) { 111 exceptionState.throwSecurityError("access is denied for this document."); 112 return; 113 } 114 m_storageArea->clear(frame->document()->url()); 115 } 116 117 bool StorageArea::contains(const String& key, ExceptionState& exceptionState, LocalFrame* frame) 118 { 119 if (!canAccessStorage(frame)) { 120 exceptionState.throwSecurityError("access is denied for this document."); 121 return false; 122 } 123 return !getItem(key, exceptionState, frame).isNull(); 124 } 125 126 bool StorageArea::canAccessStorage(LocalFrame* frame) 127 { 128 if (!frame || !frame->page()) 129 return false; 130 if (m_canAccessStorageCachedFrame == frame) 131 return m_canAccessStorageCachedResult; 132 bool result = frame->page()->storageClient().canAccessStorage(frame, m_storageType); 133 m_canAccessStorageCachedFrame = frame; 134 m_canAccessStorageCachedResult = result; 135 return result; 136 } 137 138 size_t StorageArea::memoryBytesUsedByCache() 139 { 140 return m_storageArea->memoryBytesUsedByCache(); 141 } 142 143 void StorageArea::dispatchLocalStorageEvent(const String& key, const String& oldValue, const String& newValue, SecurityOrigin* securityOrigin, const KURL& pageURL, blink::WebStorageArea* sourceAreaInstance, bool originatedInProcess) 144 { 145 // FIXME: This looks suspicious. Why doesn't this use allPages instead? 146 const HashSet<Page*>& pages = Page::ordinaryPages(); 147 for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) { 148 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) { 149 // FIXME: We do not yet have a way to dispatch events to out-of-process frames. 150 if (!frame->isLocalFrame()) 151 continue; 152 Storage* storage = frame->domWindow()->optionalLocalStorage(); 153 if (storage && toLocalFrame(frame)->document()->securityOrigin()->canAccess(securityOrigin) && !isEventSource(storage, sourceAreaInstance)) 154 frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage)); 155 } 156 InspectorInstrumentation::didDispatchDOMStorageEvent(*it, key, oldValue, newValue, LocalStorage, securityOrigin); 157 } 158 } 159 160 static Page* findPageWithSessionStorageNamespace(const blink::WebStorageNamespace& sessionNamespace) 161 { 162 // FIXME: This looks suspicious. Why doesn't this use allPages instead? 163 const HashSet<Page*>& pages = Page::ordinaryPages(); 164 for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) { 165 const bool dontCreateIfMissing = false; 166 StorageNamespace* storageNamespace = (*it)->sessionStorage(dontCreateIfMissing); 167 if (storageNamespace && storageNamespace->isSameNamespace(sessionNamespace)) 168 return *it; 169 } 170 return 0; 171 } 172 173 void StorageArea::dispatchSessionStorageEvent(const String& key, const String& oldValue, const String& newValue, SecurityOrigin* securityOrigin, const KURL& pageURL, const blink::WebStorageNamespace& sessionNamespace, blink::WebStorageArea* sourceAreaInstance, bool originatedInProcess) 174 { 175 Page* page = findPageWithSessionStorageNamespace(sessionNamespace); 176 if (!page) 177 return; 178 179 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) { 180 // FIXME: We do not yet have a way to dispatch events to out-of-process frames. 181 if (!frame->isLocalFrame()) 182 continue; 183 Storage* storage = frame->domWindow()->optionalSessionStorage(); 184 if (storage && toLocalFrame(frame)->document()->securityOrigin()->canAccess(securityOrigin) && !isEventSource(storage, sourceAreaInstance)) 185 frame->domWindow()->enqueueWindowEvent(StorageEvent::create(EventTypeNames::storage, key, oldValue, newValue, pageURL, storage)); 186 } 187 InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, SessionStorage, securityOrigin); 188 } 189 190 bool StorageArea::isEventSource(Storage* storage, blink::WebStorageArea* sourceAreaInstance) 191 { 192 ASSERT(storage); 193 StorageArea* area = storage->area(); 194 return area->m_storageArea == sourceAreaInstance; 195 } 196 197 } // namespace WebCore 198