1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-09-15 07:22:28 +02:00

this fixes 202

This commit is contained in:
gorhill 2014-09-14 16:20:40 -04:00
parent 1b033d38d7
commit ee81436ff5
19 changed files with 604 additions and 316 deletions

View File

@ -207,22 +207,14 @@
"message":"Änderungen anwenden", "message":"Änderungen anwenden",
"description":"English: Apply changes" "description":"English: Apply changes"
}, },
"logBlockedRequestsPrompt":{ "logNetRequestsPrompt":{
"message":"Protokollieren von blockierten Elementen aktivieren", "message":"Protokollieren von blockierten Elementen aktivieren",
"description":"English: Enable the logging of blocked requests" "description":"English: Enable the logging of network requests"
}, },
"logBlockedRequestsHelp":{ "logNetRequestsHelp":{
"message":"Du kannst dir die Details von blockierten Anfragen anschauen, wenn du diese Option aktivierst. Das Protokollieren von blockierten Anfragen erhöht den Speicherbedarf von <i>µBlock<\/i>. Da dieses Feature von vielen Benutzern wohl nicht genutzt werden wird, ist es standardmäßig deaktiviert.", "message":"Du kannst dir die Details von blockierten Anfragen anschauen, wenn du diese Option aktivierst. Das Protokollieren von blockierten Anfragen erhöht den Speicherbedarf von <i>µBlock<\/i>. Da dieses Feature von vielen Benutzern wohl nicht genutzt werden wird, ist es standardmäßig deaktiviert.",
"description":"English: see _locales\/en\/messages.log" "description":"English: see _locales\/en\/messages.log"
}, },
"logAllowedRequestsPrompt":{
"message":"Protokollieren von nicht-blockierten Elementen aktivieren",
"description":"English: Enable the logging of non-blocked requests"
},
"logAllowedRequestsHelp":{
"message":"Du kannst dir die Details von nicht-blockierten Anfragen anschauen, wenn du diese Option aktivierst. Das Protokollieren von nicht-blockierten Anfragen erhöht den Speicherbedarf von µBlock. Da dieses Feature von vielen Benutzern wohl nicht genutzt werden wird, ist es standardmäßig deaktiviert.",
"description":"English: see _locales\/en\/messages.log"
},
"logBlockedRequestsHeader":{ "logBlockedRequestsHeader":{
"message":"Blockierte Anfragen", "message":"Blockierte Anfragen",
"description":"English: Blocked requests" "description":"English: Blocked requests"

View File

@ -207,20 +207,12 @@
"message":"Apply changes", "message":"Apply changes",
"description":"English: Apply changes" "description":"English: Apply changes"
}, },
"logBlockedRequestsPrompt":{ "logNetRequestsPrompt":{
"message":"Enable the logging of blocked requests", "message":"Enable the logging of network requests",
"description":"English: Enable the logging of blocked requests" "description":"English: Enable the logging of network requests"
}, },
"logBlockedRequestsHelp":{ "logNetRequestsHelp":{
"message":"You can inspect the details of blocked requests if you wish by enabling this option. The logging of blocked requests increases the memory footprint of µBlock. Since many users will never use this feature, it is disabled by default.", "message":"You can inspect the details of network requests if you wish by enabling this option. The logging of network requests increases the memory footprint of µBlock. Since many users will never use this feature, it is disabled by default.",
"description":"English: see _locales\/en\/messages.log"
},
"logAllowedRequestsPrompt":{
"message":"Enable the logging of non-blocked requests",
"description":"English: Enable the logging of non-blocked requests"
},
"logAllowedRequestsHelp":{
"message":"You can inspect the details of non-blocked requests if you wish by enabling this option. The logging of non-blocked requests increases the memory footprint of µBlock. Since many users will never use this feature, it is disabled by default.",
"description":"English: see _locales\/en\/messages.log" "description":"English: see _locales\/en\/messages.log"
}, },
"logBlockedRequestsHeader":{ "logBlockedRequestsHeader":{

View File

@ -207,20 +207,12 @@
"message":"Appliquer", "message":"Appliquer",
"description":"English: Apply changes" "description":"English: Apply changes"
}, },
"logBlockedRequestsPrompt":{ "logNetRequestsPrompt":{
"message":"Activer la journalisation des requêtes bloquées", "message":"Activer la journalisation des requêtes",
"description":"English: Enable the logging of blocked requests" "description":"English: Enable the logging of network requests"
}, },
"logBlockedRequestsHelp":{ "logNetRequestsHelp":{
"message":"Vous pouvez inspecter les détails des requêtes bloquées en activant cette option. La journalisation des requêtes bloquées augmente l'empreinte mémoire utilisée par µBlock. Puisque que bon nombre d'utilisateurs n'utiliseront jamais cette fonctionnalité, elle est désactivée par défaut.", "message":"Vous pouvez inspecter les détails des requêtes en activant cette option. La journalisation des requêtes augmente l'empreinte mémoire utilisée par µBlock. Puisque que bon nombre d'utilisateurs n'utiliseront jamais cette fonctionnalité, elle est désactivée par défaut.",
"description":"English: see _locales\/en\/messages.log"
},
"logAllowedRequestsPrompt":{
"message":"Activer la journalisation des requêtes autorisées",
"description":"English: Enable the logging of non-blocked requests"
},
"logAllowedRequestsHelp":{
"message":"Vous pouvez inspecter les détails des requêtes autorisées en activant cette option. La journalisation des requêtes autorisées augmente l'empreinte mémoire utilisée par µBlock. Puisque que bon nombre d'utilisateurs n'utiliseront jamais cette fonctionnalité, elle est désactivée par défaut.",
"description":"English: see _locales\/en\/messages.log" "description":"English: see _locales\/en\/messages.log"
}, },
"logBlockedRequestsHeader":{ "logBlockedRequestsHeader":{

View File

@ -14,8 +14,8 @@
<script src="js/liquid-dict.js"></script> <script src="js/liquid-dict.js"></script>
<script src="js/utils.js"></script> <script src="js/utils.js"></script>
<script src="js/assets.js"></script> <script src="js/assets.js"></script>
<script src="js/net-filters.js"></script> <script src="js/net-filtering.js"></script>
<script src="js/cosmetic-filters.js"></script> <script src="js/cosmetic-filtering.js"></script>
<script src="js/ublock.js"></script> <script src="js/ublock.js"></script>
<script src="js/messaging.js"></script> <script src="js/messaging.js"></script>
<script src="js/profiler.js"></script> <script src="js/profiler.js"></script>

View File

@ -27,6 +27,8 @@
µBlock.asyncJobs = (function() { µBlock.asyncJobs = (function() {
/******************************************************************************/
var processJobs = function() { var processJobs = function() {
asyncJobManager.process(); asyncJobManager.process();
}; };
@ -45,6 +47,8 @@ AsyncJobEntry.prototype.destroy = function() {
this.callback = null; this.callback = null;
}; };
/******************************************************************************/
var AsyncJobManager = function() { var AsyncJobManager = function() {
this.timeResolution = 200; this.timeResolution = 200;
this.jobs = {}; this.jobs = {};
@ -54,7 +58,15 @@ var AsyncJobManager = function() {
this.timerWhen = Number.MAX_VALUE; this.timerWhen = Number.MAX_VALUE;
}; };
/******************************************************************************/
AsyncJobManager.prototype.restartTimer = function() { AsyncJobManager.prototype.restartTimer = function() {
// TODO: Another way to do this is to extract the keys, sort the keys
// in chronological order, than pick the first entry to get the next
// time at which we want a time event to fire. Completely unsure the
// overhead of extracting keys/sorting is less than what is below.
// I could also keep the keys ordered, and use binary search when adding
// a new job.
var when = Number.MAX_VALUE; var when = Number.MAX_VALUE;
var jobs = this.jobs, job; var jobs = this.jobs, job;
for ( var jobName in jobs ) { for ( var jobName in jobs ) {
@ -68,6 +80,10 @@ AsyncJobManager.prototype.restartTimer = function() {
// Quantize time value // Quantize time value
when = Math.floor((when + this.timeResolution - 1) / this.timeResolution) * this.timeResolution; when = Math.floor((when + this.timeResolution - 1) / this.timeResolution) * this.timeResolution;
// TODO: Maybe use chrome.alarms() API when the next job is at more than
// one minute in the future... From reading about it, chrome.alarms() is
// smarter in that it will fire the event only when the browser is not
// too busy. (through XAL to abstract API specificities)
if ( when < this.timerWhen ) { if ( when < this.timerWhen ) {
clearTimeout(this.timerId); clearTimeout(this.timerId);
this.timerWhen = when; this.timerWhen = when;
@ -75,6 +91,8 @@ AsyncJobManager.prototype.restartTimer = function() {
} }
}; };
/******************************************************************************/
AsyncJobManager.prototype.add = function(name, data, callback, delay, recurrent) { AsyncJobManager.prototype.add = function(name, data, callback, delay, recurrent) {
var job = this.jobs[name]; var job = this.jobs[name];
if ( !job ) { if ( !job ) {
@ -94,6 +112,22 @@ AsyncJobManager.prototype.add = function(name, data, callback, delay, recurrent)
this.restartTimer(); this.restartTimer();
}; };
/******************************************************************************/
AsyncJobManager.prototype.remove = function(jobName) {
if ( this.jobs.hasOwnProperty(jobName) === false ) {
return;
}
var job = this.jobs[jobName];
delete this.jobs[jobName];
job.destroy();
this.jobCount--;
this.jobJunkyard.push(job);
this.restartTimer();
};
/******************************************************************************/
AsyncJobManager.prototype.process = function() { AsyncJobManager.prototype.process = function() {
this.timerId = null; this.timerId = null;
this.timerWhen = Number.MAX_VALUE; this.timerWhen = Number.MAX_VALUE;
@ -120,9 +154,13 @@ AsyncJobManager.prototype.process = function() {
this.restartTimer(); this.restartTimer();
}; };
/******************************************************************************/
// Only one instance // Only one instance
var asyncJobManager = new AsyncJobManager(); var asyncJobManager = new AsyncJobManager();
/******************************************************************************/
// Publish // Publish
return asyncJobManager; return asyncJobManager;
@ -133,12 +171,12 @@ return asyncJobManager;
// Update visual of extension icon. // Update visual of extension icon.
// A time out is used to coalesce adjacent requests to update badge. // A time out is used to coalesce adjacent requests to update badge.
µBlock.updateBadgeAsync = function(tabId) { µBlock.updateBadgeAsync = (function(){
if ( tabId < 0 ) { var µb = µBlock;
return;
} // Cache callback definition, it was a bad idea to define this one inside
var µb = this; // updateBadgeAsync
var updateBadge = function() { var updateBadge = function(tabId) {
var pageStore = µb.pageStoreFromTabId(tabId); var pageStore = µb.pageStoreFromTabId(tabId);
if ( pageStore ) { if ( pageStore ) {
pageStore.updateBadge(); pageStore.updateBadge();
@ -150,5 +188,13 @@ return asyncJobManager;
'' ''
); );
}; };
this.asyncJobs.add('updateBadge-' + tabId, tabId, updateBadge, 250);
}; var updateBadgeAsync = function(tabId) {
if ( tabId < 0 ) {
return;
}
µb.asyncJobs.add('updateBadge-' + tabId, tabId, updateBadge, 250);
};
return updateBadgeAsync;
})();

View File

@ -41,8 +41,7 @@ return {
autoUpdate: true, autoUpdate: true,
collapseBlocked: true, collapseBlocked: true,
externalLists: '', externalLists: '',
logBlockedRequests: false, logRequests: false,
logAllowedRequests: false,
parseAllABPHideFilters: true, parseAllABPHideFilters: true,
showIconBadge: true showIconBadge: true
}, },

View File

@ -56,16 +56,7 @@ var uBlockMessaging = (function(name){
}; };
var start = function(name) { var start = function(name) {
port = chrome.runtime.connect({ port = chrome.runtime.connect({ name: name });
name: name +
'/' +
String.fromCharCode(
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0
)
});
port.onMessage.addListener(onPortMessage); port.onMessage.addListener(onPortMessage);
// https://github.com/gorhill/uBlock/issues/193 // https://github.com/gorhill/uBlock/issues/193
@ -111,7 +102,7 @@ var uBlockMessaging = (function(name){
var flushCallbacks = function() { var flushCallbacks = function() {
var callback; var callback;
for ( id in requestIdToCallbackMap ) { for ( var id in requestIdToCallbackMap ) {
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) { if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
continue; continue;
} }
@ -527,63 +518,11 @@ var uBlockMessaging = (function(name){
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// https://github.com/gorhill/uBlock/issues/7 // Permanent
(function() { (function() {
var messaging = uBlockMessaging; var messaging = uBlockMessaging;
var blockableElements = {
'embed': 'src',
'iframe': 'src',
'img': 'src',
'object': 'data'
};
// First pass
messaging.ask({ what: 'blockedRequests' }, function(details) {
var elems = document.querySelectorAll('embed,iframe,img,object');
var blockedRequests = details.blockedRequests;
var collapse = details.collapse;
var i = elems.length;
var elem, tagName, prop, src;
var selectors = [];
while ( i-- ) {
elem = elems[i];
tagName = elem.tagName.toLowerCase();
prop = blockableElements[tagName];
if ( prop === undefined ) {
continue;
}
src = elem[prop];
if ( typeof src !== 'string' || src === '' ) {
continue;
}
if ( blockedRequests[src] === undefined ) {
continue;
}
// If `!important` is not there, going back using history will
// likely cause the hidden element to re-appear.
if ( collapse ) {
if ( elem.parentNode ) {
elem.parentNode.removeChild(elem);
} else {
elem.style.setProperty('display', 'none', 'important');
}
} else {
elem.style.setProperty('visibility', 'hidden', 'important');
}
selectors.push(tagName + '[' + prop + '="' + src + '"]');
}
if ( selectors.length !== 0 ) {
messaging.tell({
what: 'injectedSelectors',
type: 'net',
hostname: window.location.hostname,
selectors: selectors
});
}
});
// Listeners to mop up whatever is otherwise missed: // Listeners to mop up whatever is otherwise missed:
// - Future requests not blocked yet // - Future requests not blocked yet
// - Elements dynamically added to the page // - Elements dynamically added to the page
@ -612,11 +551,15 @@ var uBlockMessaging = (function(name){
if ( typeof src !== 'string' || src === '' ) { if ( typeof src !== 'string' || src === '' ) {
return; return;
} }
if ( src.slice(0, 4) !== 'http' ) {
return;
}
// https://github.com/gorhill/uBlock/issues/174 // https://github.com/gorhill/uBlock/issues/174
// Do not remove fragment from src URL // Do not remove fragment from src URL
var onAnswerReceived = function(details) { var onAnswerReceived = function(details) {
if ( !details.blocked ) { if ( typeof details !== 'object' || details === null ) {
return; return;
} }
// If `!important` is not there, going back using history will // If `!important` is not there, going back using history will
@ -637,7 +580,15 @@ var uBlockMessaging = (function(name){
selectors: tagName + '[' + prop + '="' + src + '"]' selectors: tagName + '[' + prop + '="' + src + '"]'
}); });
}; };
messaging.ask({ what: 'blockedRequest', url: src }, onAnswerReceived);
var details = {
what: 'filterRequest',
tagName: tagName,
requestURL: src,
pageHostname: window.location.hostname,
pageURL: window.location.href
};
messaging.ask(details, onAnswerReceived);
}; };
var onResourceLoaded = function(ev) { var onResourceLoaded = function(ev) {
@ -655,3 +606,95 @@ var uBlockMessaging = (function(name){
})(); })();
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/7
// Executed only once
(function() {
var messaging = uBlockMessaging;
var readyProps = {
'img': 'complete'
};
var srcProps = {
'embed': 'src',
'iframe': 'src',
'img': 'src',
'object': 'data'
};
var elements = [];
var onAnswerReceived = function(details) {
if ( typeof details !== 'object' || details === null ) {
return;
}
var requests = details.requests;
var collapse = details.collapse;
var selectors = [];
var i = requests.length;
var request, elem;
while ( i-- ) {
request = requests[i];
elem = elements[request.index];
if ( collapse ) {
if ( elem.parentNode ) {
elem.parentNode.removeChild(elem);
} else {
elem.style.setProperty('display', 'none', 'important');
}
} else {
elem.style.setProperty('visibility', 'hidden', 'important');
}
selectors.push(request.tagName + '[' + srcProps[request.tagName] + '="' + request.url + '"]');
}
if ( selectors.length !== 0 ) {
messaging.tell({
what: 'injectedSelectors',
type: 'net',
hostname: window.location.hostname,
selectors: selectors
});
}
};
var requests = [];
var tagNames = ['embed','iframe','img','object'];
var elementIndex = 0;
var tagName, elems, i, elem, prop, src;
while ( tagName = tagNames.pop() ) {
elems = document.getElementsByTagName(tagName);
i = elems.length;
while ( i-- ) {
elem = elems[i];
prop = srcProps[tagName];
if ( prop === undefined ) {
continue;
}
src = elem[prop];
if ( typeof src !== 'string' || src === '' ) {
continue;
}
if ( src.slice(0, 4) !== 'http' ) {
continue;
}
requests.push({
index: elementIndex,
tagName: tagName,
url: src
});
elements[elementIndex] = elem;
elementIndex += 1;
}
}
var details = {
what: 'filterRequests',
pageURL: window.location.href,
pageHostname: window.location.hostname,
requests: requests
};
messaging.ask(details, onAnswerReceived);
})();
/******************************************************************************/

View File

@ -66,16 +66,7 @@ var uBlockMessaging = (function(name){
}; };
var start = function(name) { var start = function(name) {
port = chrome.runtime.connect({ port = chrome.runtime.connect({ name: name });
name: name +
'/' +
String.fromCharCode(
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0
)
});
port.onMessage.addListener(onPortMessage); port.onMessage.addListener(onPortMessage);
// https://github.com/gorhill/uBlock/issues/193 // https://github.com/gorhill/uBlock/issues/193
@ -121,7 +112,7 @@ var uBlockMessaging = (function(name){
var flushCallbacks = function() { var flushCallbacks = function() {
var callback; var callback;
for ( id in requestIdToCallbackMap ) { for ( var id in requestIdToCallbackMap ) {
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) { if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
continue; continue;
} }

View File

@ -143,16 +143,7 @@ var messaging = (function(name){
}; };
var start = function(name) { var start = function(name) {
port = chrome.runtime.connect({ port = chrome.runtime.connect({ name: name });
name: name +
'/' +
String.fromCharCode(
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0
)
});
port.onMessage.addListener(onPortMessage); port.onMessage.addListener(onPortMessage);
// https://github.com/gorhill/uBlock/issues/193 // https://github.com/gorhill/uBlock/issues/193
@ -198,7 +189,7 @@ var messaging = (function(name){
var flushCallbacks = function() { var flushCallbacks = function() {
var callback; var callback;
for ( id in requestIdToCallbackMap ) { for ( var id in requestIdToCallbackMap ) {
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) { if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
continue; continue;
} }

View File

@ -68,16 +68,7 @@ var messaging = (function(name){
}; };
var start = function(name) { var start = function(name) {
port = chrome.runtime.connect({ port = chrome.runtime.connect({ name: name });
name: name +
'/' +
String.fromCharCode(
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0
)
});
port.onMessage.addListener(onPortMessage); port.onMessage.addListener(onPortMessage);
// https://github.com/gorhill/uBlock/issues/193 // https://github.com/gorhill/uBlock/issues/193
@ -123,7 +114,7 @@ var messaging = (function(name){
var flushCallbacks = function() { var flushCallbacks = function() {
var callback; var callback;
for ( id in requestIdToCallbackMap ) { for ( var id in requestIdToCallbackMap ) {
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) { if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
continue; continue;
} }

View File

@ -21,6 +21,7 @@
/* global chrome, µBlock, YaMD5 */ /* global chrome, µBlock, YaMD5 */
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
(function() { (function() {
@ -40,8 +41,7 @@ var getStats = function(request) {
pageAllowedRequestCount: 0, pageAllowedRequestCount: 0,
netFilteringSwitch: false, netFilteringSwitch: false,
cosmeticFilteringSwitch: false, cosmeticFilteringSwitch: false,
logBlockedRequests: µb.userSettings.logBlockedRequests, logRequests: µb.userSettings.logRequests
logAllowedRequests: µb.userSettings.logAllowedRequests
}; };
var pageStore = µb.pageStoreFromTabId(request.tabId); var pageStore = µb.pageStoreFromTabId(request.tabId);
if ( pageStore ) { if ( pageStore ) {
@ -95,6 +95,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// contentscript-start.js // contentscript-start.js
@ -136,6 +137,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// contentscript-end.js // contentscript-end.js
@ -144,9 +146,70 @@ var onMessage = function(request, sender, callback) {
var µb = µBlock; var µb = µBlock;
var onMessage = function(request, sender, callback) { /******************************************************************************/
var tagNameToRequestTypeMap = {
'embed': 'object',
'iframe': 'sub_frame',
'img': 'image',
'object': 'object'
};
/******************************************************************************/
// Evaluate many requests
var filterRequests = function(pageStore, details) {
details.pageDomain = µb.URI.domainFromHostname(details.pageHostname);
var inRequests = details.requests;
var outRequests = [];
var request, result;
var i = inRequests.length;
while ( i-- ) {
request = inRequests[i];
if ( tagNameToRequestTypeMap.hasOwnProperty(request.tagName) === false ) {
continue;
}
result = pageStore.filterRequest(
details,
tagNameToRequestTypeMap[request.tagName],
request.url
);
if ( pageStore.boolFromResult(result) ) {
outRequests.push(request);
}
}
return {
collapse: µb.userSettings.collapseBlocked,
requests: outRequests
};
};
/******************************************************************************/
// Evaluate a single request
var filterRequest = function(pageStore, details) {
if ( tagNameToRequestTypeMap.hasOwnProperty(details.tagName) === false ) {
return;
}
details.pageDomain = µb.URI.domainFromHostname(details.pageHostname);
var result = pageStore.filterRequest(
details,
tagNameToRequestTypeMap[details.tagName],
details.requestURL
);
if ( pageStore.boolFromResult(result) ) {
return { collapse: µb.userSettings.collapseBlocked };
}
};
/******************************************************************************/
var onMessage = function(details, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( details.what ) {
default: default:
break; break;
} }
@ -159,34 +222,33 @@ var onMessage = function(request, sender, callback) {
pageStore = µb.pageStoreFromTabId(sender.tab.id); pageStore = µb.pageStoreFromTabId(sender.tab.id);
} }
switch ( request.what ) { switch ( details.what ) {
case 'retrieveGenericCosmeticSelectors': case 'retrieveGenericCosmeticSelectors':
if ( pageStore && pageStore.getNetFilteringSwitch() ) { if ( pageStore && pageStore.getNetFilteringSwitch() ) {
response = µb.cosmeticFilteringEngine.retrieveGenericSelectors(request); response = µb.cosmeticFilteringEngine.retrieveGenericSelectors(details);
} }
break; break;
case 'injectedSelectors': case 'injectedSelectors':
µb.cosmeticFilteringEngine.addToSelectorCache(request); µb.cosmeticFilteringEngine.addToSelectorCache(details);
break; break;
case 'blockedRequests': // Evaluate many requests
response = { case 'filterRequests':
collapse: µb.userSettings.collapseBlocked, if ( pageStore && pageStore.getNetFilteringSwitch() ) {
blockedRequests: pageStore ? pageStore.blockedRequests : {} response = filterRequests(pageStore, details);
}; }
break; break;
// Check a single request // Evaluate a single request
case 'blockedRequest': case 'filterRequest':
response = { if ( pageStore && pageStore.getNetFilteringSwitch() ) {
collapse: µb.userSettings.collapseBlocked, response = filterRequest(pageStore, details);
blocked: pageStore && pageStore.blockedRequests[request.url] }
};
break; break;
default: default:
return µb.messaging.defaultHandler(request, sender, callback); return µb.messaging.defaultHandler(details, sender, callback);
} }
callback(response); callback(response);
@ -196,6 +258,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// element-picker.js // element-picker.js
@ -238,6 +301,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// 3p-filters.js // 3p-filters.js
@ -309,6 +373,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// 1p-filters.js // 1p-filters.js
@ -345,6 +410,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// whitelist.js // whitelist.js
@ -384,6 +450,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// stats.js // stats.js
@ -400,46 +467,48 @@ var getPageDetails = function(µb, tabId) {
if ( !pageStore ) { if ( !pageStore ) {
return r; return r;
} }
var prepareRequests = function(requests, hasher) { var prepareRequests = function(wantBlocked, hasher) {
var µburi = µb.URI; var µburi = µb.URI;
var dict = pageStore.netFilteringCache.fetchAll();
var r = []; var r = [];
var details, pos, hostname, domain; var details, pos, result, hostname, domain;
for ( var requestURL in requests ) { for ( var url in dict ) {
if ( requests.hasOwnProperty(requestURL) === false ) { if ( dict.hasOwnProperty(url) === false ) {
continue; continue;
} }
details = requests[requestURL]; details = dict[url].data;
if ( typeof details !== 'string' ) { if ( typeof details !== 'string' ) {
continue; continue;
} }
hasher.appendStr(requestURL);
hasher.appendStr(details);
pos = details.indexOf('\t'); pos = details.indexOf('\t');
hostname = µburi.hostnameFromURI(requestURL); result = details.slice(pos + 1);
domain = µburi.domainFromHostname(hostname); if ( wantBlocked !== pageStore.boolFromResult(result) ) {
if ( domain === '' ) { continue;
domain = hostname;
} }
hasher.appendStr(url);
hasher.appendStr(details);
hostname = µburi.hostnameFromURI(url);
domain = µburi.domainFromHostname(hostname) || hostname;
r.push({ r.push({
type: details.slice(0, pos), type: details.slice(0, pos),
domain: domain, domain: domain,
url: requestURL, url: url,
reason: details.slice(pos + 1) reason: result
}); });
} }
return r; return r;
}; };
var hasher = new YaMD5(); var hasher = new YaMD5();
if ( µb.userSettings.logBlockedRequests ) { if ( µb.userSettings.logRequests ) {
r.blockedRequests = prepareRequests(pageStore.blockedRequests, hasher); r.blockedRequests = prepareRequests(true, hasher);
} r.allowedRequests = prepareRequests(false, hasher);
if ( µb.userSettings.logAllowedRequests ) {
r.allowedRequests = prepareRequests(pageStore.allowedRequests, hasher);
} }
r.hash = hasher.end(); r.hash = hasher.end();
return r; return r;
}; };
/******************************************************************************/
var onMessage = function(request, sender, callback) { var onMessage = function(request, sender, callback) {
var µb = µBlock; var µb = µBlock;
@ -472,6 +541,7 @@ var onMessage = function(request, sender, callback) {
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// about.js // about.js

View File

@ -50,6 +50,7 @@
/******************************************************************************/ /******************************************************************************/
var runtimeIdGenerator = 1;
var nameToPortMap = {}; var nameToPortMap = {};
var nameToListenerMap = {}; var nameToListenerMap = {};
var nullFunc = function(){}; var nullFunc = function(){};
@ -58,7 +59,7 @@ var nullFunc = function(){};
var listenerNameFromPortName = function(portName) { var listenerNameFromPortName = function(portName) {
var pos = portName.indexOf('/'); var pos = portName.indexOf('/');
if ( pos <= 0 ) { if ( pos === -1 ) {
return ''; return '';
} }
return portName.slice(0, pos); return portName.slice(0, pos);
@ -213,14 +214,13 @@ var onDisconnect = function(port) {
var onConnect = function(port) { var onConnect = function(port) {
// We must have a port name. // We must have a port name.
if ( !port.name ) { if ( typeof port.name !== 'string' || port.name === '' ) {
throw 'µBlock> messaging.js / onConnectHandler(): no port name!'; console.error('µBlock> messaging.js / onConnectHandler(): no port name!');
return;
} }
// Port should not already exist. // Ensure port name is unique
if ( nameToPortMap[port.name] ) { port.name += '/' + runtimeIdGenerator++;
throw 'µBlock> messaging.js / onConnectHandler(): port already exists!';
}
nameToPortMap[port.name] = port; nameToPortMap[port.name] = port;
port.onMessage.addListener(onMessage); port.onMessage.addListener(onMessage);

View File

@ -28,6 +28,8 @@
/******************************************************************************/ /******************************************************************************/
var µb = µBlock;
// fedcba9876543210 // fedcba9876543210
// ||| | | | // ||| | | |
// ||| | | | // ||| | | |
@ -1023,7 +1025,7 @@ FilterParser.prototype.parseOptParty = function(not) {
/******************************************************************************/ /******************************************************************************/
FilterParser.prototype.parseOptHostnames = function(raw) { FilterParser.prototype.parseOptHostnames = function(raw) {
var µburi = µBlock.URI; var µburi = µb.URI;
var hostnames = raw.split('|'); var hostnames = raw.split('|');
var hostname, not, domain; var hostname, not, domain;
for ( var i = 0; i < hostnames.length; i++ ) { for ( var i = 0; i < hostnames.length; i++ ) {
@ -1155,8 +1157,8 @@ FilterParser.prototype.parse = function(s) {
var FilterContainer = function() { var FilterContainer = function() {
this.reAnyToken = /[%0-9a-z]+/g; this.reAnyToken = /[%0-9a-z]+/g;
this.buckets = new Array(8); this.buckets = new Array(8);
this.blockedAnyPartyHostnames = new µBlock.LiquidDict(); this.blockedAnyPartyHostnames = new µb.LiquidDict();
this.blocked3rdPartyHostnames = new µBlock.LiquidDict(); this.blocked3rdPartyHostnames = new µb.LiquidDict();
this.filterParser = new FilterParser(); this.filterParser = new FilterParser();
this.noDomainBits = this.toDomainBits(noDomainName); this.noDomainBits = this.toDomainBits(noDomainName);
this.reset(); this.reset();
@ -1633,7 +1635,7 @@ FilterContainer.prototype.matchAnyPartyHostname = function(requestHostname) {
return '||' + requestHostname + '^'; return '||' + requestHostname + '^';
} }
// Check parent hostnames if quick test failed // Check parent hostnames if quick test failed
var hostnames = µBlock.URI.parentHostnamesFromHostname(requestHostname); var hostnames = µb.URI.parentHostnamesFromHostname(requestHostname);
for ( var i = 0, n = hostnames.length; i < n; i++ ) { for ( var i = 0, n = hostnames.length; i < n; i++ ) {
if ( this.blockedAnyPartyHostnames.test(hostnames[i]) ) { if ( this.blockedAnyPartyHostnames.test(hostnames[i]) ) {
return '||' + hostnames[i] + '^'; return '||' + hostnames[i] + '^';
@ -1658,7 +1660,7 @@ FilterContainer.prototype.match3rdPartyHostname = function(requestHostname) {
return '||' + requestHostname + '^$third-party'; return '||' + requestHostname + '^$third-party';
} }
// Check parent hostnames if quick test failed // Check parent hostnames if quick test failed
var hostnames = µBlock.URI.parentHostnamesFromHostname(requestHostname); var hostnames = µb.URI.parentHostnamesFromHostname(requestHostname);
for ( var i = 0, n = hostnames.length; i < n; i++ ) { for ( var i = 0, n = hostnames.length; i < n; i++ ) {
if ( this.blocked3rdPartyHostnames.test(hostnames[i]) ) { if ( this.blocked3rdPartyHostnames.test(hostnames[i]) ) {
return '||' + hostnames[i] + '^$third-party'; return '||' + hostnames[i] + '^$third-party';
@ -1675,9 +1677,10 @@ FilterContainer.prototype.match3rdPartyHostname = function(requestHostname) {
// Some type of requests are exceptional, they need custom handling, // Some type of requests are exceptional, they need custom handling,
// not the generic handling. // not the generic handling.
FilterContainer.prototype.matchStringExactType = function(pageDetails, requestURL, requestType, requestHostname) { FilterContainer.prototype.matchStringExactType = function(pageDetails, requestURL, requestType) {
var url = requestURL.toLowerCase(); var url = requestURL.toLowerCase();
var pageDomain = pageDetails.pageDomain || ''; var pageDomain = pageDetails.pageDomain || '';
var requestHostname = µb.URI.hostnameFromURI(requestURL);
var party = requestHostname.slice(-pageDomain.length) === pageDomain ? var party = requestHostname.slice(-pageDomain.length) === pageDomain ?
FirstParty : FirstParty :
ThirdParty; ThirdParty;
@ -1710,7 +1713,7 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | type | this.noDomainBits)]; buckets[7] = categories[this.makeCategoryKey(BlockOneParty | type | this.noDomainBits)];
bf = this.matchTokens(url); bf = this.matchTokens(url);
if ( bf === false ) { if ( bf === false ) {
return false; return '';
} }
// Test against allow filters // Test against allow filters
@ -1728,7 +1731,7 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.matchString = function(pageDetails, requestURL, requestType, requestHostname) { FilterContainer.prototype.matchString = function(pageDetails, requestURL, requestType) {
// https://github.com/gorhill/httpswitchboard/issues/239 // https://github.com/gorhill/httpswitchboard/issues/239
// Convert url to lower case: // Convert url to lower case:
// `match-case` option not supported, but then, I saw only one // `match-case` option not supported, but then, I saw only one
@ -1757,9 +1760,17 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
// filter. // filter.
var pageDomain = pageDetails.pageDomain || ''; var pageDomain = pageDetails.pageDomain || '';
var party = requestHostname.slice(-pageDomain.length) === pageDomain ? var requestHostname = µb.URI.hostnameFromURI(requestURL);
FirstParty :
ThirdParty; // Find out the relation between the page and request
var party = ThirdParty;
if ( requestHostname.slice(0 - pageDomain.length) === pageDomain ) {
// Be sure to not confuse 'example.com' with 'anotherexample.com'
var c = requestHostname.charAt(0 - pageDomain.length - 1);
if ( c === '' || c === '.' ) {
party = FirstParty;
}
}
// This will be used by hostname-based filters // This will be used by hostname-based filters
pageHostname = pageDetails.pageHostname || ''; pageHostname = pageDetails.pageHostname || '';
@ -1784,7 +1795,7 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | Important | type | this.noDomainBits)]; buckets[7] = categories[this.makeCategoryKey(BlockOneParty | Important | type | this.noDomainBits)];
var bf = this.matchTokens(url); var bf = this.matchTokens(url);
if ( bf !== false ) { if ( bf !== false ) {
return bf.toString(); return bf.toString() + '$important';
} }
// Test hostname-based block filters // Test hostname-based block filters
@ -1810,7 +1821,7 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
// If there is no block filter, no need to test against allow filters // If there is no block filter, no need to test against allow filters
if ( bf === false ) { if ( bf === false ) {
return false; return '';
} }
// Test against allow filters // Test against allow filters

View File

@ -38,32 +38,180 @@ To create a log of net requests
/******************************************************************************/ /******************************************************************************/
var µb = µBlock; var µb = µBlock;
var frameStoreJunkyard = [];
var pageStoreJunkyard = []; /******************************************************************************/
/******************************************************************************/
// To mitigate memory churning
var netFilteringResultCacheEntryJunkyard = [];
var netFilteringResultCacheEntryJunkyardMax = 200;
/******************************************************************************/ /******************************************************************************/
var frameStoreFactory = function(frameURL) { var NetFilteringResultCacheEntry = function(data) {
var entry = frameStoreJunkyard.pop(); this.init(data);
if ( entry ) {
return entry.init(frameURL);
}
return new FrameStore(frameURL);
}; };
var disposeFrameStores = function(map) { /******************************************************************************/
for ( var k in map ) {
if ( map.hasOwnProperty(k) === false ) { NetFilteringResultCacheEntry.prototype.init = function(data) {
this.data = data;
this.time = Date.now();
};
/******************************************************************************/
NetFilteringResultCacheEntry.prototype.dispose = function() {
this.data = null;
if ( netFilteringResultCacheEntryJunkyard.length < netFilteringResultCacheEntryJunkyardMax ) {
netFilteringResultCacheEntryJunkyard.push(this);
}
};
/******************************************************************************/
NetFilteringResultCacheEntry.factory = function(data) {
var entry = netFilteringResultCacheEntryJunkyard.pop();
if ( entry === undefined ) {
entry = new NetFilteringResultCacheEntry(data);
} else {
entry.init(data);
}
return entry;
};
/******************************************************************************/
/******************************************************************************/
// To mitigate memory churning
var uidGenerator = 1;
var netFilteringCacheJunkyard = [];
var netFilteringCacheJunkyardMax = 10;
/******************************************************************************/
var NetFilteringResultCache = function() {
this.init();
};
/******************************************************************************/
NetFilteringResultCache.factory = function() {
var entry = netFilteringCacheJunkyard.pop();
if ( entry === undefined ) {
entry = new NetFilteringResultCache();
} else {
entry.init();
}
return entry;
};
/******************************************************************************/
NetFilteringResultCache.prototype.init = function() {
this.uname = 'NetFilteringResultCache:' + uidGenerator++;
this.urls = {};
this.count = 0;
this.shelfLife = 60 * 1000;
};
/******************************************************************************/
NetFilteringResultCache.prototype.dispose = function() {
for ( var key in this.urls ) {
if ( this.urls.hasOwnProperty(key) === false ) {
continue; continue;
} }
if ( frameStoreJunkyard.length > 50 ) { this.urls[key].dispose();
}
µBlock.asyncJobs.remove(this.uname);
this.uname = '';
this.urls = {};
this.count = 0;
if ( netFilteringCacheJunkyard.length < netFilteringCacheJunkyardMax ) {
netFilteringCacheJunkyard.push(this);
}
return null;
};
/******************************************************************************/
NetFilteringResultCache.prototype.add = function(url, data) {
var entry = this.urls[url];
if ( entry !== undefined ) {
entry.data = data;
entry.time = Date.now();
return;
}
this.urls[url] = NetFilteringResultCacheEntry.factory(data);
if ( this.count === 0 ) {
this.pruneAsync();
}
this.count += 1;
};
/******************************************************************************/
NetFilteringResultCache.prototype.fetchAll = function() {
return this.urls;
};
/******************************************************************************/
NetFilteringResultCache.prototype.compareEntries = function(a, b) {
return this.urls[b].time - this.urls[a].time;
};
/******************************************************************************/
NetFilteringResultCache.prototype.prune = function() {
var keys = Object.keys(this.urls).sort(this.compareEntries.bind(this));
var obsolete = Date.now() - this.shelfLife;
var key, entry;
var i = keys.length;
while ( i-- ) {
key = keys[i];
entry = this.urls[key];
if ( entry.time > obsolete ) {
break; break;
} }
frameStoreJunkyard.push(map[k].dispose()); entry.dispose();
delete this.urls[key];
}
this.count -= keys.length - i - 1;
if ( this.count > 0 ) {
this.pruneAsync();
} }
return {};
}; };
// https://www.youtube.com/watch?v=0vTBZzB_gfY
/******************************************************************************/
NetFilteringResultCache.prototype.pruneAsync = function() {
µBlock.asyncJobs.add(
this.uname,
null,
this.prune.bind(this),
this.shelfLife + 120000,
false
);
};
/******************************************************************************/
NetFilteringResultCache.prototype.lookup = function(url) {
var entry = this.urls[url];
return entry !== undefined ? entry.data : undefined;
};
/******************************************************************************/
/******************************************************************************/
// To mitigate memory churning
var frameStoreJunkyard = [];
var frameStoreJunkyardMax = 50;
/******************************************************************************/ /******************************************************************************/
var FrameStore = function(frameURL) { var FrameStore = function(frameURL) {
@ -72,6 +220,18 @@ var FrameStore = function(frameURL) {
/******************************************************************************/ /******************************************************************************/
FrameStore.factory = function(frameURL) {
var entry = frameStoreJunkyard.pop();
if ( entry === undefined ) {
entry = new FrameStore(frameURL);
} else {
entry.init(frameURL);
}
return entry;
};
/******************************************************************************/
FrameStore.prototype.init = function(frameURL) { FrameStore.prototype.init = function(frameURL) {
var µburi = µb.URI; var µburi = µb.URI;
this.pageHostname = µburi.hostnameFromURI(frameURL); this.pageHostname = µburi.hostnameFromURI(frameURL);
@ -83,18 +243,24 @@ FrameStore.prototype.init = function(frameURL) {
FrameStore.prototype.dispose = function() { FrameStore.prototype.dispose = function() {
this.pageHostname = this.pageDomain = ''; this.pageHostname = this.pageDomain = '';
return this; if ( frameStoreJunkyard.length < frameStoreJunkyardMax ) {
frameStoreJunkyard.push(this);
}
return null;
}; };
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
var pageStoreFactory = function(tabId, pageURL) { // To mitigate memory churning
var entry = pageStoreJunkyard.pop(); var pageStoreJunkyard = [];
if ( entry ) { var pageStoreJunkyardMax = 10;
return entry.init(tabId, pageURL);
} /******************************************************************************/
return new PageStore(tabId, pageURL);
}; // Cache only what is worth it if logging is disabled
// http://jsperf.com/string-indexof-vs-object
var collapsibleRequestTypes = 'image sub_frame object';
/******************************************************************************/ /******************************************************************************/
@ -104,6 +270,18 @@ var PageStore = function(tabId, pageURL) {
/******************************************************************************/ /******************************************************************************/
PageStore.factory = function(tabId, pageURL) {
var entry = pageStoreJunkyard.pop();
if ( entry === undefined ) {
entry = new PageStore(tabId, pageURL);
} else {
entry.init(tabId, pageURL);
}
return entry;
};
/******************************************************************************/
PageStore.prototype.init = function(tabId, pageURL) { PageStore.prototype.init = function(tabId, pageURL) {
this.tabId = tabId; this.tabId = tabId;
this.previousPageURL = ''; this.previousPageURL = '';
@ -114,26 +292,33 @@ PageStore.prototype.init = function(tabId, pageURL) {
// Use hostname if no domain can be extracted // Use hostname if no domain can be extracted
this.pageDomain = µb.URI.domainFromHostname(this.pageHostname) || this.pageHostname; this.pageDomain = µb.URI.domainFromHostname(this.pageHostname) || this.pageHostname;
this.frames = disposeFrameStores(this.frames); this.frames = {};
this.netFiltering = true; this.netFiltering = true;
this.netFilteringReadTime = 0; this.netFilteringReadTime = 0;
this.perLoadBlockedRequestCount = 0; this.perLoadBlockedRequestCount = 0;
this.perLoadAllowedRequestCount = 0; this.perLoadAllowedRequestCount = 0;
this.blockedRequests = {};
this.allowedRequests = {}; this.netFilteringCache = NetFilteringResultCache.factory();
this.disposeTime = 0; if ( µb.userSettings.logRequests ) {
this.netFilteringCache.shelfLife = 30 * 60 * 1000;
}
return this; return this;
}; };
/******************************************************************************/ /******************************************************************************/
PageStore.prototype.reuse = function(pageURL) { PageStore.prototype.reuse = function(pageURL) {
this.disposeFrameStores();
this.netFilteringCache = this.netFilteringCache.dispose();
var previousPageURL = this.pageURL; var previousPageURL = this.pageURL;
this.init(this.tabId, pageURL); this.init(this.tabId, pageURL);
this.previousPageURL = previousPageURL; this.previousPageURL = previousPageURL;
return this; return this;
}; };
// https://www.youtube.com/watch?v=dltNSbOupgE
/******************************************************************************/ /******************************************************************************/
PageStore.prototype.dispose = function() { PageStore.prototype.dispose = function() {
@ -142,11 +327,30 @@ PageStore.prototype.dispose = function() {
// sizeable enough chunks (especially requests, through the request URL // sizeable enough chunks (especially requests, through the request URL
// used as a key). // used as a key).
this.pageURL = ''; this.pageURL = '';
this.previousPageURL = '';
this.pageHostname = ''; this.pageHostname = '';
this.pageDomain = ''; this.pageDomain = '';
if ( pageStoreJunkyard.length < 8 ) { this.disposeFrameStores();
this.netFilteringCache = this.netFilteringCache.dispose();
if ( pageStoreJunkyard.length < pageStoreJunkyardMax ) {
pageStoreJunkyard.push(this); pageStoreJunkyard.push(this);
} }
return null;
};
/******************************************************************************/
PageStore.prototype.disposeFrameStores = function() {
var frames = this.frames;
if ( typeof frames === 'object' ) {
for ( var k in frames ) {
if ( frames.hasOwnProperty(k) === false ) {
continue;
}
frames[k].dispose();
}
}
this.frames = {};
}; };
/******************************************************************************/ /******************************************************************************/
@ -154,7 +358,7 @@ PageStore.prototype.dispose = function() {
PageStore.prototype.addFrame = function(frameId, frameURL) { PageStore.prototype.addFrame = function(frameId, frameURL) {
var frameStore = this.frames[frameId]; var frameStore = this.frames[frameId];
if ( frameStore === undefined ) { if ( frameStore === undefined ) {
this.frames[frameId] = frameStore = frameStoreFactory(frameURL); this.frames[frameId] = frameStore = FrameStore.factory(frameURL);
//console.debug('µBlock> PageStore.addFrame(%d, "%s")', frameId, frameURL); //console.debug('µBlock> PageStore.addFrame(%d, "%s")', frameId, frameURL);
} }
return frameStore; return frameStore;
@ -178,35 +382,26 @@ PageStore.prototype.getNetFilteringSwitch = function() {
/******************************************************************************/ /******************************************************************************/
PageStore.prototype.recordRequest = function(type, url, reason) { PageStore.prototype.filterRequest = function(context, requestType, requestURL) {
var blocked = reason !== false && reason.slice(0, 2) !== '@@'; var result = this.netFilteringCache.lookup(requestURL);
if ( result !== undefined ) {
if ( !blocked ) { return result.slice(result.indexOf('\t') + 1);
this.perLoadAllowedRequestCount++;
µb.localSettings.allowedRequestCount++;
if ( µb.userSettings.logAllowedRequests ) {
this.allowedRequests[url] = type + '\t' + (reason || '');
}
return;
} }
//console.debug('µBlock> PageStore.filterRequest(): "%s" not in cache', requestURL);
µb.updateBadgeAsync(this.tabId); result = µb.netFilteringEngine.matchString(context, requestURL, requestType);
if ( collapsibleRequestTypes.indexOf(requestType) !== -1 || µb.userSettings.logRequests ) {
this.perLoadBlockedRequestCount++; this.netFilteringCache.add(requestURL, requestType + '\t' + result);
µb.localSettings.blockedRequestCount++;
// https://github.com/gorhill/uBlock/issues/7
// https://github.com/gorhill/uBlock/issues/12
// No need to record blocked requests which are not image or frame, as
// these are the only ones we try to hide when they are blocked.
if ( µb.userSettings.logBlockedRequests === false ) {
if ( type === 'image' || type === 'sub_frame' ) {
this.blockedRequests[url] = true;
}
return;
} }
this.blockedRequests[url] = type + '\t' + reason; return result;
};
/******************************************************************************/
// false: not blocked
// true: blocked
PageStore.prototype.boolFromResult = function(result) {
return typeof result === 'string' && result !== '' && result.slice(0, 2) !== '@@';
}; };
/******************************************************************************/ /******************************************************************************/
@ -229,7 +424,7 @@ PageStore.prototype.updateBadge = function() {
/******************************************************************************/ /******************************************************************************/
return { return {
factory: pageStoreFactory factory: PageStore.factory
}; };
})(); })();

View File

@ -59,7 +59,7 @@ var renderStats = function() {
// - logging of requests enabled // - logging of requests enabled
uDom('#gotoLog').toggleClass( uDom('#gotoLog').toggleClass(
'enabled', 'enabled',
isHTTP && (stats.logBlockedRequests || stats.logAllowedRequests) isHTTP && stats.logRequests
); );
// Conditions for element picker: // Conditions for element picker:

View File

@ -31,27 +31,13 @@ messaging.start('stats.js');
/******************************************************************************/ /******************************************************************************/
var logBlockedSettingChanged = function() { var logSettingChanged = function() {
messaging.tell({ messaging.tell({
what: 'userSettings', what: 'userSettings',
name: 'logBlockedRequests', name: 'logRequests',
value: this.checked value: this.checked
}); });
uDom('#requests table').toggleClass('hideBlocked', !this.checked); uDom('#requests').toggleClass('logEnabled', this.checked);
uDom('#requests').toggleClass('logEnabled', this.checked || uDom('#logAllowedRequests').prop('checked'));
renderPageSelector();
};
/******************************************************************************/
var logAllowedSettingChanged = function() {
messaging.tell({
what: 'userSettings',
name: 'logAllowedRequests',
value: this.checked
});
uDom('#requests table').toggleClass('hideAllowed', !this.checked);
uDom('#requests').toggleClass('logEnabled', this.checked || uDom('#logBlockedRequests').prop('checked'));
renderPageSelector(); renderPageSelector();
}; };
@ -186,7 +172,7 @@ var pageSelectorChanged = function() {
/******************************************************************************/ /******************************************************************************/
var renderPageSelector = function(targetTabId) { var renderPageSelector = function(targetTabId) {
if ( !uDom('#logBlockedRequests').prop('checked') && !uDom('#logAllowedRequests').prop('checked') ) { if ( !uDom('#logRequests').prop('checked') ) {
return; return;
} }
var selectedTabId = targetTabId || parseInt(uDom('#pageSelector').val(), 10); var selectedTabId = targetTabId || parseInt(uDom('#pageSelector').val(), 10);
@ -228,18 +214,14 @@ var renderPageSelector = function(targetTabId) {
/******************************************************************************/ /******************************************************************************/
var onUserSettingsReceived = function(details) { var onUserSettingsReceived = function(details) {
uDom('#logBlockedRequests').prop('checked', details.logBlockedRequests); uDom('#logRequests').prop('checked', details.logRequests);
uDom('#logAllowedRequests').prop('checked', details.logAllowedRequests); uDom('#requests').toggleClass('logEnabled', details.logRequests);
uDom('#requests').toggleClass('logEnabled', details.logBlockedRequests || details.logAllowedRequests);
uDom('#requests table').toggleClass('hideBlocked', !details.logBlockedRequests);
uDom('#requests table').toggleClass('hideAllowed', !details.logAllowedRequests);
var matches = window.location.search.slice(1).match(/(?:^|&)which=(\d+)/); var matches = window.location.search.slice(1).match(/(?:^|&)which=(\d+)/);
var tabId = matches && matches.length === 2 ? parseInt(matches[1], 10) : 0; var tabId = matches && matches.length === 2 ? parseInt(matches[1], 10) : 0;
renderPageSelector(tabId); renderPageSelector(tabId);
uDom('#logBlockedRequests').on('change', logBlockedSettingChanged); uDom('#logRequests').on('change', logSettingChanged);
uDom('#logAllowedRequests').on('change', logAllowedSettingChanged);
uDom('#refresh').on('click', function() { renderPageSelector(); }); uDom('#refresh').on('click', function() { renderPageSelector(); });
uDom('#pageSelector').on('change', pageSelectorChanged); uDom('#pageSelector').on('change', pageSelectorChanged);
}; };

View File

@ -114,7 +114,11 @@
µBlock.unbindTabFromPageStats = function(tabId) { µBlock.unbindTabFromPageStats = function(tabId) {
//console.debug('µBlock> unbindTabFromPageStats(%d)', tabId); //console.debug('µBlock> unbindTabFromPageStats(%d)', tabId);
delete this.pageStores[tabId]; var pageStore = this.pageStores[tabId];
if ( pageStore !== undefined ) {
pageStore.dispose();
delete this.pageStores[tabId];
}
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -51,7 +51,6 @@ var onBeforeRequest = function(details) {
} }
var µburi = µb.URI.set(requestURL); var µburi = µb.URI.set(requestURL);
var requestHostname = µburi.hostname;
var requestPath = µburi.path; var requestPath = µburi.path;
// rhill 2013-12-15: // rhill 2013-12-15:
@ -78,31 +77,35 @@ var onBeforeRequest = function(details) {
} }
} }
var reason = false; var result = '';
if ( pageStore.getNetFilteringSwitch() ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.netFilteringEngine.matchString(requestContext, requestURL, requestType, requestHostname); result = pageStore.filterRequest(requestContext, requestType, requestURL);
} }
// Record what happened.
pageStore.recordRequest(requestType, requestURL, reason);
// Not blocked? // Not blocked
if ( reason === false || reason.slice(0, 2) === '@@' ) { if ( pageStore.boolFromResult(result) === false ) {
//console.debug('µBlock> onBeforeRequest()> ALLOW "%s" (%o)', details.url, details); pageStore.perLoadAllowedRequestCount++;
µb.localSettings.allowedRequestCount++;
// https://github.com/gorhill/uBlock/issues/114 // https://github.com/gorhill/uBlock/issues/114
if ( frameId > 0 && frameStore === undefined ) { if ( frameId > 0 && frameStore === undefined ) {
pageStore.addFrame(frameId, requestURL); pageStore.addFrame(frameId, requestURL);
} }
//console.debug('µBlock> onBeforeRequest()> ALLOW "%s" (%o)', details.url, details);
return; return;
} }
// Blocked // Blocked
//console.debug('µBlock> onBeforeRequest()> BLOCK "%s" (%o) because "%s"', details.url, details, reason); pageStore.perLoadBlockedRequestCount++;
µb.localSettings.blockedRequestCount++;
µb.updateBadgeAsync(tabId);
// https://github.com/gorhill/uBlock/issues/18 // https://github.com/gorhill/uBlock/issues/18
// Do not use redirection, we need to block outright to be sure the request // Do not use redirection, we need to block outright to be sure the request
// will not be made. There can be no such guarantee with redirection. // will not be made. There can be no such guarantee with redirection.
//console.debug('µBlock> onBeforeRequest()> BLOCK "%s" (%o) because "%s"', details.url, details, result);
return { 'cancel': true }; return { 'cancel': true };
}; };
@ -166,18 +169,13 @@ var onBeforeSendHeaders = function(details) {
// switch of the popup. If so, that would require being able to lookup // switch of the popup. If so, that would require being able to lookup
// a page store from a URL. Have to keep in mind the same URL can appear // a page store from a URL. Have to keep in mind the same URL can appear
// in multiple tabs. // in multiple tabs.
var reason = false; var result = '';
if ( pageStore.getNetFilteringSwitch() ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.netFilteringEngine.matchStringExactType( result = µb.netFilteringEngine.matchStringExactType(pageDetails, requestURL, 'popup');
pageDetails,
requestURL,
'popup',
µburi.hostnameFromURI(requestURL)
);
} }
// Not blocked? // Not blocked?
if ( reason === false || reason.slice(0, 2) === '@@' ) { if ( result === '' || result.slice(0, 2) === '@@' ) {
return; return;
} }

View File

@ -70,12 +70,6 @@ tr.requestEntry td:nth-of-type(1) {
tr.requestEntry td:nth-of-type(2) { tr.requestEntry td:nth-of-type(2) {
text-align: right; text-align: right;
} }
table.hideBlocked tr.logBlocked {
display: none;
}
table.hideAllowed tr.logAllowed {
display: none;
}
tr.logBlocked { tr.logBlocked {
background-color: #fff8f8; background-color: #fff8f8;
} }
@ -98,12 +92,9 @@ tr.logAllowed ~ tr td:nth-of-type(3) b {
<body> <body>
<ul> <ul>
<li><input id="logBlockedRequests" type="checkbox" data-range="bool" /><label data-i18n="logBlockedRequestsPrompt"></label> <li><input id="logRequests" type="checkbox" data-range="bool" /><label data-i18n="logNetRequestsPrompt"></label>
<button class="whatisthis"></button> <button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="logBlockedRequestsHelp"></div> <div class="whatisthis-expandable para" data-i18n="logNetRequestsHelp"></div>
<li><input id="logAllowedRequests" type="checkbox" data-range="bool" /><label data-i18n="logAllowedRequestsPrompt"></label>
<button class="whatisthis"></button>
<div class="whatisthis-expandable para" data-i18n="logAllowedRequestsHelp"></div>
</ul> </ul>
<div id="requests"> <div id="requests">