This function is somewhat redundant nowadays, and is only used by tests, so moving the logic out of E10SUtils and into the tests may make more sense. Differential Revision: https://phabricator.services.mozilla.com/D282084
461 lines
13 KiB
JavaScript
461 lines
13 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
|
|
const lazy = {};
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
lazy,
|
|
"useCrossOriginOpenerPolicy",
|
|
"browser.tabs.remote.useCrossOriginOpenerPolicy",
|
|
false
|
|
);
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
lazy,
|
|
"serializationHelper",
|
|
"@mozilla.org/network/serialization-helper;1",
|
|
Ci.nsISerializationHelper
|
|
);
|
|
|
|
const NOT_REMOTE = null;
|
|
|
|
// These must match the similar ones in RemoteTypes.h, ProcInfo.h, ChromeUtils.webidl and ChromeUtils.cpp
|
|
const WEB_REMOTE_TYPE = "web";
|
|
const FISSION_WEB_REMOTE_TYPE = "webIsolated";
|
|
const WEB_REMOTE_COOP_COEP_TYPE_PREFIX = "webCOOP+COEP=";
|
|
const FILE_REMOTE_TYPE = "file";
|
|
const EXTENSION_REMOTE_TYPE = "extension";
|
|
const PRIVILEGEDABOUT_REMOTE_TYPE = "privilegedabout";
|
|
const PRIVILEGEDMOZILLA_REMOTE_TYPE = "privilegedmozilla";
|
|
const SERVICEWORKER_REMOTE_TYPE = "webServiceWorker";
|
|
|
|
// This must start with the WEB_REMOTE_TYPE above.
|
|
const DEFAULT_REMOTE_TYPE = WEB_REMOTE_TYPE;
|
|
|
|
// This list is duplicated between Navigator.cpp and here because navigator
|
|
// is not accessible in this context. Please update both if the list changes.
|
|
const STANDARD_SAFE_PROTOCOLS = [
|
|
"bitcoin",
|
|
"ftp",
|
|
"ftps",
|
|
"geo",
|
|
"im",
|
|
"irc",
|
|
"ircs",
|
|
"magnet",
|
|
"mailto",
|
|
"matrix",
|
|
"mms",
|
|
"news",
|
|
"nntp",
|
|
"openpgp4fpr",
|
|
"sftp",
|
|
"sip",
|
|
"sms",
|
|
"smsto",
|
|
"ssh",
|
|
"tel",
|
|
"urn",
|
|
"webcal",
|
|
"wtai",
|
|
"xmpp",
|
|
];
|
|
|
|
export var E10SUtils = {
|
|
DEFAULT_REMOTE_TYPE,
|
|
NOT_REMOTE,
|
|
WEB_REMOTE_TYPE,
|
|
WEB_REMOTE_COOP_COEP_TYPE_PREFIX,
|
|
FILE_REMOTE_TYPE,
|
|
EXTENSION_REMOTE_TYPE,
|
|
PRIVILEGEDABOUT_REMOTE_TYPE,
|
|
PRIVILEGEDMOZILLA_REMOTE_TYPE,
|
|
FISSION_WEB_REMOTE_TYPE,
|
|
SERVICEWORKER_REMOTE_TYPE,
|
|
STANDARD_SAFE_PROTOCOLS,
|
|
|
|
/**
|
|
* @param aURI The URI of the about page
|
|
* @return The instance of the nsIAboutModule related to this uri
|
|
*/
|
|
getAboutModule(aURL) {
|
|
// Needs to match NS_GetAboutModuleName
|
|
let moduleName = aURL.pathQueryRef.replace(/[#?].*/, "").toLowerCase();
|
|
let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName;
|
|
try {
|
|
return Cc[contract].getService(Ci.nsIAboutModule);
|
|
} catch (e) {
|
|
// Either the about module isn't defined or it is broken. In either case
|
|
// ignore it.
|
|
return null;
|
|
}
|
|
},
|
|
|
|
useCrossOriginOpenerPolicy() {
|
|
return lazy.useCrossOriginOpenerPolicy;
|
|
},
|
|
|
|
_log: null,
|
|
_uriStr: function uriStr(aUri) {
|
|
return aUri ? aUri.spec : "undefined";
|
|
},
|
|
|
|
log: function log() {
|
|
if (!this._log) {
|
|
this._log = console.createInstance({
|
|
prefix: "ProcessSwitch",
|
|
maxLogLevel: "Error", // Change to "Debug" the process switching code
|
|
});
|
|
|
|
this._log.debug("Setup logger");
|
|
}
|
|
|
|
return this._log;
|
|
},
|
|
|
|
/**
|
|
* Serialize csp data.
|
|
*
|
|
* @param {nsIContentSecurity} csp. The csp to serialize.
|
|
* @return {string} The base64 encoded csp data.
|
|
*/
|
|
serializeCSP(csp) {
|
|
let serializedCSP = null;
|
|
|
|
try {
|
|
if (csp) {
|
|
serializedCSP = lazy.serializationHelper.serializeToString(csp);
|
|
}
|
|
} catch (e) {
|
|
this.log().error(`Failed to serialize csp '${csp}' ${e}`);
|
|
}
|
|
return serializedCSP;
|
|
},
|
|
|
|
/**
|
|
* Deserialize a base64 encoded csp (serialized with
|
|
* Utils::serializeCSP).
|
|
*
|
|
* @param {string} csp_b64 A base64 encoded serialized csp.
|
|
* @return {nsIContentSecurityPolicy} A deserialized csp.
|
|
*/
|
|
deserializeCSP(csp_b64) {
|
|
if (!csp_b64) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
let csp = lazy.serializationHelper.deserializeObject(csp_b64);
|
|
csp.QueryInterface(Ci.nsIContentSecurityPolicy);
|
|
return csp;
|
|
} catch (e) {
|
|
this.log().error(`Failed to deserialize csp_b64 '${csp_b64}' ${e}`);
|
|
}
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Serialize policyContainer data.
|
|
*
|
|
* @param {nsIPolicyContainer} policyContainer. The policyContainer to serialize.
|
|
* @return {string} The base64 encoded policyContainer data.
|
|
*/
|
|
serializePolicyContainer(policyContainer) {
|
|
let serializedPolicyContainer = null;
|
|
|
|
try {
|
|
if (policyContainer) {
|
|
serializedPolicyContainer =
|
|
lazy.serializationHelper.serializeToString(policyContainer);
|
|
}
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to serialize policyContainer '${policyContainer}' ${e}`
|
|
);
|
|
}
|
|
return serializedPolicyContainer;
|
|
},
|
|
|
|
/**
|
|
* Deserialize a base64 encoded policyContainer (serialized with
|
|
* Utils::serializePolicyContainer).
|
|
*
|
|
* @param {string} policyContainerB64 A base64 encoded serialized policyContainer.
|
|
* @return {nsIPolicyContainer} A deserialized policyContainer.
|
|
*/
|
|
deserializePolicyContainer(policyContainerB64) {
|
|
if (!policyContainerB64) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
let policyContainer =
|
|
lazy.serializationHelper.deserializeObject(policyContainerB64);
|
|
policyContainer.QueryInterface(Ci.nsIPolicyContainer);
|
|
return policyContainer;
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to deserialize policyContainerB64 '${policyContainerB64}' ${e}`
|
|
);
|
|
}
|
|
return null;
|
|
},
|
|
|
|
makeInputStream(data) {
|
|
if (typeof data == "string") {
|
|
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
|
|
Ci.nsISupportsCString
|
|
);
|
|
stream.data = data;
|
|
return stream; // XPConnect will QI this to nsIInputStream for us.
|
|
}
|
|
|
|
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
|
|
Ci.nsISupportsCString
|
|
);
|
|
stream.data = data.content;
|
|
|
|
if (data.headers) {
|
|
let mimeStream = Cc[
|
|
"@mozilla.org/network/mime-input-stream;1"
|
|
].createInstance(Ci.nsIMIMEInputStream);
|
|
|
|
mimeStream.setData(stream);
|
|
for (let [name, value] of data.headers) {
|
|
mimeStream.addHeader(name, value);
|
|
}
|
|
return mimeStream;
|
|
}
|
|
|
|
return stream; // XPConnect will QI this to nsIInputStream for us.
|
|
},
|
|
|
|
/**
|
|
* Serialize principal data.
|
|
*
|
|
* @param {nsIPrincipal} principal The principal to serialize.
|
|
* @return {string} The serialized principal data.
|
|
*/
|
|
serializePrincipal(principal) {
|
|
let serializedPrincipal = null;
|
|
|
|
try {
|
|
if (principal) {
|
|
serializedPrincipal =
|
|
Services.scriptSecurityManager.principalToJSON(principal);
|
|
}
|
|
} catch (e) {
|
|
this.log().error(`Failed to serialize principal '${principal}' ${e}`);
|
|
}
|
|
|
|
return serializedPrincipal;
|
|
},
|
|
|
|
/**
|
|
* Deserialize a principal (serialized with serializePrincipal).
|
|
*
|
|
* @param {string} serializedPincipal A serialized principal.
|
|
* @return {nsIPrincipal} A deserialized principal.
|
|
*/
|
|
deserializePrincipal(serializedPincipal, fallbackPrincipalCallback = null) {
|
|
if (!serializedPincipal) {
|
|
if (!fallbackPrincipalCallback) {
|
|
this.log().warn(
|
|
"No principal passed to deserializePrincipal and no fallbackPrincipalCallback"
|
|
);
|
|
return null;
|
|
}
|
|
|
|
return fallbackPrincipalCallback();
|
|
}
|
|
|
|
try {
|
|
let principal;
|
|
// The current JSON representation of principal is not stored as base64. We start by checking
|
|
// if the serialized data starts with '{' to determine if we're using the new JSON representation.
|
|
// If it doesn't we try the two legacy formats, old JSON and nsISerializable.
|
|
if (serializedPincipal.startsWith("{")) {
|
|
principal =
|
|
Services.scriptSecurityManager.JSONToPrincipal(serializedPincipal);
|
|
} else {
|
|
// Both the legacy and legacy JSON representation of principals are stored as base64
|
|
// The legacy JSON kind are the only ones that will start with "{" when decoded.
|
|
// We check here for the legacy JSON serialized, if it doesn't start with that continue using nsISerializable.
|
|
// JSONToPrincipal accepts a *non* base64 encoded string and returns a principal or a null.
|
|
let tmpa = atob(serializedPincipal);
|
|
if (tmpa.startsWith("{")) {
|
|
principal = Services.scriptSecurityManager.JSONToPrincipal(tmpa);
|
|
} else {
|
|
principal =
|
|
lazy.serializationHelper.deserializeObject(serializedPincipal);
|
|
}
|
|
}
|
|
principal.QueryInterface(Ci.nsIPrincipal);
|
|
return principal;
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to deserialize serializedPincipal '${serializedPincipal}' ${e}`
|
|
);
|
|
}
|
|
if (!fallbackPrincipalCallback) {
|
|
this.log().warn(
|
|
"No principal passed to deserializePrincipal and no fallbackPrincipalCallback"
|
|
);
|
|
return null;
|
|
}
|
|
return fallbackPrincipalCallback();
|
|
},
|
|
|
|
/**
|
|
* Serialize cookieJarSettings.
|
|
*
|
|
* @param {nsICookieJarSettings} cookieJarSettings The cookieJarSettings to
|
|
* serialize.
|
|
* @return {string} The base64 encoded cookieJarSettings data.
|
|
*/
|
|
serializeCookieJarSettings(cookieJarSettings) {
|
|
let serialized = null;
|
|
if (cookieJarSettings) {
|
|
try {
|
|
serialized =
|
|
lazy.serializationHelper.serializeToString(cookieJarSettings);
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to serialize cookieJarSettings '${cookieJarSettings}' ${e}`
|
|
);
|
|
}
|
|
}
|
|
return serialized;
|
|
},
|
|
|
|
/**
|
|
* Deserialize a base64 encoded cookieJarSettings
|
|
*
|
|
* @param {string} cookieJarSettings_b64 A base64 encoded serialized cookieJarSettings.
|
|
* @return {nsICookieJarSettings} A deserialized cookieJarSettings.
|
|
*/
|
|
deserializeCookieJarSettings(cookieJarSettings_b64) {
|
|
let deserialized = null;
|
|
if (cookieJarSettings_b64) {
|
|
try {
|
|
deserialized = lazy.serializationHelper.deserializeObject(
|
|
cookieJarSettings_b64
|
|
);
|
|
deserialized.QueryInterface(Ci.nsICookieJarSettings);
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to deserialize cookieJarSettings_b64 '${cookieJarSettings_b64}' ${e}`
|
|
);
|
|
}
|
|
}
|
|
return deserialized;
|
|
},
|
|
|
|
wrapHandlingUserInput(aWindow, aIsHandling, aCallback) {
|
|
var handlingUserInput;
|
|
try {
|
|
handlingUserInput = aWindow.windowUtils.setHandlingUserInput(aIsHandling);
|
|
aCallback();
|
|
} finally {
|
|
handlingUserInput.destruct();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Serialize referrerInfo.
|
|
*
|
|
* @param {nsIReferrerInfo} The referrerInfo to serialize.
|
|
* @return {string} The base64 encoded referrerInfo.
|
|
*/
|
|
serializeReferrerInfo(referrerInfo) {
|
|
let serialized = null;
|
|
if (referrerInfo) {
|
|
try {
|
|
serialized = lazy.serializationHelper.serializeToString(referrerInfo);
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to serialize referrerInfo '${referrerInfo}' ${e}`
|
|
);
|
|
}
|
|
}
|
|
return serialized;
|
|
},
|
|
/**
|
|
* Deserialize a base64 encoded referrerInfo
|
|
*
|
|
* @param {string} referrerInfo_b64 A base64 encoded serialized referrerInfo.
|
|
* @return {nsIReferrerInfo} A deserialized referrerInfo.
|
|
*/
|
|
deserializeReferrerInfo(referrerInfo_b64) {
|
|
let deserialized = null;
|
|
if (referrerInfo_b64) {
|
|
try {
|
|
deserialized =
|
|
lazy.serializationHelper.deserializeObject(referrerInfo_b64);
|
|
deserialized.QueryInterface(Ci.nsIReferrerInfo);
|
|
} catch (e) {
|
|
this.log().error(
|
|
`Failed to deserialize referrerInfo_b64 '${referrerInfo_b64}' ${e}`
|
|
);
|
|
}
|
|
}
|
|
return deserialized;
|
|
},
|
|
|
|
/**
|
|
* Returns the pids for a remote browser and its remote subframes.
|
|
*/
|
|
getBrowserPids(aBrowser, aRemoteSubframes) {
|
|
if (!aBrowser.isRemoteBrowser || !aBrowser.frameLoader) {
|
|
return [];
|
|
}
|
|
let tabPid = aBrowser.frameLoader.remoteTab.osPid;
|
|
let pids = new Set();
|
|
if (aRemoteSubframes) {
|
|
let stack = [aBrowser.browsingContext];
|
|
while (stack.length) {
|
|
let bc = stack.pop();
|
|
stack.push(...bc.children);
|
|
if (bc.currentWindowGlobal) {
|
|
let pid = bc.currentWindowGlobal.osPid;
|
|
if (pid != tabPid) {
|
|
pids.add(pid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return [tabPid, ...pids];
|
|
},
|
|
|
|
/**
|
|
* The suffix after a `=` in a remoteType is dynamic, and used to control the
|
|
* process pool to use. The C++ version of this method is mozilla::dom::RemoteTypePrefix().
|
|
*/
|
|
remoteTypePrefix(aRemoteType) {
|
|
return aRemoteType.split("=")[0];
|
|
},
|
|
|
|
/**
|
|
* There are various types of remote types that are for web content processes, but
|
|
* they all start with "web". The C++ version of this method is
|
|
* mozilla::dom::IsWebRemoteType().
|
|
*/
|
|
isWebRemoteType(aRemoteType) {
|
|
return aRemoteType.startsWith(WEB_REMOTE_TYPE);
|
|
},
|
|
};
|
|
|
|
ChromeUtils.defineLazyGetter(
|
|
E10SUtils,
|
|
"SERIALIZED_SYSTEMPRINCIPAL",
|
|
function () {
|
|
return btoa(
|
|
E10SUtils.serializePrincipal(
|
|
Services.scriptSecurityManager.getSystemPrincipal()
|
|
)
|
|
);
|
|
}
|
|
);
|