diff options
-rw-r--r-- | icon.html | 2 | ||||
-rw-r--r-- | images/icon19redirected.png | bin | 0 -> 262 bytes | |||
-rw-r--r-- | images/icon38redirected.png | bin | 0 -> 386 bytes | |||
-rw-r--r-- | js/background.js | 196 | ||||
-rw-r--r-- | manifest.json | 2 | ||||
-rw-r--r-- | redirector.html | 2 |
6 files changed, 176 insertions, 26 deletions
@@ -32,7 +32,7 @@ function createImageLink(size, logoFontSize, logoX, logoY) { - var colors = {'#333' : 'active', '#bbb' : 'disabled'}; + var colors = {'#333' : 'active', '#bbb' : 'disabled', 'green' : 'redirected'}; for (var color in colors) { var canvas = document.createElement('canvas'); canvas.width = canvas.height = size; diff --git a/images/icon19redirected.png b/images/icon19redirected.png Binary files differnew file mode 100644 index 0000000..dce8b13 --- /dev/null +++ b/images/icon19redirected.png diff --git a/images/icon38redirected.png b/images/icon38redirected.png Binary files differnew file mode 100644 index 0000000..45c1db8 --- /dev/null +++ b/images/icon38redirected.png diff --git a/js/background.js b/js/background.js index 35b1243..d080504 100644 --- a/js/background.js +++ b/js/background.js @@ -1,50 +1,200 @@ +//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. -function checkForRedirect(details) { +//TODO: Better browser detection... +var isFirefox = !!navigator.userAgent.match(/Firefox\//); +var storage = chrome.storage.local; //TODO: Change to sync when Firefox supports it... + +//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 = { +}; + +function log(msg) { + if (log.enabled) { + console.log(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) { + + log('Checking: ' + details.url); + //We only allow GET request to be redirected, don't want to accidentally redirect //sensitive POST parameters if (details.method != 'GET') { return null; } - if (details.url.match(/mbl\.is/)) { - console.log('Redirecting ' + details.url); - return {redirectUrl: 'http://foo.is'}; //this doesn't work - } - return null; //{redirectUrl: 'http://foo.is'}; //this doesn't work + var list = partitionedRedirects[details.type]; + if (!list) { + log('No list for type: ' + details.type); + return; + } + + for (var i = 0; i < list.length; i++) { + var r = list[i]; + var result = r.getMatch(details.url); + + if (result.isMatch) { + + //Have to check if the result also matches, which would cause a loop... + //Based on tests in chrome it actually looks like we don't get passed the redirect url back into our listener so + //this should be unneccessary. But lets verify on Firefox and Opera first, before removing this code (and the recursive warning in the + //edit box) + var recursiveResult = r.getMatch(result.redirectTo); + if (recursiveResult.isMatch) { + log('Ignoring pattern ' + r.includePattern + ' for url ' + details.url + ', because it would also match the result: ' + result.redirectTo); + } else { + 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; + }*/ + 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(); -var filter = {urls:["http://*/*", "https://*/*"]}; + if (changes.disabled.newValue == true) { + log('Disabling Redirector, removing listener'); + redirectEvent.removeListener(checkRedirects); + } else { + log('Enabling Redirector, setting up listener'); + setUpRedirectListener(); + } + } -//TODO: Better browser detection... -var isFirefox = !!navigator.userAgent.match(/Firefox\//); + if (changes.redirects) { + log('Redirects have changed, setting up listener again'); + setUpRedirectListener(); + } +}); -var ev = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest; -ev.addListener(checkForRedirect, filter, ["blocking"]); +//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(); -var storage = chrome.storage.local; //TODO: Change to sync when Firefox supports it... + return { + urls: ["http://*/*", "https://*/*"], + types : types + }; +} +function createPartitionedRedirects(redirects) { + var partitioned = {}; -//Icon updating code below + for (var i = 0; i < redirects.length; i++) { + var redirect = new Redirect(redirects[i]); + redirect.compile(); + for (var j=0; j<redirect.appliesTo.length;j++) { + var requestType = redirect.appliesTo[j]; + if (partitioned[requestType]) { + partitioned[requestType].push(redirect); + } else { + partitioned[requestType] = [redirect]; + } + } + } + return partitioned; +} + +//Sets up the listener, partitions the redirects, creates the appropriate filters etc. +function setUpRedirectListener() { + + redirectEvent.removeListener(checkRedirects); //Unsubscribe first, in case there are changes... + + storage.get('redirects', function(obj) { + if (!obj.redirects) { + log('No redirects to set up'); + return; + } + + partitionedRedirects = createPartitionedRedirects(obj.redirects); + var filter = createFilter(obj.redirects); + + log('Setting filter for listener: ' + JSON.stringify(filter)); + redirectEvent.addListener(checkRedirects, filter, ["blocking"]); + }); +} function updateIcon() { storage.get({disabled:false}, function(obj) { - chrome.browserAction.setIcon({ - path: { - 19: obj.disabled ? "images/icon19disabled.png" : "images/icon19active.png", - 38: obj.disabled ? "images/icon38disabled.png" : "images/icon38active.png" - } - }); + if (obj.disabled) { + setIcon("images/icon19disabled.png", "images/icon38disabled.png"); + } else { + setIcon("images/icon19active.png", "images/icon38active.png"); + } }); } +//First time setup updateIcon(); - -chrome.storage.onChanged.addListener(function(changes, namespace) { - if (changes.disabled) { - updateIcon(); +storage.get({disabled:false}, function(obj) { + if (!obj.disabled) { + setUpRedirectListener(); } });
\ No newline at end of file diff --git a/manifest.json b/manifest.json index 75579fa..834b928 100644 --- a/manifest.json +++ b/manifest.json @@ -17,7 +17,7 @@ }, "background": { - "scripts": ["js/background.js"], + "scripts": ["js/redirect.js", "js/background.js"], "persistent": true }, diff --git a/redirector.html b/redirector.html index 2af7493..c437288 100644 --- a/redirector.html +++ b/redirector.html @@ -99,7 +99,7 @@ </div> </div> <div class="button-container"> - <a ng-class="{disabled:redirect.error}" class="btn green large" ng-click="saveRedirect()">Save</a> + <a ng-class="{disabled:redirect.error || redirect.includePattern == ''}" class="btn green large" ng-click="saveRedirect()">Save</a> <a class="btn red large" ng-click="cancelEdit()">Cancel</a> </div> </div> |