Search code examples
javascriptfirefoxfirefox-addon-sdkxpcom

firefox detect tab id in "sdk/system/events" api


Good day. i have problem with porting chromium extension to firefox. i need to detect all outgoing request and id's of tabs to which it belongs. to detect requests i using system/events api, but i can't find a way how to detect id of tab from incomming events. As i understand this events is xpcom objects and i should use QueryInterface to get some interface to get some other interface to get some other interface to get some other interface ..... to get some other interface to get id of tab from it (just like in COM implementation in windows), but i can't find which interface i need, can't find documentation about this events at all...

code which i using in chromium:

chrome.webRequest.onBeforeRequest.addListener(
 function(info) {
     if(info.tabId)
         //do stuff here
 }

so it's what i want to achieve from firefox...

code which i currently write for firefox:

exports.main = function(options)
{
    //stuf here ....
    ........
    function listener(event)
    {
        var channel = event.subject.QueryInterface(Ci.nsIHttpChannel);
        console.log(channel);
        //TODO: get tab here somehow
    }
    events.on("http-on-opening-request", listener);
}

i have looked on xpcom docs few days, but still have not enough info to implement this simple thing... so if someone have success with this, please help.


Solution

  • I just found a code snippet for getting the browser that fires the http-on-modify-request notification. The code there seems to be broken but I used some of it to create this function to get a tab from the channel.

    const getTabFromChannel = (aChannel) => {
      try {
        let notificationCallbacks = aChannel.notificationCallbacks || aChannel.loadGroup.notificationCallbacks;
        if (!notificationCallbacks)
          return null;
    
        let domWin = notificationCallbacks.getInterface(Ci.nsIDOMWindow);
        let chromeTab = tabsUtils.getTabForContentWindow(domWin);
        return getSdkTabFromChromeTab(chromeTab);
      }
      catch (e) {
        // some type errors happen here, not sure how to handle them
        console.log(e);
        return null;
      }
    } 
    

    This function converts the low-level tab to a high-level tab. Depending on which one you need you could skip this function of course. Again, in the latest SDK you probably can replace it with tabs.viewFor(chromeTab).

    const tabs = require("sdk/tabs");
    const tabsUtils = require("sdk/tabs/utils");
    
    const getSdkTabFromChromeTab = (chromeTab) => {
      const tabId = tabsUtils.getTabId(chromeTab);
      for each (let sdkTab in tabs){
        if (sdkTab.id === tabId) {
          return sdkTab;
        }
      }
      return null;
    };
    

    There seems to be a problem that the listener fails when switching between windows when using system/events. Use Services.obs.addObserver instead:

    const httpRequestObserver = {
        observe: function (subject, topic, data) {
            var channel = subject.QueryInterface(Ci.nsIHttpChannel);
            console.log("channel");
            var tab = getTabFromChannel(channel);
            if(tab) {
              console.log("request by tab", tab.id);
            }
        }
    }
    
    exports.main = function() {
      Cu.import('resource://gre/modules/Services.jsm');
      Services.obs.addObserver(httpRequestObserver, 'http-on-opening-request', false);
    }
    

    I can only hope that it works for all the requests you need to detect. The documentation already mentions some cases where it won't work:

    Note that some HTTP requests aren't associated with a tab; for example, RSS feed updates, extension manager requests, XHR requests from XPCOM components, etc.