Sunday, November 19, 2017

Expires? Pragma? Cache-Control? Anybody home?... Yay! (exclusively for the Fox on Fire)

As you may already have noticed, from my previous articles and my (limited) GitHub contributions, that I am an absolute Firefox (FF) fan (though I cannot really call myself a Mozillian yet). Some of my recent endeavors with FF brought me closer to FF's internal and add-on APIs, which happen to be somewhat tough but quite interesting to work with.

I have been running an ancient FF version (45.0) until recent times, as I had too much to lose (and migrate) in terms of customizations if I decided to upgrade. Besides, I loved the single-process elegance of FF, amidst the endless "multiprocess Chrome is eating up my RAM!" complaints from the "Chromians" all around. I even downloaded a Nightly several months ago, but did not proceed to install it as it would simply involve too much hassle. Meanwhile, needless to say, I was continually being bombarded with sites howling "WTF is your browser? It's stone-age!" (in more civilized jargon, of course).

About a month ago I finally gave in, and installed the old nightly just to get the hang of the new FF. I must say I wasn't disappointed—in fact, I was a bit impressed. The multiprocess version didn't seem to be as bad as Chrome in terms of memory footprints (although I had to keep on restarting the browser every week; possibly due to some memory leaks introduced by my customizations?), and the addons too had matured to be e10s compatible. All was going fine...

... until I tried to reload the Gmail mobile page that I just visited, in offline mode.

I was baffled when, instead of the cached page, I was smacked with an "Offline Mode" error message.

What the... has FF stopped caching pages?

Nope, some pages still get loaded perfectly under offline mode.

Then where's the problem?

Maybe Gmail has set some brand-new cache-prevention header, right by the time I was busy setting up my new browser?

Luckily I had left my old browser intact; and no, it continued to cache the same page just fine.

Maybe the actual response from mail.google.com would give a clue.

Well, that was it. Gmail had been sending an Expires: Mon, 01 Jan 1990 00:00:00 GMT header, and my dear old FF 45.0 seems to have somehow been neglecting it all this time, hence unintentionally offering me the luxury of being able to view cached Gmail mobile pages all the way until the end of the current session.

Now that the "feature" was gone, I was basically doomed.

Worse still, the new "compiance" had rendered several other sites uncacheable: including Facebook, Twitter and even Google Search.

Of course you realize, this means war.

Reading a few MDN docs and browsing the FF Addons site, I soon realized that I was going to be all alone on this one. So I set forth, writing a response interceptor based on the Observer_Notifications framework, to strip off the expiration-related headers from all responses, hopefully before they have a chance of reaching (correction: not reaching) the Cache2.

Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).addObserver({
	observe: function(aSubject, aTopic, aData) {
		var channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
		channel.setResponseHeader("Expires", "", false);
		channel.setResponseHeader("expires", "", false);
		channel.setResponseHeader("cache-control", "", false);
		channel.setResponseHeader("Cache-Control", "", false);
		channel.setResponseHeader("pragma", "", false);
		channel.setResponseHeader("Pragma", "", false);
	}
}, "http-on-modify-request", false);

That's all. Just 11 lines of code, a copy-paste into the browser console (Ctrl+Shift+F12), and a gentle touch on the Enter key.

No, hit it down hard, because you're going to nail it, once and for all!

I registered the handler on the browser, with a handy KeyConfig shortcut to toggle it when required (with some help from my own ToggleService framework; and all was back to normal. In fact it was better than normal, because some sites that were skipping the cache so far, started submitting to my desires right away; and because some self-destruct pages started to live across browser sessions—I could restart the btowser and enjoy viewing the Facebook, Gmail and other pages that usually kept on disappearing from the cache after each restart.

All of it, thanks to the amazing extensibility and customizability of Firefox.

No comments: