Bug 1146724 - Use a SendingContext for WebChannels. r=MattN, r=markh, a=abillings
This commit is contained in:
@@ -566,7 +566,7 @@ addEventListener("WebChannelMessageToChrome", function (e) {
|
|||||||
let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
|
let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
|
||||||
|
|
||||||
if (e.detail) {
|
if (e.detail) {
|
||||||
sendAsyncMessage("WebChannelMessageToChrome", e.detail, null, principal);
|
sendAsyncMessage("WebChannelMessageToChrome", e.detail, { eventTarget: e.target }, principal);
|
||||||
} else {
|
} else {
|
||||||
Cu.reportError("WebChannel message failed. No message detail.");
|
Cu.reportError("WebChannel message failed. No message detail.");
|
||||||
}
|
}
|
||||||
@@ -575,12 +575,30 @@ addEventListener("WebChannelMessageToChrome", function (e) {
|
|||||||
// Add message listener for "WebChannelMessageToContent" messages from chrome scripts
|
// Add message listener for "WebChannelMessageToContent" messages from chrome scripts
|
||||||
addMessageListener("WebChannelMessageToContent", function (e) {
|
addMessageListener("WebChannelMessageToContent", function (e) {
|
||||||
if (e.data) {
|
if (e.data) {
|
||||||
content.dispatchEvent(new content.CustomEvent("WebChannelMessageToContent", {
|
// e.objects.eventTarget will be defined if sending a response to
|
||||||
|
// a WebChannelMessageToChrome event. An unsolicited send
|
||||||
|
// may not have an eventTarget defined, in this case send to the
|
||||||
|
// main content window.
|
||||||
|
let eventTarget = e.objects.eventTarget || content;
|
||||||
|
|
||||||
|
// if eventTarget is window then we want the document principal,
|
||||||
|
// otherwise use target itself.
|
||||||
|
let targetPrincipal = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget.document.nodePrincipal : eventTarget.nodePrincipal;
|
||||||
|
|
||||||
|
if (e.principal.subsumes(targetPrincipal)) {
|
||||||
|
// if eventTarget is a window, use it as the targetWindow, otherwise
|
||||||
|
// find the window that owns the eventTarget.
|
||||||
|
let targetWindow = eventTarget instanceof Ci.nsIDOMWindow ? eventTarget : eventTarget.ownerDocument.defaultView;
|
||||||
|
|
||||||
|
eventTarget.dispatchEvent(new targetWindow.CustomEvent("WebChannelMessageToContent", {
|
||||||
detail: Cu.cloneInto({
|
detail: Cu.cloneInto({
|
||||||
id: e.data.id,
|
id: e.data.id,
|
||||||
message: e.data.message,
|
message: e.data.message,
|
||||||
}, content),
|
}, targetWindow),
|
||||||
}));
|
}));
|
||||||
|
} else {
|
||||||
|
Cu.reportError("WebChannel message failed. Principal mismatch.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Cu.reportError("WebChannel message failed. No message data.");
|
Cu.reportError("WebChannel message failed. No message data.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,14 +149,15 @@ this.FxAccountsOAuthClient.prototype = {
|
|||||||
* Command webChannelId
|
* Command webChannelId
|
||||||
* @param message {Object}
|
* @param message {Object}
|
||||||
* Command message
|
* Command message
|
||||||
* @param target {EventTarget}
|
* @param sendingContext {Object}
|
||||||
* Channel message event target
|
* Channel message event sendingContext
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
let listener = function (webChannelId, message, target) {
|
let listener = function (webChannelId, message, sendingContext) {
|
||||||
if (message) {
|
if (message) {
|
||||||
let command = message.command;
|
let command = message.command;
|
||||||
let data = message.data;
|
let data = message.data;
|
||||||
|
let target = sendingContext && sendingContext.browser;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "oauth_complete":
|
case "oauth_complete":
|
||||||
|
|||||||
@@ -66,11 +66,15 @@ let WebChannelBroker = Object.create({
|
|||||||
*/
|
*/
|
||||||
_listener: function (event) {
|
_listener: function (event) {
|
||||||
let data = event.data;
|
let data = event.data;
|
||||||
let sender = event.target;
|
let sendingContext = {
|
||||||
|
browser: event.target,
|
||||||
|
eventTarget: event.objects.eventTarget,
|
||||||
|
principal: event.principal,
|
||||||
|
};
|
||||||
|
|
||||||
if (data && data.id) {
|
if (data && data.id) {
|
||||||
if (!event.principal) {
|
if (!event.principal) {
|
||||||
this._sendErrorEventToContent(data.id, sender, "Message principal missing");
|
this._sendErrorEventToContent(data.id, sendingContext, "Message principal missing");
|
||||||
} else {
|
} else {
|
||||||
let validChannelFound = false;
|
let validChannelFound = false;
|
||||||
data.message = data.message || {};
|
data.message = data.message || {};
|
||||||
@@ -79,13 +83,13 @@ let WebChannelBroker = Object.create({
|
|||||||
if (channel.id === data.id &&
|
if (channel.id === data.id &&
|
||||||
channel._originCheckCallback(event.principal)) {
|
channel._originCheckCallback(event.principal)) {
|
||||||
validChannelFound = true;
|
validChannelFound = true;
|
||||||
channel.deliver(data, sender);
|
channel.deliver(data, sendingContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no valid origins send an event that there is no such valid channel
|
// if no valid origins send an event that there is no such valid channel
|
||||||
if (!validChannelFound) {
|
if (!validChannelFound) {
|
||||||
this._sendErrorEventToContent(data.id, sender, "No Such Channel");
|
this._sendErrorEventToContent(data.id, sendingContext, "No Such Channel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -108,20 +112,24 @@ let WebChannelBroker = Object.create({
|
|||||||
*
|
*
|
||||||
* @param id {String}
|
* @param id {String}
|
||||||
* The WebChannel id to include in the message
|
* The WebChannel id to include in the message
|
||||||
* @param sender {EventTarget}
|
* @param sendingContext {Object}
|
||||||
* EventTarget with a "messageManager" that will send be used to send the message
|
* Message sending context
|
||||||
* @param [errorMsg] {String}
|
* @param [errorMsg] {String}
|
||||||
* Error message
|
* Error message
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sendErrorEventToContent: function (id, sender, errorMsg) {
|
_sendErrorEventToContent: function (id, sendingContext, errorMsg) {
|
||||||
|
let { browser: targetBrowser, eventTarget, principal: targetPrincipal } = sendingContext;
|
||||||
|
|
||||||
errorMsg = errorMsg || "Web Channel Broker error";
|
errorMsg = errorMsg || "Web Channel Broker error";
|
||||||
|
|
||||||
if (sender.messageManager) {
|
if (targetBrowser && targetBrowser.messageManager) {
|
||||||
sender.messageManager.sendAsyncMessage("WebChannelMessageToContent", {
|
targetBrowser.messageManager.sendAsyncMessage("WebChannelMessageToContent", {
|
||||||
id: id,
|
id: id,
|
||||||
error: errorMsg,
|
error: errorMsg,
|
||||||
}, sender);
|
}, { eventTarget: eventTarget }, targetPrincipal);
|
||||||
|
} else {
|
||||||
|
Cu.reportError("Failed to send a WebChannel error. Target invalid.");
|
||||||
}
|
}
|
||||||
Cu.reportError(id.toString() + " error message. " + errorMsg);
|
Cu.reportError(id.toString() + " error message. " + errorMsg);
|
||||||
},
|
},
|
||||||
@@ -211,8 +219,17 @@ this.WebChannel.prototype = {
|
|||||||
* The WebChannel id that was used for this message
|
* The WebChannel id that was used for this message
|
||||||
* @param {Object} message
|
* @param {Object} message
|
||||||
* The message itself
|
* The message itself
|
||||||
* @param {EventTarget} sender
|
* @param sendingContext {Object}
|
||||||
* The source of the message
|
* The sending context of the source of the message. Can be passed to
|
||||||
|
* `send` to respond to a message.
|
||||||
|
* @param sendingContext.browser {browser}
|
||||||
|
* The <browser> object that captured the
|
||||||
|
* WebChannelMessageToChrome.
|
||||||
|
* @param sendingContext.eventTarget {EventTarget}
|
||||||
|
* The <EventTarget> where the message was sent.
|
||||||
|
* @param sendingContext.principal {Principal}
|
||||||
|
* The <Principal> of the EventTarget where the
|
||||||
|
* message was sent.
|
||||||
*/
|
*/
|
||||||
listen: function (callback) {
|
listen: function (callback) {
|
||||||
if (this._deliverCallback) {
|
if (this._deliverCallback) {
|
||||||
@@ -239,16 +256,27 @@ this.WebChannel.prototype = {
|
|||||||
*
|
*
|
||||||
* @param message {Object}
|
* @param message {Object}
|
||||||
* The message object that will be sent
|
* The message object that will be sent
|
||||||
* @param target {browser}
|
* @param target {Object}
|
||||||
* The <browser> object that has a "messageManager" that sends messages
|
* A <target> with the information of where to send the message.
|
||||||
*
|
* @param target.browser {browser}
|
||||||
|
* The <browser> object with a "messageManager" that will
|
||||||
|
* be used to send the message.
|
||||||
|
* @param target.principal {Principal}
|
||||||
|
* Principal of the target. Prevents messages from
|
||||||
|
* being dispatched to unexpected origins. The system principal
|
||||||
|
* can be specified to send to any target.
|
||||||
|
* @param [target.eventTarget] {EventTarget}
|
||||||
|
* Optional eventTarget within the browser, use to send to a
|
||||||
|
* specific element, e.g., an iframe.
|
||||||
*/
|
*/
|
||||||
send: function (message, target) {
|
send: function (message, target) {
|
||||||
if (message && target && target.messageManager) {
|
let { browser, principal, eventTarget } = target;
|
||||||
target.messageManager.sendAsyncMessage("WebChannelMessageToContent", {
|
|
||||||
|
if (message && browser && browser.messageManager && principal) {
|
||||||
|
browser.messageManager.sendAsyncMessage("WebChannelMessageToContent", {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
message: message
|
message: message
|
||||||
});
|
}, { eventTarget }, principal);
|
||||||
} else if (!message) {
|
} else if (!message) {
|
||||||
Cu.reportError("Failed to send a WebChannel message. Message not set.");
|
Cu.reportError("Failed to send a WebChannel message. Message not set.");
|
||||||
} else {
|
} else {
|
||||||
@@ -261,18 +289,26 @@ this.WebChannel.prototype = {
|
|||||||
*
|
*
|
||||||
* @param data {Object}
|
* @param data {Object}
|
||||||
* Message data
|
* Message data
|
||||||
* @param sender {browser}
|
* @param sendingContext {Object}
|
||||||
* Message sender
|
* Message sending context.
|
||||||
|
* @param sendingContext.browser {browser}
|
||||||
|
* The <browser> object that captured the
|
||||||
|
* WebChannelMessageToChrome.
|
||||||
|
* @param sendingContext.eventTarget {EventTarget}
|
||||||
|
* The <EventTarget> where the message was sent.
|
||||||
|
* @param sendingContext.principal {Principal}
|
||||||
|
* The <Principal> of the EventTarget where the message was sent.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
deliver: function(data, sender) {
|
deliver: function(data, sendingContext) {
|
||||||
if (this._deliverCallback) {
|
if (this._deliverCallback) {
|
||||||
try {
|
try {
|
||||||
this._deliverCallback(data.id, data.message, sender);
|
this._deliverCallback(data.id, data.message, sendingContext);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
this.send({
|
this.send({
|
||||||
errno: ERRNO_UNKNOWN_ERROR,
|
errno: ERRNO_UNKNOWN_ERROR,
|
||||||
error: ex.message ? ex.message : ERROR_UNKNOWN
|
error: ex.message ? ex.message : ERROR_UNKNOWN
|
||||||
}, sender);
|
}, sendingContext);
|
||||||
Cu.reportError("Failed to execute callback:" + ex);
|
Cu.reportError("Failed to execute callback:" + ex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ add_task(function test_web_channel_broker_listener() {
|
|||||||
},
|
},
|
||||||
principal: {
|
principal: {
|
||||||
origin: URL_STRING
|
origin: URL_STRING
|
||||||
}
|
},
|
||||||
|
objects: {
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
WebChannelBroker._listener(mockEvent);
|
WebChannelBroker._listener(mockEvent);
|
||||||
|
|||||||
Reference in New Issue
Block a user