diff --git a/browser/components/BrowserContentHandler.jsm b/browser/components/BrowserContentHandler.jsm index e018d59536cc..74a44078fd99 100644 --- a/browser/components/BrowserContentHandler.jsm +++ b/browser/components/BrowserContentHandler.jsm @@ -231,20 +231,18 @@ function openBrowserWindow( forcePrivate = false ) { let chromeURL = AppConstants.BROWSER_CHROME_URL; + const isStartup = + cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH; let args; if (!urlOrUrlList) { // Just pass in the defaultArgs directly. We'll use system principal on the other end. - args = [gBrowserContentHandler.defaultArgs]; + args = [gBrowserContentHandler.getArgs(isStartup)]; } else { let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService( Ci.nsIToolkitProfileService ); - if ( - cmdLine && - cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH && - pService.createdAlternateProfile - ) { + if (isStartup && pService.createdAlternateProfile) { let url = getNewInstallPage(); if (Array.isArray(urlOrUrlList)) { urlOrUrlList.unshift(url); @@ -295,7 +293,7 @@ function openBrowserWindow( } } - if (cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) { + if (isStartup) { let win = Services.wm.getMostRecentWindow("navigator:blank"); if (win) { // Remove the windowtype of our blank window so that we don't close it @@ -603,6 +601,10 @@ nsBrowserContentHandler.prototype = { /* nsIBrowserHandler */ get defaultArgs() { + return this.getArgs(); + }, + + getArgs(isStartup = false) { var prefb = Services.prefs; if (!gFirstWindow) { @@ -688,6 +690,24 @@ nsBrowserContentHandler.prototype = { overridePage = ""; } + // Allow showing a one-time startup override if we're not showing one + const ONCE_PREF = "browser.startup.homepage_override.once"; + if (isStartup && overridePage == "" && prefb.prefHasUserValue(ONCE_PREF)) { + try { + // Show if we haven't passed the expiration or there's no expiration + const { expire, url } = JSON.parse( + Services.urlFormatter.formatURLPref(ONCE_PREF) + ); + if (!(Date.now() > expire) && typeof url == "string") { + overridePage = url; + } + } catch (ex) { + // Invalid json pref, so ignore (and clear below) + } finally { + prefb.clearUserPref(ONCE_PREF); + } + } + if (!additionalPage) { additionalPage = LaterRun.getURL() || ""; } diff --git a/browser/components/tests/browser/browser.ini b/browser/components/tests/browser/browser.ini index c583c5180053..037d56ee1248 100644 --- a/browser/components/tests/browser/browser.ini +++ b/browser/components/tests/browser/browser.ini @@ -7,4 +7,5 @@ reason = test depends on update channel [browser_default_bookmark_toolbar_visibility.js] [browser_initial_tab_remoteType.js] fail-if = fission +[browser_startup_homepage.js] [browser_urlbar_matchBuckets_migration60.js] diff --git a/browser/components/tests/browser/browser_bug538331.js b/browser/components/tests/browser/browser_bug538331.js index 50007de34c5c..03fda70c6600 100644 --- a/browser/components/tests/browser/browser_bug538331.js +++ b/browser/components/tests/browser/browser_bug538331.js @@ -81,8 +81,10 @@ const BCH_TESTS = [ add_task(async function test_bug538331() { // Reset the startup page pref since it may have been set by other tests - // and we will assume it is default. - Services.prefs.clearUserPref("browser.startup.page"); + // and we will assume it is (non-test) default. + await SpecialPowers.pushPrefEnv({ + clear: [["browser.startup.page"]], + }); let originalMstone = Services.prefs.getCharPref(PREF_MSTONE); diff --git a/browser/components/tests/browser/browser_startup_homepage.js b/browser/components/tests/browser/browser_startup_homepage.js new file mode 100644 index 000000000000..9df9150a28f3 --- /dev/null +++ b/browser/components/tests/browser/browser_startup_homepage.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +async function checkArgs(message, expect, prefs = {}) { + info(`Setting prefs: ${JSON.stringify(prefs)}`); + await SpecialPowers.pushPrefEnv({ + set: Object.entries(prefs).map(keyVal => { + if (typeof keyVal[1] == "object") { + keyVal[1] = JSON.stringify(keyVal[1]); + } + return keyVal; + }), + }); + + // Check the defaultArgs for startup behavior + Assert.equal( + Cc["@mozilla.org/browser/clh;1"] + .getService(Ci.nsIBrowserHandler) + .wrappedJSObject.getArgs(true), + expect, + message + ); +} + +add_task(async function test_once_expire() { + const url = "https://www.mozilla.org/"; + await checkArgs("no expiration", url, { + "browser.startup.homepage_override.once": { url }, + }); + + await checkArgs("expired", "about:blank", { + "browser.startup.homepage_override.once": { expire: 0, url }, + }); + + await checkArgs("not expired", url, { + "browser.startup.homepage_override.once": { expire: Date.now() * 2, url }, + }); +}); + +add_task(async function test_once_invalid() { + await checkArgs("not json", "about:blank", { + "browser.startup.homepage_override.once": "https://not.json", + }); + + await checkArgs("not string", "about:blank", { + "browser.startup.homepage_override.once": { url: 5 }, + }); +}); + +add_task(async function test_once() { + await checkArgs("initial test prefs (no homepage)", "about:blank"); + + const url = "https://www.mozilla.org/"; + await checkArgs("override once", url, { + "browser.startup.homepage_override.once": { url }, + }); + + await checkArgs("once cleared", "about:blank"); + + await checkArgs("formatted", "https://www.mozilla.org/en-US", { + "browser.startup.homepage_override.once": { + url: "https://www.mozilla.org/%LOCALE%", + }, + }); + + await checkArgs("use homepage", "about:home", { + "browser.startup.page": 1, + }); + + await checkArgs("once with homepage", `${url}|about:home`, { + "browser.startup.homepage_override.once": { url }, + }); + + await checkArgs("once cleared again", "about:home"); + + await checkArgs("prefer major version override", `about:welcome|about:home`, { + "browser.startup.homepage_override.mstone": "1.0", + "browser.startup.homepage_override.once": { url }, + "startup.homepage_override_url": "about:welcome", + }); + + await checkArgs("once after major", `${url}|about:home`); + + await checkArgs("once cleared yet again", "about:home"); +});