зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to autoland. a=merge
This commit is contained in:
Коммит
609e39ab2e
|
@ -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;
|
||||
|
||||
|
|
|
@ -227,36 +227,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");
|
||||
|
@ -511,11 +403,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;
|
||||
}
|
||||
|
||||
|
@ -606,11 +498,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;
|
||||
}
|
||||
|
||||
|
@ -652,8 +544,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;
|
||||
|
@ -664,11 +555,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;
|
||||
|
@ -694,8 +586,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,59 +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;
|
||||
RefPtr<ClientManagerService> mService = ClientManagerService::GetInstance();
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
|
@ -96,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();
|
||||
|
||||
|
@ -116,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',
|
||||
|
|
Загрузка…
Ссылка в новой задаче