Title: [285503] trunk
Revision
285503
Author
cdu...@apple.com
Date
2021-11-09 09:49:37 -0800 (Tue, 09 Nov 2021)

Log Message

Ignore BroadcastChannel::postMessage from detached iframe / closing worker contexts
https://bugs.webkit.org/show_bug.cgi?id=232693

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Resync BroadcastChannel WPT tests from upstream to gain test coverage.

* web-platform-tests/webmessaging/broadcastchannel/basics.any.serviceworker.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/cross-origin-expected.txt: Added.
* web-platform-tests/webmessaging/broadcastchannel/cross-origin.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/detached-iframe-expected.txt: Added.
* web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/ordering-expected.txt: Added.
* web-platform-tests/webmessaging/broadcastchannel/ordering.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js: Added.
* web-platform-tests/webmessaging/broadcastchannel/resources/w3c-import.log:
* web-platform-tests/webmessaging/broadcastchannel/resources/worker.js:
(handler):
* web-platform-tests/webmessaging/broadcastchannel/service-worker.https-expected.txt: Added.
* web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html: Added.
* web-platform-tests/webmessaging/broadcastchannel/w3c-import.log:
* web-platform-tests/webmessaging/broadcastchannel/workers-expected.txt:
* web-platform-tests/webmessaging/broadcastchannel/workers.html:

Source/WebCore:

Ignore BroadcastChannel::postMessage from detached iframe / closing worker contexts:
- https://html.spec.whatwg.org/#eligible-for-messaging

Tests: imported/w3c/web-platform-tests/webmessaging/broadcastchannel/basics.any.serviceworker.html
       imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html
       imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html
       imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html
       imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html

* dom/BroadcastChannel.cpp:
(WebCore::BroadcastChannel::postMessage):
(WebCore::BroadcastChannel::dispatchMessage):
(WebCore::BroadcastChannel::isEligibleForMessaging const):
* dom/BroadcastChannel.h:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-11-09 17:49:37 UTC (rev 285503)
@@ -1,3 +1,31 @@
+2021-11-09  Chris Dumez  <cdu...@apple.com>
+
+        Ignore BroadcastChannel::postMessage from detached iframe / closing worker contexts
+        https://bugs.webkit.org/show_bug.cgi?id=232693
+
+        Reviewed by Darin Adler.
+
+        Resync BroadcastChannel WPT tests from upstream to gain test coverage.
+
+        * web-platform-tests/webmessaging/broadcastchannel/basics.any.serviceworker.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/cross-origin-expected.txt: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/cross-origin.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/detached-iframe-expected.txt: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/ordering-expected.txt: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/ordering.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/resources/w3c-import.log:
+        * web-platform-tests/webmessaging/broadcastchannel/resources/worker.js:
+        (handler):
+        * web-platform-tests/webmessaging/broadcastchannel/service-worker.https-expected.txt: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html: Added.
+        * web-platform-tests/webmessaging/broadcastchannel/w3c-import.log:
+        * web-platform-tests/webmessaging/broadcastchannel/workers-expected.txt:
+        * web-platform-tests/webmessaging/broadcastchannel/workers.html:
+
 2021-11-09  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, reverting r285488.

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin-expected.txt (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin-expected.txt	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,4 @@
+
+
+PASS Messages aren't delivered across origins
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src=""
+<script src=""
+<script src=""
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src=""
+<body>
+<script>
+
+const events = [];
+
+function testCompletion(t) {
+  return new Promise((resolve) => {
+    window.addEventListener("message", t.step_func(e => {
+      if (e.data == 'done') {
+        assert_equals(events.length, 0);
+        resolve();
+      }
+    }));
+  });
+}
+
+promise_test(async t => {
+
+  const bc0 = new BroadcastChannel('no-cross-origin-messages');
+  bc0._onmessage_ = e => {window.events.push(e);};
+
+  const testResults = testCompletion(t);
+  const url = "" +
+    '/webmessaging/broadcastchannel/resources/cross-origin.html';
+  await with_iframe(url);
+
+  return testResults;
+}, "Messages aren't delivered across origins");
+
+</script>
+</body>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe-expected.txt (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe-expected.txt	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,8 @@
+
+PASS BroadcastChannel messages from detached iframe to parent should be ignored (BC created before detaching)
+PASS BroadcastChannel messages from detached iframe to parent should be ignored (BC created after detaching)
+PASS BroadcastChannel messages from parent to detached iframe should be ignored (BC created before detaching)
+PASS BroadcastChannel messages from parent to detached iframe should be ignored (BC created after detaching)
+PASS BroadcastChannel messages within detached iframe should be ignored (BCs created before detaching)
+PASS BroadcastChannel messages within detached iframe should be ignored (BCs created after detaching)
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src=""
+<script src=""
+<script src=""
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src=""
+<body>
+<script>
+const TEST_IFRAME_CLASS_NAME = 'test-iframe';
+const events = [];
+var bc1;
+const DONE_MSG = 'done';
+
+function DetachedIframeTestCheckForOneMessage(t) {
+  return new Promise((resolve) => {
+    bc1._onmessage_ = t.step_func(e => {
+      events.push(e);
+      if (e.data == DONE_MSG) {
+        assert_equals(events.length, 1);
+        resolve();
+      }
+    });
+  });
+}
+
+const IframeAction = {
+  REMOVE_BEFORE_CREATION: 'remove-before-creation',
+  REMOVE_AFTER_CREATION: 'remove-after-creation',
+};
+
+async function doMessageSentTest(t, channelName, action) {
+  await with_iframe('about:blank');
+  const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+  const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+  if (action ="" IframeAction.REMOVE_BEFORE_CREATION) {
+    iframe.remove();
+  }
+
+  events.length = 0;
+
+  bc1 = new BroadcastChannel(channelName);
+  const bc2 = new BroadcastChannel(channelName);
+  const iframe_bc = new iframe_BroadcastChannel(channelName);
+
+  if (action ="" IframeAction.REMOVE_AFTER_CREATION) {
+    iframe.remove();
+  }
+
+  const testResultsPromise = DetachedIframeTestCheckForOneMessage(t);
+
+  iframe_bc.postMessage('test');
+  bc2.postMessage(DONE_MSG);
+
+  bc2.close();
+  iframe_bc.close();
+  t.add_cleanup(() => bc1.close());
+
+  return testResultsPromise;
+}
+
+promise_test(async t => {
+  return doMessageSentTest(
+      t, 'postMessage-from-detached-iframe-pre',
+      IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created before detaching)');
+
+promise_test(async t => {
+  return doMessageSentTest(
+      t, 'postMessage-from-detached-iframe-post',
+      IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created after detaching)');
+
+
+async function doMessageReceivedTest(t, channelName, action) {
+  await with_iframe('about:blank');
+  const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+  const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+  if (action ="" IframeAction.REMOVE_BEFORE_CREATION) {
+    iframe.remove();
+  }
+
+  events.length = 0;
+
+  // `iframe_bc` must be created first so that it receives messages before
+  // `bc1`. That way we can tell whether `iframe_bc` received a message by
+  // inspecting `events` in the `bc1` message handler.
+  const iframe_bc = new iframe_BroadcastChannel(channelName);
+  iframe_bc._onmessage_ = e => {
+    events.push(e)
+  };
+  bc1 = new BroadcastChannel(channelName);
+  const bc2 = new BroadcastChannel(channelName);
+
+  if (action ="" IframeAction.REMOVE_AFTER_CREATION) {
+    iframe.remove();
+  }
+
+  const testResultsPromise = DetachedIframeTestCheckForOneMessage(t);
+  bc2.postMessage(DONE_MSG);
+
+  bc2.close();
+  iframe_bc.close();
+  t.add_cleanup(() => bc1.close());
+}
+
+promise_test(async t => {
+  return doMessageReceivedTest(
+      t, 'postMessage-to-detached-iframe-pre',
+      IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created before detaching)');
+
+promise_test(async t => {
+  return doMessageReceivedTest(
+      t, 'postMessage-to-detached-iframe-post',
+      IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created after detaching)');
+
+
+async function doMessageSendReceiveTest(t, channelName, action) {
+  await with_iframe('about:blank');
+  const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+  const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+  if (action ="" IframeAction.REMOVE_BEFORE_CREATION) {
+    iframe.remove();
+  }
+
+  const iframe_bc1 = new iframe_BroadcastChannel(channelName);
+  const iframe_bc2 = new iframe_BroadcastChannel(channelName);
+  iframe_bc1._onmessage_ = t.unreached_func(
+      'Detached iframe BroadcastChannel instance received message unexpectedly');
+
+  if (action ="" IframeAction.REMOVE_AFTER_CREATION) {
+    iframe.remove();
+  }
+
+  iframe_bc2.postMessage(DONE_MSG);
+
+  iframe_bc2.close();
+  t.add_cleanup(() => iframe_bc1.close());
+
+  // To avoid calling t.step_timeout here, instead just create two new
+  // BroadcastChannel instances and complete the test when a message is passed
+  // between them.  Per the spec, all "BroadcastChannel objects whose relevant
+  // agents are the same" must have messages delivered to them in creation
+  // order, so if we get this message then it's safe to assume the earlier
+  // message would have been delivered if it was going to be.
+  const bc1 = new BroadcastChannel(channelName);
+  const bc2 = new BroadcastChannel(channelName);
+  return new Promise((resolve) => {
+    bc1._onmessage_ = t.step_func(e => {
+      resolve();
+    });
+    bc2.postMessage(DONE_MSG);
+  });
+}
+
+promise_test(async t => {
+  return doMessageSendReceiveTest(
+      t, 'postMessage-within-detached-iframe-pre',
+      IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created before detaching)');
+
+promise_test(async t => {
+  return doMessageSendReceiveTest(
+      t, 'postMessage-within-detached-iframe-post',
+      IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created after detaching)');
+
+</script>
+</body>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering-expected.txt (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering-expected.txt	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,4 @@
+
+
+PASS Messages are delivered in port creation order across multiple frames
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src=""
+<script src=""
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src=""
+<body>
+<script>
+
+const BC0_FIRST_MSG = 'from BC0 - first';
+const BC1_FIRST_MSG = 'from BC1 - first';
+const BC2_FIRST_MSG = 'from BC2 - first';
+const BC3_FIRST_MSG = 'from BC3 - first';
+const BC0_SECOND_MSG = 'from BC0 - second';
+const BC1_SECOND_MSG = 'from BC1 - second';
+const BC2_SECOND_MSG = 'from BC2 - second';
+const BC3_SECOND_MSG = 'done';
+const BC0_TARGET_NAME = 'BC1';
+const BC1_TARGET_NAME = 'BC1';
+const BC2_TARGET_NAME = 'BC2';
+const BC3_TARGET_NAME = 'BC3';
+const MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME = 'multi-frame-order';
+
+const bc0 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+const messages = [];
+
+function logReceivedMessage(targetname, e) {
+  messages.push({'target': targetname, 'data': e.data});
+}
+
+function postMessagesToChannel() {
+  return new Promise((resolve) => {
+    bc0.postMessage(BC0_FIRST_MSG);
+    bc0.postMessage(BC0_SECOND_MSG);
+    resolve();
+  });
+}
+
+// Expected flow of messages between the BroadcastChannel objects (based on
+// the requirement that messages get delivered to BroadcastChannel objects
+// "in creation order, oldest first") and comments describing the actions
+// taken in response to each event
+const EXPECTED_RESULTS = [
+  // -> BC0 sends two messages, BC1 and BC2 are connected to the channel
+
+  {'data': BC0_FIRST_MSG, 'target': BC1_TARGET_NAME},
+  // -> BC1 Creates BC3 and sends first message
+
+  {'data': BC0_FIRST_MSG, 'target': BC2_TARGET_NAME},
+  // -> BC2 sends two messages
+
+  // BC3 isn't expected to receive the messages sent before it was created, so
+  // no corresponding entries here for messages from BC0.
+
+  {'data': BC0_SECOND_MSG, 'target': BC1_TARGET_NAME},
+  // -> BC1 sends second message
+
+  {'data': BC0_SECOND_MSG, 'target': BC2_TARGET_NAME},
+  // -> BC2 closes
+
+  {'data': BC1_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+  {'data': BC1_FIRST_MSG, 'target': BC3_TARGET_NAME},
+  // -> BC3 sends first message
+
+  {'data': BC2_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+  {'data': BC2_FIRST_MSG, 'target': BC1_TARGET_NAME},
+  // -> BC1 closes
+
+  {'data': BC2_FIRST_MSG, 'target': BC3_TARGET_NAME},
+  // -> BC3 sends second message
+
+  {'data': BC2_SECOND_MSG, 'target': BC0_TARGET_NAME},
+
+  {'data': BC2_SECOND_MSG, 'target': BC3_TARGET_NAME},
+  // -> BC3 closes
+
+  {'data': BC1_SECOND_MSG, 'target': BC0_TARGET_NAME},
+
+  {'data': BC3_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+  {'data': BC3_SECOND_MSG, 'target': BC0_TARGET_NAME},
+];
+
+function testCompletion(t) {
+  return new Promise((resolve) => {
+    bc0._onmessage_ = t.step_func(e => {
+      logReceivedMessage(BC0_TARGET_NAME, e);
+      if (e.data == BC3_SECOND_MSG) {
+        assert_equals(messages.length, EXPECTED_RESULTS.length);
+        for(var i = 0; i < messages.length; i++) {
+          assert_equals(messages[i].target, EXPECTED_RESULTS[i].target, `Message ${i+1} has unexpected target`);
+          assert_equals(messages[i].data, EXPECTED_RESULTS[i].data, `Message ${i+1} has unexpected message contents`);
+        }
+        resolve();
+      }
+    });
+  });
+}
+
+promise_test(async t => {
+
+  const testResults = testCompletion(t);
+  // Await them sequentially because we need the BroadcastChannel object in
+  // iframe1 to be created first, we need the BroadcastChannel object in
+  // iframe2 to be created second, and then we only want to call
+  // postMessagesToChannel once both BroadcastChannels have been created.
+  await with_iframe('resources/ordering.html?id=iframe1');
+  await with_iframe('resources/ordering.html?id=iframe2');
+  await postMessagesToChannel();
+  return testResults;
+}, "Messages are delivered in port creation order across multiple frames");
+
+</script>
+</body>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,15 @@
+<body></body>
+<script>
+  window._onload_ = function() {
+    bc1 = new BroadcastChannel('no-cross-origin-messages');
+    bc2 = new BroadcastChannel('no-cross-origin-messages');
+    bc2._onmessage_ = e => {
+      parent.postMessage('done', "*");
+    };
+    // Post a message on bc1 and once we receive it in bc2, we know that the
+    // message should have been sent to bc0 if messages were being passed
+    // across origin (assuming compliance with the spec regarding message
+    // delivery in port creation order).
+    bc1.postMessage('ignition');
+  }
+</script>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,78 @@
+<body></body>
+<script>
+  const BC0_FIRST_MSG = 'from BC0 - first';
+  const BC1_FIRST_MSG = 'from BC1 - first';
+  const BC2_FIRST_MSG = 'from BC2 - first';
+  const BC3_FIRST_MSG = 'from BC3 - first';
+  const BC0_SECOND_MSG = 'from BC0 - second';
+  const BC1_SECOND_MSG = 'from BC1 - second';
+  const BC2_SECOND_MSG = 'from BC2 - second';
+  const BC3_SECOND_MSG = 'done';
+  const BC0_TARGET_NAME = 'BC1';
+  const BC1_TARGET_NAME = 'BC1';
+  const BC2_TARGET_NAME = 'BC2';
+  const BC3_TARGET_NAME = 'BC3';
+  const MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME = 'multi-frame-order';
+
+  var bc1, bc2, bc3;
+  var sentMessageCountForBc1 = 0;
+  var sentMessageCountForBc2 = 0;
+  var sentMessageCountForBc3 = 0;
+
+  var bc1_handler = e => {
+    window.top.logReceivedMessage(BC1_TARGET_NAME, e);
+    switch(sentMessageCountForBc1) {
+      case 0:
+        bc3 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+        bc3._onmessage_ = bc3_handler;
+        bc1.postMessage(BC1_FIRST_MSG);
+        break;
+      case 1:
+        bc1.postMessage(BC1_SECOND_MSG);
+        break;
+      case 2:
+        bc1.close();
+        return;
+    }
+    sentMessageCountForBc1 += 1;
+  }
+  var bc2_handler = e => {
+    window.top.logReceivedMessage(BC2_TARGET_NAME, e);
+    switch(sentMessageCountForBc2) {
+      case 0:
+        bc2.postMessage(BC2_FIRST_MSG);
+        bc2.postMessage(BC2_SECOND_MSG);
+        sentMessageCountForBc2 += 2;
+        break;
+      case 2:
+        bc2.close();
+        return;
+    }
+  };
+  var bc3_handler = e => {
+    window.top.logReceivedMessage(BC3_TARGET_NAME, e);
+    switch(sentMessageCountForBc3) {
+      case 0:
+        bc3.postMessage(BC3_FIRST_MSG);
+        break;
+      case 1:
+        bc3.postMessage(BC3_SECOND_MSG);
+        break;
+      case 2:
+        bc3.close();
+        return;
+    }
+    sentMessageCountForBc3 += 1;
+  };
+
+  window._onload_ = function() {
+    const params = new URLSearchParams(window.location.search);
+    if (params.get('id') === 'iframe1') {
+      bc1 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+      bc1._onmessage_ = bc1_handler;
+    } else if (params.get('id')  === 'iframe2') {
+      bc2 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+      bc2._onmessage_ = bc2_handler;
+    }
+  }
+</script>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,15 @@
+let promise_func = null;
+let promise = new Promise(resolve => promise_func = resolve);
+
+const SERVICE_WORKER_TEST_CHANNEL_NAME = 'service worker';
+const bc3 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+bc3._onmessage_ = e => {
+  bc3.postMessage('done');
+  promise_func();
+};
+bc3.postMessage('from worker');
+
+// Ensure that the worker stays alive for the duration of the test
+self.addEventListener('install', evt => {
+  evt.waitUntil(promise);
+});

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/w3c-import.log (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/w3c-import.log	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/w3c-import.log	2021-11-09 17:49:37 UTC (rev 285503)
@@ -14,6 +14,9 @@
 None
 ------------------------------------------------------------------------
 List of files:
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/cross-origin.html
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/ordering.html
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/origin.html
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/sandboxed.html
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/service-worker.js
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/worker.js

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/worker.js (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/worker.js	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/resources/worker.js	2021-11-09 17:49:37 UTC (rev 285503)
@@ -16,6 +16,12 @@
   c = new BroadcastChannel(e.data.channel);
   let messages = [];
   c._onmessage_ = e => {
+      if (e.data ="" 'ready') {
+        // Ignore any 'ready' messages from the other thread since there could
+        // be some race conditions between this BroadcastChannel instance
+        // being created / ready to receive messages and the message being sent.
+        return;
+      }
       messages.push(e.data);
       if (e.data == 'done')
         reply(messages);

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https-expected.txt (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https-expected.txt	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,3 @@
+
+FAIL BroadcastChannel works in service workers promise_test: Unhandled rejection with value: object "TypeError: ReferenceError: Can't find variable: BroadcastChannel"
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html (0 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src=""
+<script src=""
+<script>
+
+const SERVICE_WORKER_TEST_CHANNEL_NAME = 'service worker';
+const events = [];
+const c1 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+const c2 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+c1._onmessage_ = e => events.push(e);
+c2._onmessage_ = e => events.push(e);
+
+function testCompletion(t) {
+  return new Promise((resolve) => {
+    c2.addEventListener("message", t.step_func(e => {
+      if (e.data == 'from worker') {
+        c2.postMessage('from c2');
+      } else if (e.data == 'done') {
+        assert_equals(events.length, 5);
+        assert_equals(events[0].data, 'from worker');
+        assert_equals(events[0].target, c1);
+        assert_equals(events[1].data, 'from worker');
+        assert_equals(events[1].target, c2);
+        assert_equals(events[2].data, 'from c2');
+        assert_equals(events[3].data, 'done');
+        assert_equals(events[3].target, c1);
+        assert_equals(events[4].data, 'done');
+        assert_equals(events[4].target, c2);
+        resolve();
+      }
+    }));
+  });
+}
+
+promise_test(async t => {
+
+    const testResults = testCompletion(t);
+    const SCRIPT = "resources/service-worker.js";
+    const SCOPE = "/webmessaging/broadcastchannel/resources/not-used/";
+
+    const reg = await navigator.serviceWorker.register(SCRIPT, {'scope': SCOPE});
+    t.add_cleanup(() => reg.unregister());
+
+    return testResults;
+  }, 'BroadcastChannel works in service workers');
+</script>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/w3c-import.log (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/w3c-import.log	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/w3c-import.log	2021-11-09 17:49:37 UTC (rev 285503)
@@ -16,7 +16,11 @@
 List of files:
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/basics.any.js
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/blobs.html
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/interface.any.js
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/origin.window.js
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/sandbox.html
+/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html
 /LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers.html

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers-expected.txt (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers-expected.txt	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers-expected.txt	2021-11-09 17:49:37 UTC (rev 285503)
@@ -3,5 +3,10 @@
 FAIL BroadcastChannel works in shared workers null is not an object (evaluating 'worker.port')
 PASS Closing and re-opening a channel works.
 PASS BroadcastChannel created after a worker self.close()
-PASS BroadcastChannel used after a worker self.close()
+PASS BroadcastChannel messages from closed worker to parent should be ignored (BC created before closing)
+PASS BroadcastChannel messages from closed worker to parent should be ignored (BC created after closing)
+PASS BroadcastChannel messages from parent to closed worker should be ignored (BC created before closing)
+PASS BroadcastChannel messages from parent to closed worker should be ignored (BC created after closing)
+PASS BroadcastChannel messages within closed worker should be ignored (BCs created before closing)
+PASS BroadcastChannel messages within closed worker should be ignored (BCs created after closing)
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers.html (285502 => 285503)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers.html	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webmessaging/broadcastchannel/workers.html	2021-11-09 17:49:37 UTC (rev 285503)
@@ -80,11 +80,14 @@
 
     let worker = new Worker('resources/worker.js');
     worker._onmessage_ = t.step_func(e => {
-        assert_array_equals(events, ['c1: from worker', 'c2: echo'],
+        assert_array_equals(events,
+                            ['c1: from worker', 'c2: ready', 'c2: echo'],
                             'messages in document');
         assert_array_equals(e.data, ['done'], 'messages in worker');
         t.done();
       });
+    worker._onmessagerror_ =
+        t.unreached_func('Worker\'s onmessageerror handler called');
 
     c.addEventListener('message', e => {
         if (e.data == 'from worker') {
@@ -94,14 +97,29 @@
               let c2 = new BroadcastChannel('worker-close');
               c2._onmessage_ = e => {
                   events.push('c2: ' + e.data);
-                  c2.postMessage('done');
+                  if (e.data ="" 'ready') {
+                    worker.postMessage({ping: 'echo'});
+                  } else {
+                    c2.postMessage('done');
+                    c2.close();
+                  }
                 };
-              worker.postMessage({ping: 'echo'});
+              // For some implementations there may be a race condition between
+              // when the BroadcastChannel instance above is created / ready to
+              // receive messages and when the worker calls postMessage on it's
+              // BroadcastChannel instance. To avoid this, confirm that our
+              // instance can receive a message before indicating to the other
+              // thread that we are ready. For more details, see:
+              // https://github.com/whatwg/html/issues/7267
+              let c3 = new BroadcastChannel('worker-close');
+              c3.postMessage('ready');
+              c3.close();
             }, 1);
         }
       });
 
     worker.postMessage({channel: 'worker-close'});
+    t.add_cleanup(() => worker.terminate());
 
   }, 'Closing and re-opening a channel works.');
 
@@ -108,34 +126,250 @@
 async_test(t => {
   function workerCode() {
     close();
-    var bc = new BroadcastChannel('worker-test');
+    try {
+      var bc = new BroadcastChannel('worker-create-after-close');
+    } catch (e) {
+      postMessage(e);
+      return;
+    }
     postMessage(true);
   }
 
-  var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], {type:"application/_javascript_"});
+  var workerBlob = new Blob(
+      [workerCode.toString() + ';workerCode();'],
+      {type: 'application/_javascript_'});
 
   var w = new Worker(URL.createObjectURL(workerBlob));
-  w._onmessage_ = function(e) {
-    assert_true(e.data, "BroadcastChannel created on worker shutdown.");
-    t.done();
-  }
+  w._onmessage_ = t.step_func_done(function(e) {
+    assert_equals(
+        e.data, true,
+        'BroadcastChannel creation in closed worker triggered exception: ' +
+            e.data.message);
+  });
+  t.add_cleanup(() => w.terminate());
 }, 'BroadcastChannel created after a worker self.close()');
 
-async_test(t => {
-  function workerCode() {
+
+function postMessageFromWorkerWorkerCode(workerName, channelName) {
+  if (workerName === 'close-before-create-worker') {
     close();
-    var bc = new BroadcastChannel('worker-test-after-close');
-    bc.postMessage(true);
   }
+  let bc = new BroadcastChannel(channelName);
+  if (workerName === 'close-after-create-worker') {
+    close();
+  }
+  bc.postMessage(workerName + ' done');
+  postMessage(true);
+}
 
-  var bc = new BroadcastChannel('worker-test-after-close');
-  bc._onmessage_ = function(e) {
-    assert_true(e.data, "BroadcastChannel created on worker shutdown.");
-    t.done();
+function doPostMessageFromWorkerTest(t, workerName, channelName) {
+  var bc = new BroadcastChannel(channelName);
+  bc._onmessage_ = t.step_func_done(function(e) {
+    assert_equals(
+        e.data, 'done-worker done',
+        'BroadcastChannel message should only be received from the second worker');
+  });
+  t.add_cleanup(() => bc.close());
+
+  var testMessageHandler = t.step_func(function(e) {
+    assert_equals(
+        e.data, true,
+        'Worker sent postMessage indicating it sent a BroadcastChannel message');
+
+    var w = createWorker(
+        postMessageFromWorkerWorkerCode, 'done-worker', channelName);
+    t.add_cleanup(() => w.terminate());
+  });
+  createWorker(
+      postMessageFromWorkerWorkerCode, workerName, channelName,
+      testMessageHandler);
+
+  // To avoid calling t.step_timeout here, have the worker postMessage(true)
+  // once it is finished and then we'll instantiate another worker that
+  // performs the same test steps but doesn't close. By the time the
+  // BroadcastChannel message in that worker gets sent successfully it should
+  // be safe to assume that any BroadcastChannel messages from the previous
+  // worker would have been sent if they were going to be.
+}
+
+function createWorker(workerCode, workerName, channelName, handler = null) {
+  var workerCodeStr = workerCode.toString() +
+      `;${workerCode.name}("${workerName}", "${channelName}");`;
+  var workerBlob = new Blob([workerCodeStr], {type: 'application/_javascript_'});
+  var w = new Worker(URL.createObjectURL(workerBlob));
+  if (handler !== null) {
+    w._onmessage_ = handler;
   }
+  return w;
+}
 
-  var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], {type:"application/_javascript_"});
-  new Worker(URL.createObjectURL(workerBlob));
-}, 'BroadcastChannel used after a worker self.close()');
+async_test(t => {
+  const workerName = 'close-after-create-worker';
+  const channelName = workerName + '-postmessage-from-worker';
+  doPostMessageFromWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from closed worker to parent should be ignored (BC created before closing)');
 
+async_test(t => {
+  const workerName = 'close-before-create-worker';
+  const channelName = workerName + '-postmessage-from-worker';
+  doPostMessageFromWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from closed worker to parent should be ignored (BC created after closing)');
+
+
+function postMessageToWorkerWorkerCode(workerName, channelName) {
+  self.addEventListener('message', () => {
+    if (workerName === 'close-before-create-worker') {
+      close();
+    }
+    try {
+      let bc1 = new BroadcastChannel(channelName);
+      bc1._onmessage_ = e => {
+        if (e.data ="" 'ready') {
+          postMessage(e.data);
+        } else if (e.data ="" 'test') {
+          postMessage(workerName + ' done');
+        }
+      };
+      bc1._onmessageerror_ = () => {
+        postMessage('onmessageerror called from worker BroadcastChannel');
+      };
+      if (workerName === 'close-after-create-worker') {
+        close();
+      }
+    } catch (e) {
+      postMessage(e);
+      return;
+    }
+
+    if (workerName === 'done-worker') {
+      // For some implementations there may be a race condition between when
+      // the BroadcastChannel instance above is created / ready to receive
+      // messages and when the parent calls postMessage on it's
+      // BroadcastChannel instance. To avoid this, confirm that our instance
+      // can receive a message before indicating to the other thread that we
+      // are ready. For more details, see:
+      // https://github.com/whatwg/html/issues/7267
+      let bc2 = new BroadcastChannel(channelName);
+      bc2.postMessage('ready');
+      bc2.close();
+    } else {
+      // Since the worker has closed, it's not expected that the
+      // BroadcastChannel will receive messages (there's a separate test for
+      // that), so just indicate directly that it's ready to test receiving
+      // a message from the parent dispite the possibility of a race condition.
+      postMessage('ready');
+    }
+  });
+  self.addEventListener('messageerror', () => {
+    postMessage('onmessageerror called from worker');
+  });
+}
+
+function doPostMessageToWorkerTest(t, workerName, channelName) {
+  var bc = new BroadcastChannel(channelName);
+  t.add_cleanup(() => bc.close());
+
+  var doneMessageHandler = t.step_func(function(e) {
+    if (e.data ="" 'ready') {
+      bc.postMessage('test');
+    } else if (e.data ="" 'done-worker done') {
+      t.done();
+    } else {
+      assert_unreached(
+          'BroadcastChannel.postMessage triggered exception within second worker: ' +
+          e.data.message);
+    }
+  });
+  var testMessageHandler = t.step_func(function(e) {
+    assert_equals(
+        e.data, 'ready',
+        'Worker sent postMessage indicating its BroadcastChannel instance is ready');
+    bc.postMessage('test');
+
+    var doneWorker = createWorker(
+        postMessageToWorkerWorkerCode, 'done-worker', channelName,
+        doneMessageHandler);
+    t.add_cleanup(() => {
+      doneWorker.terminate();
+    });
+    doneWorker.postMessage('start');
+  });
+  var testWorker = createWorker(
+      postMessageToWorkerWorkerCode, workerName, channelName,
+      testMessageHandler);
+  testWorker.postMessage('start');
+}
+
+async_test(t => {
+  const workerName = 'close-after-create-worker';
+  const channelName = workerName + '-postmessage-to-worker';
+  doPostMessageToWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from parent to closed worker should be ignored (BC created before closing)');
+
+async_test(t => {
+  const workerName = 'close-before-create-worker';
+  const channelName = workerName + '-postmessage-to-worker';
+  doPostMessageToWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from parent to closed worker should be ignored (BC created after closing)');
+
+
+function postMessageWithinWorkerWorkerCode(workerName, channelName) {
+  if (workerName === 'close-before-create-worker') {
+    close();
+  }
+  try {
+    let bc1 = new BroadcastChannel(channelName);
+    let bc2 = new BroadcastChannel(channelName);
+    bc1._onmessage_ = e => {
+      postMessage(workerName + ' done')
+    };
+    if (workerName === 'close-after-create-worker') {
+      close();
+    }
+    bc2.postMessage(true);
+    postMessage(true);
+  } catch (e) {
+    postMessage(e);
+  }
+}
+
+function doPostMessageWithinWorkerTest(t, workerName, channelName) {
+  var doneMessageHandler = t.step_func(function(e) {
+    if (e.data ="" true) {
+      // Done worker has finished - no action needed
+    } else if (e.data ="" 'done-worker done') {
+      t.done();
+    } else {
+      assert_unreached(
+          'BroadcastChannel.postMessage triggered exception within second worker: ' +
+          e.data.message);
+    }
+  });
+  var testMessageHandler = t.step_func(function(e) {
+    assert_equals(
+        e.data, true,
+        'Worker indicated that the test procedures were executed successfully');
+
+    var w = createWorker(
+        postMessageWithinWorkerWorkerCode, 'done-worker', channelName,
+        doneMessageHandler);
+    t.add_cleanup(() => w.terminate());
+  });
+  createWorker(
+      postMessageWithinWorkerWorkerCode, workerName, channelName,
+      testMessageHandler);
+}
+
+async_test(t => {
+  const workerName = 'close-after-create-worker';
+  const channelName = workerName + '-postmessage-within-worker';
+  doPostMessageWithinWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages within closed worker should be ignored (BCs created before closing)');
+
+async_test(t => {
+  const workerName = 'close-before-create-worker';
+  const channelName = workerName + '-postmessage-within-worker';
+  doPostMessageWithinWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages within closed worker should be ignored (BCs created after closing)');
+
 </script>

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (285502 => 285503)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2021-11-09 17:49:37 UTC (rev 285503)
@@ -387,6 +387,7 @@
 imported/w3c/web-platform-tests/web-locks/secure-context.tentative.https.any.serviceworker.html [ Skip ]
 imported/w3c/web-platform-tests/web-locks/signal.tentative.https.any.serviceworker.html [ Skip ]
 imported/w3c/web-platform-tests/web-locks/steal.tentative.https.any.serviceworker.html [ Skip ]
+imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/animation-worklet-service-worker-interception.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/audio-worklet-service-worker-interception.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/layout-worklet-service-worker-interception.https.html [ Skip ]

Modified: trunk/LayoutTests/platform/win/TestExpectations (285502 => 285503)


--- trunk/LayoutTests/platform/win/TestExpectations	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/LayoutTests/platform/win/TestExpectations	2021-11-09 17:49:37 UTC (rev 285503)
@@ -3756,6 +3756,7 @@
 imported/w3c/web-platform-tests/web-locks/secure-context.tentative.https.any.serviceworker.html [ Skip ]
 imported/w3c/web-platform-tests/web-locks/signal.tentative.https.any.serviceworker.html [ Skip ]
 imported/w3c/web-platform-tests/web-locks/steal.tentative.https.any.serviceworker.html [ Skip ]
+imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/animation-worklet-service-worker-interception.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/audio-worklet-service-worker-interception.https.html [ Skip ]
 imported/w3c/web-platform-tests/worklets/layout-worklet-service-worker-interception.https.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (285502 => 285503)


--- trunk/Source/WebCore/ChangeLog	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/Source/WebCore/ChangeLog	2021-11-09 17:49:37 UTC (rev 285503)
@@ -1,3 +1,25 @@
+2021-11-09  Chris Dumez  <cdu...@apple.com>
+
+        Ignore BroadcastChannel::postMessage from detached iframe / closing worker contexts
+        https://bugs.webkit.org/show_bug.cgi?id=232693
+
+        Reviewed by Darin Adler.
+
+        Ignore BroadcastChannel::postMessage from detached iframe / closing worker contexts:
+        - https://html.spec.whatwg.org/#eligible-for-messaging
+
+        Tests: imported/w3c/web-platform-tests/webmessaging/broadcastchannel/basics.any.serviceworker.html
+               imported/w3c/web-platform-tests/webmessaging/broadcastchannel/cross-origin.html
+               imported/w3c/web-platform-tests/webmessaging/broadcastchannel/detached-iframe.html
+               imported/w3c/web-platform-tests/webmessaging/broadcastchannel/ordering.html
+               imported/w3c/web-platform-tests/webmessaging/broadcastchannel/service-worker.https.html
+
+        * dom/BroadcastChannel.cpp:
+        (WebCore::BroadcastChannel::postMessage):
+        (WebCore::BroadcastChannel::dispatchMessage):
+        (WebCore::BroadcastChannel::isEligibleForMessaging const):
+        * dom/BroadcastChannel.h:
+
 2021-11-09  Ziran Sun  <z...@igalia.com>
 
         [css-grid] update the content-sized grid width before laying out a grid item with block constraints and aspect-ratio

Modified: trunk/Source/WebCore/dom/BroadcastChannel.cpp (285502 => 285503)


--- trunk/Source/WebCore/dom/BroadcastChannel.cpp	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/Source/WebCore/dom/BroadcastChannel.cpp	2021-11-09 17:49:37 UTC (rev 285503)
@@ -180,6 +180,9 @@
 
 ExceptionOr<void> BroadcastChannel::postMessage(JSC::JSGlobalObject& globalObject, JSC::JSValue message)
 {
+    if (!isEligibleForMessaging())
+        return { };
+
     if (m_isClosed)
         return Exception { InvalidStateError, "This BroadcastChannel is closed" };
 
@@ -225,6 +228,9 @@
 
 void BroadcastChannel::dispatchMessage(Ref<SerializedScriptValue>&& message)
 {
+    if (!isEligibleForMessaging())
+        return;
+
     if (m_isClosed)
         return;
 
@@ -249,4 +255,17 @@
     return !m_isClosed && m_hasRelevantEventListener;
 }
 
+// https://html.spec.whatwg.org/#eligible-for-messaging
+bool BroadcastChannel::isEligibleForMessaging() const
+{
+    auto* context = scriptExecutionContext();
+    if (!context)
+        return false;
+
+    if (is<Document>(*context))
+        return downcast<Document>(*context).isFullyActive();
+
+    return !downcast<WorkerGlobalScope>(*context).isClosing();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/BroadcastChannel.h (285502 => 285503)


--- trunk/Source/WebCore/dom/BroadcastChannel.h	2021-11-09 16:58:33 UTC (rev 285502)
+++ trunk/Source/WebCore/dom/BroadcastChannel.h	2021-11-09 17:49:37 UTC (rev 285503)
@@ -70,6 +70,8 @@
     void dispatchMessage(Ref<SerializedScriptValue>&&);
     void ensureOnMainThread(Function<void(Document&)>&&);
 
+    bool isEligibleForMessaging() const;
+
     // EventTarget
     EventTargetInterface eventTargetInterface() const final { return BroadcastChannelEventTargetInterfaceType; }
     ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to