Blocking images (and other content) with Mozilla Add-on SDK and nsIContentPolicy

Using XPCOM with the add-on SDK has been a difficult task for me lately since most of it remains undocumented, and the main MDN information can be puzzling because it describes the traditional methods to create extensions. A useful example I found online is the Widgeon add-on, which implements nsIContentPolicy: http://code.google.com/p/widgeon/source/browse/trunk/jetpack/lib/about-widgets.js?r=39

But in order to intercept the load of various content types, we also need to register the content-policy with nsICategoryManager.

Here is an example of a module, for an sdk addon, that uses nsIContentPolicy to prevent images from loading. Here is a file I called preventimage.js and placed in the lib/ folder:

const {Cc, Ci, Cu, Cm, Cr, components} = require("chrome");
const xpcom = require("xpcom");
var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm");

exports.preventimage = function() {}

exports.preventimage.prototype = {
    classDescription:   "Implements content policy to prevent images from being loaded",
    classID:            components.ID("{ff795b25-dad0-43c5-9da2-7ffe3a6343f8}"),
    contractID:         "@lduros.net/PreventImage-policy",
    _xpcom_categories:  [{ category: "content-policy"}],
    QueryInterface:     XPCOMUtils.generateQI([Ci.nsIContentPolicy]),

   shouldLoad: function (contType, contLoc, reqOrig, ctx, typeGuess, extra) {
      if (contType === 3) {
            return Ci.nsIContentPolicy.REJECT;
          }
         else {
            return Ci.nsIContentPolicy.ACCEPT;
         }
    },

    shouldProcess: function (contType, contLoc, reqOrig, ctx, mimeType, extra) {
       return Ci.nsIContentPolicy.ACCEPT;
    }
};

xpcom.register({
     create:     exports.preventimage,
     name:       exports.preventimage.prototype.classDescription,
     contractID: exports.preventimage.prototype.contractID,
     uuid:       exports.preventimage.prototype.classID
});

shouldLoad gets triggered every time an element is about to load, and 3 correspond to images. So the component should allow everything except images. Now that we are done with this, we have to let the rest of the application know about the new content policy. To do so, we must register the component with the nsICategoryManager component.

Here is the main.js for the add-on:

var {Cc, Ci, Cu} = require("chrome");
var xpcom = require("xpcom");
var pi = require("preventimage");

var categoryManager = Cc["@mozilla.org/categorymanager;1"]
                      .getService(Ci.nsICategoryManager);

try {

   var imageBlocker = Cc["@lduros.net/PreventImage-policy"]
                      .getService(Ci.nsIContentPolicy);           
   categoryManager.addCategoryEntry("content-policy", "preventimage.preventimage", "@lduros.net/PreventImage-policy", false, true);

} catch (anError) {
  dump("ERROR: " + anError);
}

The result is an SDK add-on that prevents the loading of images, from the CSS, from the HTML, and anywhere else:

no image

No image is displayed. This functionality is used by many traditional Firefox add-ons such as NoSCript or Adblock.

One of the issues I had was to leave the aPersist argument as "true" in the addCategoryEntry call. This makes an error when trying to run the add-on. I guess the category might not be able to persist across application sessions with the SDK.