2017-05-17 08:01:13 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 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/. */
|
|
|
|
|
|
|
|
#include "LocalStorage.h"
|
2017-05-17 08:01:14 +03:00
|
|
|
#include "LocalStorageCache.h"
|
2017-05-17 08:01:14 +03:00
|
|
|
#include "LocalStorageManager.h"
|
2017-05-17 08:01:14 +03:00
|
|
|
#include "StorageUtils.h"
|
2017-05-17 08:01:13 +03:00
|
|
|
|
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
|
|
|
|
#include "mozilla/dom/PermissionMessageUtils.h"
|
|
|
|
#include "mozilla/dom/StorageBinding.h"
|
|
|
|
#include "mozilla/dom/StorageEvent.h"
|
|
|
|
#include "mozilla/dom/StorageEventBinding.h"
|
2017-08-09 00:02:28 +03:00
|
|
|
#include "mozilla/ipc/BackgroundChild.h"
|
|
|
|
#include "mozilla/ipc/PBackgroundChild.h"
|
2017-05-17 08:01:13 +03:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/EnumSet.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace ipc;
|
|
|
|
|
|
|
|
namespace dom {
|
|
|
|
|
2018-11-29 23:47:48 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(LocalStorage)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(LocalStorage, Storage)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mManager)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(LocalStorage, Storage)
|
|
|
|
CycleCollectionNoteChild(
|
|
|
|
cb, NS_ISUPPORTS_CAST(nsIDOMStorageManager*, tmp->mManager.get()),
|
|
|
|
"mManager");
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
2017-05-17 08:01:13 +03:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
|
|
NS_INTERFACE_MAP_END_INHERITING(Storage)
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
|
|
|
|
|
|
|
|
LocalStorage::LocalStorage(nsPIDOMWindowInner* aWindow,
|
2017-05-17 08:01:14 +03:00
|
|
|
LocalStorageManager* aManager,
|
2017-05-17 08:01:14 +03:00
|
|
|
LocalStorageCache* aCache,
|
2017-05-17 08:01:13 +03:00
|
|
|
const nsAString& aDocumentURI,
|
2019-05-14 08:49:46 +03:00
|
|
|
nsIPrincipal* aPrincipal,
|
|
|
|
nsIPrincipal* aStoragePrincipal, bool aIsPrivate)
|
|
|
|
: Storage(aWindow, aPrincipal, aStoragePrincipal),
|
2017-05-17 08:01:13 +03:00
|
|
|
mManager(aManager),
|
|
|
|
mCache(aCache),
|
|
|
|
mDocumentURI(aDocumentURI),
|
|
|
|
mIsPrivate(aIsPrivate) {
|
|
|
|
mCache->Preload();
|
|
|
|
}
|
|
|
|
|
|
|
|
LocalStorage::~LocalStorage() {}
|
|
|
|
|
|
|
|
int64_t LocalStorage::GetOriginQuotaUsage() const {
|
|
|
|
return mCache->GetOriginQuotaUsage(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t LocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
|
|
|
|
ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t length;
|
|
|
|
aRv = mCache->GetLength(this, &length);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::Key(uint32_t aIndex, nsAString& aResult,
|
|
|
|
nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRv = mCache->GetKey(this, aIndex, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::GetItem(const nsAString& aKey, nsAString& aResult,
|
|
|
|
nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRv = mCache->GetItem(this, aKey, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::SetItem(const nsAString& aKey, const nsAString& aData,
|
|
|
|
nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsString data;
|
|
|
|
bool ok = data.Assign(aData, fallible);
|
|
|
|
if (!ok) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsString old;
|
|
|
|
aRv = mCache->SetItem(this, aKey, data, old);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
2018-07-14 09:34:14 +03:00
|
|
|
OnChange(aKey, old, aData);
|
2017-05-17 08:01:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::RemoveItem(const nsAString& aKey,
|
|
|
|
nsIPrincipal& aSubjectPrincipal,
|
|
|
|
ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString old;
|
|
|
|
aRv = mCache->RemoveItem(this, aKey, old);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
2018-07-14 09:34:14 +03:00
|
|
|
OnChange(aKey, old, VoidString());
|
2017-05-17 08:01:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
|
|
|
|
if (!CanUseStorage(aSubjectPrincipal)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRv = mCache->Clear(this);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
|
2018-07-14 09:34:14 +03:00
|
|
|
OnChange(VoidString(), VoidString(), VoidString());
|
2017-05-17 08:01:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-14 09:34:14 +03:00
|
|
|
void LocalStorage::OnChange(const nsAString& aKey, const nsAString& aOldValue,
|
|
|
|
const nsAString& aNewValue) {
|
2019-05-14 08:49:46 +03:00
|
|
|
NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey, aOldValue,
|
|
|
|
aNewValue, /* aStorageType */ u"localStorage", mDocumentURI,
|
|
|
|
mIsPrivate, /* aImmediateDispatch */ false);
|
2017-05-17 08:01:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::ApplyEvent(StorageEvent* aStorageEvent) {
|
|
|
|
MOZ_ASSERT(aStorageEvent);
|
|
|
|
|
|
|
|
nsAutoString key;
|
|
|
|
nsAutoString old;
|
|
|
|
nsAutoString value;
|
|
|
|
|
|
|
|
aStorageEvent->GetKey(key);
|
|
|
|
aStorageEvent->GetNewValue(value);
|
|
|
|
|
|
|
|
// No key means clearing the full storage.
|
|
|
|
if (key.IsVoid()) {
|
|
|
|
MOZ_ASSERT(value.IsVoid());
|
2017-05-17 08:01:14 +03:00
|
|
|
mCache->Clear(this, LocalStorageCache::E10sPropagated);
|
2017-05-17 08:01:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No new value means removing the key.
|
|
|
|
if (value.IsVoid()) {
|
2017-05-17 08:01:14 +03:00
|
|
|
mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
|
2017-05-17 08:01:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we set the new value.
|
2017-05-17 08:01:14 +03:00
|
|
|
mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
|
2017-05-17 08:01:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
|
|
|
|
if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
|
|
|
|
// return just an empty array
|
|
|
|
aKeys.Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mCache->GetKeys(this, aKeys);
|
|
|
|
}
|
|
|
|
|
2017-05-17 08:01:14 +03:00
|
|
|
bool LocalStorage::IsForkOf(const Storage* aOther) const {
|
|
|
|
MOZ_ASSERT(aOther);
|
|
|
|
if (aOther->Type() != eLocalStorage) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
|
|
|
|
}
|
|
|
|
|
2017-05-17 08:01:13 +03:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|