Sunday, June 10, 2012

Facebook's cross-domain handler upgrades..

If you've read any postings about Facebook's cross-domain handling code, Facebook has gone to great lengths to implement support for it between most modern browsers.  The main use case is Facebook's Login Social Plugin, which opens a popup window that prompts to fill out a form that will prompt you for your email/password:




This popup needs to communicate with the parent window to send back information about what to do next upon successful login.   Since the parent window is most likely a page hosted on your site and the popup is a window hosted from facebook.com, there has to be a way for a successful login to pass a message between windows hosted on different sites.  Usually browser same-origin security policies will prevent such data exchanges, but there are legitimate use cases to allow messages to pass between windows, which is why the HTML5 postMessage function was introduced.

Older browsers such as Internet Explorer 7 don't have support for HTML5 postMessage, so an alternate way using Adobe Flash was used instead.   The idea was to rely on ActiveX objects to implement an equivalent postMessage functionality in Flash.  If you're curious about the internals of how it was done in Flash, you can read here for more information.

The Facebook Javascript SDK has once again gone through a significant number of changes in the last month or so, and while Facebook doesn't openly discuss internals about its code, it's helpful to know in case since some of the revisions actually directly impact how your site may be functioning.  Some of the changes include the following:

1. A lot of the cross-domain code has been completely rewritten.  IE8 and IE9 now appear to be both using the HTML5 postMessage feature natively.  There was one limitation in IE8 in that HTML postMessage could only be used within an IFrame, so Facebook has gone ahead and implemented the suggested workaround.  As a result, IE8 no longer depends on trying to use Adobe Flash and falling back to using basic iFrame message passing if Flash is not available.  IE8 and IE9 now will use its native HTML5 postMessage routine.

2. You may have noticed that the cross-domain code is no longer called xd_proxy.php.  It is now called xd_arbiter.php.  The purpose of both of these files is still the same, which is to send messages to the parent window.  The xd_proxy.php file used to include 3 different callback functions that were embedded as query strings depending on whether there was a successful login: ok_session, no_session, and no_user. You used to be able see all these query strings in the popup window. Now you can't.

Now these 3 different states are no longer shown and embedded as FORM values inside the popup window, depending on the user interaction.  For instance, there is now a cancel_url FORM input value that will close the popup window and return control back to the original frame.

http://static.ak.facebook.com/connect/xd_arbiter.php?version=6#cb=ff5d002c57c23a&origin=http%3A%2F%2F[MYHOST.COM]%2Ff1e938e69c3d116

The most important information passed is the callback (cb) querystring parameter, which contains a global unique identifier (guid) that corresponds to a key in the FB._callbacks dictionary that is used to load the code that is loaded. This callback function should correspond to a key in the parent window. If you close that parent window, you may notice a blank dialog permissions.request screen if you were to login.

3. Within the fb-root tag, there is now an iFrame with the ID fb_xdm_frame_http or fb_xdm_frame_https (depending on the protocol) that will implement the cross-domain receivers, whether they implement via postMessage, Flash, or IFrame's.  You can also figure out which transport mechanism by looking at the channel= query parameter.

<iframe id="fb_xdm_frame_https" name="fb_xdm_frame_https" src="https://s-static.ak.facebook.com/connect/xd_arbiter.php?version=6#channel=f38dfabf84&amp;origin=https%3A%2F%2F[MY_APP_HOSTNAME]&amp;channel_path=%2F%3Ffb_xd_fragment%23xd_sig%3Df3b4c64464%26&amp;transport=postmessage"></iframe>

If you want to better understand how all the cross-domain messages get passed, I've found it useful to deminify the all.js code, substitute the script include, and then putting a breakpoint on the xdRecv handler.  This allows you to see how Facebook decodes the query string parameters in xd_arbiter.php, extracts the callback function guid, and executes the code to set the appropriate cookies on your browser with the signed token response.

In summary, the big win here is that IE8 now uses the native HTML postMessage and therefore no longer depends on the Adobe Shockwave/Flash Add-On in your browser.   You can also uncover which transport mechanism within the iFrame's stored inside the fb-root div tag that you use.

No comments:

Post a Comment