1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 var EXPORTED_SYMBOLS = ["TabSession"];
9 const { Session } = ChromeUtils.import(
10 "chrome://remote/content/sessions/Session.jsm"
14 * A session to communicate with a given tab
16 class TabSession extends Session {
18 * @param Connection connection
19 * The connection used to communicate with the server.
20 * @param TabTarget target
21 * The tab target to which this session communicates with.
22 * @param Number id (optional)
23 * If this session isn't the default one used for the HTTP endpoint we
24 * connected to, the session requires an id to distinguish it from the default
25 * one. This id is used to filter our request, responses and events between
26 * all active sessions.
27 * For now, this is only passed by `Target.attachToTarget()`.
28 * Otherwise it will be undefined when you are connecting directly to
29 * a given Tab. i.e. connect directly to the WebSocket URL provided by
30 * /json/list HTTP endpoint.
32 constructor(connection, target, id) {
33 super(connection, target, id);
35 // Request id => { resolve, reject }
36 this.requestPromises = new Map();
38 this.mm.addMessageListener("remote:event", this);
39 this.mm.addMessageListener("remote:result", this);
40 this.mm.addMessageListener("remote:error", this);
42 this.mm.loadFrameScript(
43 "chrome://remote/content/sessions/frame-script.js",
51 this.requestPromises.clear();
53 this.mm.sendAsyncMessage("remote:destroy", {
54 browsingContextId: this.browsingContext.id,
57 this.mm.removeMessageListener("remote:event", this);
58 this.mm.removeMessageListener("remote:result", this);
59 this.mm.removeMessageListener("remote:error", this);
62 execute(id, domain, command, params) {
63 // Check if the domain and command is implemented in the parent
64 // and execute it there. Otherwise forward the command to the content process
65 // in order to try to execute it in the content process.
66 if (this.domains.domainSupportsMethod(domain, command)) {
67 return super.execute(id, domain, command, params);
69 return this.executeInChild(id, domain, command, params);
72 executeInChild(id, domain, command, params) {
73 return new Promise((resolve, reject) => {
74 // Save the promise's resolution and rejection handler in order to later
75 // resolve this promise once we receive the reply back from the content process.
76 this.requestPromises.set(id, { resolve, reject });
78 this.mm.sendAsyncMessage("remote:request", {
79 browsingContextId: this.browsingContext.id,
80 request: { id, domain, command, params },
86 return this.target.mm;
89 get browsingContext() {
90 return this.target.browsingContext;
95 receiveMessage({ name, data }) {
96 const { id, result, event, error } = data;
100 const { resolve } = this.requestPromises.get(id);
102 this.requestPromises.delete(id);
106 this.connection.onEvent(event.eventName, event.params, this.id);
110 const { reject } = this.requestPromises.get(id);
112 this.requestPromises.delete(id);