Search code examples
firefox-addonfirefox-addon-sdkxpcom

How to implement XPCOM component (nsIContentPolicy) in bootstrapped Firefox extension


I have a bootstrapped extension for Firefox. And now I want to implement nsIContentPolicy XPCOM component. I wrote a component module code. And now I want to register this component. The reason I want to register component is that I want to add my component to nsICategoryManager.addCategoryEntry with "content-policy" category.

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

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

//console.error("Running interceptor");

function Interceptor() 
}

Interceptor.prototype = {

    classDescription: "DeferredTo HTTP requests Interceptor",
    classID: "{B5B3D9A0-08FC-11E3-8253-5EF06188709B}",
    contractID: "@deferredto.com/Interceptor;1",
    QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy]),

    shouldLoad : function dt_shouldLoad(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
        console.log("dt_shouldLoad");

        if (contentLocation.scheme != "http" && contentLocation.scheme != "https")
            return Ci.nsIContentPolicy.ACCEPT;

        let result = Ci.nsIContentPolicy.ACCEPT;

        // we should check for TYPE_SUBDOCUMENT as well if we want frames.
        if ((Ci.nsIContentPolicy.TYPE_DOCUMENT == aContentType) &&
            SOME_REGULAR_EXPRESSION.test(aContentLocation.spec)) {
            // do stuff here, possibly changing result.
        }
        return result;
    },

    shouldProcess: function ILO_shouldProcess() Ci.nsIContentPolicy.ACCEPT,

    _xpcom_categories: [
        { category: "content-policy", service: true }
    ],
    classInfo: XPCOMUtils.generateCI(
    {classID: Components.ID("{B5B3D9A0-08FC-11E3-8253-5EF06188709B}"),
     contractID: "@deferredto.com/Interceptor;1",
     classDescription: "Interceptor implements nsIContentPolicy to block images that are not yet at screen @DeferredTo",
     interfaces: [
                  Ci.nsIContentPolicy,
                  ],
     flags: Ci.nsIClassInfo.SINGLETON})
}

var components = [Interceptor];

var NSGetFactory = XPCOMUtils.generateNSGetFactory([Interceptor]);

Questions:

  • Is it possible to register the component from bootstrapped extension?
  • Is it possible to register the component from restartless extension?
  • Is it possible to use nsICategoryManager.addCategoryEntry "content-policy" without component?
  • How to register the component in bootstrapped extension or somehow add new "content-policy" category entry?

I've added to harness-options.js

"requirements": {
"sdk/page-mod": "sdk/page-mod",
"sdk/self": "sdk/self",
"chrome": "chrome"},

That is how I try to import module:

var {Cc, Ci, Cu} = require("chrome");
Cu.import("resource://deferredto/lib/interceptor.js");

I' ve tried many paths ))) But none works. resource entry in chrome.manifest file does not allowed for bootstrapped extensions. The path to component module file is: resources/deferredto/lib/interceptor.js


Solution

  • Now my nsIContentPolicy sdk-based component look like this. File interceptor.js:

    'use strict';
    
    var { Class } = require('sdk/core/heritage');
    var xpcom = require('sdk/platform/xpcom');
    var { Cc, Ci, Cu, Cm } = require('chrome');
    var categoryManager = Cc["@mozilla.org/categorymanager;1"]
                          .getService(Ci.nsICategoryManager);
    
    
    // nsIDOMNode
    const TYPE_DOCUMENT_NODE        = Ci.nsIDOMNode.DOCUMENT_NODE;
    
    
    /// Interceptor
    
    
    var contractId = "@deferredto.com/Interceptor;1";
    
    var Interceptor = Class({
      extends:  xpcom.Unknown,
      interfaces: [ 'nsIContentPolicy' ],
      get wrappedJSObject() this,
    
      shouldLoad : function dt_shouldLoad(contentType, contentLocation, requestOrigin, context, mimeTypeGuess, extra) {
    
            let result = Ci.nsIContentPolicy.ACCEPT;
    
            return result;
        },
    
        shouldProcess: function () Ci.nsIContentPolicy.ACCEPT
    });
    
    var factory = xpcom.Factory({
      contract: contractId,
      Component: Interceptor,
      unregister: false // see https://bugzilla.mozilla.org/show_bug.cgi?id=753687
    });
    
    /// unload 
    var unload = require("sdk/system/unload");
    
    unload.when(function() {
      function trueUnregister() {
        categoryManager.deleteCategoryEntry("content-policy", contractId, false);
        try {
          console.log("xpcom.isRegistered(factory)="  + xpcom.isRegistered(factory));
          console.log("trueUnregister");
          xpcom.unregister(factory);
          console.log("xpcom.isRegistered(factory)="  + xpcom.isRegistered(factory));
        } catch (ex) {
            Cu.reportError(ex);
        }      
      }
      if ("dispatch" in Cu) {
        console.log('"dispatch" in Cu');
        Cu.dispatch(trueUnregister, trueUnregister);
      } else {
        console.log('"dispatch" not! in Cu');
        Cu.import("resource://gre/modules/Services.jsm");
        Services.tm.mainThread.dispatch(trueUnregister, 0);
      }
    });
    
    
    //xpcom.register(factory);
    
    var interceptor = Cc[contractId].createInstance(Ci.nsIContentPolicy);
    
    categoryManager.deleteCategoryEntry("content-policy", contractId, false);
    categoryManager.addCategoryEntry("content-policy", contractId, contractId, false, true);
    

    And you can use it from sdk like this:

    var interceptor = require("./interceptor");