Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
var EXPORTED_SYMBOLS = [
6
"nsBrowserContentHandler",
7
"nsDefaultCommandLineHandler",
8
];
9
10
const { XPCOMUtils } = ChromeUtils.import(
12
);
13
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
14
const { AppConstants } = ChromeUtils.import(
16
);
17
18
XPCOMUtils.defineLazyModuleGetters(this, {
19
AboutPrivateBrowsingHandler:
21
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
30
RemotePages:
32
});
33
XPCOMUtils.defineLazyServiceGetter(
34
this,
35
"WindowsUIUtils",
36
"@mozilla.org/windows-ui-utils;1",
37
"nsIWindowsUIUtils"
38
);
39
XPCOMUtils.defineLazyServiceGetter(
40
this,
41
"UpdateManager",
42
"@mozilla.org/updates/update-manager;1",
43
"nsIUpdateManager"
44
);
45
46
XPCOMUtils.defineLazyGetter(this, "gSystemPrincipal", () =>
47
Services.scriptSecurityManager.getSystemPrincipal()
48
);
49
XPCOMUtils.defineLazyGlobalGetters(this, [URL]);
50
51
const NEWINSTALL_PAGE = "about:newinstall";
52
53
// One-time startup homepage override configurations
54
const ONCE_DOMAINS = ["mozilla.org", "firefox.com"];
55
const ONCE_PREF = "browser.startup.homepage_override.once";
56
57
function shouldLoadURI(aURI) {
58
if (aURI && !aURI.schemeIs("chrome")) {
59
return true;
60
}
61
62
dump("*** Preventing external load of chrome: URI into browser window\n");
63
dump(" Use --chrome <uri> instead\n");
64
return false;
65
}
66
67
function resolveURIInternal(aCmdLine, aArgument) {
68
var uri = aCmdLine.resolveURI(aArgument);
69
var uriFixup = Services.uriFixup;
70
71
if (!(uri instanceof Ci.nsIFileURL)) {
72
return uriFixup.createFixupURI(
73
aArgument,
74
uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
75
);
76
}
77
78
try {
79
if (uri.file.exists()) {
80
return uri;
81
}
82
} catch (e) {
83
Cu.reportError(e);
84
}
85
86
// We have interpreted the argument as a relative file URI, but the file
87
// doesn't exist. Try URI fixup heuristics: see bug 290782.
88
89
try {
90
uri = uriFixup.createFixupURI(aArgument, 0);
91
} catch (e) {
92
Cu.reportError(e);
93
}
94
95
return uri;
96
}
97
98
let gKiosk = false;
99
100
let gRemoteInstallPage = null;
101
102
function getNewInstallPage() {
103
if (!gRemoteInstallPage) {
104
gRemoteInstallPage = new RemotePages(NEWINSTALL_PAGE);
105
}
106
107
return NEWINSTALL_PAGE;
108
}
109
110
var gFirstWindow = false;
111
112
const OVERRIDE_NONE = 0;
113
const OVERRIDE_NEW_PROFILE = 1;
114
const OVERRIDE_NEW_MSTONE = 2;
115
const OVERRIDE_NEW_BUILD_ID = 3;
116
const OVERRIDE_ALTERNATE_PROFILE = 4;
117
/**
118
* Determines whether a home page override is needed.
119
* Returns:
120
* OVERRIDE_NEW_PROFILE if this is the first run with a new profile.
121
* OVERRIDE_NEW_MSTONE if this is the first run with a build with a different
122
* Gecko milestone (i.e. right after an upgrade).
123
* OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the
124
* same Gecko milestone (i.e. after a nightly upgrade).
125
* OVERRIDE_NONE otherwise.
126
*/
127
function needHomepageOverride(prefb) {
128
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
129
Ci.nsIToolkitProfileService
130
);
131
if (pService.createdAlternateProfile) {
132
return OVERRIDE_ALTERNATE_PROFILE;
133
}
134
var savedmstone = prefb.getCharPref(
135
"browser.startup.homepage_override.mstone",
136
""
137
);
138
139
if (savedmstone == "ignore") {
140
return OVERRIDE_NONE;
141
}
142
143
var mstone = Services.appinfo.platformVersion;
144
145
var savedBuildID = prefb.getCharPref(
146
"browser.startup.homepage_override.buildID",
147
""
148
);
149
150
var buildID = Services.appinfo.platformBuildID;
151
152
if (mstone != savedmstone) {
153
// Bug 462254. Previous releases had a default pref to suppress the EULA
154
// agreement if the platform's installer had already shown one. Now with
155
// about:rights we've removed the EULA stuff and default pref, but we need
156
// a way to make existing profiles retain the default that we removed.
157
if (savedmstone) {
158
prefb.setBoolPref("browser.rights.3.shown", true);
159
}
160
161
prefb.setCharPref("browser.startup.homepage_override.mstone", mstone);
162
prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
163
return savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE;
164
}
165
166
if (buildID != savedBuildID) {
167
prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
168
return OVERRIDE_NEW_BUILD_ID;
169
}
170
171
return OVERRIDE_NONE;
172
}
173
174
/**
175
* Gets the override page for the first run after the application has been
176
* updated.
177
* @param update
178
* The nsIUpdate for the update that has been applied.
179
* @param defaultOverridePage
180
* The default override page.
181
* @return The override page.
182
*/
183
function getPostUpdateOverridePage(update, defaultOverridePage) {
184
update = update.QueryInterface(Ci.nsIWritablePropertyBag);
185
let actions = update.getProperty("actions");
186
// When the update doesn't specify actions fallback to the original behavior
187
// of displaying the default override page.
188
if (!actions) {
189
return defaultOverridePage;
190
}
191
192
// The existence of silent or the non-existence of showURL in the actions both
193
// mean that an override page should not be displayed.
194
if (actions.includes("silent") || !actions.includes("showURL")) {
195
return "";
196
}
197
198
// If a policy was set to not allow the update.xml-provided
199
// URL to be used, use the default fallback (which will also
200
// be provided by the policy).
201
if (!Services.policies.isAllowed("postUpdateCustomPage")) {
202
return defaultOverridePage;
203
}
204
205
return update.getProperty("openURL") || defaultOverridePage;
206
}
207
208
/**
209
* Open a browser window. If this is the initial launch, this function will
210
* attempt to use the navigator:blank window opened by BrowserGlue.jsm during
211
* early startup.
212
*
213
* @param cmdLine
214
* The nsICommandLine object given to nsICommandLineHandler's handle
215
* method.
216
* Used to check if we are processing the command line for the initial launch.
217
* @param triggeringPrincipal
218
* The nsIPrincipal to use as triggering principal for the page load(s).
219
* @param urlOrUrlList (optional)
220
* When omitted, the browser window will be opened with the default
221
* arguments, which will usually load the homepage.
222
* This can be a JS array of urls provided as strings, each url will be
223
* loaded in a tab. postData will be ignored in this case.
224
* This can be a single url to load in the new window, provided as a string.
225
* postData will be used in this case if provided.
226
* @param postData (optional)
227
* An nsIInputStream object to use as POST data when loading the provided
228
* url, or null.
229
* @param forcePrivate (optional)
230
* Boolean. If set to true, the new window will be a private browsing one.
231
*
232
* @returns {ChromeWindow}
233
* Returns the top level window opened.
234
*/
235
function openBrowserWindow(
236
cmdLine,
237
triggeringPrincipal,
238
urlOrUrlList,
239
postData = null,
240
forcePrivate = false
241
) {
242
let chromeURL = AppConstants.BROWSER_CHROME_URL;
243
const isStartup =
244
cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH;
245
246
let args;
247
if (!urlOrUrlList) {
248
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
249
args = [gBrowserContentHandler.getArgs(isStartup)];
250
} else {
251
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
252
Ci.nsIToolkitProfileService
253
);
254
if (isStartup && pService.createdAlternateProfile) {
255
let url = getNewInstallPage();
256
if (Array.isArray(urlOrUrlList)) {
257
urlOrUrlList.unshift(url);
258
} else {
259
urlOrUrlList = [url, urlOrUrlList];
260
}
261
}
262
263
if (Array.isArray(urlOrUrlList)) {
264
// There isn't an explicit way to pass a principal here, so we load multiple URLs
265
// with system principal when we get to actually loading them.
266
if (
267
!triggeringPrincipal ||
268
!triggeringPrincipal.equals(gSystemPrincipal)
269
) {
270
throw new Error(
271
"Can't open multiple URLs with something other than system principal."
272
);
273
}
274
// Passing an nsIArray for the url disables the "|"-splitting behavior.
275
let uriArray = Cc["@mozilla.org/array;1"].createInstance(
276
Ci.nsIMutableArray
277
);
278
urlOrUrlList.forEach(function(uri) {
279
var sstring = Cc["@mozilla.org/supports-string;1"].createInstance(
280
Ci.nsISupportsString
281
);
282
sstring.data = uri;
283
uriArray.appendElement(sstring);
284
});
285
args = [uriArray];
286
} else {
287
// Always pass at least 3 arguments to avoid the "|"-splitting behavior,
288
// ie. avoid the loadOneOrMoreURIs function.
289
// Also, we need to pass the triggering principal.
290
args = [
291
urlOrUrlList,
292
null, // charset
293
null, // refererInfo
294
postData,
295
undefined, // allowThirdPartyFixup; this would be `false` but that
296
// needs a conversion. Hopefully bug 1485961 will fix.
297
undefined, // user context id
298
null, // origin principal
299
null, // origin storage principal
300
triggeringPrincipal,
301
];
302
}
303
}
304
305
if (isStartup) {
306
let win = Services.wm.getMostRecentWindow("navigator:blank");
307
if (win) {
308
// Remove the windowtype of our blank window so that we don't close it
309
// later on when seeing cmdLine.preventDefault is true.
310
win.document.documentElement.removeAttribute("windowtype");
311
312
if (forcePrivate) {
313
win.docShell.QueryInterface(
314
Ci.nsILoadContext
315
).usePrivateBrowsing = true;
316
}
317
318
win.location = chromeURL;
319
win.arguments = args; // <-- needs to be a plain JS array here.
320
321
return win;
322
}
323
}
324
325
// We can't provide arguments to openWindow as a JS array.
326
if (!urlOrUrlList) {
327
// If we have a single string guaranteed to not contain '|' we can simply
328
// wrap it in an nsISupportsString object.
329
let [url] = args;
330
args = Cc["@mozilla.org/supports-string;1"].createInstance(
331
Ci.nsISupportsString
332
);
333
args.data = url;
334
} else {
335
// Otherwise, pass an nsIArray.
336
if (args.length > 1) {
337
let string = Cc["@mozilla.org/supports-string;1"].createInstance(
338
Ci.nsISupportsString
339
);
340
string.data = args[0];
341
args[0] = string;
342
}
343
let array = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
344
args.forEach(a => {
345
array.appendElement(a);
346
});
347
args = array;
348
}
349
350
let features =
351
"chrome,dialog=no,all" + gBrowserContentHandler.getFeatures(cmdLine);
352
if (forcePrivate) {
353
features += ",private";
354
}
355
356
return Services.ww.openWindow(null, chromeURL, "_blank", features, args);
357
}
358
359
function openPreferences(cmdLine, extraArgs) {
360
openBrowserWindow(cmdLine, gSystemPrincipal, "about:preferences");
361
}
362
363
async function doSearch(searchTerm, cmdLine) {
364
// XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
365
// preferences, but need nsIBrowserDOMWindow extensions
366
// Open the window immediately as BrowserContentHandler needs to
367
// be handled synchronously. Then load the search URI when the
368
// SearchService has loaded.
369
let win = openBrowserWindow(cmdLine, gSystemPrincipal, "about:blank");
370
await new Promise(resolve => {
371
Services.obs.addObserver(function observe(subject) {
372
if (subject == win) {
373
Services.obs.removeObserver(
374
observe,
375
"browser-delayed-startup-finished"
376
);
377
resolve();
378
}
379
}, "browser-delayed-startup-finished");
380
});
381
382
win.BrowserSearch.loadSearchFromCommandLine(
383
searchTerm,
384
PrivateBrowsingUtils.isInTemporaryAutoStartMode ||
385
PrivateBrowsingUtils.isWindowPrivate(win),
386
gSystemPrincipal,
387
win.gBrowser.selectedBrowser.csp
388
).catch(Cu.reportError);
389
}
390
391
function nsBrowserContentHandler() {
392
if (!gBrowserContentHandler) {
393
gBrowserContentHandler = this;
394
}
395
return gBrowserContentHandler;
396
}
397
nsBrowserContentHandler.prototype = {
398
/* nsISupports */
399
QueryInterface: ChromeUtils.generateQI([
400
Ci.nsICommandLineHandler,
401
Ci.nsIBrowserHandler,
402
Ci.nsIContentHandler,
403
Ci.nsICommandLineValidator,
404
]),
405
406
/* nsICommandLineHandler */
407
handle: function bch_handle(cmdLine) {
408
if (cmdLine.handleFlag("kiosk", false)) {
409
gKiosk = true;
410
}
411
if (cmdLine.handleFlag("browser", false)) {
412
openBrowserWindow(cmdLine, gSystemPrincipal);
413
cmdLine.preventDefault = true;
414
}
415
416
// In the past, when an instance was not already running, the -remote
417
// option returned an error code. Any script or application invoking the
418
// -remote option is expected to be handling this case, otherwise they
419
// wouldn't be doing anything when there is no Firefox already running.
420
// Making the -remote option always return an error code makes those
421
// scripts or applications handle the situation as if Firefox was not
422
// already running.
423
if (cmdLine.handleFlag("remote", true)) {
424
throw Cr.NS_ERROR_ABORT;
425
}
426
427
var uriparam;
428
try {
429
while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
430
let uri = resolveURIInternal(cmdLine, uriparam);
431
if (!shouldLoadURI(uri)) {
432
continue;
433
}
434
openBrowserWindow(cmdLine, gSystemPrincipal, uri.spec);
435
cmdLine.preventDefault = true;
436
}
437
} catch (e) {
438
Cu.reportError(e);
439
}
440
441
try {
442
while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) {
443
let uri = resolveURIInternal(cmdLine, uriparam);
444
handURIToExistingBrowser(
445
uri,
446
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
447
cmdLine,
448
false,
449
gSystemPrincipal
450
);
451
cmdLine.preventDefault = true;
452
}
453
} catch (e) {
454
Cu.reportError(e);
455
}
456
457
var chromeParam = cmdLine.handleFlagWithParam("chrome", false);
458
if (chromeParam) {
459
// Handle old preference dialog URLs.
460
if (
461
chromeParam == "chrome://browser/content/pref/pref.xul" ||
463
) {
464
openPreferences(cmdLine);
465
cmdLine.preventDefault = true;
466
} else {
467
try {
468
let resolvedURI = resolveURIInternal(cmdLine, chromeParam);
469
let isLocal = uri => {
470
let localSchemes = new Set(["chrome", "file", "resource"]);
471
if (uri instanceof Ci.nsINestedURI) {
472
uri = uri.QueryInterface(Ci.nsINestedURI).innerMostURI;
473
}
474
return localSchemes.has(uri.scheme);
475
};
476
if (isLocal(resolvedURI)) {
477
// If the URI is local, we are sure it won't wrongly inherit chrome privs
478
let features = "chrome,dialog=no,all" + this.getFeatures(cmdLine);
479
// Provide 1 null argument, as openWindow has a different behavior
480
// when the arg count is 0.
481
let argArray = Cc["@mozilla.org/array;1"].createInstance(
482
Ci.nsIMutableArray
483
);
484
argArray.appendElement(null);
485
Services.ww.openWindow(
486
null,
487
resolvedURI.spec,
488
"_blank",
489
features,
490
argArray
491
);
492
cmdLine.preventDefault = true;
493
} else {
494
dump("*** Preventing load of web URI as chrome\n");
495
dump(
496
" If you're trying to load a webpage, do not pass --chrome.\n"
497
);
498
}
499
} catch (e) {
500
Cu.reportError(e);
501
}
502
}
503
}
504
if (cmdLine.handleFlag("preferences", false)) {
505
openPreferences(cmdLine);
506
cmdLine.preventDefault = true;
507
}
508
if (cmdLine.handleFlag("silent", false)) {
509
cmdLine.preventDefault = true;
510
}
511
512
try {
513
var privateWindowParam = cmdLine.handleFlagWithParam(
514
"private-window",
515
false
516
);
517
if (privateWindowParam) {
518
// Ensure we initialize the handler before trying to load
519
// about:privatebrowsing.
520
AboutPrivateBrowsingHandler.init();
521
let forcePrivate = true;
522
let resolvedURI;
523
if (!PrivateBrowsingUtils.enabled) {
524
// Load about:privatebrowsing in a normal tab, which will display an error indicating
525
// access to private browsing has been disabled.
526
forcePrivate = false;
527
resolvedURI = Services.io.newURI("about:privatebrowsing");
528
} else {
529
resolvedURI = resolveURIInternal(cmdLine, privateWindowParam);
530
}
531
handURIToExistingBrowser(
532
resolvedURI,
533
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
534
cmdLine,
535
forcePrivate,
536
gSystemPrincipal
537
);
538
cmdLine.preventDefault = true;
539
}
540
} catch (e) {
541
if (e.result != Cr.NS_ERROR_INVALID_ARG) {
542
throw e;
543
}
544
// NS_ERROR_INVALID_ARG is thrown when flag exists, but has no param.
545
if (cmdLine.handleFlag("private-window", false)) {
546
// Ensure we initialize the handler before trying to load
547
// about:privatebrowsing.
548
AboutPrivateBrowsingHandler.init();
549
openBrowserWindow(
550
cmdLine,
551
gSystemPrincipal,
552
"about:privatebrowsing",
553
null,
554
PrivateBrowsingUtils.enabled
555
);
556
cmdLine.preventDefault = true;
557
}
558
}
559
560
var searchParam = cmdLine.handleFlagWithParam("search", false);
561
if (searchParam) {
562
doSearch(searchParam, cmdLine);
563
cmdLine.preventDefault = true;
564
}
565
566
// The global PB Service consumes this flag, so only eat it in per-window
567
// PB builds.
568
if (cmdLine.handleFlag("private", false) && PrivateBrowsingUtils.enabled) {
569
PrivateBrowsingUtils.enterTemporaryAutoStartMode();
570
if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
571
let win = Services.wm.getMostRecentWindow("navigator:blank");
572
if (win) {
573
win.docShell.QueryInterface(
574
Ci.nsILoadContext
575
).usePrivateBrowsing = true;
576
}
577
}
578
}
579
if (cmdLine.handleFlag("setDefaultBrowser", false)) {
580
ShellService.setDefaultBrowser(true, true);
581
}
582
583
if (cmdLine.handleFlag("first-startup", false)) {
584
FirstStartup.init();
585
}
586
587
var fileParam = cmdLine.handleFlagWithParam("file", false);
588
if (fileParam) {
589
var file = cmdLine.resolveFile(fileParam);
590
var fileURI = Services.io.newFileURI(file);
591
openBrowserWindow(cmdLine, gSystemPrincipal, fileURI.spec);
592
cmdLine.preventDefault = true;
593
}
594
595
if (AppConstants.platform == "win") {
596
// Handle "? searchterm" for Windows Vista start menu integration
597
for (var i = cmdLine.length - 1; i >= 0; --i) {
598
var param = cmdLine.getArgument(i);
599
if (param.match(/^\? /)) {
600
cmdLine.removeArguments(i, i);
601
cmdLine.preventDefault = true;
602
603
searchParam = param.substr(2);
604
doSearch(searchParam, cmdLine);
605
}
606
}
607
}
608
},
609
610
get helpInfo() {
611
let info =
612
" --browser Open a browser window.\n" +
613
" --new-window <url> Open <url> in a new window.\n" +
614
" --new-tab <url> Open <url> in a new tab.\n" +
615
" --private-window <url> Open <url> in a new private window.\n";
616
if (AppConstants.platform == "win") {
617
info += " --preferences Open Options dialog.\n";
618
} else {
619
info += " --preferences Open Preferences dialog.\n";
620
}
621
info +=
622
" --screenshot [<path>] Save screenshot to <path> or in working directory.\n";
623
info +=
624
" --window-size width[,height] Width and optionally height of screenshot.\n";
625
info +=
626
" --search <term> Search <term> with your default search engine.\n";
627
info += " --setDefaultBrowser Set this app as the default browser.\n";
628
info +=
629
" --first-startup Run post-install actions before opening a new window.\n";
630
info += " --kiosk Start the browser in kiosk mode.\n";
631
return info;
632
},
633
634
/* nsIBrowserHandler */
635
636
get defaultArgs() {
637
return this.getArgs();
638
},
639
640
getArgs(isStartup = false) {
641
var prefb = Services.prefs;
642
643
if (!gFirstWindow) {
644
gFirstWindow = true;
645
if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
646
return "about:privatebrowsing";
647
}
648
}
649
650
var override;
651
var overridePage = "";
652
var additionalPage = "";
653
var willRestoreSession = false;
654
try {
655
// Read the old value of homepage_override.mstone before
656
// needHomepageOverride updates it, so that we can later add it to the
657
// URL if we do end up showing an overridePage. This makes it possible
658
// to have the overridePage's content vary depending on the version we're
659
// upgrading from.
660
let old_mstone = Services.prefs.getCharPref(
661
"browser.startup.homepage_override.mstone",
662
"unknown"
663
);
664
let old_buildId = Services.prefs.getCharPref(
665
"browser.startup.homepage_override.buildID",
666
"unknown"
667
);
668
override = needHomepageOverride(prefb);
669
if (override != OVERRIDE_NONE) {
670
switch (override) {
671
case OVERRIDE_ALTERNATE_PROFILE:
672
// Override the welcome page to explain why the user has a new
673
// profile. nsBrowserGlue.css will be responsible for showing the
674
// modal dialog.
675
overridePage = getNewInstallPage();
676
break;
677
case OVERRIDE_NEW_PROFILE:
678
// New profile.
679
overridePage = Services.urlFormatter.formatURLPref(
680
"startup.homepage_welcome_url"
681
);
682
additionalPage = Services.urlFormatter.formatURLPref(
683
"startup.homepage_welcome_url.additional"
684
);
685
// Turn on 'later run' pages for new profiles.
686
LaterRun.enabled = true;
687
break;
688
case OVERRIDE_NEW_MSTONE:
689
// Check whether we will restore a session. If we will, we assume
690
// that this is an "update" session. This does not take crashes
691
// into account because that requires waiting for the session file
692
// to be read. If a crash occurs after updating, before restarting,
693
// we may open the startPage in addition to restoring the session.
694
willRestoreSession = SessionStartup.isAutomaticRestoreEnabled();
695
696
overridePage = Services.urlFormatter.formatURLPref(
697
"startup.homepage_override_url"
698
);
699
let update = UpdateManager.activeUpdate;
700
if (
701
update &&
702
Services.vc.compare(update.appVersion, old_mstone) > 0
703
) {
704
overridePage = getPostUpdateOverridePage(update, overridePage);
705
// Send the update ping to signal that the update was successful.
706
UpdatePing.handleUpdateSuccess(old_mstone, old_buildId);
707
}
708
709
overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
710
break;
711
case OVERRIDE_NEW_BUILD_ID:
712
if (UpdateManager.activeUpdate) {
713
// Send the update ping to signal that the update was successful.
714
UpdatePing.handleUpdateSuccess(old_mstone, old_buildId);
715
}
716
break;
717
}
718
}
719
} catch (ex) {}
720
721
// formatURLPref might return "about:blank" if getting the pref fails
722
if (overridePage == "about:blank") {
723
overridePage = "";
724
}
725
726
// Allow showing a one-time startup override if we're not showing one
727
if (isStartup && overridePage == "" && prefb.prefHasUserValue(ONCE_PREF)) {
728
try {
729
// Show if we haven't passed the expiration or there's no expiration
730
const { expire, url } = JSON.parse(
731
Services.urlFormatter.formatURLPref(ONCE_PREF)
732
);
733
if (!(Date.now() > expire)) {
734
// Only set allowed urls as override pages
735
overridePage = url
736
.split("|")
737
.map(val => {
738
try {
739
return new URL(val);
740
} catch (ex) {
741
// Invalid URL, so filter out below
742
Cu.reportError(`Invalid once url: ${ex}`);
743
return null;
744
}
745
})
746
.filter(
747
parsed =>
748
parsed &&
749
parsed.protocol == "https:" &&
750
// Only accept exact hostname or subdomain; without port
751
ONCE_DOMAINS.includes(
752
Services.eTLD.getBaseDomainFromHost(parsed.host)
753
)
754
)
755
.join("|");
756
757
// Be noisy as properly configured urls should be unchanged
758
if (overridePage != url) {
759
Cu.reportError(`Mismatched once urls: ${url}`);
760
}
761
}
762
} catch (ex) {
763
// Invalid json pref, so ignore (and clear below)
764
Cu.reportError(`Invalid once pref: ${ex}`);
765
} finally {
766
prefb.clearUserPref(ONCE_PREF);
767
}
768
}
769
770
if (!additionalPage) {
771
additionalPage = LaterRun.getURL() || "";
772
}
773
774
if (additionalPage && additionalPage != "about:blank") {
775
if (overridePage) {
776
overridePage += "|" + additionalPage;
777
} else {
778
overridePage = additionalPage;
779
}
780
}
781
782
var startPage = "";
783
try {
784
var choice = prefb.getIntPref("browser.startup.page");
785
if (choice == 1 || choice == 3) {
786
startPage = HomePage.get();
787
}
788
} catch (e) {
789
Cu.reportError(e);
790
}
791
792
if (startPage == "about:blank") {
793
startPage = "";
794
}
795
796
let skipStartPage =
797
(override == OVERRIDE_NEW_PROFILE ||
798
override == OVERRIDE_ALTERNATE_PROFILE) &&
799
prefb.getBoolPref("browser.startup.firstrunSkipsHomepage");
800
// Only show the startPage if we're not restoring an update session and are
801
// not set to skip the start page on this profile
802
if (overridePage && startPage && !willRestoreSession && !skipStartPage) {
803
return overridePage + "|" + startPage;
804
}
805
806
return overridePage || startPage || "about:blank";
807
},
808
809
mFeatures: null,
810
811
getFeatures: function bch_features(cmdLine) {
812
if (this.mFeatures === null) {
813
this.mFeatures = "";
814
815
if (cmdLine) {
816
try {
817
var width = cmdLine.handleFlagWithParam("width", false);
818
var height = cmdLine.handleFlagWithParam("height", false);
819
820
if (width) {
821
this.mFeatures += ",width=" + width;
822
}
823
if (height) {
824
this.mFeatures += ",height=" + height;
825
}
826
} catch (e) {}
827
}
828
829
// The global PB Service consumes this flag, so only eat it in per-window
830
// PB builds.
831
if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
832
this.mFeatures += ",private";
833
}
834
835
if (
836
Services.prefs.getBoolPref("browser.suppress_first_window_animation") &&
837
!Services.wm.getMostRecentWindow("navigator:browser")
838
) {
839
this.mFeatures += ",suppressanimation";
840
}
841
}
842
843
return this.mFeatures;
844
},
845
846
get kiosk() {
847
return gKiosk;
848
},
849
850
/* nsIContentHandler */
851
852
handleContent: function bch_handleContent(contentType, context, request) {
853
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
854
855
try {
856
var webNavInfo = Cc["@mozilla.org/webnavigation-info;1"].getService(
857
Ci.nsIWebNavigationInfo
858
);
859
if (!webNavInfo.isTypeSupported(contentType, null)) {
860
throw NS_ERROR_WONT_HANDLE_CONTENT;
861
}
862
} catch (e) {
863
throw NS_ERROR_WONT_HANDLE_CONTENT;
864
}
865
866
request.QueryInterface(Ci.nsIChannel);
867
handURIToExistingBrowser(
868
request.URI,
869
Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
870
null,
871
false,
872
request.loadInfo.triggeringPrincipal
873
);
874
request.cancel(Cr.NS_BINDING_ABORTED);
875
},
876
877
/* nsICommandLineValidator */
878
validate: function bch_validate(cmdLine) {
879
var urlFlagIdx = cmdLine.findFlag("url", false);
880
if (
881
urlFlagIdx > -1 &&
882
cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_EXPLICIT
883
) {
884
var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
885
if (
886
cmdLine.length != urlFlagIdx + 2 ||
887
/firefoxurl(-[a-f0-9]+)?:/i.test(urlParam)
888
) {
889
throw Cr.NS_ERROR_ABORT;
890
}
891
var isDefault = false;
892
try {
893
var url =
894
Services.urlFormatter.formatURLPref("app.support.baseURL") +
895
"win10-default-browser";
896
if (urlParam == url) {
897
isDefault = ShellService.isDefaultBrowser(false, false);
898
}
899
} catch (ex) {}
900
if (isDefault) {
901
// Firefox is already the default HTTP handler.
902
// We don't have to show the instruction page.
903
throw Cr.NS_ERROR_ABORT;
904
}
905
}
906
},
907
};
908
var gBrowserContentHandler = new nsBrowserContentHandler();
909
910
function handURIToExistingBrowser(
911
uri,
912
location,
913
cmdLine,
914
forcePrivate,
915
triggeringPrincipal
916
) {
917
if (!shouldLoadURI(uri)) {
918
return;
919
}
920
921
// Unless using a private window is forced, open external links in private
922
// windows only if we're in perma-private mode.
923
var allowPrivate =
924
forcePrivate || PrivateBrowsingUtils.permanentPrivateBrowsing;
925
var navWin = BrowserWindowTracker.getTopWindow({ private: allowPrivate });
926
if (!navWin) {
927
// if we couldn't load it in an existing window, open a new one
928
openBrowserWindow(
929
cmdLine,
930
triggeringPrincipal,
931
uri.spec,
932
null,
933
forcePrivate
934
);
935
return;
936
}
937
938
var bwin = navWin.browserDOMWindow;
939
bwin.openURI(
940
uri,
941
null,
942
location,
943
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
944
triggeringPrincipal
945
);
946
}
947
948
function nsDefaultCommandLineHandler() {}
949
950
nsDefaultCommandLineHandler.prototype = {
951
/* nsISupports */
952
QueryInterface: ChromeUtils.generateQI(["nsICommandLineHandler"]),
953
954
_haveProfile: false,
955
956
/* nsICommandLineHandler */
957
handle: function dch_handle(cmdLine) {
958
var urilist = [];
959
960
if (AppConstants.platform == "win") {
961
// If we don't have a profile selected yet (e.g. the Profile Manager is
962
// displayed) we will crash if we open an url and then select a profile. To
963
// prevent this handle all url command line flags and set the command line's
964
// preventDefault to true to prevent the display of the ui. The initial
965
// command line will be retained when nsAppRunner calls LaunchChild though
966
// urls launched after the initial launch will be lost.
967
if (!this._haveProfile) {
968
try {
969
// This will throw when a profile has not been selected.
970
Services.dirsvc.get("ProfD", Ci.nsIFile);
971
this._haveProfile = true;
972
} catch (e) {
973
// eslint-disable-next-line no-empty
974
while ((ar = cmdLine.handleFlagWithParam("url", false))) {}
975
cmdLine.preventDefault = true;
976
}
977
}
978
}
979
980
try {
981
var ar;
982
while ((ar = cmdLine.handleFlagWithParam("url", false))) {
983
var uri = resolveURIInternal(cmdLine, ar);
984
urilist.push(uri);
985
}
986
} catch (e) {
987
Cu.reportError(e);
988
}
989
990
if (cmdLine.findFlag("screenshot", true) != -1) {
991
HeadlessShell.handleCmdLineArgs(
992
cmdLine,
993
urilist.filter(shouldLoadURI).map(u => u.spec)
994
);
995
return;
996
}
997
998
for (let i = 0; i < cmdLine.length; ++i) {
999
var curarg = cmdLine.getArgument(i);
1000
if (curarg.match(/^-/)) {
1001
Cu.reportError(
1002
"Warning: unrecognized command line flag " + curarg + "\n"
1003
);
1004
// To emulate the pre-nsICommandLine behavior, we ignore
1005
// the argument after an unrecognized flag.
1006
++i;
1007
} else {
1008
try {
1009
urilist.push(resolveURIInternal(cmdLine, curarg));
1010
} catch (e) {
1011
Cu.reportError(
1012
"Error opening URI '" +
1013
curarg +
1014
"' from the command line: " +
1015
e +
1016
"\n"
1017
);
1018
}
1019
}
1020
}
1021
1022
if (urilist.length) {
1023
if (
1024
cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
1025
urilist.length == 1
1026
) {
1027
// Try to find an existing window and load our URI into the
1028
// current tab, new tab, or new window as prefs determine.
1029
try {
1030
handURIToExistingBrowser(
1031
urilist[0],
1032
Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
1033
cmdLine,
1034
false,
1035
gSystemPrincipal
1036
);
1037
return;
1038
} catch (e) {}
1039
}
1040
1041
var URLlist = urilist.filter(shouldLoadURI).map(u => u.spec);
1042
if (URLlist.length) {
1043
openBrowserWindow(cmdLine, gSystemPrincipal, URLlist);
1044
}
1045
} else if (!cmdLine.preventDefault) {
1046
if (
1047
AppConstants.isPlatformAndVersionAtLeast("win", "10") &&
1048
cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
1049
WindowsUIUtils.inTabletMode
1050
) {
1051
// In windows 10 tablet mode, do not create a new window, but reuse the existing one.
1052
let win = BrowserWindowTracker.getTopWindow();
1053
if (win) {
1054
win.focus();
1055
return;
1056
}
1057
}
1058
openBrowserWindow(cmdLine, gSystemPrincipal);
1059
} else {
1060
// Need a better solution in the future to avoid opening the blank window
1061
// when command line parameters say we are not going to show a browser
1062
// window, but for now the blank window getting closed quickly (and
1063
// causing only a slight flicker) is better than leaving it open.
1064
let win = Services.wm.getMostRecentWindow("navigator:blank");
1065
if (win) {
1066
win.close();
1067
}
1068
}
1069
},
1070
1071
helpInfo: "",
1072
};