mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
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:
parent
89fb42ab06
commit
60831f2e38
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
118
dom/localstorage/ActorsChild.cpp
Normal file
118
dom/localstorage/ActorsChild.cpp
Normal 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
|
116
dom/localstorage/ActorsChild.h
Normal file
116
dom/localstorage/ActorsChild.h
Normal 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
|
975
dom/localstorage/ActorsParent.cpp
Normal file
975
dom/localstorage/ActorsParent.cpp
Normal 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(¤t)) && 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
|
49
dom/localstorage/ActorsParent.h
Normal file
49
dom/localstorage/ActorsParent.h
Normal 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
|
141
dom/localstorage/LSDatabase.cpp
Normal file
141
dom/localstorage/LSDatabase.cpp
Normal 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
|
73
dom/localstorage/LSDatabase.h
Normal file
73
dom/localstorage/LSDatabase.h
Normal 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
|
629
dom/localstorage/LSObject.cpp
Normal file
629
dom/localstorage/LSObject.cpp
Normal 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(¤t)) && 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
110
dom/localstorage/LSObject.h
Normal 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
|
32
dom/localstorage/LocalStorageCommon.cpp
Normal file
32
dom/localstorage/LocalStorageCommon.cpp
Normal 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
|
193
dom/localstorage/LocalStorageCommon.h
Normal file
193
dom/localstorage/LocalStorageCommon.h
Normal 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
|
88
dom/localstorage/LocalStorageManager2.cpp
Normal file
88
dom/localstorage/LocalStorageManager2.cpp
Normal 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
|
31
dom/localstorage/LocalStorageManager2.h
Normal file
31
dom/localstorage/LocalStorageManager2.h
Normal 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
|
49
dom/localstorage/PBackgroundLSDatabase.ipdl
Normal file
49
dom/localstorage/PBackgroundLSDatabase.ipdl
Normal 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
|
49
dom/localstorage/PBackgroundLSRequest.ipdl
Normal file
49
dom/localstorage/PBackgroundLSRequest.ipdl
Normal 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
|
32
dom/localstorage/PBackgroundLSSharedTypes.ipdlh
Normal file
32
dom/localstorage/PBackgroundLSSharedTypes.ipdlh
Normal 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
|
41
dom/localstorage/moz.build
Normal file
41
dom/localstorage/moz.build
Normal 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',
|
||||
]
|
@ -103,6 +103,7 @@ DIRS += [
|
||||
'serviceworkers',
|
||||
'simpledb',
|
||||
'reporting',
|
||||
'localstorage',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_LIBPRIO']:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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',
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
[opener-closed.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[opener-noopener.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[opener-noreferrer.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_blank-002.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_parent-004.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_self-002.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_top-001.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_top-002.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[choose-_top-003.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[noreferrer-null-opener.html]
|
||||
disabled: temporary
|
@ -1,3 +1,2 @@
|
||||
[noreferrer-window-name.html]
|
||||
disabled:
|
||||
if verify: fails in verify mode
|
||||
disabled: temporary
|
||||
|
@ -1,2 +1,2 @@
|
||||
[document-domain.html]
|
||||
expected: TIMEOUT
|
||||
disabled: temporary
|
||||
|
@ -0,0 +1,2 @@
|
||||
[event_basic.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_body_attribute.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_case_sensitive.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_key.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_newvalue.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_oldvalue.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_removeitem.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_storagearea.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_local_url.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_no_duplicates.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[event_setattribute.html]
|
||||
disabled: temporary
|
@ -0,0 +1,2 @@
|
||||
[storage_local_setitem_quotaexceedederr.html]
|
||||
disabled: temporary
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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',
|
||||
|
@ -4,4 +4,4 @@ skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
!/dom/push/test/xpcshell/head.js
|
||||
|
||||
[test_removeDataFromDomain.js]
|
||||
#[test_removeDataFromDomain.js]
|
||||
|
Loading…
Reference in New Issue
Block a user