Is cross-origin postMessage broken in IE10? - html

I'm trying to make a trivial postMessage example work...
in IE10
between windows/tabs (vs. iframes)
across origins
Remove any one of these conditions, and things work fine :-)
But as far as I can tell, between-window postMessage only appears to work in IE10 when both windows share an origin. (Well, in fact -- and weirdly -- the behavior is slightly more permissive than that: two different origins that share a host seem to work, too).
Is this a documented bug? Any workarounds or other advice?
(Note: This question touches on the issues, but its answer is about IE8 and IE9 -- not 10)
More details + example...
launcher page demo
<!DOCTYPE html>
<html>
<script>
window.addEventListener("message", function(e){
console.log("Received message: ", e);
}, false);
</script>
<button onclick="window.open('http://jsbin.com/ameguj/1');">
Open new window
</button>
</html>
launched page demo
<!DOCTYPE html>
<html>
<script>
window.opener.postMessage("Ahoy!", "*");
</script>
</html>
This works at: http://jsbin.com/ahuzir/1 -- because both pages are hosted at the same origin (jsbin.com). But move the second page anywhere else, and it fails in IE10.

I was mistaken when I originally posted this answer: it doesn't actually work in IE10. Apparently people have found this useful for other reasons so I'm leaving it up for posterity. Original answer below:
Worth noting: the link in that answer you linked to states that postMessage isn't cross origin for separate windows in IE8 and IE9 -- however, it was also written in 2009, before IE10 came around. So I wouldn't take that as an indication that it's fixed in IE10.
As for postMessage itself, http://caniuse.com/#feat=x-doc-messaging notably indicates that it's still broken in IE10, which seems to match up with your demo. The caniuse page links to this article, which contains a very relevant quote:
Internet Explorer 8+ partially supports cross-document messaging: it
currently works with iframes, but not new windows. Internet Explorer
10, however, will support MessageChannel. Firefox currently supports
cross-document messaging, but not MessageChannel.
So your best bet is probably to have a MessageChannel based codepath, and fallback to postMessage if that doesn't exist. It won't get you IE8/IE9 support, but at least it'll work with IE10.
Docs on MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx

Create a proxy page on the same host as launcher. Proxy page has an iframe with source set to remote page. Cross-origin postMessage will now work in IE10 like so:
Remote page uses window.parent.postMessage to pass data to proxy page. As this uses iframes, it's supported by IE10
Proxy page uses window.opener.postMessage to pass data back to launcher page. As this is on same domain - there are no cross-origin issues. It can also directly call global methods on the launcher page if you don't want to use postMessage - eg. window.opener.someMethod(data)
Sample (all URLs are fictitous)
Launcher page at http://example.com/launcher.htm
<!DOCTYPE html>
<html>
<head>
<title>Test launcher page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function log(msg) {
if (!msg) return;
var logger = document.getElementById('logger');
logger.value += msg + '\r\n';
}
function toJson(obj) {
return JSON.stringify(obj, null, 2);
}
function openProxy() {
var url = 'proxy.htm';
window.open(url, 'wdwProxy', 'location=no');
log('Open proxy: ' + url);
}
window.addEventListener('message', function(e) {
log('Received message: ' + toJson(e.data));
}, false);
</script>
<button onclick="openProxy();">Open remote</button> <br/>
<textarea cols="150" rows="20" id="logger"></textarea>
</body>
</html>
Proxy page at http://example.com/proxy.htm
<!DOCTYPE html>
<html>
<head>
<title>Proxy page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function toJson(obj) {
return JSON.stringify(obj, null, 2);
}
window.addEventListener('message', function(e) {
console.log('Received message: ' + toJson(e.data));
window.opener.postMessage(e.data, '*');
window.close(self);
}, false);
</script>
<iframe src="http://example.net/remote.htm" frameborder="0" height="300" width="500" marginheight="0" marginwidth="0" scrolling="auto"></iframe>
</body>
</html>
Remote page at http://example.net/remote.htm
<!DOCTYPE html>
<html>
<head>
<title>Remote page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function remoteSubmit() {
var data = {
message: document.getElementById('msg').value
};
window.parent.postMessage(data, '*');
}
</script>
<h2>Remote page</h2>
<input type="text" id="msg" placeholder="Type a message" /><button onclick="remoteSubmit();">Close</button>
</body>
</html>

== WORKING SOLUTION IN 2020 without iframe ==
Building on answer by tangle, I had success in IE11 [and emulated IE10 mode] using following snippet:
var submitWindow = window.open("/", "processingWindow");
submitWindow.location.href = 'about:blank';
submitWindow.location.href = 'remotePage to communicate with';
Then I was able to communicate using typical postMessage stack, I'm using one global static messenger in my scenario (although I don't suppose it's of any significance, I'm also attaching my messenger class)
var messagingProvider = {
_initialized: false,
_currentHandler: null,
_init: function () {
var self = this;
this._initialized = true;
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
var callback = self._currentHandler;
if (callback != null) {
var key = e.message ? "message" : "data";
var data = e[key];
callback(data);
}
}, false);
},
post: function (target, message) {
target.postMessage(message, '*');
},
setListener: function (callback) {
if (!this._initialized) {
this._init();
}
this._currentHandler = callback;
}
}
No matter how hard I tried, I wasn't able to make things work on IE9 and IE8
My config where it's working:
IE version: 11.0.10240.16590, Update versions: 11.0.25 (KB3100773)

Building upon the answers by LyphTEC and Akrikos, another work-around is to create an <iframe> within a blank popup window, which avoids the need for a separate proxy page, since the blank popup has the same origin as its opener.
Launcher page at http://example.com/launcher.htm
<html>
<head>
<title>postMessage launcher</title>
<script>
function openWnd() {
var w = window.open("", "theWnd", "resizeable,status,width=400,height=300"),
i = w.document.createElement("iframe");
i.src = "http://example.net/remote.htm";
w.document.body.appendChild(i);
w.addEventListener("message", function (e) {
console.log("message from " + e.origin + ": " + e.data);
// Send a message back to the source
e.source.postMessage("reply", e.origin);
});
}
</script>
</head>
<body>
<h2>postMessage launcher</h2>
<p>click me</p>
</body>
</html>
Remote page at http://example.net/remote.htm
<html>
<head>
<title>postMessage remote</title>
<script>
window.addEventListener("message", function (e) {
alert("message from " + e.origin + ": " + e.data);
});
// Send a message to the parent window every 5 seconds
setInterval(function () {
window.parent.postMessage("hello", "*");
}, 5000);
</script>
</head>
<body>
<h2>postMessage remote</h2>
</body>
</html>
I'm not sure how fragile this is, but it is working in IE 11 and Firefox 40.0.3.

Right now, (2014-09-02), Your best bet is to use a proxy frame as noted in the msdn blog post that details a workaround for this issue: https://blogs.msdn.microsoft.com/ieinternals/2009/09/15/html5-implementation-issues-in-ie8-and-later/
Here's the working example: http://www.debugtheweb.com/test/xdm/origin/
You need to set up a proxy frame on your page that has the same origin as the popup. Send information from the popup to the proxy frame using window.opener.frames[0]. Then use postMessage from the proxy frame to the main page.

This solution involves adding the site to Internet Explore's Trusted Sites and not in the Local Intranet sites. I tested this solution in Windows 10/IE 11.0.10240.16384, Windows 10/Microsoft Edge 20.10240.16384.0 and Windows 7 SP1/IE 10.0.9200.17148. The page must not be included in the Intranet Zone.
So open Internet Explorer configuration (Tools > Internet Options > Security > Trusted Sites > Sites), and add the page, here I use * to match all the subdomains. Make sure the page isn't listed in the Local intranet sites (Tools > Internet Options > Security > Local Intranet > Sites > Advanced). Restart your browser and test again.
In Windows 10/Microsoft Edge you will find this configuration in Control Panel > Internet Options.
UPDATE
If this doesn't work you could try resetting all your settings in Tools > Internet Options > Advanced Settings > Reset Internet Explorer settings and then Reset: use it with caution! Then you will need to reboot your system. After that add the sites to the Trusted sites.
See in what zone your page is in File > Properties or using right click.
UPDATE
I am in a corporate intranet and sometimes it works and sometimes it doesn't (automatic configuration? I even started to blame the corporate proxy). In the end I used this solution https://stackoverflow.com/a/36630058/2692914.

This Q is old but this is what easyXDM is for, maybe check it out as a potential fallback when you detect a browser that does not support html5 .postMessage :
https://easyxdm.net/
It uses VBObject wrapper and all types of stuff you'd never want to have to deal with to send cross domain messages between windows or frames where window.postMessage fails for various IE versions (and edge maybe, still not sure 100% on the support Edge has but it seems to also need a workaround for .postMessage)

MessageChannel doesn't work for IE 9-11 between windows/tabs since it relies on postMessage, which is still broken in this scenario. The "best" workaround is to call a function through window.opener (ie. window.opener.somefunction("somedata") ).
Workaround in more detail here

Related

How can i create an automatic redirect to AppStore or PlayStore based on Device?

For example: xyz.com/app-download
This domain (and only THIS!) shoudl redirect Android users in the PlayStore and iOS users in the AppStore.
If this domain is opened by Windows or Linux it should not redirect, but show the content, which is on the site!
This should preferrably be done by .htaccess file editing.
Can anyone come up with a nice and understandable solution for this?
Thanks a lot!
with a little Javascript you can achieve this, just add this code to the page
<script>
function redirectByMobileOS() {
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
//for Android
if (/android/i.test(userAgent)) {
window.location.href = "http://www.link-for-android.com";
}
//For iPhone / iPad / iPod (iOS
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
window.location.href = "http://www.link-for-iphone.com";
}
}
</script>
and call the function on page load from your <body> tag like this
<body onload="redirectByMobileOS()">
</body>

Why can't I create my own custom component in Google Chrome 48?

I have built a library of custom elements using the webcomponents polyfills provided by Polymer. It works in Firefox and Safari. But it doesn't work in Chrome 48 with native component support. I can make it work if I use the polyfill code hacked to not use the native implementation...
Here is an example:
<!DOCTYPE html>
<html>
<head>
<script>
var myComp = Object.create(HTMLElement.prototype);
document.registerElement('my-comp', {prototype: myComp});
myComp.attachedCallback = function () {
console.log('my-comp attached');
}
</script>
</head>
<body>
<my-comp></my-comp>
<p> Just to check that page is loaded</p>
</body>
</html>
I should see the message in the console, but nothing is displayed. Support is enabled in Chrome (I can see that document.registerElement is native), my code is loaded and executed (the element is registered, I get a warning if I try to register it again in the console), and the callback is valid (I can call it by hand in the console).
What happens? How can I make it work?
You will make it work by attaching event handlers before registering element:
var myComp = Object.create(HTMLElement.prototype);
myComp.attachedCallback = function ()
{
console.log('my-comp attached');
}
document.registerElement('my-comp', {prototype: myComp});

WebRTC getUserMedia promise api support in Chrome

Does chrome support promise based APIs for WebRTC? I am not able to get the getUserMedia() promised based API working in Chrome.
<!DOCTYPE html>
<html>
<head>
<title> Mitel WebRTC client </title>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src='dist/webrtc.min.js'></script>
<script type="text/javascript">
function startUp() {
var options = {
audio: true,
video: true
};
if (getUserMedia) {
getUserMedia(options)
.then(function (stream) {
console.log("Acquired audio and video!");
})
.catch(function (err) {
console.log(err.name + ": " + err.message);
});
} else {
alert("WebRTC not supported on this browser");
}
}
</script>
</head>
<body onload="startUp();">
<h1>WebRTC Promise API Client Application</h1>
</body>
</html>
On the console, I see the following error
This appears to be Chrome
adapter-latest.js:32 chrome: {"audio":true,"video":true}
adapter-latest.js:410 Uncaught TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': The callback provided as parameter 2 is not a function.
I want to make use of promise based API. Am I missing something?
It is not implemented yet in Chrome, but it works there if you use the official adapter.js WebRTC polyfill: https://jsfiddle.net/srn9db4h/
var constraints = { video: true, audio: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => video.srcObject = stream)
.catch(e => console.error(e));
Firefox and Edge support it natively FWIW.
Update: Chrome (50) appears to support this now. And Chrome 52 even supports srcObject.
To access navigator.mediaDevices you must to connect your site with HTTPS connection. There are no access this feature with HTTP.
https://developers.google.com/web/fundamentals/media/capturing-images/
Warning: Direct access to the camera is a powerful feature. It requires consent from the user, and your site MUST be on a secure origin (HTTPS).
Although this is not recommended but still you can try this to test your project by disabling security for media.
chrome://flags/#unsafely-treat-insecure-origin-as-secure
you can add your IP and chrome will treat it as secure.
You can also get this error if you're running Chrome your app in http. If so, you should run your app as https. Only localhost urls with http are supported by Chrome.
`http://jsfiddle.net/jib1/srn9db4h/ `
// not working
`https://jsfiddle.net/jib1/srn9db4h/`
//working with https

Cache Manifest with Windows Forms WebBrowser control (Visual Studio)

I am using the Windows Forms WebBrowser control to display a web application that I am also writing. The Web Application is using the HTML5 Cache Manifest functionality which I have got working fine when I call the page up in Chrome and IE (V11). However when I test the Cache Manifest in my WebBrowser control it does not work.
My understanding is that the WebBrowser control uses the latest local instance of IE for rendering/processing - however it does not like the Cache Manifest functionality. My cache manifest (cache.appcache) file contains the following:
CACHE MANIFEST
#V1.6
CACHE:
Default.aspx
NETWORK:
FALLBACK:
Error.aspx
and the rest of the project is pretty standard.
I did have to update the MIME of IIS to recognize the appcache extension and this has been cast as: text/cache-manifest
Any help anyone can give on this would be massively appreciated! I have looked at the possibility of using other Web Broswer controls in the project but really want to keep things as simple as possible... if possible!
Thanks!
Got it!
for anyone else that might need some help with appcache inside a .net webcontrol.
below code is a sample I was testing with.
the code covers the aspx page, javascript, webconfig and appcache file.
the javascript also has some event handlers to display its progress.
the meta tag in the aspx page was a key player - without it, it just didn't work.
don't forget, the nature of appcache is to download the changes the 1st time you visit the site, then display changes on the next visit.. you can intercept any changes and display automatically via the event handlers if you wish.
also something else that caught me, avoid using localhost to visit the page, (only seems to be a problem in chrome), the appcache doesn't seem to work the same way.. you really want to use an IP address:
eg:
don't use: http://localhost/web/index.aspx
use: http://10.1.1.4/web/index.aspx
one last thing - filename case sensitivity!
I noticed that the appcache contents relies on exact case - so i just made sure all my files are in lowercase. (appcache file, aspx, js, images, everything!)
hope it helps - good luck all!
#### ASPX Page (file: index.aspx) #####
<html manifest="index.appcache">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
</head>
<body>
<div>index.aspx--v1</div>
<img src="./images/data_replace.png" />
<textarea id="Textarea1"
style="position: absolute; font-family: Arial; font-size: 10pt;
width: 277px; height: 360px; margin-top: 2px; text-align: left; top: 103px; left: 18px; z-index:1000;"></textarea>
</body>
<script type="text/javascript" src="index.js"></script>
</html>
###### JavaScript (file: index.js) ######
function $get(id) {
return document.getElementById(id);
}
function fnLoad() {
setTimeout(function () { alert("hello"); }, 1000);
if (window.applicationCache) {
var appCache = window.applicationCache;
appCache.addEventListener('error', appCacheError, false);
appCache.addEventListener('checking', checkingEvent, false);
appCache.addEventListener('noupdate', noUpdateEvent, false);
appCache.addEventListener('downloading', downloadingEvent, false);
appCache.addEventListener('progress', progressEvent, false);
appCache.addEventListener('updateready', updateReadyEvent, false);
appCache.addEventListener('cached', cachedEvent, false);
}
function appCacheError() { $get('Textarea1').value = $get('Textarea1').value + "\nerror" }
function checkingEvent() { $get('Textarea1').value = $get('Textarea1').value + "\nchecking" }
function noUpdateEvent() { $get('Textarea1').value = $get('Textarea1').value + "\nnoupdate" }
function downloadingEvent() { $get('Textarea1').value = $get('Textarea1').value + "\ndownloading" }
function progressEvent() { $get('Textarea1').value = $get('Textarea1').value + "\nprogress" }
function updateReadyEvent() { $get('Textarea1').value = $get('Textarea1').value + "\nupdateready" }
function cachedEvent() { $get('Textarea1').value = $get('Textarea1').value + "\ncached" }
}
fnLoad();
#### Web.Config #####
<system.webServer>
<staticContent>
<mimeMap fileExtension=".appcache" mimeType="text/cache-manifest"/>
</staticContent>
</system.webServer>
#### Appcache File (file: index.appcache) ####
CACHE MANIFEST
# v1.1
CACHE:
index.js
images/data_replace.png
NETWORK:
*
I've run into the same problem, not sure if you found a fix for this yet?
I notice that the webbrowser control creates Temporary Internet Files
(C:\Users\[USER]\AppData\Local\Microsoft\Windows\Temporary Internet Files)
Whereas the native IE11 browser does not, so it seems like the temp files are trumping the appcache.. and if I set a no-cache meta tag in the aspx page, then the appcache stops working.. I've been going in circles all week!
Regardless, i'll keep hunting and make sure to post an answer if I find one.

Print Screen to Website [duplicate]

This question already has answers here:
Using HTML5/Canvas/JavaScript to take in-browser screenshots
(7 answers)
Closed 9 years ago.
My user need to screen shot their error message throw my website. They should directly paste from clipboard in my website instead convert the jpeg. Preferable browser is Firefox. I try to use ZeroClipBoard but it works for words not images. Appreciated if anyone could advice and share any links for references.
Simple answer: you can't. There is no web-standards way to read binary data from the clipboard, I also do not believe that Flash or Silverlight does this either (Flash can expose bitmap data from the clipboard, but only under AIR, i.e. not in a browser context).
You could write a small desktop utility program that your users download and run, which will take a screenshot and upload it for them, but without that your users will have to paste the image into Paint, save to disk, and upload with an <input type="file">.
I'm not sure of the compatibility with mozilla but you should look at the onpaste event
https://developer.mozilla.org/en-US/docs/Web/API/element.onpaste
and event.clipboarddata
http://www.w3.org/TR/clipboard-apis/
Cross compatibility is probably is probably going to be an issue.
You can look at the source for wordpress plugin Image Elevator http://wordpress.org/plugins/image-elevator/
Look at admin/assests/js/image-elevator-global.js for ideas.
After looking at the plugin I got the following code to work. It reloads the page image with whatever you paste. Works on chrome but not firefox.
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
document.onpaste = function (e) {
var items = e.clipboardData.items;
for (var i = 0; i < items.length; ++i) {
// uploads image on a server
var img = items[i].getAsFile();
var oData = new FormData();
oData.append('file', img);
var req = new XMLHttpRequest();
req.open("POST", "test-pastup.php");
req.onreadystatechange = function() {
setTimeout(function() {
var img = $('img').clone();
$('img').remove();
$('body').prepend(img);
}, 100);
}
req.send(oData);
return;
}
}
</script>
</head>
<body>
<img src="aaa.png" />
<input/>
</body>
</html>
for the server side - test-pastup.php
<?php
$source = $_FILES['file']['tmp_name'];
move_uploaded_file( $source, 'aaa.png' );
?>