January 16, 2015

The problem at https://developers.facebook.com/bugs/791622154267956 seems to have fixed itself, but there was nothing on the bug report to indicate that it was resolved. There were enough people this week who said that things were working again, so it wasn't clear what had happened.

After tracing through Facebook's minified JS over the weekend, I came upon a tangential issue that referred a module named "quickling." It turns out that Quickling refers to Facebook's entire Ajax framework:

Many of our users saw that blank content area with the Facebook toolbar at the top. The blank area seemed to indicate that the Quickling framework was blanking the screen after successful logins. On this blank page, it was supposed to redirect back to our site -- the problem was that a lot of users were seeing "Errors on the Page" on the bottom left corner and weren't able to complete the auth flow.

I took a snapshot of the breaking JavaScript in question -- essentially the file is a shim for all the JS methods that aren't included with Internet Explorer. What I was looking for in this code was where the redirect URL would happen. I managed to confirm the section of the code is the goURI() function that usually gets executed on successful redirects. It was easier to use IE9 than IE8 to identify this function, which has the ability to debug minified JavaScript. In addition, without using an IE-based version, this file didn't seem to get loaded.

__d("goURI", ["URISchemes"], function(a, b, c, d, e, f, g) {
    function h(i, j, k) {
        i = i.toString();
        if (/^([^.:/?#]+):/.test(i) && !g.isAllowed(RegExp.$1)) throw new Error('goURI: URI scheme rejected, URI: ' + i);
        if (!j && a.PageTransitions && a.PageTransitions.isInitialized()) {
            a.PageTransitions.go(i, k);
        } else if (window.location.href == i) {
            window.location.reload();
        } else window.location.href = i;
    }
    e.exports = h;
}, null);

Note: The function __d() is basically equivalent to their require() function used in RequireJS. The first parameter is the module name being declared, the second declares the module depedencies, and the third provides references to the declared dependencies, including 6 default ones that are always included (see http://connect.facebook.net/en_US/all/debug.js for more context.)

Comparing against what this IE-specific code is today, it looks like the code that injects itself for checking load times (called "Calvary" -- http://davidwei.org/cv/talks/FacebookFrontEnd_Velocity2009.pdf) wasn't being wrapped in a require block.

Old file: https://fbstatic-a.akamaihd.net/rsrc.php/v2/yP/r/ZUMgdMGlluT.js
New file: https://fbstatic-a.akamaihd.net/rsrc.php/v2/yD/r/ZCm6GakvyT5.js

< /*!CK:3945686364!*//*1420495125,*/
---
> /*!CK:2123995118!*//*1421197783,*/
3c3
< if (self.CavalryLogger) { CavalryLogger.start_js(["FwIBa"]); }
---
> (self.TimeSlice ? self.TimeSlice.guard : function(f) { return f; })(function() {if (self.CavalryLogger) { CavalryLogger.start_js(["lPiYN"]); }

< __d("setIntervalAcrossTransitions",[],function(a,b,c,d,e,f){function g(h,i){return setInterval(h,i,false);}e.exports=g;},null);
---
> __d("setIntervalAcrossTransitions",["TimeSlice"],function(a,b,c,d,e,f,g){var h=a.setInterval;e.exports=function(){for(var i=[],j=0,k=arguments.length;j<k;j++)i.push(arguments[j]);i[0]=g.guard(i[0],'setInterval');return h(i[0],i[1],i[2],i[3],i[4],i[5]);};},null);

I suspect it's the changes in this diff that helped resolve our issues this past week. At the very least, it has some connection to the 2nd bug I encountered that eventually led to these findings.



blog comments powered by Disqus