Cross-domain quirks in IE8

Anton Kovalyov
3 min readSep 14, 2014

This post was originally published on April 5th, 2011 on my personal blog.

Eliminate all other factors, and the one which remains must be the truth. — Sherlock Holmes

For the past couple of days, I have had to deal with a couple of fascinating issues reproducible only in Internet Explorer 8 (I used IE9 with compatibility mode).

Issue 1. Permission Denied when trying access window.parent.

Let’s say you have two pages — hosted on example.com and sub.example.com — and the latter opens the former in an iframe. You also want the iframed page to communicate with its parent by calling a callback using window.parent.callback().

The code above works fine in Chrome, Firefox, Opera and Internet Explorer 9. However, IE8 raises a Permission Denied error when the child page is trying to communicate with its parent. Removing the document.domain part from the child doesn’t fix the issue and doesn’t make a lot of sense since both parties must opt into the same domain to communicate with each other.

The only hint I had was the fact that we had already implemented a working cross-domain tunnel using a similar technique elsewhere. So, by eliminating all the differences, I found out that due to some mysterious bug, Internet Explorer 8 does not allow a top level domain to communicate with its subdomain. Using alias.example.com (or any other alias) instead of example.com fixes the issue.

Issue 2. Wrong origin in the postMessage event.

Another thing we noticed is that easyXDM — our cross-domain messaging library of choice — refused to pass messages back to the parent page but only after the child page sent at least one AJAX request. As soon as you made a request, easyXDM would start to silently fail at passing messages.

It took me a few debugger statements and console.log calls to find that the problem was in the code below (modified to fit the page):

/**
* Resolves the origin from the event object
* @private
* @param {Object} event The messageevent
* @return {String} The scheme, host and port of the origin
*/
function _getOrigin(event){
if (event.origin) {
// This is the HTML5 property
return event.origin;
}
if (event.uri) {
// From earlier implementations
return getLocation(event.uri);
}
if (event.domain) {
// This is the last option and will fail if the
// origin is not using the same schema as we are
return location.protocol + “//” + event.domain;
}
throw “Unable to retrieve the origin of the event”;
}
/**
* This is the main implementation for the onMessage event.
* It checks the validity of the origin and passes the message
* on if appropriate.
* @private
* @param {Object} event The messageevent
*/
function _window_onMessage(event){
var origin = _getOrigin(event);
if (origin == targetOrigin &&
event.data.substring(0, config.channel.length + 1) == \
config.channel + “ “) {
pub.up.incoming(
event.data.substring(config.channel.length + 1), origin);
}
}

The problem was with IE8 using document.domain value as the origin for all postMessage events after the first AJAX request. Since it was not the case in all other major browsers, including the current version of Internet Explorer, I assumed it was an IE8 browser bug.

To fix that, I was thinking about passing all valid origins to easyXDM, but then I saw a tweet by @jakobo that said, “If window.postMessage in IE8 is the disease, you should know that window.setTimeout is the cure.” And he was right: wrapping callbacks in setTimeout rolls the postMessage origin property back to what it is supposed to be.

TL;DR

  1. To solve a Permission Denied problem when communicating from example.com to sub.example.com using window.parent, use subdomain alias for example.com.
  2. To make sure you always have the correct postMessage origin value for your cross-domain messages, wrap them in setTimeout.

--

--