From 114012ae119062b9bfee50a418cf185d276059a5 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 10 Jan 2021 11:56:27 -0500 Subject: [PATCH] Add ability to lookup effective context from store of frames Content scripts can't properly look up effective context for sandboxed frames. This commit add ability to extract effective context from already existing store of frames used for each tab. --- src/js/contentscript.js | 1 - src/js/messaging.js | 7 ++++++ src/js/pagestore.js | 50 ++++++++++++++++++++++++++++------------- src/js/tab.js | 25 ++++++++++++--------- src/js/traffic.js | 2 +- 5 files changed, 58 insertions(+), 27 deletions(-) diff --git a/src/js/contentscript.js b/src/js/contentscript.js index 6f29027e1..3656b4177 100644 --- a/src/js/contentscript.js +++ b/src/js/contentscript.js @@ -1735,7 +1735,6 @@ vAPI.injectScriptlet = function(doc, text) { vAPI.messaging.send('contentscript', { what: 'retrieveContentScriptParameters', url: vAPI.effectiveSelf.location.href, - charset: document.characterSet, }).then(response => { bootstrapPhase1(response); }); diff --git a/src/js/messaging.js b/src/js/messaging.js index a76ca5d82..a8cb08450 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -557,6 +557,13 @@ const retrieveContentScriptParameters = function(sender, request) { return; } + // A content script may not always be able to successfully look up the + // effective context, hence in such case we try again to look up here + // using cached information about embedded frames. + if ( frameId !== 0 && request.url.startsWith('about:') ) { + request.url = pageStore.getEffectiveFrameURL(sender); + } + const noCosmeticFiltering = pageStore.noCosmeticFiltering === true; const response = { diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 0444e2018..5667878fb 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -181,12 +181,13 @@ const frameStoreJunkyard = []; const frameStoreJunkyardMax = 50; const FrameStore = class { - constructor(frameURL) { - this.init(frameURL); + constructor(frameURL, parentId) { + this.init(frameURL, parentId); } - init(frameURL) { + init(frameURL, parentId) { this.t0 = Date.now(); + this.parentId = parentId; this.exceptCname = undefined; this.clickToLoad = false; this.rawURL = frameURL; @@ -199,7 +200,6 @@ const FrameStore = class { } dispose() { - this.exceptCname = undefined; this.rawURL = this.hostname = this.domain = ''; if ( frameStoreJunkyard.length < frameStoreJunkyardMax ) { frameStoreJunkyard.push(this); @@ -207,12 +207,12 @@ const FrameStore = class { return null; } - static factory(frameURL) { + static factory(frameURL, parentId = -1) { const entry = frameStoreJunkyard.pop(); if ( entry === undefined ) { - return new FrameStore(frameURL); + return new FrameStore(frameURL, parentId); } - return entry.init(frameURL); + return entry.init(frameURL, parentId); } }; @@ -277,7 +277,7 @@ const PageStore = class { this.frameAddCount = 0; this.frames = new Map(); - this.setFrameURL(0, tabContext.rawURL); + this.setFrameURL({ url: tabContext.rawURL }); // https://github.com/uBlockOrigin/uBlock-issues/issues/314 const masterSwitch = tabContext.getNetFilteringSwitch(); @@ -324,7 +324,7 @@ const PageStore = class { // As part of https://github.com/chrisaljoudi/uBlock/issues/405 // URL changed, force a re-evaluation of filtering switch this.rawURL = tabContext.rawURL; - this.setFrameURL(0, this.rawURL); + this.setFrameURL({ url: this.rawURL }); return this; } @@ -375,14 +375,20 @@ const PageStore = class { return this.frames.get(frameId) || null; } - setFrameURL(frameId, frameURL) { + setFrameURL(details) { + let { frameId, url, parentFrameId } = details; + if ( frameId === undefined ) { frameId = 0; } + if ( parentFrameId === undefined ) { parentFrameId = -1; } let frameStore = this.frames.get(frameId); if ( frameStore !== undefined ) { - return frameURL === frameStore.rawURL - ? frameStore - : frameStore.init(frameURL); + if ( url === frameStore.rawURL ) { + frameStore.parentId = parentFrameId; + } else { + frameStore.init(url, parentFrameId); + } + return frameStore; } - frameStore = FrameStore.factory(frameURL); + frameStore = FrameStore.factory(url, parentFrameId); this.frames.set(frameId, frameStore); this.frameAddCount += 1; if ( (this.frameAddCount & 0b111111) === 0 ) { @@ -391,6 +397,20 @@ const PageStore = class { return frameStore; } + getEffectiveFrameURL(sender) { + let { frameId } = sender; + for (;;) { + const frameStore = this.getFrameStore(frameId); + if ( frameStore === null ) { break; } + if ( frameStore.rawURL.startsWith('about:') === false ) { + return frameStore.rawURL; + } + frameId = frameStore.parentId; + if ( frameId === -1 ) { break; } + } + return sender.frameURL; + } + // 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 @@ -851,7 +871,7 @@ const PageStore = class { clickToLoad(frameId, frameURL) { let frameStore = this.getFrameStore(frameId); if ( frameStore === null ) { - frameStore = this.setFrameURL(frameId, frameURL); + frameStore = this.setFrameURL({ frameId, url: frameURL }); } this.netFilteringCache.forgetResult( this.tabHostname, diff --git a/src/js/tab.js b/src/js/tab.js index ebdce0c42..fe04dbe08 100644 --- a/src/js/tab.js +++ b/src/js/tab.js @@ -875,18 +875,23 @@ vAPI.Tabs = class extends vAPI.Tabs { onNavigation(details) { super.onNavigation(details); const µb = µBlock; - if ( details.frameId === 0 ) { - µb.tabContextManager.commit(details.tabId, details.url); - let pageStore = µb.bindTabToPageStore(details.tabId, 'tabCommitted'); - if ( pageStore ) { - pageStore.journalAddRootFrame('committed', details.url); + const { frameId, tabId, url } = details; + if ( frameId === 0 ) { + µb.tabContextManager.commit(tabId, url); + const pageStore = µb.bindTabToPageStore(tabId, 'tabCommitted'); + if ( pageStore !== null ) { + pageStore.journalAddRootFrame('committed', url); } } - if ( µb.canInjectScriptletsNow && µb.URI.isNetworkURI(details.url) ) { - const pageStore = µb.pageStoreFromTabId(details.tabId); - if ( pageStore !== null && pageStore.getNetFilteringSwitch() ) { - µb.scriptletFilteringEngine.injectNow(details); - } + const pageStore = µb.pageStoreFromTabId(tabId); + if ( pageStore === null ) { return; } + pageStore.setFrameURL(details); + if ( + µb.canInjectScriptletsNow && + µb.URI.isNetworkURI(url) && + pageStore.getNetFilteringSwitch() + ) { + µb.scriptletFilteringEngine.injectNow(details); } } diff --git a/src/js/traffic.js b/src/js/traffic.js index ce25ef13c..5ebf7586b 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -113,7 +113,7 @@ const onBeforeRequest = function(details) { details.parentFrameId !== -1 && details.aliasURL === undefined ) { - pageStore.setFrameURL(details.frameId, details.url); + pageStore.setFrameURL(details); } if ( result === 2 ) {