I'm creating an iframe programmatically using the "data" URI:
<iframe id="myFrame" src='data:text/html;charset=utf-8,<!DOCTYPE html><html><head></head><body><h1>Hello.</h1></body></html>'></iframe>
This frame loads fine, but it seems that working with the iframe programmatically hits cross-domain security checks.
var iframeDoc = document.getElementById('myFrame').contentWindow.document;
$(iframeDoc.body).find('h1').text('Changed');
Throws an error in Chrome and Safari:
Unsafe JavaScript attempt to access frame with URL data:text/html;charset=utf-8,... from frame with URL http://... The frame requesting access has a protocol of 'http', the frame being accessed has a protocol of ''. Protocols must match.
Here's a fiddle showing the security error: http://jsfiddle.net/bhGcw/4/
Firefox and Opera do not throw this exception and allow the iframe contents to be changed. Seems like Webkit sees a blank protocol for data URIs, and sees this as a cross-domain violation.
Is there any way around this?
It appears that Webkit does a simple string comparison in their domain checking code:
String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow)
{
...
SecurityOrigin* activeOrigin = activeWindow->document()->securityOrigin();
SecurityOrigin* targetOrigin = document()->securityOrigin();
if (targetOrigin->protocol() != activeOrigin->protocol())
return message + " The frame requesting access has a protocol of '" + activeOrigin->protocol() + "', the frame being accessed has a protocol of '" + targetOrigin->protocol() + "'. Protocols must match.\n";
...
}
It looks like Chromium is being more strict than the HTML5 spec, at least according the following bug reports:
Chromium devs don't seem to be in favor of relaxing this rule. Bummer.
The answer put forward by @jamie works well for loading HTML into an iframe and allowing subsequent programatic interaction with the content document.
XHTML is not so easy.
The srcdoc
attribute appears to be limited to HTML, not XHTML.
A work around is to use a Blob
URL which allows the content-type
to be specified.
var documentSource = '<?xml version="1.0" encoding="UTF-8"?>\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>...';
var blob = new Blob([documentSource], { type: "application/xhtml+xml" });
iframe.src = URL.createObjectURL(blob);
This technique works for at least Chrome, Firefox and Safari.
It's a bit late, how about instead of using a data URL, you use the HTML5 attribute srcdoc.
<iframe id="iframe" srcdoc='<html><body><h1>Hello!</h1></body></html>'></iframe>
<script type="text/javascript">
$(function(){
$($("iframe")[0].contentWindow.document).find("h1").text("Modified from the parent window!");
});
</script>
There's an example at http://jsfiddle.net/ff3bF/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With