Search code examples
javascriptgoogle-chrome-extensionchrome-webrequest

chrome.webRequest.onBeforeRequest.addListener not blocking an array of urls


I am trying to block an array of urls based on user input. I have the url array in JSON format, but the sites are not actually being blocked when I navigate to them. If I use only one site, instead of an array, it does get blocked successfully. Here is the function.

function addListener(){
    chrome.webRequest.onBeforeRequest.addListener(
      function(){ return {cancel: true}; },
      {
        urls: blockedUrls()
      },
      ["blocking"]
    );
}

And here is my function blockedUrls.

var blockedUrls = function () {
        chrome.storage.sync.get(['block'], function(result) {
            if (typeof result.block === 'undefined') {
                //blocks is not yet set
                var jobj = ["*://www.whatever.com/*"];
                return [jobj[0]];
                console.log("not set");
            }
            else{
                var xt = JSON.parse(result.block);
                console.log(JSON.stringify(xt.urls));
                return JSON.stringify(xt.urls);
            } 
        });
        return ["*://www.whatever.com/*"];
}

The console.log does print out what I want, which is this (some were just used for testing obviously)

["doesntexist.com","*://www.yahoo.com/*","*://www.xbox.com/*","*://www.hello.com/*","*://www.es/*"]

And, if it helps, here is where the sites get initially set into chrome storage, from the variable request.newSites.

var jsonStr = '{"urls":["doesntexist.com"]}';

                var obj = JSON.parse(jsonStr);

                //add url matching patterns to the urls from user input
                for (var i = 0; i < request.newSite.length; i++){
                    obj['urls'].push( '*://www.' + request.newSite[i] + '/*');
                }

                jsonStr = JSON.stringify(obj);


                chrome.storage.sync.set({'block': jsonStr}, function(){
                    addListener();
                });

Thanks in advance.


Solution

  • There are a couple of problems with your code:

    1) chrome.storage.sync.get's callback function is asynchronous. Therefore, in your function blockedUrls the return value will always be ["*://www.whatever.com/*"], because the line return ["*://www.whatever.com/*"]; will run before chrome.storage.sync.get's callback function.

    2) The second argument of chrome.webRequest.onBeforeRequest listener should be an object in the following form: {urls: theUrls} where theUrls is an Array of strings, not a string.

    Apart from that, you can take advantage of the fact that chrome.storage can store objects and arrays directly, so there is no need to stringify them.

    Try with:

    var obj = {urls: ['*://doesntexist.com/*']};
    
    for (var i = 0, j = request.newSite.length; i < j; i++){
        obj.urls.push( '*://www.' + request.newSite[i] + '/*');
    }
    
    chrome.storage.sync.set({block: obj}, function(){
        addListener();
    });
    
    function addListener() {
        chrome.storage.sync.get('block', function (result) {
            var myUrls = result.block || ["*://www.whatever.com/*"];
            chrome.webRequest.onBeforeRequest.addListener(function(){
                return {cancel: true}
            },
            {urls: myUrls},
            ["blocking"] );
        });
    }