Fleegix.org

BOSH and iframe cross-domain pain

2009-01-22 02:14:00

A big feature of the new Seesmic.com Webapp is our auto-update feature which provides near-real-time updates in the UI of videos as they're posted.

Under the hood the auto-update uses simple long-polling of our XMPP service via BOSH, using Jack Moffitt's excellent Strophe.js library to handle the nitty-gritty of connections, auth, and parsing all that tricksy XML output.

Pretty cool seeing those video posts pop into the UI over that sweet BOSH connection. But of course with that permanent long-running connection in the browser, we butt right up against the dreaded two-connection limit, and API calls to the backend are stuck going serially through the one remaining pipe. That really sucks a lot of the awesome out of the user-experience we're trying to bring.

The obvious solution was to move that dude to to a different subdomain so it's not permanently hogging half of the pipe to the backend. The same-origin policy for XHR calls in JavaScript throws a little bit of cold water on this plan, but like all things in the world of cross-browser Ajax apps, judicious application of a bit of ugly hackery will make things work.

In this case, the hackery is the fun and super-interesting world of cross-domain iframe communication. This technique has been around for a long time, but I've never had the pleasure of working with it. And by "pleasure," of course I mean "annoying, nagging pain, like a migraine that just won't go away."

The same-origin policy means pages served from different subdomains can't communicate with each other, but that's precisely what we need in this case -- we need to unload that BOSH connection to a different subdomain. Cross-domain iframe communication gets around this limitation by taking advantage of the fact that you can change the document.domain (essentially the security context that JavaScript executes in) of a page after it reaches the browser.

The idea is pretty simple -- serve the page in an iframe from a subdomain, change document.domain to match the hosting page. XHR objects in the iframe page don't change their notion of relative URLs, so they can still make calls back to the original subdomain server with no problem, but JavaScript can report those results back up to the parent page.

In practice, it's tweakier than that, with different browsers having different ideas about what exactly "match the hosting page" means. And as you might expect, it's Safari and Firefox at one end of the table, and IE way down at the other.

Here's the breakdown I found. Maybe this will save some other folks a few minutes of irritation.

Firefox/Safari

  • TLD: They don't care if the parent page and the iframe document.domain are a top-level domain or not, they just want them to match.

  • Setting the document.domain: Bizarrely, you have to set the document.domain on both the parent page and the iframe page even if the parent page is already what you want.

Internet Explorer

  • TLD: Totally doesn't work unless both parent page and iframe page are using a top-level domain for the document.domain.

  • Setting the document.domain: Bizarrely, you cannot reset the document.domain of the parent page if it's already a TLD. Resetting it (even to the same value) will break the cross-iframe communication.

Once I got through stubbing toes on all the annoying inconsistencies, communication back and forth between the iframe document and the parent worked great. Now we've got the two pages chit-chatting back and forth like two distant relatives at a family reunion who discover they both love Ronnie James Dio.

The browser still has to deal with the continuous open connection to the backend, but it's noticeable how much snappier the app is without BOSH sitting there Bogarting one of only two available connections to the main app domain.

About

This is the blog for Matthew Eernisse. I currently work at Yammer as a developer, working mostly with JavaScript. All opinions expressed here are my own, not my employer's.

Related

Previous posts

All previous posts ยป

This blog is a GeddyJS application.