mirror of
https://gitee.com/willfree/MINResolveV2.git
synced 2026-06-03 08:16:55 +08:00
646 lines
21 KiB
JavaScript
646 lines
21 KiB
JavaScript
/**
|
||
* The background script to handle url redirection.
|
||
*/
|
||
|
||
var storage = null;
|
||
var downloading = false;
|
||
var downloadTimer = null;
|
||
// 存储MIS的IP
|
||
var misHost="121.15.171.92";
|
||
// 请求映射表项时兴趣包使用的前缀
|
||
var misPrefix="/mis/resolve";
|
||
// 兴趣包前缀序号
|
||
var misPrefixNum=0;
|
||
// 兴趣包过期时间:默认两秒
|
||
var interestLifetimeMilliseconds=2000;
|
||
// 是否开启mis更新映射表
|
||
var misEnableState=true;
|
||
// 全局变量,用于设置是否刷新当前active的界面
|
||
// var myInterval=null;
|
||
|
||
// min协议的URI协议头
|
||
var minProtocolHeader="min/";
|
||
// 适配的其它浏览器默认协议:
|
||
// 插件将自动拦截该头部,以做协议转换
|
||
var httpProtocolHeader="http://";
|
||
var httpsProtocolHeader="https://";
|
||
// 适配的搜索引擎
|
||
var searchLibs=[
|
||
// 百度
|
||
"https://www.baidu.com",
|
||
"http://www.baidu.com",
|
||
// 谷歌
|
||
"https://www.google.com",
|
||
"http://www.google.com",
|
||
// 搜狗
|
||
"https://www.sogou.com",
|
||
"http://www.sogou.com",
|
||
// 360
|
||
"https://www.so.com",
|
||
"http://www.so.com",
|
||
// bing
|
||
"https://cn.bing.com",
|
||
"http://cn.bing.com",
|
||
// bing
|
||
"https://www.bing.com",
|
||
"http://www.bing.com"
|
||
];
|
||
|
||
// 获取兴趣包前缀
|
||
function getInterestPrefix() {
|
||
misPrefixNum++;
|
||
browser.storage.local.set({'misPrefixNum':misPrefixNum});
|
||
return misPrefix+'/'+misPrefixNum;
|
||
}
|
||
|
||
// 加载mis的IP
|
||
function loadMisHost() {
|
||
browser.storage.local.get('misHostIP',function (result) {
|
||
if($.isEmptyObject(result)){
|
||
// alert("hostIP: null");
|
||
browser.storage.local.set({'misHostIP':misHost});
|
||
}else{
|
||
// alert("hostIP: "+result.misHostIP);
|
||
misHost=result.misHostIP;
|
||
}
|
||
});
|
||
browser.storage.local.get('misPrefix',function (result) {
|
||
if($.isEmptyObject(result)){
|
||
// alert("misPrefix: null");
|
||
browser.storage.local.set({'misPrefix':misPrefix});
|
||
}else{
|
||
// alert("misPrefix: "+result.misPrefix);
|
||
misPrefix=result.misPrefix;
|
||
}
|
||
});
|
||
browser.storage.local.get('misPrefixNum',function (result) {
|
||
if($.isEmptyObject(result)){
|
||
// alert("misPrefix: null");
|
||
browser.storage.local.set({'misPrefixNum':misPrefixNum});
|
||
}else{
|
||
// alert("misPrefix: "+result.misPrefix);
|
||
misPrefixNum=result.misPrefixNum;
|
||
}
|
||
});
|
||
browser.storage.local.get('misEnableState',function (result) {
|
||
if($.isEmptyObject(result)){
|
||
// alert("misPrefix: null");
|
||
browser.storage.local.set({'misEnableState':misEnableState});
|
||
}else{
|
||
// alert("misPrefix: "+result.misPrefix);
|
||
misEnableState=result.misEnableState;
|
||
// alert("48641");
|
||
}
|
||
});
|
||
}
|
||
|
||
/* Reload callback */
|
||
function reload(result) {
|
||
storage = new Storage();
|
||
if (result && result.storage) {
|
||
storage.fromObject(result.storage);
|
||
// resetDownloadTimer();
|
||
}
|
||
}
|
||
|
||
/* Auto reload */
|
||
browser.storage.onChanged.addListener(function (changes, area) {
|
||
load("storage", reload);
|
||
loadMisHost();
|
||
});
|
||
|
||
|
||
/* The first time of loading storage */
|
||
load("storage", reload);
|
||
loadMisHost();
|
||
// alert("成功加载mis的IP: "+misHost+"; misPrefix: "+misPrefix);
|
||
|
||
function getJsonString(u_identifier){
|
||
var jsonObj={
|
||
"Type":"user-act",
|
||
"Command":"Resolve",
|
||
"QueryCode":2,
|
||
"U_identifier":u_identifier
|
||
};
|
||
// return jsonObj;
|
||
return JSON.stringify(jsonObj);
|
||
}
|
||
|
||
|
||
function onTimeout(interest)
|
||
{
|
||
console.log("time out...");
|
||
}
|
||
|
||
// 增加映射表项时,判断该表项是否重复
|
||
function addCustomRule(editingRule) {
|
||
var flag=0;
|
||
for (var i=0; i<storage.customRules.length; i++) {
|
||
var rule = storage.customRules[i];
|
||
if ((rule.origin === editingRule.origin) && (rule.target === editingRule.target)) {
|
||
flag=1;
|
||
}
|
||
}
|
||
if(flag===0){
|
||
storage.customRules.push(editingRule);
|
||
}
|
||
}
|
||
|
||
// 刷新正在浏览的浏览器界面
|
||
function refreshActiveTab () {
|
||
chrome.tabs.query({active: true}, function(tabs) {
|
||
var tabIndex = tabs[0].index;
|
||
chrome.tabs.query({}, function(tabs) {
|
||
chrome.tabs.reload(tabs[tabIndex].id);
|
||
// var o;
|
||
// o.url="https://www.csdn.net/";
|
||
// chrome.tabs.create(o,function () {
|
||
// console.log("test");
|
||
// });
|
||
})
|
||
});
|
||
console.log("refresh########");
|
||
}
|
||
|
||
function express(prefixUri) {
|
||
// alert("成功加载mis的IP: "+misHost+"; misPrefix: "+misPrefix);
|
||
// Connect to the forwarder with a WebSocket.
|
||
var face = new Face({host: misHost});
|
||
|
||
var name = new Name(getInterestPrefix());
|
||
var jsonPrefix=getJsonString(prefixUri);
|
||
|
||
var interest=new Interest(name);
|
||
interest.setMustBeFresh(true);
|
||
interest.setApplicationParameters(new Blob(jsonPrefix));
|
||
interest.setInterestLifetimeMilliseconds(interestLifetimeMilliseconds);
|
||
// alert("express Interest: "+jsonPrefix+" ; "+interest.name.toString());
|
||
|
||
face.expressInterest(interest, function(interest,data){
|
||
var targetJsonString=data.getContent().buf().toString('binary');
|
||
// alert("targetJsonString: "+targetJsonString);
|
||
var targetJson=JSON.parse(targetJsonString);
|
||
// 将targetJson解析成targetUri
|
||
var StatusCode=targetJson.StatusCode;
|
||
var targetUri=targetJson.Message;
|
||
if((StatusCode===200)&&(targetUri!=="")) {
|
||
var editingRule = new Rule();
|
||
editingRule.enable = true;
|
||
editingRule.description = "initial based on MIS";
|
||
editingRule.origin = prefixUri;
|
||
editingRule.target = targetUri;
|
||
editingRule.exclude = "";
|
||
editingRule.example = "";
|
||
editingRule.process = "";
|
||
editingRule.methods = [];
|
||
editingRule.types = [];
|
||
// storage.customRules.push(editingRule);
|
||
addCustomRule(editingRule);
|
||
/* save */
|
||
save({"storage": storage});
|
||
load("storage", reload);
|
||
// setTimeout(refreshActiveTab(),2000);
|
||
}else{
|
||
// mis没有该前缀对应的映射
|
||
}
|
||
}, onTimeout);
|
||
}
|
||
|
||
// /* Download online rules */
|
||
// function downloadOnlineURLs() {
|
||
// /* Still downloading */
|
||
// if (!storage.onlineURLs || storage.onlineURLs.length <=0 || downloading) {
|
||
// return;
|
||
// }
|
||
// downloading = true;
|
||
// var toDownload = []; // URLs that need to be downloaded
|
||
// for (var i = 0; i < storage.onlineURLs.length; i++) {
|
||
// var onlineURL = storage.onlineURLs[i];
|
||
// if (onlineURL.auto && onlineURL.enable && onlineURL.url !== "") {
|
||
// toDownload.push(onlineURL.url);
|
||
// }
|
||
// }
|
||
// if (toDownload.length === 0) {
|
||
// sendMessage("downloaded");
|
||
// }
|
||
// var downloadErrors = [];
|
||
// var parseErrors = [];
|
||
// for (var i = 0; i<toDownload.length; i++) {
|
||
// download(toDownload[i], function (url, content) {
|
||
// toDownload.remove(url);
|
||
// if (content) {
|
||
// try {
|
||
// var json;
|
||
// // content may be a string or json object
|
||
// if (typeof content === "string") {
|
||
// json = JSON.parse(content);
|
||
// } else {
|
||
// json = content;
|
||
// }
|
||
// json.url = url;
|
||
// json.enable = true;
|
||
// json.downloadAt = new Date();
|
||
// /* To compact with gooreplacer */
|
||
// /* version < 1.0, version >= 1.0 doesn't change */
|
||
// if (!json.version || json.version < "1.0") {
|
||
// var rules = [];
|
||
// for (var key in json.rules) {
|
||
// var rule = json.rules[key];
|
||
// rules.push({
|
||
// origin: key,
|
||
// target: rule.dstURL,
|
||
// enable: rule.enable === undefined ? true : rule.enable,
|
||
// kind: rule.kind
|
||
// });
|
||
// }
|
||
// json.rules = rules;
|
||
// }
|
||
// /* replace the onlineURL */
|
||
// for (var j = 0; j < storage.onlineURLs.length; j++){
|
||
// if (storage.onlineURLs[j].url == url){
|
||
// storage.onlineURLs[j] = new OnlineURL();
|
||
// storage.onlineURLs[j].fromObject(json);
|
||
// break;
|
||
// }
|
||
// }
|
||
// } catch (err) {
|
||
// parseErrors.push(url);
|
||
// console.error(err);
|
||
// }
|
||
// }
|
||
// else {
|
||
// downloadErrors.push(url);
|
||
// }
|
||
// if (toDownload.length <= 0) {
|
||
// downloading = false;
|
||
// sendMessage("downloaded");
|
||
// if (downloadErrors.length > 0) {
|
||
// sendMessage("downloadError", downloadErrors);
|
||
// }
|
||
// if (parseErrors.length > 0) {
|
||
// sendMessage("parseError", parseErrors);
|
||
// }
|
||
// storage.updatedAt = (new Date()).toISOString();
|
||
// save({"storage": storage});
|
||
// }
|
||
// });
|
||
// }
|
||
// }
|
||
//
|
||
// /* Reset download timer to download online urls */
|
||
// /* Setup a listener if alarm api supported */
|
||
// if (browser.alarms) {
|
||
// browser.alarms.onAlarm.addListener(function (alarm) {
|
||
// if (alarm.name == "download") {
|
||
// downloadOnlineURLs();
|
||
// }
|
||
// })
|
||
// }
|
||
//
|
||
// /* Reset the download timer */
|
||
// function resetDownloadTimer() {
|
||
// var interval = 900; // Default 15min
|
||
// if (storage.updateInterval) {
|
||
// interval = parseInt(storage.updateInterval);
|
||
// }
|
||
// /* If the browser support alarms api */
|
||
// if (browser.alarms) {
|
||
// browser.alarms.create("download", {
|
||
// periodInMinutes: Math.ceil(interval / 60)
|
||
// });
|
||
// }
|
||
// else {
|
||
// /* With setInterval */
|
||
// if (downloadTimer != null) {
|
||
// clearInterval(downloadTimer);
|
||
// }
|
||
// interval = interval * 1000; // In milli-seconds
|
||
// downloadTimer = setInterval(function () {
|
||
// if (storage.enable) {
|
||
// downloadOnlineURLs();
|
||
// }
|
||
// }, interval);
|
||
// }
|
||
// }
|
||
|
||
/* Handle runtime messages */
|
||
// browser.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||
// if (message.method == "download" && !downloading) {
|
||
// // downloadOnlineURLs();
|
||
// }
|
||
// else if (message.method == "isDownloading") {
|
||
// // sendResponse(downloading);
|
||
// }
|
||
// else {
|
||
// // console.error("Unknown method");
|
||
// }
|
||
// });
|
||
|
||
function redirect(details) {
|
||
if (storage.enable && details.url) {
|
||
var newURL = storage.redirect(details.url, details.method, details.type);
|
||
if (newURL){
|
||
return {
|
||
redirectUrl: newURL
|
||
}
|
||
}
|
||
}
|
||
return {};
|
||
}
|
||
|
||
// var _redirect_promise_supported = false;
|
||
|
||
// 对小于0的数取0
|
||
function getPositiveNum(num) {
|
||
if(num>0){
|
||
return num;
|
||
}else{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// 判断某个字符串是否是一个搜索url:搜索某个内容的URI
|
||
function isSearchUrl(urlString){
|
||
var flag=0;
|
||
for(var i=0;i<searchLibs.length;i++){
|
||
if(urlString.indexOf(searchLibs[i])>=0){
|
||
flag=1;
|
||
break;
|
||
}
|
||
}
|
||
var haveSearchString=getPositiveNum(urlString.indexOf("?wd="))
|
||
+getPositiveNum(urlString.indexOf("&wd="))
|
||
+getPositiveNum(urlString.indexOf("?q="))
|
||
+getPositiveNum(urlString.indexOf("&q="))
|
||
+getPositiveNum(urlString.indexOf("?query="))
|
||
+getPositiveNum(urlString.indexOf("&query="));
|
||
if((flag>0)&&(haveSearchString>0)){
|
||
// alert("it is a searchUrl: "+urlString);
|
||
return true;
|
||
}else{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 传入一个搜索uri,获取其中的搜索数值;
|
||
// 传入一个非搜索uri,返回空字符串
|
||
function getSearchContent(uriString) {
|
||
if(!isSearchUrl(uriString)){
|
||
return "";
|
||
}
|
||
var content="";
|
||
if(uriString.indexOf("//www.baidu.com")>=0){
|
||
// &wd= [end] 或 &wd= &
|
||
var startIndex=getPositiveNum(uriString.indexOf("?wd="))
|
||
+getPositiveNum(uriString.indexOf("&wd="))+4;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else if(uriString.indexOf("//www.google.com")>=0){
|
||
// ?q= &
|
||
var startIndex=getPositiveNum(uriString.indexOf("?q="))
|
||
+getPositiveNum(uriString.indexOf("&q="))+3;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else if(uriString.indexOf("//www.sogou.com")>=0){
|
||
// &query= [end]
|
||
var startIndex=getPositiveNum(uriString.indexOf("?query="))
|
||
+getPositiveNum(uriString.indexOf("&query="))+7;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else if(uriString.indexOf("//www.so.com")>=0){
|
||
// &q= [end]
|
||
var startIndex=getPositiveNum(uriString.indexOf("?q="))
|
||
+getPositiveNum(uriString.indexOf("&q="))+3;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else if(uriString.indexOf("//cn.bing.com")>=0){
|
||
// ?q= &
|
||
var startIndex=getPositiveNum(uriString.indexOf("?q="))
|
||
+getPositiveNum(uriString.indexOf("&q="))+3;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else if(uriString.indexOf("//www.bing.com")>=0){
|
||
// ?q= &
|
||
var startIndex=getPositiveNum(uriString.indexOf("?q="))
|
||
+getPositiveNum(uriString.indexOf("&q="))+3;
|
||
var lastString=uriString.substring(startIndex);
|
||
var endIndex=lastString.indexOf('&');
|
||
if(endIndex>=0){
|
||
content=lastString.substring(0,endIndex);
|
||
}else{
|
||
content=lastString;
|
||
}
|
||
}else{}
|
||
return decodeURIComponent(content);
|
||
}
|
||
|
||
// 模糊判断一个string是否是一个合法前缀/合法标识
|
||
function isRightfulPrefix(string){
|
||
// 不能为空
|
||
if(string===''){
|
||
return false;
|
||
}
|
||
// 不能包含.
|
||
if(string.indexOf('.')>=0){
|
||
return false;
|
||
}
|
||
// 第一个字符必须是/
|
||
var stringDecoded=decodeURIComponent(string);
|
||
if(stringDecoded.indexOf('/')!==0){
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 判断一个url是否是一个min协议的合法URI
|
||
function isRightfulMinURI(urlString){
|
||
var urlStringDecoded=decodeURIComponent(urlString);
|
||
// 长度要大于min协议头的长度
|
||
if(urlStringDecoded.length<=minProtocolHeader.length){
|
||
return false;
|
||
}
|
||
// 前几个字符必须是min协议头
|
||
if(urlStringDecoded.indexOf(minProtocolHeader)!==0){
|
||
return false;
|
||
}
|
||
// 协议头后面跟的是一个合法前缀/合法标识
|
||
var prefix=urlStringDecoded.substring(minProtocolHeader.length);
|
||
if(!isRightfulPrefix(prefix)){
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 从一个合法minUri提取出前缀
|
||
function getPrefixFromMinURI(minURI){
|
||
if(isRightfulMinURI(minURI)){
|
||
var urlStringDecoded=decodeURIComponent(minURI);
|
||
return urlStringDecoded.substring(minProtocolHeader.length);
|
||
}else{
|
||
return "";
|
||
}
|
||
}
|
||
|
||
// 判断某个没使用url编码的string是否是映射表的一个表项
|
||
function isCustomRulesItemString(string) {
|
||
// 遍历本地映射表
|
||
var flag=0;
|
||
for (var i=0; i<storage.customRules.length; i++) {
|
||
var rule = storage.customRules[i];
|
||
if (string===rule.origin) {
|
||
flag=1;
|
||
break;
|
||
}
|
||
}
|
||
if(flag===0){
|
||
// alert("it is not rules: "+string);
|
||
return false;
|
||
}else{
|
||
// alert("it is rules: "+string);
|
||
// console.log("it includes rules");
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 判断某个minUrl中的前缀是否是映射表的一个表项
|
||
function isCustomRulesItemMinURI(minURI) {
|
||
// 如果不是min协议URI,返回false
|
||
var prefix=getPrefixFromMinURI(minURI);
|
||
if(prefix===""){
|
||
return false;
|
||
}
|
||
// alert("是minuri");
|
||
return isCustomRulesItemString(prefix);
|
||
}
|
||
|
||
// 根据传入的前缀/标识,更新本地映射表
|
||
function updateStorageBasedPrefix(prefix) {
|
||
if(isRightfulPrefix(prefix)){
|
||
express(prefix);
|
||
}
|
||
}
|
||
|
||
// 根据传入的MINuri获取前缀,从而更新本地映射表
|
||
function updateStorageBasedMinURI(minURI) {
|
||
// alert("begin upgrate");
|
||
var prefix=getPrefixFromMinURI(minURI);
|
||
if(!(prefix==="")){
|
||
express(prefix);
|
||
}
|
||
}
|
||
|
||
function sleep(numberMillis) {
|
||
// alert("开始卡死cpu");
|
||
var now = new Date();
|
||
var exitTime = now.getTime() + numberMillis;
|
||
while (true) {
|
||
now = new Date();
|
||
if (now.getTime() > exitTime)
|
||
// alert("释放cpu");
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 将一个http或https请求的协议头去掉
|
||
function getCutHttpHeader(urlString){
|
||
var urlString=decodeURIComponent(urlString);
|
||
if(urlString.indexOf(httpProtocolHeader)===0){
|
||
return urlString.substring(httpProtocolHeader.length);
|
||
}else if(urlString.indexOf(httpsProtocolHeader)===0){
|
||
return urlString.substring(httpsProtocolHeader.length);
|
||
}else{
|
||
return "";
|
||
}
|
||
}
|
||
|
||
/* Handle redirect */
|
||
function handleRedirect(details) {
|
||
// alert(details.url);
|
||
// 判断url是否是一个搜索url,并根据搜索内容,判断是否直接命中本地映射表
|
||
var searchContent=getSearchContent(details.url); // 已解码
|
||
var minUri=getCutHttpHeader(details.url); //已解码
|
||
// alert("?s: "+searchContent+" ; ?u: "+minUri);
|
||
// 如果该搜索内容或网址命中了缓存中的映射表前缀,则重定向
|
||
if(isCustomRulesItemMinURI(searchContent)||isCustomRulesItemMinURI(minUri)){
|
||
// alert("s: "+searchContent+" ; u: "+minUri);
|
||
var prefixTemp="";
|
||
if(searchContent!==""){
|
||
prefixTemp=getPrefixFromMinURI(searchContent);
|
||
}else{
|
||
prefixTemp=getPrefixFromMinURI(minUri);
|
||
}
|
||
details.url = httpProtocolHeader+prefixTemp; //如果映射表中加了http协议头,这里就不要加了
|
||
return redirect(details);
|
||
}
|
||
// 如果没有命中缓存映射表,但是它是一个检索内容的网络请求
|
||
if(searchContent!==""){
|
||
// alert("检索内容了呢:"+searchContent);
|
||
if ((misEnableState === true)&&isRightfulMinURI(searchContent)) {
|
||
details.url = httpProtocolHeader + searchContent;
|
||
// 如果检索内容模糊判断是一个前缀,且mis同步是开着的
|
||
// alert("成功加载mis的IP: "+misHost+"; misPrefix: "+misPrefix+", searchContent: "+searchContent);
|
||
updateStorageBasedMinURI(searchContent);
|
||
// alert("重定向url:"+details.url);
|
||
return {
|
||
redirectUrl: details.url
|
||
};
|
||
}else{
|
||
// 如果是搜索了一个内容,该内容没命中缓存,
|
||
// 且mis没开,或该内容不符合前缀标识符表示规则,
|
||
// 则该内容一定是不会命中一个映射表项的
|
||
return {};
|
||
}
|
||
}else{
|
||
// 如果本地没有命中映射表,且没有检索内容,是一个正常的网页
|
||
if((misEnableState===true)&&isRightfulMinURI(minUri)){
|
||
updateStorageBasedMinURI(minUri);
|
||
}
|
||
return redirect(details);
|
||
}
|
||
}
|
||
|
||
/* Since firefox 52, could return a promise to handles asynchronously */
|
||
// if (browser.runtime.getBrowserInfo) {
|
||
// function checkRedirectPromise(info) {
|
||
// if (info.name == "Firefox") {
|
||
// if (parseInt(info.version.split('.')[0]) >= 52) {
|
||
// _redirect_promise_supported = true;
|
||
// }
|
||
// }
|
||
// }
|
||
// var gettingInfo = browser.runtime.getBrowserInfo();
|
||
// gettingInfo.then(checkRedirectPromise)
|
||
// }
|
||
|
||
/* Add listener */
|
||
browser.webRequest.onBeforeRequest.addListener(
|
||
handleRedirect,
|
||
{urls: ["<all_urls>"]},
|
||
["blocking"]
|
||
);
|