Bug 1908842: update password generator prompt text r=android-reviewers,gl
[gecko.git] / toolkit / modules / E10SUtils.sys.mjs
blobc91bb2a80d875bf8ad44d5f02a945dd84037c1db
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/. */
5 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
7 const lazy = {};
9 XPCOMUtils.defineLazyPreferenceGetter(
10   lazy,
11   "useSeparateFileUriProcess",
12   "browser.tabs.remote.separateFileUriProcess",
13   false
15 XPCOMUtils.defineLazyPreferenceGetter(
16   lazy,
17   "useSeparatePrivilegedAboutContentProcess",
18   "browser.tabs.remote.separatePrivilegedContentProcess",
19   false
21 XPCOMUtils.defineLazyPreferenceGetter(
22   lazy,
23   "separatePrivilegedMozillaWebContentProcess",
24   "browser.tabs.remote.separatePrivilegedMozillaWebContentProcess",
25   false
27 XPCOMUtils.defineLazyPreferenceGetter(
28   lazy,
29   "separatedMozillaDomains",
30   "browser.tabs.remote.separatedMozillaDomains",
31   "",
32   false,
33   val => val.split(",")
36 XPCOMUtils.defineLazyPreferenceGetter(
37   lazy,
38   "useCrossOriginOpenerPolicy",
39   "browser.tabs.remote.useCrossOriginOpenerPolicy",
40   false
42 XPCOMUtils.defineLazyServiceGetter(
43   lazy,
44   "serializationHelper",
45   "@mozilla.org/network/serialization-helper;1",
46   "nsISerializationHelper"
48 XPCOMUtils.defineLazyServiceGetter(
49   lazy,
50   "extProtService",
51   "@mozilla.org/uriloader/external-protocol-service;1",
52   "nsIExternalProtocolService"
55 function getOriginalReaderModeURI(aURI) {
56   try {
57     let searchParams = new URLSearchParams(aURI.query);
58     if (searchParams.has("url")) {
59       return Services.io.newURI(searchParams.get("url"));
60     }
61   } catch (e) {}
62   return null;
65 const NOT_REMOTE = null;
67 // These must match the similar ones in RemoteTypes.h, ProcInfo.h, ChromeUtils.webidl and ChromeUtils.cpp
68 const WEB_REMOTE_TYPE = "web";
69 const FISSION_WEB_REMOTE_TYPE = "webIsolated";
70 const WEB_REMOTE_COOP_COEP_TYPE_PREFIX = "webCOOP+COEP=";
71 const FILE_REMOTE_TYPE = "file";
72 const EXTENSION_REMOTE_TYPE = "extension";
73 const PRIVILEGEDABOUT_REMOTE_TYPE = "privilegedabout";
74 const PRIVILEGEDMOZILLA_REMOTE_TYPE = "privilegedmozilla";
75 const SERVICEWORKER_REMOTE_TYPE = "webServiceWorker";
77 // This must start with the WEB_REMOTE_TYPE above.
78 const DEFAULT_REMOTE_TYPE = WEB_REMOTE_TYPE;
80 // This list is duplicated between Navigator.cpp and here because navigator
81 // is not accessible in this context. Please update both if the list changes.
82 const kSafeSchemes = [
83   "bitcoin",
84   "ftp",
85   "ftps",
86   "geo",
87   "im",
88   "irc",
89   "ircs",
90   "magnet",
91   "mailto",
92   "matrix",
93   "mms",
94   "news",
95   "nntp",
96   "openpgp4fpr",
97   "sftp",
98   "sip",
99   "sms",
100   "smsto",
101   "ssh",
102   "tel",
103   "urn",
104   "webcal",
105   "wtai",
106   "xmpp",
109 const STANDARD_SAFE_PROTOCOLS = kSafeSchemes;
111 // Note that even if the scheme fits the criteria for a web-handled scheme
112 // (ie it is compatible with the checks registerProtocolHandler uses), it may
113 // not be web-handled - it could still be handled via the OS by another app.
114 function hasPotentiallyWebHandledScheme({ scheme }) {
115   // Note that `scheme` comes from a URI object so is already lowercase.
116   if (kSafeSchemes.includes(scheme)) {
117     return true;
118   }
119   if (!scheme.startsWith("web+") || scheme.length < 5) {
120     return false;
121   }
122   // Check the rest of the scheme only consists of ascii a-z chars
123   return /^[a-z]+$/.test(scheme.substr("web+".length));
126 function validatedWebRemoteType(
127   aPreferredRemoteType,
128   aTargetUri,
129   aCurrentUri,
130   aResultPrincipal,
131   aRemoteSubframes,
132   aOriginAttributes = {}
133 ) {
134   // To load into the Privileged Mozilla Content Process you must be https,
135   // and be an exact match or a subdomain of an allowlisted domain.
136   // This code is duplicated in ProcessIolation.cpp, please update both.
137   if (
138     lazy.separatePrivilegedMozillaWebContentProcess &&
139     aTargetUri.asciiHost &&
140     aTargetUri.scheme == "https" &&
141     lazy.separatedMozillaDomains.some(function (val) {
142       return (
143         aTargetUri.asciiHost == val || aTargetUri.asciiHost.endsWith("." + val)
144       );
145     })
146   ) {
147     return PRIVILEGEDMOZILLA_REMOTE_TYPE;
148   }
150   // If we're in the parent and we were passed a web-handled scheme,
151   // transform it now to avoid trying to load it in the wrong process.
152   if (aRemoteSubframes && hasPotentiallyWebHandledScheme(aTargetUri)) {
153     if (
154       Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT &&
155       Services.appinfo.remoteType.startsWith(FISSION_WEB_REMOTE_TYPE + "=")
156     ) {
157       // If we're in a child process, assume we're OK to load this non-web
158       // URL for now. We'll either load it externally or re-evaluate once
159       // we know the "real" URL to which we'll redirect.
160       return Services.appinfo.remoteType;
161     }
163     // This doesn't work (throws) in the child - see
164     // https://bugzilla.mozilla.org/show_bug.cgi?id=1589082
165     // Even if it did, it'd cause sync IPC
166     // ( https://bugzilla.mozilla.org/show_bug.cgi?id=1589085 ), and this code
167     // can get called several times per page load so that seems like something
168     // we'd want to avoid.
169     let handlerInfo = lazy.extProtService.getProtocolHandlerInfo(
170       aTargetUri.scheme
171     );
172     try {
173       if (!handlerInfo.alwaysAskBeforeHandling) {
174         let app = handlerInfo.preferredApplicationHandler;
175         app.QueryInterface(Ci.nsIWebHandlerApp);
176         // If we get here, the default handler is a web app.
177         // Target to the origin of that web app:
178         let uriStr = app.uriTemplate.replace(/%s/, aTargetUri.spec);
179         aTargetUri = Services.io.newURI(uriStr);
180       }
181     } catch (ex) {
182       // It's not strange for this to throw, we just ignore it and fall through.
183     }
184   }
186   // If the domain is allow listed to allow it to use file:// URIs, then we have
187   // to run it in a file content process, in case it uses file:// sub-resources.
188   const sm = Services.scriptSecurityManager;
189   if (sm.inFileURIAllowlist(aTargetUri)) {
190     return FILE_REMOTE_TYPE;
191   }
193   // If we're within a fission window, extract site information from the URI in
194   // question, and use it to generate an isolated origin.
195   if (aRemoteSubframes) {
196     let originAttributes = {};
197     // Only use specific properties of OriginAttributes in our remoteType
198     let { userContextId, privateBrowsingId, geckoViewSessionContextId } =
199       aOriginAttributes;
200     originAttributes = {
201       userContextId,
202       privateBrowsingId,
203       geckoViewSessionContextId,
204     };
206     // Get a principal to use for isolation.
207     let targetPrincipal;
208     if (aResultPrincipal) {
209       targetPrincipal = sm.principalWithOA(aResultPrincipal, originAttributes);
210     } else {
211       targetPrincipal = sm.createContentPrincipal(aTargetUri, originAttributes);
212     }
214     // If this is a special webCOOP+COEP= remote type that matches the
215     // principal's siteOrigin, we don't want to override it with webIsolated=
216     // as it's already isolated.
217     if (
218       aPreferredRemoteType &&
219       aPreferredRemoteType.startsWith(
220         `${WEB_REMOTE_COOP_COEP_TYPE_PREFIX}${targetPrincipal.siteOrigin}`
221       )
222     ) {
223       return aPreferredRemoteType;
224     }
226     return `${FISSION_WEB_REMOTE_TYPE}=${targetPrincipal.siteOrigin}`;
227     // else fall through and probably return WEB_REMOTE_TYPE
228   }
230   if (!aPreferredRemoteType) {
231     return WEB_REMOTE_TYPE;
232   }
234   if (aPreferredRemoteType.startsWith(WEB_REMOTE_TYPE)) {
235     return aPreferredRemoteType;
236   }
238   return WEB_REMOTE_TYPE;
241 export var E10SUtils = {
242   DEFAULT_REMOTE_TYPE,
243   NOT_REMOTE,
244   WEB_REMOTE_TYPE,
245   WEB_REMOTE_COOP_COEP_TYPE_PREFIX,
246   FILE_REMOTE_TYPE,
247   EXTENSION_REMOTE_TYPE,
248   PRIVILEGEDABOUT_REMOTE_TYPE,
249   PRIVILEGEDMOZILLA_REMOTE_TYPE,
250   FISSION_WEB_REMOTE_TYPE,
251   SERVICEWORKER_REMOTE_TYPE,
252   STANDARD_SAFE_PROTOCOLS,
254   /**
255    * @param aURI The URI of the about page
256    * @return The instance of the nsIAboutModule related to this uri
257    */
258   getAboutModule(aURL) {
259     // Needs to match NS_GetAboutModuleName
260     let moduleName = aURL.pathQueryRef.replace(/[#?].*/, "").toLowerCase();
261     let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName;
262     try {
263       return Cc[contract].getService(Ci.nsIAboutModule);
264     } catch (e) {
265       // Either the about module isn't defined or it is broken. In either case
266       // ignore it.
267       return null;
268     }
269   },
271   useCrossOriginOpenerPolicy() {
272     return lazy.useCrossOriginOpenerPolicy;
273   },
275   _log: null,
276   _uriStr: function uriStr(aUri) {
277     return aUri ? aUri.spec : "undefined";
278   },
280   log: function log() {
281     if (!this._log) {
282       this._log = console.createInstance({
283         prefix: "ProcessSwitch",
284         maxLogLevel: "Error", // Change to "Debug" the process switching code
285       });
287       this._log.debug("Setup logger");
288     }
290     return this._log;
291   },
293   /**
294    * Serialize csp data.
295    *
296    * @param {nsIContentSecurity} csp. The csp to serialize.
297    * @return {String} The base64 encoded csp data.
298    */
299   serializeCSP(csp) {
300     let serializedCSP = null;
302     try {
303       if (csp) {
304         serializedCSP = lazy.serializationHelper.serializeToString(csp);
305       }
306     } catch (e) {
307       this.log().error(`Failed to serialize csp '${csp}' ${e}`);
308     }
309     return serializedCSP;
310   },
312   /**
313    * Deserialize a base64 encoded csp (serialized with
314    * Utils::serializeCSP).
315    *
316    * @param {String} csp_b64 A base64 encoded serialized csp.
317    * @return {nsIContentSecurityPolicy} A deserialized csp.
318    */
319   deserializeCSP(csp_b64) {
320     if (!csp_b64) {
321       return null;
322     }
324     try {
325       let csp = lazy.serializationHelper.deserializeObject(csp_b64);
326       csp.QueryInterface(Ci.nsIContentSecurityPolicy);
327       return csp;
328     } catch (e) {
329       this.log().error(`Failed to deserialize csp_b64 '${csp_b64}' ${e}`);
330     }
331     return null;
332   },
334   canLoadURIInRemoteType(
335     aURL,
336     aRemoteSubframes,
337     aRemoteType = DEFAULT_REMOTE_TYPE,
338     aOriginAttributes = {}
339   ) {
340     // aRemoteType cannot be undefined, as that would cause it to default to
341     // `DEFAULT_REMOTE_TYPE`. This means any falsy remote types are
342     // intentionally `NOT_REMOTE`.
344     return (
345       aRemoteType ==
346       this.getRemoteTypeForURI(
347         aURL,
348         true,
349         aRemoteSubframes,
350         aRemoteType,
351         null,
352         aOriginAttributes
353       )
354     );
355   },
357   getRemoteTypeForURI(
358     aURL,
359     aMultiProcess,
360     aRemoteSubframes,
361     aPreferredRemoteType = DEFAULT_REMOTE_TYPE,
362     aCurrentUri,
363     aOriginAttributes = {}
364   ) {
365     if (!aMultiProcess) {
366       return NOT_REMOTE;
367     }
369     // loadURI in browser.js treats null as about:blank
370     if (!aURL) {
371       aURL = "about:blank";
372     }
374     let uri;
375     try {
376       uri = Services.uriFixup.getFixupURIInfo(aURL).preferredURI;
377     } catch (e) {
378       // If we have an invalid URI, it's still possible that it might get
379       // fixed-up into a valid URI later on. However, we don't want to return
380       // aPreferredRemoteType here, in case the URI gets fixed-up into
381       // something that wouldn't normally run in that process.
382       return DEFAULT_REMOTE_TYPE;
383     }
385     return this.getRemoteTypeForURIObject(uri, {
386       multiProcess: aMultiProcess,
387       remoteSubFrames: aRemoteSubframes,
388       preferredRemoteType: aPreferredRemoteType,
389       currentURI: aCurrentUri,
390       originAttributes: aOriginAttributes,
391     });
392   },
394   getRemoteTypeForURIObject(aURI, options) {
395     let {
396       multiProcess = Services.appinfo.browserTabsRemoteAutostart,
397       remoteSubFrames = Services.appinfo.fissionAutostart,
398       preferredRemoteType = DEFAULT_REMOTE_TYPE,
399       currentURI = null,
400       resultPrincipal = null,
401       originAttributes = {},
402     } = options;
403     if (!multiProcess) {
404       return NOT_REMOTE;
405     }
407     switch (aURI.scheme) {
408       case "javascript":
409         // javascript URIs can load in any, they apply to the current document.
410         return preferredRemoteType;
412       case "data":
413       case "blob":
414         // We need data: and blob: URIs to load in any remote process, because
415         // they need to be able to load in whatever is the current process
416         // unless it is non-remote. In that case we don't want to load them in
417         // the parent process, so we load them in the default remote process,
418         // which is sandboxed and limits any risk.
419         return preferredRemoteType == NOT_REMOTE
420           ? DEFAULT_REMOTE_TYPE
421           : preferredRemoteType;
423       case "file":
424         return lazy.useSeparateFileUriProcess
425           ? FILE_REMOTE_TYPE
426           : DEFAULT_REMOTE_TYPE;
428       case "about":
429         let module = this.getAboutModule(aURI);
430         // If the module doesn't exist then an error page will be loading, that
431         // should be ok to load in any process
432         if (!module) {
433           return preferredRemoteType;
434         }
436         let flags = module.getURIFlags(aURI);
437         if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_EXTENSION_PROCESS) {
438           return WebExtensionPolicy.useRemoteWebExtensions
439             ? EXTENSION_REMOTE_TYPE
440             : NOT_REMOTE;
441         }
443         if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
444           if (
445             flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS &&
446             (lazy.useSeparatePrivilegedAboutContentProcess ||
447               aURI.filePath == "logins" ||
448               // Force about:welcome and about:home into the privileged content process to
449               // workaround code coverage test failures which result from the
450               // workaround in bug 161269. Once that bug is fixed for real,
451               // the about:welcome and about:home case below can be removed.
452               aURI.filePath == "welcome" ||
453               aURI.filePath == "home")
454           ) {
455             return PRIVILEGEDABOUT_REMOTE_TYPE;
456           }
458           // When loading about:reader, try to display the document in the same
459           // web remote type as the document it's loading.
460           if (aURI.filePath == "reader") {
461             let readerModeURI = getOriginalReaderModeURI(aURI);
462             if (readerModeURI) {
463               let innerRemoteType = this.getRemoteTypeForURIObject(
464                 readerModeURI,
465                 options
466               );
467               if (
468                 innerRemoteType &&
469                 innerRemoteType.startsWith(WEB_REMOTE_TYPE)
470               ) {
471                 return innerRemoteType;
472               }
473             }
474           }
476           return DEFAULT_REMOTE_TYPE;
477         }
479         // If the about page can load in parent or child, it should be safe to
480         // load in any remote type.
481         if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) {
482           return preferredRemoteType;
483         }
485         return NOT_REMOTE;
487       case "chrome":
488         let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(
489           Ci.nsIXULChromeRegistry
490         );
491         if (chromeReg.mustLoadURLRemotely(aURI)) {
492           return DEFAULT_REMOTE_TYPE;
493         }
495         if (
496           chromeReg.canLoadURLRemotely(aURI) &&
497           preferredRemoteType != NOT_REMOTE
498         ) {
499           return DEFAULT_REMOTE_TYPE;
500         }
502         return NOT_REMOTE;
504       case "moz-extension":
505         // Extension iframes should load in the same process
506         // as their outer frame, but that's handled elsewhere.
507         return WebExtensionPolicy.useRemoteWebExtensions
508           ? EXTENSION_REMOTE_TYPE
509           : NOT_REMOTE;
511       case "imap":
512       case "mailbox":
513       case "news":
514       case "nntp":
515       case "snews":
516         // Protocols used by Thunderbird to display email messages.
517         return NOT_REMOTE;
519       default:
520         // WebExtensions may set up protocol handlers for protocol names
521         // beginning with ext+.  These may redirect to http(s) pages or to
522         // moz-extension pages.  We can't actually tell here where one of
523         // these pages will end up loading but Talos tests use protocol
524         // handlers that redirect to extension pages that rely on this
525         // behavior so a pageloader frame script is injected correctly.
526         // Protocols that redirect to http(s) will just flip back to a
527         // regular content process after the redirect.
528         if (aURI.scheme.startsWith("ext+")) {
529           return WebExtensionPolicy.useRemoteWebExtensions
530             ? EXTENSION_REMOTE_TYPE
531             : NOT_REMOTE;
532         }
534         // For any other nested URIs, we use the innerURI to determine the
535         // remote type. In theory we should use the innermost URI, but some URIs
536         // have fake inner URIs (e.g. about URIs with inner moz-safe-about) and
537         // if such URIs are wrapped in other nested schemes like view-source:,
538         // we don't want to "skip" past "about:" by going straight to the
539         // innermost URI. Any URIs like this will need to be handled in the
540         // cases above, so we don't still end up using the fake inner URI here.
541         if (aURI instanceof Ci.nsINestedURI) {
542           let innerURI = aURI.QueryInterface(Ci.nsINestedURI).innerURI;
543           return this.getRemoteTypeForURIObject(innerURI, options);
544         }
546         var log = this.log();
547         log.debug("validatedWebRemoteType()");
548         log.debug(`  aPreferredRemoteType: ${preferredRemoteType}`);
549         log.debug(`  aTargetUri: ${this._uriStr(aURI)}`);
550         log.debug(`  aCurrentUri: ${this._uriStr(currentURI)}`);
551         var remoteType = validatedWebRemoteType(
552           preferredRemoteType,
553           aURI,
554           currentURI,
555           resultPrincipal,
556           remoteSubFrames,
557           originAttributes
558         );
559         log.debug(`  validatedWebRemoteType() returning: ${remoteType}`);
560         return remoteType;
561     }
562   },
564   makeInputStream(data) {
565     if (typeof data == "string") {
566       let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
567         Ci.nsISupportsCString
568       );
569       stream.data = data;
570       return stream; // XPConnect will QI this to nsIInputStream for us.
571     }
573     let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
574       Ci.nsISupportsCString
575     );
576     stream.data = data.content;
578     if (data.headers) {
579       let mimeStream = Cc[
580         "@mozilla.org/network/mime-input-stream;1"
581       ].createInstance(Ci.nsIMIMEInputStream);
583       mimeStream.setData(stream);
584       for (let [name, value] of data.headers) {
585         mimeStream.addHeader(name, value);
586       }
587       return mimeStream;
588     }
590     return stream; // XPConnect will QI this to nsIInputStream for us.
591   },
593   /**
594    * Serialize principal data.
595    *
596    * @param {nsIPrincipal} principal The principal to serialize.
597    * @return {String} The serialized principal data.
598    */
599   serializePrincipal(principal) {
600     let serializedPrincipal = null;
602     try {
603       if (principal) {
604         serializedPrincipal =
605           Services.scriptSecurityManager.principalToJSON(principal);
606       }
607     } catch (e) {
608       this.log().error(`Failed to serialize principal '${principal}' ${e}`);
609     }
611     return serializedPrincipal;
612   },
614   /**
615    * Deserialize a principal (serialized with serializePrincipal).
616    *
617    * @param {String} serializedPincipal A serialized principal.
618    * @return {nsIPrincipal} A deserialized principal.
619    */
620   deserializePrincipal(serializedPincipal, fallbackPrincipalCallback = null) {
621     if (!serializedPincipal) {
622       if (!fallbackPrincipalCallback) {
623         this.log().warn(
624           "No principal passed to deserializePrincipal and no fallbackPrincipalCallback"
625         );
626         return null;
627       }
629       return fallbackPrincipalCallback();
630     }
632     try {
633       let principal;
634       // The current JSON representation of principal is not stored as base64. We start by checking
635       // if the serialized data starts with '{' to determine if we're using the new JSON representation.
636       // If it doesn't we try the two legacy formats, old JSON and nsISerializable.
637       if (serializedPincipal.startsWith("{")) {
638         principal =
639           Services.scriptSecurityManager.JSONToPrincipal(serializedPincipal);
640       } else {
641         // Both the legacy and legacy  JSON representation of principals are stored as base64
642         // The legacy JSON kind are the only ones that will start with "{" when decoded.
643         // We check here for the legacy JSON serialized, if it doesn't start with that continue using nsISerializable.
644         // JSONToPrincipal accepts a *non* base64 encoded string and returns a principal or a null.
645         let tmpa = atob(serializedPincipal);
646         if (tmpa.startsWith("{")) {
647           principal = Services.scriptSecurityManager.JSONToPrincipal(tmpa);
648         } else {
649           principal =
650             lazy.serializationHelper.deserializeObject(serializedPincipal);
651         }
652       }
653       principal.QueryInterface(Ci.nsIPrincipal);
654       return principal;
655     } catch (e) {
656       this.log().error(
657         `Failed to deserialize serializedPincipal '${serializedPincipal}' ${e}`
658       );
659     }
660     if (!fallbackPrincipalCallback) {
661       this.log().warn(
662         "No principal passed to deserializePrincipal and no fallbackPrincipalCallback"
663       );
664       return null;
665     }
666     return fallbackPrincipalCallback();
667   },
669   /**
670    * Serialize cookieJarSettings.
671    *
672    * @param {nsICookieJarSettings} cookieJarSettings The cookieJarSettings to
673    *   serialize.
674    * @return {String} The base64 encoded cookieJarSettings data.
675    */
676   serializeCookieJarSettings(cookieJarSettings) {
677     let serialized = null;
678     if (cookieJarSettings) {
679       try {
680         serialized =
681           lazy.serializationHelper.serializeToString(cookieJarSettings);
682       } catch (e) {
683         this.log().error(
684           `Failed to serialize cookieJarSettings '${cookieJarSettings}' ${e}`
685         );
686       }
687     }
688     return serialized;
689   },
691   /**
692    * Deserialize a base64 encoded cookieJarSettings
693    *
694    * @param {String} cookieJarSettings_b64 A base64 encoded serialized cookieJarSettings.
695    * @return {nsICookieJarSettings} A deserialized cookieJarSettings.
696    */
697   deserializeCookieJarSettings(cookieJarSettings_b64) {
698     let deserialized = null;
699     if (cookieJarSettings_b64) {
700       try {
701         deserialized = lazy.serializationHelper.deserializeObject(
702           cookieJarSettings_b64
703         );
704         deserialized.QueryInterface(Ci.nsICookieJarSettings);
705       } catch (e) {
706         this.log().error(
707           `Failed to deserialize cookieJarSettings_b64 '${cookieJarSettings_b64}' ${e}`
708         );
709       }
710     }
711     return deserialized;
712   },
714   wrapHandlingUserInput(aWindow, aIsHandling, aCallback) {
715     var handlingUserInput;
716     try {
717       handlingUserInput = aWindow.windowUtils.setHandlingUserInput(aIsHandling);
718       aCallback();
719     } finally {
720       handlingUserInput.destruct();
721     }
722   },
724   /**
725    * Serialize referrerInfo.
726    *
727    * @param {nsIReferrerInfo} The referrerInfo to serialize.
728    * @return {String} The base64 encoded referrerInfo.
729    */
730   serializeReferrerInfo(referrerInfo) {
731     let serialized = null;
732     if (referrerInfo) {
733       try {
734         serialized = lazy.serializationHelper.serializeToString(referrerInfo);
735       } catch (e) {
736         this.log().error(
737           `Failed to serialize referrerInfo '${referrerInfo}' ${e}`
738         );
739       }
740     }
741     return serialized;
742   },
743   /**
744    * Deserialize a base64 encoded referrerInfo
745    *
746    * @param {String} referrerInfo_b64 A base64 encoded serialized referrerInfo.
747    * @return {nsIReferrerInfo} A deserialized referrerInfo.
748    */
749   deserializeReferrerInfo(referrerInfo_b64) {
750     let deserialized = null;
751     if (referrerInfo_b64) {
752       try {
753         deserialized =
754           lazy.serializationHelper.deserializeObject(referrerInfo_b64);
755         deserialized.QueryInterface(Ci.nsIReferrerInfo);
756       } catch (e) {
757         this.log().error(
758           `Failed to deserialize referrerInfo_b64 '${referrerInfo_b64}' ${e}`
759         );
760       }
761     }
762     return deserialized;
763   },
765   /**
766    * Returns the pids for a remote browser and its remote subframes.
767    */
768   getBrowserPids(aBrowser, aRemoteSubframes) {
769     if (!aBrowser.isRemoteBrowser || !aBrowser.frameLoader) {
770       return [];
771     }
772     let tabPid = aBrowser.frameLoader.remoteTab.osPid;
773     let pids = new Set();
774     if (aRemoteSubframes) {
775       let stack = [aBrowser.browsingContext];
776       while (stack.length) {
777         let bc = stack.pop();
778         stack.push(...bc.children);
779         if (bc.currentWindowGlobal) {
780           let pid = bc.currentWindowGlobal.osPid;
781           if (pid != tabPid) {
782             pids.add(pid);
783           }
784         }
785       }
786     }
787     return [tabPid, ...pids];
788   },
790   /**
791    * The suffix after a `=` in a remoteType is dynamic, and used to control the
792    * process pool to use. The C++ version of this method is mozilla::dom::RemoteTypePrefix().
793    */
794   remoteTypePrefix(aRemoteType) {
795     return aRemoteType.split("=")[0];
796   },
798   /**
799    * There are various types of remote types that are for web content processes, but
800    * they all start with "web". The C++ version of this method is
801    * mozilla::dom::IsWebRemoteType().
802    */
803   isWebRemoteType(aRemoteType) {
804     return aRemoteType.startsWith(WEB_REMOTE_TYPE);
805   },
807   /**
808    * Assemble or predict originAttributes from available arguments.
809    */
810   predictOriginAttributes({
811     window,
812     browser,
813     userContextId,
814     geckoViewSessionContextId,
815     privateBrowsingId,
816   }) {
817     if (browser) {
818       if (browser.browsingContext) {
819         return browser.browsingContext.originAttributes;
820       }
821       if (!window) {
822         window = browser.contentDocument?.defaultView;
823       }
824       if (!userContextId) {
825         userContextId = browser.getAttribute("usercontextid") || 0;
826       }
827       if (!geckoViewSessionContextId) {
828         geckoViewSessionContextId =
829           browser.getAttribute("geckoViewSessionContextId") || "";
830       }
831     }
833     if (window && !privateBrowsingId) {
834       privateBrowsingId = window.browsingContext.usePrivateBrowsing ? 1 : 0;
835     }
836     return { privateBrowsingId, userContextId, geckoViewSessionContextId };
837   },
840 ChromeUtils.defineLazyGetter(
841   E10SUtils,
842   "SERIALIZED_SYSTEMPRINCIPAL",
843   function () {
844     return btoa(
845       E10SUtils.serializePrincipal(
846         Services.scriptSecurityManager.getSystemPrincipal()
847       )
848     );
849   }