Make FilterJustOrigin derive from FilterOriginHitSet

By reusing FilterOriginHitSet for FilterJustOrigin, this
remove the need to special-case entity-based just-origin
filters.
This commit is contained in:
Raymond Hill 2021-12-26 10:46:59 -05:00
parent 7dc5997aa5
commit 57e660e39b
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
3 changed files with 148 additions and 118 deletions

View File

@ -174,8 +174,8 @@ const µBlock = { // jshint ignore:line
// Read-only
systemSettings: {
compiledMagic: 44, // Increase when compiled format changes
selfieMagic: 45, // Increase when selfie format changes
compiledMagic: 46, // Increase when compiled format changes
selfieMagic: 46, // Increase when selfie format changes
},
// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501

View File

@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2014-2018 Raymond Hill
Copyright (C) 2014-present 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

View File

@ -605,6 +605,60 @@ const filterDumpInfo = (idata) => {
};
/*******************************************************************************
Filter classes
Pattern:
FilterPatternAny
FilterPatternPlain
FilterPatternPlain1
FilterPatternPlainX
FilterPatternGeneric
FilterRegex
FilterPlainTrie
FilterHostnameDict
Pattern modifiers:
FilterAnchorHnLeft
FilterAnchorHn
FilterAnchorRight
FilterAnchorLeft
FilterTrailingSeparator
Context, immediate:
FilterOriginHit
FilterOriginMiss
FilterOriginEntityMiss
FilterOriginEntityHit
FilterOriginHitSet
FilterOriginMissSet
FilterJustOrigin
FilterHTTPJustOrigin
FilterHTTPSJustOrigin
Other options:
FilterDenyAllow
FilterImportant
FilterNotType
FilterStrictParty
FilterModifier
Collection:
FilterCollection
FilterCompositeAll
FilterBucket
FilterBucketIf
FilterBucketIfOriginHits
FilterBucketIfRegexHits
FilterOriginHitAny
A single filter can be made of many parts, in which case FilterCompositeAll
is used to hold all the parts, and where all the parts must be a match in
order for the filter to be a match.
**/
/******************************************************************************/
const FilterPatternAny = class {
@ -1307,9 +1361,13 @@ const FilterOriginHit = class {
return true;
}
static getMatchTarget() {
return $docHostname;
}
static match(idata) {
return origHNTrieContainer.matchesHostname(
$docHostname,
this.getMatchTarget(),
filterData[idata+1],
filterData[idata+2]
);
@ -1374,38 +1432,79 @@ const FilterOriginHitSet = class {
return true;
}
static match(idata) {
const refs = filterRefs[filterData[idata+6]];
if ( $docHostname === refs.$last ) {
return filterData[idata+5] !== -1;
}
refs.$last = $docHostname;
const which = filterData[idata+3];
const itrie = filterData[idata+4] || this.toTrie(idata);
let lastResult = -1;
if ( (which & 0b01) !== 0 ) {
lastResult = origHNTrieContainer
.setNeedle($docHostname)
.matches(itrie);
}
if ( lastResult === -1 && (which & 0b10) !== 0 ) {
lastResult = origHNTrieContainer
.setNeedle($docEntity.compute())
.matches(itrie);
}
return (filterData[idata+5] = lastResult) !== -1;
static getTrieCount(idata) {
const itrie = filterData[idata+4];
if ( itrie === 0 ) { return 0; }
return Array.from(
origHNTrieContainer.trieIterator(filterData[idata+4])
).length;
}
static create(domainOpt, which = 0b11) {
static getLastResult(idata) {
return filterData[idata+5];
}
static getMatchTarget(which) {
return (which & 0b01) !== 0
? $docHostname
: $docEntity.compute();
}
static getMatchedHostname(idata) {
const lastResult = filterData[idata+5];
if ( lastResult === -1 ) { return ''; }
return this.getMatchTarget(lastResult >>> 8).slice(lastResult & 0xFF);
}
static match(idata) {
const refs = filterRefs[filterData[idata+6]];
const docHostname = this.getMatchTarget(0b01);
if ( docHostname === refs.$last ) {
return filterData[idata+5] !== -1;
}
refs.$last = docHostname;
const which = filterData[idata+3];
const itrie = filterData[idata+4] || this.toTrie(idata);
if ( itrie === 0 ) { return false; }
if ( (which & 0b01) !== 0 ) {
const pos = origHNTrieContainer
.setNeedle(docHostname)
.matches(itrie);
if ( pos !== -1 ) {
filterData[idata+5] = 0b01 << 8 | pos;
return true;
}
}
if ( (which & 0b10) !== 0 ) {
const pos = origHNTrieContainer
.setNeedle(this.getMatchTarget(0b10))
.matches(itrie);
if ( pos !== -1 ) {
filterData[idata+5] = 0b10 << 8 | pos;
return true;
}
}
filterData[idata+5] = -1;
return false;
}
static add(idata, hn) {
origHNTrieContainer.setNeedle(hn).add(filterData[idata+4]);
filterData[idata+3] |= hn.charCodeAt(hn.length - 1) !== 0x2A /* '*' */
? 0b01
: 0b10;
filterData[idata+5] = -1;
}
static create(fid = -1) {
const idata = filterDataAllocLen(7);
filterData[idata+0] = FilterOriginHitSet.fid;
filterData[idata+1] = origHNTrieContainer.storeDomainOpt(domainOpt);
filterData[idata+2] = domainOpt.length;
filterData[idata+3] = which;
filterData[idata+4] = 0; // itrie
filterData[idata+0] = fid !== -1 ? fid : FilterOriginHitSet.fid;
filterData[idata+1] = 0;
filterData[idata+2] = 0;
filterData[idata+3] = 0;
filterData[idata+4] = origHNTrieContainer.createTrie();
filterData[idata+5] = -1; // $lastResult
filterData[idata+6] = filterRefAdd({ $last: '' });
this.toTrie(idata);
return idata;
}
@ -1430,6 +1529,7 @@ const FilterOriginHitSet = class {
}
static toTrie(idata) {
if ( filterData[idata+2] === 0 ) { return 0; }
const itrie = filterData[idata+4] =
origHNTrieContainer.createTrieFromStoredDomainOpt(
filterData[idata+1],
@ -1488,12 +1588,8 @@ registerFilterClass(FilterOriginMissSet);
/******************************************************************************/
const FilterOriginEntityHit = class extends FilterOriginHit {
static match(idata) {
return origHNTrieContainer.matchesHostname(
$docEntity.compute(),
filterData[idata+1],
filterData[idata+2]
);
static getMatchTarget() {
return $docEntity.compute();
}
static compile(entity) {
@ -1506,12 +1602,8 @@ registerFilterClass(FilterOriginEntityHit);
/******************************************************************************/
const FilterOriginEntityMiss = class extends FilterOriginMiss {
static match(idata) {
return origHNTrieContainer.matchesHostname(
$docEntity.compute(),
filterData[idata+1],
filterData[idata+2]
) === false;
static getMatchTarget() {
return $docEntity.compute();
}
static compile(entity) {
@ -1620,10 +1712,6 @@ const FilterModifierResult = class {
/******************************************************************************/
const FilterCollection = class {
static isEmpty(idata) {
return this.forEach(idata, ( ) => { return true; }) !== true;
}
static getCount(idata) {
let n = 0;
this.forEach(idata, ( ) => { n += 1; });
@ -1649,14 +1737,6 @@ const FilterCollection = class {
filterData[idata+1] = filterData[filterData[idata+1]+1];
}
static getSequenceRoot(idata) {
return filterData[idata+1];
}
static setSequenceRoot(idata, i) {
filterData[idata+1] = i;
}
static create(fid = -1) {
return filterDataAlloc(
fid !== -1 ? fid : FilterCollection.fid,
@ -1930,44 +2010,23 @@ registerFilterClass(FilterDenyAllow);
// Dictionary of hostnames for filters which only purpose is to match
// the document origin.
const FilterJustOrigin = class {
static getCount(idata) {
return Array.from(
origHNTrieContainer.trieIterator(filterData[idata+1])
).length;
}
static match(idata) {
const pos = origHNTrieContainer.setNeedle($docHostname).matches(filterData[idata+1]);
if ( pos === -1 ) { return false; }
filterRefs[filterData[idata+2]] = $docHostname.slice(pos);
return true;
}
static add(idata, hn) {
return origHNTrieContainer.setNeedle(hn).add(filterData[idata+1]);
}
const FilterJustOrigin = class extends FilterOriginHitSet {
static create(fid = -1) {
const idata = filterDataAllocLen(3);
filterData[idata+0] = fid !== -1 ? fid : FilterJustOrigin.fid; // fid
filterData[idata+1] = origHNTrieContainer.createTrie(); // itrie
filterData[idata+2] = filterRefAdd(''); // $hostname
return idata;
return super.create(fid !== -1 ? fid : FilterJustOrigin.fid);
}
static fromCompiled(args) {
return FilterJustOrigin.create(args[0]);
static logPattern(idata, details) {
details.pattern.push('*');
details.regex.push('^');
}
static logData(idata, details) {
details.pattern.push('*');
details.regex.push('^');
details.domains.push(filterRefs[filterData[idata+2]]);
this.logPattern(idata, details);
details.domains.push(this.getMatchedHostname(idata));
}
static dumpInfo(idata) {
return this.getCount(idata);
return this.getTrieCount(idata);
}
};
@ -1984,14 +2043,9 @@ const FilterHTTPSJustOrigin = class extends FilterJustOrigin {
return super.create(FilterHTTPSJustOrigin.fid);
}
static fromCompiled(args) {
return super.fromCompiled(args);
}
static logData(idata, details) {
static logPattern(idata, details) {
details.pattern.push('|https://');
details.regex.push('^https://');
details.domains.push(filterRefs[filterData[idata+2]]);
}
};
@ -2008,14 +2062,9 @@ const FilterHTTPJustOrigin = class extends FilterJustOrigin {
return super.create(FilterHTTPJustOrigin.fid);
}
static fromCompiled(args) {
return super.fromCompiled(args);
}
static logData(idata, details) {
static logPattern(idata, details) {
details.pattern.push('|http://');
details.regex.push('^http://');
details.domains.push(filterRefs[filterData[idata+2]]);
}
};
@ -3308,7 +3357,6 @@ class FilterCompiler {
// filters, the original filter is split into as many filters as there
// are entries in the `domain=` option.
if ( this.isJustOrigin() ) {
const tokenHash = this.tokenHash;
if ( this.pattern === '*' || this.pattern.startsWith('http*') ) {
this.tokenHash = ANY_TOKEN_HASH;
} else if /* 'https:' */ ( this.pattern.startsWith('https') ) {
@ -3316,26 +3364,8 @@ class FilterCompiler {
} else /* 'http:' */ {
this.tokenHash = ANY_HTTP_TOKEN_HASH;
}
const entities = [];
for ( const hn of this.domainOptList ) {
if ( this.domainIsEntity(hn) === false ) {
this.compileToAtomicFilter(hn, writer);
} else {
entities.push(hn);
}
}
if ( entities.length === 0 ) { return; }
this.tokenHash = tokenHash;
const leftAnchored = (this.anchor & 0b010) !== 0;
for ( const entity of entities ) {
const units = [];
this.compilePattern(units);
if ( leftAnchored ) { units.push(FilterAnchorLeft.compile()); }
compileDomainOpt([ entity ], true, units);
this.compileToAtomicFilter(
FilterCompositeAll.compile(units),
writer
);
this.compileToAtomicFilter(hn, writer);
}
return;
}
@ -3492,8 +3522,8 @@ FilterCompiler.prototype.FILTER_UNSUPPORTED = 2;
/******************************************************************************/
const FilterContainer = function() {
this.compilerVersion = '6';
this.selfieVersion = '7';
this.compilerVersion = '8';
this.selfieVersion = '8';
this.MAX_TOKEN_LENGTH = MAX_TOKEN_LENGTH;
this.optimizeTaskId = undefined;