mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Bug 1541557: Part 6 - Read scripts for loadChromeScript in child process rather than parent. r=nika
`loadChromeScript` is often called with http: URLs pointing to mochitest resources, which need to be read synchronously before they can be executed. Unfortunately, while the API for this pretends to be synchronous, it really spins the event loop underneath. When we attempt to use it in the parent, that means that we spin the event loop and process messages from the child before the script has been executed. And since those messages often contain messages intended for the chrome script, that causes problems. When the chrome script APIs use sync messaging, this doesn't matter much, since the `loadChromeScript` call blocks the caller until the message handler in the parent returns. When it uses async messaging, though, we have no such luck, and the messages intended for the script get sent to the parent immediately. Loading the script contents in the child solves this problem, since it reliably blocks the child callers until the script contents are ready, and doesn't give them a chance to try to send messages to the script while it's still being read. Differential Revision: https://phabricator.services.mozilla.com/D35056 --HG-- extra : rebase_source : 137a244f2c071977ee633631de05f7fd776e9b88 extra : source : c2697f04d38cf0b01b1f3e227910ab5890926a33
This commit is contained in:
parent
3e44c16cf9
commit
0f5c62c855
@ -235,6 +235,46 @@ class SpecialPowersAPI {
|
||||
return mc.port2;
|
||||
}
|
||||
|
||||
_readUrlAsString(aUrl) {
|
||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
||||
// to evaluate http:// urls...
|
||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: aUrl,
|
||||
loadUsingSystemPrincipal: true,
|
||||
});
|
||||
var input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
var str;
|
||||
var buffer = [];
|
||||
|
||||
while ((str = scriptableStream.read(4096))) {
|
||||
buffer.push(str);
|
||||
}
|
||||
|
||||
var output = buffer.join("");
|
||||
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
|
||||
var status;
|
||||
if (channel instanceof Ci.nsIHttpChannel) {
|
||||
status = channel.responseStatus;
|
||||
}
|
||||
|
||||
if (status == 404) {
|
||||
throw new Error(
|
||||
`Error while executing chrome script '${aUrl}':\n` +
|
||||
"The script doesn't exist. Ensure you have registered it in " +
|
||||
"'support-files' in your mochitest.ini.");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
loadChromeScript(urlOrFunction, sandboxOptions) {
|
||||
// Create a unique id for this chrome script
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
||||
@ -249,6 +289,14 @@ class SpecialPowersAPI {
|
||||
name: urlOrFunction.name,
|
||||
};
|
||||
} else {
|
||||
// Note: We need to do this in the child since, even though
|
||||
// `_readUrlAsString` pretends to be synchronous, its channel
|
||||
// winds up spinning the event loop when loading HTTP URLs. That
|
||||
// leads to unexpected out-of-order operations if the child sends
|
||||
// a message immediately after loading the script.
|
||||
scriptArgs.function = {
|
||||
body: this._readUrlAsString(urlOrFunction),
|
||||
};
|
||||
scriptArgs.url = urlOrFunction;
|
||||
}
|
||||
this._sendSyncMessage("SPLoadChromeScript",
|
||||
|
@ -7,7 +7,6 @@
|
||||
var EXPORTED_SYMBOLS = ["SpecialPowersObserverAPI", "SpecialPowersError"];
|
||||
|
||||
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
var {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
@ -206,46 +205,6 @@ class SpecialPowersObserverAPI {
|
||||
return Services.io.newURI(url);
|
||||
}
|
||||
|
||||
_readUrlAsString(aUrl) {
|
||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
||||
// to evaluate http:// urls...
|
||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: aUrl,
|
||||
loadUsingSystemPrincipal: true,
|
||||
});
|
||||
var input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
var str;
|
||||
var buffer = [];
|
||||
|
||||
while ((str = scriptableStream.read(4096))) {
|
||||
buffer.push(str);
|
||||
}
|
||||
|
||||
var output = buffer.join("");
|
||||
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
|
||||
var status;
|
||||
if (channel instanceof Ci.nsIHttpChannel) {
|
||||
status = channel.responseStatus;
|
||||
}
|
||||
|
||||
if (status == 404) {
|
||||
throw new SpecialPowersError(
|
||||
"Error while executing chrome script '" + aUrl + "':\n" +
|
||||
"The script doesn't exists. Ensure you have registered it in " +
|
||||
"'support-files' in your mochitest.ini.");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
_sendReply(aMessage, aReplyName, aReplyMsg) {
|
||||
let mm = aMessage.target.frameLoader
|
||||
.messageManager;
|
||||
@ -446,14 +405,12 @@ class SpecialPowersObserverAPI {
|
||||
|
||||
case "SPLoadChromeScript": {
|
||||
let id = aMessage.json.id;
|
||||
let jsScript;
|
||||
let scriptName;
|
||||
|
||||
let jsScript = aMessage.json.function.body;
|
||||
if (aMessage.json.url) {
|
||||
jsScript = this._readUrlAsString(aMessage.json.url);
|
||||
scriptName = aMessage.json.url;
|
||||
} else if (aMessage.json.function) {
|
||||
jsScript = aMessage.json.function.body;
|
||||
scriptName = aMessage.json.function.name
|
||||
|| "<loadChromeScript anonymous function>";
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user