summaryrefslogtreecommitdiffstats
path: root/devtools/client/framework/test/browser_commands_from_url.js
blob: 6d1412005c5500963ef4504a732e258312b8b41e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

const TEST_URI =
  "data:text/html;charset=utf-8," + "<p>browser_target-from-url.js</p>";

const { DevToolsLoader } = ChromeUtils.importESModule(
  "resource://devtools/shared/loader/Loader.sys.mjs"
);
const {
  commandsFromURL,
} = require("resource://devtools/client/framework/commands-from-url.js");

Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false);

SimpleTest.registerCleanupFunction(() => {
  Services.prefs.clearUserPref("devtools.debugger.remote-enabled");
  Services.prefs.clearUserPref("devtools.debugger.prompt-connection");
});

function assertTarget(target, url) {
  is(target.url, url);
  is(target.isBrowsingContext, true);
}

add_task(async function () {
  const tab = await addTab(TEST_URI);
  const browser = tab.linkedBrowser;
  let commands, target;

  info("Test invalid type");
  try {
    await commandsFromURL(new URL("https://foo?type=x"));
    ok(false, "Shouldn't pass");
  } catch (e) {
    is(e.message, "commandsFromURL, unsupported type 'x' parameter");
  }

  info("Test tab");
  commands = await commandsFromURL(
    new URL("https://foo?type=tab&id=" + browser.browserId)
  );
  // Descriptor's getTarget will only work if the TargetCommand watches for the first top target
  await commands.targetCommand.startListening();

  // For now, we can't spawn a commands flagged as 'local tab' via URL query params
  // The only way to has isLocalTab is to create the toolbox via showToolboxForTab
  // and spawn the command via CommandsFactory.forTab.
  is(
    commands.descriptorFront.isLocalTab,
    false,
    "Even if we refer to a local tab, isLocalTab is false (for now)"
  );

  target = await commands.descriptorFront.getTarget();

  assertTarget(target, TEST_URI);
  await commands.destroy();

  info("Test invalid tab id");
  try {
    await commandsFromURL(new URL("https://foo?type=tab&id=10000"));
    ok(false, "Shouldn't pass");
  } catch (e) {
    is(e.message, "commandsFromURL, tab with browserId '10000' doesn't exist");
  }

  info("Test parent process");
  commands = await commandsFromURL(new URL("https://foo?type=process"));
  target = await commands.descriptorFront.getTarget();
  const topWindow = Services.wm.getMostRecentWindow("navigator:browser");
  assertTarget(target, topWindow.location.href);
  await commands.destroy();

  await testRemoteTCP();
  await testRemoteWebSocket();

  gBrowser.removeCurrentTab();
});

async function setupDevToolsServer(webSocket) {
  info("Create a separate loader instance for the DevToolsServer.");
  const loader = new DevToolsLoader();
  const { DevToolsServer } = loader.require(
    "resource://devtools/server/devtools-server.js"
  );
  const { SocketListener } = loader.require(
    "resource://devtools/shared/security/socket.js"
  );

  DevToolsServer.init();
  DevToolsServer.registerAllActors();
  DevToolsServer.allowChromeProcess = true;
  const socketOptions = {
    // Pass -1 to automatically choose an available port
    portOrPath: -1,
    webSocket,
  };

  const listener = new SocketListener(DevToolsServer, socketOptions);
  ok(listener, "Socket listener created");
  await listener.open();
  is(DevToolsServer.listeningSockets, 1, "1 listening socket");

  return { DevToolsServer, listener };
}

function teardownDevToolsServer({ DevToolsServer, listener }) {
  info("Close the listener socket");
  listener.close();
  is(DevToolsServer.listeningSockets, 0, "0 listening sockets");

  info("Destroy the temporary devtools server");
  DevToolsServer.destroy();
}

async function testRemoteTCP() {
  info("Test remote process via TCP Connection");

  const server = await setupDevToolsServer(false);

  const { port } = server.listener;
  const commands = await commandsFromURL(
    new URL("https://foo?type=process&host=127.0.0.1&port=" + port)
  );
  const target = await commands.descriptorFront.getTarget();
  const topWindow = Services.wm.getMostRecentWindow("navigator:browser");
  assertTarget(target, topWindow.location.href);

  const settings = commands.client._transport.connectionSettings;
  is(settings.host, "127.0.0.1");
  is(parseInt(settings.port, 10), port);
  is(settings.webSocket, false);

  await commands.destroy();

  teardownDevToolsServer(server);
}

async function testRemoteWebSocket() {
  info("Test remote process via WebSocket Connection");

  const server = await setupDevToolsServer(true);

  const { port } = server.listener;
  const commands = await commandsFromURL(
    new URL("https://foo?type=process&host=127.0.0.1&port=" + port + "&ws=true")
  );
  const target = await commands.descriptorFront.getTarget();
  const topWindow = Services.wm.getMostRecentWindow("navigator:browser");
  assertTarget(target, topWindow.location.href);

  const settings = commands.client._transport.connectionSettings;
  is(settings.host, "127.0.0.1");
  is(parseInt(settings.port, 10), port);
  is(settings.webSocket, true);
  await commands.destroy();

  teardownDevToolsServer(server);
}