Detect if browser supports data uri scheme with iframes
Asked Answered
M

2

5

Internet Explorer does not support the data uri scheme for iframe urls (see http://msdn.microsoft.com/en-us/library/cc848897%28v=vs.85%29.aspx). Other browsers do. As browser detection is loaded with testing and future-proofing problems, I want to use feature detection to work around this issue.

So: how can I detect whether or not a browser supports the data uri scheme for iframes?

Matron answered 4/8, 2014 at 16:28 Comment(2)
Thread from modernizr talking about it, looks like no solution on their end yet. github.com/Modernizr/Modernizr/issues/1190Exemplum
Frame documents loaded from a data-uri are cross-site sourced, so accessing the frame document throws a security violation. If you start with no src attribute (or src="about:blank") and attach a load event to the frame, then this.contentWindow.document will throw on success. IE fires the load event even though nothing is loaded, so a simply try/catch will tell you if the browser supports data uri in a frame.Wilberwilberforce
S
10

This solution by Kevin Martin is tested and seems to be giving the correct result in IE, FF and Chrome:

function iframeDataURITest(src) {
    var support,
        iframe = document.createElement('iframe');

    iframe.style.display = 'none';
    iframe.setAttribute('src', src);

    document.body.appendChild(iframe);

    try {
        support = !!iframe.contentDocument;
    } catch (e) {
        support = false;
    }

    document.body.removeChild(iframe);

    return support;
}

console.log('Empty data uri', iframeDataURITest('data:;base64,'));
console.log('"*" data uri', iframeDataURITest('data:text/html;base64,Kg=='));

Unlike some of the other suggestions, it is synchronous - no need to mess around with timeouts or callbacks.

Strength answered 8/7, 2015 at 10:18 Comment(0)
S
1

If the onload event of the iframe with a data: URI fires, the browser supports data: URIs. Otherwise, the browser doesn't support data: URIs.

The example code also checks if scripting is allowed from a data: URI by sending a message from the iframe to the parent window.

Working code

var iframeDataURISupport = { checked: false, supported: false, scriptingSupported: false };

function iframesSupportDataURIs(callback) {
    if (!iframeDataURISupport.checked) {
        var iframe = document.createElement('iframe'), alreadyCalled = false, done = function () {
            if (!alreadyCalled) {
                alreadyCalled = true;

                document.body.removeChild(iframe);

                console.log(iframeDataURISupport);

                callback && callback(iframeDataURISupport);
            }
        }, previousMessageHandler = window.onmessage, dataURI = 'data:text/html,<' + 'script>window.parent.postMessage("data: URIs supported", "*");<' + '/script>';

        window.onmessage = function (e) {
            if (e.data === 'data: URIs supported') {
                window.onmessage = previousMessageHandler;

                iframeDataURISupport.supported = true;
                iframeDataURISupport.scriptingSupported = true;

                done();
            } else {
                window.onmessage.apply(this, arguments);
            }
        };

        iframe.src = dataURI;
        iframe.setAttribute('style', 'display: inline-block; width: 0; height: 0; overflow: hidden; border: 0 none; padding: 0; margin: 0;'.replace(/;/g, ' !important;'));

        iframe.onload = function (e) {
            if (iframe.src === dataURI) {
                iframeDataURISupport.supported = true;

                setTimeout(done, 100);
            } else done();
        };

        document.body.appendChild(iframe);

        setTimeout(done, 500);
    } else {
        setTimeout(function () {
            callback && callback(iframeDataURISupport);
        }, 5);
    }
};

Usage

iframesSupportDataURIs(function (details) {
    alert('This browser ' + (details.supported ? 'supports' : 'does not support') + ' data: URIs. It ' + (details.scriptingSupported ? 'also supports' : 'does not support') + ' scripting from data: URIs');
});

If you want more advanced control, you can call it like this:

iframeDataURISupport.checked ? functionName(iframeDataURISupport) : iframesSupportDataURIs(functionName);

Demo

Play with it on JSFiddle.

Scarabaeid answered 4/8, 2014 at 16:31 Comment(3)
Thanks @toothbrush, but testing the fiddle with IE (11), the script tells me that data Uris and scripting from data uris are supported, which unfortunately isn't the case. It appears the onload event fires in any case.Matron
@PaulTaylor I think it should work now, and I've updated the post. I've not currently got access to a machine running Internet Explorer 11, but perhaps you could tell me if it works now?Scarabaeid
IE now says "supports data urls, does not support scripting" - getting closer!Matron

© 2022 - 2024 — McMap. All rights reserved.