Bug 1533679 - Implement /json/version. r=ato
authorAlexandre Poirot <poirot.alex@gmail.com>
Sun, 10 Mar 2019 12:51:49 +0000
changeset 521284 735dcab78c93
parent 521283 13431774ebec
child 521285 44e4bcd29904
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1533679
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1533679 - Implement /json/version. r=ato Introduces a new kind of target "main-process", which is not bound to any particular browser-element/browsing-context. This implements only a subtest of domains and typical won't support the "content" ones. This will require some more work in order to acknowledge having multiple kinds of targets. We will also have "worker", "addon" and remoted-frames which will be very similar to tabs. Depends on D22690 Differential Revision: https://phabricator.services.mozilla.com/D22691
remote/JSONHandler.jsm
remote/jar.mn
remote/targets/MainProcessTarget.jsm
remote/targets/Targets.jsm
--- a/remote/JSONHandler.jsm
+++ b/remote/JSONHandler.jsm
@@ -17,17 +17,25 @@ class JSONHandler {
     this.routes = {
       "/json/version": this.getVersion.bind(this),
       "/json/protocol": this.getProtocol.bind(this),
       "/json/list": this.getTargetList.bind(this),
     };
   }
 
   getVersion() {
-    return {};
+    const mainProcessTarget = this.agent.targets.getMainProcessTarget();
+    return {
+      "Browser": "Firefox",
+      "Protocol-Version": "1.0",
+      "User-Agent": "Mozilla",
+      "V8-Version": "1.0",
+      "WebKit-Version": "1.0",
+      "webSocketDebuggerUrl": mainProcessTarget.toJSON().webSocketDebuggerUrl,
+    };
   }
 
   getProtocol() {
     return Protocol.Description;
   }
 
   getTargetList() {
     return [...this.agent.targets];
--- a/remote/jar.mn
+++ b/remote/jar.mn
@@ -16,16 +16,17 @@ remote.jar:
 
   # sessions
   content/sessions/frame-script.js (sessions/frame-script.js)
   content/sessions/ContentProcessSession.jsm (sessions/ContentProcessSession.jsm)
   content/sessions/Session.jsm (sessions/Session.jsm)
 
   # targets
   content/targets/Target.jsm (targets/Target.jsm)
+  content/targets/MainProcessTarget.jsm (targets/MainProcessTarget.jsm)
   content/targets/Targets.jsm (targets/Targets.jsm)
 
   # domains
   content/domains/Domain.jsm (domains/Domain.jsm)
   content/domains/Domains.jsm (domains/Domains.jsm)
   content/domains/ContentProcessDomain.jsm (domains/ContentProcessDomain.jsm)
   content/domains/ContentProcessDomains.jsm (domains/ContentProcessDomains.jsm)
   content/domains/ParentProcessDomains.jsm (domains/ParentProcessDomains.jsm)
new file mode 100644
--- /dev/null
+++ b/remote/targets/MainProcessTarget.jsm
@@ -0,0 +1,71 @@
+/* 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 = ["MainProcessTarget"];
+
+const {Connection} = ChromeUtils.import("chrome://remote/content/Connection.jsm");
+const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
+const {WebSocketDebuggerTransport} = ChromeUtils.import("chrome://remote/content/server/WebSocketTransport.jsm");
+const {WebSocketServer} = ChromeUtils.import("chrome://remote/content/server/WebSocket.jsm");
+
+/**
+ * The main process Target.
+ *
+ * Matches BrowserDevToolsAgentHost from chromium, and only support a couple of Domains:
+ * https://cs.chromium.org/chromium/src/content/browser/devtools/browser_devtools_agent_host.cc?dr=CSs&g=0&l=80-91
+ */
+class MainProcessTarget {
+  /**
+   * @param Targets targets
+   */
+  constructor(targets) {
+    this.targets = targets;
+    this.sessions = new Map();
+
+    this.type = "main-process";
+  }
+
+  get wsDebuggerURL() {
+    const RemoteAgent = Cc["@mozilla.org/remote/agent"]
+        .getService(Ci.nsISupports).wrappedJSObject;
+    const {host, port} = RemoteAgent;
+    return `ws://${host}:${port}/devtools/page/${this.id}`;
+  }
+
+  toString() {
+    return `[object MainProcessTarget]`;
+  }
+
+  toJSON() {
+    return {
+      description: "Main process target",
+      devtoolsFrontendUrl: "",
+      faviconUrl: "",
+      id: "main-process",
+      title: "Main process target",
+      type: this.type,
+      url: "",
+      webSocketDebuggerUrl: this.wsDebuggerURL,
+    };
+  }
+
+  // nsIHttpRequestHandler
+
+  async handle(request, response) {
+    const so = await WebSocketServer.upgrade(request, response);
+    const transport = new WebSocketDebuggerTransport(so);
+    const conn = new Connection(transport);
+    this.sessions.set(conn, new Session(conn, this));
+  }
+
+  // XPCOM
+
+  get QueryInterface() {
+    return ChromeUtils.generateQI([
+      Ci.nsIHttpRequestHandler,
+    ]);
+  }
+}
--- a/remote/targets/Targets.jsm
+++ b/remote/targets/Targets.jsm
@@ -4,16 +4,17 @@
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["Targets"];
 
 const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
 const {MessagePromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
 const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.jsm");
+const {MainProcessTarget} = ChromeUtils.import("chrome://remote/content/targets/MainProcessTarget.jsm");
 
 class Targets {
   constructor() {
     // browser context ID -> Target<XULElement>
     this._targets = new Map();
 
     EventEmitter.decorate(this);
   }
@@ -48,22 +49,38 @@ class Targets {
       this._targets.delete(target.id);
     }
   }
 
   clear() {
     for (const target of this) {
       this.disconnect(target.browser);
     }
+    if (this.mainProcessTarget) {
+      this.mainProcessTarget.disconnect();
+      this.mainProcessTarget = null;
+    }
   }
 
   get size() {
     return this._targets.size;
   }
 
+  /**
+   * Get the Target instance for the main process.
+   * This target is a singleton and only exposes a subset of domains.
+   */
+  getMainProcessTarget() {
+    if (!this.mainProcessTarget) {
+      this.mainProcessTarget = new MainProcessTarget(this);
+      this.emit("connect", this.mainProcessTarget);
+    }
+    return this.mainProcessTarget;
+  }
+
   * [Symbol.iterator]() {
     for (const target of this._targets.values()) {
       yield target;
     }
   }
 
   toJSON() {
     return [...this];