This commit is contained in:
gorhill 2016-10-14 10:06:34 -04:00
parent da163bbe4b
commit cbefeb923c
5 changed files with 81 additions and 104 deletions

View File

@ -858,7 +858,8 @@ vAPI.net.registerListeners = function() {
// https://bugs.chromium.org/p/chromium/issues/detail?id=410382
// Between Chromium 38-48, plug-ins' network requests were reported as
// type "other" instead of "object".
var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent);
var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent),
is_v49_55 = /\bChrom[a-z]+\/(?:49|5[012345])\b/.test(navigator.userAgent);
// Chromium-based browsers understand only these network request types.
var validTypes = {
@ -1003,9 +1004,20 @@ vAPI.net.registerListeners = function() {
return onBeforeRequestClient(details);
};
var onHeadersReceivedClient = this.onHeadersReceived.callback;
var onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0);
var onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
// This is needed for Chromium 49-55.
var onBeforeSendHeaders = function(details) {
if ( details.type !== 'ping' || details.method !== 'POST' ) { return; }
var type = headerValue(details.requestHeaders, 'content-type');
if ( type === '' ) { return; }
if ( type.endsWith('/csp-report') ) {
details.type = 'csp_report';
return onBeforeRequestClient(details);
}
};
var onHeadersReceivedClient = this.onHeadersReceived.callback,
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
var onHeadersReceived = function(details) {
normalizeRequestDetails(details);
// Hack to work around Chromium API limitations, where requests of
@ -1033,19 +1045,17 @@ vAPI.net.registerListeners = function() {
};
var installListeners = (function() {
var listener;
var crapi = chrome.webRequest;
listener = onBeforeRequest;
//listener = function(details) {
// quickProfiler.start('onBeforeRequest');
// var r = onBeforeRequest(details);
// quickProfiler.stop();
// return r;
//};
if ( crapi.onBeforeRequest.hasListener(listener) === false ) {
if ( crapi.onBeforeRequest.hasListener(onBeforeRequest) === false ) {
crapi.onBeforeRequest.addListener(
listener,
onBeforeRequest,
{
'urls': this.onBeforeRequest.urls || ['<all_urls>'],
'types': this.onBeforeRequest.types || undefined
@ -1054,10 +1064,22 @@ vAPI.net.registerListeners = function() {
);
}
listener = onHeadersReceived;
if ( crapi.onHeadersReceived.hasListener(listener) === false ) {
// Chromium 48 and lower does not support `ping` type.
// Chromium 56 and higher does support `csp_report` stype.
if ( is_v49_55 && crapi.onBeforeSendHeaders.hasListener(onBeforeSendHeaders) === false ) {
crapi.onBeforeSendHeaders.addListener(
onBeforeSendHeaders,
{
'urls': [ '<all_urls>' ],
'types': [ 'ping' ]
},
[ 'blocking', 'requestHeaders' ]
);
}
if ( crapi.onHeadersReceived.hasListener(onHeadersReceived) === false ) {
crapi.onHeadersReceived.addListener(
listener,
onHeadersReceived,
{
'urls': this.onHeadersReceived.urls || ['<all_urls>'],
'types': onHeadersReceivedTypes

View File

@ -260,15 +260,12 @@ vAPI.browserSettings = {
case 'hyperlinkAuditing':
this.rememberOriginalValue('browser', 'send_pings');
this.rememberOriginalValue('beacon', 'enabled');
// https://github.com/gorhill/uBlock/issues/292
// "true" means "do not disable", i.e. leave entry alone
if ( settingVal ) {
this.clear('browser', 'send_pings');
this.clear('beacon', 'enabled');
} else {
this.setValue('browser', 'send_pings', false);
this.setValue('beacon', 'enabled', false);
}
break;
@ -1892,6 +1889,7 @@ var httpObserver = {
14: 'font',
15: 'media',
16: 'websocket',
17: 'csp_report',
19: 'beacon',
21: 'image'
},
@ -2156,8 +2154,8 @@ var httpObserver = {
// 'Content-Security-Policy' MUST come last in the array. Need to
// revised this eventually.
var responseHeaders = [];
var value = channel.contentLength;
var responseHeaders = [],
value = channel.contentLength;
if ( value !== -1 ) {
responseHeaders.push({ name: 'Content-Length', value: value });
}
@ -2339,9 +2337,6 @@ vAPI.net = {};
/******************************************************************************/
vAPI.net.registerListeners = function() {
// Since it's not used
this.onBeforeSendHeaders = null;
if ( typeof this.onBeforeRequest.callback === 'function' ) {
httpObserver.onBeforeRequest = this.onBeforeRequest.callback;
httpObserver.onBeforeRequestTypes = this.onBeforeRequest.types ?

View File

@ -212,7 +212,7 @@
"description":"English: "
},
"settingsHyperlinkAuditingDisabledPrompt":{
"message":"Disable hyperlink auditing/beacon",
"message":"Disable hyperlink auditing",
"description":"English: "
},
"settingsWebRTCIPAddressHiddenPrompt":{

View File

@ -313,6 +313,7 @@ PageStore.prototype.init = function(tabId) {
this.largeMediaCount = 0;
this.largeMediaTimer = null;
this.netFilteringCache = NetFilteringResultCache.factory();
this.internalRedirectionCount = 0;
this.noCosmeticFiltering = µb.hnSwitches.evaluateZ('no-cosmetic-filtering', tabContext.rootHostname) === true;
if ( µb.logger.isEnabled() && this.noCosmeticFiltering ) {
@ -614,10 +615,15 @@ PageStore.prototype.journalProcess = function(fromTimer) {
PageStore.prototype.filterRequest = function(context) {
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 sub_frame object'.indexOf(requestType) === -1 ) {
return this.filterRequestNoCache(context);
}
if ( this.getNetFilteringSwitch() === false ) {
if ( collapsibleRequestTypes.indexOf(requestType) !== -1 ) {
this.netFilteringCache.add(context, '');
}
this.netFilteringCache.add(context, '');
return '';
}
@ -629,23 +635,13 @@ PageStore.prototype.filterRequest = function(context) {
var result = '';
if ( requestType === 'font' ) {
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
result = µb.hnSwitches.toResultString();
}
this.remoteFontCount += 1;
}
// Dynamic URL filtering.
if ( result === '' ) {
µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType);
result = µb.sessionURLFiltering.toFilterString();
}
// Given that:
// - Dynamic filtering override static filtering
// - Evaluating dynamic filtering is much faster than static filtering
// We evaluate dynamic filtering first, and hopefully we can skip
// evaluation of static filtering.
// Dynamic hostname/type filtering.
if ( result === '' && µb.userSettings.advancedUserEnabled ) {
µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, requestType);
if ( µb.sessionFirewall.mustBlockOrAllow() ) {
@ -653,7 +649,7 @@ PageStore.prototype.filterRequest = function(context) {
}
}
// Static filtering never override dynamic filtering
// Static filtering has lowest precedence.
if ( result === '' || result.charAt(1) === 'n' ) {
if ( µb.staticNetFilteringEngine.matchString(context) !== undefined ) {
result = µb.staticNetFilteringEngine.toResultString(µb.logger.isEnabled());
@ -661,18 +657,11 @@ PageStore.prototype.filterRequest = function(context) {
}
//console.debug('cache MISS: PageStore.filterRequest("%s")', context.requestURL);
if ( collapsibleRequestTypes.indexOf(requestType) !== -1 ) {
this.netFilteringCache.add(context, result);
}
// console.debug('[%s, %s] = "%s"', context.requestHostname, requestType, result);
this.netFilteringCache.add(context, result);
return result;
};
// http://jsperf.com/string-indexof-vs-object
var collapsibleRequestTypes = 'image sub_frame object';
/******************************************************************************/
PageStore.prototype.filterRequestNoCache = function(context) {
@ -680,26 +669,27 @@ PageStore.prototype.filterRequestNoCache = function(context) {
return '';
}
var requestType = context.requestType;
var result = '';
var requestType = context.requestType,
result = '';
if ( requestType === 'font' ) {
if ( requestType === 'csp_report' ) {
if ( this.internalRedirectionCount !== 0 ) {
result = 'gb:no-spurious-csp-report';
}
} else if ( requestType === 'font' ) {
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
result = µb.hnSwitches.toResultString();
}
this.remoteFontCount += 1;
}
// Dynamic URL filtering.
if ( result === '' ) {
µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType);
result = µb.sessionURLFiltering.toFilterString();
}
// Given that:
// - Dynamic filtering override static filtering
// - Evaluating dynamic filtering is much faster than static filtering
// We evaluate dynamic filtering first, and hopefully we can skip
// evaluation of static filtering.
// Dynamic hostname/type filtering.
if ( result === '' && µb.userSettings.advancedUserEnabled ) {
µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
if ( µb.sessionFirewall.mustBlockOrAllow() ) {
@ -707,7 +697,7 @@ PageStore.prototype.filterRequestNoCache = function(context) {
}
}
// Static filtering never override dynamic filtering
// Static filtering has lowest precedence.
if ( result === '' || result.charAt(1) === 'n' ) {
if ( µb.staticNetFilteringEngine.matchString(context) !== undefined ) {
result = µb.staticNetFilteringEngine.toResultString(µb.logger.isEnabled());

View File

@ -45,12 +45,6 @@ var onBeforeRequest = function(details) {
return onBeforeRootFrameRequest(details);
}
// https://github.com/gorhill/uBlock/issues/870
// This work for Chromium 49+.
if ( requestType === 'beacon' ) {
return onBeforeBeacon(details);
}
// Special treatment: behind-the-scene requests
var tabId = details.tabId;
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
@ -58,8 +52,8 @@ var onBeforeRequest = function(details) {
}
// Lookup the page store associated with this tab id.
var µb = µBlock;
var pageStore = µb.pageStoreFromTabId(tabId);
var µb = µBlock,
pageStore = µb.pageStoreFromTabId(tabId);
if ( !pageStore ) {
var tabContext = µb.tabContextManager.mustLookup(tabId);
if ( vAPI.isBehindTheSceneTabId(tabContext.tabId) ) {
@ -119,6 +113,7 @@ var onBeforeRequest = function(details) {
// Redirect blocked request?
var url = µb.redirectEngine.toURL(requestContext);
if ( url !== undefined ) {
pageStore.internalRedirectionCount += 1;
if ( µb.logger.isEnabled() ) {
µb.logger.writeOne(
tabId,
@ -277,62 +272,37 @@ var toBlockDocResult = function(url, hostname, result) {
/******************************************************************************/
// Intercept and filter behind-the-scene requests.
// https://github.com/gorhill/uBlock/issues/870
// Finally, Chromium 49+ gained the ability to report network request of type
// `beacon`, so now we can block them according to the state of the
// "Disable hyperlink auditing/beacon" setting.
var onBeforeBeacon = function(details) {
var µb = µBlock;
var tabId = details.tabId;
var pageStore = µb.mustPageStoreFromTabId(tabId);
var context = pageStore.createContextFromPage();
context.requestURL = details.url;
context.requestHostname = µb.URI.hostnameFromURI(details.url);
context.requestType = details.type;
// "g" in "gb:" stands for "global setting"
var result = µb.userSettings.hyperlinkAuditingDisabled ? 'gb:' : '';
pageStore.journalAddRequest(context.requestHostname, result);
if ( µb.logger.isEnabled() ) {
µb.logger.writeOne(
tabId,
'net',
result,
details.type,
details.url,
context.rootHostname,
context.rootHostname
);
}
context.dispose();
if ( result !== '' ) {
return { cancel: true };
}
};
/******************************************************************************/
// Intercept and filter behind-the-scene requests.
var onBeforeBehindTheSceneRequest = function(details) {
var µb = µBlock;
var pageStore = µb.pageStoreFromTabId(vAPI.noTabId);
if ( !pageStore ) {
return;
}
var µb = µBlock,
pageStore = µb.pageStoreFromTabId(vAPI.noTabId);
if ( !pageStore ) { return; }
var result = '',
context = pageStore.createContextFromPage(),
requestType = details.type,
requestURL = details.url;
var context = pageStore.createContextFromPage();
var requestURL = details.url;
context.requestURL = requestURL;
context.requestHostname = µb.URI.hostnameFromURI(requestURL);
context.requestType = details.type;
context.requestType = requestType;
// "g" in "gb:" stands for "global setting"
if ( requestType === 'beacon' && µb.userSettings.hyperlinkAuditingDisabled ) {
result = 'gb:no-hyperlink-auditing';
}
// Blocking behind-the-scene requests can break a lot of stuff: prevent
// browser updates, prevent extension updates, prevent extensions from
// working properly, etc.
// So we filter if and only if the "advanced user" mode is selected
var result = '';
if ( µb.userSettings.advancedUserEnabled ) {
if ( result === '' && µb.userSettings.advancedUserEnabled ) {
result = pageStore.filterRequestNoCache(context);
}
@ -343,7 +313,7 @@ var onBeforeBehindTheSceneRequest = function(details) {
vAPI.noTabId,
'net',
result,
details.type,
requestType,
requestURL,
context.rootHostname,
context.rootHostname