Do let grow subframe dictionary grow unbound

Related discussion:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1652925

It's not clear the code here will fix the reported
issue, but I did identify that the subframe
dictionary of a very long-lived web page can
theoretically grow unbound.
This commit is contained in:
Raymond Hill 2020-07-18 07:44:26 -04:00
parent cf31d83acf
commit feabfe3793
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 36 additions and 2 deletions

View File

@ -101,6 +101,7 @@ const webext = {
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation
webNavigation: { webNavigation: {
getFrame: promisify(chrome.webNavigation, 'getFrame'), getFrame: promisify(chrome.webNavigation, 'getFrame'),
getAllFrames: promisify(chrome.webNavigation, 'getAllFrames'),
}, },
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows
windows: { windows: {

View File

@ -163,6 +163,7 @@ const FrameStore = class {
} }
init(frameURL) { init(frameURL) {
this.t0 = Date.now();
this.exceptCname = undefined; this.exceptCname = undefined;
this.rawURL = frameURL; this.rawURL = frameURL;
if ( frameURL !== undefined ) { if ( frameURL !== undefined ) {
@ -252,6 +253,7 @@ const PageStore = class {
this.frames = new Map(); this.frames = new Map();
this.setFrame(0, tabContext.rawURL); this.setFrame(0, tabContext.rawURL);
this.frameAddCount = 0;
// The current filtering context is cloned because: // The current filtering context is cloned because:
// - We may be called with or without the current context having been // - We may be called with or without the current context having been
@ -359,8 +361,39 @@ const PageStore = class {
const frameStore = this.frames.get(frameId); const frameStore = this.frames.get(frameId);
if ( frameStore !== undefined ) { if ( frameStore !== undefined ) {
frameStore.init(frameURL); frameStore.init(frameURL);
} else { return;
this.frames.set(frameId, FrameStore.factory(frameURL)); }
this.frames.set(frameId, FrameStore.factory(frameURL));
this.frameAddCount += 1;
if ( (this.frameAddCount & 0b111111) !== 0 ) { return; }
this.pruneFrames();
}
// 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
// not a critical task, so this is executed just once on a while, to avoid
// bloated dictionary of subframes.
// A TTL is used to avoid race conditions when new iframes are added
// through the webRequest API but still not yet visible through the
// webNavigation API.
async pruneFrames() {
let entries;
try {
entries = await webext.webNavigation.getAllFrames({
tabId: this.tabId
});
} catch(ex) {
}
if ( Array.isArray(entries) === false ) { return; }
const toKeep = new Set();
for ( const { frameId } of entries ) {
toKeep.add(frameId);
}
const obsolete = Date.now() - 60000;
for ( const [ frameId, { t0 } ] of this.frames ) {
if ( toKeep.has(frameId) || t0 >= obsolete ) { continue; }
this.frames.delete(frameId);
} }
} }