From 925c8d5d0c37dbc1f82e57a92e74350de2c5eab1 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Thu, 30 Dec 2021 09:24:38 -0500 Subject: [PATCH] Add setting to control suspension on network activity at launch Related discussion: - https://github.com/gorhill/uBlock/commit/a0a9497b4aca86727b314d8fc31ad345dad08ac8#commitcomment-62560291 The new setting, when disabled (enabled by default), allows a user to prevent uBO from waiting for all filter lists to be loaded before allowing network activity at launch. The setting is enabled by default, meaning uBO waits for all filter lists to be loaded in memory before unsuspending network activity. Some users may find this behavior undesirable, hence the new setting. This gives the option to potentially speed up page load at launch, at the cost of potentially not properly filtering network requests as per filter lists/rules. For platforms not supporting the suspension of network activity, the setting will merely prevent whatever mechanism exists on the platform to mitigate improper filtering of network requests at launch. For example, in Chromium-based browsers, unchecking the new setting will prevent the browser from re-loading tabs for which there was network activity while in "suspended" state at launch. --- platform/chromium/vapi-background-ext.js | 8 +++++--- platform/common/vapi-background.js | 10 ++++------ platform/firefox/vapi-background-ext.js | 8 ++++++-- src/3p-filters.html | 13 ++++++++++--- src/js/3p-filters.js | 15 ++++++++++----- src/js/background.js | 4 ++-- src/js/messaging.js | 1 + src/js/start.js | 20 ++++++++++---------- src/js/storage.js | 10 +++------- src/js/traffic.js | 17 +---------------- 10 files changed, 52 insertions(+), 54 deletions(-) diff --git a/platform/chromium/vapi-background-ext.js b/platform/chromium/vapi-background-ext.js index b40c2f14b..1369714a7 100644 --- a/platform/chromium/vapi-background-ext.js +++ b/platform/chromium/vapi-background-ext.js @@ -186,9 +186,11 @@ vAPI.Tabs = class extends vAPI.Tabs { return { cancel: true }; } - unsuspendAllRequests() { - for ( const tabId of this.suspendedTabIds ) { - vAPI.tabs.reload(tabId); + unsuspendAllRequests(discard = false) { + if ( discard !== true ) { + for ( const tabId of this.suspendedTabIds ) { + vAPI.tabs.reload(tabId); + } } this.suspendedTabIds.clear(); } diff --git a/platform/common/vapi-background.js b/platform/common/vapi-background.js index daafa7f24..ce7c90ed1 100644 --- a/platform/common/vapi-background.js +++ b/platform/common/vapi-background.js @@ -1220,12 +1220,10 @@ vAPI.Net = class { } unsuspendAllRequests() { } - suspend(force = false) { - if ( this.canSuspend() || force ) { - this.suspendDepth += 1; - } + suspend() { + this.suspendDepth += 1; } - unsuspend(all = false) { + unsuspend({ all = false, discard = false } = {}) { if ( this.suspendDepth === 0 ) { return; } if ( all ) { this.suspendDepth = 0; @@ -1233,7 +1231,7 @@ vAPI.Net = class { this.suspendDepth -= 1; } if ( this.suspendDepth !== 0 ) { return; } - this.unsuspendAllRequests(); + this.unsuspendAllRequests(discard); } canSuspend() { return false; diff --git a/platform/firefox/vapi-background-ext.js b/platform/firefox/vapi-background-ext.js index 69609f216..fc04d32dc 100644 --- a/platform/firefox/vapi-background-ext.js +++ b/platform/firefox/vapi-background-ext.js @@ -292,11 +292,15 @@ import { this.pendingRequests.push(pending); return pending.promise; } - unsuspendAllRequests() { + unsuspendAllRequests(discard = false) { const pendingRequests = this.pendingRequests; this.pendingRequests = []; for ( const entry of pendingRequests ) { - entry.resolve(this.onBeforeSuspendableRequest(entry.details)); + entry.resolve( + discard !== true + ? this.onBeforeSuspendableRequest(entry.details) + : undefined + ); } } canSuspend() { diff --git a/src/3p-filters.html b/src/3p-filters.html index 24e73095d..2eca266e8 100644 --- a/src/3p-filters.html +++ b/src/3p-filters.html @@ -24,10 +24,17 @@
-
-
+
+
-
+
+ +
+
+ +
+
+
diff --git a/src/js/3p-filters.js b/src/js/3p-filters.js index 3f1dc1081..924159c07 100644 --- a/src/js/3p-filters.js +++ b/src/js/3p-filters.js @@ -286,7 +286,8 @@ const renderFilterLists = function(soft) { // Re-insert import widget. uDom('[data-groupkey="custom"] .listEntries').append(importWidget); - uDom.nodeFromId('autoUpdate').checked = listDetails.autoUpdate === true; + uDom.nodeFromId('autoUpdate').checked = + listDetails.autoUpdate === true; uDom.nodeFromId('listsOfBlockedHostsPrompt').textContent = vAPI.i18n('3pListsOfBlockedHostsPrompt') .replace( @@ -301,6 +302,8 @@ const renderFilterLists = function(soft) { listDetails.parseCosmeticFilters === true; uDom.nodeFromId('ignoreGenericCosmeticFilters').checked = listDetails.ignoreGenericCosmeticFilters === true; + uDom.nodeFromId('suspendUntilListsAreLoaded').checked = + listDetails.suspendUntilListsAreLoaded === true; // Compute a hash of the settings so that we can keep track of changes // affecting the loading of filter lists. @@ -529,11 +532,12 @@ const buttonPurgeAllHandler = async function(hard) { /******************************************************************************/ -const autoUpdateCheckboxChanged = function() { +const userSettingCheckboxChanged = function() { + const target = event.target; messaging.send('dashboard', { what: 'userSettings', - name: 'autoUpdate', - value: this.checked, + name: target.id, + value: target.checked, }); }; @@ -683,9 +687,10 @@ self.hasUnsavedData = function() { /******************************************************************************/ -uDom('#autoUpdate').on('change', autoUpdateCheckboxChanged); +uDom('#autoUpdate').on('change', userSettingCheckboxChanged); uDom('#parseCosmeticFilters').on('change', onFilteringSettingsChanged); uDom('#ignoreGenericCosmeticFilters').on('change', onFilteringSettingsChanged); +uDom('#suspendUntilListsAreLoaded').on('change', userSettingCheckboxChanged); uDom('#buttonApply').on('click', ( ) => { buttonApplyHandler(); }); uDom('#buttonUpdate').on('click', ( ) => { buttonUpdateHandler(); }); uDom('#buttonPurgeAll').on('click', ev => { diff --git a/src/js/background.js b/src/js/background.js index 4e94b942c..5c9d95abe 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -80,7 +80,6 @@ const hiddenSettingsDefault = { requestJournalProcessPeriod: 1000, selfieAfter: 2, strictBlockingBypassDuration: 120, - suspendTabsUntilReady: 'unset', uiPopupConfig: 'unset', uiFlavor: 'unset', uiStyles: 'unset', @@ -109,6 +108,7 @@ const userSettingsDefault = { prefetchingDisabled: true, requestLogMaxEntries: 1000, showIconBadge: true, + suspendUntilListsAreLoaded: true, tooltipsDisabled: false, webrtcIPAddressHidden: false, }; @@ -214,7 +214,7 @@ const µBlock = { // jshint ignore:line readyToFilter: false, supportStats: { - launchToReadiness: '', + allReadyAfter: '', }, pageStores: new Map(), diff --git a/src/js/messaging.js b/src/js/messaging.js index 4aa038a4c..b2f7cc3d5 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -1091,6 +1091,7 @@ const getLists = async function(callback) { isUpdating: io.isUpdating(), netFilterCount: staticNetFilteringEngine.getFilterCount(), parseCosmeticFilters: µb.userSettings.parseAllABPHideFilters, + suspendUntilListsAreLoaded: µb.userSettings.suspendUntilListsAreLoaded, userFiltersPath: µb.userFiltersPath }; const [ lists, metadata ] = await Promise.all([ diff --git a/src/js/start.js b/src/js/start.js index cb3d43e4f..2702973ea 100644 --- a/src/js/start.js +++ b/src/js/start.js @@ -192,6 +192,13 @@ const onNetWhitelistReady = function(netWhitelistRaw, adminExtra) { // User settings are in memory const onUserSettingsReady = function(fetched) { + // Terminate suspended state? + if ( fetched.suspendUntilListsAreLoaded === false ) { + vAPI.net.unsuspend({ all: true, discard: true }); + ubolog(`Unsuspend network activity listener`); + µb.supportStats.unsuspendAfter = `${Date.now() - vAPI.T0} ms`; + } + // `externalLists` will be deprecated in some future, it is kept around // for forward compatibility purpose, and should reflect the content of // `importedLists`. @@ -282,13 +289,6 @@ const onHiddenSettingsReady = async function() { ubolog(`Override default webext flavor with ${tokens}`); } - // Maybe override current network listener suspend state - if ( µb.hiddenSettings.suspendTabsUntilReady === 'no' ) { - vAPI.net.unsuspend(true); - } else if ( µb.hiddenSettings.suspendTabsUntilReady === 'yes' ) { - vAPI.net.suspend(true); - } - // Maybe disable WebAssembly if ( vAPI.canWASM && µb.hiddenSettings.disableWebAssembly !== true ) { const wasmModuleFetcher = function(path) { @@ -506,11 +506,11 @@ browser.runtime.onUpdateAvailable.addListener(details => { } }); -µb.supportStats.launchToReadiness = `${Date.now() - vAPI.T0} ms`; +µb.supportStats.allReadyAfter = `${Date.now() - vAPI.T0} ms`; if ( selfieIsValid ) { - µb.supportStats.launchToReadiness += ' (selfie)'; + µb.supportStats.allReadyAfter += ' (selfie)'; } -ubolog(`All ready ${µb.supportStats.launchToReadiness} ms after launch`); +ubolog(`All ready ${µb.supportStats.allReadyAfter} ms after launch`); // <<<<< end of private scope })(); diff --git a/src/js/storage.js b/src/js/storage.js index 65d397419..2532a0eb8 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -239,12 +239,6 @@ import { if ( typeof hs[key] !== typeof hsDefault[key] ) { continue; } this.hiddenSettings[key] = hs[key]; } - if ( typeof this.hiddenSettings.suspendTabsUntilReady === 'boolean' ) { - this.hiddenSettings.suspendTabsUntilReady = - this.hiddenSettings.suspendTabsUntilReady - ? 'yes' - : 'unset'; - } this.fireDOMEvent('hiddenSettingsChanged'); }; @@ -810,7 +804,9 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { const onFilterListsReady = function(lists) { this.availableFilterLists = lists; - vAPI.net.suspend(); + if ( vAPI.net.canSuspend() ) { + vAPI.net.suspend(); + } redirectEngine.reset(); staticExtFilteringEngine.reset(); staticNetFilteringEngine.reset(); diff --git a/src/js/traffic.js b/src/js/traffic.js index d4a01bbf6..e44ca9139 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -1146,22 +1146,7 @@ const webRequest = { { urls: [ 'http://*/*', 'https://*/*' ] }, [ 'blocking', 'responseHeaders' ] ); - vAPI.net.unsuspend(true); - // Mitigation: force-reload active tabs for environments not - // supporting suspended network request listeners. - if ( - vAPI.net.canSuspend() !== true || - µb.hiddenSettings.suspendTabsUntilReady === 'no' - ) { - const tabs = await vAPI.tabs.query({ - active: true, - url: [ 'https://*/*', 'http://*/*' ], - windowType: 'normal', - }); - for ( const tab of tabs ) { - vAPI.tabs.reload(tab.id); - } - } + vAPI.net.unsuspend({ all: true }); }; })(),