code review for c5d85881181a: mind about:blank et al. iframes

This commit is contained in:
Raymond Hill 2018-05-20 06:49:12 -04:00
parent db67c6bcc4
commit 0c5e2eb7ee
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 109 additions and 24 deletions

View File

@ -878,30 +878,28 @@ vAPI.domCollapser = (function() {
attributeFilter: [ 'src' ] attributeFilter: [ 'src' ]
}; };
// The injected scriptlets are those which were injected in the current
// document, from within `bootstrapPhase1`, and which scriptlets are
// selectively looked-up from:
// https://github.com/uBlockOrigin/uAssets/blob/master/filters/resources.txt
var primeLocalIFrame = function(iframe) { var primeLocalIFrame = function(iframe) {
// Should probably also copy injected styles.
// The injected scripts are those which were injected in the current
// document, from within the `contentscript-start.js / injectScripts`,
// and which scripts are selectively looked-up from:
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
if ( vAPI.injectedScripts ) { if ( vAPI.injectedScripts ) {
vAPI.injectScriptlet(iframe.contentDocument, vAPI.injectedScripts); vAPI.injectScriptlet(iframe.contentDocument, vAPI.injectedScripts);
} }
}; };
// https://github.com/gorhill/uBlock/issues/162
// Be prepared to deal with possible change of src attribute.
var addIFrame = function(iframe, dontObserve) { var addIFrame = function(iframe, dontObserve) {
// https://github.com/gorhill/uBlock/issues/162
// Be prepared to deal with possible change of src attribute.
if ( dontObserve !== true ) { if ( dontObserve !== true ) {
iframeSourceObserver.observe(iframe, iframeSourceObserverOptions); iframeSourceObserver.observe(iframe, iframeSourceObserverOptions);
} }
var src = iframe.src; var src = iframe.src;
if ( src === '' || typeof src !== 'string' ) { if ( src === '' || typeof src !== 'string' ) {
primeLocalIFrame(iframe); primeLocalIFrame(iframe);
return; return;
} }
if ( src.lastIndexOf('http', 0) !== 0 ) { return; } if ( src.startsWith('http') === false ) { return; }
toFilter[toFilter.length] = { toFilter[toFilter.length] = {
type: 'sub_frame', type: 'sub_frame',
url: iframe.src url: iframe.src

View File

@ -36,22 +36,109 @@
scriptletsRegister = new Map(), scriptletsRegister = new Map(),
reEscapeScriptArg = /[\\'"]/g; reEscapeScriptArg = /[\\'"]/g;
// Purpose of `contentscriptCode` below is too programmatically inject
// content script code which only purpose is to inject scriptlets. This
// essentially does the same as what uBO's declarative content script does,
// except that this allows to inject the scriptlets earlier than it is
// possible through the declarative content script.
//
// Declaratively:
// 1. Browser injects generic content script =>
// 2. Content script queries scriptlets =>
// 3. Main process sends scriptlets =>
// 4. Content script injects scriptlets
//
// Programmatically:
// 1. uBO injects specific scriptlets-aware content script =>
// 2. Content script injects scriptlets
//
// However currently this programmatic injection works well only on
// Chromium-based browsers, it does not work properly with Firefox. More
// investigations is needed to find out why this fails with Firefox.
// Consequently, the programmatic-injection code path is taken only with
// Chromium-based browsers.
let contentscriptCode = (function() { let contentscriptCode = (function() {
let parts = [ let parts = [
'(', '(',
function(hostname, scriptlets) { function(hostname, scriptlets) {
if ( hostname !== window.location.hostname ) { return; } if (
let d = document; document.location === null ||
let script = d.createElement('script'); hostname !== document.location.hostname
try { ) {
script.appendChild(d.createTextNode( return;
decodeURIComponent(scriptlets))
);
(d.head || d.documentElement).appendChild(script);
} catch (ex) {
} }
if ( script.parentNode ) { let injectScriptlets = function(d) {
script.parentNode.removeChild(script); let script = d.createElement('script');
try {
script.appendChild(d.createTextNode(
decodeURIComponent(scriptlets))
);
(d.head || d.documentElement).appendChild(script);
} catch (ex) {
}
if ( script.parentNode ) {
script.parentNode.removeChild(script);
}
};
injectScriptlets(document);
let processIFrame = function(iframe) {
let src = iframe.src;
if ( /^https?:\/\//.test(src) === false ) {
injectScriptlets(iframe.contentDocument);
}
};
let observerTimer,
observerLists = [];
let observerAsync = function() {
for ( let nodelist of observerLists ) {
for ( let node of nodelist ) {
if ( node.nodeType !== 1 ) { continue; }
if ( node.parentElement === null ) { continue; }
if ( node.localName === 'iframe' ) {
processIFrame(node);
}
if ( node.childElementCount === 0 ) { continue; }
let iframes = node.querySelectorAll('iframe');
for ( let iframe of iframes ) {
processIFrame(iframe);
}
}
}
observerLists = [];
observerTimer = undefined;
};
let ready = function(ev) {
if ( ev !== undefined ) {
window.removeEventListener(ev.type, ready);
}
let iframes = document.getElementsByTagName('iframe');
if ( iframes.length !== 0 ) {
observerLists.push(iframes);
observerTimer = setTimeout(observerAsync, 1);
}
let observer = new MutationObserver(function(mutations) {
for ( let mutation of mutations ) {
if ( mutation.addedNodes.length !== 0 ) {
observerLists.push(mutation.addedNodes);
}
}
if (
observerLists.length !== 0 &&
observerTimer === undefined
) {
observerTimer = setTimeout(observerAsync, 1);
}
});
observer.observe(
document.documentElement,
{ childList: true, subtree: true }
);
};
if ( document.readyState === 'loading' ) {
window.addEventListener('DOMContentLoaded', ready);
} else {
ready();
} }
}.toString(), }.toString(),
')(', ')(',
@ -283,9 +370,6 @@
if ( out.length === 0 ) { return; } if ( out.length === 0 ) { return; }
if ( µb.hiddenSettings.debugScriptlets ) {
out.unshift('debugger;');
}
return out.join('\n'); return out.join('\n');
}; };
@ -305,12 +389,15 @@
let scriptlets = µb.scriptletFilteringEngine.retrieve(request); let scriptlets = µb.scriptletFilteringEngine.retrieve(request);
if ( scriptlets === undefined ) { return; } if ( scriptlets === undefined ) { return; }
let code = contentscriptCode.assemble(request.hostname, scriptlets); let code = contentscriptCode.assemble(request.hostname, scriptlets);
if ( µb.hiddenSettings.debugScriptlets ) {
code = 'debugger;\n' + code;
}
chrome.tabs.executeScript( chrome.tabs.executeScript(
details.tabId, details.tabId,
{ {
code: code, code: code,
frameId: details.frameId, frameId: details.frameId,
matchAboutBlank: true, matchAboutBlank: false,
runAt: 'document_start' runAt: 'document_start'
} }
); );