PDA

View Full Version : Cross origin security error although the iframe is on the same domain



Rain Lover
05-30-2014, 10:14 AM
I get a security error in console when I click the button:


var iframe = document.getElementById('iframe'),
button = document.getElementById('button');
button.onclick = function () {
iframe.src = 'linked-frame.html';
iframe.contentDocument.body.style.background = 'red';
};

DEMO (http://dl.dropboxusercontent.com/u/4017788/Labs/cross-origin-security-error.html)

jscheuer1
05-30-2014, 12:42 PM
The iframe is on example.com and the button is on dl.dropboxusercontent.com Both must be on the same domain.

However, once the local page loads, it works. Problem is, since loading isn't instantaneous, it's still on example.com when it tries to change the color. Once it's on the local page it works. But it might go by too quickly to notice in some browsers, because again, it happens before the page loads, so it changes the color and then reloads the local page in its native color.

In other words, you're expecting the code to run synchronously, but it's not. First there's a call to change the src, and then while the server is responding, the line about the color executes (or tries to, depending upon which page is at that moment in the iframe). Then the response comes from the serve rand the page loads into the iframe. If you listened for the load event of the iframe, you should be able to wait until after the page loads before trying to change its color. A timeout would also work, but the required amount of time would be arbitrary and vary by browser as well as by network/server traffic conditions. You would have to remove the listener after the callback to prevent the code from executing when the off domain page loads.

Rain Lover
05-30-2014, 12:58 PM
The iframe is on example.com and the button is on dl.dropboxusercontent.com Both must be on the same domain.

But it shouldn't throw such an error as I change the iframe source in my function.
I just learned I can partially resolve the issue if I wait until the iframe finishes loading: Demo (http://dl.dropboxusercontent.com/u/4017788/Labs/cross-origin-security-error2.html). However, it gives the same error message if click on the link inside the red iframe

jscheuer1
05-30-2014, 01:15 PM
I added some detail to my explanation. Refresh the page and reread my explanation. Here's code that works:



<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Cross Origin Security Error</title>
</head>

<body>
<iframe src="http://www.example.com/" id="iframe"></iframe>
<input type="button" value="Color it!" id="button">
<script>
var addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})();
var removeEvent = (function(){return window.addEventListener? function(el, ev, f){
el.removeEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.detachEvent('on' + ev, f);
}:function(){return;};
})();
var iframe = document.getElementById('iframe'),
button = document.getElementById('button');
function colorbg(){
var iDoc = (iframe.contentWindow || iframe.contentDocument || null);
if ((iDoc = iDoc.document)){
iDoc.body.style.background = 'red';
}
removeEvent(iframe, 'load', colorbg);
}
addEvent(button, 'click', function () {
addEvent(iframe, 'load', colorbg);
iframe.src = 'linked-frame.html';
});
</script>
</body>

</html>

Rain Lover
05-30-2014, 01:47 PM
I added some detail to my explanation. Refresh the page and reread my explanation. Here's code that works...


Thanks very much! Is it OK to simplify it like this:


<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Cross Origin Security Error 3</title>
</head>

<body>
<iframe src="http://www.example.com/" id="iframe"></iframe>
<input type="button" value="Color it!" id="button">
<script>
var iframe = document.getElementById('iframe'),
button = document.getElementById('button');
button.onclick = function () {
iframe.src = 'linked-frame.html';

iframe.onload = function() {
iframe.contentDocument.body.style.background = 'red'; iframe.onload = null;
};

};
</script>
</body>

</html>

DEMO (http://dl.dropboxusercontent.com/u/4017788/Labs/cross-origin-security-error3.html)

jscheuer1
05-30-2014, 02:04 PM
In some browsers, using iframe.onload = may not be optimal (might not work in some, may cause memory drain in others, and/or both). And, just in case the code does execute synchronously, the load function should be assigned before the request is made (src attribute change). Further, iframe.contentDocument is not valid in all browsers (there's another way around that than what I feature below, treating the iframe as a window - it's simpler but excludes using the getElementById() method to get a reference to the iframe). That all said, you can do whatever you like. My current version of the code looks like so:


<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Cross Origin Security Error</title>
</head>

<body>
<iframe src="http://www.example.com/" id="iframe"></iframe>
<input type="button" value="Color it!" id="button">
<script>
var addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})(), removeEvent = (function(){return window.addEventListener? function(el, ev, f){
el.removeEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.detachEvent('on' + ev, f);
}:function(){return;};
})(), iframe = document.getElementById('iframe'), button = document.getElementById('button'), iDoc;
function colorbg(){
if(!iDoc){
iDoc = (function(){
return iframe.contentDocument? function(){return iframe.contentDocument;} :
iframe.contentWindow? function(){return iframe.contentWindow;} : null;
})();
}
if (iDoc && iDoc().body){
iDoc().body.style.background = 'red';
}
removeEvent(iframe, 'load', colorbg);
}
addEvent(button, 'click', function () {
addEvent(iframe, 'load', colorbg);
iframe.src = 'linked-frame.html';
});
</script>
</body>

</html>

Even at that, it might not work out well in all browsers. I think older Opera was weird about the reference to the document in the iframe.

Rain Lover
05-30-2014, 05:33 PM
In some browsers, using iframe.onload = may not be optimal (might not work in some, may cause memory drain in others, and/or both). And, just in case the code does execute synchronously, the load function should be assigned before the request is made (src attribute change). Further, iframe.contentDocument is not valid in all browsers (there's another way around that than what I feature below, treating the iframe as a window - it's simpler but excludes using the getElementById() method to get a reference to the iframe). That all said, you can do whatever you like. My current version of the code looks like so:


<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Cross Origin Security Error</title>
</head>

<body>
<iframe src="http://www.example.com/" id="iframe"></iframe>
<input type="button" value="Color it!" id="button">
<script>
var addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})(), removeEvent = (function(){return window.addEventListener? function(el, ev, f){
el.removeEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.detachEvent('on' + ev, f);
}:function(){return;};
})(), iframe = document.getElementById('iframe'), button = document.getElementById('button'), iDoc;
function colorbg(){
if(!iDoc){
iDoc = (function(){
return iframe.contentDocument? function(){return iframe.contentDocument;} :
iframe.contentWindow? function(){return iframe.contentWindow;} : null;
})();
}
if (iDoc && iDoc().body){
iDoc().body.style.background = 'red';
}
removeEvent(iframe, 'load', colorbg);
}
addEvent(button, 'click', function () {
addEvent(iframe, 'load', colorbg);
iframe.src = 'linked-frame.html';
});
</script>
</body>

</html>

Even at that, it might not work out well in all browsers. I think older Opera was weird about the reference to the document in the iframe.

Thanks again for the detailed answers and snippets! You've been always of great help! :)