Cross Domain Comet

Last night we got Cometd working across domains, without plugins.

“Cross domain Ajax” (see JSONP) hasn’t taken off the way that I’d hoped, perhaps in part because of a lack of necessity. It might just be easier to set up a permissive proxy to do requests to services hosted on other domains. Moore’s Law discounts distributed coordination in favor of localized transformation. But whatever the reason, there hasn’t been huge uptake, even with beautiful abstractions like Dojo’s JSON-RPC facilities (see the Yahoo services example). Intensely useful, but not everyone is on board just yet. Hopefully Joseph Smarr‘s talk on the topic at OSCON will help turn some heads.

But there’s one scenario where it’s a total no-brainer: cross-domain Comet. Normally when you set up a Comet server, it either has to sit in front of the application server or have requests passed off to it from the main web server. In the case where the app server dishes off the requests, it’s potentially still “involved” in the process if it acts like a proxy. Unless your front-end web server is also built with event-based-IO in it’s core, this can really really hurt. Luckily, there’s hope on the horizon. Sun even announced that they’re baking Comet support directly into their app server. But until the web tier collectively upgrades, we need some other way to simplify the configuration of apps+Comet servers. Until now, help has come in the form of iframes plus document.domain setting. This lets you put the Comet server on a sub-domain and still pass event payloads back-and-forth between parent document and the iframe. This is how the tried-and-true mod_pubsub client operates, but it’s brittle. Browsers get picky when you try to set document.domain and things don’t line up exactly the right way. Add Safari’s non-deterministic iframe behaviors to the mix and it’s a recipe for sleepless nights and begging forgiveness from the ops folks when you need just one more DNS change and server restart.

We can do better.

The solution to this that Juggernaut employs is to use the built-in cross-domain capabilities of the Flash player and it’s proprietary crossdomain.xml scheme. This isn’t a bad solution, but having Flash turned off isn’t unheard of. The performance-across-the-flash-boundary problems are mostly licked these days (thanks dojo.flash!), but the complexity with getting it all set up correctly puts it in the position of “Plan B” if something better comes along. And we just might have something better in the form of <script src="...">.

By building on top of the Dojo ScriptSrcIO infrastructure it was trivial to make a JSONP transport for Cometd. We just adapt the long-poll style of Comet but make the initial handshake messages JSONP-clued. That in place, the rest works just like “normal” long-polling, except that the client can connect from *any domain*. The configuration problem just dropped from “make sure everything cooperates at the systems and network level” to “make sure that the client and server speak the same protocol”…and I like solutions that put the problem in software and not external configuration or human effort. The checked-in server-side code shows how to handle it.

So what’s the downside? The first downside is that the latency characteristics for cross-domain Comet using this technique are the same as long-polling. Not bad, mind you, but not as optimal as iframe, multipart-mime, or Flash-based solutions when you have large numbers of messages being thrown at the client. Additionally, it’s more difficult to know when a connection “times out” or in some other way fails, but I think these are tractable. Having a Plan A and a Plan B for cross-domain Comet and a server that can speak both styles via pluggable transport wrappers is exciting to me. By lowering the configuration barrier, I think we’ll start to see a significant uptick in Comet adoption.

Next time: Why we need a standard protocol for this stuff, and what we’re doing about that in Cometd.

PS: as usual, big thanks go out to my employer SitePen who is funding this research and making it available under liberal Open Source licenses.

2 Comments

  1. Posted October 29, 2006 at 6:48 pm | Permalink

    If you want to run scalable services at low latency using ajax transport, you would probably be interested in rphd, the Ajax/Comet Request Router.

  2. Posted February 15, 2007 at 6:58 am | Permalink

    I wonder how the long polling can work “normally” when the client doesnt give the control back to the browser?

7 Trackbacks

  1. By Ajaxian » Cross Domain Comet on July 26, 2006 at 7:42 am

    [...] Adding on to the last post on cross domain XHR, Cometd now supports working across domains, without plugins. [...]

  2. By Agile Ajax on July 26, 2006 at 9:00 pm

    Cross Domain Comet

    I hate to be a blog echo chamber, but this post from Alex Russell of Dojo Toolkit is worth spreading around a bit more.

  3. By JasonKolb.com on August 3, 2006 at 12:20 pm

    Web 2.0 and AJAX Security Vulnerabilities

    Ajaxian has a post about some sessions at the Black Hat USA 2006 conference. I’m quite honestly surprised that this is just gaining some press now, I’ve figured it would happen sooner than it has (but that’s typical for me

  4. By Life is Beautiful on October 29, 2006 at 4:33 pm

    Live Page-View Counter, Comet server and JSON-push

    This Live Page-View Counter is an experimental implementation of live version of page-view counter, which displays the current page-views, dynamically updating the counter on the HTML page, utilizing Comet server and JSON, which I call JSON-push. Overv…

  5. [...] I have been playing around with the twisted cometd in a cross domain configuration. Alex Russel (From the dojotoolkit foundation) in his article mentioned that he got it to work in a cross domain setting. The technique used to do this was to initially use the jsonp transport in the callback polling mode and fallback to long polling. I have already spent 2 days now trying to understand why it doesnot work. I am not a great Javascript hacker but I know that Javascript doesnot support threading yet. Asynchronous updates are possible if you use iframes or xmlhttp. So how does Alex’s technique work ( I havent seen it work yet ??). [...]

  6. [...] If we need completely cross-domain Comet, browser security policies render all of the previous transports inoperable. Instead, we must turn to “dynamic” script tags—sometimes called “JSONP“—in a method described by Alex Russell last year, which I call “CometP”. We use JavaScript to create a script tag, setting its source to our Comet server. This connection stays open until the server has new data to send, at which point the browser executes the script, and we open up another script tag to wait for the next event. The performance here is comparable to XHR long polling, but this works across domains. [...]

  7. [...] Instead, we must turn to “dynamic” script tags—sometimes called “JSONP”—in a method described by Alex Russell last year, which I call “CometP”. We use JavaScript to create a script tag, [...]