Windows Live Quantum Mechanics -
As I've been wrapping up our 2nd generation cross-domain in-browser communication channel API, I've been nosing around and thinking about what my next project should be. There's no shortage of tasks to do in Windows Live, and I had a few leads for interesting projects elsewhere within Microsoft as well.
Just as I cleared my mental desk to consider these options in detail, suddenly their came a tapping as if someone gently rapping, rapping on my chamber door. It was a startup calling, trying to seduce me into doing something rash. I've been approached by startups before, but most are easy to dismiss because they have no funding. No matter how good the idea, I can't afford to work for IOUs. This one was different. Disruptive ideas, razor sharp team, and recently funded by Kleiner Perkins. Well that's different.
As fate would have it, my next gig will be at CoolIris, building browser plugins that are one part eye candy an two parts antimatter disrupter.
While I will be leaving the Microsoft payroll, I won't be leaving the Windows Live arena. I'm moving from the service producer to the service consumer side of the field. CoolIris will quickly need user logins, address books, photos, and storage, and I will certainly make sure they are aware of Windows Live's service offerings. We should definitely leverage rather than build out infrastructure.
The cross-domain communications article series will continue, "posthumously" if you will. The siloed domain lowering technique mentioned in the last article is on hold pending clearance of some internal paperwork. It will be published ASAP after the paperwork is sorted out.
The last article in the series (for now) will document the InterFrame Messaging channel API that we've been working on as a by-product of our development of the Windows Live Contacts control. That article is on hold pending the release of the IFM channel API, which is on track for Real Soon Now. Keep an eye on dev.live.com for announcements.
I will be starting up a new blog next week. It's not ready yet, but it will be hosted on my personal domain, www.dannythorpe.com. (Please forgive the dust; I haven't updated that site for years.) From there I'll link back to this blog and to my prior work at Borland.
So long, and thanks for all the fish!
Windows Live Quantum Mechanics -
TMobile announced this week the addition of the Blackberry 8230 "Curve" to the list of cell phones supported by TMobile's HotSpot@Home WiFi phone service.
This is a big step up in handset functionality over the minimalistic handsets that the service launched with earlier this year. I'm very tempted to jump in, since the Blackberry can do web surfing and web email that I crave, but of course there are just two little things that would make it just perfect: a smaller smartphone handset (the Curve is almost as wide as it is tall) and a smartphone handset that can run .NET CF applications.
Not that I've written any .NET CF apps lately, mind you, but just because I like having that option at my disposal. I've endured locked phones before where the only thing you can do with the phone is what the cellular provider says you can do with it (thanks, Nextel) and I don't intend to go through that again.
Smartphone with WiFi calling... Tempting, very tempting...
Windows Live Quantum Mechanics -
More than a few blog posts ago I stated my intent to publish a series of articles on cross-domain communication techniques. More time has passed than I had intended, but at last here is the start of that series of articles. The series will explore progressively more advanced cross-domain techniques as well as their strengths and weaknesses, culminating in an announcement about stuff we've been working on that I think you'll find interesting.
Cross-domain communication is usually discussed in the context of a browser client communicating to a web server that is different than the domain of the web page currently shown in the browser. The browser client displays a page from server foo.com, and that page tries to access data on server bar.com. This is forbidden by the same-origin browser security policy because bar.com isn't foo.com.
Server Side Proxy
One relatively simple way to resolve this is to have the browser page request data from the page's web server, and have the web server relay that request to the actual third party server. The browser displays a page from foo.com, and that page makes a data request to foo.com which foo.com relays to bar.com. Bar.com replies to foo.com, and foo.com forwards that response on to the browser client page to complete the circuit.
While this solution is simple and quite widespread today, it has some significant problems:
- Scalability and Network costs: The request and response travel across your server's network twice. Request in, request out, response in, response out. Traffic on your server network grows four times faster than growth of your application use. That means you'll reach network saturation four times sooner than with other techniques, and you'll pay four times more (in server network traffic costs) for the privilege.
- Impersonating the user: When your foo.com server makes a request to bar.com seeking data for the user, you're essentially impersonating the end user. If the data on bar.com requires any sort of user identification or authorization, your server side proxy suddenly jumps from super simple to super difficult. It's easy enough to ask the user to log in to bar.com, but your foo.com can't see anything that goes on in bar.com. In particular, foo.com cannot see whatever browser cookies that bar.com sets to indicate logged in state. Thus, it will be next to impossible for foo.com to present the appropriate cookies or credentials in its http request to bar.com to make bar.com believe that the request is coming from the legitimate user. And this should be difficult - this is nothing short of a man-in-the-middle attack on bar.com's security!
So, server side proxies are a quick and dirty way to toss anonymous data around, but they don't scale well and they hit a wall when the data requires authentication.
Web Sites With Subdomains
Web sites and web applications generally start out as simple beasts running on a single web domain (www.foo.com). As the site grows in functionality and complexity, the incentives to break that site up into subdomains (downloads.foo.com, feedback.food.com, images.foo.com) grows as well. Perhaps your web site has a download area that needs to be optimized for large file transfers. That would probably be easier to fine tune as a server or cluster dedicated to that function than to try to tune the entire web site for large file downloads.
Subdomains often sprout as a byproduct of a company's internal structure. It takes a lot more effort to coordinate updates to one central server shared by multiple departments on different schedules than for a department to own their own subdomain, nicely isolated from the rest of the company's constant revisions.
Double Edged Sword
Domain isolation is convenient to let you get your work done independently of the noise going on in the rest of the company's web presence, but also presents a new problem: web pages served from your subdomain cannot share information with web pages served from other subdomains of your company. If the user logs in to your company's main page, the browser cookies representing that login state are not accessible to your subdomain.
Lowering the Domain Barrier
The major browsers support a technique around this quandary, to allow subdomains to operate as equals within a common shared context. The HTML document object has a domain property which normally reflects the complete domain name of the server from which the HTML document was loaded. The browser will allow you to assign a subset of the current domain name to the document.domain property to indicate that you wish for the HTML document to be treated as though it were loaded from the parent domain.
So, an HTML page served from downloads.foo.com can assign document.domain = "foo.com" in a JavaScript code block. From that point forward, browser domain security checks will treat that page as a peer of any page in the foo.com domain.
The browser will (should) only allow you to change the document.domain to a less specific version of your current domain. one.two.three.foo.com could be lowered to foo.com, or could be lowered to three.foo.com.
The browser should not allow assignment of a top-level domain (domain suffix) to document.domain. You should not be able to change a document domain from "one.foo.com" to "com". There have been browser bugs in this area in the past where a browser implementer mistakenly interpreted "top level domain" to mean "the bit of the domain after the last dot". ".com", ".edu", and ".org" are top level domains, but ".co.uk" and ".co.jp" are TLDs also.
The browsers will not allow you to raise the domain of an HTML document to something more specific than its domain of origin, nor allow lateral domain shuttling. Changing document.domain from "two.foo.com" to one.two.foo.com" is forbidden. Changing a document.domain from "one.foo.com" to "two.foo.com" is forbidden.
Irreversible (Mostly)
Firefox 1.5 and 2.0 will not allow you to assign a domain name that is more specific than the document's current domain name under any circumstances. Once you lower one.foo.com to foo.com, it's stuck at foo.com forever. The only way to clear that state is to reload the page.
IE6 and IE7 will allow you to raise a document's domain back to it's actual domain of origin. If a page was served from one.foo.com, and you lower it to foo.com, IE will let you raise it back to one.foo.com. However, I've seen some instabilities and inconsistencies in the aftermath of "raising shields", so I don't recommend relying on this behavior. Since Firefox doesn't allow restoring domains to their original values, you should ignore the fact that IE sort of does allow it.
Bridging Silos Via Least Common Denominators
When an HTML document's domain is lowered to a parent domain, the security context and JavaScript symbol space of that document joins the security context and JavaScript symbol space of any and all pages that are also in the parent domain. JavaScript in your page served from one.foo.com and lowered to foo.com can access JavaScript functions and variables defined in other pages whose domain is foo.com, and visa-versa.
So, if you have pages on one.foo.com that would like to interoperate with pages on two.foo.com, you can use domain lowering to pull down the domain barriers just enough to allow them to talk to each other, but still provide domain protections against third parties trying to steal or corrupt the internal state of your web app. Place a JavaScript block at the top of each page in the "one" and "two" subdomains which assigns document.domain = "foo.com" and you're good to go. All the pages will operate as though they were served from the same domain, and can access anything in each other's DOMs and JavaScript symbol space.
One or the Other, Not Both
Note that once your one.foo.com page has been lowered into the parent domain, your HTML and JavaScript code loses all access to DOMs and JavaScript data in any other pages that are still in the original one.foo.com subdomain. A web page can only be in one domain context or the other, not both.
Interesting Inconsistencies
Domain lowering applies only to the DOM and JavaScript sandboxes. Parts (actually, nearly all) of the browser execute in native machine code outside the browser security sandbox. Native objects exposed to JavaScript in the sandbox are largely on their own to implement appropriate security checks on operations initiated by JavaScript. JavaScript can't access the local file system, for example, but if the user installs an ActiveX control for IE or a browser plugin for Firefox that allows local file access, and that extension declares itself safe for scripting, then JavaScript could use that control to access files on the local file system.
In both IE and Firefox, XMLHttpRequest (XHR) is a native object exposed to JavaScript. This is pretty obvious in IE6 since you have to construct the object using ActiveXObject; in Firefox you can deduce that the XHR is a native object from the phrasing of some error messages and error behaviors while the browser goes down in flames.
XHR is restricted to connecting only to the current HTML page's domain of origin. Domain lowering applies only to the browser sandbox. XHR operates outside the browser sandbox, enforcing same-origin domain policy on its own. This leads to an interesting - and valuable - inconsistency:
XMLHttpRequest is not affected by domain lowering.
This means you can actually have one foot in each domain: Your JavaScript executes in the context of the lowered subdomain (foo.com), but XHR requests made by your JavaScript are held to the domain restriction of the page's original subdomain (one.foo.com). XHR doesn't know anything about document.domain.
If you're trying to get your JavaScript to open an XHR to a resource on foo.com, this can be infuriating because XHR won't do it. You have to refer to an HTML page served from foo.com in order to get XHR to open a connection to foo.com.
The Money Shot
This inconsistency in the handling of document.domain enforcement/awareness makes the following scenario possible: The logic of your web app runs in the context of a page loaded from one.foo.com, and you want to XHR load data from two.foo.com.
Here's how you do that:
- Make your html page A served from one.foo.com lower its document.domain to foo.com
- Place an html page B on two.foo.com, and have it lower its document.domain to foo.com early in its load cycle. (A JavaScript statement in global scope in the <head> section is fine).
- Implement a function GetData(callback) on this page that constructs an XHR request to load the desired data from two.foo.com. Wire up the XHR onReadyStateChanged to process the data completion using a function implemented in B.html, and in that function pass the received data to the callback function passed into GetData().
- Insert an invisible (1x1 pixel) iframe on page A and set its src to http://two.foo.com/B.html
- After page A has fully loaded, and page B in the iframe has loaded, JavaScript code in page A can call the GetData() function in page B through the iframe element: bframe.window.GetData(mycallback)
Believe it or not, this works. Domain lowering allows JavaScript to call between A and B, and the fact that B is served from two.foo.com allows the XHR request implemented in B to access two.foo.com.
Here Be Pixies. (Try Not To Piss Them Off)
The path through this murky realm is neither straight nor wide. If you take liberties or shortcuts with this recipe, be careful to test your code thoroughly on multiple browsers. Chances are high that any deviation will lead to failure on one of the browsers.
IE is fairly flexible in this area. You don't actually have to implement the GetData function in the B page. You can just construct in the A context an XHR object type from the B context and use it directly in the A context. ( var xhr = new bframe.window.XMLHttpRequest() ) For IE, the B page need only lower the domain to foo.com. After that, all the driving can be done from A.
Firefox is more particular about this technique. Firefox will allow you to construct an instance of the B XHR in the context of A, but you'll get access denied or weirder errors when you try to call the methods of the B XHR from the context of A. Firefox gets confused when you call native object methods across these convoluted domain bridges, but calling JavaScript functions and methods works fine on either side of the context boundary. Once the JavaScript call context gets from A to B, then the native object method calls will work.
This is also why step 3 above mandates that the XHR onReadyStateChange event handler should be wired to a function implemented in the B page - the native XHR object operating in the B context may have difficulty firing an event wired to a function in the A page context.
The Downside to Homogeneity
For domain lowering to work between two subdomains, both sides have to "lower their shields" to a common middle ground. As this technique catches on across departments and their corresponding subdomains, you can quickly reach a point where just about all the subdomains on the corporate web have provisions to lower their domain to the common corporate parent domain.
This is convenient and quite powerful for building web apps that can access data bits from all across the company. The problem is that it weakens your corporate defenses across the board. If just one of the subdomain silos were compromised and an attacker were able to inject malicious JavaScript to execute in the browser context of that compromised subdomain, that malicious code would have easy access to every subdomain across the company that lowers its domain to foo.com.
This risk grows with scale. The more subdomains you have that routinely lower their domains to the common ground, the greater the risk that one of them may be compromisable and serve as a beachhead to your entire network.
Tune In Next Time
There is a way to mitigate this weakest link risk such that an attacker compromising a weak subdomain does not get access to everything. This requires inverting some of the relationships presented in this article and making the silos deeper rather than shallower. I'll cover "Siloed Domain Lowering" in my next cross-domain article.
Windows Live Quantum Mechanics -
MSN just launched The Podium '08 as part of their 2008 US Presidential election coverage. The Podium '08 brings together data on presidential candidates for voters and election followers to explore by topic and compare candidates head to head on specific issues.
What's interesting about The Podium is that the content is not canned editorial material. When you select a candidate and click on a specific issue (say, Immigration) to see where the candidate stands on that issue, the list of articles displayed is actually drawn from Live Search on the fly. As new articles appear on the web on these candidates and these topics, those articles will appear in The Podium 08 for that candidate and topic.
The Podium 08 is built using Silverlight 1.0 to present a slick, modern rich UI experience that seamlessly and intelligently integrates services on the back-end.
Want to see what Software plus Services means to the average Joe? Take a look at The Podium 08.
Windows Live Quantum Mechanics -
Yesterday the Seattle Times ran an article about Penny Arcade and the overnight success of the Penny Arcade Expo. I had to laugh a little when the article used the words "imploded" and "E3" in the same sentence. I used pretty much the same pairing of words back in my January 2007 Events Calendar post.
The Seattle Times article has more timely data than that January post, naturally. PAX2007 is expecting some 30,000 people through its doors this weekend. Thirty Thousand! Jiminy Cricket! PAX2005 was only 1500 or so people (and 3x the expected turnout even then).
E3 Dies Again
In other news, FiringSquad reports that the new event that came out of nowhere, E for All Expo, is having trouble attracting major exhibitors. Sony is not interested, Microsoft is noncommittal. The only player signed up so far is Nintendo. E for All Expo is the brainchild of IDC, the very makers and destroyers of the late great E3 Expo. If this is IDC's attempt to rectify their choice to kill consumer access to E3, it sounds like the vendors are not playing ball. And why should they? IDC has a terrible track record with the consumer market.
Windows Live Quantum Mechanics -
Windows Live SkyDrive (formerly known as Folders) is now in beta, enabling end users to store arbitrary data on the web under password access control. Files can be accessed over http(s) from web pages and from stand-alone client applications (thanks to the http file handler add-on in XPSP2). Files can be private to your Windows LiveID only, shared with other specific users (via their Windows LiveID), or publicly accessible to everyone on the Internet, anonymously.
The layout feels similar to SharePoint, with web-based directory trees and file metadata browsing and editing. There's no mention of drive letter mapping (ala file shares) in the SkyDrive intro docs, but I'm sure someone will create a utility to map your private SkyDrive folder to a local drive letter. It'd certainly be a slick way to shortcut the traditional file upload process.
SkyDrive isn't a web host - it's not intended to be the place from which you run a web app (html content), but you can store files in SkyDrive that are referenced by your web app running on your own server or hosted provider. Browser cross-domain barriers stilly apply: you can easily reference JavaScript or image files stored on your SkyDrive from your web site, but the JavaScript in your web pages will not be able to read or write the SkyDrive files directly because they reside in a different domain than your web app.
You can link to individual files in your SkyDrive storage using plain old URLs, like this: Paradoxes in Web App Development or you can embed a "badge" for the file in your web page in a couple of different styles, like this:
or this:
You can also embed a folder to direct viewers to whole directories of related file content:
This will make it a lot easier to post presentation slide decks, podcasts, code samples and demo app source code for blog articles!
Windows Live Quantum Mechanics -
Another month, another release! This month we've added incremental search to the contacts and presence controls to make it easier to find a particular contact in your haystack of hundreds of family, friends, and coworkers. Just type in a few letters of the name or word you're looking for, and the control will reduce the list of displayed contacts to only those that contain that letter sequence, anywhere in the contact display name, case insensitive.
Check it out in our little control testbed apps: http://dev.live.com/mashups/trycontactscontrol and http://dev.live.com/mashups/trypresencecontrol
While we were at it, we also added support for filtering the list by group as well. Click on the dropdown button to the right of the search box to select from a list of groups you have defined in your addressbook. In the Contacts Control in tile view, you can also filter by online state, to display only your buddies that are online, for example.
We've cleaned up the control UI a bit, too. The info panel below the contacts list didn't get favorable reviews from the field, so we've removed it to make room for displaying more contacts in our always-cramped-for-display-real-estate web control. The edit and delete buttons that bordered the info panel have been moved to the display contact details page. You really ought to review the details before editing or deleting anyway, so putting them all on the same page makes sense.
What do you need to do to pick up these new features? Nothing! It's an inline release on the v0.3 version. As long as you're referencing http://controls.services.live.com/scripts/base/v0.3/live.js and http://controls.services.live.com/scripts/base/v0.3/controls.js in your web page, you'll get these enhancements and refinements for free.
Enjoy!