What else is burried down in the depth’s of Google’s amazing JavaScript?

So the new GTalk interface in GMail is pretty rad. Congrats to Dan and the rest of the team that made it “go”.

The talk feature is cool not just from a UI perspective as the code is also chock full of little gems. I’m kind of a dork about low-latency data transport to the browser. HTTP wasn’t meant to be used this way…so of course I’m interested! Ever since Joyce got me involved in the rewrite of mod_pubsub I’ve had my eye on the various ways that servers can push data to browsers and the kinds of technology that will prevent a server that’s doing this from melting down (hellooooooooo Twisted). Using just what’s available to the browser, it’s possible to have the server push data encapsulated in <script> blocks and rely on a progressive rendering behavior that every modern browser implements to dispatch events in near real-time (compared to full page refresh or polling delay). There are a mountain of browser quirks that of course play into this process. The least desirable of these to the user are the “phantom click” and the “throbber of doom” that afflict IE users.

When a page (or an iframe it hosts) is loading content, your browser usually shows some sort of “I’m working” indicator. In the bottom “taskbar” there is usually some sort of progress meter. In the upper right (on IE) the “throbber” will continue to animate until the work is done. Of course in the scenario I’m describing the sent page is never done. The whole point is that the server keeps the connection open. Combine this with the IE behavior of producing a “click” like sound when an iframe is navigated to a different URL, and you’ve got a pretty poor user experience.

But couldn’t you do something with XMLHTTP? Short answer: yes, but not as portably and it won’t get you around IE’s 2-connection limit either so there’s not much of a win. For the long answer, see my talk at ETech or wait for me to post the slides. At the end of the day, the hidden <iframe> hack scales best and is the most portable. Especially if you can lick the UX problems.

Which Google has.

How? By cleverly abusing another safe-for-scripting ActiveX control in IE. Here’s the basic structure of the hack:

  // we were served from child.example.com but 
  // have already set document.domain to example.com
  var currentDomain = "http://exmaple.com/"; 
  var dataStreamUrl = currentDomain+"path/to/server.cgi";
  var transferDoc = new ActiveXObject("htmlfile"); // !?!
  // make sure it's really scriptable
  transferDoc.open();
  transferDoc.write("<html>");
  transferDoc.write("<script>document.domain='"+currentDomain+"';</script>");
  transferDoc.write("</html>");
  transferDoc.close();
  // set the iframe up to call the server for data
  var ifrDiv = transferDoc.createElement("div");
  transferDoc.appendChild(ifrDiv);
  // start communicating
  ifrDiv.innerHTML = "<iframe src='"+dataStreamUrl+"'></iframe>";

This is the kind of fundamental technique that is critical to making the next generation of interactive experiences a reality. Server tools like mod_pubsub and LivePage (and perhaps even JMS buses) are starting to come into their own and the benefits of event-driven IO are starting to become well understood by server-side devs. It’s only a matter of time before server-push data hits an inflection point in the same way that background single-request/single-response data transfer did with Ajax. Dojo will, of course, have infrastructure to support this kind of thing when the borader developer community is ready (most if it is already in place).

From long and painful experience and amazingly deep respect, I take my hat off and bow to whoever it was on the GMail/GTalk team that figured this out. It’s a hell of a hack. It’s no wonder that Google has been able to attract and develop the best DHTML hackers in the world.

Update: so just to be *very* clear, I worked on the rewrite of the mod_pubsub *client*. The server rewrite was handled by some folks who are much smarter than I am.

28 Comments

  1. Rui Pinheiro
    Posted March 13, 2006 at 2:28 pm | Permalink

    Amazing stuff. I wonder about the possibility of doing the reverse, i.e., making the file upload process much smarter.

    Imagine resume, upload in blocks, etc. Besides being useful in a P2P-like situation, would be great where clients have to upload LARGE files to the server.

    I know, I’m a dreamer ;)

  2. Willem Mulder
    Posted March 25, 2006 at 9:28 am | Permalink

    So… Why does Google nog use this to check if there’s new mail… For as much as I know, there’s still a click on the ‘inbox’ link required to find out if there’s new mail… (or maybe it does check, but not often enough?)

  3. Jon
    Posted March 29, 2006 at 9:05 pm | Permalink

    Sorry to join the conversation so late; you wrote waaay back at the start of all this:

    “On FF (1.5), the communication iframe only makes the statusbar say “Transfering data from example.com…? while the throbber stops when a subsequent HTTP request has finished.”

    I’ve been having a very hard time reproducing that result, and I wonder if you could clarify a bit. Is it any old HTTP request on the page (i.e. an image or something), or does something fancy need to be done to make the spinner stop for Firefox?

    Thanks very much!

  4. Jon
    Posted April 1, 2006 at 8:42 pm | Permalink

    Something fancy DOES need to happen. I’ve managed to reproduce it, but I’m not entirely sure where the magic is…

  5. Posted April 8, 2006 at 11:20 am | Permalink

    Has anyone experimented with this “htmlfile” object to try multiple synchronous ajax requests? Seems like you could just use this instead of XMLHttpRequest.

  6. Nutz
    Posted May 6, 2006 at 11:17 am | Permalink

    Can someone (Alex?) post a working code example so we can see this Comet stuff in action ?

    Would/could it work with Microsoft IIS ?

    Thanks

  7. Gordon
    Posted June 9, 2006 at 4:22 pm | Permalink

    Maybe this is a stupid question, but I’m wondering one more thing. When a user (let’s call them the sender) clicks on another user’s name (the receiver) to chat, the sender opens up a small iframe window to chat and all this code does its magic. But how does the receiver’s window know to likewise open an iframe?

    My best guess is that as soon as anyone logs into Gmail, a persistent connection is established and is constantly left open, even when no one is chatting. Do you know if this is the case?

  8. Posted June 9, 2006 at 7:42 pm | Permalink

    This rules! I’m in the process of releasing an IFRAME based AJAX implementation that is able to get around the browser “same origin” policy (http://en.wikipedia.org/wiki/Same_origin_policy). I thought I was pretty hot stuff… until I turned off the mute button on my computer…. click, click, click, click….. ARRRRG!

    However, using this ActiveXObject(“htmlfile”) solved my woes! No more clicks or annoying visual queues in IE! I need to stick with the “single-request” method rather than going for a persistent connection b/c it’s fundamental to the way I’m able to skirt same origin (except for Opera which is known to be overly sensitive with iframe security).

    Since this appears to be a well versed community, out of curiosity does anyone else here have asynchronous communcations working outside of the same origin? Would be nice to know if my architecture is as unique as I think it is, or if I simply reinvented the wheel ;)

    Thanks,
    -Craig

  9. Scott
    Posted June 28, 2006 at 9:18 am | Permalink

    Hi Alex,

    I am very interested in using DOJO for a new website. We require realtime push, just like the google dynamic iframe solution provides. Do you have any idea when this would be implemented in DOJO?

    Thanks
    Scott

  10. Posted July 23, 2006 at 6:17 am | Permalink

    Thanks Andrew,

    I remembered having seen this technique at work, but could not recall it was Pushlets :)

    Alex,
    Would it be correct to say that the client side is exactly same as Pushlets while the server side is implemented differently…or I am missing something here ? As you said, I am also curious about what other names it has gone by !

    Warm regards,
    Abhinav

  11. Posted August 16, 2006 at 12:30 am | Permalink

    That was an awesome article, still have to go through all the other links that are present.

    But all these “hacks” against the browser shouldn’t go unnoticed. These new Applications, are changing the way we browse the web.

    Soon I hope browsers should come up with the “Back” button for the “Last Ajax based event”. I don’t know how are devs @ Mozilla working towards it, probably Firefox 3.

  12. Posted August 24, 2006 at 10:51 am | Permalink

    Hi you all,

    i tried the code on ie5.5 on win98 and end up with:
    function rpc_iframe()

    {

    var currentDomain = “localhost/?;

    var dataStreamUrl = currentDomain+?rpc-test/server.php?;

    var transferDoc = new ActiveXObject(?htmlfile?); // neue Seite

    transferDoc.open();

    transferDoc.write(?”);

    transferDoc.write(?document.domain=’?+currentDomain+?‘;?);

    transferDoc.write(?”);

    transferDoc.close();

    var ifrDiv = transferDoc.createElement(?div?);

    transferDoc.appendChild(ifrDiv);

    ifrDiv.innerHTML = “?;

    }

    Everything went fine… except the window wont close.

    Any ideas to manage it?
    Thanks in advance

    M.

  13. Affonso Loyola
    Posted September 5, 2006 at 9:01 am | Permalink

    So. How do we retrieve the content from the iframe?
    I’m trying some remote scripting calling “window.parent.callback” but
    it seems that the iframe doesn’t have any reference to the “outter” document.
    So anyone knows how does it work?
    Affonso

  14. Affonso Loyola
    Posted September 5, 2006 at 9:43 am | Permalink

    I’ve tryed what Martin Franz decribed, setting the:
    transferDoc.parentWindow.foo = foo;
    But I cant make it work!
    Someone successfull on that?
    Affonso

  15. Affonso Loyola
    Posted September 5, 2006 at 10:52 am | Permalink

    I think iI might not setting the domain rigth on the outter document and
    in the iframe. I’m sunning my application on localhost. Is that a problem?
     
    Affonso 

  16. Posted September 14, 2006 at 6:59 pm | Permalink

    so,if the iframe is appened to the htmlfile activex object,
    how does the iframe frame’s javascript code call its parent frame’s functions? 
    just like the code “parent.transData(‘test’)” in the iframe.

  17. Posted September 15, 2006 at 8:01 pm | Permalink

    transferDoc.parentWindow.foo = foo;
    It works well,
    but I discover another fatal problem,the “htmlfile” activexobject will timeout after about 30s autolly,And the iframe doesn’t output anything.

  18. Bench
    Posted September 24, 2006 at 10:48 am | Permalink

    Interesting, but how do you call functions IN the window that opens the transferDoc FROM the iframe inside the transferDoc ?

    I see no logic with this at all:

    transferDoc.parentWindow.foo = foo;

  19. Bench
    Posted September 24, 2006 at 4:06 pm | Permalink

    incidentally, what would be the equivalent to this:

    var transferDoc = new ActiveXObject(“htmlfile”); // !?!

    for Firefox?

  20. Posted November 14, 2006 at 2:20 am | Permalink

     I don’t think there’s something equivalent for firefox…

  21. rick
    Posted December 1, 2006 at 4:15 am | Permalink

    Is here anybody who have found out the solution in firefox?

  22. Posted December 1, 2006 at 4:19 am | Permalink

     

  23. Ivan Garavito
    Posted December 19, 2006 at 11:02 am | Permalink

    Hi Alex,

    It seems that lots of them can’t try something new (to them). I’ve been tracking some of the Dojo Toolkit. It’s really amazing and interisting, but currently I understand that dojo uses Ajax to interact with the server. Do you, the Dojo’s development team, plan to adopt, port or migrate to “Comet” model? I know Dojo has the Cometd project, but is this a separated project? or will be integrated into dojo’s javascript libraries? If so, which version will include it?

    Regards,
    Ivan Garavito

  24. Posted January 13, 2007 at 5:15 am | Permalink

    Is this the same as the oracle htmlfile object?

  25. Dok
    Posted March 2, 2007 at 12:08 pm | Permalink

    In Firefox you don’t need to mess with frames as the XmlHttpRequest will return data as it’s being loaded and there is no “throbbing” problem.

    For IE, has anyone confirmed that you can call code in the parent of the “htmlfile” frame?

    Alex, you have comments in the cometd.js code to the effect of “TODO: improve with Gmail fix”. Any luck?

    The IE iframe issue being solved, how does gmail get around the 2-connections limit?
    What are the possible approaches for that as it’s a common problem in FF and IE?

    The obvious is to change the browser behavior. Good luck with that! We need solutions that work now.
    (http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2006-November/007599.html

  26. Aaron
    Posted March 3, 2007 at 5:17 pm | Permalink

    This is quite neat, ajax is pretty neat I just wish they would make it simpler, or turn it into a standard so that instead of opening a big xmlhttp request just have like a line or two of code that could send data and recieve data, or have an option to keep an open connection.

    Be kinda cool to see if they make web pages in the future be run off of ajax or something similiar so browsers never have to refresh.

    Regards.

  27. Jason
    Posted September 10, 2007 at 12:21 pm | Permalink

    See this link for info on how to do this in Firefox/Mozilla:http://meteorserver.org/browser-techniques/

  28. Matthew
    Posted September 4, 2009 at 8:19 pm | Permalink

    I’ve been searching around for this thing called “Comet” or “HTTP streaming” for the past hour or so, and now I find out it’s just a lame hack. Why doesn’t someone just give JavaScript a socket object, and then we can just do things in a more straightforward way that makes sense? Geez. Do I have to take the overhead of Java or Flash every time I want to open a normal socket connection?

5 Trackbacks

  1. […] What else is burried down in the depth’s of Google’s amazing JavaScript? Gmail talk ?使用的?? connection 的秘技 […]

  2. […] As with Ajax, those of us who build technology are now faced with another communication challenge. We have a hard problem for which solutions are available (and have been for some time) but no way to communicate about them. Terminology is again the missing link. Today, keeping an HTTP connection open for doing low-latency data transfer to the browser has no digestible name. When I describe a cool new hack, there’s nothing to associate it with. When people say “how the hell did they do that?”, we don’t have a compact answer. Therefore, in the spirit of improved communication (and not technology invention), I’m proposing a new name for this stuff. […]

  3. […] In early 2006, Alex Russell posted about a neat hack that the Google Talk team in Gmail use to support Comet in Internet Explorer, a trick which works as far back as IE 5.01. What great news! A reliable way to stream Comet messages to Microsoft’s browsers. If only it were that easy. […]

  4. By Antivirus free downloads on December 29, 2007 at 3:32 pm

    AVG free

  5. By Comet Daily » Blog Archive » Canonical Comet Apps on January 24, 2008 at 1:25 pm

    […] Shortly after Google launched Google Talk, they added chat to the Gmail interface, providing low-latency IM to all Gmail users. Alex Russell quickly dissected their implementation and learned that Google uses the forever-frame technique. Michael Carter made progress on understanding the htmlfile hack for Internet Explorer. […]