diff -Nru firefox-90.0.1+build1/browser/app/profile/firefox.js firefox-90.0.2+build1/browser/app/profile/firefox.js --- firefox-90.0.1+build1/browser/app/profile/firefox.js 2021-07-21 14:59:19.000000000 +0000 +++ firefox-90.0.2+build1/browser/app/profile/firefox.js 2021-07-22 11:15:13.000000000 +0000 @@ -2046,17 +2046,6 @@ // Preference that allows individual users to disable Screenshots. pref("extensions.screenshots.disabled", false); -// DoH Rollout: whether to enable automatic performance-based TRR-selection. -// This pref is controlled by a Normandy rollout so we don't overload providers. -pref("doh-rollout.trr-selection.enabled", false); - -// DoH Rollout: whether to enable automatic steering to provider endpoints. -// This pref is also controlled by a Normandy rollout. -pref("doh-rollout.provider-steering.enabled", true); - -// DoH Rollout: provider details for automatic steering. -pref("doh-rollout.provider-steering.provider-list", "[{ \"name\": \"comcast\", \"canonicalName\": \"doh-discovery.xfinity.com\", \"uri\": \"https://doh.xfinity.com/dns-query\" }]"); - // DoH Rollout: whether to clear the mode value at shutdown. pref("doh-rollout.clearModeOnShutdown", false); diff -Nru firefox-90.0.1+build1/browser/components/doh/DoHConfig.jsm firefox-90.0.2+build1/browser/components/doh/DoHConfig.jsm --- firefox-90.0.1+build1/browser/components/doh/DoHConfig.jsm 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/DoHConfig.jsm 2021-07-22 11:15:14.000000000 +0000 @@ -26,36 +26,40 @@ const kGlobalPrefBranch = "doh-rollout"; var kRegionPrefBranch; -const kEnabledPref = "enabled"; - -const kProvidersPref = "provider-list"; - -const kTRRSelectionEnabledPref = "trr-selection.enabled"; -const kTRRSelectionProvidersPref = "trr-selection.provider-list"; -const kTRRSelectionCommitResultPref = "trr-selection.commit-result"; - -const kProviderSteeringEnabledPref = "provider-steering.enabled"; -const kProviderSteeringListPref = "provider-steering.provider-list"; +const kConfigPrefs = { + kEnabledPref: "enabled", + kProvidersPref: "provider-list", + kTRRSelectionEnabledPref: "trr-selection.enabled", + kTRRSelectionProvidersPref: "trr-selection.provider-list", + kTRRSelectionCommitResultPref: "trr-selection.commit-result", + kProviderSteeringEnabledPref: "provider-steering.enabled", + kProviderSteeringListPref: "provider-steering.provider-list", +}; const kPrefChangedTopic = "nsPref:changed"; const gProvidersCollection = RemoteSettings("doh-providers"); const gConfigCollection = RemoteSettings("doh-config"); -function getPrefValueRegionFirst(prefName, defaultValue) { - return ( - Preferences.get(`${kRegionPrefBranch}.${prefName}`) || - Preferences.get(`${kGlobalPrefBranch}.${prefName}`, defaultValue) - ); +function getPrefValueRegionFirst(prefName) { + let regionalPrefName = `${kRegionPrefBranch}.${prefName}`; + let regionalPrefValue = Preferences.get(regionalPrefName); + if (regionalPrefValue !== undefined) { + return regionalPrefValue; + } + return Preferences.get(`${kGlobalPrefBranch}.${prefName}`); } function getProviderListFromPref(prefName) { - try { - return JSON.parse(getPrefValueRegionFirst(prefName, "[]")); - } catch (e) { - Cu.reportError(`DoH provider list not a valid JSON array: ${prefName}`); + let prefVal = getPrefValueRegionFirst(prefName); + if (prefVal) { + try { + return JSON.parse(prefVal); + } catch (e) { + Cu.reportError(`DoH provider list not a valid JSON array: ${prefName}`); + } } - return []; + return undefined; } // Generate a base config object with getters that return pref values. When @@ -65,43 +69,94 @@ // from it, we lose the ability to override getters because they are defined // as non-configureable properties on class instances. So just use a function. function makeBaseConfigObject() { - return { - get enabled() { - return getPrefValueRegionFirst(kEnabledPref, false); - }, - - get providerList() { - return getProviderListFromPref(kProvidersPref); - }, - - get fallbackProviderURI() { - return this.providerList[0]?.uri; - }, - - trrSelection: { - get enabled() { - return getPrefValueRegionFirst(kTRRSelectionEnabledPref, false); - }, - - get commitResult() { - return getPrefValueRegionFirst(kTRRSelectionCommitResultPref, false); - }, - - get providerList() { - return getProviderListFromPref(kTRRSelectionProvidersPref); - }, - }, - - providerSteering: { - get enabled() { - return getPrefValueRegionFirst(kProviderSteeringEnabledPref, false); + function makeConfigProperty({ + obj, + propName, + defaultVal, + prefName, + isProviderList, + }) { + let prefFn = isProviderList + ? getProviderListFromPref + : getPrefValueRegionFirst; + + let overridePropName = "_" + propName; + + Object.defineProperty(obj, propName, { + get() { + // If a pref value exists, it gets top priority. Otherwise, if it has an + // explicitly set value (from Remote Settings), we return that. + let prefVal = prefFn(prefName); + if (prefVal !== undefined) { + return prefVal; + } + if (this[overridePropName] !== undefined) { + return this[overridePropName]; + } + return defaultVal; }, - - get providerList() { - return getProviderListFromPref(kProviderSteeringListPref); + set(val) { + this[overridePropName] = val; }, + }); + } + let newConfig = { + get fallbackProviderURI() { + return this.providerList[0]?.uri; }, + trrSelection: {}, + providerSteering: {}, }; + makeConfigProperty({ + obj: newConfig, + propName: "enabled", + defaultVal: false, + prefName: kConfigPrefs.kEnabledPref, + isProviderList: false, + }); + makeConfigProperty({ + obj: newConfig, + propName: "providerList", + defaultVal: [], + prefName: kConfigPrefs.kProvidersPref, + isProviderList: true, + }); + makeConfigProperty({ + obj: newConfig.trrSelection, + propName: "enabled", + defaultVal: false, + prefName: kConfigPrefs.kTRRSelectionEnabledPref, + isProviderList: false, + }); + makeConfigProperty({ + obj: newConfig.trrSelection, + propName: "commitResult", + defaultVal: false, + prefName: kConfigPrefs.kTRRSelectionCommitResultPref, + isProviderList: false, + }); + makeConfigProperty({ + obj: newConfig.trrSelection, + propName: "providerList", + defaultVal: [], + prefName: kConfigPrefs.kTRRSelectionProvidersPref, + isProviderList: true, + }); + makeConfigProperty({ + obj: newConfig.providerSteering, + propName: "enabled", + defaultVal: false, + prefName: kConfigPrefs.kProviderSteeringEnabledPref, + isProviderList: false, + }); + makeConfigProperty({ + obj: newConfig.providerSteering, + propName: "providerList", + defaultVal: [], + prefName: kConfigPrefs.kProviderSteeringListPref, + isProviderList: true, + }); + return newConfig; } const DoHConfigController = { @@ -172,10 +227,16 @@ observe(subject, topic, data) { switch (topic) { case kPrefChangedTopic: + let allowedPrefs = Object.getOwnPropertyNames(kConfigPrefs).map( + k => kConfigPrefs[k] + ); if ( - !data.startsWith(kRegionPrefBranch) && - data != `${kGlobalPrefBranch}.${kEnabledPref}` && - data != `${kGlobalPrefBranch}.${kProvidersPref}` + !allowedPrefs.some(pref => + [ + `${kRegionPrefBranch}.${pref}`, + `${kGlobalPrefBranch}.${pref}`, + ].includes(data) + ) ) { break; } @@ -220,7 +281,6 @@ } if (localConfig.rolloutEnabled) { - delete newConfig.enabled; newConfig.enabled = true; } @@ -242,7 +302,6 @@ let regionalProviders = parseProviderList(localConfig.providers); if (regionalProviders?.length) { - delete newConfig.providerList; newConfig.providerList = regionalProviders; } @@ -252,10 +311,7 @@ p => p.canonicalName?.length ); if (steeringProviders?.length) { - delete newConfig.providerSteering.providerList; newConfig.providerSteering.providerList = steeringProviders; - - delete newConfig.providerSteering.enabled; newConfig.providerSteering.enabled = true; } } @@ -265,10 +321,7 @@ localConfig.autoDefaultProviders ); if (defaultProviders?.length) { - delete newConfig.trrSelection.providerList; newConfig.trrSelection.providerList = defaultProviders; - - delete newConfig.trrSelection.enabled; newConfig.trrSelection.enabled = true; } } diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/browser_providerSteering.js firefox-90.0.2+build1/browser/components/doh/test/browser/browser_providerSteering.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/browser_providerSteering.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/browser_providerSteering.js 2021-07-22 11:15:14.000000000 +0000 @@ -29,10 +29,13 @@ uri: "https://bar.provider2.com/query", }, ]; + let configFlushPromise = DoHTestUtils.waitForConfigFlush(); Preferences.set( prefs.PROVIDER_STEERING_LIST_PREF, JSON.stringify(providerTestcases) ); + await configFlushPromise; + await checkHeuristicsTelemetry("enable_doh", "startup"); let testNetChangeResult = async ( expectedURI, diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js firefox-90.0.2+build1/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js 2021-07-22 11:15:14.000000000 +0000 @@ -7,6 +7,18 @@ add_task(setup); add_task(setupRegion); +async function setPrefAndWaitForConfigFlush(pref, value) { + let configFlushedPromise = DoHTestUtils.waitForConfigFlush(); + Preferences.set(pref, value); + await configFlushedPromise; +} + +async function clearPrefAndWaitForConfigFlush(pref, value) { + let configFlushedPromise = DoHTestUtils.waitForConfigFlush(); + Preferences.reset(pref); + await configFlushedPromise; +} + add_task(async function testNewProfile() { is( DoHConfigController.currentConfig.enabled, @@ -52,6 +64,7 @@ "Rollout should be enabled" ); await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); Assert.deepEqual( DoHConfigController.currentConfig.providerList, [provider1, provider3], @@ -83,6 +96,46 @@ "Fallback provider URI should be that of the first one" ); + // Test that overriding with prefs works. + await setPrefAndWaitForConfigFlush(prefs.PROVIDER_STEERING_PREF, false); + is( + DoHConfigController.currentConfig.providerSteering.enabled, + false, + "Provider steering should be disabled" + ); + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); + + await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_ENABLED_PREF, false); + is( + DoHConfigController.currentConfig.trrSelection.enabled, + false, + "TRR selection should be disabled" + ); + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); + + // Try a regional pref this time + await setPrefAndWaitForConfigFlush( + `${kRegionalPrefNamespace}.enabled`, + false + ); + is( + DoHConfigController.currentConfig.enabled, + false, + "Rollout should be disabled" + ); + await ensureTRRMode(undefined); + await ensureNoHeuristicsTelemetry(); + + await clearPrefAndWaitForConfigFlush(`${kRegionalPrefNamespace}.enabled`); + + is( + DoHConfigController.currentConfig.enabled, + true, + "Rollout should be enabled" + ); + await DoHTestUtils.resetRemoteSettingsConfig(); is( diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/browser_remoteSettings_rollout.js firefox-90.0.2+build1/browser/components/doh/test/browser/browser_remoteSettings_rollout.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/browser_remoteSettings_rollout.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/browser_remoteSettings_rollout.js 2021-07-22 11:15:14.000000000 +0000 @@ -8,6 +8,8 @@ add_task(setupRegion); add_task(async function testPrefFirstRollout() { + let defaults = Services.prefs.getDefaultBranch(""); + setPassingHeuristics(); is( @@ -17,7 +19,7 @@ ); let configFlushedPromise = DoHTestUtils.waitForConfigFlush(); - Preferences.set(`${kRegionalPrefNamespace}.enabled`, true); + defaults.setBoolPref(`${kRegionalPrefNamespace}.enabled`, true); await configFlushedPromise; is( @@ -47,9 +49,8 @@ "Rollout should still be enabled" ); - let configUpdatedPromise = DoHTestUtils.waitForConfigUpdate(); - Preferences.reset(`${kRegionalPrefNamespace}.enabled`); - await configUpdatedPromise; + defaults.deleteBranch(`${kRegionalPrefNamespace}.enabled`); + await restartDoHController(); is( DoHConfigController.currentConfig.enabled, diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/browser_trrSelection_disable.js firefox-90.0.2+build1/browser/components/doh/test/browser/browser_trrSelection_disable.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/browser_trrSelection_disable.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/browser_trrSelection_disable.js 2021-07-22 11:15:14.000000000 +0000 @@ -7,8 +7,12 @@ add_task(setup); add_task(async function testTrrSelectionDisable() { - // Set up a passing environment and enable DoH. + // Turn off TRR Selection. + let configFlushed = DoHTestUtils.waitForConfigFlush(); Preferences.set(prefs.TRR_SELECT_ENABLED_PREF, false); + await configFlushed; + + // Set up a passing environment and enable DoH. setPassingHeuristics(); let promise = waitForDoorhanger(); Preferences.set(prefs.ENABLED_PREF, true); diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/browser_trrSelect.js firefox-90.0.2+build1/browser/components/doh/test/browser/browser_trrSelect.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/browser_trrSelect.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/browser_trrSelect.js 2021-07-22 11:15:14.000000000 +0000 @@ -4,6 +4,22 @@ "use strict"; +async function waitForStartup() { + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); +} + +async function setPrefAndWaitForConfigFlush(pref, value) { + let configFlushed = DoHTestUtils.waitForConfigFlush(); + if (value) { + Preferences.set(pref, value); + } else { + Preferences.reset(pref); + } + await configFlushed; + await waitForStartup(); +} + add_task(setup); add_task(async function testTRRSelect() { @@ -26,25 +42,22 @@ // Reset and restart the controller for good measure. Preferences.reset(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF); Preferences.reset(prefs.TRR_SELECT_URI_PREF); - - prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); await restartDoHController(); - await prefPromise; + await waitForStartup(); + is( Preferences.get(prefs.TRR_SELECT_URI_PREF), "https://example.com/dns-query", "TRR selection complete." ); - // Wait for heuristics to complete. - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); - - // Disable committing and reset. The committed URI should be reset to the + // Disable committing. The committed URI should be reset to the // default provider and the dry-run-result should persist. - Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, false); - prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); - await restartDoHController(); + prefPromise = TestUtils.waitForPrefChange( + prefs.TRR_SELECT_URI_PREF, + newVal => newVal == "https://example.com/1" + ); + await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_COMMIT_PREF, false); await prefPromise; is( Preferences.get(prefs.TRR_SELECT_URI_PREF), @@ -65,15 +78,13 @@ "dry-run result has the correct value." ); - // Wait for heuristics to complete. - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); - - // Reset and restart again, dry-run-result should be recorded but not + // Reset again, dry-run-result should be recorded but not // be committed. Committing is still disabled from above. Preferences.reset(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF); Preferences.reset(prefs.TRR_SELECT_URI_PREF); await restartDoHController(); + await waitForStartup(); + try { await BrowserTestUtils.waitForCondition(() => { return ( @@ -95,11 +106,6 @@ "https://example.com/dns-query", "TRR selection complete, dry-run result recorded." ); - Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, true); - - // Wait for heuristics to complete. - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); // Reset doh-rollout.uri, and change the dry-run-result to another one on the // default list. After init, the existing dry-run-result should be committed. @@ -112,7 +118,7 @@ prefs.TRR_SELECT_URI_PREF, newVal => newVal == "https://example.com/2" ); - await restartDoHController(); + await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_COMMIT_PREF, true); await prefPromise; is( Preferences.get(prefs.TRR_SELECT_URI_PREF), @@ -120,18 +126,17 @@ "TRR selection complete, existing dry-run-result committed." ); - // Wait for heuristics to complete. - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); - // Reset doh-rollout.uri, and change the dry-run-result to another one NOT on // default list. After init, a new TRR should be selected and committed. + prefPromise = TestUtils.waitForPrefChange( + prefs.TRR_SELECT_URI_PREF, + newVal => newVal == "https://example.com/dns-query" + ); Preferences.reset(prefs.TRR_SELECT_URI_PREF); Preferences.set( prefs.TRR_SELECT_DRY_RUN_RESULT_PREF, "https://example.com/4" ); - prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); await restartDoHController(); await prefPromise; is( @@ -139,8 +144,4 @@ "https://example.com/dns-query", "TRR selection complete, existing dry-run-result discarded and refreshed." ); - - // Wait for heuristics to complete. - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); }); diff -Nru firefox-90.0.1+build1/browser/components/doh/test/browser/head.js firefox-90.0.2+build1/browser/components/doh/test/browser/head.js --- firefox-90.0.1+build1/browser/components/doh/test/browser/head.js 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/doh/test/browser/head.js 2021-07-22 11:15:14.000000000 +0000 @@ -86,9 +86,10 @@ // Avoid non-local connections to the TRR endpoint. Preferences.set(prefs.CONFIRMATION_NS_PREF, "skip"); - // Enable trr selection for tests. This is off by default so it can be - // controlled via Normandy. + // Enable trr selection and provider steeringfor tests. This is off + // by default so it can be controlled via Normandy. Preferences.set(prefs.TRR_SELECT_ENABLED_PREF, true); + Preferences.set(prefs.PROVIDER_STEERING_PREF, true); // Enable committing the TRR selection. This pref ships false by default so // it can be controlled e.g. via Normandy, but for testing let's set enable. @@ -210,11 +211,11 @@ events = Services.telemetry.snapshotEvents( Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS ).parent; - return events && events.length; + events = events?.filter( + e => e[1] == "doh" && e[2] == "evaluate_v2" && e[3] == "heuristics" + ); + return events?.length; }); - events = events.filter( - e => e[1] == "doh" && e[2] == "evaluate_v2" && e[3] == "heuristics" - ); is(events.length, 1, "Found the expected heuristics event."); is(events[0][4], decision, "The event records the expected decision"); if (evaluateReason) { diff -Nru firefox-90.0.1+build1/browser/components/newtab/content-src/components/CustomizeMenu/CustomizeMenu.jsx firefox-90.0.2+build1/browser/components/newtab/content-src/components/CustomizeMenu/CustomizeMenu.jsx --- firefox-90.0.1+build1/browser/components/newtab/content-src/components/CustomizeMenu/CustomizeMenu.jsx 2021-07-21 14:59:20.000000000 +0000 +++ firefox-90.0.2+build1/browser/components/newtab/content-src/components/CustomizeMenu/CustomizeMenu.jsx 2021-07-22 11:15:14.000000000 +0000 @@ -38,9 +38,9 @@ appear={true} >