From b2ba3216ea5dbe6a74fdfa75611fce95c1481316 Mon Sep 17 00:00:00 2001 From: Einar Egilsson Date: Fri, 18 Sep 2015 15:42:21 +0000 Subject: Halfway to making Firefox compatible --- background.js | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 background.js (limited to 'background.js') diff --git a/background.js b/background.js new file mode 100644 index 0000000..4dbbdd3 --- /dev/null +++ b/background.js @@ -0,0 +1,222 @@ + +//This is the background script. It is responsible for actually redirecting requests, +//as well as monitoring changes in the redirects and the disabled status and reacting to them. + +//TODO: Better browser detection... +var isFirefox = false; + +if (typeof chrome == 'undefined') { + isFirefox = true; + var firefoxShim = require('./firefox/shim'); + chrome = firefoxShim.chrome; + Redirect = firefoxShim.Redirect; +} +//Hopefully Firefox will fix this at some point and we can just use onBeforeRequest everywhere... +var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest; + +//Redirects partitioned by request type, so we have to run through +//the minimum number of redirects for each request. +var partitionedRedirects = {}; + +//Keep track of tabids where the main_frame url has been redirected. +//Mark it as green until a new url is loaded. +var tabIdToIcon = { + +}; + +//Cache of urls that have just been redirected to. They will not be redirected again, to +//stop recursive redirects, and endless redirect chains. +//Key is url, value is timestamp of redirect. +var ignoreNextRequest = { + +}; + +function log(msg) { + if (log.enabled) { + console.log('REDIRECTOR: ' + msg); + } +} +log.enabled = true; + +function setIcon(image19, image38, tabId) { + var data = { + path: { + 19: image19, + 38: image38 + } + }; + if (typeof tabId !== 'undefined') { + data.tabId = tabId; + } + chrome.browserAction.setIcon(data, function(tab) { + var err = chrome.runtime.lastError; + if (err) { + //If not checked we will get unchecked errors in the background page console... + log('Error in SetIcon: ' + err.message); + } + }); +} + +//This is the actual function that gets called for each request and must +//decide whether or not we want to redirect. +function checkRedirects(details) { + + //We only allow GET request to be redirected, don't want to accidentally redirect + //sensitive POST parameters + if (details.method != 'GET') { + return null; + } + + log('Checking: ' + details.type + ': ' + details.url); + + var list = partitionedRedirects[details.type]; + if (!list) { + log('No list for type: ' + details.type); + return null; + } + + var timestamp = ignoreNextRequest[details.url]; + if (timestamp) { + log('Ignoring ' + details.url + ', was just redirected ' + (new Date().getTime()-timestamp) + 'ms ago'); + delete ignoreNextRequest[details.url]; + return null; + } + + for (var i = 0; i < list.length; i++) { + var r = list[i]; + var result = r.getMatch(details.url); + + if (result.isMatch) { + + log('Redirecting ' + details.url + ' ===> ' + result.redirectTo + ', type: ' + details.type + ', pattern: ' + r.includePattern); + + /* Unfortunately the setBrowserIcon for a specific tab function is way too unreliable, fails all the time with tab not found, + even though the tab is there. So, for now I'm cancelling this feature, which would have been pretty great ... :/ + if (details.type == 'main_frame') { + log('Setting icon on tab ' + details.tabId + ' to green'); + + setIcon("images/icon19redirected.png", "images/icon38redirected.png", details.tabId); + tabIdToIcon[details.tabId] = true; + }*/ + ignoreNextRequest[result.redirectTo] = new Date().getTime(); + + return { redirectUrl: result.redirectTo }; + } + } + + /* Cancelled for now because of setBrowserIcon being really unreliable... + if (details.type == 'main_frame' && tabIdToIcon[details.tabId]) { + log('Setting icon on tab ' + details.tabId + ' back to active'); + setIcon("images/icon19active.png", "images/icon38active.png", details.tabId); + delete tabIdToIcon[details.tabId]; + }*/ + + return null; +} + +//Monitor changes in data, and setup everything again. +//This could probably be optimized to not do everything on every change +//but why bother? +chrome.storage.onChanged.addListener(function(changes, namespace) { + if (changes.disabled) { + updateIcon(); + + if (changes.disabled.newValue == true) { + log('Disabling Redirector, removing listener'); + redirectEvent.removeListener(checkRedirects); + } else { + log('Enabling Redirector, setting up listener'); + setUpRedirectListener(); + } + } + + if (changes.redirects) { + log('Redirects have changed, setting up listener again'); + setUpRedirectListener(); + } +}); + +//Creates a filter to pass to the listener so we don't have to run through +//all the redirects for all the request types we don't have any redirects for anyway. +function createFilter(redirects) { + var types = []; + for (var i = 0; i < redirects.length; i++) { + redirects[i].appliesTo.forEach(function(type) { + if (types.indexOf(type) == -1) { + types.push(type); + } + }); + } + types.sort(); + + return { + urls: ["http://*/*", "https://*/*"], + types : types + }; +} + +function createPartitionedRedirects(redirects) { + var partitioned = {}; + + for (var i = 0; i < redirects.length; i++) { + var redirect = new Redirect(redirects[i]); + redirect.compile(); + for (var j=0; j