web
web copied to clipboard
HTMLIFrameElement contentWindow property in CORS case - cannot use postMessage()
I am trying to migrate from html package, and figured out that it is impossible to call postMessage() for iframe with content from another domain.
myIFrame.contentWindow?.postMessage('aaa'.toJS, '*'.toJS);
The same code with html package works without any security exceptions.
I'm getting the following error when accessing myIFrame.contentWindow: SecurityError: Failed to read a named property from 'Window': Blocked a frame with origin "http://localhost:51005" from accessing a cross-origin frame.
There is a quite ugly workaround for this issue.
Add to index.html:
<script>
window.jsMyx = {
postMessage(iframeElt, msg) {
if (iframeElt) {
iframeElt.contentWindow.postMessage(msg, '*');
}
}
};
</script>
Then in Dart:
import 'dart:js_interop';
import 'package:web/web.dart' as web;
extension type JsMyx._(JSObject _) implements JSObject {
external void postMessage(web.HTMLIFrameElement iframe, JSAny? msg);
}
@JS()
external JsMyx get jsMyx;
And the following call works without any errors again:
void _sendMessage(Map<String, String> msg) {
if (kIsWeb) {
HTMLIFrameElement? fr = getMyIframe();
if (fr != null) {
jsMyx.postMessage(fr, msg.jsify());
}
}
}
I suspect this is the same issue as https://github.com/dart-lang/sdk/issues/54443.
The general complication is that null-checks violate cross-origin policy as it's a toString call in JS. This is true for the JS compilers, whereas I believe dart2wasm likely avoids this issue due to how it does its null-checks and then immediately boxes. Using a conditional import could probably also work as a workaround if so.
Fixing this will likely involve a runtime type that dart2js/ddc knows not to call any members on, or providing some other interface that allows users to make cross-origin calls while avoiding null and type-checks in the JS compilers. dart:html does the latter.
@srujzs Looks like the same problem in devtools was "solved" by disabling dart2js optimizations :-( Also trick with safelyPostMessage() extension is not working.