mirror of https://github.com/gorhill/uBlock.git
Rewrite logger's "exceptor" feature
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1861 The "exceptor" feature has been rewritten, with the following changes as a result: - The excepted filters cease to exist when closing the logger - It's now possible to temporary except network filters When toggling on/off a temporary exception, filter lists are now fully reloaded. This simplified managing temporary exceptions, and made it easy to implement temporary exception for network filters, but this also means there might be a perceptible delay when adding/removing temporary exceptions. At this point I consider this an acceptable side-effect just to bring the ability to easily create temporary exception for network filters, while this simplified the existing temporary exception code throughout.
This commit is contained in:
parent
ce3f852bad
commit
a91781a495
|
@ -919,6 +919,9 @@ vAPI.messaging = {
|
||||||
this.onPortDisconnect(port);
|
this.onPortDisconnect(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( this.defaultHandler ) {
|
||||||
|
this.defaultHandler(message, null, ( ) => { });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFrameworkMessage: function(request, port, callback) {
|
onFrameworkMessage: function(request, port, callback) {
|
||||||
|
|
|
@ -678,6 +678,9 @@ body[dir="rtl"] #netFilteringDialog > .panes > .details > div > span:nth-of-type
|
||||||
background-color: rgb(var(--primary-50) / 50%);
|
background-color: rgb(var(--primary-50) / 50%);
|
||||||
}
|
}
|
||||||
#netFilteringDialog > .panes > .details .exceptor::before {
|
#netFilteringDialog > .panes > .details .exceptor::before {
|
||||||
|
content: '@@';
|
||||||
|
}
|
||||||
|
#netFilteringDialog.extendedRealm > .panes > .details .exceptor::before {
|
||||||
content: '#@#';
|
content: '#@#';
|
||||||
}
|
}
|
||||||
#netFilteringDialog > div.panes > .dynamic > .toolbar {
|
#netFilteringDialog > div.panes > .dynamic > .toolbar {
|
||||||
|
|
|
@ -211,6 +211,9 @@ const µBlock = { // jshint ignore:line
|
||||||
availableFilterLists: {},
|
availableFilterLists: {},
|
||||||
badLists: new Map(),
|
badLists: new Map(),
|
||||||
|
|
||||||
|
inMemoryFilters: [],
|
||||||
|
inMemoryFiltersCompiled: '',
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/974
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/974
|
||||||
// This can be used to defer filtering decision-making.
|
// This can be used to defer filtering decision-making.
|
||||||
readyToFilter: false,
|
readyToFilter: false,
|
||||||
|
|
|
@ -27,10 +27,7 @@ import './utils.js';
|
||||||
import logger from './logger.js';
|
import logger from './logger.js';
|
||||||
import µb from './background.js';
|
import µb from './background.js';
|
||||||
|
|
||||||
import {
|
import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
|
||||||
StaticExtFilteringHostnameDB,
|
|
||||||
StaticExtFilteringSessionDB,
|
|
||||||
} from './static-ext-filtering-db.js';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -236,10 +233,7 @@ const FilterContainer = function() {
|
||||||
// specific filters
|
// specific filters
|
||||||
this.specificFilters = new StaticExtFilteringHostnameDB(2);
|
this.specificFilters = new StaticExtFilteringHostnameDB(2);
|
||||||
|
|
||||||
// temporary filters
|
// low generic cosmetic filters: map of hash => stringified selector list
|
||||||
this.sessionFilterDB = new StaticExtFilteringSessionDB();
|
|
||||||
|
|
||||||
// low generic cosmetic filters: map of hash => array of selectors
|
|
||||||
this.lowlyGeneric = new Map();
|
this.lowlyGeneric = new Map();
|
||||||
|
|
||||||
// highly generic selectors sets
|
// highly generic selectors sets
|
||||||
|
@ -478,15 +472,6 @@ FilterContainer.prototype.compileSpecificSelector = function(
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.compileTemporary = function(parser) {
|
|
||||||
return {
|
|
||||||
session: this.sessionFilterDB,
|
|
||||||
selector: parser.result.compiled,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
FilterContainer.prototype.fromCompiledContent = function(reader, options) {
|
FilterContainer.prototype.fromCompiledContent = function(reader, options) {
|
||||||
if ( options.skipCosmetic ) {
|
if ( options.skipCosmetic ) {
|
||||||
this.skipCompiledContent(reader, 'SPECIFIC');
|
this.skipCompiledContent(reader, 'SPECIFIC');
|
||||||
|
@ -697,12 +682,6 @@ FilterContainer.prototype.disableSurveyor = function(details) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.getSession = function() {
|
|
||||||
return this.sessionFilterDB;
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
FilterContainer.prototype.cssRuleFromProcedural = function(json) {
|
FilterContainer.prototype.cssRuleFromProcedural = function(json) {
|
||||||
const pfilter = JSON.parse(json);
|
const pfilter = JSON.parse(json);
|
||||||
if ( pfilter.cssable !== true ) { return; }
|
if ( pfilter.cssable !== true ) { return; }
|
||||||
|
@ -831,11 +810,6 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve temporary filters
|
|
||||||
if ( this.sessionFilterDB.isNotEmpty ) {
|
|
||||||
this.sessionFilterDB.retrieve([ null, exceptionSet ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve filters with a non-empty hostname
|
// Retrieve filters with a non-empty hostname
|
||||||
this.specificFilters.retrieve(
|
this.specificFilters.retrieve(
|
||||||
hostname,
|
hostname,
|
||||||
|
|
|
@ -27,10 +27,7 @@ import logger from './logger.js';
|
||||||
import µb from './background.js';
|
import µb from './background.js';
|
||||||
import { sessionFirewall } from './filtering-engines.js';
|
import { sessionFirewall } from './filtering-engines.js';
|
||||||
|
|
||||||
import {
|
import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
|
||||||
StaticExtFilteringHostnameDB,
|
|
||||||
StaticExtFilteringSessionDB,
|
|
||||||
} from './static-ext-filtering-db.js';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -38,7 +35,6 @@ const pselectors = new Map();
|
||||||
const duplicates = new Set();
|
const duplicates = new Set();
|
||||||
|
|
||||||
const filterDB = new StaticExtFilteringHostnameDB(2);
|
const filterDB = new StaticExtFilteringHostnameDB(2);
|
||||||
const sessionFilterDB = new StaticExtFilteringSessionDB();
|
|
||||||
|
|
||||||
let acceptedCount = 0;
|
let acceptedCount = 0;
|
||||||
let discardedCount = 0;
|
let discardedCount = 0;
|
||||||
|
@ -347,13 +343,6 @@ htmlFilteringEngine.compile = function(parser, writer) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
htmlFilteringEngine.compileTemporary = function(parser) {
|
|
||||||
return {
|
|
||||||
session: sessionFilterDB,
|
|
||||||
selector: parser.result.compiled,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
htmlFilteringEngine.fromCompiledContent = function(reader) {
|
htmlFilteringEngine.fromCompiledContent = function(reader) {
|
||||||
// Don't bother loading filters if stream filtering is not supported.
|
// Don't bother loading filters if stream filtering is not supported.
|
||||||
if ( µb.canFilterResponseData === false ) { return; }
|
if ( µb.canFilterResponseData === false ) { return; }
|
||||||
|
@ -373,10 +362,6 @@ htmlFilteringEngine.fromCompiledContent = function(reader) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
htmlFilteringEngine.getSession = function() {
|
|
||||||
return sessionFilterDB;
|
|
||||||
};
|
|
||||||
|
|
||||||
htmlFilteringEngine.retrieve = function(details) {
|
htmlFilteringEngine.retrieve = function(details) {
|
||||||
const hostname = details.hostname;
|
const hostname = details.hostname;
|
||||||
|
|
||||||
|
@ -384,9 +369,6 @@ htmlFilteringEngine.retrieve = function(details) {
|
||||||
const procedurals = new Set();
|
const procedurals = new Set();
|
||||||
const exceptions = new Set();
|
const exceptions = new Set();
|
||||||
|
|
||||||
if ( sessionFilterDB.isNotEmpty ) {
|
|
||||||
sessionFilterDB.retrieve([ null, exceptions ]);
|
|
||||||
}
|
|
||||||
filterDB.retrieve(
|
filterDB.retrieve(
|
||||||
hostname,
|
hostname,
|
||||||
[ plains, exceptions, procedurals, exceptions ]
|
[ plains, exceptions, procedurals, exceptions ]
|
||||||
|
|
|
@ -28,16 +28,12 @@ import µb from './background.js';
|
||||||
import { entityFromDomain } from './uri-utils.js';
|
import { entityFromDomain } from './uri-utils.js';
|
||||||
import { sessionFirewall } from './filtering-engines.js';
|
import { sessionFirewall } from './filtering-engines.js';
|
||||||
|
|
||||||
import {
|
import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
|
||||||
StaticExtFilteringHostnameDB,
|
|
||||||
StaticExtFilteringSessionDB,
|
|
||||||
} from './static-ext-filtering-db.js';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const duplicates = new Set();
|
const duplicates = new Set();
|
||||||
const filterDB = new StaticExtFilteringHostnameDB(1);
|
const filterDB = new StaticExtFilteringHostnameDB(1);
|
||||||
const sessionFilterDB = new StaticExtFilteringSessionDB();
|
|
||||||
|
|
||||||
const $headers = new Set();
|
const $headers = new Set();
|
||||||
const $exceptions = new Set();
|
const $exceptions = new Set();
|
||||||
|
@ -123,13 +119,6 @@ httpheaderFilteringEngine.compile = function(parser, writer) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
httpheaderFilteringEngine.compileTemporary = function(parser) {
|
|
||||||
return {
|
|
||||||
session: sessionFilterDB,
|
|
||||||
selector: parser.result.compiled.slice(15, -1),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 01234567890123456789
|
// 01234567890123456789
|
||||||
// responseheader(name)
|
// responseheader(name)
|
||||||
// ^ ^
|
// ^ ^
|
||||||
|
@ -152,10 +141,6 @@ httpheaderFilteringEngine.fromCompiledContent = function(reader) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
httpheaderFilteringEngine.getSession = function() {
|
|
||||||
return sessionFilterDB;
|
|
||||||
};
|
|
||||||
|
|
||||||
httpheaderFilteringEngine.apply = function(fctxt, headers) {
|
httpheaderFilteringEngine.apply = function(fctxt, headers) {
|
||||||
if ( filterDB.size === 0 ) { return; }
|
if ( filterDB.size === 0 ) { return; }
|
||||||
|
|
||||||
|
@ -173,9 +158,6 @@ httpheaderFilteringEngine.apply = function(fctxt, headers) {
|
||||||
$headers.clear();
|
$headers.clear();
|
||||||
$exceptions.clear();
|
$exceptions.clear();
|
||||||
|
|
||||||
if ( sessionFilterDB.isNotEmpty ) {
|
|
||||||
sessionFilterDB.retrieve([ null, $exceptions ]);
|
|
||||||
}
|
|
||||||
filterDB.retrieve(hostname, [ $headers, $exceptions ]);
|
filterDB.retrieve(hostname, [ $headers, $exceptions ]);
|
||||||
filterDB.retrieve(entity, [ $headers, $exceptions ], 1);
|
filterDB.retrieve(entity, [ $headers, $exceptions ], 1);
|
||||||
if ( $headers.size === 0 ) { return; }
|
if ( $headers.size === 0 ) { return; }
|
||||||
|
|
|
@ -1246,9 +1246,13 @@ const reloadTab = function(ev) {
|
||||||
// Toggle temporary exception filter
|
// Toggle temporary exception filter
|
||||||
if ( tcl.contains('exceptor') ) {
|
if ( tcl.contains('exceptor') ) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
const filter = filterFromTargetRow();
|
||||||
|
const exceptedFilter = dom.cl.has(targetRow, 'extendedRealm')
|
||||||
|
? `#@#${filter.replace(/^.*?#@?#/, '')}`
|
||||||
|
: `@@${filter.replace(/^@@/, '')}`;
|
||||||
const status = await messaging.send('loggerUI', {
|
const status = await messaging.send('loggerUI', {
|
||||||
what: 'toggleTemporaryException',
|
what: 'toggleInMemoryFilter',
|
||||||
filter: filterFromTargetRow(),
|
filter: exceptedFilter,
|
||||||
});
|
});
|
||||||
const row = target.closest('div');
|
const row = target.closest('div');
|
||||||
dom.cl.toggle(row, 'exceptored', status);
|
dom.cl.toggle(row, 'exceptored', status);
|
||||||
|
@ -1477,26 +1481,16 @@ const reloadTab = function(ev) {
|
||||||
const toSummaryPaneFilterNode = async function(receiver, filter) {
|
const toSummaryPaneFilterNode = async function(receiver, filter) {
|
||||||
receiver.children[1].textContent = filter;
|
receiver.children[1].textContent = filter;
|
||||||
if ( filterAuthorMode !== true ) { return; }
|
if ( filterAuthorMode !== true ) { return; }
|
||||||
const match = /#@?#/.exec(filter);
|
if ( dom.cl.has(targetRow, 'canLookup') === false ) { return; }
|
||||||
if ( match === null ) { return; }
|
const exceptedFilter = dom.cl.has(targetRow, 'extendedRealm')
|
||||||
const fragment = document.createDocumentFragment();
|
? `#@#${filter.replace(/^.*?#@?#/, '')}`
|
||||||
const pos = match.index + match[0].length;
|
: `@@${filter.replace(/^@@/, '')}`;
|
||||||
fragment.appendChild(document.createTextNode(filter.slice(0, pos)));
|
|
||||||
const selector = filter.slice(pos);
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.className = 'filter';
|
|
||||||
span.textContent = selector;
|
|
||||||
fragment.appendChild(span);
|
|
||||||
const isTemporaryException = await messaging.send('loggerUI', {
|
const isTemporaryException = await messaging.send('loggerUI', {
|
||||||
what: 'hasTemporaryException',
|
what: 'hasInMemoryFilter',
|
||||||
filter,
|
filter: exceptedFilter,
|
||||||
});
|
});
|
||||||
dom.cl.toggle(receiver, 'exceptored', isTemporaryException);
|
dom.cl.toggle(receiver, 'exceptored', isTemporaryException);
|
||||||
if ( match[0] === '##' || isTemporaryException ) {
|
receiver.children[2].style.visibility = '';
|
||||||
receiver.children[2].style.visibility = '';
|
|
||||||
}
|
|
||||||
receiver.children[1].textContent = '';
|
|
||||||
receiver.children[1].appendChild(fragment);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fillSummaryPaneFilterList = async function(rows) {
|
const fillSummaryPaneFilterList = async function(rows) {
|
||||||
|
|
|
@ -32,19 +32,15 @@ let writePtr = 0;
|
||||||
const logBufferObsoleteAfter = 30 * 1000;
|
const logBufferObsoleteAfter = 30 * 1000;
|
||||||
|
|
||||||
const janitor = ( ) => {
|
const janitor = ( ) => {
|
||||||
if (
|
if ( buffer === null ) { return; }
|
||||||
buffer !== null &&
|
if ( lastReadTime >= (Date.now() - logBufferObsoleteAfter) ) {
|
||||||
lastReadTime < (Date.now() - logBufferObsoleteAfter)
|
return vAPI.setTimeout(janitor, logBufferObsoleteAfter);
|
||||||
) {
|
|
||||||
logger.enabled = false;
|
|
||||||
buffer = null;
|
|
||||||
writePtr = 0;
|
|
||||||
logger.ownerId = undefined;
|
|
||||||
vAPI.messaging.broadcast({ what: 'loggerDisabled' });
|
|
||||||
}
|
|
||||||
if ( buffer !== null ) {
|
|
||||||
vAPI.setTimeout(janitor, logBufferObsoleteAfter);
|
|
||||||
}
|
}
|
||||||
|
logger.enabled = false;
|
||||||
|
buffer = null;
|
||||||
|
writePtr = 0;
|
||||||
|
logger.ownerId = undefined;
|
||||||
|
vAPI.messaging.broadcast({ what: 'loggerDisabled' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const boxEntry = function(details) {
|
const boxEntry = function(details) {
|
||||||
|
|
|
@ -35,7 +35,6 @@ import logger from './logger.js';
|
||||||
import lz4Codec from './lz4.js';
|
import lz4Codec from './lz4.js';
|
||||||
import io from './assets.js';
|
import io from './assets.js';
|
||||||
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
||||||
import staticExtFilteringEngine from './static-ext-filtering.js';
|
|
||||||
import staticFilteringReverseLookup from './reverselookup.js';
|
import staticFilteringReverseLookup from './reverselookup.js';
|
||||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||||
import µb from './background.js';
|
import µb from './background.js';
|
||||||
|
@ -305,6 +304,10 @@ const onMessage = function(request, sender, callback) {
|
||||||
µb.elementPickerExec(request.tabId, 0, request.targetURL, request.zap);
|
µb.elementPickerExec(request.tabId, 0, request.targetURL, request.zap);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'loggerDisabled':
|
||||||
|
µb.clearInMemoryFilters();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'gotoURL':
|
case 'gotoURL':
|
||||||
µb.openNewTab(request.details);
|
µb.openNewTab(request.details);
|
||||||
break;
|
break;
|
||||||
|
@ -1680,42 +1683,11 @@ const getURLFilteringData = function(details) {
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
const compileTemporaryException = function(filter) {
|
|
||||||
const parser = new StaticFilteringParser({
|
|
||||||
nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'),
|
|
||||||
});
|
|
||||||
parser.analyze(filter);
|
|
||||||
if ( parser.shouldDiscard() ) { return; }
|
|
||||||
return staticExtFilteringEngine.compileTemporary(parser);
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleTemporaryException = function(details) {
|
|
||||||
const result = compileTemporaryException(details.filter);
|
|
||||||
if ( result === undefined ) { return false; }
|
|
||||||
const { session, selector } = result;
|
|
||||||
if ( session.has(1, selector) ) {
|
|
||||||
session.remove(1, selector);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
session.add(1, selector);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasTemporaryException = function(details) {
|
|
||||||
const result = compileTemporaryException(details.filter);
|
|
||||||
if ( result === undefined ) { return false; }
|
|
||||||
const { session, selector } = result;
|
|
||||||
return session && session.has(1, selector);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMessage = function(request, sender, callback) {
|
const onMessage = function(request, sender, callback) {
|
||||||
// Async
|
// Async
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'readAll':
|
case 'readAll':
|
||||||
if (
|
if ( logger.ownerId !== undefined && logger.ownerId !== request.ownerId ) {
|
||||||
logger.ownerId !== undefined &&
|
|
||||||
logger.ownerId !== request.ownerId
|
|
||||||
) {
|
|
||||||
return callback({ unavailable: true });
|
return callback({ unavailable: true });
|
||||||
}
|
}
|
||||||
vAPI.tabs.getCurrent().then(tab => {
|
vAPI.tabs.getCurrent().then(tab => {
|
||||||
|
@ -1723,6 +1695,13 @@ const onMessage = function(request, sender, callback) {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 'toggleInMemoryFilter': {
|
||||||
|
const promise = µb.hasInMemoryFilter(request.filter)
|
||||||
|
? µb.removeInMemoryFilter(request.filter)
|
||||||
|
: µb.addInMemoryFilter(request.filter);
|
||||||
|
promise.then(status => { callback(status); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1731,14 +1710,14 @@ const onMessage = function(request, sender, callback) {
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'hasTemporaryException':
|
case 'hasInMemoryFilter':
|
||||||
response = hasTemporaryException(request);
|
response = µb.hasInMemoryFilter(request.filter);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'releaseView':
|
case 'releaseView':
|
||||||
if ( request.ownerId === logger.ownerId ) {
|
if ( request.ownerId !== logger.ownerId ) { break; }
|
||||||
logger.ownerId = undefined;
|
logger.ownerId = undefined;
|
||||||
}
|
µb.clearInMemoryFilters();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'saveURLFilteringRules':
|
case 'saveURLFilteringRules':
|
||||||
|
@ -1761,10 +1740,6 @@ const onMessage = function(request, sender, callback) {
|
||||||
response = getURLFilteringData(request);
|
response = getURLFilteringData(request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'toggleTemporaryException':
|
|
||||||
response = toggleTemporaryException(request);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return vAPI.messaging.UNHANDLED;
|
return vAPI.messaging.UNHANDLED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,7 @@ import µb from './background.js';
|
||||||
import { redirectEngine } from './redirect-engine.js';
|
import { redirectEngine } from './redirect-engine.js';
|
||||||
import { sessionFirewall } from './filtering-engines.js';
|
import { sessionFirewall } from './filtering-engines.js';
|
||||||
|
|
||||||
import {
|
import { StaticExtFilteringHostnameDB } from './static-ext-filtering-db.js';
|
||||||
StaticExtFilteringHostnameDB,
|
|
||||||
StaticExtFilteringSessionDB,
|
|
||||||
} from './static-ext-filtering-db.js';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
domainFromHostname,
|
domainFromHostname,
|
||||||
|
@ -46,7 +43,6 @@ const scriptletCache = new µb.MRUCache(32);
|
||||||
const reEscapeScriptArg = /[\\'"]/g;
|
const reEscapeScriptArg = /[\\'"]/g;
|
||||||
|
|
||||||
const scriptletDB = new StaticExtFilteringHostnameDB(1);
|
const scriptletDB = new StaticExtFilteringHostnameDB(1);
|
||||||
const sessionScriptletDB = new StaticExtFilteringSessionDB();
|
|
||||||
|
|
||||||
let acceptedCount = 0;
|
let acceptedCount = 0;
|
||||||
let discardedCount = 0;
|
let discardedCount = 0;
|
||||||
|
@ -262,13 +258,6 @@ scriptletFilteringEngine.compile = function(parser, writer) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scriptletFilteringEngine.compileTemporary = function(parser) {
|
|
||||||
return {
|
|
||||||
session: sessionScriptletDB,
|
|
||||||
selector: parser.result.compiled,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 01234567890123456789
|
// 01234567890123456789
|
||||||
// +js(token[, arg[, ...]])
|
// +js(token[, arg[, ...]])
|
||||||
// ^ ^
|
// ^ ^
|
||||||
|
@ -291,10 +280,6 @@ scriptletFilteringEngine.fromCompiledContent = function(reader) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scriptletFilteringEngine.getSession = function() {
|
|
||||||
return sessionScriptletDB;
|
|
||||||
};
|
|
||||||
|
|
||||||
const $scriptlets = new Set();
|
const $scriptlets = new Set();
|
||||||
const $exceptions = new Set();
|
const $exceptions = new Set();
|
||||||
const $scriptletToCodeMap = new Map();
|
const $scriptletToCodeMap = new Map();
|
||||||
|
@ -307,9 +292,6 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) {
|
||||||
$scriptlets.clear();
|
$scriptlets.clear();
|
||||||
$exceptions.clear();
|
$exceptions.clear();
|
||||||
|
|
||||||
if ( sessionScriptletDB.isNotEmpty ) {
|
|
||||||
sessionScriptletDB.retrieve([ null, $exceptions ]);
|
|
||||||
}
|
|
||||||
scriptletDB.retrieve(hostname, [ $scriptlets, $exceptions ]);
|
scriptletDB.retrieve(hostname, [ $scriptlets, $exceptions ]);
|
||||||
const entity = request.entity !== ''
|
const entity = request.entity !== ''
|
||||||
? `${hostname.slice(0, -request.domain.length)}${request.entity}`
|
? `${hostname.slice(0, -request.domain.length)}${request.entity}`
|
||||||
|
|
|
@ -170,55 +170,8 @@ const StaticExtFilteringHostnameDB = class {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const StaticExtFilteringSessionDB = class {
|
|
||||||
constructor() {
|
|
||||||
this.db = new Map();
|
|
||||||
}
|
|
||||||
compile(s) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
add(bits, s) {
|
|
||||||
const bucket = this.db.get(bits);
|
|
||||||
if ( bucket === undefined ) {
|
|
||||||
this.db.set(bits, new Set([ s ]));
|
|
||||||
} else {
|
|
||||||
bucket.add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
remove(bits, s) {
|
|
||||||
const bucket = this.db.get(bits);
|
|
||||||
if ( bucket === undefined ) { return; }
|
|
||||||
bucket.delete(s);
|
|
||||||
if ( bucket.size !== 0 ) { return; }
|
|
||||||
this.db.delete(bits);
|
|
||||||
}
|
|
||||||
retrieve(out) {
|
|
||||||
const mask = out.length - 1;
|
|
||||||
for ( const [ bits, bucket ] of this.db ) {
|
|
||||||
const i = bits & mask;
|
|
||||||
if ( out[i] instanceof Object === false ) { continue; }
|
|
||||||
for ( const s of bucket ) {
|
|
||||||
out[i].add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
has(bits, s) {
|
|
||||||
const selectors = this.db.get(bits);
|
|
||||||
return selectors !== undefined && selectors.has(s);
|
|
||||||
}
|
|
||||||
clear() {
|
|
||||||
this.db.clear();
|
|
||||||
}
|
|
||||||
get isNotEmpty() {
|
|
||||||
return this.db.size !== 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
StaticExtFilteringHostnameDB,
|
StaticExtFilteringHostnameDB,
|
||||||
StaticExtFilteringSessionDB,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -132,19 +132,6 @@ staticExtFilteringEngine.compile = function(parser, writer) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
staticExtFilteringEngine.compileTemporary = function(parser) {
|
|
||||||
if ( (parser.flavorBits & parser.BITFlavorExtScriptlet) !== 0 ) {
|
|
||||||
return scriptletFilteringEngine.compileTemporary(parser);
|
|
||||||
}
|
|
||||||
if ( (parser.flavorBits & parser.BITFlavorExtResponseHeader) !== 0 ) {
|
|
||||||
return httpheaderFilteringEngine.compileTemporary(parser);
|
|
||||||
}
|
|
||||||
if ( (parser.flavorBits & parser.BITFlavorExtHTML) !== 0 ) {
|
|
||||||
return htmlFilteringEngine.compileTemporary(parser);
|
|
||||||
}
|
|
||||||
return cosmeticFilteringEngine.compileTemporary(parser);
|
|
||||||
};
|
|
||||||
|
|
||||||
staticExtFilteringEngine.fromCompiledContent = function(reader, options) {
|
staticExtFilteringEngine.fromCompiledContent = function(reader, options) {
|
||||||
cosmeticFilteringEngine.fromCompiledContent(reader, options);
|
cosmeticFilteringEngine.fromCompiledContent(reader, options);
|
||||||
scriptletFilteringEngine.fromCompiledContent(reader, options);
|
scriptletFilteringEngine.fromCompiledContent(reader, options);
|
||||||
|
|
|
@ -618,6 +618,36 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µb.hasInMemoryFilter = function(raw) {
|
||||||
|
return this.inMemoryFilters.includes(raw);
|
||||||
|
};
|
||||||
|
|
||||||
|
µb.addInMemoryFilter = async function(raw) {
|
||||||
|
if ( this.inMemoryFilters.includes(raw) ){ return true; }
|
||||||
|
this.inMemoryFilters.push(raw);
|
||||||
|
this.inMemoryFiltersCompiled = '';
|
||||||
|
await this.loadFilterLists();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
µb.removeInMemoryFilter = async function(raw) {
|
||||||
|
const pos = this.inMemoryFilters.indexOf(raw);
|
||||||
|
if ( pos === -1 ) { return false; }
|
||||||
|
this.inMemoryFilters.splice(pos, 1);
|
||||||
|
this.inMemoryFiltersCompiled = '';
|
||||||
|
await this.loadFilterLists();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
µb.clearInMemoryFilters = async function() {
|
||||||
|
if ( this.inMemoryFilters.length === 0 ) { return; }
|
||||||
|
this.inMemoryFilters = [];
|
||||||
|
this.inMemoryFiltersCompiled = '';
|
||||||
|
await this.loadFilterLists();
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
µb.getAvailableLists = async function() {
|
µb.getAvailableLists = async function() {
|
||||||
let oldAvailableLists = {},
|
let oldAvailableLists = {},
|
||||||
newAvailableLists = {};
|
newAvailableLists = {};
|
||||||
|
@ -760,12 +790,12 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µb.loadFilterLists = (( ) => {
|
{
|
||||||
const loadedListKeys = [];
|
const loadedListKeys = [];
|
||||||
let loadingPromise;
|
let loadingPromise;
|
||||||
let t0 = 0;
|
let t0 = 0;
|
||||||
|
|
||||||
const onDone = function() {
|
const onDone = ( ) => {
|
||||||
ubolog(`loadFilterLists() took ${Date.now()-t0} ms`);
|
ubolog(`loadFilterLists() took ${Date.now()-t0} ms`);
|
||||||
|
|
||||||
staticNetFilteringEngine.freeze();
|
staticNetFilteringEngine.freeze();
|
||||||
|
@ -773,30 +803,30 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
redirectEngine.freeze();
|
redirectEngine.freeze();
|
||||||
vAPI.net.unsuspend();
|
vAPI.net.unsuspend();
|
||||||
|
|
||||||
vAPI.storage.set({ 'availableFilterLists': this.availableFilterLists });
|
vAPI.storage.set({ 'availableFilterLists': µb.availableFilterLists });
|
||||||
|
|
||||||
vAPI.messaging.broadcast({
|
vAPI.messaging.broadcast({
|
||||||
what: 'staticFilteringDataChanged',
|
what: 'staticFilteringDataChanged',
|
||||||
parseCosmeticFilters: this.userSettings.parseAllABPHideFilters,
|
parseCosmeticFilters: µb.userSettings.parseAllABPHideFilters,
|
||||||
ignoreGenericCosmeticFilters: this.userSettings.ignoreGenericCosmeticFilters,
|
ignoreGenericCosmeticFilters: µb.userSettings.ignoreGenericCosmeticFilters,
|
||||||
listKeys: loadedListKeys
|
listKeys: loadedListKeys
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selfieManager.destroy();
|
µb.selfieManager.destroy();
|
||||||
lz4Codec.relinquish();
|
lz4Codec.relinquish();
|
||||||
this.compiledFormatChanged = false;
|
µb.compiledFormatChanged = false;
|
||||||
|
|
||||||
loadingPromise = undefined;
|
loadingPromise = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyCompiledFilters = function(assetKey, compiled) {
|
const applyCompiledFilters = (assetKey, compiled) => {
|
||||||
const snfe = staticNetFilteringEngine;
|
const snfe = staticNetFilteringEngine;
|
||||||
const sxfe = staticExtFilteringEngine;
|
const sxfe = staticExtFilteringEngine;
|
||||||
let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount,
|
let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount;
|
||||||
discardedCount = snfe.discardedCount + sxfe.discardedCount;
|
let discardedCount = snfe.discardedCount + sxfe.discardedCount;
|
||||||
this.applyCompiledFilters(compiled, assetKey === this.userFiltersPath);
|
µb.applyCompiledFilters(compiled, assetKey === µb.userFiltersPath);
|
||||||
if ( this.availableFilterLists.hasOwnProperty(assetKey) ) {
|
if ( µb.availableFilterLists.hasOwnProperty(assetKey) ) {
|
||||||
const entry = this.availableFilterLists[assetKey];
|
const entry = µb.availableFilterLists[assetKey];
|
||||||
entry.entryCount = snfe.acceptedCount + sxfe.acceptedCount -
|
entry.entryCount = snfe.acceptedCount + sxfe.acceptedCount -
|
||||||
acceptedCount;
|
acceptedCount;
|
||||||
entry.entryUsedCount = entry.entryCount -
|
entry.entryUsedCount = entry.entryCount -
|
||||||
|
@ -805,8 +835,8 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
loadedListKeys.push(assetKey);
|
loadedListKeys.push(assetKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFilterListsReady = function(lists) {
|
const onFilterListsReady = lists => {
|
||||||
this.availableFilterLists = lists;
|
µb.availableFilterLists = lists;
|
||||||
|
|
||||||
if ( vAPI.Net.canSuspend() ) {
|
if ( vAPI.Net.canSuspend() ) {
|
||||||
vAPI.net.suspend();
|
vAPI.net.suspend();
|
||||||
|
@ -814,7 +844,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
redirectEngine.reset();
|
redirectEngine.reset();
|
||||||
staticExtFilteringEngine.reset();
|
staticExtFilteringEngine.reset();
|
||||||
staticNetFilteringEngine.reset();
|
staticNetFilteringEngine.reset();
|
||||||
this.selfieManager.destroy();
|
µb.selfieManager.destroy();
|
||||||
staticFilteringReverseLookup.resetLists();
|
staticFilteringReverseLookup.resetLists();
|
||||||
|
|
||||||
// We need to build a complete list of assets to pull first: this is
|
// We need to build a complete list of assets to pull first: this is
|
||||||
|
@ -825,37 +855,44 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
for ( const assetKey in lists ) {
|
for ( const assetKey in lists ) {
|
||||||
if ( lists.hasOwnProperty(assetKey) === false ) { continue; }
|
if ( lists.hasOwnProperty(assetKey) === false ) { continue; }
|
||||||
if ( lists[assetKey].off ) { continue; }
|
if ( lists[assetKey].off ) { continue; }
|
||||||
|
|
||||||
toLoad.push(
|
toLoad.push(
|
||||||
this.getCompiledFilterList(assetKey).then(details => {
|
µb.getCompiledFilterList(assetKey).then(details => {
|
||||||
applyCompiledFilters.call(
|
applyCompiledFilters(details.assetKey, details.content);
|
||||||
this,
|
|
||||||
details.assetKey,
|
|
||||||
details.content
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( µb.inMemoryFilters.length !== 0 ) {
|
||||||
|
if ( µb.inMemoryFiltersCompiled === '' ) {
|
||||||
|
µb.inMemoryFiltersCompiled =
|
||||||
|
µb.compileFilters(
|
||||||
|
µb.inMemoryFilters.join('\n'),
|
||||||
|
{ assetKey: 'in-memory'}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( µb.inMemoryFiltersCompiled !== '' ) {
|
||||||
|
toLoad.push(
|
||||||
|
µb.applyCompiledFilters(µb.inMemoryFiltersCompiled, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(toLoad);
|
return Promise.all(toLoad);
|
||||||
};
|
};
|
||||||
|
|
||||||
return function() {
|
µb.loadFilterLists = function() {
|
||||||
if ( loadingPromise instanceof Promise === false ) {
|
if ( loadingPromise instanceof Promise ) { return loadingPromise; }
|
||||||
t0 = Date.now();
|
t0 = Date.now();
|
||||||
loadedListKeys.length = 0;
|
loadedListKeys.length = 0;
|
||||||
loadingPromise = Promise.all([
|
loadingPromise = Promise.all([
|
||||||
this.getAvailableLists().then(lists =>
|
this.getAvailableLists().then(lists => onFilterListsReady(lists)),
|
||||||
onFilterListsReady.call(this, lists)
|
this.loadRedirectResources(),
|
||||||
),
|
]).then(( ) => {
|
||||||
this.loadRedirectResources(),
|
onDone();
|
||||||
]).then(( ) => {
|
});
|
||||||
onDone.call(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return loadingPromise;
|
return loadingPromise;
|
||||||
};
|
};
|
||||||
})();
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -1158,6 +1195,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
// memory usage at selfie-load time. For some reasons.
|
// memory usage at selfie-load time. For some reasons.
|
||||||
|
|
||||||
const create = async function() {
|
const create = async function() {
|
||||||
|
if ( µb.inMemoryFilters.length !== 0 ) { return; }
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
io.put(
|
io.put(
|
||||||
'selfie/main',
|
'selfie/main',
|
||||||
|
|
Loading…
Reference in New Issue