summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js')
-rw-r--r--toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js198
1 files changed, 198 insertions, 0 deletions
diff --git a/toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js b/toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js
new file mode 100644
index 0000000000..11f53d69ed
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js
@@ -0,0 +1,198 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const FIRST_PARTY_A = "http://example.com";
+const FIRST_PARTY_B = "http://example.org";
+const THIRD_PARTY = "http://example.net";
+const WS_ENDPOINT_HOST = "mochi.test:8888";
+
+function getWSTestUrlForHost(host) {
+ return (
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ `ws://${host}`
+ ) + `file_ws_handshake_delay`
+ );
+}
+
+function connect(browsingContext, host, protocol) {
+ let url = getWSTestUrlForHost(host);
+ info("Creating websocket with endpoint " + url);
+
+ // Create websocket connection in third party iframe.
+ let createPromise = SpecialPowers.spawn(
+ browsingContext.children[0],
+ [url, protocol],
+ (url, protocol) => {
+ let ws = new content.WebSocket(url, [protocol]);
+ ws.addEventListener("error", () => {
+ ws._testError = true;
+ });
+ if (!content.ws) {
+ content.ws = {};
+ }
+ content.ws[protocol] = ws;
+ }
+ );
+
+ let openPromise = createPromise.then(() =>
+ SpecialPowers.spawn(
+ browsingContext.children[0],
+ [protocol],
+ async protocol => {
+ let ws = content.ws[protocol];
+ if (ws.readyState != 0) {
+ return !ws._testError;
+ }
+ // Still connecting.
+ let result = await Promise.race([
+ ContentTaskUtils.waitForEvent(ws, "open"),
+ ContentTaskUtils.waitForEvent(ws, "error"),
+ ]);
+ return result.type != "error";
+ }
+ )
+ );
+
+ let result = { createPromise, openPromise };
+ return result;
+}
+
+// Open 3 websockets which target the same ip/port combination, but have
+// different principals. We send a protocol identifier to the server to signal
+// how long the request should be delayed.
+//
+// When partitioning is disabled A blocks B and B blocks C. The timeline will
+// look like this:
+// A________
+// B____
+// C_
+//
+// When partitioning is enabled, connection handshakes for A and B will run
+// (semi-) parallel since they have different origin attributes. B and C share
+// origin attributes and therefore still run serially.
+// A________
+// B____
+// C_
+//
+// By observing the order of the handshakes we can ensure that the queue
+// partitioning is working correctly.
+async function runTest(partitioned) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["privacy.partition.network_state", partitioned]],
+ });
+
+ let tabA = BrowserTestUtils.addTab(gBrowser, FIRST_PARTY_A);
+ await BrowserTestUtils.browserLoaded(tabA.linkedBrowser);
+ let tabB = BrowserTestUtils.addTab(gBrowser, FIRST_PARTY_B);
+ await BrowserTestUtils.browserLoaded(tabB.linkedBrowser);
+
+ for (let tab of [tabA, tabB]) {
+ await SpecialPowers.spawn(tab.linkedBrowser, [THIRD_PARTY], async src => {
+ let frame = content.document.createElement("iframe");
+ frame.src = src;
+ let loadPromise = ContentTaskUtils.waitForEvent(frame, "load");
+ content.document.body.appendChild(frame);
+ await loadPromise;
+ });
+ }
+
+ // First ensure that we can open websocket connections to the test endpoint.
+ let { openPromise, createPromise } = await connect(
+ tabA.linkedBrowser.browsingContext,
+ WS_ENDPOINT_HOST,
+ false
+ );
+ await createPromise;
+ let openPromiseResult = await openPromise;
+ ok(openPromiseResult, "Websocket endpoint accepts connections.");
+
+ let openedA;
+ let openedB;
+ let openedC;
+
+ let { createPromise: createPromiseA, openPromise: openPromiseA } = connect(
+ tabA.linkedBrowser.browsingContext,
+ WS_ENDPOINT_HOST,
+ "test-6"
+ );
+
+ openPromiseA = openPromiseA.then(opened => {
+ openedA = opened;
+ info("Completed WS connection A");
+ if (partitioned) {
+ ok(openedA, "Should have opened A");
+ ok(openedB, "Should have opened B");
+ } else {
+ ok(openedA, "Should have opened A");
+ ok(openedB == null, "B should be pending");
+ }
+ });
+ await createPromiseA;
+
+ // The frame of connection B is embedded in a different first party as A.
+ let { createPromise: createPromiseB, openPromise: openPromiseB } = connect(
+ tabB.linkedBrowser.browsingContext,
+ WS_ENDPOINT_HOST,
+ "test-3"
+ );
+ openPromiseB = openPromiseB.then(opened => {
+ openedB = opened;
+ info("Completed WS connection B");
+ if (partitioned) {
+ ok(openedA == null, "A should be pending");
+ ok(openedB, "Should have opened B");
+ ok(openedC == null, "C should be pending");
+ } else {
+ ok(openedA, "Should have opened A");
+ ok(openedB, "Should have opened B");
+ ok(openedC == null, "C should be pending");
+ }
+ });
+ await createPromiseB;
+
+ // The frame of connection C is embedded in the same first party as B.
+ let { createPromise: createPromiseC, openPromise: openPromiseC } = connect(
+ tabB.linkedBrowser.browsingContext,
+ WS_ENDPOINT_HOST,
+ "test-0"
+ );
+ openPromiseC = openPromiseC.then(opened => {
+ openedC = opened;
+ info("Completed WS connection C");
+ if (partitioned) {
+ ok(openedB, "Should have opened B");
+ ok(openedC, "Should have opened C");
+ } else {
+ ok(opened, "Should have opened B");
+ ok(opened, "Should have opened C");
+ }
+ });
+ await createPromiseC;
+
+ // Wait for all connections to complete before closing the tabs.
+ await Promise.all([openPromiseA, openPromiseB, openPromiseC]);
+
+ BrowserTestUtils.removeTab(tabA);
+ BrowserTestUtils.removeTab(tabB);
+
+ await SpecialPowers.popPrefEnv();
+}
+
+add_setup(async function () {
+ // This test relies on a WS connection timeout > 6 seconds.
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.websocket.timeout.open", 20]],
+ });
+});
+
+add_task(async function test_non_partitioned() {
+ await runTest(false);
+});
+
+add_task(async function test_partitioned() {
+ await runTest(true);
+});