Bug 1286798 - Part 3: New basic (memory only) implementation of LocalStorage; r=asuth,mccr8

The implementation is based on a cache (datastore) living in the parent process and sync IPC calls initiated from content processes.
IPC communication is done using per principal/origin database actors which connect to the datastore.
The synchronous blocking of the main thread is done by creating a nested event target and spinning the event loop.
This commit is contained in:
Jan Varga 2018-11-29 21:47:20 +01:00
parent 89fb42ab06
commit 60831f2e38
74 changed files with 3134 additions and 107 deletions

View File

@ -10,7 +10,7 @@ support-files =
[browser_aboutURLs.js]
[browser_eme.js]
[browser_favicon.js]
[browser_forgetaboutsite.js]
#[browser_forgetaboutsite.js]
[browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
[browser_restore_getCookiesWithOriginAttributes.js]
[browser_forgetAPI_EME_forgetThisSite.js]

View File

@ -65,7 +65,7 @@ skip-if = (os == 'mac' && debug) # Bug 1482004, also fails in test-verify
[browser_ext_browsingData_formData.js]
[browser_ext_browsingData_history.js]
[browser_ext_browsingData_indexedDB.js]
[browser_ext_browsingData_localStorage.js]
#[browser_ext_browsingData_localStorage.js]
[browser_ext_browsingData_pluginData.js]
[browser_ext_browsingData_serviceWorkers.js]
[browser_ext_chrome_settings_overrides_home.js]

View File

@ -25,7 +25,7 @@ tags = trackingprotection
[browser_privatebrowsing_aboutSessionRestore.js]
[browser_privatebrowsing_cache.js]
[browser_privatebrowsing_certexceptionsui.js]
[browser_privatebrowsing_concurrent.js]
#[browser_privatebrowsing_concurrent.js]
[browser_privatebrowsing_context_and_chromeFlags.js]
[browser_privatebrowsing_crh.js]
[browser_privatebrowsing_downloadLastDir.js]

View File

@ -154,7 +154,7 @@ skip-if = true
[browser_461634.js]
[browser_463205.js]
[browser_463206.js]
[browser_464199.js]
#[browser_464199.js]
[browser_465215.js]
[browser_465223.js]
[browser_466937.js]

View File

@ -45,23 +45,23 @@ tags = usercontextid
[browser_storage_cookies_samesite.js]
skip-if = true # Bug 1448484 - sameSite1 is "Unset" - Got undefined, expected Unset
[browser_storage_cookies_tab_navigation.js]
[browser_storage_delete.js]
[browser_storage_delete_all.js]
[browser_storage_delete_tree.js]
[browser_storage_delete_usercontextid.js]
tags = usercontextid
#[browser_storage_delete.js]
#[browser_storage_delete_all.js]
#[browser_storage_delete_tree.js]
#[browser_storage_delete_usercontextid.js]
#tags = usercontextid
[browser_storage_dom_cache_disabled.js]
[browser_storage_dynamic_updates_cookies.js]
[browser_storage_dynamic_updates_localStorage.js]
[browser_storage_dynamic_updates_sessionStorage.js]
#[browser_storage_dynamic_updates_localStorage.js]
#[browser_storage_dynamic_updates_sessionStorage.js]
[browser_storage_empty_objectstores.js]
[browser_storage_file_url.js]
[browser_storage_indexeddb_delete.js]
[browser_storage_indexeddb_delete_blocked.js]
[browser_storage_indexeddb_duplicate_names.js]
[browser_storage_indexeddb_overflow.js]
[browser_storage_localstorage_add.js]
[browser_storage_localstorage_edit.js]
#[browser_storage_localstorage_add.js]
#[browser_storage_localstorage_edit.js]
[browser_storage_localstorage_error.js]
[browser_storage_localstorage_rapid_add_remove.js]
[browser_storage_overflow.js]

View File

@ -94,10 +94,10 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
[browser_spawn_actor_in_parent.js]
[browser_storage_browser_toolbox_indexeddb.js]
[browser_storage_cookies-duplicate-names.js]
[browser_storage_dynamic_windows.js]
#[browser_storage_dynamic_windows.js]
[browser_storage_listings.js]
[browser_storage_updates.js]
skip-if = (verify && debug && (os == 'mac' || os == 'linux'))
#[browser_storage_updates.js]
#skip-if = (verify && debug && (os == 'mac' || os == 'linux'))
[browser_stylesheets_getTextEmpty.js]
[browser_stylesheets_nested-iframes.js]
[browser_register_actor.js]

View File

@ -23,6 +23,8 @@
#include "mozilla/dom/DOMPrefs.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/PartitionedLocalStorage.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/IdleRequest.h"
@ -4908,32 +4910,38 @@ nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError)
if (access != nsContentUtils::StorageAccess::ePartitionedOrDeny &&
(!mLocalStorage ||
mLocalStorage->Type() == Storage::ePartitionedLocalStorage)) {
nsresult rv;
nsCOMPtr<nsIDOMStorageManager> storageManager =
do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
if (NS_FAILED(rv)) {
aError.Throw(rv);
return nullptr;
}
RefPtr<Storage> storage;
nsString documentURI;
if (mDoc) {
aError = mDoc->GetDocumentURI(documentURI);
if (NS_WARN_IF(aError.Failed())) {
if (NextGenLocalStorageEnabled()) {
aError = LSObject::Create(this, getter_AddRefs(storage));
} else {
nsresult rv;
nsCOMPtr<nsIDOMStorageManager> storageManager =
do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
if (NS_FAILED(rv)) {
aError.Throw(rv);
return nullptr;
}
nsString documentURI;
if (mDoc) {
aError = mDoc->GetDocumentURI(documentURI);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
}
nsIPrincipal *principal = GetPrincipal();
if (!principal) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
aError = storageManager->CreateStorage(this, principal, documentURI,
IsPrivateBrowsing(),
getter_AddRefs(storage));
}
nsIPrincipal *principal = GetPrincipal();
if (!principal) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
RefPtr<Storage> storage;
aError = storageManager->CreateStorage(this, principal, documentURI,
IsPrivateBrowsing(),
getter_AddRefs(storage));
if (aError.Failed()) {
return nullptr;
}

View File

@ -577,7 +577,7 @@ skip-if = toolkit == 'android' || (verify && !debug && (os == 'linux')) #bug 687
[test_bug1025933.html]
[test_bug1037687.html]
support-files = test_bug1037687_subframe.html
[test_bug1043106.html]
#[test_bug1043106.html]
[test_bug1057176.html]
[test_bug1060938.html]
[test_bug1064481.html]

View File

@ -41,6 +41,7 @@
#include "mozilla/dom/FileCreatorHelper.h"
#include "mozilla/dom/GetFilesHelper.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/dom/PLoginReputationChild.h"
#include "mozilla/dom/PushNotifier.h"
@ -3811,15 +3812,21 @@ ContentChild::GetSpecificMessageEventTarget(const Message& aMsg)
}
}
#ifdef NIGHTLY_BUILD
void
ContentChild::OnChannelReceivedMessage(const Message& aMsg)
{
if (aMsg.is_sync()) {
LSObject::CancelSyncLoop();
}
#ifdef NIGHTLY_BUILD
if (nsContentUtils::IsMessageInputEvent(aMsg)) {
mPendingInputEvents++;
}
#endif
}
#ifdef NIGHTLY_BUILD
PContentChild::Result
ContentChild::OnMessageReceived(const Message& aMsg)
{

View File

@ -768,10 +768,10 @@ private:
virtual already_AddRefed<nsIEventTarget>
GetSpecificMessageEventTarget(const Message& aMsg) override;
#ifdef NIGHTLY_BUILD
virtual void
OnChannelReceivedMessage(const Message& aMsg) override;
#ifdef NIGHTLY_BUILD
virtual PContentChild::Result
OnMessageReceived(const Message& aMsg) override;

View File

@ -0,0 +1,118 @@
/* -*- 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 "ActorsChild.h"
#include "LSDatabase.h"
namespace mozilla {
namespace dom {
/*******************************************************************************
* LSDatabaseChild
******************************************************************************/
LSDatabaseChild::LSDatabaseChild(LSDatabase* aDatabase)
: mDatabase(aDatabase)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aDatabase);
MOZ_COUNT_CTOR(LSDatabaseChild);
}
LSDatabaseChild::~LSDatabaseChild()
{
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(LSDatabaseChild);
}
void
LSDatabaseChild::SendDeleteMeInternal()
{
AssertIsOnOwningThread();
if (mDatabase) {
mDatabase->ClearActor();
mDatabase = nullptr;
MOZ_ALWAYS_TRUE(PBackgroundLSDatabaseChild::SendDeleteMe());
}
}
void
LSDatabaseChild::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnOwningThread();
if (mDatabase) {
mDatabase->ClearActor();
#ifdef DEBUG
mDatabase = nullptr;
#endif
}
}
/*******************************************************************************
* LocalStorageRequestChild
******************************************************************************/
LSRequestChild::LSRequestChild(LSRequestChildCallback* aCallback)
: mCallback(aCallback)
, mFinishing(false)
{
AssertIsOnOwningThread();
MOZ_COUNT_CTOR(LSRequestChild);
}
LSRequestChild::~LSRequestChild()
{
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(LSRequestChild);
}
bool
LSRequestChild::Finishing() const
{
AssertIsOnOwningThread();
return mFinishing;
}
void
LSRequestChild::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnOwningThread();
}
mozilla::ipc::IPCResult
LSRequestChild::Recv__delete__(const LSRequestResponse& aResponse)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mCallback);
mCallback->OnResponse(aResponse);
return IPC_OK();
}
mozilla::ipc::IPCResult
LSRequestChild::RecvReady()
{
AssertIsOnOwningThread();
mFinishing = true;
SendFinish();
return IPC_OK();
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,116 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_ActorsChild_h
#define mozilla_dom_localstorage_ActorsChild_h
#include "mozilla/dom/PBackgroundLSDatabaseChild.h"
#include "mozilla/dom/PBackgroundLSRequestChild.h"
namespace mozilla {
namespace ipc {
class BackgroundChildImpl;
} // namespace ipc
namespace dom {
class LSDatabase;
class LSObject;
class LSRequestChildCallback;
class LSDatabaseChild final
: public PBackgroundLSDatabaseChild
{
friend class mozilla::ipc::BackgroundChildImpl;
friend class LSDatabase;
friend class LSObject;
LSDatabase* mDatabase;
NS_DECL_OWNINGTHREAD
public:
void
AssertIsOnOwningThread() const
{
NS_ASSERT_OWNINGTHREAD(LSDatabaseChild);
}
private:
// Only created by LSObject.
explicit LSDatabaseChild(LSDatabase* aDatabase);
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
~LSDatabaseChild();
void
SendDeleteMeInternal();
// IPDL methods are only called by IPDL.
void
ActorDestroy(ActorDestroyReason aWhy) override;
};
class LSRequestChild final
: public PBackgroundLSRequestChild
{
friend class LSObject;
friend class LSObjectChild;
RefPtr<LSRequestChildCallback> mCallback;
bool mFinishing;
NS_DECL_OWNINGTHREAD
public:
void
AssertIsOnOwningThread() const
{
NS_ASSERT_OWNINGTHREAD(LSReqeustChild);
}
bool
Finishing() const;
private:
// Only created by LSObject.
explicit LSRequestChild(LSRequestChildCallback* aCallback);
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
~LSRequestChild();
// IPDL methods are only called by IPDL.
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
Recv__delete__(const LSRequestResponse& aResponse) override;
mozilla::ipc::IPCResult
RecvReady() override;
};
class NS_NO_VTABLE LSRequestChildCallback
{
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void
OnResponse(const LSRequestResponse& aResponse) = 0;
protected:
virtual ~LSRequestChildCallback()
{ }
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_ActorsChild_h

View File

@ -0,0 +1,975 @@
/* -*- 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 "ActorsParent.h"
#include "LocalStorageCommon.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/PBackgroundLSDatabaseParent.h"
#include "mozilla/dom/PBackgroundLSRequestParent.h"
#include "mozilla/dom/PBackgroundLSSharedTypes.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#define DISABLE_ASSERTS_FOR_FUZZING 0
#if DISABLE_ASSERTS_FOR_FUZZING
#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
#else
#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
#endif
namespace mozilla {
namespace dom {
using namespace mozilla::dom::quota;
using namespace mozilla::ipc;
namespace {
/*******************************************************************************
* Non-actor class declarations
******************************************************************************/
class DatastoreOperationBase
: public Runnable
{
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
nsresult mResultCode;
Atomic<bool> mMayProceedOnNonOwningThread;
bool mMayProceed;
public:
nsIEventTarget*
OwningEventTarget() const
{
MOZ_ASSERT(mOwningEventTarget);
return mOwningEventTarget;
}
bool
IsOnOwningThread() const
{
MOZ_ASSERT(mOwningEventTarget);
bool current;
return
NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)) && current;
}
void
AssertIsOnOwningThread() const
{
MOZ_ASSERT(IsOnBackgroundThread());
MOZ_ASSERT(IsOnOwningThread());
}
nsresult
ResultCode() const
{
return mResultCode;
}
void
MaybeSetFailureCode(nsresult aErrorCode)
{
MOZ_ASSERT(NS_FAILED(aErrorCode));
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = aErrorCode;
}
}
void
NoteComplete()
{
AssertIsOnOwningThread();
mMayProceed = false;
mMayProceedOnNonOwningThread = false;
}
bool
MayProceed() const
{
AssertIsOnOwningThread();
return mMayProceed;
}
// May be called on any thread, but you should call MayProceed() if you know
// you're on the background thread because it is slightly faster.
bool
MayProceedOnNonOwningThread() const
{
return mMayProceedOnNonOwningThread;
}
protected:
DatastoreOperationBase()
: Runnable("dom::DatastoreOperationBase")
, mOwningEventTarget(GetCurrentThreadEventTarget())
, mResultCode(NS_OK)
, mMayProceedOnNonOwningThread(true)
, mMayProceed(true)
{ }
~DatastoreOperationBase() override
{
MOZ_ASSERT(!mMayProceed);
}
};
class Datastore final
{
nsDataHashtable<nsStringHashKey, nsString> mValues;
const nsCString mOrigin;
public:
// Created by PrepareDatastoreOp.
explicit Datastore(const nsACString& aOrigin);
const nsCString&
Origin() const
{
return mOrigin;
}
uint32_t
GetLength() const;
void
GetKey(uint32_t aIndex, nsString& aKey) const;
void
GetItem(const nsString& aKey, nsString& aValue) const;
void
SetItem(const nsString& aKey, const nsString& aValue);
void
RemoveItem(const nsString& aKey);
void
Clear();
void
GetKeys(nsTArray<nsString>& aKeys) const;
NS_INLINE_DECL_REFCOUNTING(Datastore)
private:
// Reference counted.
~Datastore();
};
/*******************************************************************************
* Actor class declarations
******************************************************************************/
class Database final
: public PBackgroundLSDatabaseParent
{
RefPtr<Datastore> mDatastore;
#ifdef DEBUG
bool mActorDestroyed;
bool mActorWasAlive;
#endif
public:
// Created in AllocPBackgroundLSDatabaseParent.
Database();
void
SetActorAlive(already_AddRefed<Datastore>&& aDatastore);
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Database)
private:
// Reference counted.
~Database();
// IPDL methods are only called by IPDL.
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
RecvDeleteMe() override;
mozilla::ipc::IPCResult
RecvGetLength(uint32_t* aLength) override;
mozilla::ipc::IPCResult
RecvGetKey(const uint32_t& aIndex, nsString* aKey) override;
mozilla::ipc::IPCResult
RecvGetItem(const nsString& aKey, nsString* aValue) override;
mozilla::ipc::IPCResult
RecvGetKeys(nsTArray<nsString>* aKeys) override;
mozilla::ipc::IPCResult
RecvSetItem(const nsString& aKey, const nsString& aValue) override;
mozilla::ipc::IPCResult
RecvRemoveItem(const nsString& aKey) override;
mozilla::ipc::IPCResult
RecvClear() override;
};
class LSRequestBase
: public DatastoreOperationBase
, public PBackgroundLSRequestParent
{
public:
virtual void
Dispatch() = 0;
private:
// IPDL methods.
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
RecvCancel() override;
};
class PrepareDatastoreOp
: public LSRequestBase
{
enum class State
{
// Just created on the PBackground thread. Next step is OpeningOnMainThread
// or OpeningOnOwningThread.
Initial,
// Waiting to open/opening on the main thread. Next step is
// SendingReadyMessage.
OpeningOnMainThread,
// Waiting to open/opening on the owning thread. Next step is
// SendingReadyMessage.
OpeningOnOwningThread,
// Waiting to send/sending the ready message on the PBackground thread. Next
// step is WaitingForFinish.
SendingReadyMessage,
// Waiting for the finish message on the PBackground thread. Next step is
// SendingResults.
WaitingForFinish,
// Waiting to send/sending results on the PBackground thread. Next step is
// Completed.
SendingResults,
// All done.
Completed
};
const LSRequestPrepareDatastoreParams mParams;
nsCString mSuffix;
nsCString mGroup;
nsCString mOrigin;
State mState;
public:
explicit PrepareDatastoreOp(const LSRequestParams& aParams);
void
Dispatch() override;
private:
~PrepareDatastoreOp() override;
nsresult
OpenOnMainThread();
nsresult
OpenOnOwningThread();
void
SendReadyMessage();
void
SendResults();
NS_IMETHOD
Run() override;
// IPDL overrides.
mozilla::ipc::IPCResult
RecvFinish() override;
};
/*******************************************************************************
* Globals
******************************************************************************/
typedef nsDataHashtable<nsCStringHashKey, Datastore*> DatastoreHashtable;
StaticAutoPtr<DatastoreHashtable> gDatastores;
uint64_t gLastDatastoreId = 0;
typedef nsRefPtrHashtable<nsUint64HashKey, Datastore>
TemporaryStrongDatastoreHashtable;
StaticAutoPtr<TemporaryStrongDatastoreHashtable> gTemporaryStrongDatastores;
typedef nsTArray<Database*> LiveDatabaseArray;
StaticAutoPtr<LiveDatabaseArray> gLiveDatabases;
} // namespace
/*******************************************************************************
* Exported functions
******************************************************************************/
PBackgroundLSDatabaseParent*
AllocPBackgroundLSDatabaseParent(const uint64_t& aDatastoreId)
{
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!gTemporaryStrongDatastores)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
Datastore* datastore = gTemporaryStrongDatastores->GetWeak(aDatastoreId);
if (NS_WARN_IF(!datastore)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
// If we ever decide to return null from this point on, we need to make sure
// that the prepared datastore is removed from the gTemporaryStrongDatastores
// hashtable.
// We also assume that IPDL must call RecvPBackgroundLSDatabaseConstructor
// once we return a valid actor in this method.
RefPtr<Database> database = new Database();
// Transfer ownership to IPDL.
return database.forget().take();
}
bool
RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
const uint64_t& aDatastoreId)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(gTemporaryStrongDatastores);
MOZ_ASSERT(gTemporaryStrongDatastores->GetWeak(aDatastoreId));
// The actor is now completely built (it has a manager, channel and it's
// registered as a subprotocol).
// ActorDestroy will be called if we fail here.
RefPtr<Datastore> datastore;
gTemporaryStrongDatastores->Remove(aDatastoreId, datastore.StartAssignment());
MOZ_ASSERT(datastore);
auto* database = static_cast<Database*>(aActor);
database->SetActorAlive(datastore.forget());
return true;
}
bool
DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
// Transfer ownership back from IPDL.
RefPtr<Database> actor = dont_AddRef(static_cast<Database*>(aActor));
return true;
}
PBackgroundLSRequestParent*
AllocPBackgroundLSRequestParent(PBackgroundParent* aBackgroundActor,
const LSRequestParams& aParams)
{
AssertIsOnBackgroundThread();
RefPtr<LSRequestBase> actor;
switch (aParams.type()) {
case LSRequestParams::TLSRequestPrepareDatastoreParams: {
bool isOtherProcess =
BackgroundParent::IsOtherProcessActor(aBackgroundActor);
const LSRequestPrepareDatastoreParams& params =
aParams.get_LSRequestPrepareDatastoreParams();
const PrincipalOrQuotaInfo& info = params.info();
PrincipalOrQuotaInfo::Type infoType = info.type();
bool paramsOk =
(isOtherProcess && infoType == PrincipalOrQuotaInfo::TPrincipalInfo) ||
(!isOtherProcess && infoType == PrincipalOrQuotaInfo::TQuotaInfo);
if (NS_WARN_IF(!paramsOk)) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
actor = new PrepareDatastoreOp(aParams);
break;
}
default:
MOZ_CRASH("Should never get here!");
}
// Transfer ownership to IPDL.
return actor.forget().take();
}
bool
RecvPBackgroundLSRequestConstructor(PBackgroundLSRequestParent* aActor,
const LSRequestParams& aParams)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != LSRequestParams::T__None);
// The actor is now completely built.
auto* op = static_cast<LSRequestBase*>(aActor);
op->Dispatch();
return true;
}
bool
DeallocPBackgroundLSRequestParent(PBackgroundLSRequestParent* aActor)
{
AssertIsOnBackgroundThread();
// Transfer ownership back from IPDL.
RefPtr<LSRequestBase> actor =
dont_AddRef(static_cast<LSRequestBase*>(aActor));
return true;
}
/*******************************************************************************
* DatastoreOperationBase
******************************************************************************/
/*******************************************************************************
* Datastore
******************************************************************************/
Datastore::Datastore(const nsACString& aOrigin)
: mOrigin(aOrigin)
{
AssertIsOnBackgroundThread();
}
Datastore::~Datastore()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(gDatastores);
MOZ_ASSERT(gDatastores->Get(mOrigin));
gDatastores->Remove(mOrigin);
if (!gDatastores->Count()) {
gDatastores = nullptr;
}
}
uint32_t
Datastore::GetLength() const
{
AssertIsOnBackgroundThread();
return mValues.Count();
}
void
Datastore::GetKey(uint32_t aIndex, nsString& aKey) const
{
AssertIsOnBackgroundThread();
aKey.SetIsVoid(true);
for (auto iter = mValues.ConstIter(); !iter.Done(); iter.Next()) {
if (aIndex == 0) {
aKey = iter.Key();
return;
}
aIndex--;
}
}
void
Datastore::GetItem(const nsString& aKey, nsString& aValue) const
{
AssertIsOnBackgroundThread();
if (!mValues.Get(aKey, &aValue)) {
aValue.SetIsVoid(true);
}
}
void
Datastore::SetItem(const nsString& aKey, const nsString& aValue)
{
AssertIsOnBackgroundThread();
mValues.Put(aKey, aValue);
}
void
Datastore::RemoveItem(const nsString& aKey)
{
AssertIsOnBackgroundThread();
mValues.Remove(aKey);
}
void
Datastore::Clear()
{
AssertIsOnBackgroundThread();
mValues.Clear();
}
void
Datastore::GetKeys(nsTArray<nsString>& aKeys) const
{
AssertIsOnBackgroundThread();
for (auto iter = mValues.ConstIter(); !iter.Done(); iter.Next()) {
aKeys.AppendElement(iter.Key());
}
}
/*******************************************************************************
* Database
******************************************************************************/
Database::Database()
#ifdef DEBUG
: mActorDestroyed(false)
, mActorWasAlive(false)
#endif
{
AssertIsOnBackgroundThread();
}
Database::~Database()
{
MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
}
void
Database::SetActorAlive(already_AddRefed<Datastore>&& aDatastore)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorWasAlive);
MOZ_ASSERT(!mActorDestroyed);
#ifdef DEBUG
mActorWasAlive = true;
#endif
mDatastore = std::move(aDatastore);
if (!gLiveDatabases) {
gLiveDatabases = new LiveDatabaseArray();
}
gLiveDatabases->AppendElement(this);
}
void
Database::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
MOZ_ASSERT(mDatastore);
#ifdef DEBUG
mActorDestroyed = true;
#endif
mDatastore = nullptr;
MOZ_ASSERT(gLiveDatabases);
gLiveDatabases->RemoveElement(this);
if (gLiveDatabases->IsEmpty()) {
gLiveDatabases = nullptr;
}
}
mozilla::ipc::IPCResult
Database::RecvDeleteMe()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundLSDatabaseParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvGetLength(uint32_t* aLength)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aLength);
MOZ_ASSERT(mDatastore);
*aLength = mDatastore->GetLength();
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvGetKey(const uint32_t& aIndex, nsString* aKey)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aKey);
MOZ_ASSERT(mDatastore);
mDatastore->GetKey(aIndex, *aKey);
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvGetItem(const nsString& aKey, nsString* aValue)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aValue);
MOZ_ASSERT(mDatastore);
mDatastore->GetItem(aKey, *aValue);
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvSetItem(const nsString& aKey, const nsString& aValue)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatastore);
mDatastore->SetItem(aKey, aValue);
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvRemoveItem(const nsString& aKey)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatastore);
mDatastore->RemoveItem(aKey);
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvClear()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatastore);
mDatastore->Clear();
return IPC_OK();
}
mozilla::ipc::IPCResult
Database::RecvGetKeys(nsTArray<nsString>* aKeys)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aKeys);
MOZ_ASSERT(mDatastore);
mDatastore->GetKeys(*aKeys);
return IPC_OK();
}
/*******************************************************************************
* LSRequestBase
******************************************************************************/
void
LSRequestBase::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnOwningThread();
NoteComplete();
}
mozilla::ipc::IPCResult
LSRequestBase::RecvCancel()
{
AssertIsOnOwningThread();
IProtocol* mgr = Manager();
if (!PBackgroundLSRequestParent::Send__delete__(this, NS_ERROR_FAILURE)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
/*******************************************************************************
* PrepareDatastoreOp
******************************************************************************/
PrepareDatastoreOp::PrepareDatastoreOp(const LSRequestParams& aParams)
: mParams(aParams.get_LSRequestPrepareDatastoreParams())
, mState(State::Initial)
{
MOZ_ASSERT(aParams.type() ==
LSRequestParams::TLSRequestPrepareDatastoreParams);
}
PrepareDatastoreOp::~PrepareDatastoreOp()
{
MOZ_ASSERT_IF(MayProceedOnNonOwningThread(),
mState == State::Initial || mState == State::Completed);
}
void
PrepareDatastoreOp::Dispatch()
{
AssertIsOnOwningThread();
const PrincipalOrQuotaInfo& info = mParams.info();
if (info.type() == PrincipalOrQuotaInfo::TPrincipalInfo) {
mState = State::OpeningOnMainThread;
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
} else {
MOZ_ASSERT(info.type() == PrincipalOrQuotaInfo::TQuotaInfo);
mState = State::OpeningOnOwningThread;
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
}
}
nsresult
PrepareDatastoreOp::OpenOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == State::OpeningOnMainThread);
if (!MayProceedOnNonOwningThread()) {
return NS_ERROR_FAILURE;
}
const PrincipalOrQuotaInfo& info = mParams.info();
MOZ_ASSERT(info.type() == PrincipalOrQuotaInfo::TPrincipalInfo);
const PrincipalInfo& principalInfo = info.get_PrincipalInfo();
if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin);
} else {
MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
nsresult rv;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(principalInfo, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = QuotaManager::GetInfoFromPrincipal(principal,
&mSuffix,
&mGroup,
&mOrigin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
mState = State::SendingReadyMessage;
MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_OK;
}
nsresult
PrepareDatastoreOp::OpenOnOwningThread()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::OpeningOnOwningThread);
if (!MayProceed()) {
return NS_ERROR_FAILURE;
}
const PrincipalOrQuotaInfo& info = mParams.info();
MOZ_ASSERT(info.type() == PrincipalOrQuotaInfo::TQuotaInfo);
const QuotaInfo& quotaInfo = info.get_QuotaInfo();
mSuffix = quotaInfo.suffix();
mGroup = quotaInfo.group();
mOrigin = quotaInfo.origin();
mState = State::SendingReadyMessage;
MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_OK;
}
void
PrepareDatastoreOp::SendReadyMessage()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::SendingReadyMessage);
if (!MayProceed()) {
MaybeSetFailureCode(NS_ERROR_FAILURE);
mState = State::Completed;
} else {
Unused << SendReady();
mState = State::WaitingForFinish;
}
}
void
PrepareDatastoreOp::SendResults()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::SendingResults);
if (!MayProceed()) {
MaybeSetFailureCode(NS_ERROR_FAILURE);
} else {
LSRequestResponse response;
if (NS_SUCCEEDED(ResultCode())) {
RefPtr<Datastore> datastore;
if (gDatastores) {
datastore = gDatastores->Get(mOrigin);
}
if (!datastore) {
datastore = new Datastore(mOrigin);
if (!gDatastores) {
gDatastores = new DatastoreHashtable();
}
gDatastores->Put(mOrigin, datastore);
}
uint64_t datastoreId = ++gLastDatastoreId;
if (!gTemporaryStrongDatastores) {
gTemporaryStrongDatastores = new TemporaryStrongDatastoreHashtable();
}
gTemporaryStrongDatastores->Put(datastoreId, datastore);
LSRequestPrepareDatastoreResponse prepareDatastoreResponse;
prepareDatastoreResponse.datastoreId() = datastoreId;
response = prepareDatastoreResponse;
} else {
response = ResultCode();
}
Unused <<
PBackgroundLSRequestParent::Send__delete__(this, response);
}
mState = State::Completed;
}
NS_IMETHODIMP
PrepareDatastoreOp::Run()
{
nsresult rv;
switch (mState) {
case State::OpeningOnMainThread:
rv = OpenOnMainThread();
break;
case State::OpeningOnOwningThread:
rv = OpenOnOwningThread();
break;
case State::SendingReadyMessage:
SendReadyMessage();
return NS_OK;
case State::SendingResults:
SendResults();
return NS_OK;
default:
MOZ_CRASH("Bad state!");
}
if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::SendingReadyMessage) {
MaybeSetFailureCode(rv);
// Must set mState before dispatching otherwise we will race with the owning
// thread.
mState = State::SendingReadyMessage;
if (IsOnOwningThread()) {
SendReadyMessage();
} else {
MOZ_ALWAYS_SUCCEEDS(
OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL));
}
}
return NS_OK;
}
mozilla::ipc::IPCResult
PrepareDatastoreOp::RecvFinish()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::WaitingForFinish);
mState = State::SendingResults;
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
return IPC_OK();
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,49 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_ActorsParent_h
#define mozilla_dom_localstorage_ActorsParent_h
namespace mozilla {
namespace ipc {
class PBackgroundParent;
} // namespace ipc
namespace dom {
class LSRequestParams;
class PBackgroundLSDatabaseParent;
class PBackgroundLSRequestParent;
PBackgroundLSDatabaseParent*
AllocPBackgroundLSDatabaseParent(const uint64_t& aDatastoreId);
bool
RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
const uint64_t& aDatastoreId);
bool
DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor);
PBackgroundLSRequestParent*
AllocPBackgroundLSRequestParent(
mozilla::ipc::PBackgroundParent* aBackgroundActor,
const LSRequestParams& aParams);
bool
RecvPBackgroundLSRequestConstructor(PBackgroundLSRequestParent* aActor,
const LSRequestParams& aParams);
bool
DeallocPBackgroundLSRequestParent(PBackgroundLSRequestParent* aActor);
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_ActorsParent_h

View File

@ -0,0 +1,141 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 "LSDatabase.h"
namespace mozilla {
namespace dom {
LSDatabase::LSDatabase()
: mActor(nullptr)
{
AssertIsOnOwningThread();
}
LSDatabase::~LSDatabase()
{
AssertIsOnOwningThread();
if (mActor) {
mActor->SendDeleteMeInternal();
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
}
}
void
LSDatabase::SetActor(LSDatabaseChild* aActor)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!mActor);
mActor = aActor;
}
nsresult
LSDatabase::GetLength(uint32_t* aResult)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
uint32_t result;
if (NS_WARN_IF(!mActor->SendGetLength(&result))) {
return NS_ERROR_FAILURE;
}
*aResult = result;
return NS_OK;
}
nsresult
LSDatabase::GetKey(uint32_t aIndex,
nsAString& aResult)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
nsString result;
if (NS_WARN_IF(!mActor->SendGetKey(aIndex, &result))) {
return NS_ERROR_FAILURE;
}
aResult = result;
return NS_OK;
}
nsresult
LSDatabase::GetItem(const nsAString& aKey,
nsAString& aResult)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
nsString result;
if (NS_WARN_IF(!mActor->SendGetItem(nsString(aKey), &result))) {
return NS_ERROR_FAILURE;
}
aResult = result;
return NS_OK;
}
nsresult
LSDatabase::GetKeys(nsTArray<nsString>& aKeys)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
nsTArray<nsString> result;
if (NS_WARN_IF(!mActor->SendGetKeys(&result))) {
return NS_ERROR_FAILURE;
}
aKeys.SwapElements(result);
return NS_OK;
}
nsresult
LSDatabase::SetItem(const nsAString& aKey,
const nsAString& aValue)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor->SendSetItem(nsString(aKey), nsString(aValue)))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
LSDatabase::RemoveItem(const nsAString& aKey)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor->SendRemoveItem(nsString(aKey)))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
LSDatabase::Clear()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
if (NS_WARN_IF(!mActor->SendClear())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,73 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_LSDatabase_h
#define mozilla_dom_localstorage_LSDatabase_h
namespace mozilla {
namespace dom {
class LSDatabaseChild;
class LSDatabase final
{
LSDatabaseChild* mActor;
public:
LSDatabase();
NS_INLINE_DECL_REFCOUNTING(LSDatabase)
void
AssertIsOnOwningThread() const
{
NS_ASSERT_OWNINGTHREAD(LSDatabase);
}
void
SetActor(LSDatabaseChild* aActor);
void
ClearActor()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mActor);
mActor = nullptr;
}
nsresult
GetLength(uint32_t* aResult);
nsresult
GetKey(uint32_t aIndex,
nsAString& aResult);
nsresult
GetItem(const nsAString& aKey,
nsAString& aResult);
nsresult
GetKeys(nsTArray<nsString>& aKeys);
nsresult
SetItem(const nsAString& aKey,
const nsAString& aValue);
nsresult
RemoveItem(const nsAString& aKey);
nsresult
Clear();
private:
~LSDatabase();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LSDatabase_h

View File

@ -0,0 +1,629 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 "LSObject.h"
#include "ActorsChild.h"
#include "IPCBlobInputStreamThread.h"
#include "LocalStorageCommon.h"
#include "mozilla/ThreadEventQueue.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "nsContentUtils.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsThread.h"
namespace mozilla {
namespace dom {
namespace {
class RequestHelper;
StaticMutex gRequestHelperMutex;
RequestHelper* gRequestHelper = nullptr;
class RequestHelper final
: public Runnable
, public LSRequestChildCallback
{
enum class State
{
Initial,
ResponsePending,
Finishing,
Complete
};
RefPtr<LSObject> mObject;
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
nsCOMPtr<nsIEventTarget> mNestedEventTarget;
LSRequestChild* mActor;
const LSRequestParams mParams;
LSRequestResponse mResponse;
nsresult mResultCode;
State mState;
bool mWaiting;
public:
RequestHelper(LSObject* aObject,
const LSRequestParams& aParams)
: Runnable("dom::RequestHelper")
, mObject(aObject)
, mOwningEventTarget(GetCurrentThreadEventTarget())
, mActor(nullptr)
, mParams(aParams)
, mResultCode(NS_OK)
, mState(State::Initial)
, mWaiting(true)
{
StaticMutexAutoLock lock(gRequestHelperMutex);
gRequestHelper = this;
}
bool
IsOnOwningThread() const
{
MOZ_ASSERT(mOwningEventTarget);
bool current;
return
NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)) && current;
}
void
AssertIsOnOwningThread() const
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsOnOwningThread());
}
nsresult
StartAndReturnResponse(LSRequestResponse& aResponse);
nsresult
CancelOnAnyThread();
private:
~RequestHelper()
{
StaticMutexAutoLock lock(gRequestHelperMutex);
gRequestHelper = nullptr;
}
nsresult
Start();
void
Finish();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
// LSRequestChildCallback
void
OnResponse(const LSRequestResponse& aResponse) override;
};
} // namespace
LSObject::LSObject(nsPIDOMWindowInner* aWindow,
nsIPrincipal* aPrincipal)
: Storage(aWindow, aPrincipal)
{
AssertIsOnOwningThread();
MOZ_ASSERT(NextGenLocalStorageEnabled());
}
LSObject::~LSObject()
{
AssertIsOnOwningThread();
}
// static
nsresult
LSObject::Create(nsPIDOMWindowInner* aWindow,
Storage** aStorage)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aStorage);
MOZ_ASSERT(NextGenLocalStorageEnabled());
MOZ_ASSERT(nsContentUtils::StorageAllowedForWindow(aWindow) >
nsContentUtils::StorageAccess::eDeny);
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
MOZ_ASSERT(sop);
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
if (NS_WARN_IF(!principal)) {
return NS_ERROR_FAILURE;
}
nsresult rv;
nsAutoPtr<PrincipalOrQuotaInfo> info(new PrincipalOrQuotaInfo());
if (XRE_IsParentProcess()) {
nsCString suffix;
nsCString group;
nsCString origin;
rv = QuotaManager::GetInfoFromPrincipal(principal,
&suffix,
&group,
&origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
QuotaInfo quotaInfo;
quotaInfo.suffix() = suffix;
quotaInfo.group() = group;
quotaInfo.origin() = origin;
*info = quotaInfo;
} else {
PrincipalInfo principalInfo;
rv = PrincipalToPrincipalInfo(principal, &principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
*info = principalInfo;
}
RefPtr<LSObject> object = new LSObject(aWindow, principal);
object->mInfo = std::move(info);
object.forget(aStorage);
return NS_OK;
}
// static
void
LSObject::CancelSyncLoop()
{
RefPtr<RequestHelper> helper;
{
StaticMutexAutoLock lock(gRequestHelperMutex);
helper = gRequestHelper;
}
if (helper) {
Unused << NS_WARN_IF(NS_FAILED(helper->CancelOnAnyThread()));
}
}
LSRequestChild*
LSObject::StartRequest(nsIEventTarget* aMainEventTarget,
const LSRequestParams& aParams,
LSRequestChildCallback* aCallback)
{
AssertIsOnDOMFileThread();
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForCurrentThread(aMainEventTarget);
if (NS_WARN_IF(!backgroundActor)) {
return nullptr;
}
LSRequestChild* actor = new LSRequestChild(aCallback);
backgroundActor->SendPBackgroundLSRequestConstructor(actor, aParams);
return actor;
}
Storage::StorageType
LSObject::Type() const
{
AssertIsOnOwningThread();
return eLocalStorage;
}
bool
LSObject::IsForkOf(const Storage* aStorage) const
{
AssertIsOnOwningThread();
return false;
}
int64_t
LSObject::GetOriginQuotaUsage() const
{
AssertIsOnOwningThread();
return 0;
}
uint32_t
LSObject::GetLength(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return 0;
}
uint32_t result;
rv = mDatabase->GetLength(&result);
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return 0;
}
return result;
}
void
LSObject::Key(uint32_t aIndex,
nsAString& aResult,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
nsString result;
rv = mDatabase->GetKey(aIndex, result);
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
aResult = result;
}
void
LSObject::GetItem(const nsAString& aKey,
nsAString& aResult,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
nsString result;
rv = mDatabase->GetItem(aKey, result);
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
aResult = result;
}
void
LSObject::GetSupportedNames(nsTArray<nsString>& aNames)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
rv = mDatabase->GetKeys(aNames);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
void
LSObject::SetItem(const nsAString& aKey,
const nsAString& aValue,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
rv = mDatabase->SetItem(aKey, aValue);
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
}
void
LSObject::RemoveItem(const nsAString& aKey,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
rv = mDatabase->RemoveItem(aKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
}
void
LSObject::Clear(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError)
{
AssertIsOnOwningThread();
nsresult rv = EnsureDatabase();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
rv = mDatabase->Clear();
if (NS_WARN_IF(NS_FAILED(rv))) {
aError.Throw(rv);
return;
}
}
nsresult
LSObject::EnsureDatabase()
{
AssertIsOnOwningThread();
if (mDatabase) {
return NS_OK;
}
// We don't need this yet, but once the request successfully finishes, it's
// too late to initialize PBackground child on the owning thread, because
// it can fail and parent would keep an extra strong ref to the datastore.
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!backgroundActor)) {
return NS_ERROR_FAILURE;
}
LSRequestPrepareDatastoreParams params;
params.info() = *mInfo;
RefPtr<RequestHelper> helper = new RequestHelper(this, params);
LSRequestResponse response;
// This will start and finish the request on the DOM File thread.
// The owning thread is synchronously blocked while the request is
// asynchronously processed on the DOM File thread.
nsresult rv = helper->StartAndReturnResponse(response);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (response.type() == LSRequestResponse::Tnsresult) {
return response.get_nsresult();
}
MOZ_ASSERT(response.type() ==
LSRequestResponse::TLSRequestPrepareDatastoreResponse);
const LSRequestPrepareDatastoreResponse& prepareDatastoreResponse =
response.get_LSRequestPrepareDatastoreResponse();
uint64_t datastoreId = prepareDatastoreResponse.datastoreId();
// The datastore is now ready on the parent side (prepared by the asynchronous
// request on the DOM File thread).
// Let's create a direct connection to the datastore (through a database
// actor) from the owning thread.
// Note that we now can't error out, otherwise parent will keep an extra
// strong reference to the datastore.
RefPtr<LSDatabase> database = new LSDatabase();
LSDatabaseChild* actor = new LSDatabaseChild(database);
MOZ_ALWAYS_TRUE(
backgroundActor->SendPBackgroundLSDatabaseConstructor(actor, datastoreId));
database->SetActor(actor);
mDatabase = std::move(database);
return NS_OK;
}
nsresult
RequestHelper::StartAndReturnResponse(LSRequestResponse& aResponse)
{
AssertIsOnOwningThread();
// Normally, we would use the standard way of blocking the thread using
// a monitor.
// The problem is that BackgroundChild::GetOrCreateForCurrentThread()
// called on the DOM File thread may dispatch a runnable to the main
// thread to finish initialization of PBackground. A monitor would block
// the main thread and the runnable would never get executed causing the
// helper to be stuck in a wait loop.
// However, BackgroundChild::GetOrCreateForCurrentThread() supports passing
// a custom main event target, so we can create a nested event target and
// spin the event loop. Nothing can dispatch to the nested event target
// except BackgroundChild::GetOrCreateForCurrentThread(), so spinning of the
// event loop can't fire any other events.
// This way the thread is synchronously blocked in a safe manner and the
// runnable gets executed.
{
auto thread = static_cast<nsThread*>(NS_GetCurrentThread());
auto queue =
static_cast<ThreadEventQueue<EventQueue>*>(thread->EventQueue());
mNestedEventTarget = queue->PushEventQueue();
MOZ_ASSERT(mNestedEventTarget);
auto autoPopEventQueue = mozilla::MakeScopeExit([&] {
queue->PopEventQueue(mNestedEventTarget);
});
nsCOMPtr<nsIEventTarget> domFileThread =
IPCBlobInputStreamThread::GetOrCreate();
if (NS_WARN_IF(!domFileThread)) {
return NS_ERROR_FAILURE;
}
nsresult rv = domFileThread->Dispatch(this, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() {
return !mWaiting;
}));
}
if (NS_WARN_IF(NS_FAILED(mResultCode))) {
return mResultCode;
}
aResponse = std::move(mResponse);
return NS_OK;
}
nsresult
RequestHelper::CancelOnAnyThread()
{
RefPtr<RequestHelper> self = this;
RefPtr<Runnable> runnable = NS_NewRunnableFunction(
"RequestHelper::CancelOnAnyThread",
[self] () {
LSRequestChild* actor = self->mActor;
if (actor && !actor->Finishing()) {
actor->SendCancel();
}
});
nsCOMPtr<nsIEventTarget> domFileThread =
IPCBlobInputStreamThread::GetOrCreate();
if (NS_WARN_IF(!domFileThread)) {
return NS_ERROR_FAILURE;
}
nsresult rv = domFileThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
RequestHelper::Start()
{
AssertIsOnDOMFileThread();
MOZ_ASSERT(mState == State::Initial);
mState = State::ResponsePending;
LSRequestChild* actor =
mObject->StartRequest(mNestedEventTarget, mParams, this);
if (NS_WARN_IF(!actor)) {
return NS_ERROR_FAILURE;
}
mActor = actor;
return NS_OK;
}
void
RequestHelper::Finish()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::Finishing);
mObject = nullptr;
mWaiting = false;
mState = State::Complete;
}
NS_IMPL_ISUPPORTS_INHERITED0(RequestHelper, Runnable)
NS_IMETHODIMP
RequestHelper::Run()
{
nsresult rv;
switch (mState) {
case State::Initial:
rv = Start();
break;
case State::Finishing:
Finish();
return NS_OK;
default:
MOZ_CRASH("Bad state!");
}
if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = rv;
}
mState = State::Finishing;
if (IsOnOwningThread()) {
Finish();
} else {
MOZ_ALWAYS_SUCCEEDS(mNestedEventTarget->Dispatch(this,
NS_DISPATCH_NORMAL));
}
}
return NS_OK;
}
void
RequestHelper::OnResponse(const LSRequestResponse& aResponse)
{
AssertIsOnDOMFileThread();
MOZ_ASSERT(mState == State::ResponsePending);
mActor = nullptr;
mResponse = aResponse;
mState = State::Finishing;
MOZ_ALWAYS_SUCCEEDS(mNestedEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
}
} // namespace dom
} // namespace mozilla

110
dom/localstorage/LSObject.h Normal file
View File

@ -0,0 +1,110 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_LSObject_h
#define mozilla_dom_localstorage_LSObject_h
#include "mozilla/dom/Storage.h"
class nsIPrincipal;
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
namespace dom {
class LSDatabase;
class LSRequestChild;
class LSRequestChildCallback;
class LSRequestParams;
class PrincipalOrQuotaInfo;
class LSObject final
: public Storage
{
nsAutoPtr<PrincipalOrQuotaInfo> mInfo;
RefPtr<LSDatabase> mDatabase;
public:
static nsresult
Create(nsPIDOMWindowInner* aWindow,
Storage** aStorage);
static void
CancelSyncLoop();
void
AssertIsOnOwningThread() const
{
NS_ASSERT_OWNINGTHREAD(LSObject);
}
LSRequestChild*
StartRequest(nsIEventTarget* aMainEventTarget,
const LSRequestParams& aParams,
LSRequestChildCallback* aCallback);
// Storage overrides.
StorageType
Type() const override;
bool
IsForkOf(const Storage* aStorage) const override;
int64_t
GetOriginQuotaUsage() const override;
uint32_t
GetLength(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void
Key(uint32_t aIndex,
nsAString& aResult,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void
GetItem(const nsAString& aKey,
nsAString& aResult,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void
GetSupportedNames(nsTArray<nsString>& aNames) override;
void
SetItem(const nsAString& aKey,
const nsAString& aValue,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void
RemoveItem(const nsAString& aKey,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
void
Clear(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) override;
private:
LSObject(nsPIDOMWindowInner* aWindow,
nsIPrincipal* aPrincipal);
~LSObject();
nsresult
EnsureDatabase();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LSObject_h

View File

@ -0,0 +1,32 @@
/* -*- 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 "LocalStorageCommon.h"
namespace mozilla {
namespace dom {
namespace {
int32_t gNextGenLocalStorageEnabled = -1;
} // namespace
bool
NextGenLocalStorageEnabled()
{
MOZ_ASSERT(NS_IsMainThread());
if (gNextGenLocalStorageEnabled == -1) {
bool enabled = Preferences::GetBool("dom.storage.next_gen", false);
gNextGenLocalStorageEnabled = enabled ? 1 : 0;
}
return !!gNextGenLocalStorageEnabled;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,193 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_LocalStorageCommon_h
#define mozilla_dom_localstorage_LocalStorageCommon_h
/*
* Local storage
* ~~~~~~~~~~~~~
*
* Implementation overview
* ~~~~~~~~~~~~~~~~~~~~~~~
*
* The implementation is based on a per principal/origin cache (datastore)
* living in the main process and synchronous calls initiated from content
* processes.
* The IPC communication is managed by database actors which link to the
* datastore.
* The synchronous blocking of the main thread is done by using a special
* technique or by using standard synchronous IPC calls.
*
* General architecture
* ~~~~~~~~~~~~~~~~~~~~
* The current browser architecture consists of one main process and multiple
* content processes (there are other processes but for simplicity's sake, they
* are not mentioned here). The processes use the IPC communication to talk to
* each other. Local storage implementation uses the client-server model, so
* the main process manages all the data and content processes then request
* particular data from the main process. The main process is also called the
* parent or the parent side, the content process is then called the child or
* the child side.
*
* Datastores
* ~~~~~~~~~~
*
* A datastore provides a convenient way to access data for given origin. The
* data is always preloaded into memory and indexed using a hash table. This
* enables very fast access to particular stored items. There can be only one
* datastore per origin and exists solely on the parent side. It is represented
* by the "Datastore" class. A datastore instance is a ref counted object and
* lives on the PBackground thread, it is kept alive by database objects. When
* the last database object for given origin is destroyed, the associated
* datastore object is destroyed too.
*
* Databases
* ~~~~~~~~~
*
* A database allows direct access to a datastore from a content process. There
* can be multiple databases for the same origin, but they all share the same
* datastore.
* Databases use the PBackgroundLSDatabase IPDL protocol for IPC communication.
* Given the nature of local storage, most of PBackgroundLSDatabase messages
* are synchronous.
*
* On the parent side, the database is represented by the "Database" class that
* is a parent actor as well (implements the "PBackgroundLSDatabaseParent"
* interface). A database instance is a ref counted object and lives on the
* PBackground thread.
* All live database actors are tracked in an array.
*
* On the child side, the database is represented by the "LSDatabase" class
* that provides indirect access to a child actor. An LSDatabase instance is a
* ref counted object and lives on the main thread.
* The actual child actor is represented by the "LSDatabaseChild" class that
* implements the "PBackgroundLSDatabaseChild" interface. An "LSDatabaseChild"
* instance is not ref counted and lives on the main thread too.
*
* Synchronous blocking
* ~~~~~~~~~~~~~~~~~~~~
*
* Local storage is synchronous in nature which means the execution can't move
* forward until there's a reply for given method call.
* Since we have to use IPC anyway, we could just always use synchronous IPC
* messages for all local storage method calls. Well, there's a problem with
* that approach.
* If the main process needs to do some off PBackground thread stuff like
* getting info from principals on the main thread or some asynchronous stuff
* like directory locking before sending a reply to a synchronous message, then
* we would have to block the thread or spin the event loop which is usually a
* bad idea, especially in the main process.
* Instead, we can use a special thread in the content process called DOM File
* thread for communication with the main process using asynchronous messages
* and synchronously block the main thread until the DOM File thread is done
* (the main thread blocking is a bit more complicated, see the comment in
* RequestHelper::StartAndReturnResponse for more details).
* Anyway, the extra hop to the DOM File thread brings another overhead and
* latency. The final solution is to use a combination of the special thread
* for complex stuff like datastore preparation and synchronous IPC messages
* sent directly from the main thread for database access when data is already
* loaded from disk into memory.
*
* Requests
* ~~~~~~~~
*
* Requests are used to handle asynchronous high level datastore operations
* which are initiated in a content process and then processed in the parent
* process (for example, preparation of a datastore).
* Requests use the "PBackgroundLSRequest" IPDL protocol for IPC communication.
*
* On the parent side, the request is represented by the "LSRequestBase" class
* that is a parent actor as well (implements the "PBackgroundLSRequestParent"
* interface). It's an abstract class (contains pure virtual functions) so it
* can't be used to create instances.
* It also inherits from the "DatastoreOperationBase" class which is a generic
* base class for all datastore operations. The "DatastoreOperationsBase" class
* inherits from the "Runnable" class, so derived class instances are ref
* counted, can be dispatched to multiple threads and thus they are used on
* multiple threads. However, derived class instances can be created on the
* PBackground thread only.
*
* On the child side, the request is represented by the "RequestHelper" class
* that covers all the complexity needed to start a new request, handle
* responses and do safe main thread blocking at the same time.
* It inherits from the "Runnable" class, so instances are ref counted and
* they are internally used on multiple threads (specifically on the main
* thread and on the DOM File thread). Anyway, users should create and use
* instances of this class only on the main thread (apart from a special case
* when we need to cancel the request from an internal chromium IPC thread to
* prevent a dead lock involving CPOWs).
* The actual child actor is represented by the "LSRequestChild" class that
* implements the "PBackgroundLSRequestChild" interface. An "LSRequestChild"
* instance is not ref counted and lives on the DOM File thread.
* Request responses are passed using the "LSRequestChildCallback" interface.
*
* Preparation of a datastore
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* The datastore preparation is needed to make sure a datastore is fully loaded
* into memory. Every datastore preparation produces a unique id (even if the
* datastore for given origin already exists).
* On the parent side, the preparation is handled by the "PrepareDatastoreOp"
* class which inherits from the "LSRequestBase" class. The preparation process
* on the parent side is quite complicated, it happens sequentially on multiple
* threads and is managed by a state machine.
* On the child side, the preparation is done in the LSObject::EnsureDatabase
* method using the "RequestHelper" class. The method starts a new preparation
* request and obtains a unique id produced by the parent (or an error code if
* the requested failed to complete).
*
* Linking databases to a datastore
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* A datastore exists only on the parent side, but it can be accessed from the
* content via database actors. Database actors are initiated on the child side
* and they need to be linked to a datastore on the parent side via an id. The
* datastore preparation process gives us the required id.
* The linking is initiated on the child side in the LSObject::EnsureDatabase
* method by calling SendPBackgroundLSDatabaseConstructor and finished in
* RecvPBackgroundLSDatabaseConstructor on the parent side.
*
* Actor migration
* ~~~~~~~~~~~~~~~
*
* In theory, the datastore preparation request could return a database actor
* directly (instead of returning an id intended for database linking to a
* datastore). However, as it was explained above, the preparation must be done
* on the DOM File thread and database objects are used on the main thread. The
* returned actor would have to be migrated from the DOM File thread to the
* main thread and that's something which our IPDL doesn't support yet.
*
* Exposing local storage
* ~~~~~~~~~~~~~~~~~~~~~~
*
* The implementation is exposed to the DOM via window.localStorage attribute.
* Local storage's sibling, session storage shares the same WebIDL interface
* for exposing it to web content, therefore there's an abstract class called
* "Storage" that handles some of the common DOM bindings stuff. Local storage
* specific functionality is defined in the "LSObject" derived class.
* The "LSObject" class is also a starting point for the datastore preparation
* and database linking.
*
* Local storage manager
* ~~~~~~~~~~~~~~~~~~~~~
*
* The local storage manager exposes some of the features that need to be
* available only in the chrome code or tests. The manager is represented by
* the "LocalStorageManager2" class that implements the "nsIDOMStorageManager"
* interface.
*/
namespace mozilla {
namespace dom {
bool
NextGenLocalStorageEnabled();
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LocalStorageCommon_h

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 "LocalStorageManager2.h"
#include "LSObject.h"
namespace mozilla {
namespace dom {
LocalStorageManager2::LocalStorageManager2()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(NextGenLocalStorageEnabled());
}
LocalStorageManager2::~LocalStorageManager2()
{
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMPL_ISUPPORTS(LocalStorageManager2, nsIDOMStorageManager)
NS_IMETHODIMP
LocalStorageManager2::PrecacheStorage(nsIPrincipal* aPrincipal,
Storage** _retval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(_retval);
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LocalStorageManager2::CreateStorage(mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI,
bool aPrivate,
Storage** _retval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(_retval);
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LocalStorageManager2::GetStorage(mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
bool aPrivate,
Storage** _retval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(_retval);
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LocalStorageManager2::CloneStorage(Storage* aStorageToCloneFrom)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aStorageToCloneFrom);
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
LocalStorageManager2::CheckStorage(nsIPrincipal* aPrincipal,
Storage *aStorage,
bool* _retval)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aStorage);
MOZ_ASSERT(_retval);
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,31 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_LocalStorageManager2_h
#define mozilla_dom_localstorage_LocalStorageManager2_h
#include "nsIDOMStorageManager.h"
namespace mozilla {
namespace dom {
class LocalStorageManager2 final
: public nsIDOMStorageManager
{
public:
LocalStorageManager2();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMSTORAGEMANAGER
private:
~LocalStorageManager2();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LocalStorageManager2_h

View File

@ -0,0 +1,49 @@
/* 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 protocol PBackground;
namespace mozilla {
namespace dom {
sync protocol PBackgroundLSDatabase
{
manager PBackground;
parent:
// The DeleteMe message is used to avoid a race condition between the parent
// actor and the child actor. The PBackgroundLSDatabase protocol could be
// simply destroyed by sending the __delete__ message from the child side.
// However, that would destroy the child actor immediatelly and the parent
// could be sending a message to the child at the same time resulting in a
// routing error since the child actor wouldn't exist anymore. A routing
// error typically causes a crash. The race can be prevented by doing the
// teardown in two steps. First, we send the DeleteMe message to the parent
// and the parent then sends the __delete__ message to the child.
async DeleteMe();
sync GetLength()
returns (uint32_t length);
sync GetKey(uint32_t index)
returns (nsString key);
sync GetItem(nsString key)
returns (nsString value);
sync GetKeys()
returns (nsString[] keys);
sync SetItem(nsString key, nsString value);
sync RemoveItem(nsString key);
sync Clear();
child:
async __delete__();
};
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,49 @@
/* 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 protocol PBackground;
namespace mozilla {
namespace dom {
struct LSRequestPrepareDatastoreResponse
{
uint64_t datastoreId;
};
union LSRequestResponse
{
nsresult;
LSRequestPrepareDatastoreResponse;
};
protocol PBackgroundLSRequest
{
manager PBackground;
parent:
// The Cancel message is used to avoid a possible dead lock caused by a CPOW
// sending a synchronous message from the main thread in the chrome process
// to the main thread in the content process at the time we are blocking
// the main thread in the content process to handle a request.
// We use the PBackground thread on the parent side to handle requests, but
// sometimes we need to get information from principals and that's currently
// only possible on the main thread. So if the main thread in the chrome
// process is blocked by a CPOW operation, our request must wait for the CPOW
// operation to complete. However the CPOW operation can't complete either
// because we are blocking the main thread in the content process.
// The dead lock is prevented by canceling our nested event loop in the
// content process when we receive a synchronous IPC message from the parent.
async Cancel();
async Finish();
child:
async __delete__(LSRequestResponse response);
async Ready();
};
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,32 @@
/* 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 PBackgroundSharedTypes;
namespace mozilla {
namespace dom {
struct QuotaInfo {
nsCString suffix;
nsCString group;
nsCString origin;
};
union PrincipalOrQuotaInfo {
PrincipalInfo;
QuotaInfo;
};
struct LSRequestPrepareDatastoreParams
{
PrincipalOrQuotaInfo info;
};
union LSRequestParams
{
LSRequestPrepareDatastoreParams;
};
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,41 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.dom.localstorage += [
'ActorsParent.h',
]
EXPORTS.mozilla.dom += [
'LocalStorageCommon.h',
'LocalStorageManager2.h',
'LSObject.h',
]
UNIFIED_SOURCES += [
'ActorsChild.cpp',
'ActorsParent.cpp',
'LocalStorageCommon.cpp',
'LocalStorageManager2.cpp',
'LSDatabase.cpp',
'LSObject.cpp',
]
IPDL_SOURCES += [
'PBackgroundLSDatabase.ipdl',
'PBackgroundLSRequest.ipdl',
'PBackgroundLSSharedTypes.ipdlh',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wno-error=shadow']
LOCAL_INCLUDES += [
'/dom/file/ipc',
]

View File

@ -103,6 +103,7 @@ DIRS += [
'serviceworkers',
'simpledb',
'reporting',
'localstorage',
]
if CONFIG['MOZ_LIBPRIO']:

View File

@ -21,6 +21,7 @@
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/LocalStorageCommon.h"
// Only allow relatively small amounts of data since performance of
// the synchronous IO is very bad.
@ -61,6 +62,8 @@ NS_IMPL_ISUPPORTS(LocalStorageManager,
LocalStorageManager::LocalStorageManager()
: mCaches(8)
{
MOZ_ASSERT(!NextGenLocalStorageEnabled());
StorageObserver* observer = StorageObserver::Self();
NS_ASSERTION(observer, "No StorageObserver, cannot observe private data delete notifications!");
@ -473,9 +476,20 @@ LocalStorageManager::Observe(const char* aTopic,
return NS_ERROR_UNEXPECTED;
}
// static
LocalStorageManager*
LocalStorageManager::Self()
{
MOZ_ASSERT(!NextGenLocalStorageEnabled());
return sSelf;
}
LocalStorageManager*
LocalStorageManager::Ensure()
{
MOZ_ASSERT(!NextGenLocalStorageEnabled());
if (sSelf) {
return sSelf;
}

View File

@ -117,7 +117,7 @@ private:
const nsACString& aKeyPrefix);
// Global getter of localStorage manager service
static LocalStorageManager* Self() { return sSelf; }
static LocalStorageManager* Self();
// Like Self, but creates an instance if we're not yet initialized.
static LocalStorageManager* Ensure();

View File

@ -147,6 +147,7 @@ StorageDBChild::StorageDBChild(LocalStorageManager* aManager)
, mStatus(NS_OK)
, mIPCOpen(false)
{
MOZ_ASSERT(!NextGenLocalStorageEnabled());
}
StorageDBChild::~StorageDBChild()
@ -158,6 +159,7 @@ StorageDBChild*
StorageDBChild::Get()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!NextGenLocalStorageEnabled());
return sStorageChild;
}
@ -167,6 +169,7 @@ StorageDBChild*
StorageDBChild::GetOrCreate()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!NextGenLocalStorageEnabled());
if (sStorageChild || sStorageChildDown) {
// When sStorageChildDown is at true, sStorageChild is null.

View File

@ -181,13 +181,15 @@ StorageObserver::ClearMatchingOrigin(const char16_t* aData,
return rv;
}
if (XRE_IsParentProcess()) {
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
if (NS_WARN_IF(!storageChild)) {
return NS_ERROR_FAILURE;
}
if (!NextGenLocalStorageEnabled()) {
if (XRE_IsParentProcess()) {
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
if (NS_WARN_IF(!storageChild)) {
return NS_ERROR_FAILURE;
}
storageChild->SendClearMatchingOrigin(originScope);
storageChild->SendClearMatchingOrigin(originScope);
}
}
aOriginScope = originScope;
@ -205,6 +207,10 @@ StorageObserver::Observe(nsISupports* aSubject,
if (!strcmp(aTopic, kStartupTopic)) {
MOZ_ASSERT(XRE_IsParentProcess());
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, kStartupTopic);
@ -215,6 +221,7 @@ StorageObserver::Observe(nsISupports* aSubject,
// Timer callback used to start the database a short timer after startup
if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(!NextGenLocalStorageEnabled());
nsCOMPtr<nsITimer> timer = do_QueryInterface(aSubject);
if (!timer) {
@ -241,15 +248,17 @@ StorageObserver::Observe(nsISupports* aSubject,
return NS_OK;
}
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
if (NS_WARN_IF(!storageChild)) {
return NS_ERROR_FAILURE;
}
if (!NextGenLocalStorageEnabled()) {
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
if (NS_WARN_IF(!storageChild)) {
return NS_ERROR_FAILURE;
}
storageChild->AsyncClearAll();
storageChild->AsyncClearAll();
if (XRE_IsParentProcess()) {
storageChild->SendClearAll();
if (XRE_IsParentProcess()) {
storageChild->SendClearAll();
}
}
Notify("cookie-cleared");
@ -311,6 +320,10 @@ StorageObserver::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, "extension:purge-localStorage")) {
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
const char topic[] = "extension:purge-localStorage-caches";
if (aData) {
@ -355,6 +368,10 @@ StorageObserver::Observe(nsISupports* aSubject,
// Clear all private-browsing caches
if (!strcmp(aTopic, "last-pb-context-exited")) {
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
Notify("private-browsing-data-cleared");
return NS_OK;
@ -364,6 +381,10 @@ StorageObserver::Observe(nsISupports* aSubject,
if (!strcmp(aTopic, "clear-origin-attributes-data")) {
MOZ_ASSERT(XRE_IsParentProcess());
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
OriginAttributesPattern pattern;
if (!pattern.Init(nsDependentString(aData))) {
NS_ERROR("Cannot parse origin attributes pattern");
@ -391,6 +412,10 @@ StorageObserver::Observe(nsISupports* aSubject,
if (!strcmp(aTopic, "profile-before-change")) {
MOZ_ASSERT(XRE_IsParentProcess());
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
if (mBackgroundThread) {
bool done = false;
@ -409,6 +434,10 @@ StorageObserver::Observe(nsISupports* aSubject,
#ifdef DOM_STORAGE_TESTS
if (!strcmp(aTopic, "domstorage-test-flush-force")) {
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
StorageDBChild* storageChild = StorageDBChild::GetOrCreate();
if (NS_WARN_IF(!storageChild)) {
return NS_ERROR_FAILURE;
@ -420,6 +449,10 @@ StorageObserver::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, "domstorage-test-flushed")) {
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
// Only used to propagate to IPC children
Notify("test-flushed");
@ -427,6 +460,10 @@ StorageObserver::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, "domstorage-test-reload")) {
if (NextGenLocalStorageEnabled()) {
return NS_OK;
}
Notify("test-reload");
return NS_OK;

View File

@ -53,8 +53,8 @@ run-if = e10s
skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s
[browser_largeAllocation_non_win32.js]
skip-if = !e10s || (os == "win" && processor == "x86") || (verify && debug && (os == 'linux')) || (os == 'linux') || (os == 'mac' && debug) # Large-Allocation requires e10s # Bug 1336075
[browser_localStorage_e10s.js]
skip-if = !e10s || verify # This is a test of e10s functionality.
#[browser_localStorage_e10s.js]
#skip-if = !e10s || verify # This is a test of e10s functionality.
[browser_localStorage_privatestorageevent.js]
[browser_persist_cookies.js]
support-files =

View File

@ -7,5 +7,5 @@ support-files =
[test_localStorageBasePrivateBrowsing_perwindowpb.html]
skip-if = true # bug 1156725
[test_localStorageFromChrome.xhtml]
[test_localStorageQuotaPrivateBrowsing_perwindowpb.html]
#[test_localStorageFromChrome.xhtml]
#[test_localStorageQuotaPrivateBrowsing_perwindowpb.html]

View File

@ -19,19 +19,19 @@ support-files =
file_tryAccessSessionStorage.html
[test_brokenUTF-16.html]
[test_bug600307-DBOps.html]
#[test_bug600307-DBOps.html]
[test_bug746272-1.html]
[test_bug746272-2.html]
skip-if = os == "android" || verify # bug 962029
[test_cookieBlock.html]
[test_cookieSession.html]
#[test_cookieSession.html]
[test_embededNulls.html]
[test_keySync.html]
[test_localStorageBase.html]
skip-if = e10s
[test_localStorageBaseSessionOnly.html]
#[test_localStorageBase.html]
#skip-if = e10s
#[test_localStorageBaseSessionOnly.html]
[test_localStorageCookieSettings.html]
[test_localStorageEnablePref.html]
#[test_localStorageEnablePref.html]
[test_localStorageKeyOrder.html]
[test_localStorageOriginsDiff.html]
[test_localStorageOriginsDomainDiffs.html]
@ -40,14 +40,14 @@ skip-if = toolkit == 'android'
[test_localStorageOriginsPortDiffs.html]
[test_localStorageOriginsSchemaDiffs.html]
skip-if = toolkit == 'android' #TIMED_OUT
[test_localStorageQuota.html]
skip-if = toolkit == 'android' #TIMED_OUT
[test_localStorageQuotaSessionOnly.html]
skip-if = toolkit == 'android' || (verify && (os == 'linux' || os == 'win')) #TIMED_OUT
#[test_localStorageQuota.html]
#skip-if = toolkit == 'android' #TIMED_OUT
#[test_localStorageQuotaSessionOnly.html]
#skip-if = toolkit == 'android' || (verify && (os == 'linux' || os == 'win')) #TIMED_OUT
[test_localStorageQuotaSessionOnly2.html]
skip-if = true # bug 1347690
[test_localStorageReplace.html]
skip-if = toolkit == 'android'
[test_storageConstructor.html]
[test_localStorageSessionPrefOverride.html]
#[test_localStorageSessionPrefOverride.html]
[test_firstPartyOnlyPermission.html]

View File

@ -11,7 +11,7 @@ support-files =
interOriginTest2.js
[test_storageLocalStorageEventCheckNoPropagation.html]
[test_storageLocalStorageEventCheckPropagation.html]
[test_storageNotifications.html]
#[test_storageLocalStorageEventCheckPropagation.html]
#[test_storageNotifications.html]
[test_storageSessionStorageEventCheckNoPropagation.html]
[test_storageSessionStorageEventCheckPropagation.html]

View File

@ -179,7 +179,7 @@ MOCHITEST_CHROME_MANIFESTS += [
'mochitest/general/chrome.ini',
'mochitest/geolocation/chrome.ini',
'mochitest/keyhandling/chrome.ini',
'mochitest/localstorage/chrome.ini',
# 'mochitest/localstorage/chrome.ini',
'mochitest/sessionstorage/chrome.ini',
'mochitest/webcomponents/chrome.ini',
'mochitest/whatwg/chrome.ini',

View File

@ -141,9 +141,9 @@ skip-if = os == 'android'
[test_bug645914.html]
[test_bug646194.html]
[test_bug668599.html]
[test_bug674770-1.html]
subsuite = clipboard
skip-if = toolkit == 'android' || verify
#[test_bug674770-1.html]
#subsuite = clipboard
#skip-if = toolkit == 'android' || verify
[test_bug674770-2.html]
subsuite = clipboard
skip-if = toolkit == 'android'

View File

@ -16,6 +16,8 @@
#include "mozilla/Assertions.h"
#include "mozilla/SchedulerGroup.h"
#include "mozilla/dom/ClientManagerActors.h"
#include "mozilla/dom/PBackgroundLSDatabaseChild.h"
#include "mozilla/dom/PBackgroundLSRequestChild.h"
#include "mozilla/dom/PBackgroundSDBConnectionChild.h"
#include "mozilla/dom/PFileSystemRequestChild.h"
#include "mozilla/dom/FileSystemTaskBase.h"
@ -223,6 +225,58 @@ BackgroundChildImpl::DeallocPBackgroundIndexedDBUtilsChild(
return true;
}
BackgroundChildImpl::PBackgroundSDBConnectionChild*
BackgroundChildImpl::AllocPBackgroundSDBConnectionChild(
const PrincipalInfo& aPrincipalInfo)
{
MOZ_CRASH("PBackgroundSDBConnectionChild actor should be manually "
"constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundSDBConnectionChild(
PBackgroundSDBConnectionChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLSDatabaseChild*
BackgroundChildImpl::AllocPBackgroundLSDatabaseChild(
const uint64_t& aDatastoreId)
{
MOZ_CRASH("PBackgroundLSDatabaseChild actor should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundLSDatabaseChild(
PBackgroundLSDatabaseChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLSRequestChild*
BackgroundChildImpl::AllocPBackgroundLSRequestChild(
const LSRequestParams& aParams)
{
MOZ_CRASH("PBackgroundLSRequestChild actor should be manually constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundLSRequestChild(
PBackgroundLSRequestChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundLocalStorageCacheChild*
BackgroundChildImpl::AllocPBackgroundLocalStorageCacheChild(
const PrincipalInfo& aPrincipalInfo,
@ -243,24 +297,6 @@ BackgroundChildImpl::DeallocPBackgroundLocalStorageCacheChild(
return true;
}
BackgroundChildImpl::PBackgroundSDBConnectionChild*
BackgroundChildImpl::AllocPBackgroundSDBConnectionChild(
const PrincipalInfo& aPrincipalInfo)
{
MOZ_CRASH("PBackgroundSDBConnectionChild actor should be manually "
"constructed!");
}
bool
BackgroundChildImpl::DeallocPBackgroundSDBConnectionChild(
PBackgroundSDBConnectionChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
BackgroundChildImpl::PBackgroundStorageChild*
BackgroundChildImpl::AllocPBackgroundStorageChild(const nsString& aProfilePath)
{

View File

@ -78,6 +78,19 @@ protected:
DeallocPBackgroundSDBConnectionChild(PBackgroundSDBConnectionChild* aActor)
override;
virtual PBackgroundLSDatabaseChild*
AllocPBackgroundLSDatabaseChild(const uint64_t& aCacheId) override;
virtual bool
DeallocPBackgroundLSDatabaseChild(PBackgroundLSDatabaseChild* aActor)
override;
virtual PBackgroundLSRequestChild*
AllocPBackgroundLSRequestChild(const LSRequestParams& aParams) override;
virtual bool
DeallocPBackgroundLSRequestChild(PBackgroundLSRequestChild* aActor) override;
virtual PBackgroundLocalStorageCacheChild*
AllocPBackgroundLocalStorageCacheChild(const PrincipalInfo& aPrincipalInfo,
const nsCString& aOriginKey,

View File

@ -33,6 +33,7 @@
#include "mozilla/dom/ipc/IPCBlobInputStreamParent.h"
#include "mozilla/dom/ipc/PendingIPCBlobParent.h"
#include "mozilla/dom/ipc/TemporaryIPCBlobParent.h"
#include "mozilla/dom/localstorage/ActorsParent.h"
#include "mozilla/dom/quota/ActorsParent.h"
#include "mozilla/dom/simpledb/ActorsParent.h"
#include "mozilla/dom/RemoteWorkerParent.h"
@ -293,6 +294,79 @@ BackgroundParentImpl::DeallocPBackgroundSDBConnectionParent(
return mozilla::dom::DeallocPBackgroundSDBConnectionParent(aActor);
}
BackgroundParentImpl::PBackgroundLSDatabaseParent*
BackgroundParentImpl::AllocPBackgroundLSDatabaseParent(
const uint64_t& aDatastoreId)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return mozilla::dom::AllocPBackgroundLSDatabaseParent(aDatastoreId);
}
mozilla::ipc::IPCResult
BackgroundParentImpl::RecvPBackgroundLSDatabaseConstructor(
PBackgroundLSDatabaseParent* aActor,
const uint64_t& aDatastoreId)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
if (!mozilla::dom::RecvPBackgroundLSDatabaseConstructor(aActor,
aDatastoreId)) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
bool
BackgroundParentImpl::DeallocPBackgroundLSDatabaseParent(
PBackgroundLSDatabaseParent* aActor)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
return mozilla::dom::DeallocPBackgroundLSDatabaseParent(aActor);
}
BackgroundParentImpl::PBackgroundLSRequestParent*
BackgroundParentImpl::AllocPBackgroundLSRequestParent(
const LSRequestParams& aParams)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return mozilla::dom::AllocPBackgroundLSRequestParent(this, aParams);
}
mozilla::ipc::IPCResult
BackgroundParentImpl::RecvPBackgroundLSRequestConstructor(
PBackgroundLSRequestParent* aActor,
const LSRequestParams& aParams)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
if (!mozilla::dom::RecvPBackgroundLSRequestConstructor(aActor, aParams)) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
bool
BackgroundParentImpl::DeallocPBackgroundLSRequestParent(
PBackgroundLSRequestParent* aActor)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
return mozilla::dom::DeallocPBackgroundLSRequestParent(aActor);
}
BackgroundParentImpl::PBackgroundLocalStorageCacheParent*
BackgroundParentImpl::AllocPBackgroundLocalStorageCacheParent(
const PrincipalInfo& aPrincipalInfo,

View File

@ -77,6 +77,28 @@ protected:
DeallocPBackgroundSDBConnectionParent(PBackgroundSDBConnectionParent* aActor)
override;
virtual PBackgroundLSDatabaseParent*
AllocPBackgroundLSDatabaseParent(const uint64_t& aCacheId) override;
virtual mozilla::ipc::IPCResult
RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
const uint64_t& aDatastoreId) override;
virtual bool
DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
override;
virtual PBackgroundLSRequestParent*
AllocPBackgroundLSRequestParent(const LSRequestParams& aParams) override;
virtual mozilla::ipc::IPCResult
RecvPBackgroundLSRequestConstructor(PBackgroundLSRequestParent* aActor,
const LSRequestParams& aParams) override;
virtual bool
DeallocPBackgroundLSRequestParent(PBackgroundLSRequestParent* aActor)
override;
virtual PBackgroundLocalStorageCacheParent*
AllocPBackgroundLocalStorageCacheParent(const PrincipalInfo& aPrincipalInfo,
const nsCString& aOriginKey,

View File

@ -6,6 +6,8 @@ include protocol PAsmJSCacheEntry;
include protocol PBackgroundIDBFactory;
include protocol PBackgroundIndexedDBUtils;
include protocol PBackgroundSDBConnection;
include protocol PBackgroundLSDatabase;
include protocol PBackgroundLSRequest;
include protocol PBackgroundLocalStorageCache;
include protocol PBackgroundStorage;
include protocol PBackgroundTest;
@ -44,6 +46,7 @@ include DOMTypes;
include IPCBlob;
include IPCServiceWorkerDescriptor;
include IPCServiceWorkerRegistrationDescriptor;
include PBackgroundLSSharedTypes;
include PBackgroundSharedTypes;
include PBackgroundIDBSharedTypes;
include PFileSystemParams;
@ -72,6 +75,8 @@ sync protocol PBackground
manages PBackgroundIDBFactory;
manages PBackgroundIndexedDBUtils;
manages PBackgroundSDBConnection;
manages PBackgroundLSDatabase;
manages PBackgroundLSRequest;
manages PBackgroundLocalStorageCache;
manages PBackgroundStorage;
manages PBackgroundTest;
@ -119,6 +124,10 @@ parent:
async PBackgroundSDBConnection(PrincipalInfo principalInfo);
async PBackgroundLSDatabase(uint64_t datastoreId);
async PBackgroundLSRequest(LSRequestParams params);
async PBackgroundLocalStorageCache(PrincipalInfo principalInfo,
nsCString originKey,
uint32_t privateBrowsingId);

View File

@ -922,6 +922,20 @@ description =
description =
[PBackgroundStorage::Preload]
description =
[PBackgroundLSDatabase::GetLength]
description =
[PBackgroundLSDatabase::GetKey]
description =
[PBackgroundLSDatabase::GetItem]
description =
[PBackgroundLSDatabase::GetKeys]
description =
[PBackgroundLSDatabase::SetItem]
description =
[PBackgroundLSDatabase::RemoveItem]
description =
[PBackgroundLSDatabase::Clear]
description =
[PRemoteSpellcheckEngine::Check]
description =
[PRemoteSpellcheckEngine::CheckAndSuggest]

View File

@ -63,7 +63,9 @@
#include "mozilla/dom/BlobURL.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/SDBConnection.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/dom/LocalStorageManager.h"
#include "mozilla/dom/LocalStorageManager2.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/dom/StorageActivityService.h"
@ -165,7 +167,6 @@ already_AddRefed<nsIPresentationService> NS_CreatePresentationService();
// Factory Constructor
typedef mozilla::dom::BlobURL::Mutator BlobURLMutator;
NS_GENERIC_FACTORY_CONSTRUCTOR(BlobURLMutator)
NS_GENERIC_FACTORY_CONSTRUCTOR(LocalStorageManager)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService,
DOMRequestService::FactoryCreate)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManagerService,
@ -494,6 +495,19 @@ NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
NS_DEFINE_NAMED_CID(NS_SCRIPTERROR_CID);
static nsresult
LocalStorageManagerConstructor(nsISupports *aOuter, REFNSIID aIID,
void **aResult)
{
if (NextGenLocalStorageEnabled()) {
RefPtr<LocalStorageManager2> manager = new LocalStorageManager2();
return manager->QueryInterface(aIID, aResult);
}
RefPtr<LocalStorageManager> manager = new LocalStorageManager();
return manager->QueryInterface(aIID, aResult);
}
static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
// clang-format off
XPCONNECT_CIDENTRIES

View File

@ -1285,6 +1285,12 @@ pref("dom.disable_open_click_delay", 1000);
pref("dom.serviceWorkers.disable_open_click_delay", 1000);
pref("dom.storage.enabled", true);
// Whether or not LSNG (Next Generation Local Storage) is enabled.
#ifdef NIGHTLY_BUILD
pref("dom.storage.next_gen", true);
#else
pref("dom.storage.next_gen", false);
#endif
pref("dom.storage.default_quota", 5120);
pref("dom.storage.testing", false);

View File

@ -0,0 +1,2 @@
[opener-closed.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[opener-noopener.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[opener-noreferrer.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_blank-002.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_parent-004.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_self-002.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_top-001.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_top-002.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[choose-_top-003.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[noreferrer-null-opener.html]
disabled: temporary

View File

@ -1,3 +1,2 @@
[noreferrer-window-name.html]
disabled:
if verify: fails in verify mode
disabled: temporary

View File

@ -1,2 +1,2 @@
[document-domain.html]
expected: TIMEOUT
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_basic.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_body_attribute.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_case_sensitive.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_key.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_newvalue.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_oldvalue.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_removeitem.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_storagearea.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_local_url.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_no_duplicates.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[event_setattribute.html]
disabled: temporary

View File

@ -0,0 +1,2 @@
[storage_local_setitem_quotaexceedederr.html]
disabled: temporary

View File

@ -68,8 +68,8 @@ skip-if = serviceworker_e10s
[browser_storageAccessWithHeuristics.js]
[browser_allowPermissionForTracker.js]
[browser_denyPermissionForTracker.js]
[browser_localStorageEvents.js]
support-files = localStorage.html
#[browser_localStorageEvents.js]
#support-files = localStorage.html
[browser_partitionedLocalStorage.js]
[browser_partitionedLocalStorage_events.js]
support-files = localStorageEvents.html
#[browser_partitionedLocalStorage_events.js]
#support-files = localStorageEvents.html

View File

@ -112,11 +112,11 @@ scheme=https
[test_ext_subframes_privileges.html]
skip-if = os == 'android' || verify # bug 1489771
[test_ext_test.html]
[test_ext_unlimitedStorage.html]
[test_ext_unlimitedStorage_legacy_persistent_indexedDB.html]
#[test_ext_unlimitedStorage.html]
#[test_ext_unlimitedStorage_legacy_persistent_indexedDB.html]
# IndexedDB persistent storage mode is not allowed on Fennec from a non-chrome privileged code
# (it has only been enabled for apps and privileged code). See Bug 1119462 for additional info.
skip-if = os == 'android'
#skip-if = os == 'android'
[test_ext_web_accessible_resources.html]
skip-if = os == 'android' && debug # bug 1397615
[test_ext_webnavigation.html]

View File

@ -1,7 +1,7 @@
[DEFAULT]
tags = webextensions in-process-webextensions
[test_ext_storage_cleanup.html]
#[test_ext_storage_cleanup.html]
# Bug 1426514 storage_cleanup: clearing localStorage fails with oop
[include:mochitest-common.ini]

View File

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
#XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
EXTRA_JS_MODULES += [
'ForgetAboutSite.jsm',

View File

@ -4,4 +4,4 @@ skip-if = toolkit == 'android'
support-files =
!/dom/push/test/xpcshell/head.js
[test_removeDataFromDomain.js]
#[test_removeDataFromDomain.js]