Having some trouble intercepting AJAX events - suggestions please? :)

G’day all,

Just started working on an addon which involves a button/hotkey to stop all current and future network activity in a tab, until user initiates a change (clicking a link, typing a new addy in the bar, pressing Enter etc).

Unfortunately the following code does not appear to capture events such as those seen when typing into a search box on www.google.com or www.duckduckgo.com - a little bit stumped as to why not (it simply doesn’t fire any of these onChanges at all). :confused:

Any suggestions as to what I may be doing wrong, or another way to approach? Any help would be much appreicated :grin:

myWebProgressListener.init();
var myWebProgressListener = {
    init: function() {
        var webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress);
        webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW | Ci.nsIWebProgress.NOTIFY_LOCATION);
    },
    uninit: function() {
        if (!docShell) {
            return;
        }
        var webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress);
        webProgress.removeProgressListener(this);
    },

    onStateChange: function(webProgress, aRequest, flags, status) {
        console.log('onStateChange:', arguments);
        if (aRequest) {
            aRequest.cancel(Cr.NS_BINDING_ABORTED)
        }
    },
    onLocationChange: function(webProgress, aRequest, locationURI, flags) {
        console.log('onLocationChange:', arguments);
        if (aRequest) {
            aRequest.cancel(Cr.NS_BINDING_ABORTED)
        }
    },
    onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {
        console.log('onStatusChange:', arguments);
        if (aRequest) {
            aRequest.cancel(Cr.NS_BINDING_ABORTED)
        }
    },
    onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
        console.log('onProgressChange:', arguments);
        if (aRequest) {
            aRequest.cancel(Cr.NS_BINDING_ABORTED)
        }
    },
    onSecurityChange: function(aWebProgress, aRequest, aState) {
        console.log('onSecurityChange:', arguments);
        if (aRequest) {
            aRequest.cancel(Cr.NS_BINDING_ABORTED)
        }
    },
    QueryInterface: function QueryInterface(aIID) {
        if (aIID.equals(Ci.nsIWebProgressListener) || aIID.equals(Ci.nsISupportsWeakReference) || aIID.equals(Ci.nsISupports)) {
            return this;
        }

        throw Components.results.NS_ERROR_NO_INTERFACE;
    }
};

The code for this simple addon is here:

This is the framescript that is injected, it is basically the above: Full-Stop/resources/scripts/framescript.js at master · Noitidart/Full-Stop · GitHub

We use CUI.jsm to add a button and then on click of it we insert this framescript. Very simple: Full-Stop/bootstrap.js at master · Noitidart/Full-Stop · GitHub

I’m not sure why its not catching AJAX and other background requests, does anyone know why?

This user on stackovrflow asked

"how to retrieve the IP address for every request(images, ajax, initial, etc.) "

and a solution of nsiWebProgressListener was given, so I expect that it should catch ajax, images, etc, here it is:

So Im real confused why its not, working for @Gliktch above

According to Lithopsian in another thread, we need to use http- observers and then filter out by originating tab browser (to cull the list down to network activity in our own tab), then we can take action on specific connection attempts in the ‘Fully Stopped’ tab.

Looks like http-on-opening-request, to capture new events in a tab, and if the connection is already open, then http-on-modify-request as per this example will do the trick:

Components.utils.import('resource://gre/modules/Services.jsm');
Services.obs.addObserver(httpObs, 'http-on-modify-request', false);

var httpObs = {
observe: function (aSubject, aTopic, aData) {
        if (aTopic == 'http-on-modify-request') {
            var oHttp = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
            var interfaceRequestor = oHttp.notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
            var loadContext;
            try {
                loadContext = interfaceRequestor.getInterface(Components.interfaces.nsILoadContext);
            } catch (ex) {
                try {
                    loadContext = aSubject.loadGroup.notificationCallbacks.getInterface(Components.interfaces.nsILoadContext);
                    // in ff26+, aSubject.loadGroup.notificationCallbacks was null for me, I couldnt find a situation where it wasnt null, but whenever this was null, and a loadContext is supposed to be there, I found that "interfaceRequestor.getInterface(Components.interfaces.nsILoadContext);" worked fine, so I'm thinking in ff26+ it doesnt use aSubject.loadGroup.notificationCallbacks anymore, but I'm not sure
                } catch (ex2) {
                    loadContext = null;
                }
            }
            var url = oHttp.URI.spec; // can get url without needing loadContext
            if (loadContext) {
                var contentWindow = loadContext.associatedWindow; //this is the HTML window of the page that just loaded
                // aDOMWindow this is the firefox window holding the tab
                var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
                var gBrowser = aDOMWindow.gBrowser; // this is the gBrowser object of the firefox window this tab is in
                var aTab = gBrowser._getTabForContentWindow(contentWindow.top); // this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above // can stylize tab like aTab.style.backgroundColor = 'blue'; and aTab.style.fontColor = 'red';
                var browser = aTab.linkedBrowser; // this is the browser within the tab
            } else {
                Components.utils.reportError('EXCEPTION: Load Context Not Found!');
                // this is likely no big deal as the channel proably has no associated window, ie: the channel was loading some resource. but if its an ajax call we may end up here
            }
        }
    }
};

// Services.obs.removeObserver(httpObs, 'http-on-modify-request'); When we want to remove the observer

Noooooooo I figured it out!!!

So silly! When we add the progress listener we werent passing in the right flags. This is what we did:

webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW | Ci.nsIWebProgress.NOTIFY_LOCATION)

We need to do this:

webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL)

and boom :slight_smile: try it out! :slight_smile: