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

report active cosmetic filters in logger

This commit is contained in:
gorhill 2015-04-25 07:28:35 -04:00
parent bcbc06b2ff
commit 3d3bd13ea1
9 changed files with 284 additions and 106 deletions

View File

@ -70,6 +70,9 @@ body.colorBlind #content table tr.allowed {
#content table tr.maindoc { #content table tr.maindoc {
background-color: #eee; background-color: #eee;
} }
#content table tr.cosmetic {
background-color: rgba(255, 255, 0, 0.1)
}
body:not(.filterOff) #content table tr.hidden { body:not(.filterOff) #content table tr.hidden {
display: none; display: none;
} }

View File

@ -169,7 +169,7 @@ var uBlockCollapser = (function() {
} }
if ( selectors.length !== 0 ) { if ( selectors.length !== 0 ) {
messager.send({ messager.send({
what: 'injectedSelectors', what: 'cosmeticFiltersInjected',
type: 'net', type: 'net',
hostname: window.location.hostname, hostname: window.location.hostname,
selectors: selectors selectors: selectors
@ -385,7 +385,7 @@ var uBlockCollapser = (function() {
// - Injecting a style tag // - Injecting a style tag
var addStyleTag = function(selectors) { var addStyleTag = function(selectors) {
var selectorStr = selectors.toString(); var selectorStr = selectors.join(',\n');
var style = document.createElement('style'); var style = document.createElement('style');
// The linefeed before the style block is very important: do no remove! // The linefeed before the style block is very important: do no remove!
style.appendChild(document.createTextNode(selectorStr + '\n{display:none !important;}')); style.appendChild(document.createTextNode(selectorStr + '\n{display:none !important;}'));
@ -396,7 +396,7 @@ var uBlockCollapser = (function() {
} }
hideElements(selectorStr); hideElements(selectorStr);
messager.send({ messager.send({
what: 'injectedSelectors', what: 'cosmeticFiltersInjected',
type: 'cosmetic', type: 'cosmetic',
hostname: window.location.hostname, hostname: window.location.hostname,
selectors: selectors selectors: selectors

View File

@ -123,6 +123,8 @@ var netFilters = function(details) {
}; };
var filteringHandler = function(details) { var filteringHandler = function(details) {
var styleTagCount = vAPI.styles.length;
vAPI.skipCosmeticFiltering = !details || details.skipCosmeticFiltering; vAPI.skipCosmeticFiltering = !details || details.skipCosmeticFiltering;
if ( details ) { if ( details ) {
if ( details.cosmeticHide.length !== 0 || details.cosmeticDonthide.length !== 0 ) { if ( details.cosmeticHide.length !== 0 || details.cosmeticDonthide.length !== 0 ) {
@ -135,6 +137,12 @@ var filteringHandler = function(details) {
// the browser to flush this script from memory. // the browser to flush this script from memory.
} }
// This is just to inform the background process that cosmetic filters were
// actually injected.
if ( vAPI.styles.length !== styleTagCount ) {
localMessager.send({ what: 'cosmeticFiltersInjected' });
}
// https://github.com/chrisaljoudi/uBlock/issues/587 // https://github.com/chrisaljoudi/uBlock/issues/587
// If no filters were found, maybe the script was injected before uBlock's // If no filters were found, maybe the script was injected before uBlock's
// process was fully initialized. When this happens, pages won't be // process was fully initialized. When this happens, pages won't be

96
src/js/cosmetic-logger.js Normal file
View File

@ -0,0 +1,96 @@
/*******************************************************************************
uBlock - a browser extension to block requests.
Copyright (C) 2015 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
/* global vAPI, HTMLDocument */
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/464
if ( document instanceof HTMLDocument === false ) {
//console.debug('cosmetic-logger.js > not a HTLMDocument');
return;
}
// This can happen
if ( !vAPI ) {
//console.debug('cosmetic-logger.js > vAPI not found');
return;
}
/******************************************************************************/
var loggedSelectors = vAPI.loggedSelectors || {};
var injectedSelectors = [];
var reProperties = /\s*\{[^}]+\}\s*/;
var i;
var styles = vAPI.styles || [];
i = styles.length;
while ( i-- ) {
injectedSelectors = injectedSelectors.concat(styles[i].textContent.replace(reProperties, '').split(/\s*,\n\s*/));
}
if ( injectedSelectors.length === 0 ) {
return;
}
var matchedSelectors = [];
var selector;
i = injectedSelectors.length;
while ( i-- ) {
selector = injectedSelectors[i];
if ( loggedSelectors.hasOwnProperty(selector) ) {
continue;
}
loggedSelectors[selector] = true;
if ( document.querySelector(selector) === null ) {
continue;
}
matchedSelectors.push(selector);
}
vAPI.loggedSelectors = loggedSelectors;
/******************************************************************************/
var localMessager = vAPI.messaging.channel('cosmetic-*.js');
localMessager.send({
what: 'logCosmeticFilteringData',
pageURL: window.location.href,
matchedSelectors: matchedSelectors
}, function() {
localMessager.close();
});
/******************************************************************************/
})();
/******************************************************************************/

View File

@ -31,13 +31,13 @@
// https://github.com/gorhill/uBlock/issues/464 // https://github.com/gorhill/uBlock/issues/464
if ( document instanceof HTMLDocument === false ) { if ( document instanceof HTMLDocument === false ) {
//console.debug('cosmetic-on.js > not a HTLMDocument'); //console.debug('cosmetic-survey.js > not a HTLMDocument');
return; return;
} }
// This can happen // This can happen
if ( !vAPI ) { if ( !vAPI ) {
//console.debug('cosmetic-count.js > no vAPI'); //console.debug('cosmetic-survey.js > vAPI not found');
return; return;
} }
@ -45,23 +45,20 @@ if ( !vAPI ) {
// Insert all cosmetic filtering-related style tags in the DOM // Insert all cosmetic filtering-related style tags in the DOM
var selectors = []; var injectedSelectors = [];
var filteredElementCount = 0;
var reProperties = /\s*\{[^}]+\}\s*/; var reProperties = /\s*\{[^}]+\}\s*/;
var i; var i;
var styles = vAPI.styles || []; var styles = vAPI.styles || [];
i = styles.length; i = styles.length;
while ( i-- ) { while ( i-- ) {
selectors.push(styles[i].textContent.replace(reProperties, '')); injectedSelectors = injectedSelectors.concat(styles[i].textContent.replace(reProperties, '').split(/\s*,\n\s*/));
} }
var elems = []; if ( injectedSelectors.length !== 0 ) {
filteredElementCount = document.querySelectorAll(injectedSelectors.join(',')).length;
if ( selectors.length !== 0 ) {
try {
elems = document.querySelectorAll(selectors.join(','));
} catch (e) {
}
} }
/******************************************************************************/ /******************************************************************************/
@ -69,8 +66,10 @@ if ( selectors.length !== 0 ) {
var localMessager = vAPI.messaging.channel('cosmetic-*.js'); var localMessager = vAPI.messaging.channel('cosmetic-*.js');
localMessager.send({ localMessager.send({
what: 'hiddenElementCount', what: 'liveCosmeticFilteringData',
count: elems.length pageURL: window.location.href,
filteredElementCount: filteredElementCount,
injectedSelectors: injectedSelectors
}, function() { }, function() {
localMessager.close(); localMessager.close();
}); });

View File

@ -123,6 +123,12 @@ var createRow = function() {
var renderLogEntry = function(entry) { var renderLogEntry = function(entry) {
var tr = createRow(); var tr = createRow();
// Cosmetic filter?
if ( entry.result.charAt(0) === 'c' ) {
tr.classList.add('cosmetic');
}
if ( entry.result.charAt(1) === 'b' ) { if ( entry.result.charAt(1) === 'b' ) {
tr.classList.add('blocked'); tr.classList.add('blocked');
tr.cells[0].textContent = ' -\u00A0'; tr.cells[0].textContent = ' -\u00A0';
@ -135,13 +141,16 @@ var renderLogEntry = function(entry) {
} else { } else {
tr.cells[0].textContent = ''; tr.cells[0].textContent = '';
} }
if ( entry.type === 'main_frame' ) { if ( entry.type === 'main_frame' ) {
tr.classList.add('maindoc'); tr.classList.add('maindoc');
} }
var filterText = entry.result.slice(3); var filterText = entry.result.slice(3);
if ( entry.result.lastIndexOf('sa', 0) === 0 ) { if ( entry.result.lastIndexOf('sa', 0) === 0 ) {
filterText = '@@' + filterText; filterText = '@@' + filterText;
} }
tr.cells[1].textContent = filterText + '\t'; tr.cells[1].textContent = filterText + '\t';
tr.cells[2].textContent = (prettyRequestTypes[entry.type] || entry.type) + '\t'; tr.cells[2].textContent = (prettyRequestTypes[entry.type] || entry.type) + '\t';
vAPI.insertHTML(tr.cells[3], renderURL(entry.url, entry.result)); vAPI.insertHTML(tr.cells[3], renderURL(entry.url, entry.result));

View File

@ -152,7 +152,7 @@ var logBufferObsoleteAfter = 30 * 1000;
/******************************************************************************/ /******************************************************************************/
var loggerWriteOne = function(tabId, details, result) { var writeOne = function(tabId, details, result) {
if ( logBuffers.hasOwnProperty(tabId) === false ) { if ( logBuffers.hasOwnProperty(tabId) === false ) {
return; return;
} }
@ -162,7 +162,7 @@ var loggerWriteOne = function(tabId, details, result) {
/******************************************************************************/ /******************************************************************************/
var loggerReadAll = function(tabId) { var readAll = function(tabId) {
if ( logBuffers.hasOwnProperty(tabId) === false ) { if ( logBuffers.hasOwnProperty(tabId) === false ) {
logBuffers[tabId] = new LogBuffer(); logBuffers[tabId] = new LogBuffer();
} }
@ -171,6 +171,12 @@ var loggerReadAll = function(tabId) {
/******************************************************************************/ /******************************************************************************/
var isObserved = function(tabId) {
return logBuffers.hasOwnProperty(tabId);
};
/******************************************************************************/
var loggerJanitor = function() { var loggerJanitor = function() {
var logBuffer; var logBuffer;
var obsolete = Date.now() - logBufferObsoleteAfter; var obsolete = Date.now() - logBufferObsoleteAfter;
@ -195,8 +201,9 @@ setTimeout(loggerJanitor, loggerJanitorPeriod);
/******************************************************************************/ /******************************************************************************/
return { return {
writeOne: loggerWriteOne, writeOne: writeOne,
readAll: loggerReadAll readAll: readAll,
isObserved: isObserved
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -37,67 +37,80 @@ var onMessage = function(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
case 'getAssetContent': case 'getAssetContent':
// https://github.com/chrisaljoudi/uBlock/issues/417 // https://github.com/chrisaljoudi/uBlock/issues/417
µb.assets.get(request.url, callback); µb.assets.get(request.url, callback);
return; return;
case 'reloadAllFilters': case 'reloadAllFilters':
µb.reloadAllFilters(callback); µb.reloadAllFilters(callback);
return; return;
default: default:
break; break;
} }
var tabId = sender && sender.tab ? sender.tab.id : 0;
// Sync // Sync
var response; var response;
switch ( request.what ) { switch ( request.what ) {
case 'contextMenuEvent': case 'contextMenuEvent':
µb.contextMenuClientX = request.clientX; µb.contextMenuClientX = request.clientX;
µb.contextMenuClientY = request.clientY; µb.contextMenuClientY = request.clientY;
break; break;
case 'forceUpdateAssets': case 'cosmeticFiltersInjected':
µb.assetUpdater.force(); // Is this a request to cache selectors?
break; if ( Array.isArray(request.selectors) ) {
µb.cosmeticFilteringEngine.addToSelectorCache(request);
}
// Net-based cosmetic filters are of no interest for logging purpose.
if ( µb.logger.isObserved(tabId) && request.type !== 'net' ) {
µb.logCosmeticFilters(tabId);
}
break;
case 'getAppData': case 'forceUpdateAssets':
response = {name: vAPI.app.name, version: vAPI.app.version}; µb.assetUpdater.force();
break; break;
case 'getUserSettings': case 'getAppData':
response = µb.userSettings; response = {name: vAPI.app.name, version: vAPI.app.version};
break; break;
case 'gotoURL': case 'getUserSettings':
vAPI.tabs.open(request.details); response = µb.userSettings;
break; break;
case 'reloadTab': case 'gotoURL':
if ( vAPI.isBehindTheSceneTabId(request.tabId) === false ) { vAPI.tabs.open(request.details);
vAPI.tabs.reload(request.tabId); break;
if ( request.select && vAPI.tabs.select ) {
vAPI.tabs.select(request.tabId); case 'reloadTab':
} if ( vAPI.isBehindTheSceneTabId(request.tabId) === false ) {
vAPI.tabs.reload(request.tabId);
if ( request.select && vAPI.tabs.select ) {
vAPI.tabs.select(request.tabId);
} }
break; }
break;
case 'selectFilterLists': case 'selectFilterLists':
µb.selectFilterLists(request.switches); µb.selectFilterLists(request.switches);
break; break;
case 'toggleHostnameSwitch': case 'toggleHostnameSwitch':
µb.toggleHostnameSwitch(request); µb.toggleHostnameSwitch(request);
break; break;
case 'userSettings': case 'userSettings':
response = µb.changeUserSettings(request.name, request.value); response = µb.changeUserSettings(request.name, request.value);
break; break;
default: default:
return vAPI.messaging.UNHANDLED; return vAPI.messaging.UNHANDLED;
} }
callback(response); callback(response);
@ -296,7 +309,7 @@ var getPopupDataLazy = function(tabId, callback) {
return; return;
} }
µb.getHiddenElementCount(tabId, function() { µb.surveyCosmeticFilters(tabId, function() {
r.hiddenElementCount = pageStore.hiddenElementCount; r.hiddenElementCount = pageStore.hiddenElementCount;
callback(r); callback(r);
}); });
@ -497,11 +510,11 @@ var filterRequests = function(pageStore, details) {
/******************************************************************************/ /******************************************************************************/
var onMessage = function(details, sender, callback) { var onMessage = function(request, sender, callback) {
// Async // Async
switch ( details.what ) { switch ( request.what ) {
default: default:
break; break;
} }
// Sync // Sync
@ -512,33 +525,29 @@ var onMessage = function(details, sender, callback) {
pageStore = µb.pageStoreFromTabId(sender.tab.id); pageStore = µb.pageStoreFromTabId(sender.tab.id);
} }
switch ( details.what ) { switch ( request.what ) {
case 'retrieveGenericCosmeticSelectors': case 'retrieveGenericCosmeticSelectors':
response = { response = {
shutdown: !pageStore || !pageStore.getNetFilteringSwitch(), shutdown: !pageStore || !pageStore.getNetFilteringSwitch(),
result: null result: null
}; };
if ( !response.shutdown && pageStore.getGenericCosmeticFilteringSwitch() ) { if ( !response.shutdown && pageStore.getGenericCosmeticFilteringSwitch() ) {
response.result = µb.cosmeticFilteringEngine.retrieveGenericSelectors(details); response.result = µb.cosmeticFilteringEngine.retrieveGenericSelectors(request);
} }
break; break;
case 'injectedSelectors': case 'filterRequests':
µb.cosmeticFilteringEngine.addToSelectorCache(details); response = {
break; shutdown: !pageStore || !pageStore.getNetFilteringSwitch(),
result: null
};
if ( !response.shutdown ) {
response.result = filterRequests(pageStore, request);
}
break;
case 'filterRequests': default:
response = { return vAPI.messaging.UNHANDLED;
shutdown: !pageStore || !pageStore.getNetFilteringSwitch(),
result: null
};
if ( !response.shutdown ) {
response.result = filterRequests(pageStore, details);
}
break;
default:
return vAPI.messaging.UNHANDLED;
} }
callback(response); callback(response);
@ -565,6 +574,28 @@ var µb = µBlock;
/******************************************************************************/ /******************************************************************************/
var logCosmeticFilters = function(tabId, details) {
if ( µb.logger.isObserved(tabId) === false ) {
return;
}
var context = {
requestURL: '',
requestHostname: µb.URI.hostnameFromURI(details.pageURL),
requestType: 'dom'
};
var selectors = details.matchedSelectors;
selectors.sort();
for ( var i = 0; i < selectors.length; i++ ) {
µb.logger.writeOne(tabId, context, 'cb:##' + selectors[i]);
}
};
/******************************************************************************/
var onMessage = function(request, sender, callback) { var onMessage = function(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
@ -575,20 +606,22 @@ var onMessage = function(request, sender, callback) {
// Sync // Sync
var response; var response;
var pageStore; var tabId = sender && sender.tab ? sender.tab.id : 0;
if ( sender && sender.tab ) {
pageStore = µb.pageStoreFromTabId(sender.tab.id);
}
switch ( request.what ) { switch ( request.what ) {
case 'hiddenElementCount': case 'liveCosmeticFilteringData':
if ( pageStore ) { var pageStore = µb.pageStoreFromTabId(tabId);
pageStore.hiddenElementCount = request.count; if ( pageStore ) {
} pageStore.hiddenElementCount = request.filteredElementCount;
break; }
break;
default: case 'logCosmeticFilteringData':
return vAPI.messaging.UNHANDLED; logCosmeticFilters(tabId, request);
break;
default:
return vAPI.messaging.UNHANDLED;
} }
callback(response); callback(response);

View File

@ -338,15 +338,38 @@ var matchWhitelistDirective = function(url, hostname, directive) {
/******************************************************************************/ /******************************************************************************/
µBlock.getHiddenElementCount = function(tabId, callback) { µBlock.surveyCosmeticFilters = function(tabId, callback) {
callback = callback || this.noopFunc; callback = callback || this.noopFunc;
if ( vAPI.isBehindTheSceneTabId(tabId) ) { if ( vAPI.isBehindTheSceneTabId(tabId) ) {
callback(); callback();
return; return;
} }
vAPI.tabs.injectScript(tabId, { file: 'js/cosmetic-count.js' }, callback); vAPI.tabs.injectScript(tabId, { file: 'js/cosmetic-survey.js' }, callback);
}; };
/******************************************************************************/ /******************************************************************************/
µBlock.logCosmeticFilters = (function() {
var tabIdToTimerMap = {};
var injectNow = function(tabId) {
delete tabIdToTimerMap[tabId];
vAPI.tabs.injectScript(tabId, { file: 'js/cosmetic-logger.js' });
};
var injectAsync = function(tabId) {
if ( tabIdToTimerMap.hasOwnProperty(tabId) ) {
return;
}
tabIdToTimerMap[tabId] = setTimeout(
injectNow.bind(null, tabId),
100
);
};
return injectAsync;
})();
/******************************************************************************/
})(); })();