Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically accessing an iframe that uses a data URI as a source

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?

like image 564
Vlad Magdalin Avatar asked Jan 04 '13 00:01

Vlad Magdalin


3 Answers

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:

  • https://bugs.webkit.org/show_bug.cgi?id=17352
  • https://code.google.com/p/chromium/issues/detail?id=58999

Chromium devs don't seem to be in favor of relaxing this rule. Bummer.

like image 83
Vlad Magdalin Avatar answered Nov 06 '22 03:11

Vlad Magdalin


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.

like image 26
mark-buer Avatar answered Nov 06 '22 04:11

mark-buer


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/

like image 8
Jamie Avatar answered Nov 06 '22 04:11

Jamie