Bug 1937111 - Implement a test-coordination method without unpartitioning storage - r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D231408
This commit is contained in:
@@ -82,8 +82,8 @@ function executeTest() {
|
||||
bc1.postMessage("close");
|
||||
}
|
||||
|
||||
var bc1 = new BroadcastChannel("bug646641_1");
|
||||
var bc2 = new BroadcastChannel("bug646641_2");
|
||||
var bc1 = SpecialPowers.wrap(BroadcastChannel).unpartitionedTestingChannel("bug646641_1");
|
||||
var bc2 = SpecialPowers.wrap(BroadcastChannel).unpartitionedTestingChannel("bug646641_2");
|
||||
bc1.onmessage = (msgEvent) => {
|
||||
var msg = msgEvent.data.message;
|
||||
var n = msgEvent.data.num;
|
||||
@@ -126,25 +126,8 @@ function executeTest() {
|
||||
gGen.next();
|
||||
});
|
||||
}
|
||||
if (isXOrigin) {
|
||||
// Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
|
||||
// Acquire storage access permission here so that the BroadcastChannel used to
|
||||
// communicate with the opened windows works in xorigin tests. Otherwise,
|
||||
// the iframe containing this page is isolated from first-party storage access,
|
||||
// which isolates BroadcastChannel communication.
|
||||
SpecialPowers.wrap(document).notifyUserGestureActivation();
|
||||
SpecialPowers.addPermission("storageAccessAPI", true, window.location.href).then(() => {
|
||||
SpecialPowers.wrap(document).requestStorageAccess().then(() => {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["privacy.partition.always_partition_third_party_non_cookie_storage", false]],
|
||||
}).then(() => {
|
||||
executeTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
executeTest();
|
||||
}
|
||||
|
||||
executeTest();
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -139,6 +139,121 @@ JSObject* BroadcastChannel::WrapObject(JSContext* aCx,
|
||||
return BroadcastChannel_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<BroadcastChannel>
|
||||
BroadcastChannel::UnpartitionedTestingChannel(const GlobalObject& aGlobal,
|
||||
const nsAString& aChannel,
|
||||
ErrorResult& aRv) {
|
||||
// This function must not be used outside of automation.
|
||||
if (!xpc::IsInAutomation()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsID portUUID = {};
|
||||
aRv = nsID::GenerateUUIDInPlace(portUUID);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BroadcastChannel> bc =
|
||||
new BroadcastChannel(global, aChannel, portUUID);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> unpartitionedPrincipal;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
|
||||
if (NS_WARN_IF(!window)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(global);
|
||||
if (NS_WARN_IF(!sop)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We are *intentionally* getting the unpartitioned principal here for
|
||||
// testing purposes, but the correct thing to do normally is to get the
|
||||
// storage key/principal. Passerby, do not imitate this code.
|
||||
unpartitionedPrincipal = sop->GetPrincipal();
|
||||
if (!unpartitionedPrincipal) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
|
||||
workerPrivate, "BroadcastChannel", [bc]() { bc->Shutdown(); });
|
||||
// We are already shutting down the worker. Let's return a non-active
|
||||
// object.
|
||||
if (NS_WARN_IF(!workerRef)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We are *intentionally* getting the unpartitioned principal here for
|
||||
// testing purposes, but the correct thing to do normally is to get the
|
||||
// storage key/principal. Passerby, do not imitate this code.
|
||||
unpartitionedPrincipal = workerPrivate->GetPrincipal();
|
||||
|
||||
bc->mWorkerRef = workerRef;
|
||||
}
|
||||
|
||||
// Register this component to PBackground.
|
||||
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
|
||||
if (NS_WARN_IF(!actorChild)) {
|
||||
// Firefox is probably shutting down. Let's return a 'generic' error.
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString origin;
|
||||
aRv = unpartitionedPrincipal->GetOrigin(origin);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsString originForEvents;
|
||||
aRv = nsContentUtils::GetWebExposedOriginSerialization(unpartitionedPrincipal,
|
||||
originForEvents);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PrincipalInfo unpartitionedPrincipalInfo;
|
||||
aRv = PrincipalToPrincipalInfo(unpartitionedPrincipal,
|
||||
&unpartitionedPrincipalInfo);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PBroadcastChannelChild* actor = actorChild->SendPBroadcastChannelConstructor(
|
||||
unpartitionedPrincipalInfo, origin, nsString(aChannel));
|
||||
if (!actor) {
|
||||
// The PBackground actor is shutting down, return a 'generic' error.
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bc->mActor = static_cast<BroadcastChannelChild*>(actor);
|
||||
bc->mActor->SetParent(bc);
|
||||
bc->mOriginForEvents = std::move(originForEvents);
|
||||
|
||||
return bc.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<BroadcastChannel> BroadcastChannel::Constructor(
|
||||
const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv) {
|
||||
|
||||
@@ -43,6 +43,9 @@ class BroadcastChannel final : public DOMEventTargetHelper {
|
||||
static already_AddRefed<BroadcastChannel> Constructor(
|
||||
const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<BroadcastChannel> UnpartitionedTestingChannel(
|
||||
const GlobalObject& aGlobal, const nsAString& aChannel, ErrorResult& aRv);
|
||||
|
||||
void GetName(nsAString& aName) const { aName = mChannel; }
|
||||
|
||||
void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
|
||||
@@ -12,6 +12,12 @@ interface BroadcastChannel : EventTarget {
|
||||
[Throws]
|
||||
constructor(DOMString channel);
|
||||
|
||||
// This function is for simplifying tests that need to coordinate between
|
||||
// top-level and third-party documents from the same origin.
|
||||
// This will throw if called outside of automation.
|
||||
[ChromeOnly,Throws]
|
||||
static BroadcastChannel unpartitionedTestingChannel(DOMString channel);
|
||||
|
||||
readonly attribute DOMString name;
|
||||
|
||||
[Throws]
|
||||
|
||||
Reference in New Issue
Block a user