2014-06-24 00:42:43 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2016-03-07 15:55:04 +01:00
|
|
|
uBlock Origin - a browser extension to block requests.
|
2018-07-22 16:47:02 +02:00
|
|
|
Copyright (C) 2014-present Raymond Hill
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2016-07-01 04:03:29 +02:00
|
|
|
'use strict';
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
|
|
|
|
A PageRequestStore object is used to store net requests in two ways:
|
|
|
|
|
|
|
|
To record distinct net requests
|
|
|
|
To create a log of net requests
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
{
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// start of private namespace
|
|
|
|
// >>>>>
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2018-12-13 18:30:54 +01:00
|
|
|
const µb = µBlock;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const NetFilteringResultCache = class {
|
|
|
|
constructor() {
|
|
|
|
this.init();
|
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
init() {
|
2018-12-21 20:16:17 +01:00
|
|
|
this.blocked = new Map();
|
|
|
|
this.results = new Map();
|
|
|
|
this.hash = 0;
|
|
|
|
this.timer = undefined;
|
|
|
|
return this;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2020-10-10 14:36:30 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/3619
|
|
|
|
// Don't collapse redirected resources
|
2019-07-05 23:44:08 +02:00
|
|
|
rememberResult(fctxt, result) {
|
2018-12-21 20:16:17 +01:00
|
|
|
if ( fctxt.tabId <= 0 ) { return; }
|
|
|
|
if ( this.results.size === 0 ) {
|
|
|
|
this.pruneAsync();
|
2017-08-03 16:18:05 +02:00
|
|
|
}
|
2020-10-10 14:36:30 +02:00
|
|
|
const key = `${fctxt.getDocHostname()} ${fctxt.type} ${fctxt.url}`;
|
2018-12-21 20:16:17 +01:00
|
|
|
this.results.set(key, {
|
2020-10-10 14:36:30 +02:00
|
|
|
result,
|
|
|
|
redirectURL: fctxt.redirectURL,
|
2018-12-21 20:16:17 +01:00
|
|
|
logData: fctxt.filter,
|
|
|
|
tstamp: Date.now()
|
|
|
|
});
|
2020-10-10 14:36:30 +02:00
|
|
|
if ( result !== 1 || fctxt.redirectURL !== undefined ) { return; }
|
2018-12-21 20:16:17 +01:00
|
|
|
const now = Date.now();
|
|
|
|
this.blocked.set(key, now);
|
|
|
|
this.hash = now;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
rememberBlock(fctxt) {
|
2018-12-21 20:16:17 +01:00
|
|
|
if ( fctxt.tabId <= 0 ) { return; }
|
|
|
|
if ( this.blocked.size === 0 ) {
|
|
|
|
this.pruneAsync();
|
2014-07-30 07:05:35 +02:00
|
|
|
}
|
2020-10-10 14:36:30 +02:00
|
|
|
if ( fctxt.redirectURL !== undefined ) { return; }
|
2018-12-21 20:16:17 +01:00
|
|
|
const now = Date.now();
|
|
|
|
this.blocked.set(
|
2020-10-10 14:36:30 +02:00
|
|
|
`${fctxt.getDocHostname()} ${fctxt.type} ${fctxt.url}`,
|
2018-12-21 20:16:17 +01:00
|
|
|
now
|
|
|
|
);
|
|
|
|
this.hash = now;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2020-10-10 14:36:30 +02:00
|
|
|
forgetResult(docHostname, type, url) {
|
|
|
|
const key = `${docHostname} ${type} ${url}`;
|
2020-10-09 19:50:54 +02:00
|
|
|
this.results.delete(key);
|
|
|
|
this.blocked.delete(key);
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
empty() {
|
2018-12-21 20:16:17 +01:00
|
|
|
this.blocked.clear();
|
|
|
|
this.results.clear();
|
|
|
|
this.hash = 0;
|
|
|
|
if ( this.timer !== undefined ) {
|
|
|
|
clearTimeout(this.timer);
|
|
|
|
this.timer = undefined;
|
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
prune() {
|
2018-12-21 20:16:17 +01:00
|
|
|
const obsolete = Date.now() - this.shelfLife;
|
|
|
|
for ( const entry of this.blocked ) {
|
|
|
|
if ( entry[1] <= obsolete ) {
|
|
|
|
this.results.delete(entry[0]);
|
|
|
|
this.blocked.delete(entry[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for ( const entry of this.results ) {
|
|
|
|
if ( entry[1].tstamp <= obsolete ) {
|
|
|
|
this.results.delete(entry[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( this.blocked.size !== 0 || this.results.size !== 0 ) {
|
|
|
|
this.pruneAsync();
|
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
pruneAsync() {
|
2018-12-21 20:16:17 +01:00
|
|
|
if ( this.timer !== undefined ) { return; }
|
|
|
|
this.timer = vAPI.setTimeout(
|
|
|
|
( ) => {
|
|
|
|
this.timer = undefined;
|
|
|
|
this.prune();
|
|
|
|
},
|
|
|
|
this.shelfLife
|
|
|
|
);
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
lookupResult(fctxt) {
|
2018-12-21 20:16:17 +01:00
|
|
|
return this.results.get(
|
|
|
|
fctxt.getDocHostname() + ' ' +
|
|
|
|
fctxt.type + ' ' +
|
|
|
|
fctxt.url
|
|
|
|
);
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
lookupAllBlocked(hostname) {
|
2018-12-21 20:16:17 +01:00
|
|
|
const result = [];
|
|
|
|
for ( const entry of this.blocked ) {
|
|
|
|
const pos = entry[0].indexOf(' ');
|
|
|
|
if ( entry[0].slice(0, pos) === hostname ) {
|
|
|
|
result[result.length] = entry[0].slice(pos + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
static factory() {
|
2019-09-21 22:42:15 +02:00
|
|
|
return new NetFilteringResultCache();
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2014-09-14 22:20:40 +02:00
|
|
|
};
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
NetFilteringResultCache.prototype.shelfLife = 15000;
|
|
|
|
|
2014-09-14 22:20:40 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
// Frame stores are used solely to associate a URL with a frame id.
|
2015-04-09 00:46:08 +02:00
|
|
|
|
2014-09-14 22:20:40 +02:00
|
|
|
// To mitigate memory churning
|
2018-12-13 18:30:54 +01:00
|
|
|
const frameStoreJunkyard = [];
|
|
|
|
const frameStoreJunkyardMax = 50;
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const FrameStore = class {
|
|
|
|
constructor(frameURL) {
|
|
|
|
this.init(frameURL);
|
|
|
|
}
|
2014-07-30 07:05:35 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
init(frameURL) {
|
2020-07-18 13:44:26 +02:00
|
|
|
this.t0 = Date.now();
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
this.exceptCname = undefined;
|
2020-10-10 14:36:30 +02:00
|
|
|
this.clickToLoad = false;
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
this.rawURL = frameURL;
|
|
|
|
if ( frameURL !== undefined ) {
|
|
|
|
this.hostname = vAPI.hostnameFromURI(frameURL);
|
|
|
|
this.domain =
|
|
|
|
vAPI.domainFromHostname(this.hostname) || this.hostname;
|
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
return this;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2018-12-21 20:16:17 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
dispose() {
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
this.exceptCname = undefined;
|
|
|
|
this.rawURL = this.hostname = this.domain = '';
|
2018-12-21 20:16:17 +01:00
|
|
|
if ( frameStoreJunkyard.length < frameStoreJunkyardMax ) {
|
|
|
|
frameStoreJunkyard.push(this);
|
|
|
|
}
|
|
|
|
return null;
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2014-07-30 07:05:35 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
static factory(frameURL) {
|
|
|
|
const entry = frameStoreJunkyard.pop();
|
|
|
|
if ( entry === undefined ) {
|
|
|
|
return new FrameStore(frameURL);
|
|
|
|
}
|
|
|
|
return entry.init(frameURL);
|
2014-09-14 22:20:40 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-07-30 07:05:35 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-09-14 22:20:40 +02:00
|
|
|
// To mitigate memory churning
|
2018-12-13 18:30:54 +01:00
|
|
|
const pageStoreJunkyard = [];
|
|
|
|
const pageStoreJunkyardMax = 10;
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const PageStore = class {
|
|
|
|
constructor(tabId, context) {
|
|
|
|
this.extraData = new Map();
|
|
|
|
this.journal = [];
|
|
|
|
this.journalTimer = null;
|
|
|
|
this.journalLastCommitted = this.journalLastUncommitted = undefined;
|
|
|
|
this.journalLastUncommittedURL = undefined;
|
2019-09-21 22:42:15 +02:00
|
|
|
this.netFilteringCache = NetFilteringResultCache.factory();
|
2019-07-05 23:44:08 +02:00
|
|
|
this.init(tabId, context);
|
2014-09-14 22:20:40 +02:00
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
static factory(tabId, context) {
|
|
|
|
let entry = pageStoreJunkyard.pop();
|
|
|
|
if ( entry === undefined ) {
|
|
|
|
entry = new PageStore(tabId, context);
|
|
|
|
} else {
|
|
|
|
entry.init(tabId, context);
|
|
|
|
}
|
|
|
|
return entry;
|
|
|
|
}
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/3201
|
|
|
|
// The context is used to determine whether we report behavior change
|
|
|
|
// to the logger.
|
2017-11-07 17:31:19 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
init(tabId, context) {
|
|
|
|
const tabContext = µb.tabContextManager.mustLookup(tabId);
|
|
|
|
this.tabId = tabId;
|
2016-01-17 19:30:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// If we are navigating from-to same site, remember whether large
|
|
|
|
// media elements were temporarily allowed.
|
|
|
|
if (
|
|
|
|
typeof this.allowLargeMediaElementsUntil !== 'number' ||
|
|
|
|
tabContext.rootHostname !== this.tabHostname
|
|
|
|
) {
|
|
|
|
this.allowLargeMediaElementsUntil = 0;
|
|
|
|
}
|
2016-01-17 19:30:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
this.tabHostname = tabContext.rootHostname;
|
|
|
|
this.title = tabContext.rawURL;
|
|
|
|
this.rawURL = tabContext.rawURL;
|
|
|
|
this.hostnameToCountMap = new Map();
|
|
|
|
this.contentLastModified = 0;
|
|
|
|
this.logData = undefined;
|
|
|
|
this.perLoadBlockedRequestCount = 0;
|
|
|
|
this.perLoadAllowedRequestCount = 0;
|
|
|
|
this.remoteFontCount = 0;
|
|
|
|
this.popupBlockedCount = 0;
|
|
|
|
this.largeMediaCount = 0;
|
|
|
|
this.largeMediaTimer = null;
|
|
|
|
this.internalRedirectionCount = 0;
|
|
|
|
this.extraData.clear();
|
|
|
|
|
2020-07-19 15:01:45 +02:00
|
|
|
this.frameAddCount = 0;
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
this.frames = new Map();
|
2020-10-09 19:50:54 +02:00
|
|
|
this.setFrameURL(0, tabContext.rawURL);
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// The current filtering context is cloned because:
|
|
|
|
// - We may be called with or without the current context having been
|
|
|
|
// initialized.
|
|
|
|
// - If it has been initialized, we do not want to change the state
|
|
|
|
// of the current context.
|
|
|
|
const fctxt = µb.logger.enabled
|
|
|
|
? µb.filteringContext
|
2018-12-13 18:30:54 +01:00
|
|
|
.duplicate()
|
|
|
|
.fromTabId(tabId)
|
|
|
|
.setURL(tabContext.rawURL)
|
2019-07-05 23:44:08 +02:00
|
|
|
: undefined;
|
2014-07-14 17:24:59 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/314
|
|
|
|
const masterSwitch = tabContext.getNetFilteringSwitch();
|
2015-03-22 01:30:00 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
this.noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
|
|
|
|
'no-cosmetic-filtering',
|
|
|
|
tabContext.rootHostname
|
|
|
|
) === true;
|
|
|
|
if (
|
|
|
|
masterSwitch &&
|
|
|
|
this.noCosmeticFiltering &&
|
|
|
|
µb.logger.enabled &&
|
|
|
|
context === 'tabCommitted'
|
|
|
|
) {
|
|
|
|
fctxt.setRealm('cosmetic')
|
|
|
|
.setType('dom')
|
|
|
|
.setFilter(µb.sessionSwitches.toLogData())
|
|
|
|
.toLogger();
|
|
|
|
}
|
2015-03-26 00:28:22 +01:00
|
|
|
|
2014-10-02 22:45:26 +02:00
|
|
|
return this;
|
|
|
|
}
|
2015-04-09 00:46:08 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
reuse(context) {
|
|
|
|
// When force refreshing a page, the page store data needs to be reset.
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// If the hostname changes, we can't merely just update the context.
|
|
|
|
const tabContext = µb.tabContextManager.mustLookup(this.tabId);
|
|
|
|
if ( tabContext.rootHostname !== this.tabHostname ) {
|
|
|
|
context = '';
|
|
|
|
}
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// If URL changes without a page reload (more and more common), then
|
|
|
|
// we need to keep all that we collected for reuse. In particular,
|
|
|
|
// not doing so was causing a problem in `videos.foxnews.com`:
|
|
|
|
// clicking a video thumbnail would not work, because the frame
|
|
|
|
// hierarchy structure was flushed from memory, while not really being
|
|
|
|
// flushed on the page.
|
|
|
|
if ( context === 'tabUpdated' ) {
|
|
|
|
// As part of https://github.com/chrisaljoudi/uBlock/issues/405
|
|
|
|
// URL changed, force a re-evaluation of filtering switch
|
|
|
|
this.rawURL = tabContext.rawURL;
|
2020-10-09 19:50:54 +02:00
|
|
|
this.setFrameURL(0, this.rawURL);
|
2019-07-05 23:44:08 +02:00
|
|
|
return this;
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// A new page is completely reloaded from scratch, reset all.
|
|
|
|
if ( this.largeMediaTimer !== null ) {
|
|
|
|
clearTimeout(this.largeMediaTimer);
|
|
|
|
this.largeMediaTimer = null;
|
|
|
|
}
|
|
|
|
this.disposeFrameStores();
|
|
|
|
this.init(this.tabId, context);
|
|
|
|
return this;
|
2014-06-24 00:42:43 +02:00
|
|
|
}
|
2014-09-14 22:20:40 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
dispose() {
|
|
|
|
this.tabHostname = '';
|
|
|
|
this.title = '';
|
|
|
|
this.rawURL = '';
|
|
|
|
this.hostnameToCountMap = null;
|
2019-09-21 22:42:15 +02:00
|
|
|
this.netFilteringCache.empty();
|
2019-07-05 23:44:08 +02:00
|
|
|
this.allowLargeMediaElementsUntil = 0;
|
|
|
|
if ( this.largeMediaTimer !== null ) {
|
|
|
|
clearTimeout(this.largeMediaTimer);
|
|
|
|
this.largeMediaTimer = null;
|
|
|
|
}
|
|
|
|
this.disposeFrameStores();
|
|
|
|
if ( this.journalTimer !== null ) {
|
|
|
|
clearTimeout(this.journalTimer);
|
|
|
|
this.journalTimer = null;
|
|
|
|
}
|
|
|
|
this.journal = [];
|
|
|
|
this.journalLastUncommittedURL = undefined;
|
|
|
|
if ( pageStoreJunkyard.length < pageStoreJunkyardMax ) {
|
|
|
|
pageStoreJunkyard.push(this);
|
|
|
|
}
|
|
|
|
return null;
|
2014-09-14 22:20:40 +02:00
|
|
|
}
|
2014-07-30 07:05:35 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
disposeFrameStores() {
|
|
|
|
for ( const frameStore of this.frames.values() ) {
|
|
|
|
frameStore.dispose();
|
|
|
|
}
|
|
|
|
this.frames.clear();
|
2015-02-25 20:15:36 +01:00
|
|
|
}
|
2014-07-30 07:05:35 +02:00
|
|
|
|
2020-10-09 19:50:54 +02:00
|
|
|
getFrameStore(frameId) {
|
2019-07-05 23:44:08 +02:00
|
|
|
return this.frames.get(frameId) || null;
|
|
|
|
}
|
2014-07-30 07:05:35 +02:00
|
|
|
|
2020-10-09 19:50:54 +02:00
|
|
|
setFrameURL(frameId, frameURL) {
|
|
|
|
let frameStore = this.frames.get(frameId);
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( frameStore !== undefined ) {
|
|
|
|
frameStore.init(frameURL);
|
2020-10-09 19:50:54 +02:00
|
|
|
} else {
|
|
|
|
frameStore = FrameStore.factory(frameURL);
|
|
|
|
this.frames.set(frameId, frameStore);
|
|
|
|
this.frameAddCount += 1;
|
|
|
|
if ( (this.frameAddCount & 0b111111) === 0 ) {
|
|
|
|
this.pruneFrames();
|
|
|
|
}
|
2020-07-18 13:44:26 +02:00
|
|
|
}
|
2020-10-09 19:50:54 +02:00
|
|
|
return frameStore;
|
2020-07-18 13:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// There is no event to tell us a specific subframe has been removed from
|
|
|
|
// the main document. The code below will remove subframes which are no
|
|
|
|
// longer present in the root document. Removing obsolete subframes is
|
|
|
|
// not a critical task, so this is executed just once on a while, to avoid
|
|
|
|
// bloated dictionary of subframes.
|
|
|
|
// A TTL is used to avoid race conditions when new iframes are added
|
|
|
|
// through the webRequest API but still not yet visible through the
|
|
|
|
// webNavigation API.
|
|
|
|
async pruneFrames() {
|
|
|
|
let entries;
|
|
|
|
try {
|
|
|
|
entries = await webext.webNavigation.getAllFrames({
|
|
|
|
tabId: this.tabId
|
|
|
|
});
|
|
|
|
} catch(ex) {
|
|
|
|
}
|
|
|
|
if ( Array.isArray(entries) === false ) { return; }
|
|
|
|
const toKeep = new Set();
|
|
|
|
for ( const { frameId } of entries ) {
|
|
|
|
toKeep.add(frameId);
|
|
|
|
}
|
|
|
|
const obsolete = Date.now() - 60000;
|
|
|
|
for ( const [ frameId, { t0 } ] of this.frames ) {
|
|
|
|
if ( toKeep.has(frameId) || t0 >= obsolete ) { continue; }
|
|
|
|
this.frames.delete(frameId);
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-02 17:40:27 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
getNetFilteringSwitch() {
|
|
|
|
return µb.tabContextManager
|
|
|
|
.mustLookup(this.tabId)
|
|
|
|
.getNetFilteringSwitch();
|
|
|
|
}
|
2015-02-06 05:14:12 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
getSpecificCosmeticFilteringSwitch() {
|
|
|
|
return this.noCosmeticFiltering !== true;
|
|
|
|
}
|
2015-01-22 03:46:11 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
toggleNetFilteringSwitch(url, scope, state) {
|
|
|
|
µb.toggleNetFilteringSwitch(url, scope, state);
|
|
|
|
this.netFilteringCache.empty();
|
|
|
|
}
|
2015-01-22 03:46:11 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
injectLargeMediaElementScriptlet() {
|
2019-09-16 22:17:48 +02:00
|
|
|
vAPI.tabs.executeScript(this.tabId, {
|
2019-07-05 23:44:08 +02:00
|
|
|
file: '/js/scriptlets/load-large-media-interactive.js',
|
|
|
|
allFrames: true,
|
|
|
|
runAt: 'document_idle',
|
|
|
|
});
|
|
|
|
µb.contextMenu.update(this.tabId);
|
|
|
|
}
|
2016-01-17 19:30:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
temporarilyAllowLargeMediaElements(state) {
|
|
|
|
this.largeMediaCount = 0;
|
|
|
|
µb.contextMenu.update(this.tabId);
|
|
|
|
this.allowLargeMediaElementsUntil = state ? Date.now() + 86400000 : 0;
|
|
|
|
µb.scriptlets.injectDeep(this.tabId, 'load-large-media-all');
|
|
|
|
}
|
2016-01-17 19:30:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/2053
|
|
|
|
// There is no way around using journaling to ensure we deal properly with
|
|
|
|
// potentially out of order navigation events vs. network request events.
|
|
|
|
journalAddRequest(hostname, result) {
|
|
|
|
if ( hostname === '' ) { return; }
|
|
|
|
this.journal.push(
|
|
|
|
hostname,
|
|
|
|
result === 1 ? 0x00000001 : 0x00010000
|
|
|
|
);
|
|
|
|
if ( this.journalTimer === null ) {
|
|
|
|
this.journalTimer = vAPI.setTimeout(
|
|
|
|
( ) => { this.journalProcess(true); },
|
|
|
|
µb.hiddenSettings.requestJournalProcessPeriod
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2016-01-17 19:30:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
journalAddRootFrame(type, url) {
|
|
|
|
if ( type === 'committed' ) {
|
|
|
|
this.journalLastCommitted = this.journal.length;
|
|
|
|
if (
|
|
|
|
this.journalLastUncommitted !== undefined &&
|
|
|
|
this.journalLastUncommitted < this.journalLastCommitted &&
|
|
|
|
this.journalLastUncommittedURL === url
|
|
|
|
) {
|
|
|
|
this.journalLastCommitted = this.journalLastUncommitted;
|
|
|
|
this.journalLastUncommitted = undefined;
|
|
|
|
}
|
|
|
|
} else if ( type === 'uncommitted' ) {
|
|
|
|
this.journalLastUncommitted = this.journal.length;
|
|
|
|
this.journalLastUncommittedURL = url;
|
|
|
|
}
|
|
|
|
if ( this.journalTimer !== null ) {
|
|
|
|
clearTimeout(this.journalTimer);
|
|
|
|
}
|
2018-09-01 00:47:02 +02:00
|
|
|
this.journalTimer = vAPI.setTimeout(
|
|
|
|
( ) => { this.journalProcess(true); },
|
|
|
|
µb.hiddenSettings.requestJournalProcessPeriod
|
|
|
|
);
|
2016-10-08 16:15:31 +02:00
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
journalProcess(fromTimer) {
|
|
|
|
if ( !fromTimer ) {
|
|
|
|
clearTimeout(this.journalTimer);
|
2016-10-08 16:15:31 +02:00
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
this.journalTimer = null;
|
2016-10-08 16:15:31 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const journal = this.journal;
|
|
|
|
const now = Date.now();
|
|
|
|
let aggregateCounts = 0;
|
|
|
|
let pivot = this.journalLastCommitted || 0;
|
|
|
|
|
|
|
|
// Everything after pivot originates from current page.
|
|
|
|
for ( let i = pivot; i < journal.length; i += 2 ) {
|
|
|
|
const hostname = journal[i];
|
|
|
|
let hostnameCounts = this.hostnameToCountMap.get(hostname);
|
|
|
|
if ( hostnameCounts === undefined ) {
|
|
|
|
hostnameCounts = 0;
|
|
|
|
this.contentLastModified = now;
|
|
|
|
}
|
|
|
|
let count = journal[i+1];
|
|
|
|
this.hostnameToCountMap.set(hostname, hostnameCounts + count);
|
|
|
|
aggregateCounts += count;
|
|
|
|
}
|
|
|
|
this.perLoadBlockedRequestCount += aggregateCounts & 0xFFFF;
|
|
|
|
this.perLoadAllowedRequestCount += aggregateCounts >>> 16 & 0xFFFF;
|
|
|
|
this.journalLastCommitted = undefined;
|
|
|
|
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/905#issuecomment-76543649
|
|
|
|
// No point updating the badge if it's not being displayed.
|
|
|
|
if ( (aggregateCounts & 0xFFFF) && µb.userSettings.showIconBadge ) {
|
|
|
|
µb.updateToolbarIcon(this.tabId, 0x02);
|
2016-10-08 16:15:31 +02:00
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// Everything before pivot does not originate from current page -- we
|
|
|
|
// still need to bump global blocked/allowed counts.
|
|
|
|
for ( let i = 0; i < pivot; i += 2 ) {
|
|
|
|
aggregateCounts += journal[i+1];
|
|
|
|
}
|
|
|
|
if ( aggregateCounts !== 0 ) {
|
|
|
|
µb.localSettings.blockedRequestCount +=
|
|
|
|
aggregateCounts & 0xFFFF;
|
|
|
|
µb.localSettings.allowedRequestCount +=
|
|
|
|
aggregateCounts >>> 16 & 0xFFFF;
|
|
|
|
µb.localSettingsLastModified = now;
|
|
|
|
}
|
|
|
|
journal.length = 0;
|
2016-10-08 16:15:31 +02:00
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
filterRequest(fctxt) {
|
|
|
|
fctxt.filter = undefined;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( this.getNetFilteringSwitch(fctxt) === false ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2017-08-03 16:18:05 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const requestType = fctxt.type;
|
2015-01-24 18:06:22 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if (
|
|
|
|
requestType === 'csp_report' &&
|
|
|
|
this.filterCSPReport(fctxt) === 1
|
|
|
|
) {
|
|
|
|
return 1;
|
|
|
|
}
|
2016-10-14 16:06:34 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( requestType.endsWith('font') && this.filterFont(fctxt) === 1 ) {
|
|
|
|
return 1;
|
|
|
|
}
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if (
|
|
|
|
requestType === 'script' &&
|
|
|
|
this.filterScripting(fctxt, true) === 1
|
|
|
|
) {
|
|
|
|
return 1;
|
|
|
|
}
|
2018-09-01 00:47:02 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
const cacheableResult = this.cacheableResults.has(requestType);
|
2017-08-03 16:18:05 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( cacheableResult ) {
|
|
|
|
const entry = this.netFilteringCache.lookupResult(fctxt);
|
|
|
|
if ( entry !== undefined ) {
|
2020-10-10 14:36:30 +02:00
|
|
|
fctxt.redirectURL = entry.redirectURL;
|
2019-07-05 23:44:08 +02:00
|
|
|
fctxt.filter = entry.logData;
|
|
|
|
return entry.result;
|
|
|
|
}
|
2017-08-03 16:18:05 +02:00
|
|
|
}
|
2015-01-06 14:01:15 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// Dynamic URL filtering.
|
|
|
|
let result = µb.sessionURLFiltering.evaluateZ(
|
2018-12-13 18:30:54 +01:00
|
|
|
fctxt.getTabHostname(),
|
2019-07-05 23:44:08 +02:00
|
|
|
fctxt.url,
|
2018-12-13 18:30:54 +01:00
|
|
|
requestType
|
|
|
|
);
|
|
|
|
if ( result !== 0 && µb.logger.enabled ) {
|
2019-07-05 23:44:08 +02:00
|
|
|
fctxt.filter = µb.sessionURLFiltering.toLogData();
|
2015-06-09 16:27:08 +02:00
|
|
|
}
|
2014-12-28 16:07:43 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// Dynamic hostname/type filtering.
|
|
|
|
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
|
|
|
result = µb.sessionFirewall.evaluateCellZY(
|
|
|
|
fctxt.getTabHostname(),
|
|
|
|
fctxt.getHostname(),
|
|
|
|
requestType
|
|
|
|
);
|
|
|
|
if ( result !== 0 && result !== 3 && µb.logger.enabled ) {
|
|
|
|
fctxt.filter = µb.sessionFirewall.toLogData();
|
|
|
|
}
|
|
|
|
}
|
2015-01-06 14:01:15 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// Static filtering has lowest precedence.
|
|
|
|
if ( result === 0 || result === 3 ) {
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
const snfe = µb.staticNetFilteringEngine;
|
|
|
|
result = snfe.matchString(fctxt);
|
|
|
|
if ( result !== 0 ) {
|
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.filter = snfe.toLogData();
|
|
|
|
}
|
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/943
|
|
|
|
// Blanket-except blocked aliased canonical hostnames?
|
|
|
|
if (
|
|
|
|
result === 1 &&
|
|
|
|
fctxt.aliasURL !== undefined &&
|
|
|
|
snfe.isBlockImportant() === false &&
|
|
|
|
this.shouldExceptCname(fctxt)
|
|
|
|
) {
|
|
|
|
return 2;
|
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
|
|
|
}
|
2017-08-03 16:18:05 +02:00
|
|
|
|
2020-10-10 14:36:30 +02:00
|
|
|
// Click-to-load?
|
2020-10-09 19:50:54 +02:00
|
|
|
// When frameId is not -1, the resource is always sub_frame.
|
|
|
|
if ( result === 1 && fctxt.frameId !== -1 ) {
|
2020-10-10 14:36:30 +02:00
|
|
|
const frameStore = this.getFrameStore(fctxt.frameId);
|
|
|
|
if ( frameStore !== null && frameStore.clickToLoad ) {
|
2020-10-09 19:50:54 +02:00
|
|
|
result = 2;
|
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.setFilter({
|
|
|
|
result,
|
|
|
|
source: 'network',
|
|
|
|
raw: 'click-to-load',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-10 14:36:30 +02:00
|
|
|
// https://github.com/gorhill/uBlock/issues/949
|
|
|
|
// Redirect blocked request?
|
|
|
|
if ( result === 1 && µb.hiddenSettings.ignoreRedirectFilters !== true ) {
|
|
|
|
const redirectURL = µb.redirectEngine.toURL(fctxt);
|
|
|
|
if ( redirectURL !== undefined ) {
|
|
|
|
fctxt.redirectURL = redirectURL;
|
|
|
|
this.internalRedirectionCount += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( cacheableResult ) {
|
|
|
|
this.netFilteringCache.rememberResult(fctxt, result);
|
2020-10-10 14:36:30 +02:00
|
|
|
} else if ( result === 1 && this.collapsibleResources.has(requestType) ) {
|
|
|
|
this.netFilteringCache.rememberBlock(fctxt);
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|
2017-08-03 16:18:05 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
return result;
|
|
|
|
}
|
2015-01-24 18:06:22 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
filterCSPReport(fctxt) {
|
|
|
|
if (
|
|
|
|
µb.sessionSwitches.evaluateZ(
|
|
|
|
'no-csp-reports',
|
|
|
|
fctxt.getHostname()
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.filter = µb.sessionSwitches.toLogData();
|
|
|
|
}
|
|
|
|
return 1;
|
2017-10-19 15:35:28 +02:00
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
return 0;
|
2017-10-19 15:35:28 +02:00
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
filterFont(fctxt) {
|
|
|
|
if ( fctxt.type === 'font' ) {
|
|
|
|
this.remoteFontCount += 1;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
µb.sessionSwitches.evaluateZ(
|
|
|
|
'no-remote-fonts',
|
|
|
|
fctxt.getTabHostname()
|
|
|
|
) !== false
|
|
|
|
) {
|
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.filter = µb.sessionSwitches.toLogData();
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2017-10-19 15:35:28 +02:00
|
|
|
}
|
2019-07-05 23:44:08 +02:00
|
|
|
|
|
|
|
filterScripting(fctxt, netFiltering) {
|
|
|
|
fctxt.filter = undefined;
|
|
|
|
if ( netFiltering === undefined ) {
|
|
|
|
netFiltering = this.getNetFilteringSwitch(fctxt);
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
netFiltering === false ||
|
|
|
|
µb.sessionSwitches.evaluateZ(
|
|
|
|
'no-scripting',
|
|
|
|
fctxt.getTabHostname()
|
|
|
|
) === false
|
|
|
|
) {
|
|
|
|
return 0;
|
|
|
|
}
|
2018-12-13 18:30:54 +01:00
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.filter = µb.sessionSwitches.toLogData();
|
2017-10-19 15:35:28 +02:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2018-09-01 00:47:02 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// The caller is responsible to check whether filtering is enabled or not.
|
|
|
|
filterLargeMediaElement(fctxt, size) {
|
|
|
|
fctxt.filter = undefined;
|
2018-09-01 00:47:02 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( Date.now() < this.allowLargeMediaElementsUntil ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
µb.sessionSwitches.evaluateZ(
|
|
|
|
'no-large-media',
|
|
|
|
fctxt.getTabHostname()
|
|
|
|
) !== true
|
|
|
|
) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ( (size >>> 10) < µb.userSettings.largeMediaSize ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-08 21:53:08 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
this.largeMediaCount += 1;
|
|
|
|
if ( this.largeMediaTimer === null ) {
|
|
|
|
this.largeMediaTimer = vAPI.setTimeout(( ) => {
|
|
|
|
this.largeMediaTimer = null;
|
|
|
|
this.injectLargeMediaElementScriptlet();
|
|
|
|
}, 500);
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
if ( µb.logger.enabled ) {
|
|
|
|
fctxt.filter = µb.sessionSwitches.toLogData();
|
|
|
|
}
|
2016-11-08 21:53:08 +01:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
return 1;
|
2016-11-08 21:53:08 +01:00
|
|
|
}
|
|
|
|
|
2020-10-09 19:50:54 +02:00
|
|
|
clickToLoad(frameId, frameURL) {
|
|
|
|
let frameStore = this.getFrameStore(frameId);
|
|
|
|
if ( frameStore === null ) {
|
|
|
|
frameStore = this.setFrameURL(frameId, frameURL);
|
|
|
|
}
|
2020-10-10 14:36:30 +02:00
|
|
|
this.netFilteringCache.forgetResult(
|
|
|
|
this.tabHostname,
|
|
|
|
'sub_frame',
|
|
|
|
frameURL
|
|
|
|
);
|
|
|
|
frameStore.clickToLoad = true;
|
2020-10-09 19:50:54 +02:00
|
|
|
}
|
|
|
|
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
shouldExceptCname(fctxt) {
|
|
|
|
let exceptCname;
|
|
|
|
let frameStore;
|
|
|
|
if ( fctxt.docId !== undefined ) {
|
2020-10-09 19:50:54 +02:00
|
|
|
frameStore = this.getFrameStore(fctxt.docId);
|
Add support for `cname` type and `denyallow` option
This concerns the static network filtering engine.
Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/943
* * *
New static network filter type: `cname`
By default, network requests which are result of
resolving a canonical name are subject to filtering.
This filtering can be bypassed by creating exception
filters using the `cname` option. For example:
@@*$cname
The filter above tells the network filtering engine
to except network requests which fulfill all the
following conditions:
- network request is blocked
- network request is that of an unaliased hostname
Filter list authors are discouraged from using
exception filters of `cname` type, unless there no
other practical solution such that maintenance
burden become the greater issue. Of course, such
exception filters should be as narrow as possible,
i.e. apply to specific domain, etc.
* * *
New static network filter option: `denyallow`
The purpose of `denyallow` is bring
default-deny/allow-exceptionally ability into static
network filtering arsenal. Example of usage:
*$3p,script, \
denyallow=x.com|y.com \
domain=a.com|b.com
The above filter tells the network filtering engine that
when the context is `a.com` or `b.com`, block all
3rd-party scripts except those from `x.com` and `y.com`.
Essentially, the new `denyallow` option makes it easier
to implement default-deny/allow-exceptionally in static
filter lists, whereas before this had to be done with
unwieldy regular expressions[1], or through the mix of
broadly blocking filters along with exception filters[2].
[1] https://hg.adblockplus.org/ruadlist/rev/f362910bc9a0
[2] Typically filters which pattern are of the
form `|http*://`
2020-03-15 17:23:25 +01:00
|
|
|
if ( frameStore instanceof Object ) {
|
|
|
|
exceptCname = frameStore.exceptCname;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( exceptCname === undefined ) {
|
|
|
|
const result = µb.staticNetFilteringEngine.matchStringReverse(
|
|
|
|
'cname',
|
|
|
|
frameStore instanceof Object
|
|
|
|
? frameStore.rawURL
|
|
|
|
: fctxt.getDocOrigin()
|
|
|
|
);
|
|
|
|
if ( result === 2 ) {
|
|
|
|
exceptCname = µb.logger.enabled
|
|
|
|
? µb.staticNetFilteringEngine.toLogData()
|
|
|
|
: true;
|
|
|
|
} else {
|
|
|
|
exceptCname = false;
|
|
|
|
}
|
|
|
|
if ( frameStore instanceof Object ) {
|
|
|
|
frameStore.exceptCname = exceptCname;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( exceptCname === false ) { return false; }
|
|
|
|
if ( exceptCname instanceof Object ) {
|
|
|
|
fctxt.setFilter(exceptCname);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
getBlockedResources(request, response) {
|
|
|
|
const normalURL = µb.normalizePageURL(this.tabId, request.frameURL);
|
|
|
|
const resources = request.resources;
|
|
|
|
const fctxt = µb.filteringContext;
|
|
|
|
fctxt.fromTabId(this.tabId)
|
|
|
|
.setDocOriginFromURL(normalURL);
|
|
|
|
// Force some resources to go through the filtering engine in order to
|
|
|
|
// populate the blocked-resources cache. This is required because for
|
|
|
|
// some resources it's not possible to detect whether they were blocked
|
|
|
|
// content script-side (i.e. `iframes` -- unlike `img`).
|
|
|
|
if ( Array.isArray(resources) && resources.length !== 0 ) {
|
|
|
|
for ( const resource of resources ) {
|
2020-10-10 14:36:30 +02:00
|
|
|
this.filterRequest(
|
2020-10-09 19:50:54 +02:00
|
|
|
fctxt.setType(resource.type).setURL(resource.url)
|
2019-07-05 23:44:08 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( this.netFilteringCache.hash === response.hash ) { return; }
|
|
|
|
response.hash = this.netFilteringCache.hash;
|
|
|
|
response.blockedResources =
|
|
|
|
this.netFilteringCache.lookupAllBlocked(fctxt.getDocHostname());
|
2017-05-12 16:35:11 +02:00
|
|
|
}
|
2016-11-08 21:53:08 +01:00
|
|
|
};
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
PageStore.prototype.cacheableResults = new Set([
|
|
|
|
'sub_frame',
|
|
|
|
]);
|
2015-06-10 15:23:48 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
PageStore.prototype.collapsibleResources = new Set([
|
|
|
|
'image',
|
|
|
|
'media',
|
|
|
|
'object',
|
|
|
|
'sub_frame',
|
|
|
|
]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
µb.PageStore = PageStore;
|
2015-01-24 18:06:22 +01:00
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
// <<<<<
|
|
|
|
// end of private namespace
|
2014-06-24 00:42:43 +02:00
|
|
|
|
2019-07-05 23:44:08 +02:00
|
|
|
}
|