зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1324467 - Make copy of data to send to listener; r=automatedtester
The payload sent to the listener through `GeckoDriver#sendAsync` is sometimes mutated if a `commandID` parameter is given. Because `data` is sometimes a reference to an object, the original object gets modified with an additional `command_id` field. To avoid this we copy the object before mutating it and pass it through to the message manager. MozReview-Commit-ID: HM2tnPqbAge --HG-- extra : rebase_source : 6aa593973d82bdf4addd8003ce68df9ad3179a4a
This commit is contained in:
Родитель
91321b54b4
Коммит
8ff4e83b8c
|
@ -209,48 +209,61 @@ GeckoDriver.prototype.switchToGlobalMessageManager = function() {
|
|||
/**
|
||||
* Helper method to send async messages to the content listener.
|
||||
* Correct usage is to pass in the name of a function in listener.js,
|
||||
* a message object consisting of JSON serialisable primitives,
|
||||
* and the current command's ID.
|
||||
* a serialisable object, and optionally the current command's ID
|
||||
* when not using the modern dispatching technique.
|
||||
*
|
||||
* @param {string} name
|
||||
* Suffix of the targetted message listener ({@code Marionette:<suffix>}).
|
||||
* Suffix of the targetted message listener
|
||||
* ({@code Marionette:<suffix>}).
|
||||
* @param {Object=} msg
|
||||
* JSON serialisable object to send to the listener.
|
||||
* @param {number=} cmdId
|
||||
* Command ID to ensure synchronisity.
|
||||
* Optional JSON serialisable object to send to the listener.
|
||||
* @param {number=} commandID
|
||||
* Optional command ID to ensure synchronisity.
|
||||
*/
|
||||
GeckoDriver.prototype.sendAsync = function (name, msg, cmdId) {
|
||||
let curRemoteFrame = this.curBrowser.frameManager.currentRemoteFrame;
|
||||
GeckoDriver.prototype.sendAsync = function (name, data, commandID) {
|
||||
name = "Marionette:" + name;
|
||||
let payload = copy(data);
|
||||
|
||||
// TODO(ato): When proxy.AsyncMessageChannel
|
||||
// is used for all chrome <-> content communication
|
||||
// this can be removed.
|
||||
if (cmdId) {
|
||||
msg.command_id = cmdId;
|
||||
if (commandID) {
|
||||
payload.command_id = commandID;
|
||||
}
|
||||
|
||||
if (curRemoteFrame === null) {
|
||||
this.curBrowser.executeWhenReady(() => {
|
||||
if (this.curBrowser.curFrameId) {
|
||||
this.mm.broadcastAsyncMessage(name + this.curBrowser.curFrameId, msg);
|
||||
} else {
|
||||
throw new NoSuchWindowError(
|
||||
"No such content frame; perhaps the listener was not registered?");
|
||||
}
|
||||
});
|
||||
if (!this.curBrowser.frameManager.currentRemoteFrame) {
|
||||
this.broadcastDelayedAsyncMessage_(name, payload);
|
||||
} else {
|
||||
let remoteFrameId = curRemoteFrame.targetFrameId;
|
||||
try {
|
||||
this.mm.sendAsyncMessage(name + remoteFrameId, msg);
|
||||
} catch (e) {
|
||||
switch(e.result) {
|
||||
case Cr.NS_ERROR_FAILURE:
|
||||
case Cr.NS_ERROR_NOT_INITIALIZED:
|
||||
throw new NoSuchWindowError();
|
||||
default:
|
||||
throw new WebDriverError(e.toString());
|
||||
}
|
||||
this.sendTargettedAsyncMessage_(name, payload);
|
||||
}
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.broadcastDelayedAsyncMessage_ = function (name, payload) {
|
||||
this.curBrowser.executeWhenReady(() => {
|
||||
if (this.curBrowser.curFrameId) {
|
||||
const target = name + this.curBrowser.curFrameId;
|
||||
this.mm.broadcastAsyncMessage(target, payload);
|
||||
} else {
|
||||
throw new NoSuchWindowError(
|
||||
"No such content frame; perhaps the listener was not registered?");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.sendTargettedAsyncMessage_ = function (name, payload) {
|
||||
const curRemoteFrame = this.curBrowser.frameManager.currentRemoteFrame;
|
||||
const target = name + curRemoteFrame.targetFrameId;
|
||||
|
||||
try {
|
||||
this.mm.sendAsyncMessage(target, payload);
|
||||
} catch (e) {
|
||||
switch (e.result) {
|
||||
case Cr.NS_ERROR_FAILURE:
|
||||
case Cr.NS_ERROR_NOT_INITIALIZED:
|
||||
throw new NoSuchWindowError();
|
||||
|
||||
default:
|
||||
throw new WebDriverError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -462,8 +475,8 @@ GeckoDriver.prototype.registerBrowser = function (id, be) {
|
|||
GeckoDriver.prototype.registerPromise = function() {
|
||||
const li = "Marionette:register";
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let cb = (msg) => {
|
||||
return new Promise(resolve => {
|
||||
let cb = msg => {
|
||||
let wid = msg.json.value;
|
||||
let be = msg.target;
|
||||
let rv = this.registerBrowser(wid, be);
|
||||
|
@ -486,7 +499,7 @@ GeckoDriver.prototype.registerPromise = function() {
|
|||
|
||||
GeckoDriver.prototype.listeningPromise = function() {
|
||||
const li = "Marionette:listenersAttached";
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
let cb = () => {
|
||||
this.mm.removeMessageListener(li, cb);
|
||||
resolve();
|
||||
|
@ -584,8 +597,10 @@ GeckoDriver.prototype.newSession = function*(cmd, resp) {
|
|||
yield registerBrowsers;
|
||||
yield browserListening;
|
||||
|
||||
resp.body.sessionId = this.sessionId;
|
||||
resp.body.capabilities = this.sessionCapabilities;
|
||||
return {
|
||||
sessionId: this.sessionId,
|
||||
capabilities: this.sessionCapabilities,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -671,7 +686,6 @@ GeckoDriver.prototype.setSessionCapabilities = function (newCaps) {
|
|||
let caps = copy(this.sessionCapabilities);
|
||||
caps = copy(newCaps, caps);
|
||||
logger.config("Changing capabilities: " + JSON.stringify(caps));
|
||||
|
||||
this.sessionCapabilities = caps;
|
||||
};
|
||||
|
||||
|
@ -2895,3 +2909,12 @@ GeckoDriver.prototype.commands = {
|
|||
"addon:install": GeckoDriver.prototype.installAddon,
|
||||
"addon:uninstall": GeckoDriver.prototype.uninstallAddon,
|
||||
};
|
||||
|
||||
function copy (obj) {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.slice();
|
||||
} else if (typeof obj == "object") {
|
||||
return Object.assign({}, obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -123,11 +123,10 @@ function registerSelf() {
|
|||
if (register[0]) {
|
||||
let {id, remotenessChange} = register[0][0];
|
||||
capabilities = register[0][2];
|
||||
isB2G = capabilities.platformName == "b2g";
|
||||
listenerId = id;
|
||||
if (typeof id != "undefined") {
|
||||
// check if we're the main process
|
||||
if (register[0][1] == true) {
|
||||
if (register[0][1]) {
|
||||
addMessageListener("MarionetteMainListener:emitTouchEvent", emitTouchEventForIFrame);
|
||||
}
|
||||
startListeners();
|
||||
|
|
Загрузка…
Ссылка в новой задаче