fune/dom/storage/LocalStorage.cpp
Jan Varga 5f8daf01d9 Bug 1462162 - Filter local storage cache synchronization messages based on origin; r=asuth
This patch adds a new IPDL protocol PBackgroundLocalStorageCache. It is used by LocalStorageCache object to broadcast changes in local storage cache to other content processes. Each origin has its own PBackgroundLocalStorageCache, so now we can notify content processes that actually have a local storage cache for given origin. This greatly improves performance and reduces memory footprint especialy when local storage changes carry big strings and/or happen very quickly (before this patch all child processes were blindly notified).
2018-07-14 08:34:14 +02:00

254 lines
6 KiB
C++

/* -*- 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"
#include "LocalStorageCache.h"
#include "LocalStorageManager.h"
#include "StorageUtils.h"
#include "nsIObserverService.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsICookiePermission.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "mozilla/EnumSet.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
using namespace ipc;
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(LocalStorage, Storage, mManager);
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,
LocalStorageManager* aManager,
LocalStorageCache* aCache,
const nsAString& aDocumentURI,
nsIPrincipal* aPrincipal,
bool aIsPrivate)
: Storage(aWindow, aPrincipal)
, 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)) {
OnChange(aKey, old, aData);
}
}
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)) {
OnChange(aKey, old, VoidString());
}
}
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)) {
OnChange(VoidString(), VoidString(), VoidString());
}
}
void
LocalStorage::OnChange(const nsAString& aKey,
const nsAString& aOldValue,
const nsAString& aNewValue)
{
NotifyChange(/* aStorage */ this,
Principal(),
aKey,
aOldValue,
aNewValue,
/* aStorageType */ u"localStorage",
mDocumentURI,
mIsPrivate,
/* aImmediateDispatch */ false);
}
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());
mCache->Clear(this, LocalStorageCache::E10sPropagated);
return;
}
// No new value means removing the key.
if (value.IsVoid()) {
mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
return;
}
// Otherwise, we set the new value.
mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
}
bool
LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
{
return StorageUtils::PrincipalsEqual(mPrincipal, aPrincipal);
}
void
LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys)
{
if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
// return just an empty array
aKeys.Clear();
return;
}
mCache->GetKeys(this, aKeys);
}
bool
LocalStorage::IsForkOf(const Storage* aOther) const
{
MOZ_ASSERT(aOther);
if (aOther->Type() != eLocalStorage) {
return false;
}
return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
}
} // namespace dom
} // namespace mozilla