StorageAreaProxy.cpp [plain text]
#include "config.h"
#include "StorageAreaProxy.h"
#include "DOMWindow.h"
#include "Document.h"
#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "Page.h"
#include "PageGroup.h"
#include "SecurityOrigin.h"
#include "Storage.h"
#include "StorageEvent.h"
#include "StorageNamespaceProxy.h"
#include "WebFrameImpl.h"
#include "WebPermissionClient.h"
#include "WebStorageArea.h"
#include "platform/WebString.h"
#include "platform/WebURL.h"
#include "WebViewImpl.h"
namespace WebCore {
StorageAreaProxy::StorageAreaProxy(WebKit::WebStorageArea* storageArea, StorageType storageType)
: m_storageArea(adoptPtr(storageArea))
, m_storageType(storageType)
{
}
StorageAreaProxy::~StorageAreaProxy()
{
}
unsigned StorageAreaProxy::length(Frame* frame) const
{
if (canAccessStorage(frame))
return m_storageArea->length();
return 0;
}
String StorageAreaProxy::key(unsigned index, Frame* frame) const
{
if (canAccessStorage(frame))
return m_storageArea->key(index);
return String();
}
String StorageAreaProxy::getItem(const String& key, Frame* frame) const
{
if (canAccessStorage(frame))
return m_storageArea->getItem(key);
return String();
}
String StorageAreaProxy::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame)
{
WebKit::WebStorageArea::Result result = WebKit::WebStorageArea::ResultOK;
WebKit::WebString oldValue;
if (!canAccessStorage(frame))
ec = QUOTA_EXCEEDED_ERR;
else {
m_storageArea->setItem(key, value, frame->document()->url(), result, oldValue);
ec = (result == WebKit::WebStorageArea::ResultOK) ? 0 : QUOTA_EXCEEDED_ERR;
String oldValueString = oldValue;
if (oldValueString != value && result == WebKit::WebStorageArea::ResultOK)
storageEvent(key, oldValue, value, m_storageType, frame->document()->securityOrigin(), frame);
}
return oldValue;
}
String StorageAreaProxy::removeItem(const String& key, Frame* frame)
{
if (!canAccessStorage(frame))
return String();
WebKit::WebString oldValue;
m_storageArea->removeItem(key, frame->document()->url(), oldValue);
if (!oldValue.isNull())
storageEvent(key, oldValue, String(), m_storageType, frame->document()->securityOrigin(), frame);
return oldValue;
}
bool StorageAreaProxy::clear(Frame* frame)
{
if (!canAccessStorage(frame))
return false;
bool clearedSomething;
m_storageArea->clear(frame->document()->url(), clearedSomething);
if (clearedSomething)
storageEvent(String(), String(), String(), m_storageType, frame->document()->securityOrigin(), frame);
return clearedSomething;
}
bool StorageAreaProxy::contains(const String& key, Frame* frame) const
{
return !getItem(key, frame).isNull();
}
void StorageAreaProxy::storageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Frame* sourceFrame)
{
Page* page = sourceFrame->page();
if (!page)
return;
Vector<RefPtr<Frame> > frames;
if (storageType == SessionStorage) {
for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
frames.append(frame);
}
for (unsigned i = 0; i < frames.size(); ++i) {
ExceptionCode ec = 0;
Storage* storage = frames[i]->domWindow()->sessionStorage(ec);
if (!ec)
frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
}
} else {
const HashSet<Page*>& pages = page->group().pages();
HashSet<Page*>::const_iterator end = pages.end();
for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (sourceFrame != frame && frame->document()->securityOrigin()->equal(securityOrigin))
frames.append(frame);
}
}
for (unsigned i = 0; i < frames.size(); ++i) {
ExceptionCode ec = 0;
Storage* storage = frames[i]->domWindow()->localStorage(ec);
if (!ec)
frames[i]->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->url(), storage));
}
}
}
bool StorageAreaProxy::canAccessStorage(Frame* frame) const
{
if (!frame->page())
return false;
WebKit::WebFrameImpl* webFrame = WebKit::WebFrameImpl::fromFrame(frame);
WebKit::WebViewImpl* webView = webFrame->viewImpl();
return !webView->permissionClient() || webView->permissionClient()->allowStorage(webFrame, m_storageType == LocalStorage);
}
void StorageAreaProxy::dispatchLocalStorageEvent(const String& pageGroupName, const String& key, const String& oldValue, const String& newValue,
SecurityOrigin* securityOrigin, const KURL& pageURL, WebKit::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
{
if (originatedInProcess)
return;
const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroupName)->pages();
for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->document()->securityOrigin()->equal(securityOrigin) && !isEventSource(frame->domWindow()->optionalLocalStorage(), sourceAreaInstance)) {
ExceptionCode ec = 0;
Storage* storage = frame->domWindow()->localStorage(ec);
if (!ec)
frame->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, pageURL, storage));
}
}
}
}
static Page* findPageWithSessionStorageNamespace(const String& pageGroupName, const WebKit::WebStorageNamespace& sessionNamespace)
{
const HashSet<Page*>& pages = PageGroup::pageGroup(pageGroupName)->pages();
for (HashSet<Page*>::const_iterator it = pages.begin(); it != pages.end(); ++it) {
const bool createIfNeeded = true;
StorageNamespaceProxy* proxy = static_cast<StorageNamespaceProxy*>((*it)->sessionStorage(createIfNeeded));
if (proxy->isSameNamespace(sessionNamespace))
return *it;
}
return 0;
}
void StorageAreaProxy::dispatchSessionStorageEvent(const String& pageGroupName, const String& key, const String& oldValue, const String& newValue,
SecurityOrigin* securityOrigin, const KURL& pageURL, const WebKit::WebStorageNamespace& sessionNamespace,
WebKit::WebStorageArea* sourceAreaInstance, bool originatedInProcess)
{
if (originatedInProcess)
return;
Page* page = findPageWithSessionStorageNamespace(pageGroupName, sessionNamespace);
if (!page)
return;
for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->document()->securityOrigin()->equal(securityOrigin) && !isEventSource(frame->domWindow()->optionalSessionStorage(), sourceAreaInstance)) {
ExceptionCode ec = 0;
Storage* storage = frame->domWindow()->sessionStorage(ec);
if (!ec)
frame->document()->enqueueWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, pageURL, storage));
}
}
}
bool StorageAreaProxy::isEventSource(Storage* storage, WebKit::WebStorageArea* sourceAreaInstance)
{
if (!storage)
return false;
StorageAreaProxy* areaProxy = static_cast<StorageAreaProxy*>(storage->area());
return areaProxy->m_storageArea == sourceAreaInstance;
}
}