Bug 258674
| Summary: | BroadcastChannel inside cross-origin iframe doesn't work | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | Alejandro <saddy802> |
| Component: | WebCore Misc. | Assignee: | Nobody <webkit-unassigned> |
| Status: | RESOLVED WONTFIX | ||
| Severity: | Normal | CC: | cdumez |
| Priority: | P2 | ||
| Version: | Safari 16 | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
Alejandro
Steps to reproduce:
I have two sites with different origins. Let it be foo.com and bar.com. Site foo.com fires messages through BroadcastChannel with 'payment-info' name. I also have an iframe, hosted on foo.com which is built in bar.com. Here's iframe code:
<html><head><script type="text/javascript">
(function () {
const bc = new BroadcastChannel('payment-info');
bc.addEventListener('message', (m) => {
const data = JSON.parse(m.data);
data.channel = 'payment-info';
if (window.top !== window) {
window.top.postMessage(JSON.stringify(data), '*');
}
});
})();
</script></head><body></body></html>
So iframe subscribes to 'payment-info' broadcast channel and when it fires, iframe post a message to it's parent window aka bar.com with some information.
On bar.com side I just listen to 'message' event and call 'receiveMessage' function with JSON.parse
window.addEventListener('message', function (message) {
receiveMessage(message);
});
It's expected to work on my site bar.com in all browsers. It doesn't work in Safari and Firefox but works in Chrome.
I combined code from several files of index.html, index2.html and iframe.html which I used to test it locally. index.html and iframe.html are considered to be from one origin and index2.html is from another. Unfortunately it's impossible to test it just as plain HTML/JS without two different servers with different domains
<!--INDEX CODE-->
<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="">
<meta property="og:type" content="">
<meta property="og:url" content="">
<meta property="og:image" content="">
<meta name="theme-color" content="#fafafa">
</head>
<body>
<p>index page</p>
<a href="/page.html">link</a>
<script>
let i = 0;
const bc = new BroadcastChannel('payment-page');
function sendItem() {
i+=1;
const message = '{"message":"Hello from the new window!"}';
if (window.opener) window.opener.postMessage(message, '*');
const data = { message: `Hello from broadcast ${i}` };
console.log(JSON.stringify(data));
bc.postMessage(JSON.stringify(data))
console.log(message)
}
</script>
<button onclick="sendItem()">send item</button>
</body>
</html>
<!--END OF INDEX CODE-->
<!--IFRAME CODE-->
<html><head><script type="text/javascript">
(function () {
const bc = new BroadcastChannel('payment-page');
console.log('broadcast channel is created', bc)
bc.addEventListener('message', (m) => {
console.log('proxy: receive message ', m);
const data = JSON.parse(m.data);
data.channel = 'payment-page';
if (window.top !== window) {
// Inside iframe. Proxy to top.
console.log('proxy: send to parent');
window.top.postMessage(JSON.stringify(data), '*');
}
});
})();
</script></head><body></body></html>
<!--END OF IFRAME-->
<!--INDEX2 CODE-->
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<iframe
width="100"
height="100"
src="http://domain-1.com:3000//iframe.html"
></iframe>
<script>
window.addEventListener('message', function (message) {
if (message.data && typeof message.data === 'string') {
console.log(JSON.parse(message.data))
}
});
</script>
</body>
</html>
<!--END OF INDEX2 CODE-->
| Attachments | ||
|---|---|---|
| Add attachment proposed patch, testcase, etc. |
Chris Dumez
This is intentional origin partitioning. In privacy-preserving browsers like Safari, iframe foo.com under bar.com is not allowed to communicate with top-level foo.com.