Add support for `all` filter option

Related discussion:
- https://www.reddit.com/r/uBlockOrigin/comments/bqnsoa/

The `all` option is equivalent to specifying all
network-based types + `popup`, `document`,
`inline-font`, `inline-script`.

Example from discussion:

    ||bet365.com^$all

Above will block all network requests, block all popups,
prevent inline fonts/scripts from `bet365.com`. EasyList-
compatible syntax does not allow to accomplish that
semantic when using only `||bet365.com^`.

If using specific negated type options along with `all`,
the order in which the options appear is important. In
such case `all` should always be first, followed by
the negated type option(s).
This commit is contained in:
Raymond Hill 2019-05-20 13:46:36 -04:00
parent 134c59e4b2
commit 1888033070
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 41 additions and 18 deletions

View File

@ -75,8 +75,26 @@ const typeNameToTypeValue = {
'webrtc': 19 << 4, 'webrtc': 19 << 4,
'unsupported': 20 << 4 'unsupported': 20 << 4
}; };
const otherTypeBitValue = typeNameToTypeValue.other; const otherTypeBitValue = typeNameToTypeValue.other;
// All network request types to bitmap
// bring origin to 0 (from 4 -- see typeNameToTypeValue)
// left-shift 1 by the above-calculated value
// subtract 1 to set all type bits
const allNetworkTypesBits =
(1 << (otherTypeBitValue >>> 4)) - 1;
const allTypesBits =
allNetworkTypesBits |
1 << (typeNameToTypeValue['popup'] >>> 4) - 1 |
1 << (typeNameToTypeValue['main_frame'] >>> 4) - 1 |
1 << (typeNameToTypeValue['inline-font'] >>> 4) - 1 |
1 << (typeNameToTypeValue['inline-script'] >>> 4) - 1;
const unsupportedTypeBit =
1 << (typeNameToTypeValue['unsupported'] >>> 4) - 1;
const typeValueToTypeName = { const typeValueToTypeName = {
1: 'stylesheet', 1: 'stylesheet',
2: 'image', 2: 'image',
@ -1792,12 +1810,6 @@ const FilterParser = function() {
this.reBadCSP = /(?:^|;)\s*report-(?:to|uri)\b/; this.reBadCSP = /(?:^|;)\s*report-(?:to|uri)\b/;
this.domainOpt = ''; this.domainOpt = '';
this.noTokenHash = µb.urlTokenizer.noTokenHash; this.noTokenHash = µb.urlTokenizer.noTokenHash;
this.unsupportedTypeBit = this.bitFromType('unsupported');
// All network request types to bitmap
// bring origin to 0 (from 4 -- see typeNameToTypeValue)
// left-shift 1 by the above-calculated value
// subtract 1 to set all type bits
this.allNetRequestTypeBits = (1 << (otherTypeBitValue >>> 4)) - 1;
this.reset(); this.reset();
}; };
@ -1807,6 +1819,7 @@ const FilterParser = function() {
// Transpose `ping` into `other` for now. // Transpose `ping` into `other` for now.
FilterParser.prototype.toNormalizedType = { FilterParser.prototype.toNormalizedType = {
'all': 'all',
'beacon': 'other', 'beacon': 'other',
'css': 'stylesheet', 'css': 'stylesheet',
'data': 'data', 'data': 'data',
@ -1833,7 +1846,7 @@ FilterParser.prototype.toNormalizedType = {
'xhr': 'xmlhttprequest', 'xhr': 'xmlhttprequest',
'xmlhttprequest': 'xmlhttprequest', 'xmlhttprequest': 'xmlhttprequest',
'webrtc': 'unsupported', 'webrtc': 'unsupported',
'websocket': 'websocket' 'websocket': 'websocket',
}; };
/******************************************************************************/ /******************************************************************************/
@ -1877,24 +1890,28 @@ FilterParser.prototype.bitFromType = function(type) {
// Be ready to handle multiple negated types // Be ready to handle multiple negated types
FilterParser.prototype.parseTypeOption = function(raw, not) { FilterParser.prototype.parseTypeOption = function(raw, not) {
var typeBit = this.bitFromType(this.toNormalizedType[raw]); const typeBit = raw !== 'all'
? this.bitFromType(this.toNormalizedType[raw])
: allTypesBits;
if ( !not ) { if ( !not ) {
this.types |= typeBit; this.types |= typeBit;
return; return;
} }
// Non-discrete network types can't be negated. // Non-network types can only toggle themselves.
if ( (typeBit & this.allNetRequestTypeBits) === 0 ) { if ( (typeBit & allNetworkTypesBits) === 0 ) {
this.types &= ~typeBit;
return; return;
} }
// Negated type: set all valid network request type bits to 1 // Negated network type: the first negation imply all network types are
// toggled on.
if ( if (
(typeBit & this.allNetRequestTypeBits) !== 0 && (typeBit & allNetworkTypesBits) !== 0 &&
(this.types & this.allNetRequestTypeBits) === 0 (this.types & allNetworkTypesBits) === 0
) { ) {
this.types |= this.allNetRequestTypeBits; this.types |= allNetworkTypesBits;
} }
this.types &= ~typeBit; this.types &= ~typeBit;
}; };
@ -2080,8 +2097,8 @@ FilterParser.prototype.parse = function(raw) {
// https://github.com/gorhill/uBlock/issues/2283 // https://github.com/gorhill/uBlock/issues/2283
// Abort if type is only for unsupported types, otherwise // Abort if type is only for unsupported types, otherwise
// toggle off `unsupported` bit. // toggle off `unsupported` bit.
if ( this.types & this.unsupportedTypeBit ) { if ( this.types & unsupportedTypeBit ) {
this.types &= ~this.unsupportedTypeBit; this.types &= ~unsupportedTypeBit;
if ( this.types === 0 ) { if ( this.types === 0 ) {
this.unsupported = true; this.unsupported = true;
return this; return this;
@ -2735,6 +2752,12 @@ FilterContainer.prototype.compileToAtomicFilter = function(
return; return;
} }
// If all network types are set, just use `no_type`.
if ( (type & allNetworkTypesBits) === allNetworkTypesBits ) {
writer.push([ descBits, parsed.tokenHash, fdata ]);
type &= ~allNetworkTypesBits;
}
// Specific type(s) // Specific type(s)
let bitOffset = 1; let bitOffset = 1;
do { do {
@ -2748,9 +2771,9 @@ FilterContainer.prototype.compileToAtomicFilter = function(
// Only static filter with an explicit type can be redirected. If we reach // Only static filter with an explicit type can be redirected. If we reach
// this point, it's because there is one or more explicit type. // this point, it's because there is one or more explicit type.
if ( parsed.redirect ) { if ( parsed.redirect ) {
let redirects = µb.redirectEngine.compileRuleFromStaticFilter(parsed.raw); const redirects = µb.redirectEngine.compileRuleFromStaticFilter(parsed.raw);
if ( Array.isArray(redirects) ) { if ( Array.isArray(redirects) ) {
for ( let redirect of redirects ) { for ( const redirect of redirects ) {
writer.push([ typeNameToTypeValue.redirect, redirect ]); writer.push([ typeNameToTypeValue.redirect, redirect ]);
} }
} }