mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-02 17:19:38 +02:00
this fixes 202
This commit is contained in:
parent
1b033d38d7
commit
ee81436ff5
@ -207,22 +207,14 @@
|
||||
"message":"Änderungen anwenden",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"logBlockedRequestsPrompt":{
|
||||
"logNetRequestsPrompt":{
|
||||
"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.",
|
||||
"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":{
|
||||
"message":"Blockierte Anfragen",
|
||||
"description":"English: Blocked requests"
|
||||
|
@ -207,20 +207,12 @@
|
||||
"message":"Apply changes",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"logBlockedRequestsPrompt":{
|
||||
"message":"Enable the logging of blocked requests",
|
||||
"description":"English: Enable the logging of blocked requests"
|
||||
"logNetRequestsPrompt":{
|
||||
"message":"Enable the logging of network requests",
|
||||
"description":"English: Enable the logging of network requests"
|
||||
},
|
||||
"logBlockedRequestsHelp":{
|
||||
"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.",
|
||||
"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.",
|
||||
"logNetRequestsHelp":{
|
||||
"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"
|
||||
},
|
||||
"logBlockedRequestsHeader":{
|
||||
|
@ -207,20 +207,12 @@
|
||||
"message":"Appliquer",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"logBlockedRequestsPrompt":{
|
||||
"message":"Activer la journalisation des requêtes bloquées",
|
||||
"description":"English: Enable the logging of blocked requests"
|
||||
"logNetRequestsPrompt":{
|
||||
"message":"Activer la journalisation des requêtes",
|
||||
"description":"English: Enable the logging of network requests"
|
||||
},
|
||||
"logBlockedRequestsHelp":{
|
||||
"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.",
|
||||
"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.",
|
||||
"logNetRequestsHelp":{
|
||||
"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"
|
||||
},
|
||||
"logBlockedRequestsHeader":{
|
||||
|
@ -14,8 +14,8 @@
|
||||
<script src="js/liquid-dict.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/assets.js"></script>
|
||||
<script src="js/net-filters.js"></script>
|
||||
<script src="js/cosmetic-filters.js"></script>
|
||||
<script src="js/net-filtering.js"></script>
|
||||
<script src="js/cosmetic-filtering.js"></script>
|
||||
<script src="js/ublock.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/profiler.js"></script>
|
||||
|
62
js/async.js
62
js/async.js
@ -27,6 +27,8 @@
|
||||
|
||||
µBlock.asyncJobs = (function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var processJobs = function() {
|
||||
asyncJobManager.process();
|
||||
};
|
||||
@ -45,6 +47,8 @@ AsyncJobEntry.prototype.destroy = function() {
|
||||
this.callback = null;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var AsyncJobManager = function() {
|
||||
this.timeResolution = 200;
|
||||
this.jobs = {};
|
||||
@ -54,7 +58,15 @@ var AsyncJobManager = function() {
|
||||
this.timerWhen = Number.MAX_VALUE;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
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 jobs = this.jobs, job;
|
||||
for ( var jobName in jobs ) {
|
||||
@ -68,6 +80,10 @@ AsyncJobManager.prototype.restartTimer = function() {
|
||||
// Quantize time value
|
||||
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 ) {
|
||||
clearTimeout(this.timerId);
|
||||
this.timerWhen = when;
|
||||
@ -75,6 +91,8 @@ AsyncJobManager.prototype.restartTimer = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
AsyncJobManager.prototype.add = function(name, data, callback, delay, recurrent) {
|
||||
var job = this.jobs[name];
|
||||
if ( !job ) {
|
||||
@ -94,6 +112,22 @@ AsyncJobManager.prototype.add = function(name, data, callback, delay, recurrent)
|
||||
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() {
|
||||
this.timerId = null;
|
||||
this.timerWhen = Number.MAX_VALUE;
|
||||
@ -120,9 +154,13 @@ AsyncJobManager.prototype.process = function() {
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Only one instance
|
||||
var asyncJobManager = new AsyncJobManager();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Publish
|
||||
return asyncJobManager;
|
||||
|
||||
@ -133,12 +171,12 @@ return asyncJobManager;
|
||||
// Update visual of extension icon.
|
||||
// A time out is used to coalesce adjacent requests to update badge.
|
||||
|
||||
µBlock.updateBadgeAsync = function(tabId) {
|
||||
if ( tabId < 0 ) {
|
||||
return;
|
||||
}
|
||||
var µb = this;
|
||||
var updateBadge = function() {
|
||||
µBlock.updateBadgeAsync = (function(){
|
||||
var µb = µBlock;
|
||||
|
||||
// Cache callback definition, it was a bad idea to define this one inside
|
||||
// updateBadgeAsync
|
||||
var updateBadge = function(tabId) {
|
||||
var pageStore = µb.pageStoreFromTabId(tabId);
|
||||
if ( pageStore ) {
|
||||
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;
|
||||
})();
|
@ -41,8 +41,7 @@ return {
|
||||
autoUpdate: true,
|
||||
collapseBlocked: true,
|
||||
externalLists: '',
|
||||
logBlockedRequests: false,
|
||||
logAllowedRequests: false,
|
||||
logRequests: false,
|
||||
parseAllABPHideFilters: true,
|
||||
showIconBadge: true
|
||||
},
|
||||
|
@ -56,16 +56,7 @@ var uBlockMessaging = (function(name){
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({
|
||||
name: name +
|
||||
'/' +
|
||||
String.fromCharCode(
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0
|
||||
)
|
||||
});
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
@ -111,7 +102,7 @@ var uBlockMessaging = (function(name){
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( id in requestIdToCallbackMap ) {
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
@ -527,63 +518,11 @@ var uBlockMessaging = (function(name){
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/7
|
||||
// Permanent
|
||||
|
||||
(function() {
|
||||
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:
|
||||
// - Future requests not blocked yet
|
||||
// - Elements dynamically added to the page
|
||||
@ -612,11 +551,15 @@ var uBlockMessaging = (function(name){
|
||||
if ( typeof src !== 'string' || src === '' ) {
|
||||
return;
|
||||
}
|
||||
if ( src.slice(0, 4) !== 'http' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/174
|
||||
// Do not remove fragment from src URL
|
||||
|
||||
var onAnswerReceived = function(details) {
|
||||
if ( !details.blocked ) {
|
||||
if ( typeof details !== 'object' || details === null ) {
|
||||
return;
|
||||
}
|
||||
// If `!important` is not there, going back using history will
|
||||
@ -637,7 +580,15 @@ var uBlockMessaging = (function(name){
|
||||
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) {
|
||||
@ -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);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -66,16 +66,7 @@ var uBlockMessaging = (function(name){
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({
|
||||
name: name +
|
||||
'/' +
|
||||
String.fromCharCode(
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0
|
||||
)
|
||||
});
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
@ -121,7 +112,7 @@ var uBlockMessaging = (function(name){
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( id in requestIdToCallbackMap ) {
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
@ -143,16 +143,7 @@ var messaging = (function(name){
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({
|
||||
name: name +
|
||||
'/' +
|
||||
String.fromCharCode(
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0
|
||||
)
|
||||
});
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
@ -198,7 +189,7 @@ var messaging = (function(name){
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( id in requestIdToCallbackMap ) {
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
@ -68,16 +68,7 @@ var messaging = (function(name){
|
||||
};
|
||||
|
||||
var start = function(name) {
|
||||
port = chrome.runtime.connect({
|
||||
name: name +
|
||||
'/' +
|
||||
String.fromCharCode(
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0,
|
||||
Math.random() * 0x7FFF | 0
|
||||
)
|
||||
});
|
||||
port = chrome.runtime.connect({ name: name });
|
||||
port.onMessage.addListener(onPortMessage);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/193
|
||||
@ -123,7 +114,7 @@ var messaging = (function(name){
|
||||
|
||||
var flushCallbacks = function() {
|
||||
var callback;
|
||||
for ( id in requestIdToCallbackMap ) {
|
||||
for ( var id in requestIdToCallbackMap ) {
|
||||
if ( requestIdToCallbackMap.hasOwnProperty(id) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
/* global chrome, µBlock, YaMD5 */
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
@ -40,8 +41,7 @@ var getStats = function(request) {
|
||||
pageAllowedRequestCount: 0,
|
||||
netFilteringSwitch: false,
|
||||
cosmeticFilteringSwitch: false,
|
||||
logBlockedRequests: µb.userSettings.logBlockedRequests,
|
||||
logAllowedRequests: µb.userSettings.logAllowedRequests
|
||||
logRequests: µb.userSettings.logRequests
|
||||
};
|
||||
var pageStore = µb.pageStoreFromTabId(request.tabId);
|
||||
if ( pageStore ) {
|
||||
@ -95,6 +95,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// contentscript-start.js
|
||||
@ -136,6 +137,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// contentscript-end.js
|
||||
@ -144,9 +146,70 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
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
|
||||
switch ( request.what ) {
|
||||
switch ( details.what ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -159,34 +222,33 @@ var onMessage = function(request, sender, callback) {
|
||||
pageStore = µb.pageStoreFromTabId(sender.tab.id);
|
||||
}
|
||||
|
||||
switch ( request.what ) {
|
||||
switch ( details.what ) {
|
||||
case 'retrieveGenericCosmeticSelectors':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = µb.cosmeticFilteringEngine.retrieveGenericSelectors(request);
|
||||
response = µb.cosmeticFilteringEngine.retrieveGenericSelectors(details);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'injectedSelectors':
|
||||
µb.cosmeticFilteringEngine.addToSelectorCache(request);
|
||||
µb.cosmeticFilteringEngine.addToSelectorCache(details);
|
||||
break;
|
||||
|
||||
case 'blockedRequests':
|
||||
response = {
|
||||
collapse: µb.userSettings.collapseBlocked,
|
||||
blockedRequests: pageStore ? pageStore.blockedRequests : {}
|
||||
};
|
||||
// Evaluate many requests
|
||||
case 'filterRequests':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = filterRequests(pageStore, details);
|
||||
}
|
||||
break;
|
||||
|
||||
// Check a single request
|
||||
case 'blockedRequest':
|
||||
response = {
|
||||
collapse: µb.userSettings.collapseBlocked,
|
||||
blocked: pageStore && pageStore.blockedRequests[request.url]
|
||||
};
|
||||
// Evaluate a single request
|
||||
case 'filterRequest':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = filterRequest(pageStore, details);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return µb.messaging.defaultHandler(request, sender, callback);
|
||||
return µb.messaging.defaultHandler(details, sender, callback);
|
||||
}
|
||||
|
||||
callback(response);
|
||||
@ -196,6 +258,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// element-picker.js
|
||||
@ -238,6 +301,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// 3p-filters.js
|
||||
@ -309,6 +373,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// 1p-filters.js
|
||||
@ -345,6 +410,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// whitelist.js
|
||||
@ -384,6 +450,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// stats.js
|
||||
@ -400,46 +467,48 @@ var getPageDetails = function(µb, tabId) {
|
||||
if ( !pageStore ) {
|
||||
return r;
|
||||
}
|
||||
var prepareRequests = function(requests, hasher) {
|
||||
var prepareRequests = function(wantBlocked, hasher) {
|
||||
var µburi = µb.URI;
|
||||
var dict = pageStore.netFilteringCache.fetchAll();
|
||||
var r = [];
|
||||
var details, pos, hostname, domain;
|
||||
for ( var requestURL in requests ) {
|
||||
if ( requests.hasOwnProperty(requestURL) === false ) {
|
||||
var details, pos, result, hostname, domain;
|
||||
for ( var url in dict ) {
|
||||
if ( dict.hasOwnProperty(url) === false ) {
|
||||
continue;
|
||||
}
|
||||
details = requests[requestURL];
|
||||
details = dict[url].data;
|
||||
if ( typeof details !== 'string' ) {
|
||||
continue;
|
||||
}
|
||||
hasher.appendStr(requestURL);
|
||||
hasher.appendStr(details);
|
||||
pos = details.indexOf('\t');
|
||||
hostname = µburi.hostnameFromURI(requestURL);
|
||||
domain = µburi.domainFromHostname(hostname);
|
||||
if ( domain === '' ) {
|
||||
domain = hostname;
|
||||
result = details.slice(pos + 1);
|
||||
if ( wantBlocked !== pageStore.boolFromResult(result) ) {
|
||||
continue;
|
||||
}
|
||||
hasher.appendStr(url);
|
||||
hasher.appendStr(details);
|
||||
hostname = µburi.hostnameFromURI(url);
|
||||
domain = µburi.domainFromHostname(hostname) || hostname;
|
||||
r.push({
|
||||
type: details.slice(0, pos),
|
||||
domain: domain,
|
||||
url: requestURL,
|
||||
reason: details.slice(pos + 1)
|
||||
url: url,
|
||||
reason: result
|
||||
});
|
||||
}
|
||||
return r;
|
||||
};
|
||||
var hasher = new YaMD5();
|
||||
if ( µb.userSettings.logBlockedRequests ) {
|
||||
r.blockedRequests = prepareRequests(pageStore.blockedRequests, hasher);
|
||||
}
|
||||
if ( µb.userSettings.logAllowedRequests ) {
|
||||
r.allowedRequests = prepareRequests(pageStore.allowedRequests, hasher);
|
||||
if ( µb.userSettings.logRequests ) {
|
||||
r.blockedRequests = prepareRequests(true, hasher);
|
||||
r.allowedRequests = prepareRequests(false, hasher);
|
||||
}
|
||||
r.hash = hasher.end();
|
||||
return r;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
var µb = µBlock;
|
||||
|
||||
@ -472,6 +541,7 @@ var onMessage = function(request, sender, callback) {
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// about.js
|
||||
|
@ -50,6 +50,7 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var runtimeIdGenerator = 1;
|
||||
var nameToPortMap = {};
|
||||
var nameToListenerMap = {};
|
||||
var nullFunc = function(){};
|
||||
@ -58,7 +59,7 @@ var nullFunc = function(){};
|
||||
|
||||
var listenerNameFromPortName = function(portName) {
|
||||
var pos = portName.indexOf('/');
|
||||
if ( pos <= 0 ) {
|
||||
if ( pos === -1 ) {
|
||||
return '';
|
||||
}
|
||||
return portName.slice(0, pos);
|
||||
@ -213,14 +214,13 @@ var onDisconnect = function(port) {
|
||||
|
||||
var onConnect = function(port) {
|
||||
// We must have a port name.
|
||||
if ( !port.name ) {
|
||||
throw 'µBlock> messaging.js / onConnectHandler(): no port name!';
|
||||
if ( typeof port.name !== 'string' || port.name === '' ) {
|
||||
console.error('µBlock> messaging.js / onConnectHandler(): no port name!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Port should not already exist.
|
||||
if ( nameToPortMap[port.name] ) {
|
||||
throw 'µBlock> messaging.js / onConnectHandler(): port already exists!';
|
||||
}
|
||||
// Ensure port name is unique
|
||||
port.name += '/' + runtimeIdGenerator++;
|
||||
|
||||
nameToPortMap[port.name] = port;
|
||||
port.onMessage.addListener(onMessage);
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
|
||||
// fedcba9876543210
|
||||
// ||| | | |
|
||||
// ||| | | |
|
||||
@ -1023,7 +1025,7 @@ FilterParser.prototype.parseOptParty = function(not) {
|
||||
/******************************************************************************/
|
||||
|
||||
FilterParser.prototype.parseOptHostnames = function(raw) {
|
||||
var µburi = µBlock.URI;
|
||||
var µburi = µb.URI;
|
||||
var hostnames = raw.split('|');
|
||||
var hostname, not, domain;
|
||||
for ( var i = 0; i < hostnames.length; i++ ) {
|
||||
@ -1155,8 +1157,8 @@ FilterParser.prototype.parse = function(s) {
|
||||
var FilterContainer = function() {
|
||||
this.reAnyToken = /[%0-9a-z]+/g;
|
||||
this.buckets = new Array(8);
|
||||
this.blockedAnyPartyHostnames = new µBlock.LiquidDict();
|
||||
this.blocked3rdPartyHostnames = new µBlock.LiquidDict();
|
||||
this.blockedAnyPartyHostnames = new µb.LiquidDict();
|
||||
this.blocked3rdPartyHostnames = new µb.LiquidDict();
|
||||
this.filterParser = new FilterParser();
|
||||
this.noDomainBits = this.toDomainBits(noDomainName);
|
||||
this.reset();
|
||||
@ -1633,7 +1635,7 @@ FilterContainer.prototype.matchAnyPartyHostname = function(requestHostname) {
|
||||
return '||' + requestHostname + '^';
|
||||
}
|
||||
// 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++ ) {
|
||||
if ( this.blockedAnyPartyHostnames.test(hostnames[i]) ) {
|
||||
return '||' + hostnames[i] + '^';
|
||||
@ -1658,7 +1660,7 @@ FilterContainer.prototype.match3rdPartyHostname = function(requestHostname) {
|
||||
return '||' + requestHostname + '^$third-party';
|
||||
}
|
||||
// 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++ ) {
|
||||
if ( this.blocked3rdPartyHostnames.test(hostnames[i]) ) {
|
||||
return '||' + hostnames[i] + '^$third-party';
|
||||
@ -1675,9 +1677,10 @@ FilterContainer.prototype.match3rdPartyHostname = function(requestHostname) {
|
||||
// Some type of requests are exceptional, they need custom 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 pageDomain = pageDetails.pageDomain || '';
|
||||
var requestHostname = µb.URI.hostnameFromURI(requestURL);
|
||||
var party = requestHostname.slice(-pageDomain.length) === pageDomain ?
|
||||
FirstParty :
|
||||
ThirdParty;
|
||||
@ -1710,7 +1713,7 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
|
||||
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | type | this.noDomainBits)];
|
||||
bf = this.matchTokens(url);
|
||||
if ( bf === false ) {
|
||||
return false;
|
||||
return '';
|
||||
}
|
||||
|
||||
// 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
|
||||
// Convert url to lower case:
|
||||
// `match-case` option not supported, but then, I saw only one
|
||||
@ -1757,9 +1760,17 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
|
||||
// filter.
|
||||
|
||||
var pageDomain = pageDetails.pageDomain || '';
|
||||
var party = requestHostname.slice(-pageDomain.length) === pageDomain ?
|
||||
FirstParty :
|
||||
ThirdParty;
|
||||
var requestHostname = µb.URI.hostnameFromURI(requestURL);
|
||||
|
||||
// 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
|
||||
pageHostname = pageDetails.pageHostname || '';
|
||||
@ -1784,7 +1795,7 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
|
||||
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | Important | type | this.noDomainBits)];
|
||||
var bf = this.matchTokens(url);
|
||||
if ( bf !== false ) {
|
||||
return bf.toString();
|
||||
return bf.toString() + '$important';
|
||||
}
|
||||
|
||||
// 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 ( bf === false ) {
|
||||
return false;
|
||||
return '';
|
||||
}
|
||||
|
||||
// Test against allow filters
|
||||
|
307
js/pagestore.js
307
js/pagestore.js
@ -38,32 +38,180 @@ To create a log of net requests
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
var frameStoreJunkyard = [];
|
||||
var pageStoreJunkyard = [];
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// To mitigate memory churning
|
||||
var netFilteringResultCacheEntryJunkyard = [];
|
||||
var netFilteringResultCacheEntryJunkyardMax = 200;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var frameStoreFactory = function(frameURL) {
|
||||
var entry = frameStoreJunkyard.pop();
|
||||
if ( entry ) {
|
||||
return entry.init(frameURL);
|
||||
}
|
||||
return new FrameStore(frameURL);
|
||||
var NetFilteringResultCacheEntry = function(data) {
|
||||
this.init(data);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
@ -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) {
|
||||
var µburi = µb.URI;
|
||||
this.pageHostname = µburi.hostnameFromURI(frameURL);
|
||||
@ -83,18 +243,24 @@ FrameStore.prototype.init = function(frameURL) {
|
||||
|
||||
FrameStore.prototype.dispose = function() {
|
||||
this.pageHostname = this.pageDomain = '';
|
||||
return this;
|
||||
if ( frameStoreJunkyard.length < frameStoreJunkyardMax ) {
|
||||
frameStoreJunkyard.push(this);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
var pageStoreFactory = function(tabId, pageURL) {
|
||||
var entry = pageStoreJunkyard.pop();
|
||||
if ( entry ) {
|
||||
return entry.init(tabId, pageURL);
|
||||
}
|
||||
return new PageStore(tabId, pageURL);
|
||||
};
|
||||
// To mitigate memory churning
|
||||
var pageStoreJunkyard = [];
|
||||
var pageStoreJunkyardMax = 10;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// 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) {
|
||||
this.tabId = tabId;
|
||||
this.previousPageURL = '';
|
||||
@ -114,26 +292,33 @@ PageStore.prototype.init = function(tabId, pageURL) {
|
||||
// Use hostname if no domain can be extracted
|
||||
this.pageDomain = µb.URI.domainFromHostname(this.pageHostname) || this.pageHostname;
|
||||
|
||||
this.frames = disposeFrameStores(this.frames);
|
||||
this.frames = {};
|
||||
this.netFiltering = true;
|
||||
this.netFilteringReadTime = 0;
|
||||
this.perLoadBlockedRequestCount = 0;
|
||||
this.perLoadAllowedRequestCount = 0;
|
||||
this.blockedRequests = {};
|
||||
this.allowedRequests = {};
|
||||
this.disposeTime = 0;
|
||||
|
||||
this.netFilteringCache = NetFilteringResultCache.factory();
|
||||
if ( µb.userSettings.logRequests ) {
|
||||
this.netFilteringCache.shelfLife = 30 * 60 * 1000;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.reuse = function(pageURL) {
|
||||
this.disposeFrameStores();
|
||||
this.netFilteringCache = this.netFilteringCache.dispose();
|
||||
var previousPageURL = this.pageURL;
|
||||
this.init(this.tabId, pageURL);
|
||||
this.previousPageURL = previousPageURL;
|
||||
return this;
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=dltNSbOupgE
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.dispose = function() {
|
||||
@ -142,11 +327,30 @@ PageStore.prototype.dispose = function() {
|
||||
// sizeable enough chunks (especially requests, through the request URL
|
||||
// used as a key).
|
||||
this.pageURL = '';
|
||||
this.previousPageURL = '';
|
||||
this.pageHostname = '';
|
||||
this.pageDomain = '';
|
||||
if ( pageStoreJunkyard.length < 8 ) {
|
||||
this.disposeFrameStores();
|
||||
this.netFilteringCache = this.netFilteringCache.dispose();
|
||||
if ( pageStoreJunkyard.length < pageStoreJunkyardMax ) {
|
||||
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) {
|
||||
var frameStore = this.frames[frameId];
|
||||
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);
|
||||
}
|
||||
return frameStore;
|
||||
@ -178,35 +382,26 @@ PageStore.prototype.getNetFilteringSwitch = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.recordRequest = function(type, url, reason) {
|
||||
var blocked = reason !== false && reason.slice(0, 2) !== '@@';
|
||||
|
||||
if ( !blocked ) {
|
||||
this.perLoadAllowedRequestCount++;
|
||||
µb.localSettings.allowedRequestCount++;
|
||||
if ( µb.userSettings.logAllowedRequests ) {
|
||||
this.allowedRequests[url] = type + '\t' + (reason || '');
|
||||
}
|
||||
return;
|
||||
PageStore.prototype.filterRequest = function(context, requestType, requestURL) {
|
||||
var result = this.netFilteringCache.lookup(requestURL);
|
||||
if ( result !== undefined ) {
|
||||
return result.slice(result.indexOf('\t') + 1);
|
||||
}
|
||||
|
||||
µb.updateBadgeAsync(this.tabId);
|
||||
|
||||
this.perLoadBlockedRequestCount++;
|
||||
µ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;
|
||||
//console.debug('µBlock> PageStore.filterRequest(): "%s" not in cache', requestURL);
|
||||
result = µb.netFilteringEngine.matchString(context, requestURL, requestType);
|
||||
if ( collapsibleRequestTypes.indexOf(requestType) !== -1 || µb.userSettings.logRequests ) {
|
||||
this.netFilteringCache.add(requestURL, requestType + '\t' + result);
|
||||
}
|
||||
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 {
|
||||
factory: pageStoreFactory
|
||||
factory: PageStore.factory
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -59,7 +59,7 @@ var renderStats = function() {
|
||||
// - logging of requests enabled
|
||||
uDom('#gotoLog').toggleClass(
|
||||
'enabled',
|
||||
isHTTP && (stats.logBlockedRequests || stats.logAllowedRequests)
|
||||
isHTTP && stats.logRequests
|
||||
);
|
||||
|
||||
// Conditions for element picker:
|
||||
|
32
js/stats.js
32
js/stats.js
@ -31,27 +31,13 @@ messaging.start('stats.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var logBlockedSettingChanged = function() {
|
||||
var logSettingChanged = function() {
|
||||
messaging.tell({
|
||||
what: 'userSettings',
|
||||
name: 'logBlockedRequests',
|
||||
name: 'logRequests',
|
||||
value: this.checked
|
||||
});
|
||||
uDom('#requests table').toggleClass('hideBlocked', !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'));
|
||||
uDom('#requests').toggleClass('logEnabled', this.checked);
|
||||
renderPageSelector();
|
||||
};
|
||||
|
||||
@ -186,7 +172,7 @@ var pageSelectorChanged = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var renderPageSelector = function(targetTabId) {
|
||||
if ( !uDom('#logBlockedRequests').prop('checked') && !uDom('#logAllowedRequests').prop('checked') ) {
|
||||
if ( !uDom('#logRequests').prop('checked') ) {
|
||||
return;
|
||||
}
|
||||
var selectedTabId = targetTabId || parseInt(uDom('#pageSelector').val(), 10);
|
||||
@ -228,18 +214,14 @@ var renderPageSelector = function(targetTabId) {
|
||||
/******************************************************************************/
|
||||
|
||||
var onUserSettingsReceived = function(details) {
|
||||
uDom('#logBlockedRequests').prop('checked', details.logBlockedRequests);
|
||||
uDom('#logAllowedRequests').prop('checked', details.logAllowedRequests);
|
||||
uDom('#requests').toggleClass('logEnabled', details.logBlockedRequests || details.logAllowedRequests);
|
||||
uDom('#requests table').toggleClass('hideBlocked', !details.logBlockedRequests);
|
||||
uDom('#requests table').toggleClass('hideAllowed', !details.logAllowedRequests);
|
||||
uDom('#logRequests').prop('checked', details.logRequests);
|
||||
uDom('#requests').toggleClass('logEnabled', details.logRequests);
|
||||
|
||||
var matches = window.location.search.slice(1).match(/(?:^|&)which=(\d+)/);
|
||||
var tabId = matches && matches.length === 2 ? parseInt(matches[1], 10) : 0;
|
||||
renderPageSelector(tabId);
|
||||
|
||||
uDom('#logBlockedRequests').on('change', logBlockedSettingChanged);
|
||||
uDom('#logAllowedRequests').on('change', logAllowedSettingChanged);
|
||||
uDom('#logRequests').on('change', logSettingChanged);
|
||||
uDom('#refresh').on('click', function() { renderPageSelector(); });
|
||||
uDom('#pageSelector').on('change', pageSelectorChanged);
|
||||
};
|
||||
|
@ -114,7 +114,11 @@
|
||||
|
||||
µBlock.unbindTabFromPageStats = function(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];
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -51,7 +51,6 @@ var onBeforeRequest = function(details) {
|
||||
}
|
||||
|
||||
var µburi = µb.URI.set(requestURL);
|
||||
var requestHostname = µburi.hostname;
|
||||
var requestPath = µburi.path;
|
||||
|
||||
// rhill 2013-12-15:
|
||||
@ -78,31 +77,35 @@ var onBeforeRequest = function(details) {
|
||||
}
|
||||
}
|
||||
|
||||
var reason = false;
|
||||
var result = '';
|
||||
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?
|
||||
if ( reason === false || reason.slice(0, 2) === '@@' ) {
|
||||
//console.debug('µBlock> onBeforeRequest()> ALLOW "%s" (%o)', details.url, details);
|
||||
// Not blocked
|
||||
if ( pageStore.boolFromResult(result) === false ) {
|
||||
pageStore.perLoadAllowedRequestCount++;
|
||||
µb.localSettings.allowedRequestCount++;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/114
|
||||
if ( frameId > 0 && frameStore === undefined ) {
|
||||
pageStore.addFrame(frameId, requestURL);
|
||||
}
|
||||
|
||||
//console.debug('µBlock> onBeforeRequest()> ALLOW "%s" (%o)', details.url, details);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
//console.debug('µBlock> onBeforeRequest()> BLOCK "%s" (%o) because "%s"', details.url, details, result);
|
||||
return { 'cancel': true };
|
||||
};
|
||||
|
||||
@ -166,18 +169,13 @@ var onBeforeSendHeaders = function(details) {
|
||||
// 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
|
||||
// in multiple tabs.
|
||||
var reason = false;
|
||||
var result = '';
|
||||
if ( pageStore.getNetFilteringSwitch() ) {
|
||||
reason = µb.netFilteringEngine.matchStringExactType(
|
||||
pageDetails,
|
||||
requestURL,
|
||||
'popup',
|
||||
µburi.hostnameFromURI(requestURL)
|
||||
);
|
||||
result = µb.netFilteringEngine.matchStringExactType(pageDetails, requestURL, 'popup');
|
||||
}
|
||||
|
||||
// Not blocked?
|
||||
if ( reason === false || reason.slice(0, 2) === '@@' ) {
|
||||
if ( result === '' || result.slice(0, 2) === '@@' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
13
stats.html
13
stats.html
@ -70,12 +70,6 @@ tr.requestEntry td:nth-of-type(1) {
|
||||
tr.requestEntry td:nth-of-type(2) {
|
||||
text-align: right;
|
||||
}
|
||||
table.hideBlocked tr.logBlocked {
|
||||
display: none;
|
||||
}
|
||||
table.hideAllowed tr.logAllowed {
|
||||
display: none;
|
||||
}
|
||||
tr.logBlocked {
|
||||
background-color: #fff8f8;
|
||||
}
|
||||
@ -98,12 +92,9 @@ tr.logAllowed ~ tr td:nth-of-type(3) b {
|
||||
<body>
|
||||
|
||||
<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>
|
||||
<div class="whatisthis-expandable para" data-i18n="logBlockedRequestsHelp"></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>
|
||||
<div class="whatisthis-expandable para" data-i18n="logNetRequestsHelp"></div>
|
||||
</ul>
|
||||
|
||||
<div id="requests">
|
||||
|
Loading…
Reference in New Issue
Block a user