Bug 660237 - implement nsIDOMStorage with a proxy, r=bzbarsky, r=mayhemer

This commit is contained in:
Andrea Marchesini 2014-07-23 01:07:12 -04:00
parent f10d7405dc
commit 179c6c5321
48 changed files with 381 additions and 648 deletions

View File

@ -107,11 +107,12 @@ let SessionStorageInternal = {
let uri = Services.io.newURI(host, null, null);
let principal = Services.scriptSecurityManager.getDocShellCodebasePrincipal(uri, aDocShell);
let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
// There is no need to pass documentURI, it's only used to fill documentURI property of
// domstorage event, which in this case has no consumer. Prevention of events in case
// of missing documentURI will be solved in a followup bug to bug 600307.
let storage = storageManager.createStorage(principal, "", aDocShell.usePrivateBrowsing);
let storage = storageManager.createStorage(window, principal, "", aDocShell.usePrivateBrowsing);
for (let key of Object.keys(data)) {
try {
@ -135,9 +136,11 @@ let SessionStorageInternal = {
let hostData = {};
let storage;
let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
try {
let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
storage = storageManager.getStorage(aPrincipal);
storage = storageManager.getStorage(window, aPrincipal);
} catch (e) {
// sessionStorage might throw if it's turned off, see bug 458954
}

View File

@ -35,7 +35,6 @@
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIContentViewer.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsCURILoader.h"
@ -2790,20 +2789,27 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIDOMWindow> domWin = do_GetInterface(GetAsSupports(this));
if (aCreate) {
return manager->CreateStorage(aPrincipal, aDocumentURI,
return manager->CreateStorage(domWin, aPrincipal, aDocumentURI,
mInPrivateBrowsing, aStorage);
}
return manager->GetStorage(aPrincipal, mInPrivateBrowsing, aStorage);
return manager->GetStorage(domWin, aPrincipal, mInPrivateBrowsing,
aStorage);
}
nsresult
nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
nsIDOMStorage* aStorage)
{
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(aStorage);
nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
nsRefPtr<DOMStorage> storage = static_cast<DOMStorage*>(aStorage);
if (!storage) {
return NS_ERROR_UNEXPECTED;
}
nsIPrincipal* storagePrincipal = storage->GetPrincipal();
if (storagePrincipal != aPrincipal) {
NS_ERROR("Wanting to add a sessionStorage for different principal");
return NS_ERROR_DOM_SECURITY_ERR;

View File

@ -113,10 +113,6 @@
#endif
#include "nsIDOMXPathNSResolver.h"
// Storage includes
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
// Drag and drop
#include "nsIDOMFile.h"
#include "nsDOMBlobBuilder.h" // nsDOMMultipartFile
@ -345,21 +341,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(XPathNSResolver, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// WhatWG Storage
// mrbkap says we don't need WANT_ADDPROPERTY on Storage objects
// since a call to addProperty() is always followed by a call to
// setProperty(), except in the case when a getter or setter is set
// for a property. But we don't care about getters or setters here.
NS_DEFINE_CLASSINFO_DATA(Storage, nsStorage2SH,
DOM_DEFAULT_SCRIPTABLE_FLAGS |
nsIXPCScriptable::WANT_NEWRESOLVE |
nsIXPCScriptable::WANT_GETPROPERTY |
nsIXPCScriptable::WANT_SETPROPERTY |
nsIXPCScriptable::WANT_DELPROPERTY |
nsIXPCScriptable::DONT_ENUM_STATIC_PROPS |
nsIXPCScriptable::WANT_NEWENUMERATE)
NS_DEFINE_CLASSINFO_DATA(Blob, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
@ -942,10 +923,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNSResolver)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Storage, nsIDOMStorage)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorage)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Blob, nsIDOMBlob)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBlob)
DOM_CLASSINFO_MAP_END
@ -3389,217 +3366,6 @@ nsEventTargetSH::PreserveWrapper(nsISupports *aNative)
target->PreserveWrapper(aNative);
}
// Storage2SH
// One reason we need a newResolve hook is that in order for
// enumeration of storage object keys to work the keys we're
// enumerating need to exist on the storage object for the JS engine
// to find them.
NS_IMETHODIMP
nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid aId, JSObject **objp,
bool *_retval)
{
JS::Rooted<jsid> id(cx, aId);
if (ObjectIsNativeWrapper(cx, obj)) {
return NS_OK;
}
JS::Rooted<JSObject*> realObj(cx, wrapper->GetJSObject());
JSAutoCompartment ac(cx, realObj);
// First check to see if the property is defined on our prototype,
// after converting id to a string if it's an integer.
JS::Rooted<JSString*> jsstr(cx, IdToString(cx, id));
if (!jsstr) {
return NS_OK;
}
JS::Rooted<JSObject*> proto(cx);
if (!::JS_GetPrototype(cx, realObj, &proto)) {
return NS_ERROR_FAILURE;
}
bool hasProp;
if (proto &&
(::JS_HasPropertyById(cx, proto, id, &hasProp) &&
hasProp)) {
// We found the property we're resolving on the prototype,
// nothing left to do here then.
return NS_OK;
}
// We're resolving property that doesn't exist on the prototype,
// check if the key exists in the storage object.
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
nsAutoJSString autoStr;
NS_ENSURE_TRUE(autoStr.init(cx, jsstr), NS_ERROR_UNEXPECTED);
// GetItem() will return null if the caller can't access the session
// storage item.
nsAutoString data;
nsresult rv = storage->GetItem(autoStr, data);
NS_ENSURE_SUCCESS(rv, rv);
if (!DOMStringIsNull(data)) {
if (!::JS_DefinePropertyById(cx, realObj, id, JS::UndefinedHandleValue,
JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
*objp = realObj;
}
return NS_OK;
}
NS_IMETHODIMP
nsStorage2SH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *aObj, jsid aId, jsval *vp, bool *_retval)
{
JS::Rooted<JSObject*> obj(cx, aObj);
JS::Rooted<jsid> id(cx, aId);
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
JSString* key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsAutoJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
// For native wrappers, do not get random names on storage objects.
if (ObjectIsNativeWrapper(cx, obj)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsAutoString val;
nsresult rv = storage->GetItem(keyStr, val);
NS_ENSURE_SUCCESS(rv, rv);
if (DOMStringIsNull(val)) {
// No such key.
*vp = JSVAL_VOID;
} else {
JSString* str =
JS_NewUCStringCopyN(cx, static_cast<const jschar *>(val.get()),
val.Length());
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
*vp = STRING_TO_JSVAL(str);
}
return NS_SUCCESS_I_DID_SOMETHING;
}
NS_IMETHODIMP
nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid aId,
jsval *vp, bool *_retval)
{
JS::Rooted<jsid> id(cx, aId);
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsAutoJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
JS::Rooted<JS::Value> val(cx, *vp);
JSString *value = JS::ToString(cx, val);
NS_ENSURE_TRUE(value, NS_ERROR_UNEXPECTED);
nsAutoJSString valueStr;
NS_ENSURE_TRUE(valueStr.init(cx, value), NS_ERROR_UNEXPECTED);
nsresult rv = storage->SetItem(keyStr, valueStr);
if (NS_SUCCEEDED(rv)) {
rv = NS_SUCCESS_I_DID_SOMETHING;
}
return rv;
}
NS_IMETHODIMP
nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid aId,
bool *_retval)
{
JS::Rooted<jsid> id(cx, aId);
nsCOMPtr<nsIDOMStorage> storage(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
JSString *key = IdToString(cx, id);
NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED);
nsAutoJSString keyStr;
NS_ENSURE_TRUE(keyStr.init(cx, key), NS_ERROR_UNEXPECTED);
nsresult rv = storage->RemoveItem(keyStr);
if (NS_FAILED(rv)) {
return rv;
}
*_retval = true;
return NS_SUCCESS_I_DID_SOMETHING;
}
NS_IMETHODIMP
nsStorage2SH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, uint32_t enum_op, jsval *statep,
jsid *idp, bool *_retval)
{
if (enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) {
nsCOMPtr<nsPIDOMStorage> storage(do_QueryWrappedNative(wrapper));
// XXXndeakin need to free the keys afterwards
nsTArray<nsString> *keys = storage->GetKeys();
NS_ENSURE_TRUE(keys, NS_ERROR_OUT_OF_MEMORY);
*statep = PRIVATE_TO_JSVAL(keys);
if (idp) {
*idp = INT_TO_JSID(keys->Length());
}
return NS_OK;
}
nsTArray<nsString> *keys = (nsTArray<nsString> *)statep->toPrivate();
if (enum_op == JSENUMERATE_NEXT && keys->Length() != 0) {
nsString& key = keys->ElementAt(0);
JS::Rooted<JSString*> str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length()));
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
JS::Rooted<jsid> id(cx);
JS_StringToId(cx, str, &id);
*idp = id;
keys->RemoveElementAt(0);
return NS_OK;
}
// destroy the keys array if we have no keys or if we're done
NS_ABORT_IF_FALSE(enum_op == JSENUMERATE_DESTROY ||
(enum_op == JSENUMERATE_NEXT && keys->Length() == 0),
"Bad call from the JS engine");
delete keys;
*statep = JSVAL_NULL;
return NS_OK;
}
// nsIDOMEventListener::HandleEvent() 'this' converter helper
NS_INTERFACE_MAP_BEGIN(nsEventListenerThisTranslator)

View File

@ -303,39 +303,6 @@ public:
};
// WebApps Storage helpers
class nsStorage2SH : public nsDOMGenericSH
{
protected:
nsStorage2SH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
{
}
virtual ~nsStorage2SH()
{
}
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, JSObject **objp,
bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, uint32_t enum_op, JS::Value *statep,
jsid *idp, bool *_retval) MOZ_OVERRIDE;
public:
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsStorage2SH(aData);
}
};
// Event handler 'this' translator class, this is called by XPConnect
// when a "function interface" (nsIDOMEventListener) is called, this
// class extracts 'this' fomr the first argument to the called

View File

@ -48,9 +48,6 @@ DOMCI_CLASS(XSLTProcessor)
// DOM Level 3 XPath objects
DOMCI_CLASS(XPathNSResolver)
// WhatWG WebApps Objects
DOMCI_CLASS(Storage)
DOMCI_CLASS(Blob)
DOMCI_CLASS(File)

View File

@ -16,9 +16,10 @@
#include "nsHistory.h"
#include "nsPerformance.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageManager.h"
#include "DOMStorage.h"
#include "mozilla/dom/DOMStorage.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "nsDOMOfflineResourceList.h"
#include "nsError.h"
#include "nsIIdleService.h"
@ -89,7 +90,6 @@
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsPIDOMStorage.h"
#include "nsDOMString.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsThreadUtils.h"
@ -10349,7 +10349,7 @@ nsGlobalWindow::GetComputedStyleHelper(Element& aElt,
return compStyle.forget();
}
nsIDOMStorage*
DOMStorage*
nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
{
FORWARD_TO_INNER_OR_THROW(GetSessionStorage, (aError), aError, nullptr);
@ -10367,15 +10367,12 @@ nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
}
#endif
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
if (piStorage) {
bool canAccess = piStorage->CanAccess(principal);
NS_ASSERTION(canAccess,
"window %x owned sessionStorage "
"that could not be accessed!");
if (!canAccess) {
mSessionStorage = nullptr;
}
bool canAccess = mSessionStorage->CanAccess(principal);
NS_ASSERTION(canAccess,
"This window owned sessionStorage "
"that could not be accessed!");
if (!canAccess) {
mSessionStorage = nullptr;
}
}
@ -10407,14 +10404,17 @@ nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
aError = storageManager->CreateStorage(principal,
documentURI,
nsCOMPtr<nsIDOMStorage> storage;
aError = storageManager->CreateStorage(this, principal, documentURI,
loadContext && loadContext->UsePrivateBrowsing(),
getter_AddRefs(mSessionStorage));
getter_AddRefs(storage));
if (aError.Failed()) {
return nullptr;
}
mSessionStorage = static_cast<DOMStorage*>(storage.get());
MOZ_ASSERT(mSessionStorage);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
@ -10437,7 +10437,7 @@ nsGlobalWindow::GetSessionStorage(ErrorResult& aError)
}
NS_IMETHODIMP
nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
nsGlobalWindow::GetSessionStorage(nsISupports** aSessionStorage)
{
ErrorResult rv;
nsCOMPtr<nsIDOMStorage> storage = GetSessionStorage(rv);
@ -10446,7 +10446,7 @@ nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
return rv.ErrorCode();
}
nsIDOMStorage*
DOMStorage*
nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
{
FORWARD_TO_INNER_OR_THROW(GetLocalStorage, (aError), aError, nullptr);
@ -10489,17 +10489,23 @@ nsGlobalWindow::GetLocalStorage(ErrorResult& aError)
nsIDocShell* docShell = GetDocShell();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
aError = storageManager->CreateStorage(principal,
documentURI,
nsCOMPtr<nsIDOMStorage> storage;
aError = storageManager->CreateStorage(this, principal, documentURI,
loadContext && loadContext->UsePrivateBrowsing(),
getter_AddRefs(mLocalStorage));
getter_AddRefs(storage));
if (aError.Failed()) {
return nullptr;
}
mLocalStorage = static_cast<DOMStorage*>(storage.get());
MOZ_ASSERT(mLocalStorage);
}
return mLocalStorage;
}
NS_IMETHODIMP
nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
nsGlobalWindow::GetLocalStorage(nsISupports** aLocalStorage)
{
NS_ENSURE_ARG(aLocalStorage);
@ -11286,34 +11292,34 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMStorage> changingStorage = event->GetStorageArea();
nsRefPtr<DOMStorage> changingStorage = event->GetStorageArea();
if (!changingStorage) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMStorage> istorage = changingStorage.get();
bool fireMozStorageChanged = false;
principal = GetPrincipal();
if (!principal) {
return NS_OK;
}
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
bool isPrivate = loadContext && loadContext->UsePrivateBrowsing();
if (pistorage->IsPrivate() != isPrivate) {
if (changingStorage->IsPrivate() != isPrivate) {
return NS_OK;
}
switch (pistorage->GetType())
switch (changingStorage->GetType())
{
case nsPIDOMStorage::SessionStorage:
case DOMStorage::SessionStorage:
{
bool check = false;
nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
if (storageManager) {
rv = storageManager->CheckStorage(principal, changingStorage, &check);
rv = storageManager->CheckStorage(principal, istorage, &check);
if (NS_FAILED(rv)) {
return rv;
}
@ -11327,19 +11333,20 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
#ifdef PR_LOGGING
if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p",
this, mSessionStorage.get(), changingStorage.get());
}
#endif
fireMozStorageChanged = SameCOMIdentity(mSessionStorage, changingStorage);
fireMozStorageChanged = mSessionStorage == changingStorage;
break;
}
case nsPIDOMStorage::LocalStorage:
case DOMStorage::LocalStorage:
{
// Allow event fire only for the same principal storages
// XXX We have to use EqualsIgnoreDomain after bug 495337 lands
nsIPrincipal* storagePrincipal = pistorage->GetPrincipal();
nsIPrincipal* storagePrincipal = changingStorage->GetPrincipal();
bool equals = false;
rv = storagePrincipal->Equals(principal, &equals);
@ -11348,7 +11355,7 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
if (!equals)
return NS_OK;
fireMozStorageChanged = SameCOMIdentity(mLocalStorage, changingStorage);
fireMozStorageChanged = mLocalStorage == changingStorage;
break;
}
default:

View File

@ -915,8 +915,8 @@ public:
mozilla::ErrorResult& aError);
void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
mozilla::ErrorResult& aError);
nsIDOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
nsIDOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
mozilla::dom::DOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
mozilla::dom::DOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
mozilla::dom::indexedDB::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
already_AddRefed<nsICSSDeclaration>
@ -1545,8 +1545,8 @@ protected:
// it wouldn't see the ~External function's declaration.
nsCOMPtr<nsISupports> mExternal;
nsCOMPtr<nsIDOMStorage> mLocalStorage;
nsCOMPtr<nsIDOMStorage> mSessionStorage;
nsRefPtr<mozilla::dom::DOMStorage> mLocalStorage;
nsRefPtr<mozilla::dom::DOMStorage> mSessionStorage;
// These member variable are used only on inner windows.
nsRefPtr<mozilla::EventListenerManager> mListenerManager;

View File

@ -1083,6 +1083,10 @@ DOMInterfaces = {
'resultNotAddRefed': [ '__indexedGetter' ],
},
'Storage': {
'nativeType': 'mozilla::dom::DOMStorage',
},
'StyleSheet': {
'nativeType': 'mozilla::CSSStyleSheet',
},

View File

@ -76,7 +76,16 @@ function test()
is(doc.documentElement.getAttribute("data-foo"), "baz",
"Attribute setter should have been called again");
// XXXbz no way yet to test non-overridebuiltins stuff with named setter
// Test non-overridebuiltins binding with named setter
var s = doc.defaultView.localStorage;
s["test_proxies_via_xray"] = "bar";
// Check that this actually got passed on to the underlying object.
is(s.wrappedJSObject["test_proxies_via_xray"], "bar",
"Set should get forwarded to the underlying object without overridebuiltins");
s["test_proxies_via_xray"] = "baz";
// Check that this actually got passed on to the underlying object.
is(s.wrappedJSObject["test_proxies_via_xray"], "baz",
"Set should get forwarded to the underlying object again without overridebuiltins");
SimpleTest.finish();
}

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/StorageEvent.h"
#include "nsIDOMStorage.h"
#include "mozilla/dom/DOMStorage.h"
namespace mozilla {
namespace dom {
@ -85,7 +85,7 @@ StorageEvent::InitStorageEvent(const nsAString& aType, bool aCanBubble,
const nsAString& aOldValue,
const nsAString& aNewValue,
const nsAString& aURL,
nsIDOMStorage* aStorageArea,
DOMStorage* aStorageArea,
ErrorResult& aRv)
{
aRv = InitEvent(aType, aCanBubble, aCancelable);

View File

@ -13,8 +13,6 @@
#include "mozilla/dom/Event.h"
#include "mozilla/dom/StorageEventBinding.h"
class nsIDOMStorage;
// Helper for EventDispatcher.
nsresult NS_NewDOMStorageEvent(nsIDOMEvent** aDOMEvent,
mozilla::dom::EventTarget* aOwner);
@ -22,6 +20,8 @@ nsresult NS_NewDOMStorageEvent(nsIDOMEvent** aDOMEvent,
namespace mozilla {
namespace dom {
class DOMStorage;
class StorageEvent : public Event
{
public:
@ -37,7 +37,7 @@ protected:
nsString mOldValue;
nsString mNewValue;
nsString mUrl;
nsCOMPtr<nsIDOMStorage> mStorageArea;
nsRefPtr<DOMStorage> mStorageArea;
public:
virtual StorageEvent* AsStorageEvent();
@ -57,7 +57,7 @@ public:
const nsAString& aOldValue,
const nsAString& aNewValue,
const nsAString& aURL,
nsIDOMStorage* aStorageArea,
DOMStorage* aStorageArea,
ErrorResult& aRv);
void GetKey(nsString& aRetVal) const
@ -80,7 +80,7 @@ public:
aRetVal = mUrl;
}
nsIDOMStorage* GetStorageArea() const
DOMStorage* GetStorageArea() const
{
return mStorageArea;
}

View File

@ -1,12 +0,0 @@
# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
[DEFAULT]
support-files =
[test_missing_arguments.html.json]
[test_storage_local_builtins.html.json]
[test_storage_local_in_js.html.json]
[test_storage_local_removeitem_js.html.json]
[test_storage_session_builtins.html.json]
[test_storage_session_in_js.html.json]
[test_storage_session_removeitem_js.html.json]

View File

@ -1,12 +0,0 @@
{
"Should throw TypeError for function \"function () { localStorage.key(); }\".": true,
"Should throw TypeError for function \"function () { localStorage.getItem(); }\".": true,
"Should throw TypeError for function \"function () { localStorage.setItem(); }\".": true,
"Should throw TypeError for function \"function () { localStorage.setItem(\"a\"); }\".": true,
"Should throw TypeError for function \"function () { localStorage.removeItem(); }\".": true,
"Should throw TypeError for function \"function () { sessionStorage.key(); }\".": true,
"Should throw TypeError for function \"function () { sessionStorage.getItem(); }\".": true,
"Should throw TypeError for function \"function () { sessionStorage.setItem(); }\".": true,
"Should throw TypeError for function \"function () { sessionStorage.setItem(\"a\"); }\".": true,
"Should throw TypeError for function \"function () { sessionStorage.removeItem(); }\".": true
}

View File

@ -1,4 +0,0 @@
{
"Web Storage 2": true,
"Web Storage 3": true
}

View File

@ -1,4 +0,0 @@
{
"Web Storage 2": true,
"Web Storage 3": true
}

View File

@ -32,6 +32,5 @@ MOCHITEST_MANIFESTS += [
'failures/html/microdata/microdata-dom-api/mochitest.ini',
'failures/html/typedarrays/mochitest.ini',
'failures/webapps/WebStorage/tests/submissions/Infraware/mochitest.ini',
'failures/webapps/WebStorage/tests/submissions/Ms2ger/mochitest.ini',
'failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/mochitest.ini',
]

View File

@ -10,7 +10,6 @@ interface nsIControllers;
interface nsIDOMBlob;
interface nsIDOMLocation;
interface nsIDOMOfflineResourceList;
interface nsIDOMStorage;
interface nsIPrompt;
interface nsISelection;
interface nsIVariant;
@ -24,7 +23,7 @@ interface nsIVariant;
* @see <http://www.whatwg.org/html/#window>
*/
[scriptable, uuid(d4316591-d16e-405c-8093-b441cbef3230)]
[scriptable, uuid(c3ff0328-6c47-4e64-a22f-ac221959e258)]
interface nsIDOMWindow : nsISupports
{
// the current browsing context
@ -241,15 +240,17 @@ interface nsIDOMWindow : nsISupports
// WindowSessionStorage
/**
* Session storage for the current browsing context.
* This attribute is a DOMStorage
*/
readonly attribute nsIDOMStorage sessionStorage;
readonly attribute nsISupports sessionStorage;
// WindowLocalStorage
/**
* Local storage for the current browsing context.
* This attribute is a DOMStorage
*/
readonly attribute nsIDOMStorage localStorage;
readonly attribute nsISupports localStorage;
// IndexedDB

View File

@ -10,8 +10,3 @@ XPIDL_SOURCES += [
]
XPIDL_MODULE = 'dom_storage'
EXPORTS += [
'nsPIDOMStorage.h',
]

View File

@ -6,63 +6,11 @@
#include "domstubs.idl"
/**
* Interface for client side storage. See
* http://www.whatwg.org/specs/web-apps/current-work/multipage/structured.html#storage0
* for more information.
*
* A storage object stores an arbitrary set of key-value pairs, which
* may be retrieved, modified and removed as needed. A key may only
* exist once within a storage object, and only one value may be
* associated with a particular key. Keys are stored in a particular
* order with the condition that this order not change by merely changing
* the value associated with a key, but the order may change when a
* key is added or removed.
* Empty interface for client side storage. DOMStorage is now ported to WebIDL
* but we still need an XPConnect interface for casting.
*/
[scriptable, uuid(43E5EDAD-1E02-42c4-9D99-C3D9DEE22A20)]
[scriptable, uuid(425a33f0-e0e9-45e7-a95f-9908bd6ae988)]
interface nsIDOMStorage : nsISupports
{
/**
* The number of keys stored.
*/
readonly attribute unsigned long length;
/**
* Retrieve the name of the key at a particular index.
*
* @param index index of the item to retrieve
* @returns the key at index, null if there is no key at that index
*/
DOMString key(in unsigned long index);
/**
* Retrieve an item with a given key
*
* @param key key to retrieve
* @returns found data or empty string if the key was not found
*/
DOMString getItem([Null(Stringify)] in DOMString key);
/**
* Assign a value with a key. If the key does not exist already, a new
* key is added associated with that value. If the key already exists,
* then the existing value is replaced with a new value.
*
* @param key key to set
* @param data data to associate with the key
*/
void setItem([Null(Stringify)] in DOMString key, [Null(Stringify)] in DOMString data);
/**
* Remove a key and its corresponding value.
*
* @param key key to remove
*/
void removeItem([Null(Stringify)] in DOMString key);
/**
* Clear the content of this storage bound to a domain
* or an origin.
*/
void clear();
};

View File

@ -7,13 +7,14 @@
interface nsIDOMStorage;
interface nsIPrincipal;
interface nsIDOMWindow;
/**
* General purpose interface that has two implementations, for localStorage
* resp. sessionStorage with "@mozilla.org/dom/localStorage-manager;1" resp.
* "@mozilla.org/dom/sessionStorage-manager;1" contract IDs.
*/
[scriptable, uuid(8096f9ea-fa61-4960-b5d7-fb30ac42c8d8)]
[scriptable, uuid(a15f7ebd-4f35-4e73-a2d8-255d27fd14ee)]
interface nsIDOMStorageManager : nsISupports
{
/**
@ -27,6 +28,8 @@ interface nsIDOMStorageManager : nsISupports
* A new object is always returned and it is ensured there is
* a storage for the scope created.
*
* @param aWindow
* The parent window.
* @param aPrincipal
* Principal to bound storage to.
* @param aDocumentURI
@ -34,7 +37,8 @@ interface nsIDOMStorageManager : nsISupports
* @param aPrivate
* Whether the demanding document is running in Private Browsing mode or not.
*/
nsIDOMStorage createStorage(in nsIPrincipal aPrincipal,
nsIDOMStorage createStorage(in nsIDOMWindow aWindow,
in nsIPrincipal aPrincipal,
in DOMString aDocumentURI,
[optional] in bool aPrivate);
/**
@ -43,12 +47,15 @@ interface nsIDOMStorageManager : nsISupports
* no object is created. Otherwise, an object (new) for the existing storage
* scope is returned.
*
* @param aWindow
* The parent window.
* @param aPrincipal
* Principal to bound storage to.
* @param aPrivate
* Whether the demanding document is running in Private Browsing mode or not.
*/
nsIDOMStorage getStorage(in nsIPrincipal aPrincipal,
nsIDOMStorage getStorage(in nsIDOMWindow aWindow,
in nsIPrincipal aPrincipal,
[optional] in bool aPrivate);
/**

View File

@ -1,54 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsPIDOMStorage_h_
#define __nsPIDOMStorage_h_
#include "nsISupports.h"
#include "nsString.h"
#include "nsTArray.h"
class nsIPrincipal;
namespace mozilla {
namespace dom {
class DOMStorageCache;
class DOMStorageManager;
} // ::dom
} // ::mozilla
// {09198A51-5D27-4992-97E4-38A9CEA2A65D}
#define NS_PIDOMSTORAGE_IID \
{ 0x9198a51, 0x5d27, 0x4992, \
{ 0x97, 0xe4, 0x38, 0xa9, 0xce, 0xa2, 0xa6, 0x5d } }
class nsPIDOMStorage : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID)
enum StorageType {
LocalStorage = 1,
SessionStorage = 2
};
virtual StorageType GetType() const = 0;
virtual mozilla::dom::DOMStorageManager* GetManager() const = 0;
virtual const mozilla::dom::DOMStorageCache* GetCache() const = 0;
virtual nsTArray<nsString>* GetKeys() = 0;
virtual nsIPrincipal* GetPrincipal() = 0;
virtual bool PrincipalEquals(nsIPrincipal* principal) = 0;
virtual bool CanAccess(nsIPrincipal *aPrincipal) = 0;
virtual bool IsPrivate() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMStorage, NS_PIDOMSTORAGE_IID)
#endif // __nsPIDOMStorage_h_

View File

@ -7,42 +7,44 @@
#include "DOMStorageCache.h"
#include "DOMStorageManager.h"
#include "mozilla/dom/StorageEvent.h"
#include "nsIObserverService.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsICookiePermission.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "nsServiceManagerUtils.h"
DOMCI_DATA(Storage, mozilla::dom::DOMStorage)
namespace mozilla {
namespace dom {
NS_IMPL_ADDREF(DOMStorage)
NS_IMPL_RELEASE(DOMStorage)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMStorage, mManager, mPrincipal, mWindow)
NS_INTERFACE_MAP_BEGIN(DOMStorage)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMStorage)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMStorage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMStorage)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Storage)
NS_INTERFACE_MAP_END
DOMStorage::DOMStorage(DOMStorageManager* aManager,
DOMStorage::DOMStorage(nsIDOMWindow* aWindow,
DOMStorageManager* aManager,
DOMStorageCache* aCache,
const nsAString& aDocumentURI,
nsIPrincipal* aPrincipal,
bool aIsPrivate)
: mManager(aManager)
: mWindow(aWindow)
, mManager(aManager)
, mCache(aCache)
, mDocumentURI(aDocumentURI)
, mPrincipal(aPrincipal)
@ -50,6 +52,7 @@ DOMStorage::DOMStorage(DOMStorageManager* aManager,
, mIsSessionOnly(false)
{
mCache->Preload();
SetIsDOMBinding();
}
DOMStorage::~DOMStorage()
@ -57,43 +60,54 @@ DOMStorage::~DOMStorage()
mCache->KeepAlive();
}
// nsIDOMStorage (web content public API implementation)
NS_IMETHODIMP
DOMStorage::GetLength(uint32_t* aLength)
/* virtual */ JSObject*
DOMStorage::WrapObject(JSContext* aCx)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
return mCache->GetLength(this, aLength);
return StorageBinding::Wrap(aCx, this);
}
NS_IMETHODIMP
DOMStorage::Key(uint32_t aIndex, nsAString& aRetval)
uint32_t
DOMStorage::GetLength(ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return 0;
}
return mCache->GetKey(this, aIndex, aRetval);
uint32_t length;
aRv = mCache->GetLength(this, &length);
return length;
}
NS_IMETHODIMP
DOMStorage::GetItem(const nsAString& aKey, nsAString& aRetval)
void
DOMStorage::Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
return mCache->GetItem(this, aKey, aRetval);
aRv = mCache->GetKey(this, aIndex, aResult);
}
NS_IMETHODIMP
DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
void
DOMStorage::GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
aRv = mCache->GetItem(this, aKey, aResult);
}
void
DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
Telemetry::Accumulate(GetType() == LocalStorage
@ -105,58 +119,57 @@ DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
nsString data;
bool ok = data.Assign(aData, fallible_t());
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
if (!ok) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
nsString old;
nsresult rv = mCache->SetItem(this, aKey, data, old);
if (NS_FAILED(rv)) {
return rv;
aRv = mCache->SetItem(this, aKey, data, old);
if (aRv.Failed()) {
return;
}
if (rv != NS_SUCCESS_DOM_NO_OPERATION) {
if (aRv.ErrorCode() != NS_SUCCESS_DOM_NO_OPERATION) {
BroadcastChangeNotification(aKey, old, aData);
}
return NS_OK;
}
NS_IMETHODIMP
DOMStorage::RemoveItem(const nsAString& aKey)
void
DOMStorage::RemoveItem(const nsAString& aKey, ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsAutoString old;
nsresult rv = mCache->RemoveItem(this, aKey, old);
if (NS_FAILED(rv)) {
return rv;
aRv = mCache->RemoveItem(this, aKey, old);
if (aRv.Failed()) {
return;
}
if (rv != NS_SUCCESS_DOM_NO_OPERATION) {
if (aRv.ErrorCode() != NS_SUCCESS_DOM_NO_OPERATION) {
BroadcastChangeNotification(aKey, old, NullString());
}
return NS_OK;
}
NS_IMETHODIMP
DOMStorage::Clear()
void
DOMStorage::Clear(ErrorResult& aRv)
{
if (!CanUseStorage(this)) {
return NS_ERROR_DOM_SECURITY_ERR;
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsresult rv = mCache->Clear(this);
if (NS_FAILED(rv)) {
return rv;
aRv = mCache->Clear(this);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (rv != NS_SUCCESS_DOM_NO_OPERATION) {
if (aRv.ErrorCode() != NS_SUCCESS_DOM_NO_OPERATION) {
BroadcastChangeNotification(NullString(), NullString(), NullString());
}
return NS_OK;
}
namespace {
@ -199,7 +212,7 @@ DOMStorage::BroadcastChangeNotification(const nsSubstring& aKey,
dict.mKey = aKey;
dict.mNewValue = aNewValue;
dict.mOldValue = aOldValue;
dict.mStorageArea = static_cast<nsIDOMStorage*>(this);
dict.mStorageArea = this;
dict.mUrl = mDocumentURI;
// Note, this DOM event should never reach JS. It is cloned later in
@ -285,9 +298,7 @@ DOMStorage::CanUseStorage(DOMStorage* aStorage)
return true;
}
// nsPIDOMStorage
nsPIDOMStorage::StorageType
DOMStorage::StorageType
DOMStorage::GetType() const
{
return mManager->Type();
@ -315,14 +326,16 @@ DOMStorage::CanAccess(nsIPrincipal* aPrincipal)
return !aPrincipal || aPrincipal->Subsumes(mPrincipal);
}
nsTArray<nsString>*
DOMStorage::GetKeys()
void
DOMStorage::GetSupportedNames(unsigned, nsTArray<nsString>& aKeys)
{
if (!CanUseStorage(this)) {
return new nsTArray<nsString>(); // return just an empty array
// return just an empty array
aKeys.Clear();
return;
}
return mCache->GetKeys(this);
mCache->GetKeys(this, aKeys);
}
} // ::dom

View File

@ -7,10 +7,16 @@
#define nsDOMStorage_h___
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsWeakReference.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWeakReference.h"
#include "nsWrapperCache.h"
#include "nsISupports.h"
class nsIPrincipal;
class nsIDOMWindow;
namespace mozilla {
namespace dom {
@ -18,30 +24,96 @@ namespace dom {
class DOMStorageManager;
class DOMStorageCache;
class DOMStorage MOZ_FINAL : public nsIDOMStorage
, public nsPIDOMStorage
, public nsSupportsWeakReference
class DOMStorage MOZ_FINAL
: public nsIDOMStorage
, public nsSupportsWeakReference
, public nsWrapperCache
{
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMSTORAGE
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(DOMStorage,
nsIDOMStorage)
// nsPIDOMStorage
virtual StorageType GetType() const MOZ_OVERRIDE;
virtual DOMStorageManager* GetManager() const MOZ_OVERRIDE { return mManager; }
virtual const DOMStorageCache* GetCache() const MOZ_OVERRIDE { return mCache; }
enum StorageType {
LocalStorage = 1,
SessionStorage = 2
};
virtual nsTArray<nsString>* GetKeys() MOZ_OVERRIDE;
virtual nsIPrincipal* GetPrincipal() MOZ_OVERRIDE;
virtual bool PrincipalEquals(nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual bool CanAccess(nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
virtual bool IsPrivate() MOZ_OVERRIDE { return mIsPrivate; }
StorageType GetType() const;
DOMStorage(DOMStorageManager* aManager,
DOMStorageManager* GetManager() const
{
return mManager;
}
DOMStorageCache const* GetCache() const
{
return mCache;
}
nsIPrincipal* GetPrincipal();
bool PrincipalEquals(nsIPrincipal* aPrincipal);
bool CanAccess(nsIPrincipal* aPrincipal);
bool IsPrivate()
{
return mIsPrivate;
}
DOMStorage(nsIDOMWindow* aWindow,
DOMStorageManager* aManager,
DOMStorageCache* aCache,
const nsAString& aDocumentURI,
nsIPrincipal* aPrincipal,
bool aIsPrivate);
// WebIDL
JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
nsIDOMWindow* GetParentObject() const
{
return mWindow;
}
uint32_t GetLength(ErrorResult& aRv);
void Key(uint32_t aIndex, nsAString& aResult, ErrorResult& aRv);
void GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv);
bool NameIsEnumerable(const nsAString& aName) const
{
return true;
}
void GetSupportedNames(unsigned, nsTArray<nsString>& aKeys);
void NamedGetter(const nsAString& aKey, bool& aFound, nsAString& aResult,
ErrorResult& aRv)
{
GetItem(aKey, aResult, aRv);
aFound = !aResult.IsVoid();
}
void SetItem(const nsAString& aKey, const nsAString& aValue,
ErrorResult& aRv);
void NamedSetter(const nsAString& aKey, const nsAString& aValue,
ErrorResult& aRv)
{
SetItem(aKey, aValue, aRv);
}
void RemoveItem(const nsAString& aKey, ErrorResult& aRv);
void NamedDeleter(const nsAString& aKey, bool& aFound, ErrorResult& aRv)
{
RemoveItem(aKey, aRv);
aFound = (aRv.ErrorCode() != NS_SUCCESS_DOM_NO_OPERATION);
}
void Clear(ErrorResult& aRv);
// The method checks whether the caller can use a storage.
// CanUseStorage is called before any DOM initiated operation
// on a storage is about to happen and ensures that the storage's
@ -60,6 +132,7 @@ private:
friend class DOMStorageManager;
friend class DOMStorageCache;
nsCOMPtr<nsIDOMWindow> mWindow;
nsRefPtr<DOMStorageManager> mManager;
nsRefPtr<DOMStorageCache> mCache;
nsString mDocumentURI;

View File

@ -428,8 +428,8 @@ KeysArrayBuilder(const nsAString& aKey, const nsString aValue, void* aArg)
} // anon
nsTArray<nsString>*
DOMStorageCache::GetKeys(const DOMStorage* aStorage)
void
DOMStorageCache::GetKeys(const DOMStorage* aStorage, nsTArray<nsString>& aKeys)
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_GETALLKEYS_MS> autoTimer;
@ -437,12 +437,11 @@ DOMStorageCache::GetKeys(const DOMStorage* aStorage)
WaitForPreload(Telemetry::LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS);
}
nsTArray<nsString>* result = new nsTArray<nsString>();
if (NS_SUCCEEDED(mLoadResult)) {
DataSet(aStorage).mKeys.EnumerateRead(KeysArrayBuilder, result);
if (NS_FAILED(mLoadResult)) {
return;
}
return result;
DataSet(aStorage).mKeys.EnumerateRead(KeysArrayBuilder, &aKeys);
}
nsresult

View File

@ -98,7 +98,7 @@ public:
nsresult RemoveItem(const DOMStorage* aStorage, const nsAString& aKey, nsString& aOld);
nsresult Clear(const DOMStorage* aStorage);
nsTArray<nsString>* GetKeys(const DOMStorage* aStorage);
void GetKeys(const DOMStorage* aStorage, nsTArray<nsString>& aKeys);
// Whether the principal equals principal the cache was created for
bool CheckPrincipal(nsIPrincipal* aPrincipal) const;

View File

@ -97,7 +97,7 @@ PrincipalsEqual(nsIPrincipal* aObjectPrincipal, nsIPrincipal* aSubjectPrincipal)
NS_IMPL_ISUPPORTS(DOMStorageManager,
nsIDOMStorageManager)
DOMStorageManager::DOMStorageManager(nsPIDOMStorage::StorageType aType)
DOMStorageManager::DOMStorageManager(DOMStorage::StorageType aType)
: mCaches(10)
, mType(aType)
, mLowDiskSpace(false)
@ -325,6 +325,7 @@ DOMStorageManager::DropCache(DOMStorageCache* aCache)
nsresult
DOMStorageManager::GetStorageInternal(bool aCreate,
nsIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI,
bool aPrivate,
@ -372,8 +373,9 @@ DOMStorageManager::GetStorageInternal(bool aCreate,
}
if (aRetval) {
*aRetval = new DOMStorage(this, cache, aDocumentURI, aPrincipal, aPrivate);
NS_ADDREF(*aRetval);
nsCOMPtr<nsIDOMStorage> storage = new DOMStorage(
aWindow, this, cache, aDocumentURI, aPrincipal, aPrivate);
storage.forget(aRetval);
}
return NS_OK;
@ -382,24 +384,29 @@ DOMStorageManager::GetStorageInternal(bool aCreate,
NS_IMETHODIMP
DOMStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal)
{
return GetStorageInternal(true, aPrincipal, EmptyString(), false, nullptr);
return GetStorageInternal(true, nullptr, aPrincipal, EmptyString(), false,
nullptr);
}
NS_IMETHODIMP
DOMStorageManager::CreateStorage(nsIPrincipal* aPrincipal,
DOMStorageManager::CreateStorage(nsIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI,
bool aPrivate,
nsIDOMStorage** aRetval)
{
return GetStorageInternal(true, aPrincipal, aDocumentURI, aPrivate, aRetval);
return GetStorageInternal(true, aWindow, aPrincipal, aDocumentURI, aPrivate,
aRetval);
}
NS_IMETHODIMP
DOMStorageManager::GetStorage(nsIPrincipal* aPrincipal,
DOMStorageManager::GetStorage(nsIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
bool aPrivate,
nsIDOMStorage** aRetval)
{
return GetStorageInternal(false, aPrincipal, EmptyString(), aPrivate, aRetval);
return GetStorageInternal(false, aWindow, aPrincipal, EmptyString(), aPrivate,
aRetval);
}
NS_IMETHODIMP
@ -410,12 +417,12 @@ DOMStorageManager::CloneStorage(nsIDOMStorage* aStorage)
return NS_ERROR_NOT_IMPLEMENTED;
}
nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage);
if (!pstorage) {
nsRefPtr<DOMStorage> storage = static_cast<DOMStorage*>(aStorage);
if (!storage) {
return NS_ERROR_UNEXPECTED;
}
const DOMStorageCache* origCache = pstorage->GetCache();
const DOMStorageCache* origCache = storage->GetCache();
DOMStorageCache* existingCache = GetCache(origCache->Scope());
if (existingCache) {
@ -437,8 +444,8 @@ DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal,
nsIDOMStorage* aStorage,
bool* aRetval)
{
nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage);
if (!pstorage) {
nsRefPtr<DOMStorage> storage = static_cast<DOMStorage*>(aStorage);
if (!storage) {
return NS_ERROR_UNEXPECTED;
}
@ -455,11 +462,11 @@ DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal,
}
DOMStorageCache* cache = GetCache(scope);
if (cache != pstorage->GetCache()) {
if (cache != storage->GetCache()) {
return NS_OK;
}
if (!pstorage->PrincipalEquals(aPrincipal)) {
if (!storage->PrincipalEquals(aPrincipal)) {
return NS_OK;
}
@ -479,7 +486,7 @@ DOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal* aPrincipal,
return NS_ERROR_UNEXPECTED;
}
return CreateStorage(aPrincipal, aDocumentURI, aPrivate, aRetval);
return CreateStorage(nullptr, aPrincipal, aDocumentURI, aPrivate, aRetval);
}
namespace { // anon

View File

@ -9,20 +9,20 @@
#include "nsIDOMStorageManager.h"
#include "DOMStorageObserver.h"
#include "nsPIDOMStorage.h"
#include "DOMStorageCache.h"
#include "mozilla/dom/DOMStorage.h"
#include "nsTHashtable.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
class nsIDOMWindow;
namespace mozilla {
namespace dom {
const nsPIDOMStorage::StorageType SessionStorage = nsPIDOMStorage::SessionStorage;
const nsPIDOMStorage::StorageType LocalStorage = nsPIDOMStorage::LocalStorage;
class DOMStorage;
const DOMStorage::StorageType SessionStorage = DOMStorage::SessionStorage;
const DOMStorage::StorageType LocalStorage = DOMStorage::LocalStorage;
class DOMStorageManager : public nsIDOMStorageManager
, public DOMStorageObserverSink
@ -31,7 +31,7 @@ class DOMStorageManager : public nsIDOMStorageManager
NS_DECL_NSIDOMSTORAGEMANAGER
public:
virtual nsPIDOMStorage::StorageType Type() { return mType; }
virtual DOMStorage::StorageType Type() { return mType; }
// Reads the preference for DOM storage quota
static uint32_t GetQuota();
@ -41,7 +41,7 @@ public:
already_AddRefed<DOMStorageUsage> GetScopeUsage(const nsACString& aScope);
protected:
DOMStorageManager(nsPIDOMStorage::StorageType aType);
DOMStorageManager(DOMStorage::StorageType aType);
virtual ~DOMStorageManager();
private:
@ -82,6 +82,7 @@ private:
// Helper for creation of DOM storage objects
nsresult GetStorageInternal(bool aCreate,
nsIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI,
bool aPrivate,
@ -89,7 +90,7 @@ private:
// Scope->cache map
nsTHashtable<DOMStorageCacheHashKey> mCaches;
const nsPIDOMStorage::StorageType mType;
const DOMStorage::StorageType mType;
// If mLowDiskSpace is true it indicates a low device storage situation and
// so no localStorage writes are allowed. sessionStorage writes are still

View File

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'DOMStorage.h',
'DOMStorageIPC.h',
]

View File

@ -1,13 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<div id="status"></div>
</body>
<script>
addEventListener('message', function(e) {
if (e.data == 'clear') {
navigator.mozApps.getSelf().onsuccess = function() {
this.result.clearBrowserData();
document.body.innerHTML = "<done></done>";
document.getElementById('status').textContent = 'done';
};
}
});

View File

@ -164,13 +164,14 @@ function browserLoadEvent() {
function waitForClearBrowserData() {
SimpleTest.executeSoon(function() {
if (frames[1].document.getElementsByTagName('done').length == 0) {
if (frames[1].document.getElementById('status').textContent != 'done') {
waitForClearBrowserData();
} else {
checks();
}
});
}
function checks() {
navigator.mozApps.mgmt.getAll().onsuccess = function() {
for (i in this.result) {

View File

@ -204,14 +204,12 @@ function startTest()
is(localStorage.getItem(null), "test");
is(localStorage["null"], "test");
localStorage.removeItem(null, "test");
// bug 350023
todo_is("null" in localStorage, false);
is("null" in localStorage, false);
localStorage.setItem(null, "test");
is("null" in localStorage, true);
localStorage.removeItem("null", "test");
// bug 350023
todo_is("null" in localStorage, false);
is("null" in localStorage, false);
// Clear the storage
localStorage.clear();

View File

@ -207,14 +207,12 @@ function doTest() {
is(privateWin.content.localStorage.getItem(null), "test");
is(privateWin.content.localStorage["null"], "test");
privateWin.content.localStorage.removeItem(null, "test");
// bug 350023
todo_is("null" in privateWin.content.localStorage, false);
is("null" in privateWin.content.localStorage, false);
privateWin.content.localStorage.setItem(null, "test");
is("null" in privateWin.content.localStorage, true);
privateWin.content.localStorage.removeItem("null", "test");
// bug 350023
todo_is("null" in privateWin.content.localStorage, false);
is("null" in privateWin.content.localStorage, false);
// Clear the storage
privateWin.content.localStorage.clear();

View File

@ -169,14 +169,12 @@ function test1() {
is(localStorage.getItem(null), "test");
is(localStorage["null"], "test");
localStorage.removeItem(null, "test");
// bug 350023
todo_is("null" in localStorage, false);
is("null" in localStorage, false);
localStorage.setItem(null, "test");
is("null" in localStorage, true);
localStorage.removeItem("null", "test");
// bug 350023
todo_is("null" in localStorage, false);
is("null" in localStorage, false);
// Clear the storage
localStorage.clear();

View File

@ -19,7 +19,7 @@ function startTest()
var uri = ios.newURI(url, "", null);
var principal = ssm.getNoAppCodebasePrincipal(uri);
var storage = dsm.createStorage(principal, "");
var storage = dsm.createStorage(window, principal, "");
storage.setItem("chromekey", "chromevalue");

View File

@ -191,14 +191,12 @@ function test1() {
is(sessionStorage.getItem(null), "test");
is(sessionStorage["null"], "test");
sessionStorage.removeItem(null, "test");
// bug 350023
todo_is("null" in sessionStorage, false);
is("null" in sessionStorage, false);
sessionStorage.setItem(null, "test");
is("null" in sessionStorage, true);
sessionStorage.removeItem("null", "test");
// bug 350023
todo_is("null" in sessionStorage, false);
is("null" in sessionStorage, false);
// Clear the storage
sessionStorage.clear();

32
dom/webidl/Storage.webidl Normal file
View File

@ -0,0 +1,32 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://www.whatwg.org/html/#the-storage-interface
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
interface Storage {
[Throws]
readonly attribute unsigned long length;
[Throws]
DOMString? key(unsigned long index);
[Throws]
getter DOMString? getItem(DOMString key);
[Throws]
setter creator void setItem(DOMString key, DOMString value);
[Throws]
deleter void removeItem(DOMString key);
[Throws]
void clear();
};

View File

@ -9,7 +9,6 @@
*
* Event sent to a window when a storage area changes.
*/
interface Storage;
[Constructor(DOMString type, optional StorageEventInit eventInitDict)]
interface StorageEvent : Event

View File

@ -325,6 +325,7 @@ WEBIDL_FILES = [
'SimpleGestureEvent.webidl',
'SourceBuffer.webidl',
'SourceBufferList.webidl',
'Storage.webidl',
'StorageEvent.webidl',
'StorageType.webidl',
'StyleSheet.webidl',

View File

@ -48,7 +48,6 @@
#include "nsIWindowProvider.h"
#include "nsIMutableArray.h"
#include "nsISupportsArray.h"
#include "nsIDOMStorage.h"
#include "nsIDOMStorageManager.h"
#include "nsIWidget.h"
#include "nsFocusManager.h"
@ -60,6 +59,7 @@
#include "nsIPrefService.h"
#include "nsSandboxFlags.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/DOMStorage.h"
#ifdef USEWEAKREFS
#include "nsIWeakReference.h"
@ -951,9 +951,17 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow *aParent,
if (parentStorageManager && newStorageManager) {
nsCOMPtr<nsIDOMStorage> storage;
parentStorageManager->GetStorage(subjectPrincipal, isPrivateBrowsingWindow, getter_AddRefs(storage));
if (storage)
nsCOMPtr<nsPIDOMWindow> pWin = do_QueryInterface(aParent);
nsCOMPtr<nsPIDOMWindow> pInnerWin = pWin->IsInnerWindow()
? pWin.get()
: pWin->GetCurrentInnerWindow();
parentStorageManager->GetStorage(pInnerWin, subjectPrincipal,
isPrivateBrowsingWindow,
getter_AddRefs(storage));
if (storage) {
newStorageManager->CloneStorage(storage);
}
}
}

View File

@ -32,14 +32,6 @@ members = [
#'nsIDOMLocation.hostname',
#'nsIDOMLocation.href',
# dom/interfaces/storage
'nsIDOMStorage.setItem',
'nsIDOMStorage.length',
'nsIDOMStorage.getItem',
'nsIDOMStorage.key',
'nsIDOMStorage.removeItem',
'nsIDOMStorage.clear',
# dom/interfaces/xpath
'nsIDOMXPathNSResolver.lookupNamespaceURI',
@ -70,18 +62,6 @@ customIncludes = [
'mozilla/dom/WindowBinding.h',
]
nsIDOMStorage_Clear_customMethodCallCode = """
rv = self->Clear();
if (NS_SUCCEEDED(rv))
JS_ClearNonGlobalObject(cx, obj);
"""
customMethodCalls = {
'nsIDOMStorage_Clear': {
'code': nsIDOMStorage_Clear_customMethodCallCode
},
}
newBindingProperties = {
# Once the last entry here goes away, we can make the sNativePropertyHooks
# of bindings static.

View File

@ -97,7 +97,7 @@ FrameWorker.prototype = {
// Bug 798660 - XHR, WebSocket and Worker have issues in a sandbox and need
// to be unwrapped to work
let needsWaive = ['XMLHttpRequest', 'WebSocket', 'Worker'];
let needsWaive = ['XMLHttpRequest', 'WebSocket', 'Worker' ];
// Methods need to be bound with the proper |this|.
let needsBind = ['atob', 'btoa', 'dump', 'setInterval', 'clearInterval',
'setTimeout', 'clearTimeout'];

View File

@ -106,6 +106,10 @@ function markOutMatched(toBeEmptied, data, deleted) {
ok(toBeEmptied[storageType][host], "Host " + host + " found");
if (!deleted) {
for (let item of data[storageType][host]) {
if ([ 'length', 'key', 'getItem', 'setItem',
'removeItem', 'clear'].indexOf(item) != -1) {
continue;
}
let index = toBeEmptied[storageType][host].indexOf(item);
ok(index > -1, "Item found - " + item);
if (index > -1) {

View File

@ -10,6 +10,8 @@ const {StorageFront} = require("devtools/server/actors/storage");
let {Task} = require("resource://gre/modules/Task.jsm");
let gWindow = null;
const domStorageProperties = ['length', 'key', 'getItem','setItem', 'removeItem', 'clear'];
const storeMap = {
cookies: {
"test1.example.org": [
@ -419,9 +421,13 @@ function testLocalStorage(localStorageActor) {
let testLocalStorageObjects = Task.async(function*(index, hosts, localStorageActor) {
let host = Object.keys(hosts)[index];
let matchItems = data => {
is(data.total, storeMap.localStorage[host].length,
is(data.total - domStorageProperties.length, storeMap.localStorage[host].length,
"Number of local storage items in host " + host + " matches");
for (let item of data.data) {
if (domStorageProperties.indexOf(item.name) != -1) {
continue;
}
let found = false;
for (let toMatch of storeMap.localStorage[host]) {
if (item.name == toMatch.name) {
@ -456,9 +462,13 @@ function testSessionStorage(sessionStorageActor) {
let testSessionStorageObjects = Task.async(function*(index, hosts, sessionStorageActor) {
let host = Object.keys(hosts)[index];
let matchItems = data => {
is(data.total, storeMap.sessionStorage[host].length,
is(data.total - domStorageProperties.length, storeMap.sessionStorage[host].length,
"Number of session storage items in host " + host + " matches");
for (let item of data.data) {
if (domStorageProperties.indexOf(item.name) != -1) {
continue;
}
let found = false;
for (let toMatch of storeMap.sessionStorage[host]) {
if (item.name == toMatch.name) {

View File

@ -673,7 +673,7 @@ function test_storage_cleared()
getNoAppCodebasePrincipal(aURI);
let dsm = Cc["@mozilla.org/dom/localStorage-manager;1"].
getService(Ci.nsIDOMStorageManager);
return dsm.createStorage(principal, "");
return dsm.createStorage(null, principal, "");
}
let s = [