mirror of https://github.com/gorhill/uBlock.git
Mind discarded status of tabs when internally handling them
Related discussion: - https://bugzilla.mozilla.org/show_bug.cgi?id=1652925#c19 Content scripts should not be injected in discarded tabs, and a discarded tab should treated as if it does not exist.
This commit is contained in:
parent
3b46b2532d
commit
aed850978e
|
@ -52,38 +52,45 @@ vAPI.app.onShutdown = function() {
|
||||||
// the extension was launched. It can be used to inject content scripts
|
// the extension was launched. It can be used to inject content scripts
|
||||||
// in already opened web pages, to remove whatever nuisance could make it to
|
// in already opened web pages, to remove whatever nuisance could make it to
|
||||||
// the web pages before uBlock was ready.
|
// the web pages before uBlock was ready.
|
||||||
|
//
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1652925#c19
|
||||||
|
// Mind discarded tabs.
|
||||||
|
|
||||||
const initializeTabs = async function() {
|
const initializeTabs = async function() {
|
||||||
const manifest = browser.runtime.getManifest();
|
const manifest = browser.runtime.getManifest();
|
||||||
if ( manifest instanceof Object === false ) { return; }
|
if ( manifest instanceof Object === false ) { return; }
|
||||||
|
|
||||||
const tabs = await vAPI.tabs.query({ url: '<all_urls>' });
|
|
||||||
const toCheck = [];
|
const toCheck = [];
|
||||||
const checker = {
|
const tabIds = [];
|
||||||
file: 'js/scriptlets/should-inject-contentscript.js'
|
{
|
||||||
};
|
const checker = { file: 'js/scriptlets/should-inject-contentscript.js' };
|
||||||
|
const tabs = await vAPI.tabs.query({ url: '<all_urls>' });
|
||||||
for ( const tab of tabs ) {
|
for ( const tab of tabs ) {
|
||||||
µb.tabContextManager.commit(tab.id, tab.url);
|
if ( tab.discarded === true ) { continue; }
|
||||||
µb.bindTabToPageStats(tab.id);
|
const { id, url } = tab;
|
||||||
|
µb.tabContextManager.commit(id, url);
|
||||||
|
µb.bindTabToPageStats(id);
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/129
|
// https://github.com/chrisaljoudi/uBlock/issues/129
|
||||||
// Find out whether content scripts need to be injected
|
// Find out whether content scripts need to be injected
|
||||||
// programmatically. This may be necessary for web pages which
|
// programmatically. This may be necessary for web pages which
|
||||||
// were loaded before uBO launched.
|
// were loaded before uBO launched.
|
||||||
toCheck.push(
|
toCheck.push(
|
||||||
/^https?:\/\//.test(tab.url)
|
/^https?:\/\//.test(url)
|
||||||
? vAPI.tabs.executeScript(tab.id, checker)
|
? vAPI.tabs.executeScript(id, checker)
|
||||||
|
.then(result => result, ( ) => false)
|
||||||
: false
|
: false
|
||||||
);
|
);
|
||||||
|
tabIds.push(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const results = await Promise.all(toCheck);
|
const results = await Promise.all(toCheck);
|
||||||
for ( let i = 0; i < results.length; i++ ) {
|
for ( let i = 0; i < results.length; i++ ) {
|
||||||
const result = results[i];
|
const result = results[i];
|
||||||
if ( result.length === 0 || result[0] !== true ) { continue; }
|
if ( result.length === 0 || result[0] !== true ) { continue; }
|
||||||
// Inject dclarative content scripts programmatically.
|
// Inject declarative content scripts programmatically.
|
||||||
const tabId = tabs[i].id;
|
|
||||||
for ( const contentScript of manifest.content_scripts ) {
|
for ( const contentScript of manifest.content_scripts ) {
|
||||||
for ( const file of contentScript.js ) {
|
for ( const file of contentScript.js ) {
|
||||||
vAPI.tabs.executeScript(tabId, {
|
vAPI.tabs.executeScript(tabIds[i], {
|
||||||
file: file,
|
file: file,
|
||||||
allFrames: contentScript.all_frames,
|
allFrames: contentScript.all_frames,
|
||||||
runAt: contentScript.run_at
|
runAt: contentScript.run_at
|
||||||
|
|
|
@ -577,26 +577,22 @@ housekeep itself.
|
||||||
tabContexts.delete(this.tabId);
|
tabContexts.delete(this.tabId);
|
||||||
};
|
};
|
||||||
|
|
||||||
TabContext.prototype.onTab = function(tab) {
|
|
||||||
if ( tab ) {
|
|
||||||
this.gcTimer = vAPI.setTimeout(( ) => this.onGC(), gcPeriod);
|
|
||||||
} else {
|
|
||||||
this.destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TabContext.prototype.onGC = async function() {
|
TabContext.prototype.onGC = async function() {
|
||||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
|
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
|
||||||
// https://github.com/gorhill/uBlock/issues/1713
|
// https://github.com/gorhill/uBlock/issues/1713
|
||||||
// For unknown reasons, Firefox's setTimeout() will sometimes
|
// For unknown reasons, Firefox's setTimeout() will sometimes
|
||||||
// causes the callback function to be called immediately, bypassing
|
// causes the callback function to be called immediately, bypassing
|
||||||
// the main event loop. For now this should prevent uBO from crashing
|
// the main event loop. For now this should prevent uBO from
|
||||||
// as a result of the bad setTimeout() behavior.
|
// crashing as a result of the bad setTimeout() behavior.
|
||||||
if ( this.onGCBarrier ) { return; }
|
if ( this.onGCBarrier ) { return; }
|
||||||
this.onGCBarrier = true;
|
this.onGCBarrier = true;
|
||||||
this.gcTimer = null;
|
this.gcTimer = null;
|
||||||
const tab = await vAPI.tabs.get(this.tabId);
|
const tab = await vAPI.tabs.get(this.tabId);
|
||||||
this.onTab(tab);
|
if ( tab instanceof Object === false || tab.discarded === true ) {
|
||||||
|
this.destroy();
|
||||||
|
} else {
|
||||||
|
this.gcTimer = vAPI.setTimeout(( ) => this.onGC(), gcPeriod);
|
||||||
|
}
|
||||||
this.onGCBarrier = false;
|
this.onGCBarrier = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1074,23 +1070,19 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µBlock.updateTitle = (( ) => {
|
µBlock.updateTitle = (( ) => {
|
||||||
const tabIdToTimer = new Map();
|
const tabIdToCount = new Map();
|
||||||
const delay = 499;
|
const delay = 499;
|
||||||
|
|
||||||
const tryAgain = function(entry) {
|
const updateTitle = async function(tabId) {
|
||||||
if ( entry.count === 1 ) { return false; }
|
let count = tabIdToCount.get(tabId);
|
||||||
entry.count -= 1;
|
if ( count === undefined ) { return; }
|
||||||
tabIdToTimer.set(
|
tabIdToCount.delete(tabId);
|
||||||
entry.tabId,
|
const tab = await vAPI.tabs.get(tabId);
|
||||||
vAPI.setTimeout(( ) => { updateTitle(entry); }, delay)
|
if ( tab instanceof Object === false || tab.discarded === true ) {
|
||||||
);
|
return;
|
||||||
return true;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onTabReady = function(entry, tab) {
|
|
||||||
if ( !tab ) { return; }
|
|
||||||
const µb = µBlock;
|
const µb = µBlock;
|
||||||
const pageStore = µb.pageStoreFromTabId(entry.tabId);
|
const pageStore = µb.pageStoreFromTabId(tabId);
|
||||||
if ( pageStore === null ) { return; }
|
if ( pageStore === null ) { return; }
|
||||||
// Firefox needs this: if you detach a tab, the new tab won't have
|
// Firefox needs this: if you detach a tab, the new tab won't have
|
||||||
// its rawURL set. Concretely, this causes the logger to report an
|
// its rawURL set. Concretely, this causes the logger to report an
|
||||||
|
@ -1098,35 +1090,32 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
// TODO: Investigate for a fix vAPI-side.
|
// TODO: Investigate for a fix vAPI-side.
|
||||||
pageStore.rawURL = tab.url;
|
pageStore.rawURL = tab.url;
|
||||||
µb.pageStoresToken = Date.now();
|
µb.pageStoresToken = Date.now();
|
||||||
if ( !tab.title && tryAgain(entry) ) { return; }
|
|
||||||
// https://github.com/gorhill/uMatrix/issues/225
|
// https://github.com/gorhill/uMatrix/issues/225
|
||||||
// Sometimes title changes while page is loading.
|
// Sometimes title changes while page is loading.
|
||||||
const settled = tab.title && tab.title === pageStore.title;
|
const settled =
|
||||||
|
typeof tab.title === 'string' &&
|
||||||
|
tab.title !== '' &&
|
||||||
|
tab.title === pageStore.title;
|
||||||
pageStore.title = tab.title || tab.url || '';
|
pageStore.title = tab.title || tab.url || '';
|
||||||
if ( !settled ) {
|
if ( settled ) { return; }
|
||||||
tryAgain(entry);
|
if ( tabIdToCount.has(tabId) ) { return; }
|
||||||
}
|
count -= 1;
|
||||||
|
if ( count === 0 ) { return; }
|
||||||
|
tabIdToCount.set(tabId, count);
|
||||||
|
updateTitleAsync(tabId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTitle = async function(entry) {
|
const updateTitleAsync = function(tabId) {
|
||||||
tabIdToTimer.delete(entry.tabId);
|
vAPI.setTimeout(( ) => { updateTitle(tabId); }, delay);
|
||||||
const tab = await vAPI.tabs.get(entry.tabId);
|
|
||||||
onTabReady(entry, tab);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return function(tabId) {
|
return function(tabId) {
|
||||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
||||||
const timer = tabIdToTimer.get(tabId);
|
const count = tabIdToCount.get(tabId);
|
||||||
if ( timer !== undefined ) {
|
tabIdToCount.set(tabId, 5);
|
||||||
clearTimeout(timer);
|
if ( count === undefined ) {
|
||||||
|
updateTitleAsync(tabId);
|
||||||
}
|
}
|
||||||
tabIdToTimer.set(
|
|
||||||
tabId,
|
|
||||||
vAPI.setTimeout(
|
|
||||||
updateTitle.bind(null, { tabId: tabId, count: 5 }),
|
|
||||||
delay
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -1140,13 +1129,14 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
let pageStoreJanitorSampleAt = 0;
|
let pageStoreJanitorSampleAt = 0;
|
||||||
let pageStoreJanitorSampleSize = 10;
|
let pageStoreJanitorSampleSize = 10;
|
||||||
|
|
||||||
const pageStoreJanitor = function() {
|
|
||||||
const tabIds = Array.from(µBlock.pageStores.keys()).sort();
|
|
||||||
const checkTab = async tabId => {
|
const checkTab = async tabId => {
|
||||||
const tab = await vAPI.tabs.get(tabId);
|
const tab = await vAPI.tabs.get(tabId);
|
||||||
if ( tab ) { return; }
|
if ( tab instanceof Object && tab.discarded !== true ) { return; }
|
||||||
µBlock.unbindTabFromPageStats(tabId);
|
µBlock.unbindTabFromPageStats(tabId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pageStoreJanitor = function() {
|
||||||
|
const tabIds = Array.from(µBlock.pageStores.keys()).sort();
|
||||||
if ( pageStoreJanitorSampleAt >= tabIds.length ) {
|
if ( pageStoreJanitorSampleAt >= tabIds.length ) {
|
||||||
pageStoreJanitorSampleAt = 0;
|
pageStoreJanitorSampleAt = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue