Monthly Archives: November

Introducing CrossFrame, a Safe Communication Mechanism Across Documents and Across Domains

The mashup problem

According to my coworker Douglas Crockford, Mashups are the most interesting advancement in software development in decades. They are also unsafe in the current generation of browsers. Lately, Douglas has been spending some time convincing the main browser vendors that mashups need to be made safe, wrote a proposal, and even mentioned Google Gears as a potential solution to the problem. While fixing the browser is the right thing to do, web developers are confronted with this problem today, and cannot afford to wait 5 years for a definitive solution.

Existing solutions to the mashup problem

One way mashups (or widgets, badges and gadgets, take your pick…) can be made safe is by sandboxing them in an IFrame pointing to another domain (Note: another way would be to run the untrusted code through ADsafe, and provide some safe API to do useful things on the page) The problem is that the Same Origin Policy isolates them so completely that they are then unable to cooperate with the page containing them or with each other. Several hacks have been exploited to achieve reasonably secure client-side cross-domain communication. The most popular ones use the URL fragment identifier or the Flash LocalConnection object.

Why the need for another technique?

CrossFrame is a variant of the URL fragment identifier mechanism. In the original technique, the containing page sets the URL fragment identifier of an embedded IFrame (usually via its src attribute), and the IFrame must poll to detect changes in the value of its location.hash property. This technique can be further built upon to allow for 2-way communications between an IFrame and its containing page, or between two distinct IFrames.

The original URL fragment identifier technique has many limitations, many of which can be worked around except maybe for the following:

  • It unnecessarily consumes CPU cycles by requiring the receiver to poll.
  • It creates “fake” history entries on Safari and Opera.

How does CrossFrame work?

While CrossFrame also has limitations of its own, I find it to be a much cleaner and simpler approach. Here is how it works:

In order to communicate with the mashup hosted in domain Y, the page, hosted in domain X, dynamically creates a hidden IFrame and points it to a special proxy file hosted in domain Y, using the URL fragment identifier to convey the message (step 1) When the special proxy file is loaded in the hidden IFrame, it reads its URL fragment identifier and passes it to a globally accessible function defined in the IFrame hosting the mashup (step 2) using parent.frames['mashup'] to get to it. The same technique can also be used by the mashup to communicate with the page (the proxy will use parent.parent to get to the page) Finally, when all is said and done, the hidden IFrame is automatically removed from the DOM by the library.

This however cannot work on Opera, which does not allow us to query any property of a window pointing to a different domain (so getting parent.parent for example will throw an exception) CrossFrame takes care of this by using, on Opera only, the HTML 5 way of sending messages across frames and across domains.

How to use CrossFrame?

In order to use the CrossFrame library, place the proxy file (proxy.html, included in the downloadable archive) on your web server so you can receive CrossFrame notifications for that domain. Make sure that the proxy file gets cached properly by web browsers, for example using a .htacess file similar to this one:

<Files proxy.html>
    ExpiresActive on
    ExpiresDefault "access plus 1 year"
</Files>

Then, import the necessary code and its dependencies in your page:

<script type="text/javascript" src=".../2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="cross-frame.js"></script>

To receive messages, subscribe to the onMessage event:

YAHOO.util.CrossFrame.onMessageEvent.subscribe(
    function (type, args, obj) {
        var message = args[0];
        var domain = args[1];
        // Do something with the incoming message...
    }
);

To send a message, call YAHOO.util.CrossFrame.send():

YAHOO.util.CrossFrame.send(".../proxy.html",
                           "frames['mashup']",
                           "message");

Here is a demo showing the CrossFrame library in action.

Limitations

The CrossFrame library does not support chunking (i.e. the ability to pass a large message in several smaller chunks) so the size of the messages that may be sent is limited by the maximum length of a URL (which varies across browsers…) However, it is not impossible to implement (for more information on chunking, you may want to look at Dojo’s XHR IFrame proxy implementation, which I believe supports chunking)

Also, the user may experience a short delay the first time a message gets sent to a specific domain. This is due to the server round trip necessary to download the proxy file. However, this can easily be mitigated by preloading the proxy file for that specific domain.

Conclusion: The dangers of temporary solutions

There is a danger associated with this kind of “hack”. First of all, browser vendors may decide to change their security policies and mimic Opera’s behavior for example. If this happens, CrossFrame will stop working for those browsers. Furthermore, I do not recommend using hacks because they slow down the rate of innovation on the web (it makes the task of developing web browsers even more complicated than it already is, and also makes your application less maintainable) Therefore, as paradoxical as it may seem, I do not recommend using CrossFrame (or any of those ugly hacks for that matter)

time to know how to download video from youtube | Great reverse number lookup service.

Getting Rid of the Navigation Click Sound on IE

Internet Explorer plays a little click sound when the location of a page changes. This is a great usability feature as it lets the user know that something is happening. However, this little click sound can become really annoying with web applications that make extensive use of iframes. For example, imagine an application using several iframes to sandbox untrusted third party ads. Refreshing the content of the iframes (by changing their src attribute) makes the application sound like an automatic rifle. Scary, huh? Well, I recently found out about a very clever trick that can make this click sound go away.

Replace:

iframe.src = "...";

by:

var newIFrame = document.createElement("iframe");
newIFrame.src = "...";
iframe.parentNode.replaceChild(newIframe, iframe);

The secret is to set the iframe src attribute before appending it to the document… However, this simple approach exhibits a very unpleasant flickering. The following snippet shows how to get rid of the flickering as well:

function setIFrameSrc(iframe, src) {
    var el;
    iframe = YAHOO.util.Dom.get(iframe);
    if (YAHOO.env.ua.ie) {
        // Create a new hidden iframe.
        el = iframe.cloneNode(true);
        el.style.position = "absolute";
        el.style.visibility = "hidden";
        // keep the original iframe id unique!
        el.id = "";
        // Listen for the onload event.
        YAHOO.util.Event.addListener(el, "load", function () {
            // First, remove the event listener or the old iframe
            // we intend to discard will not be freed...
            YAHOO.util.Event.removeListener(this, "load", arguments.callee);
            // Show the iframe.
            this.style.position = "";
            this.style.visibility = "";
            // Replace the old iframe with the new one.
            iframe.parentNode.replaceChild(this, iframe);
            // Reset the iframe id.
            this.id = iframe.id;
        });
        // Set its src first...
        el.src = src;
        // ...and then append it to the body of the document.
        document.body.appendChild(el);
    } else {
        iframe.src = src;
    }
}

This example demonstrates this technique (turn the volume up, and open it up with Internet Explorer) Note: the navigation sound you hear when using Internet Explorer (or Windows Explorer) can be configured via the Sounds dialog accessible from the Control Panel.

Update: I forgot to mention that, by using this trick, you will break the back / forward navigation buttons. Therefore, this trick should only be used for a non-navigational purpose only.

What happened to Gmail?

I have been using Gmail every since it first went public. I’ve always liked it for its simplicity, reliability and performance. When I read that the Gmail team had done some work to make their product even faster, I could not wait to get my hands on the new version. This morning, I was finally able to try it out and I was extremely disappointed. Firefox kept crashing, locking up, and the overall performance went down dramatically (in spite of disabling Firebug and turning the chat feature off.) I have read many such reports on other blogs, so I am wondering what the QA procedure is at Google. Maybe it’s time to put the “beta” back in Gmail, or roll back the previous version…

In the meantime, I’ll switch back to the good old Yahoo! Mail.

Update: Gmail is still in beta. For some reason, I thought they had passed that stage. My apologies for the misinformation.

Update: The Gmail developers kept a link to the older version (look at the links located at the top right of the page) Very wise decision indeed.