gecko-dev/remote/sessions/TabSession.jsm
Andreas Tolfsen ab0b38e5c0 bug 1537775: remote: move method sanity check into Domains.splitMethod; r=ochameau
This moves the assertions related to the well-formedness of the method
from the TabSession consumer to Domains.splitMethod.  Following the
introduction of TabSession, this was missing from the superclass Session.

This also fixes the "Foo.bar.baz" test case in
remote/test/unit/test_Domains.js by removing the split() function
and instead relying on String#split() inside Domains.splitMethod.

Thanks-to: Alexandre Poirot <ochameau@mozilla.com>

Differential Revision: https://phabricator.services.mozilla.com/D25947

--HG--
extra : moz-landing-system : lando
2019-04-04 09:39:28 +00:00

138 lines
4.0 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/. */
"use strict";
var EXPORTED_SYMBOLS = ["TabSession"];
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
/**
* A session to communicate with a given tab
*/
class TabSession extends Session {
/**
* @param Connection connection
* The connection used to communicate with the server.
* @param TabTarget target
* The tab target to which this session communicates with.
* @param Number id (optional)
* If this session isn't the default one used for the HTTP endpoint we
* connected to, the session requires an id to distinguish it from the default
* one. This id is used to filter our request, responses and events between
* all active sessions.
* @param Session parentSession (optional)
* If this isn't the default session, optional hand over a session to which
* we will forward all request responses and events via
* `Target.receivedMessageFromTarget` events.
*/
constructor(connection, target, id, parentSession) {
super(connection, target, id);
this.parentSession = parentSession;
this.mm.addMessageListener("remote:event", this);
this.mm.addMessageListener("remote:result", this);
this.mm.addMessageListener("remote:error", this);
this.mm.loadFrameScript("chrome://remote/content/sessions/frame-script.js", false);
}
destructor() {
super.destructor();
this.mm.sendAsyncMessage("remote:destroy", {
browsingContextId: this.browsingContext.id,
});
this.mm.removeMessageListener("remote:event", this);
this.mm.removeMessageListener("remote:result", this);
this.mm.removeMessageListener("remote:error", this);
}
async onMessage({id, method, params}) {
try {
if (typeof id == "undefined") {
throw new TypeError("Message missing 'id' field");
}
if (typeof method == "undefined") {
throw new TypeError("Message missing 'method' field");
}
const {domain, command} = Domains.splitMethod(method);
if (this.domains.has(domain)) {
await this.execute(id, domain, command, params);
} else {
this.executeInChild(id, domain, command, params);
}
} catch (e) {
this.onError(id, e);
}
}
executeInChild(id, domain, command, params) {
this.mm.sendAsyncMessage("remote:request", {
browsingContextId: this.browsingContext.id,
request: {id, domain, command, params},
});
}
onResult(id, result) {
super.onResult(id, result);
// When `Target.sendMessageToTarget` is used, we should forward the responses
// to the parent session from which we called `sendMessageToTarget`.
if (this.parentSession) {
this.parentSession.onEvent("Target.receivedMessageFromTarget", {
sessionId: this.id,
message: JSON.stringify({ id, result }),
});
}
}
onEvent(eventName, params) {
super.onEvent(eventName, params);
// When `Target.sendMessageToTarget` is used, we should forward the responses
// to the parent session from which we called `sendMessageToTarget`.
if (this.parentSession) {
this.parentSession.onEvent("Target.receivedMessageFromTarget", {
sessionId: this.id,
message: JSON.stringify({
method: eventName,
params,
}),
});
}
}
get mm() {
return this.target.mm;
}
get browsingContext() {
return this.target.browsingContext;
}
// nsIMessageListener
receiveMessage({name, data}) {
const {id, result, event, error} = data;
switch (name) {
case "remote:result":
this.onResult(id, result);
break;
case "remote:event":
this.onEvent(event.eventName, event.params);
break;
case "remote:error":
this.onError(id, error);
break;
}
}
}