зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 5 changesets (bug 1584007) for causing crashes in ClientManagerService.
CLOSED TREE Backed out changeset e8e6a6bb50ff (bug 1584007) Backed out changeset 9468d92f2a55 (bug 1584007) Backed out changeset 19ed74a7ea6f (bug 1584007) Backed out changeset 6c35d3d0f747 (bug 1584007) Backed out changeset ea67977a5cdd (bug 1584007)
This commit is contained in:
Родитель
df18ec3853
Коммит
b6435f7773
|
@ -163,9 +163,9 @@ class ClientChannelHelper : public nsIInterfaceRequestor,
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual void CreateClientForPrincipal(nsILoadInfo* aLoadInfo,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsISerialEventTarget* aEventTarget) {
|
||||
static void CreateClientForPrincipal(nsILoadInfo* aLoadInfo,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsISerialEventTarget* aEventTarget) {
|
||||
// Create the new ClientSource. This should only happen for window
|
||||
// Clients since support cross-origin redirects are blocked by the
|
||||
// same-origin security policy.
|
||||
|
@ -181,41 +181,16 @@ NS_IMPL_ISUPPORTS(ClientChannelHelper, nsIInterfaceRequestor,
|
|||
nsIChannelEventSink);
|
||||
|
||||
class ClientChannelHelperParent final : public ClientChannelHelper {
|
||||
~ClientChannelHelperParent() {
|
||||
// This requires that if a load completes, the associated ClientSource is
|
||||
// created and registers itself before this ClientChannelHelperParent is
|
||||
// destroyed. Otherwise, we may incorrectly "forget" a future ClientSource
|
||||
// which will actually be created.
|
||||
SetFutureSourceInfo(Nothing());
|
||||
}
|
||||
~ClientChannelHelperParent() = default;
|
||||
|
||||
void CreateClient(nsILoadInfo* aLoadInfo, nsIPrincipal* aPrincipal) override {
|
||||
CreateClientForPrincipal(aLoadInfo, aPrincipal, mEventTarget);
|
||||
}
|
||||
|
||||
void SetFutureSourceInfo(Maybe<ClientInfo>&& aClientInfo) {
|
||||
if (mRecentFutureSourceInfo) {
|
||||
// No-op if the corresponding ClientSource has alrady been created, but
|
||||
// it's not known if that's the case here.
|
||||
ClientManager::ForgetFutureSource(*mRecentFutureSourceInfo);
|
||||
}
|
||||
|
||||
if (aClientInfo) {
|
||||
Unused << NS_WARN_IF(!ClientManager::ExpectFutureSource(*aClientInfo));
|
||||
}
|
||||
|
||||
mRecentFutureSourceInfo = std::move(aClientInfo);
|
||||
}
|
||||
|
||||
// Keep track of the most recent ClientInfo created which isn't backed by a
|
||||
// ClientSource, which is used to notify ClientManagerService that the
|
||||
// ClientSource won't ever actually be constructed.
|
||||
Maybe<ClientInfo> mRecentFutureSourceInfo;
|
||||
|
||||
public:
|
||||
void CreateClientForPrincipal(nsILoadInfo* aLoadInfo,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsISerialEventTarget* aEventTarget) override {
|
||||
static void CreateClientForPrincipal(nsILoadInfo* aLoadInfo,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsISerialEventTarget* aEventTarget) {
|
||||
// If we're managing redirects in the parent, then we don't want
|
||||
// to create a new ClientSource (since those need to live with
|
||||
// the global), so just allocate a new ClientInfo/id and we can
|
||||
|
@ -225,7 +200,6 @@ class ClientChannelHelperParent final : public ClientChannelHelper {
|
|||
ClientManager::CreateInfo(ClientType::Window, aPrincipal);
|
||||
if (reservedInfo) {
|
||||
aLoadInfo->SetReservedClientInfo(*reservedInfo);
|
||||
SetFutureSourceInfo(std::move(reservedInfo));
|
||||
}
|
||||
}
|
||||
ClientChannelHelperParent(nsIInterfaceRequestor* aOuter,
|
||||
|
@ -320,12 +294,12 @@ nsresult AddClientChannelHelperInternal(nsIChannel* aChannel,
|
|||
rv = aChannel->GetNotificationCallbacks(getter_AddRefs(outerCallbacks));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<ClientChannelHelper> helper = new T(outerCallbacks, aEventTarget);
|
||||
|
||||
if (initialClientInfo.isNothing() && reservedClientInfo.isNothing()) {
|
||||
helper->CreateClientForPrincipal(loadInfo, channelPrincipal, aEventTarget);
|
||||
T::CreateClientForPrincipal(loadInfo, channelPrincipal, aEventTarget);
|
||||
}
|
||||
|
||||
RefPtr<ClientChannelHelper> helper = new T(outerCallbacks, aEventTarget);
|
||||
|
||||
// Only set the callbacks helper if we are able to reserve the client
|
||||
// successfully.
|
||||
rv = aChannel->SetNotificationCallbacks(helper);
|
||||
|
|
|
@ -27,13 +27,13 @@ void ClientHandleParent::ActorDestroy(ActorDestroyReason aReason) {
|
|||
mSource->DetachHandle(this);
|
||||
mSource = nullptr;
|
||||
} else {
|
||||
if (!mSourcePromiseHolder.IsEmpty()) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowAbortError("Client aborted");
|
||||
mSourcePromiseHolder.Reject(rv, __func__);
|
||||
}
|
||||
mService->StopWaitingForSource(this, mClientId);
|
||||
}
|
||||
|
||||
mSourcePromiseRequestHolder.DisconnectIfExists();
|
||||
if (mSourcePromise) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowAbortError("Client aborted");
|
||||
mSourcePromise->Reject(rv, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,20 +63,13 @@ ClientHandleParent::~ClientHandleParent() { MOZ_DIAGNOSTIC_ASSERT(!mSource); }
|
|||
void ClientHandleParent::Init(const IPCClientInfo& aClientInfo) {
|
||||
mClientId = aClientInfo.id();
|
||||
mPrincipalInfo = aClientInfo.principalInfo();
|
||||
mSource = mService->FindSource(aClientInfo.id(), aClientInfo.principalInfo());
|
||||
if (!mSource) {
|
||||
mService->WaitForSource(this, aClientInfo.id());
|
||||
return;
|
||||
}
|
||||
|
||||
// Callbacks are disconnected in ActorDestroy, so capturing `this` is safe.
|
||||
mService->FindSource(aClientInfo.id(), aClientInfo.principalInfo())
|
||||
->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[this](ClientSourceParent* aSource) {
|
||||
mSourcePromiseRequestHolder.Complete();
|
||||
FoundSource(aSource);
|
||||
},
|
||||
[this](const CopyableErrorResult&) {
|
||||
mSourcePromiseRequestHolder.Complete();
|
||||
Unused << Send__delete__(this);
|
||||
})
|
||||
->Track(mSourcePromiseRequestHolder);
|
||||
mSource->AttachHandle(this);
|
||||
}
|
||||
|
||||
ClientSourceParent* ClientHandleParent::GetSource() const { return mSource; }
|
||||
|
@ -86,17 +79,20 @@ RefPtr<SourcePromise> ClientHandleParent::EnsureSource() {
|
|||
return SourcePromise::CreateAndResolve(mSource, __func__);
|
||||
}
|
||||
|
||||
return mSourcePromiseHolder.Ensure(__func__);
|
||||
if (!mSourcePromise) {
|
||||
mSourcePromise = new SourcePromise::Private(__func__);
|
||||
}
|
||||
return mSourcePromise;
|
||||
}
|
||||
|
||||
void ClientHandleParent::FoundSource(ClientSourceParent* aSource) {
|
||||
MOZ_ASSERT(aSource->Info().Id() == mClientId);
|
||||
if (!ClientMatchPrincipalInfo(aSource->Info().PrincipalInfo(),
|
||||
mPrincipalInfo)) {
|
||||
if (!mSourcePromiseHolder.IsEmpty()) {
|
||||
if (mSourcePromise) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowAbortError("Client aborted");
|
||||
mSourcePromiseHolder.Reject(rv, __func__);
|
||||
mSourcePromise->Reject(rv, __func__);
|
||||
}
|
||||
Unused << Send__delete__(this);
|
||||
return;
|
||||
|
@ -104,7 +100,9 @@ void ClientHandleParent::FoundSource(ClientSourceParent* aSource) {
|
|||
|
||||
mSource = aSource;
|
||||
mSource->AttachHandle(this);
|
||||
mSourcePromiseHolder.ResolveIfExists(aSource, __func__);
|
||||
if (mSourcePromise) {
|
||||
mSourcePromise->Resolve(aSource, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#ifndef _mozilla_dom_ClientHandleParent_h
|
||||
#define _mozilla_dom_ClientHandleParent_h
|
||||
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PClientHandleParent.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
|
@ -23,18 +21,16 @@ typedef MozPromise<ClientSourceParent*, CopyableErrorResult,
|
|||
|
||||
class ClientHandleParent final : public PClientHandleParent {
|
||||
RefPtr<ClientManagerService> mService;
|
||||
|
||||
// mSource and mSourcePromiseHolder are mutually exclusive.
|
||||
ClientSourceParent* mSource;
|
||||
|
||||
// Operations will wait on this promise while mSource is null.
|
||||
MozPromiseHolder<SourcePromise> mSourcePromiseHolder;
|
||||
|
||||
MozPromiseRequestHolder<SourcePromise> mSourcePromiseRequestHolder;
|
||||
|
||||
nsID mClientId;
|
||||
PrincipalInfo mPrincipalInfo;
|
||||
|
||||
// A promise for HandleOps that want to access our ClientSourceParent.
|
||||
// Resolved once FoundSource is called and we have a ClientSourceParent
|
||||
// available.
|
||||
RefPtr<SourcePromise::Private> mSourcePromise;
|
||||
|
||||
// PClientHandleParent interface
|
||||
mozilla::ipc::IPCResult RecvTeardown() override;
|
||||
|
||||
|
|
|
@ -228,36 +228,6 @@ WorkerPrivate* ClientManager::GetWorkerPrivate() const {
|
|||
return GetActor()->GetWorkerPrivate();
|
||||
}
|
||||
|
||||
// Used to share logic between ExpectFutureSource and ForgetFutureSource.
|
||||
/* static */ bool ClientManager::ExpectOrForgetFutureSource(
|
||||
const ClientInfo& aClientInfo,
|
||||
bool (PClientManagerChild::*aMethod)(const IPCClientInfo&)) {
|
||||
bool rv = true;
|
||||
|
||||
RefPtr<ClientManager> mgr = ClientManager::GetOrCreateForCurrentThread();
|
||||
mgr->MaybeExecute(
|
||||
[&](ClientManagerChild* aActor) {
|
||||
if (!(aActor->*aMethod)(aClientInfo.ToIPC())) {
|
||||
rv = false;
|
||||
}
|
||||
},
|
||||
[&] { rv = false; });
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */ bool ClientManager::ExpectFutureSource(
|
||||
const ClientInfo& aClientInfo) {
|
||||
return ExpectOrForgetFutureSource(
|
||||
aClientInfo, &PClientManagerChild::SendExpectFutureClientSource);
|
||||
}
|
||||
|
||||
/* static */ bool ClientManager::ForgetFutureSource(
|
||||
const ClientInfo& aClientInfo) {
|
||||
return ExpectOrForgetFutureSource(
|
||||
aClientInfo, &PClientManagerChild::SendForgetFutureClientSource);
|
||||
}
|
||||
|
||||
// static
|
||||
void ClientManager::Startup() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "mozilla/dom/ClientOpPromise.h"
|
||||
#include "mozilla/dom/ClientThing.h"
|
||||
#include "mozilla/dom/PClientManagerChild.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
|
@ -74,29 +73,7 @@ class ClientManager final : public ClientThing<ClientManagerChild> {
|
|||
// Private methods called by ClientSource
|
||||
mozilla::dom::WorkerPrivate* GetWorkerPrivate() const;
|
||||
|
||||
// Don't use - use {Expect,Forget}FutureSource instead.
|
||||
static bool ExpectOrForgetFutureSource(
|
||||
const ClientInfo& aClientInfo,
|
||||
bool (PClientManagerChild::*aMethod)(const IPCClientInfo&));
|
||||
|
||||
public:
|
||||
// Asynchronously declare that a ClientSource will possibly be constructed
|
||||
// from an equivalent ClientInfo in the future. This must be called before any
|
||||
// any ClientHandles are created with the ClientInfo to avoid race conditions
|
||||
// when ClientHandles query the ClientManagerService.
|
||||
//
|
||||
// This method exists so that the ClientManagerService can determine if a
|
||||
// particular ClientSource can be expected to exist in the future or has
|
||||
// already existed and been destroyed.
|
||||
//
|
||||
// If it's later known that the expected ClientSource will not be
|
||||
// constructed, ForgetFutureSource must be called.
|
||||
static bool ExpectFutureSource(const ClientInfo& aClientInfo);
|
||||
|
||||
// May also be called even when the "future" source has become a "real"
|
||||
// source, in which case this is a no-op.
|
||||
static bool ForgetFutureSource(const ClientInfo& aClientInfo);
|
||||
|
||||
// Initialize the ClientManager at process start. This
|
||||
// does book-keeping like creating a TLS identifier, etc.
|
||||
// This should only be called by process startup code.
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "ClientManagerOpParent.h"
|
||||
#include "ClientManagerService.h"
|
||||
#include "ClientSourceParent.h"
|
||||
#include "ClientValidation.h"
|
||||
#include "mozilla/dom/PClientNavigateOpParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
|
@ -107,28 +106,5 @@ ClientManagerParent::~ClientManagerParent() { mService->RemoveManager(this); }
|
|||
|
||||
void ClientManagerParent::Init() { mService->AddManager(this); }
|
||||
|
||||
IPCResult ClientManagerParent::RecvExpectFutureClientSource(
|
||||
const IPCClientInfo& aClientInfo) {
|
||||
if (NS_WARN_IF(!ClientIsValidPrincipalInfo(aClientInfo.principalInfo()))) {
|
||||
return IPC_FAIL(this, "Invalid PrincipalInfo.");
|
||||
}
|
||||
|
||||
RefPtr<ClientManagerService> cms =
|
||||
ClientManagerService::GetOrCreateInstance();
|
||||
Unused << NS_WARN_IF(cms->ExpectFutureSource(aClientInfo));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult ClientManagerParent::RecvForgetFutureClientSource(
|
||||
const IPCClientInfo& aClientInfo) {
|
||||
if (NS_WARN_IF(!ClientIsValidPrincipalInfo(aClientInfo.principalInfo()))) {
|
||||
return IPC_FAIL(this, "Invalid PrincipalInfo.");
|
||||
}
|
||||
|
||||
RefPtr<ClientManagerService> cms = ClientManagerService::GetInstance();
|
||||
cms->ForgetFutureSource(aClientInfo);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -52,12 +52,6 @@ class ClientManagerParent final : public PClientManagerParent {
|
|||
PClientSourceParent* aActor,
|
||||
const ClientSourceConstructorArgs& aArgs) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvExpectFutureClientSource(
|
||||
const IPCClientInfo& aClientInfo) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvForgetFutureClientSource(
|
||||
const IPCClientInfo& aClientInfo) override;
|
||||
|
||||
public:
|
||||
ClientManagerParent();
|
||||
~ClientManagerParent();
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "ClientOpenWindowUtils.h"
|
||||
#include "ClientPrincipalUtils.h"
|
||||
#include "ClientSourceParent.h"
|
||||
#include "mozilla/dom/ClientIPCTypes.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ServiceWorkerManager.h"
|
||||
#include "mozilla/dom/ServiceWorkerUtils.h"
|
||||
|
@ -108,10 +107,6 @@ RefPtr<GenericPromise> OnShutdown() {
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
ClientManagerService::FutureClientSourceParent::FutureClientSourceParent(
|
||||
const IPCClientInfo& aClientInfo)
|
||||
: mPrincipalInfo(aClientInfo.principalInfo()) {}
|
||||
|
||||
ClientManagerService::ClientManagerService() : mShutdown(false) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
|
@ -141,7 +136,7 @@ ClientManagerService::ClientManagerService() : mShutdown(false) {
|
|||
|
||||
ClientManagerService::~ClientManagerService() {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSourceTable.count() == 0);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSourceTable.Count() == 0);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
|
||||
|
@ -167,38 +162,6 @@ void ClientManagerService::Shutdown() {
|
|||
}
|
||||
}
|
||||
|
||||
ClientSourceParent* ClientManagerService::MaybeUnwrapAsExistingSource(
|
||||
const SourceTableEntry& aEntry) const {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (aEntry.is<FutureClientSourceParent>()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aEntry.as<ClientSourceParent*>();
|
||||
}
|
||||
|
||||
ClientSourceParent* ClientManagerService::FindExistingSource(
|
||||
const nsID& aID, const PrincipalInfo& aPrincipalInfo) const {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto entryPtr = mSourceTable.lookup(aID);
|
||||
|
||||
if (!entryPtr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ClientSourceParent* source = MaybeUnwrapAsExistingSource(entryPtr->value());
|
||||
|
||||
if (!source || source->IsFrozen() ||
|
||||
NS_WARN_IF(!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
||||
aPrincipalInfo))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ClientManagerService>
|
||||
ClientManagerService::GetOrCreateInstance() {
|
||||
|
@ -224,143 +187,72 @@ already_AddRefed<ClientManagerService> ClientManagerService::GetInstance() {
|
|||
return ref.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsNullPrincipalInfo(const PrincipalInfo& aPrincipalInfo) {
|
||||
return aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo;
|
||||
}
|
||||
|
||||
bool AreBothNullPrincipals(const PrincipalInfo& aPrincipalInfo1,
|
||||
const PrincipalInfo& aPrincipalInfo2) {
|
||||
return IsNullPrincipalInfo(aPrincipalInfo1) &&
|
||||
IsNullPrincipalInfo(aPrincipalInfo2);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool ClientManagerService::AddSource(ClientSourceParent* aSource) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aSource);
|
||||
|
||||
const nsID& id = aSource->Info().Id();
|
||||
auto entryPtr = mSourceTable.lookupForAdd(id);
|
||||
|
||||
if (entryPtr) {
|
||||
SourceTableEntry& entry = entryPtr->value();
|
||||
|
||||
// Do not permit overwriting an existing ClientSource with the same
|
||||
// UUID. This would allow a spoofed ClientParentSource actor to
|
||||
// intercept postMessage() intended for the real actor.
|
||||
if (NS_WARN_IF(entry.is<ClientSourceParent*>())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FutureClientSourceParent& placeHolder =
|
||||
entry.as<FutureClientSourceParent>();
|
||||
|
||||
const PrincipalInfo& placeHolderPrincipalInfo = placeHolder.PrincipalInfo();
|
||||
const PrincipalInfo& sourcePrincipalInfo = aSource->Info().PrincipalInfo();
|
||||
|
||||
// The placeholder FutureClientSourceParent's PrincipalInfo must match the
|
||||
// real ClientSourceParent's PrincipalInfo. The only exception is if both
|
||||
// are null principals (two null principals are considered unequal).
|
||||
if (!AreBothNullPrincipals(placeHolderPrincipalInfo, sourcePrincipalInfo) &&
|
||||
NS_WARN_IF(!ClientMatchPrincipalInfo(placeHolderPrincipalInfo,
|
||||
sourcePrincipalInfo))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
placeHolder.ResolvePromiseIfExists(aSource);
|
||||
|
||||
entry = AsVariant(aSource);
|
||||
return true;
|
||||
auto entry = mSourceTable.LookupForAdd(aSource->Info().Id());
|
||||
// Do not permit overwriting an existing ClientSource with the same
|
||||
// UUID. This would allow a spoofed ClientParentSource actor to
|
||||
// intercept postMessage() intended for the real actor.
|
||||
if (NS_WARN_IF(!!entry)) {
|
||||
return false;
|
||||
}
|
||||
entry.OrInsert([&] { return aSource; });
|
||||
|
||||
return mSourceTable.add(entryPtr, id, AsVariant(aSource));
|
||||
// Now that we've been created, notify any handles that were
|
||||
// waiting on us.
|
||||
auto* handles = mPendingHandles.GetValue(aSource->Info().Id());
|
||||
if (handles) {
|
||||
for (auto handle : *handles) {
|
||||
handle->FoundSource(aSource);
|
||||
}
|
||||
}
|
||||
mPendingHandles.Remove(aSource->Info().Id());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientManagerService::RemoveSource(ClientSourceParent* aSource) {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aSource);
|
||||
|
||||
auto entryPtr = mSourceTable.lookup(aSource->Info().Id());
|
||||
|
||||
if (NS_WARN_IF(!entryPtr)) {
|
||||
auto entry = mSourceTable.Lookup(aSource->Info().Id());
|
||||
if (NS_WARN_IF(!entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mSourceTable.remove(entryPtr);
|
||||
entry.Remove();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientManagerService::ExpectFutureSource(
|
||||
const IPCClientInfo& aClientInfo) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
const nsID& id = aClientInfo.id();
|
||||
auto entryPtr = mSourceTable.lookupForAdd(id);
|
||||
|
||||
// Prevent overwrites.
|
||||
if (NS_WARN_IF(static_cast<bool>(entryPtr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mSourceTable.add(
|
||||
entryPtr, id,
|
||||
SourceTableEntry(VariantIndex<0>(),
|
||||
FutureClientSourceParent(aClientInfo)));
|
||||
}
|
||||
|
||||
void ClientManagerService::ForgetFutureSource(
|
||||
const IPCClientInfo& aClientInfo) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto entryPtr = mSourceTable.lookup(aClientInfo.id());
|
||||
|
||||
if (entryPtr) {
|
||||
SourceTableEntry& entry = entryPtr->value();
|
||||
|
||||
if (entry.is<ClientSourceParent*>()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowInvalidStateError("Client creation aborted.");
|
||||
entry.as<FutureClientSourceParent>().RejectPromiseIfExists(rv);
|
||||
|
||||
mSourceTable.remove(entryPtr);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<SourcePromise> ClientManagerService::FindSource(
|
||||
ClientSourceParent* ClientManagerService::FindSource(
|
||||
const nsID& aID, const PrincipalInfo& aPrincipalInfo) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
auto entryPtr = mSourceTable.lookup(aID);
|
||||
|
||||
if (!entryPtr) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowInvalidStateError("Unknown client.");
|
||||
return SourcePromise::CreateAndReject(rv, __func__);
|
||||
auto entry = mSourceTable.Lookup(aID);
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SourceTableEntry& entry = entryPtr->value();
|
||||
|
||||
if (entry.is<FutureClientSourceParent>()) {
|
||||
return entry.as<FutureClientSourceParent>().Promise();
|
||||
}
|
||||
|
||||
ClientSourceParent* source = entry.as<ClientSourceParent*>();
|
||||
|
||||
ClientSourceParent* source = entry.Data();
|
||||
if (source->IsFrozen() ||
|
||||
NS_WARN_IF(!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
||||
aPrincipalInfo))) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowInvalidStateError("Unknown client.");
|
||||
return SourcePromise::CreateAndReject(rv, __func__);
|
||||
!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(),
|
||||
aPrincipalInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SourcePromise::CreateAndResolve(source, __func__);
|
||||
return source;
|
||||
}
|
||||
|
||||
void ClientManagerService::WaitForSource(ClientHandleParent* aHandle,
|
||||
const nsID& aID) {
|
||||
auto& entry = mPendingHandles.GetOrInsert(aID);
|
||||
entry.AppendElement(aHandle);
|
||||
}
|
||||
|
||||
void ClientManagerService::StopWaitingForSource(ClientHandleParent* aHandle,
|
||||
const nsID& aID) {
|
||||
auto* entry = mPendingHandles.GetValue(aID);
|
||||
if (entry) {
|
||||
entry->RemoveElement(aHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManagerService::AddManager(ClientManagerParent* aManager) {
|
||||
|
@ -385,7 +277,7 @@ void ClientManagerService::RemoveManager(ClientManagerParent* aManager) {
|
|||
RefPtr<ClientOpPromise> ClientManagerService::Navigate(
|
||||
const ClientNavigateArgs& aArgs) {
|
||||
ClientSourceParent* source =
|
||||
FindExistingSource(aArgs.target().id(), aArgs.target().principalInfo());
|
||||
FindSource(aArgs.target().id(), aArgs.target().principalInfo());
|
||||
if (!source) {
|
||||
CopyableErrorResult rv;
|
||||
rv.ThrowInvalidStateError("Unknown client");
|
||||
|
@ -498,11 +390,11 @@ RefPtr<ClientOpPromise> ClientManagerService::MatchAll(
|
|||
|
||||
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
||||
|
||||
for (auto iter = mSourceTable.iter(); !iter.done(); iter.next()) {
|
||||
ClientSourceParent* source =
|
||||
MaybeUnwrapAsExistingSource(iter.get().value());
|
||||
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
ClientSourceParent* source = iter.UserData();
|
||||
MOZ_DIAGNOSTIC_ASSERT(source);
|
||||
|
||||
if (!source || source->IsFrozen() || !source->ExecutionReady()) {
|
||||
if (source->IsFrozen() || !source->ExecutionReady()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -593,11 +485,11 @@ RefPtr<ClientOpPromise> ClientManagerService::Claim(
|
|||
|
||||
RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
|
||||
|
||||
for (auto iter = mSourceTable.iter(); !iter.done(); iter.next()) {
|
||||
ClientSourceParent* source =
|
||||
MaybeUnwrapAsExistingSource(iter.get().value());
|
||||
for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
ClientSourceParent* source = iter.UserData();
|
||||
MOZ_DIAGNOSTIC_ASSERT(source);
|
||||
|
||||
if (!source || source->IsFrozen()) {
|
||||
if (source->IsFrozen()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -639,8 +531,7 @@ RefPtr<ClientOpPromise> ClientManagerService::Claim(
|
|||
|
||||
RefPtr<ClientOpPromise> ClientManagerService::GetInfoAndState(
|
||||
const ClientGetInfoAndStateArgs& aArgs) {
|
||||
ClientSourceParent* source =
|
||||
FindExistingSource(aArgs.id(), aArgs.principalInfo());
|
||||
ClientSourceParent* source = FindSource(aArgs.id(), aArgs.principalInfo());
|
||||
|
||||
if (!source) {
|
||||
CopyableErrorResult rv;
|
||||
|
@ -651,11 +542,12 @@ RefPtr<ClientOpPromise> ClientManagerService::GetInfoAndState(
|
|||
if (!source->ExecutionReady()) {
|
||||
RefPtr<ClientManagerService> self = this;
|
||||
|
||||
// rejection ultimately converted to `undefined` in Clients::Get
|
||||
return source->ExecutionReadyPromise()->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[self = std::move(self), aArgs]() {
|
||||
[self, aArgs]() -> RefPtr<ClientOpPromise> {
|
||||
ClientSourceParent* source =
|
||||
self->FindExistingSource(aArgs.id(), aArgs.principalInfo());
|
||||
self->FindSource(aArgs.id(), aArgs.principalInfo());
|
||||
|
||||
if (!source) {
|
||||
CopyableErrorResult rv;
|
||||
|
@ -681,8 +573,7 @@ bool ClientManagerService::HasWindow(
|
|||
const PrincipalInfo& aPrincipalInfo, const nsID& aClientId) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
ClientSourceParent* source = FindExistingSource(aClientId, aPrincipalInfo);
|
||||
|
||||
ClientSourceParent* source = FindSource(aClientId, aPrincipalInfo);
|
||||
if (!source) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -6,12 +6,7 @@
|
|||
#ifndef _mozilla_dom_ClientManagerService_h
|
||||
#define _mozilla_dom_ClientManagerService_h
|
||||
|
||||
#include "ClientHandleParent.h"
|
||||
#include "ClientOpPromise.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/HashTable.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/Variant.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -33,58 +28,13 @@ class ContentParent;
|
|||
// browser. This service runs on the PBackground thread. To interact
|
||||
// it with it please use the ClientManager and ClientHandle classes.
|
||||
class ClientManagerService final {
|
||||
// Placeholder type that represents a ClientSourceParent that may be created
|
||||
// in the future (e.g. while a redirect chain is being resolved).
|
||||
//
|
||||
// Each FutureClientSourceParent has a promise that callbacks may be chained
|
||||
// to; the promise will be resolved when the associated ClientSourceParent is
|
||||
// created or rejected when it's known that it'll never be created.
|
||||
class FutureClientSourceParent {
|
||||
public:
|
||||
explicit FutureClientSourceParent(const IPCClientInfo& aClientInfo);
|
||||
|
||||
const mozilla::ipc::PrincipalInfo& PrincipalInfo() const {
|
||||
return mPrincipalInfo;
|
||||
}
|
||||
|
||||
already_AddRefed<SourcePromise> Promise() {
|
||||
return mPromiseHolder.Ensure(__func__);
|
||||
}
|
||||
|
||||
void ResolvePromiseIfExists(ClientSourceParent* aSource) {
|
||||
MOZ_ASSERT(aSource);
|
||||
mPromiseHolder.ResolveIfExists(aSource, __func__);
|
||||
}
|
||||
|
||||
void RejectPromiseIfExists(const CopyableErrorResult& aRv) {
|
||||
MOZ_ASSERT(aRv.Failed());
|
||||
mPromiseHolder.RejectIfExists(aRv, __func__);
|
||||
}
|
||||
|
||||
private:
|
||||
const mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
||||
MozPromiseHolder<SourcePromise> mPromiseHolder;
|
||||
};
|
||||
|
||||
using SourceTableEntry =
|
||||
Variant<FutureClientSourceParent, ClientSourceParent*>;
|
||||
|
||||
struct nsIDHasher {
|
||||
using Key = nsID;
|
||||
using Lookup = Key;
|
||||
|
||||
static HashNumber hash(const Lookup& aLookup) {
|
||||
return HashBytes(&aLookup, sizeof(Lookup));
|
||||
}
|
||||
|
||||
static bool match(const Key& aKey, const Lookup& aLookup) {
|
||||
return aKey.Equals(aLookup);
|
||||
}
|
||||
};
|
||||
|
||||
// Store the possible ClientSourceParent objects in a hash table. We want to
|
||||
// Store the ClientSourceParent objects in a hash table. We want to
|
||||
// optimize for insertion, removal, and lookup by UUID.
|
||||
HashMap<nsID, SourceTableEntry, nsIDHasher> mSourceTable;
|
||||
nsDataHashtable<nsIDHashKey, ClientSourceParent*> mSourceTable;
|
||||
|
||||
// The set of handles waiting for their corresponding ClientSourceParent
|
||||
// to be created.
|
||||
nsDataHashtable<nsIDHashKey, nsTArray<ClientHandleParent*>> mPendingHandles;
|
||||
|
||||
nsTArray<ClientManagerParent*> mManagerList;
|
||||
|
||||
|
@ -95,16 +45,6 @@ class ClientManagerService final {
|
|||
|
||||
void Shutdown();
|
||||
|
||||
// Returns nullptr if aEntry isn't a ClientSourceParent (i.e. it's a
|
||||
// FutureClientSourceParent).
|
||||
ClientSourceParent* MaybeUnwrapAsExistingSource(
|
||||
const SourceTableEntry& aEntry) const;
|
||||
|
||||
// Returns nullptr if the ClientSourceParent doesn't exist yet (i.e. it's a
|
||||
// FutureClientSourceParent or has already been destroyed) or is frozen.
|
||||
ClientSourceParent* FindExistingSource(
|
||||
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo) const;
|
||||
|
||||
public:
|
||||
static already_AddRefed<ClientManagerService> GetOrCreateInstance();
|
||||
|
||||
|
@ -115,16 +55,15 @@ class ClientManagerService final {
|
|||
|
||||
bool RemoveSource(ClientSourceParent* aSource);
|
||||
|
||||
// Returns true when a FutureClientSourceParent is successfully added.
|
||||
bool ExpectFutureSource(const IPCClientInfo& aClientInfo);
|
||||
|
||||
// May still be called if it's possible that the FutureClientSourceParent
|
||||
// no longer exists.
|
||||
void ForgetFutureSource(const IPCClientInfo& aClientInfo);
|
||||
|
||||
RefPtr<SourcePromise> FindSource(
|
||||
ClientSourceParent* FindSource(
|
||||
const nsID& aID, const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
|
||||
|
||||
// Called when a ClientHandle is created before the corresponding
|
||||
// ClientSource. Will call FoundSource on the ClientHandleParent when it
|
||||
// becomes available.
|
||||
void WaitForSource(ClientHandleParent* aHandle, const nsID& aID);
|
||||
void StopWaitingForSource(ClientHandleParent* aHandle, const nsID& aID);
|
||||
|
||||
void AddManager(ClientManagerParent* aManager);
|
||||
|
||||
void RemoveManager(ClientManagerParent* aManager);
|
||||
|
|
|
@ -32,9 +32,6 @@ parent:
|
|||
async PClientManagerOp(ClientOpConstructorArgs aArgs);
|
||||
async PClientSource(ClientSourceConstructorArgs aArgs);
|
||||
|
||||
async ExpectFutureClientSource(IPCClientInfo aClientInfo);
|
||||
async ForgetFutureClientSource(IPCClientInfo aClientInfo);
|
||||
|
||||
child:
|
||||
async PClientNavigateOp(ClientNavigateOpConstructorArgs aArgs);
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
EXPORTS.mozilla.dom += [
|
||||
'ClientChannelHelper.h',
|
||||
'ClientHandle.h',
|
||||
'ClientHandleParent.h',
|
||||
'ClientInfo.h',
|
||||
'ClientIPCUtils.h',
|
||||
'ClientManager.h',
|
||||
|
|
Загрузка…
Ссылка в новой задаче