mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-11 09:31:01 +01:00
fix #2839
This commit is contained in:
parent
43512277c6
commit
eb3519b075
4 changed files with 258 additions and 357 deletions
|
@ -999,78 +999,92 @@ vAPI.domWatcher = (function() {
|
|||
/******************************************************************************/
|
||||
|
||||
vAPI.domCollapser = (function() {
|
||||
var timer = null;
|
||||
var pendingRequests = Object.create(null);
|
||||
var roundtripRequests = [];
|
||||
var resquestIdGenerator = 1,
|
||||
processTimer,
|
||||
toProcess = [],
|
||||
toFilter = [],
|
||||
toCollapse = new Map(),
|
||||
cachedBlockedSet,
|
||||
cachedBlockedSetHash,
|
||||
cachedBlockedSetTimer;
|
||||
var src1stProps = {
|
||||
'embed': 'src',
|
||||
'iframe': 'src',
|
||||
'img': 'src',
|
||||
'object': 'data'
|
||||
};
|
||||
var src2ndProps = {
|
||||
'img': 'srcset'
|
||||
};
|
||||
var netSelectorCacheCount = 0;
|
||||
var messaging = vAPI.messaging;
|
||||
|
||||
// Because a while ago I have observed constructors are faster than
|
||||
// literal object instanciations.
|
||||
var RoundtripRequest = function(tag, attr, url) {
|
||||
this.tag = tag;
|
||||
this.attr = attr;
|
||||
this.url = url;
|
||||
this.collapse = false;
|
||||
var tagToTypeMap = {
|
||||
embed: 'object',
|
||||
iframe: 'sub_frame',
|
||||
img: 'image',
|
||||
object: 'object'
|
||||
};
|
||||
var netSelectorCacheCount = 0,
|
||||
messaging = vAPI.messaging;
|
||||
var cachedBlockedSetClear = function() {
|
||||
cachedBlockedSet =
|
||||
cachedBlockedSetHash =
|
||||
cachedBlockedSetTimer = undefined;
|
||||
};
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
||||
// Do not remove fragment from src URL
|
||||
var onProcessed = function(response) {
|
||||
// This can happens if uBO is restarted.
|
||||
if ( !response ) {
|
||||
toCollapse.clear();
|
||||
return;
|
||||
}
|
||||
var requests = response.result;
|
||||
if ( requests === null || Array.isArray(requests) === false ) {
|
||||
return;
|
||||
|
||||
var targets = toCollapse.get(response.id);
|
||||
if ( targets === undefined ) { return; }
|
||||
toCollapse.delete(response.id);
|
||||
if ( cachedBlockedSetHash !== response.hash ) {
|
||||
cachedBlockedSet = new Set(response.blockedResources);
|
||||
cachedBlockedSetHash = response.hash;
|
||||
if ( cachedBlockedSetTimer !== undefined ) {
|
||||
clearTimeout(cachedBlockedSetTimer);
|
||||
}
|
||||
if ( cachedBlockedSet.size === 0 ) { return; }
|
||||
cachedBlockedSetTimer = vAPI.setTimeout(cachedBlockedSetClear, 30000);
|
||||
}
|
||||
var selectors = [],
|
||||
iframeLoadEventPatch = vAPI.iframeLoadEventPatch,
|
||||
netSelectorCacheCountMax = response.netSelectorCacheCountMax,
|
||||
aa = [ null ],
|
||||
request, key, entry, target, value;
|
||||
// https://github.com/gorhill/uBlock/issues/2256
|
||||
var iframeLoadEventPatch = vAPI.iframeLoadEventPatch;
|
||||
// Important: process in chronological order -- this ensures the
|
||||
// cached selectors are the most useful ones.
|
||||
for ( var i = 0, ni = requests.length; i < ni; i++ ) {
|
||||
request = requests[i];
|
||||
key = request.tag + ' ' + request.attr + ' ' + request.url;
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
tag, prop, src, value;
|
||||
|
||||
for ( var target of targets ) {
|
||||
tag = target.localName;
|
||||
prop = src1stProps[tag];
|
||||
if ( prop === undefined ) { continue; }
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
prop = src2ndProps[tag];
|
||||
if ( prop === undefined ) { continue; }
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) { continue; }
|
||||
}
|
||||
if ( cachedBlockedSet.has(tagToTypeMap[tag] + ' ' + src) === false ) {
|
||||
continue;
|
||||
}
|
||||
delete pendingRequests[key];
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/869
|
||||
if ( !request.collapse ) {
|
||||
continue;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/399
|
||||
// Never remove elements from the DOM, just hide them
|
||||
target.style.setProperty('display', 'none', 'important');
|
||||
target.hidden = true;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1048
|
||||
// Use attribute to construct CSS rule
|
||||
if (
|
||||
netSelectorCacheCount <= netSelectorCacheCountMax &&
|
||||
(value = target.getAttribute(prop))
|
||||
) {
|
||||
selectors.push(tag + '[' + prop + '="' + value + '"]');
|
||||
netSelectorCacheCount += 1;
|
||||
}
|
||||
if ( Array.isArray(entry) === false ) {
|
||||
aa[0] = entry;
|
||||
entry = aa;
|
||||
}
|
||||
for ( var j = 0, nj = entry.length; j < nj; j++ ) {
|
||||
target = entry[j];
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/399
|
||||
// Never remove elements from the DOM, just hide them
|
||||
target.style.setProperty('display', 'none', 'important');
|
||||
target.hidden = true;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1048
|
||||
// Use attribute to construct CSS rule
|
||||
if (
|
||||
netSelectorCacheCount <= netSelectorCacheCountMax &&
|
||||
(value = target.getAttribute(request.attr))
|
||||
) {
|
||||
selectors.push(request.tag + '[' + request.attr + '="' + value + '"]');
|
||||
netSelectorCacheCount += 1;
|
||||
}
|
||||
if ( iframeLoadEventPatch ) { iframeLoadEventPatch(target); }
|
||||
if ( iframeLoadEventPatch !== undefined ) {
|
||||
iframeLoadEventPatch(target);
|
||||
}
|
||||
}
|
||||
if ( selectors.length !== 0 ) {
|
||||
|
@ -1087,9 +1101,10 @@ vAPI.domCollapser = (function() {
|
|||
};
|
||||
|
||||
var send = function() {
|
||||
timer = null;
|
||||
processTimer = undefined;
|
||||
toCollapse.set(resquestIdGenerator, toProcess);
|
||||
// https://github.com/gorhill/uBlock/issues/1927
|
||||
// Normalize hostname to avoid trailing dot of FQHN.
|
||||
// Normalize hostname to avoid trailing dot of FQHN.
|
||||
var pageHostname = window.location.hostname || '';
|
||||
if (
|
||||
pageHostname.length &&
|
||||
|
@ -1097,62 +1112,34 @@ vAPI.domCollapser = (function() {
|
|||
) {
|
||||
pageHostname = pageHostname.slice(0, -1);
|
||||
}
|
||||
messaging.send(
|
||||
'contentscript',
|
||||
{
|
||||
what: 'filterRequests',
|
||||
pageURL: window.location.href,
|
||||
pageHostname: pageHostname,
|
||||
requests: roundtripRequests
|
||||
}, onProcessed
|
||||
);
|
||||
roundtripRequests = [];
|
||||
var msg = {
|
||||
what: 'getCollapsibleBlockedRequests',
|
||||
id: resquestIdGenerator,
|
||||
pageURL: window.location.href,
|
||||
pageHostname: pageHostname,
|
||||
resources: toFilter,
|
||||
hash: cachedBlockedSetHash
|
||||
};
|
||||
messaging.send('contentscript', msg, onProcessed);
|
||||
toProcess = [];
|
||||
toFilter = [];
|
||||
resquestIdGenerator += 1;
|
||||
};
|
||||
|
||||
var process = function(delay) {
|
||||
if ( roundtripRequests.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
if ( toProcess.length === 0 ) { return; }
|
||||
if ( delay === 0 ) {
|
||||
clearTimeout(timer);
|
||||
if ( processTimer !== undefined ) {
|
||||
clearTimeout(processTimer);
|
||||
}
|
||||
send();
|
||||
} else if ( timer === null ) {
|
||||
timer = vAPI.setTimeout(send, delay || 20);
|
||||
} else if ( processTimer === undefined ) {
|
||||
processTimer = vAPI.setTimeout(send, delay || 20);
|
||||
}
|
||||
};
|
||||
|
||||
var add = function(target) {
|
||||
var tag = target.localName;
|
||||
var prop = src1stProps[tag];
|
||||
if ( prop === undefined ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
||||
// Do not remove fragment from src URL
|
||||
var src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
prop = src2ndProps[tag];
|
||||
if ( prop === undefined ) {
|
||||
return;
|
||||
}
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var key = tag + ' ' + prop + ' ' + src,
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
pendingRequests[key] = target;
|
||||
roundtripRequests.push(new RoundtripRequest(tag, prop, src));
|
||||
} else if ( Array.isArray(entry) ) {
|
||||
entry.push(target);
|
||||
} else {
|
||||
pendingRequests[key] = [ entry, target ];
|
||||
}
|
||||
toProcess[toProcess.length] = target;
|
||||
};
|
||||
|
||||
var addMany = function(targets) {
|
||||
|
@ -1203,19 +1190,12 @@ vAPI.domCollapser = (function() {
|
|||
primeLocalIFrame(iframe);
|
||||
return;
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var key = 'iframe' + ' ' + 'src' + ' ' + src,
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
pendingRequests[key] = iframe;
|
||||
roundtripRequests.push(new RoundtripRequest('iframe', 'src', src));
|
||||
} else if ( Array.isArray(entry) ) {
|
||||
entry.push(iframe);
|
||||
} else {
|
||||
pendingRequests[key] = [ entry, iframe ];
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) { return; }
|
||||
toFilter[toFilter.length] = {
|
||||
type: 'sub_frame',
|
||||
url: iframe.src
|
||||
};
|
||||
add(iframe);
|
||||
};
|
||||
|
||||
var addIFrames = function(iframes) {
|
||||
|
@ -1226,8 +1206,10 @@ vAPI.domCollapser = (function() {
|
|||
};
|
||||
|
||||
var onResourceFailed = function(ev) {
|
||||
vAPI.domCollapser.add(ev.target);
|
||||
vAPI.domCollapser.process();
|
||||
if ( tagToTypeMap[ev.target.localName] !== undefined ) {
|
||||
vAPI.domCollapser.add(ev.target);
|
||||
vAPI.domCollapser.process();
|
||||
}
|
||||
};
|
||||
|
||||
var domChangedHandler = function(nodes) {
|
||||
|
@ -1252,7 +1234,6 @@ vAPI.domCollapser = (function() {
|
|||
// - Future requests not blocked yet
|
||||
// - Elements dynamically added to the page
|
||||
// - Elements which resource URL changes
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/7
|
||||
// Preferring getElementsByTagName over querySelectorAll:
|
||||
// http://jsperf.com/queryselectorall-vs-getelementsbytagname/145
|
||||
|
@ -1275,8 +1256,8 @@ vAPI.domCollapser = (function() {
|
|||
vAPI.shutdown.add(function() {
|
||||
document.removeEventListener('error', onResourceFailed, true);
|
||||
vAPI.domWatcher.removeListener(domChangedHandler);
|
||||
if ( timer !== null ) {
|
||||
clearTimeout(timer);
|
||||
if ( processTimer !== undefined ) {
|
||||
clearTimeout(processTimer);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -452,56 +452,6 @@ vAPI.messaging.listen('popupPanel', onMessage);
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var tagNameToRequestTypeMap = {
|
||||
'embed': 'object',
|
||||
'iframe': 'sub_frame',
|
||||
'img': 'image',
|
||||
'object': 'object'
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Evaluate many requests.
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1782
|
||||
// Treat `data:` URIs as 1st-party resources.
|
||||
|
||||
var filterRequests = function(pageStore, details) {
|
||||
var requests = details.requests;
|
||||
if ( µb.userSettings.collapseBlocked === false ) {
|
||||
return requests;
|
||||
}
|
||||
|
||||
//console.debug('messaging.js/contentscript-end.js: processing %d requests', requests.length);
|
||||
|
||||
var hostnameFromURI = µb.URI.hostnameFromURI,
|
||||
redirectEngine = µb.redirectEngine,
|
||||
punycodeURL = vAPI.punycodeURL;
|
||||
|
||||
// Create evaluation context
|
||||
var context = pageStore.createContextFromFrameHostname(details.pageHostname),
|
||||
request,
|
||||
i = requests.length;
|
||||
while ( i-- ) {
|
||||
request = requests[i];
|
||||
context.requestURL = punycodeURL(request.url);
|
||||
context.requestHostname = hostnameFromURI(context.requestURL);
|
||||
context.requestType = tagNameToRequestTypeMap[request.tag];
|
||||
if ( pageStore.filterRequest(context) !== 1 ) { continue; }
|
||||
// Redirected? (We do not hide redirected resources.)
|
||||
request.collapse = redirectEngine.matches(context) !== true;
|
||||
}
|
||||
|
||||
context.dispose();
|
||||
return requests;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
|
@ -510,14 +460,29 @@ var onMessage = function(request, sender, callback) {
|
|||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
var pageStore;
|
||||
var µb = µBlock,
|
||||
response,
|
||||
pageStore;
|
||||
if ( sender && sender.tab ) {
|
||||
pageStore = µb.pageStoreFromTabId(sender.tab.id);
|
||||
}
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getCollapsibleBlockedRequests':
|
||||
response = {
|
||||
id: request.id,
|
||||
hash: request.hash,
|
||||
netSelectorCacheCountMax: µb.cosmeticFilteringEngine.netSelectorCacheCountMax
|
||||
};
|
||||
if (
|
||||
µb.userSettings.collapseBlocked &&
|
||||
pageStore &&
|
||||
pageStore.getNetFilteringSwitch()
|
||||
) {
|
||||
pageStore.getBlockedResources(request, response);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'retrieveContentScriptParameters':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = {
|
||||
|
@ -541,15 +506,6 @@ var onMessage = function(request, sender, callback) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'filterRequests':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = {
|
||||
result: filterRequests(pageStore, request),
|
||||
netSelectorCacheCountMax: µb.cosmeticFilteringEngine.netSelectorCacheCountMax
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return vAPI.messaging.UNHANDLED;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2014-2016 Raymond Hill
|
||||
Copyright (C) 2014-2017 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
|
||||
|
@ -43,59 +43,22 @@ var µb = µBlock;
|
|||
/******************************************************************************/
|
||||
|
||||
// To mitigate memory churning
|
||||
var netFilteringResultCacheEntryJunkyard = [];
|
||||
var netFilteringResultCacheEntryJunkyardMax = 200;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var NetFilteringResultCacheEntry = function(result, type, logData) {
|
||||
this.init(result, type, logData);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.prototype.init = function(result, type, logData) {
|
||||
this.result = result;
|
||||
this.type = type;
|
||||
this.time = Date.now();
|
||||
this.logData = logData;
|
||||
return this;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.prototype.dispose = function() {
|
||||
this.result = this.type = '';
|
||||
this.logData = undefined;
|
||||
if ( netFilteringResultCacheEntryJunkyard.length < netFilteringResultCacheEntryJunkyardMax ) {
|
||||
netFilteringResultCacheEntryJunkyard.push(this);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.factory = function(result, type, logData) {
|
||||
if ( netFilteringResultCacheEntryJunkyard.length ) {
|
||||
return netFilteringResultCacheEntryJunkyard.pop().init(result, type, logData);
|
||||
}
|
||||
return new NetFilteringResultCacheEntry(result, type, logData);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// To mitigate memory churning
|
||||
var netFilteringCacheJunkyard = [];
|
||||
var netFilteringCacheJunkyardMax = 10;
|
||||
var netFilteringCacheJunkyard = [],
|
||||
netFilteringCacheJunkyardMax = 10;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var NetFilteringResultCache = function() {
|
||||
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
|
||||
this.init();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.shelfLife = 15 * 1000;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.factory = function() {
|
||||
var entry = netFilteringCacheJunkyard.pop();
|
||||
if ( entry === undefined ) {
|
||||
|
@ -109,18 +72,16 @@ NetFilteringResultCache.factory = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.init = function() {
|
||||
this.urls = Object.create(null);
|
||||
this.count = 0;
|
||||
this.shelfLife = 15 * 1000;
|
||||
this.blocked = new Map();
|
||||
this.results = new Map();
|
||||
this.hash = 0;
|
||||
this.timer = null;
|
||||
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.dispose = function() {
|
||||
this.empty();
|
||||
this.boundPruneAsyncCallback = null;
|
||||
if ( netFilteringCacheJunkyard.length < netFilteringCacheJunkyardMax ) {
|
||||
netFilteringCacheJunkyard.push(this);
|
||||
}
|
||||
|
@ -129,33 +90,42 @@ NetFilteringResultCache.prototype.dispose = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.add = function(context, result, logData) {
|
||||
var url = context.requestURL,
|
||||
type = context.requestType,
|
||||
key = type + ' ' + url,
|
||||
entry = this.urls[key];
|
||||
if ( entry !== undefined ) {
|
||||
entry.result = result;
|
||||
entry.type = type;
|
||||
entry.time = Date.now();
|
||||
entry.logData = logData;
|
||||
return;
|
||||
}
|
||||
this.urls[key] = NetFilteringResultCacheEntry.factory(result, type, logData);
|
||||
if ( this.count === 0 ) {
|
||||
NetFilteringResultCache.prototype.rememberResult = function(context, result, logData) {
|
||||
if ( this.results.size === 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
this.count += 1;
|
||||
var key = context.pageHostname + ' ' + context.requestType + ' ' + context.requestURL;
|
||||
this.results.set(key, {
|
||||
result: result,
|
||||
logData: logData,
|
||||
tstamp: Date.now()
|
||||
});
|
||||
if ( result !== 1 ) { return; }
|
||||
var now = Date.now();
|
||||
this.blocked.set(key, now);
|
||||
this.hash = now;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.rememberBlock = function(details) {
|
||||
if ( this.blocked.size === 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
var now = Date.now();
|
||||
this.blocked.set(
|
||||
details.pageHostname + ' ' + details.requestType + ' ' + details.requestURL,
|
||||
now
|
||||
);
|
||||
this.hash = now;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.empty = function() {
|
||||
for ( var key in this.urls ) {
|
||||
this.urls[key].dispose();
|
||||
}
|
||||
this.urls = Object.create(null);
|
||||
this.count = 0;
|
||||
this.blocked.clear();
|
||||
this.results.clear();
|
||||
this.hash = 0;
|
||||
if ( this.timer !== null ) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
|
@ -164,36 +134,6 @@ NetFilteringResultCache.prototype.empty = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.compareEntries = function(a, b) {
|
||||
return this.urls[b].time - this.urls[a].time;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.prune = function() {
|
||||
var keys = Object.keys(this.urls).sort(this.compareEntries.bind(this));
|
||||
var obsolete = Date.now() - this.shelfLife;
|
||||
var key, entry;
|
||||
var i = keys.length;
|
||||
while ( i-- ) {
|
||||
key = keys[i];
|
||||
entry = this.urls[key];
|
||||
if ( entry.time > obsolete ) {
|
||||
break;
|
||||
}
|
||||
entry.dispose();
|
||||
delete this.urls[key];
|
||||
}
|
||||
this.count -= keys.length - i - 1;
|
||||
if ( this.count > 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=hcVpbsDyOhM
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.pruneAsync = function() {
|
||||
if ( this.timer === null ) {
|
||||
this.timer = vAPI.setTimeout(this.boundPruneAsyncCallback, this.shelfLife * 2);
|
||||
|
@ -202,13 +142,46 @@ NetFilteringResultCache.prototype.pruneAsync = function() {
|
|||
|
||||
NetFilteringResultCache.prototype.pruneAsyncCallback = function() {
|
||||
this.timer = null;
|
||||
this.prune();
|
||||
var obsolete = Date.now() - this.shelfLife,
|
||||
entry;
|
||||
for ( entry of this.blocked ) {
|
||||
if ( entry[1] <= obsolete ) {
|
||||
this.results.delete(entry[0]);
|
||||
this.blocked.delete(entry[0]);
|
||||
}
|
||||
}
|
||||
for ( 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();
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.lookup = function(context) {
|
||||
return this.urls[context.requestType + ' ' + context.requestURL] || undefined;
|
||||
NetFilteringResultCache.prototype.lookupResult = function(context) {
|
||||
return this.results.get(
|
||||
context.pageHostname + ' ' +
|
||||
context.requestType + ' ' +
|
||||
context.requestURL
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.lookupAllBlocked = function(hostname) {
|
||||
var result = [],
|
||||
pos;
|
||||
for ( var entry of this.blocked ) {
|
||||
pos = entry[0].indexOf(' ');
|
||||
if ( entry[0].slice(0, pos) === hostname ) {
|
||||
result[result.length] = entry[0].slice(pos + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -610,24 +583,39 @@ PageStore.prototype.journalProcess = function(fromTimer) {
|
|||
PageStore.prototype.filterRequest = function(context) {
|
||||
this.logData = undefined;
|
||||
|
||||
var requestType = context.requestType;
|
||||
|
||||
// We want to short-term cache filtering results of collapsible types,
|
||||
// because they are likely to be reused, from network request handler and
|
||||
// from content script handler.
|
||||
if ( 'image media object sub_frame'.indexOf(requestType) === -1 ) {
|
||||
return this.filterRequestNoCache(context);
|
||||
}
|
||||
|
||||
if ( this.getNetFilteringSwitch() === false ) {
|
||||
this.netFilteringCache.add(context, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var entry = this.netFilteringCache.lookup(context);
|
||||
if ( entry !== undefined ) {
|
||||
this.logData = entry.logData;
|
||||
return entry.result;
|
||||
var requestType = context.requestType;
|
||||
|
||||
if ( requestType === 'csp_report' ) {
|
||||
if ( this.internalRedirectionCount !== 0 ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = { result: 1, source: 'global', raw: 'no-spurious-csp-report' };
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( requestType === 'font' ) {
|
||||
this.remoteFontCount += 1;
|
||||
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = µb.hnSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
var cacheableResult = this.cacheableResults[requestType] === true;
|
||||
|
||||
if ( cacheableResult ) {
|
||||
var entry = this.netFilteringCache.lookupResult(context);
|
||||
if ( entry !== undefined ) {
|
||||
this.logData = entry.logData;
|
||||
return entry.result;
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic URL filtering.
|
||||
|
@ -638,13 +626,13 @@ PageStore.prototype.filterRequest = function(context) {
|
|||
|
||||
// Dynamic hostname/type filtering.
|
||||
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
||||
result = µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, requestType);
|
||||
result = µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
|
||||
if ( result !== 0 && result !== 3 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Static filtering: lowest filtering precedence.
|
||||
// Static filtering has lowest precedence.
|
||||
if ( result === 0 || result === 3 ) {
|
||||
result = µb.staticNetFilteringEngine.matchString(context);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
|
@ -652,11 +640,26 @@ PageStore.prototype.filterRequest = function(context) {
|
|||
}
|
||||
}
|
||||
|
||||
this.netFilteringCache.add(context, result, this.logData);
|
||||
if ( cacheableResult ) {
|
||||
this.netFilteringCache.rememberResult(context, result, this.logData);
|
||||
} else if ( result === 1 && this.collapsibleResources[requestType] === true ) {
|
||||
this.netFilteringCache.rememberBlock(context, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
PageStore.prototype.cacheableResults = {
|
||||
sub_frame: true
|
||||
};
|
||||
|
||||
PageStore.prototype.collapsibleResources = {
|
||||
image: true,
|
||||
media: true,
|
||||
object: true,
|
||||
sub_frame: true
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// The caller is responsible to check whether filtering is enabled or not.
|
||||
|
@ -689,67 +692,28 @@ PageStore.prototype.filterLargeMediaElement = function(size) {
|
|||
return 1;
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=drW8p_dTLD4
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.filterRequestNoCache = function(context) {
|
||||
this.logData = undefined;
|
||||
|
||||
if ( this.getNetFilteringSwitch() === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var requestType = context.requestType;
|
||||
|
||||
if ( requestType === 'csp_report' ) {
|
||||
if ( this.internalRedirectionCount !== 0 ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = { result: 1, source: 'global', raw: 'no-spurious-csp-report' };
|
||||
}
|
||||
return 1;
|
||||
PageStore.prototype.getBlockedResources = function(request, response) {
|
||||
var resources = request.resources;
|
||||
if ( Array.isArray(resources) && resources.length !== 0 ) {
|
||||
var context = this.createContextFromFrameHostname(request.pageHostname);
|
||||
for ( var resource of resources ) {
|
||||
context.requestType = resource.type;
|
||||
context.requestHostname = µb.URI.hostnameFromURI(resource.url);
|
||||
context.requestURL = resource.url;
|
||||
this.filterRequest(context);
|
||||
}
|
||||
}
|
||||
|
||||
if ( requestType === 'font' ) {
|
||||
this.remoteFontCount += 1;
|
||||
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = µb.hnSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if ( this.netFilteringCache.hash === response.hash ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
|
||||
// Dynamic URL filtering.
|
||||
if ( result === 0 ) {
|
||||
result = µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionURLFiltering.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic hostname/type filtering.
|
||||
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
||||
result = µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
|
||||
if ( result !== 0 && result !== 3 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
// Static filtering has lowest precedence.
|
||||
if ( result === 0 || result === 3 ) {
|
||||
result = µb.staticNetFilteringEngine.matchString(context);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.staticNetFilteringEngine.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
response.hash = this.netFilteringCache.hash;
|
||||
response.blockedResources = this.netFilteringCache.lookupAllBlocked(request.pageHostname);
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=drW8p_dTLD4
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
return {
|
||||
|
|
|
@ -355,7 +355,7 @@ var onBeforeBehindTheSceneRequest = function(details) {
|
|||
// working properly, etc.
|
||||
// So we filter if and only if the "advanced user" mode is selected
|
||||
if ( µb.userSettings.advancedUserEnabled ) {
|
||||
result = pageStore.filterRequestNoCache(context);
|
||||
result = pageStore.filterRequest(context);
|
||||
}
|
||||
|
||||
pageStore.journalAddRequest(context.requestHostname, result);
|
||||
|
@ -450,7 +450,7 @@ var injectCSP = function(pageStore, details) {
|
|||
|
||||
context.requestType = 'inline-script';
|
||||
context.requestURL = requestURL;
|
||||
if ( pageStore.filterRequestNoCache(context) === 1 ) {
|
||||
if ( pageStore.filterRequest(context) === 1 ) {
|
||||
cspSubsets[0] = "script-src 'unsafe-eval' * blob: data:";
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=669086
|
||||
// TODO: remove when most users are beyond Chromium v56
|
||||
|
|
Loading…
Reference in a new issue