Search code examples
javascriptfirefox-addondom-events

Why is this JavaScript page redirect so slow?


I'm implementing a Firefox plugin. In the plugin's toolbar, I capture the current page and redirect users to the UK Google when they try to go to the Netherlands Google instead. However, this code takes forever to complete. When I type "google.nl" or "google.com/nl", my browser shows the Netherlands page and takes at least 1 second before redirecting.

Is there any way to make the redirect faster? Ideally, I'd like the user to not see the Netherlands Google page at all.

function loadURL(url) {
    window._content.document.location = url;
    window.content.focus();
}

var redirected = false;

function onChange()
{

    var url = gBrowser.selectedBrowser.currentURI.spec;
    url = encodeURIComponent(url);

    if(url.indexOf("google.nl") !=-1 || url.indexOf("hl%3Dnl") !=-1){
        if (!redirected){
            redirected = true;
            loadURL("https://www.google.co.uk/");
            return;
        }
    }else{
        redirected = false;
    }
}

Note: onChange() is triggered by container.addEventListener('DOMSubtreeModified',onChange, false);


Solution

  • First observersation

    Never use DOMSubtreeModified that's a MutationEvent which was supposed to have been removed. You should use MutationObserver

    So in your case instead of container.addEventListener('DOMSubtreeModified, onChange, false); do this:

    const gMutationConfig = {
        subtree: true,
        childList: true
    };
    
    var gMutationFunc = function(ms) {
        for (let m of ms) {
            console.log(m.type, m);
            //if (mutation.addedNodes && mutation.addedNodes.length > 0) { //this test if elements added
            onChange();
        }
    };
    
    var gMutationObserver = new this.DOMWindow.MutationObserver(container);
    

    Second thing is

    You probably should use nsIHTTPChannel for the redirect to be the fastest

    const { Ci, Cu, Cc, Cr } = require('chrome'); //const {interfaces: Ci, utils: Cu, classes: Cc, results: Cr } = Components;
    Cu.import('resource://gre/modules/Services.jsm');
    Cu.import('resource://gre/modules/devtools/Console.jsm');
    
    var observers = {
        'http-on-modify-request': {
            observe: function (aSubject, aTopic, aData) {
                console.info('http-on-modify-request: aSubject = ' + aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
                var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
                var requestUrl = httpChannel.URI.spec
                if (requestUrl.indexOf('google.com') > -1) {
                   //httpChannel.cancel(Cr.NS_BINDING_ABORTED); //this aborts the load
                   httpChannel.redirectTo(Services.io.newURI('data:text,url_blocked', null, null)); //can redirect with this line, if dont want to redirect and just block, then uncomment this line and comment out line above (line 17)
                }
            },
            reg: function () {
                Services.obs.addObserver(observers['http-on-modify-request'], 'http-on-modify-request', false);
            },
            unreg: function () {
                Services.obs.removeObserver(observers['http-on-modify-request'], 'http-on-modify-request');
            }
        }
    };
    

    To start observing

    To start start obseving all requests do this (for example on startup of your addon)

    for (var o in observers) {
        observers[o].reg();
    }
    

    To stop observing

    Its important to stop observring (make sure to run this at least on shutdown of addon, you dont want to leave the observer registered for memory reasons)

    for (var o in observers) {
        observers[o].unreg();
    }
    

    Full working example of the observer service to block/redirect urls: https://github.com/Noitidart/PortableTester/tree/block-urls