mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-07 11:22:38 +01:00
This commit is contained in:
parent
9a209c33c6
commit
427d0fd0ff
@ -46,7 +46,6 @@ var µBlock = (function() { // jshint ignore:line
|
|||||||
autoUpdatePeriod: 7,
|
autoUpdatePeriod: 7,
|
||||||
ignoreRedirectFilters: false,
|
ignoreRedirectFilters: false,
|
||||||
ignoreScriptInjectFilters: false,
|
ignoreScriptInjectFilters: false,
|
||||||
streamScriptInjectFilters: false,
|
|
||||||
manualUpdateAssetFetchPeriod: 500,
|
manualUpdateAssetFetchPeriod: 500,
|
||||||
popupFontSize: 'unset',
|
popupFontSize: 'unset',
|
||||||
suspendTabsUntilReady: false,
|
suspendTabsUntilReady: false,
|
||||||
|
@ -517,16 +517,7 @@ var onMessage = function(request, sender, callback) {
|
|||||||
request.entity = µb.URI.entityFromDomain(request.domain);
|
request.entity = µb.URI.entityFromDomain(request.domain);
|
||||||
response.specificCosmeticFilters =
|
response.specificCosmeticFilters =
|
||||||
µb.cosmeticFilteringEngine.retrieveDomainSelectors(request, response);
|
µb.cosmeticFilteringEngine.retrieveDomainSelectors(request, response);
|
||||||
// If response body filtering is supported, than the scriptlets have
|
|
||||||
// already been injected.
|
|
||||||
if (
|
|
||||||
µb.canFilterResponseBody === false ||
|
|
||||||
µb.hiddenSettings.streamScriptInjectFilters !== true ||
|
|
||||||
µb.textEncode === undefined ||
|
|
||||||
µb.textEncode.normalizeCharset(request.charset) === undefined
|
|
||||||
) {
|
|
||||||
response.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
response.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
||||||
}
|
|
||||||
if ( request.isRootFrame && µb.logger.isEnabled() ) {
|
if ( request.isRootFrame && µb.logger.isEnabled() ) {
|
||||||
µb.logCosmeticFilters(tabId);
|
µb.logCosmeticFilters(tabId);
|
||||||
}
|
}
|
||||||
|
@ -572,41 +572,24 @@ var reMediaContentTypes = /^(?:audio|image|video)\//;
|
|||||||
|
|
||||||
The response body filterer is responsible for:
|
The response body filterer is responsible for:
|
||||||
|
|
||||||
- Scriptlet filtering
|
|
||||||
- HTML filtering
|
- HTML filtering
|
||||||
|
|
||||||
In the spirit of efficiency, the response body filterer works this way:
|
In the spirit of efficiency, the response body filterer works this way:
|
||||||
|
|
||||||
If:
|
If:
|
||||||
- HTML filtering: no.
|
- HTML filtering: no.
|
||||||
- Scriptlet filtering: no.
|
|
||||||
Then:
|
Then:
|
||||||
No response body filtering is initiated.
|
No response body filtering is initiated.
|
||||||
|
|
||||||
If:
|
|
||||||
- HTML filtering: no.
|
|
||||||
- Scriptlet filtering: yes.
|
|
||||||
Then:
|
|
||||||
Inject scriptlets before first chunk of response body data reported
|
|
||||||
then immediately disconnect response body data listener.
|
|
||||||
|
|
||||||
If:
|
If:
|
||||||
- HTML filtering: yes.
|
- HTML filtering: yes.
|
||||||
- Scriptlet filtering: no/yes.
|
|
||||||
Then:
|
Then:
|
||||||
Assemble all response body data into a single buffer. Once all the
|
Assemble all response body data into a single buffer. Once all the
|
||||||
response data has been received, create a document from it. Then:
|
response data has been received, create a document from it. Then:
|
||||||
- Inject scriptlets in the resulting DOM.
|
|
||||||
- Remove all DOM elements matching HTML filters.
|
- Remove all DOM elements matching HTML filters.
|
||||||
Then serialize the resulting modified document as the new response
|
Then serialize the resulting modified document as the new response
|
||||||
body.
|
body.
|
||||||
|
|
||||||
This way, the overhead is minimal for when only scriptlets need to be
|
|
||||||
injected.
|
|
||||||
|
|
||||||
If the platform does not support response body filtering, the scriptlets
|
|
||||||
will be injected the old way, through the content script.
|
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var filterDocument = (function() {
|
var filterDocument = (function() {
|
||||||
@ -658,85 +641,6 @@ var filterDocument = (function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Purpose of following helper is to disconnect from watching the stream
|
|
||||||
// if all the following conditions are fulfilled:
|
|
||||||
// - Only need to inject scriptlets.
|
|
||||||
// - Charset of resource is utf-8.
|
|
||||||
// - A well-formed doc type declaration is found at the top.
|
|
||||||
//
|
|
||||||
// When all the conditions are fulfilled, then the scriptlets are safely
|
|
||||||
// injected after the doc type declaration, and the stream listener is
|
|
||||||
// disconnected, thus removing overhead from future streaming data.
|
|
||||||
//
|
|
||||||
// If at least one of the condition is not fulfilled and scriptlets need
|
|
||||||
// to be injected, it will be done the longer way when the whole stream
|
|
||||||
// has been collated in memory.
|
|
||||||
|
|
||||||
var streamJobDone = function(filterer, responseBytes) {
|
|
||||||
if (
|
|
||||||
filterer.scriptlets === undefined ||
|
|
||||||
filterer.selectors !== undefined ||
|
|
||||||
filterer.charset === undefined
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// We need to insert after DOCTYPE, or else the browser may fall into
|
|
||||||
// quirks mode.
|
|
||||||
if ( responseBytes.byteLength < 256 ) { return false; }
|
|
||||||
var bb = new Uint8Array(responseBytes, 0, 256),
|
|
||||||
i = 0, b;
|
|
||||||
// Skip BOM if present.
|
|
||||||
if ( bb[0] === 0xEF && bb[1] === 0xBB && bb[2] === 0xBF ) { i += 3; }
|
|
||||||
// Scan for '<'
|
|
||||||
for (;;) {
|
|
||||||
b = bb[i++];
|
|
||||||
if ( b === 0x3C /* '<' */ ) { break; }
|
|
||||||
if ( b > 0x20 || i > 240 ) { return false; }
|
|
||||||
}
|
|
||||||
// Case insensitively test for '!doctype'.
|
|
||||||
if (
|
|
||||||
bb[i+0] === 0x21 /* '!' */ &&
|
|
||||||
( bb[i+1] | 0x20 ) === 0x64 /* 'd' */ &&
|
|
||||||
( bb[i+2] | 0x20 ) === 0x6F /* 'o' */ &&
|
|
||||||
( bb[i+3] | 0x20 ) === 0x63 /* 'c' */ &&
|
|
||||||
( bb[i+4] | 0x20 ) === 0x74 /* 't' */ &&
|
|
||||||
( bb[i+5] | 0x20 ) === 0x79 /* 'y' */ &&
|
|
||||||
( bb[i+6] | 0x20 ) === 0x70 /* 'p' */ &&
|
|
||||||
( bb[i+7] | 0x20 ) === 0x65 /* 'e' */
|
|
||||||
) {
|
|
||||||
i += 8;
|
|
||||||
}
|
|
||||||
// Case insensitively test for 'html'.
|
|
||||||
else if (
|
|
||||||
( bb[i+0] | 0x20 ) === 0x68 /* 'h' */ &&
|
|
||||||
( bb[i+1] | 0x20 ) === 0x74 /* 't' */ &&
|
|
||||||
( bb[i+2] | 0x20 ) === 0x6D /* 'm' */ &&
|
|
||||||
( bb[i+3] | 0x20 ) === 0x6C /* 'l' */
|
|
||||||
) {
|
|
||||||
i += 4;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Scan for '>'.
|
|
||||||
var qcount = 0;
|
|
||||||
for (;;) {
|
|
||||||
b = bb[i++];
|
|
||||||
if ( b === 0x3E /* '>' */ ) { break; }
|
|
||||||
if ( b === 0x22 /* '"' */ || b === 0x27 /* "'" */ ) { qcount += 1; }
|
|
||||||
if ( b > 0x7F || i > 240 ) { return false; }
|
|
||||||
}
|
|
||||||
// Bail out if mismatched quotes.
|
|
||||||
if ( (qcount & 1) !== 0 ) { return false; }
|
|
||||||
// We found a valid insertion point.
|
|
||||||
if ( textEncoder === undefined ) { textEncoder = new TextEncoder(); }
|
|
||||||
filterer.stream.write(new Uint8Array(responseBytes, 0, i));
|
|
||||||
filterer.stream.write(
|
|
||||||
textEncoder.encode('<script>' + filterer.scriptlets + '</script>')
|
|
||||||
);
|
|
||||||
filterer.stream.write(new Uint8Array(responseBytes, i));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var streamClose = function(filterer, buffer) {
|
var streamClose = function(filterer, buffer) {
|
||||||
if ( buffer !== undefined ) {
|
if ( buffer !== undefined ) {
|
||||||
filterer.stream.write(buffer);
|
filterer.stream.write(buffer);
|
||||||
@ -773,11 +677,6 @@ var filterDocument = (function() {
|
|||||||
// confirmed, there is nothing which can be done uBO-side to reduce
|
// confirmed, there is nothing which can be done uBO-side to reduce
|
||||||
// overhead.
|
// overhead.
|
||||||
if ( filterer.buffer === null ) {
|
if ( filterer.buffer === null ) {
|
||||||
if ( streamJobDone(filterer, ev.data) ) {
|
|
||||||
filterers.delete(this);
|
|
||||||
this.disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
filterer.buffer = new Uint8Array(ev.data);
|
filterer.buffer = new Uint8Array(ev.data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -855,11 +754,6 @@ var filterDocument = (function() {
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( filterer.scriptlets !== undefined ) {
|
|
||||||
if ( µb.scriptletFilteringEngine.apply(doc, filterer) ) {
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( modified === false ) {
|
if ( modified === false ) {
|
||||||
return streamClose(filterer);
|
return streamClose(filterer);
|
||||||
@ -909,32 +803,13 @@ var filterDocument = (function() {
|
|||||||
domain: domain,
|
domain: domain,
|
||||||
entity: µb.URI.entityFromDomain(domain),
|
entity: µb.URI.entityFromDomain(domain),
|
||||||
selectors: undefined,
|
selectors: undefined,
|
||||||
scriptlets: undefined,
|
|
||||||
buffer: null,
|
buffer: null,
|
||||||
mime: 'text/html',
|
mime: 'text/html',
|
||||||
charset: undefined
|
charset: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
request.selectors = µb.htmlFilteringEngine.retrieve(request);
|
request.selectors = µb.htmlFilteringEngine.retrieve(request);
|
||||||
|
if ( request.selectors === undefined ) { return; }
|
||||||
// https://github.com/gorhill/uBlock/issues/3526
|
|
||||||
// https://github.com/uBlockOrigin/uAssets/issues/1492
|
|
||||||
// Two distinct issues, but both are arising as a result of
|
|
||||||
// injecting scriptlets through stream filtering. So falling back
|
|
||||||
// to "slow" scriplet injection for the time being. Stream filtering
|
|
||||||
// (`##^`) should be used for when scriptlets are defeated by early
|
|
||||||
// script tags on a page.
|
|
||||||
//
|
|
||||||
if ( µb.hiddenSettings.streamScriptInjectFilters ) {
|
|
||||||
request.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
request.selectors === undefined &&
|
|
||||||
request.scriptlets === undefined
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var headers = details.responseHeaders,
|
var headers = details.responseHeaders,
|
||||||
contentType = headerValueFromName('content-type', headers);
|
contentType = headerValueFromName('content-type', headers);
|
||||||
|
Loading…
Reference in New Issue
Block a user