summaryrefslogtreecommitdiffstats
path: root/remote/cdp/test/browser/browser_httpd.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--remote/cdp/test/browser/browser_httpd.js288
1 files changed, 288 insertions, 0 deletions
diff --git a/remote/cdp/test/browser/browser_httpd.js b/remote/cdp/test/browser/browser_httpd.js
new file mode 100644
index 0000000000..fb74ae8b70
--- /dev/null
+++ b/remote/cdp/test/browser/browser_httpd.js
@@ -0,0 +1,288 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { JSONHandler } = ChromeUtils.importESModule(
+ "chrome://remote/content/cdp/JSONHandler.sys.mjs"
+);
+
+// Get list of supported routes from JSONHandler
+const routes = new JSONHandler().routes;
+
+add_task(async function json_version() {
+ const { userAgent } = Cc[
+ "@mozilla.org/network/protocol;1?name=http"
+ ].getService(Ci.nsIHttpProtocolHandler);
+
+ const json = await requestJSON("/json/version");
+ is(
+ json.Browser,
+ `${Services.appinfo.name}/${Services.appinfo.version}`,
+ "Browser name and version found"
+ );
+ is(json["Protocol-Version"], "1.3", "Protocol version found");
+ is(json["User-Agent"], userAgent, "User agent found");
+ is(json["V8-Version"], "1.0", "V8 version found");
+ is(json["WebKit-Version"], "1.0", "Webkit version found");
+ is(
+ json.webSocketDebuggerUrl,
+ RemoteAgent.cdp.targetList.getMainProcessTarget().wsDebuggerURL,
+ "Websocket URL for main process target found"
+ );
+});
+
+add_task(async function check_routes() {
+ for (const route in routes) {
+ const { parameter, method } = routes[route];
+ // Skip routes expecting parameter
+ if (parameter) {
+ continue;
+ }
+
+ // Check request succeeded (200) and responded with valid JSON
+ info(`Checking ${route}`);
+ await requestJSON(route, { method });
+
+ // Check with trailing slash
+ info(`Checking ${route + "/"}`);
+ await requestJSON(route + "/", { method });
+
+ // Test routes expecting a certain method
+ if (method) {
+ const responseText = await requestJSON(route, {
+ method: "DELETE",
+ status: 405,
+ json: false,
+ });
+ is(
+ responseText,
+ `Using unsafe HTTP verb DELETE to invoke ${route}. This action supports only ${method} verb.`,
+ "/json/new fails with 405 when using GET"
+ );
+ }
+ }
+});
+
+add_task(async function json_list({ client }) {
+ const { Target } = client;
+ const { targetInfos } = await Target.getTargets();
+
+ const json = await requestJSON("/json/list");
+ const jsonAlias = await requestJSON("/json");
+
+ Assert.deepEqual(json, jsonAlias, "/json/list and /json return the same");
+
+ ok(Array.isArray(json), "Target list is an array");
+
+ is(
+ json.length,
+ targetInfos.length,
+ "Targets as listed on /json/list are equal to Target.getTargets"
+ );
+
+ for (let i = 0; i < json.length; i++) {
+ const jsonTarget = json[i];
+ const wsTarget = targetInfos[i];
+
+ is(
+ jsonTarget.id,
+ wsTarget.targetId,
+ "Target id matches between HTTP and Target.getTargets"
+ );
+ is(
+ jsonTarget.type,
+ wsTarget.type,
+ "Target type matches between HTTP and Target.getTargets"
+ );
+ is(
+ jsonTarget.url,
+ wsTarget.url,
+ "Target url matches between HTTP and Target.getTargets"
+ );
+
+ // Ensure expected values specifically for JSON endpoint
+ // and that type is always "page" as main process target should not be included
+ is(
+ jsonTarget.type,
+ "page",
+ `Target (${jsonTarget.id}) from list has expected type (page)`
+ );
+ is(
+ jsonTarget.webSocketDebuggerUrl,
+ `ws://${RemoteAgent.debuggerAddress}/devtools/page/${wsTarget.targetId}`,
+ `Target (${jsonTarget.id}) from list has expected webSocketDebuggerUrl value`
+ );
+ }
+});
+
+add_task(async function json_new_target({ client }) {
+ const newUrl = "https://example.com";
+
+ let getError = await requestJSON("/json/new?" + newUrl, {
+ status: 405,
+ json: false,
+ });
+ is(
+ getError,
+ "Using unsafe HTTP verb GET to invoke /json/new. This action supports only PUT verb.",
+ "/json/new fails with 405 when using GET"
+ );
+
+ const newTarget = await requestJSON("/json/new?" + newUrl, { method: "PUT" });
+
+ is(newTarget.type, "page", "Returned target type is 'page'");
+ is(newTarget.url, newUrl, "Returned target URL matches");
+ ok(!!newTarget.id, "Returned target has id");
+ ok(
+ !!newTarget.webSocketDebuggerUrl,
+ "Returned target has webSocketDebuggerUrl"
+ );
+
+ const { Target } = client;
+ const targets = await getDiscoveredTargets(Target);
+ const foundTarget = targets.find(target => target.targetId === newTarget.id);
+
+ ok(!!foundTarget, "Returned target id was found");
+});
+
+add_task(async function json_activate_target({ client, tab }) {
+ const { Target, target } = client;
+
+ const currentTargetId = target.id;
+ const targets = await getDiscoveredTargets(Target);
+ const initialTarget = targets.find(
+ target => target.targetId === currentTargetId
+ );
+ ok(!!initialTarget, "The current target has been found");
+
+ // open some more tabs in the initial window
+ await openTab(Target);
+ await openTab(Target);
+
+ const lastTabFirstWindow = await openTab(Target);
+ is(
+ gBrowser.selectedTab,
+ lastTabFirstWindow.newTab,
+ "Selected tab has changed to a new tab"
+ );
+
+ const activateResponse = await requestJSON(
+ "/json/activate/" + initialTarget.targetId,
+ { json: false }
+ );
+
+ is(
+ activateResponse,
+ "Target activated",
+ "Activate endpoint returned expected string"
+ );
+
+ is(gBrowser.selectedTab, tab, "Selected tab is the initial tab again");
+
+ const invalidResponse = await requestJSON("/json/activate/does-not-exist", {
+ status: 404,
+ json: false,
+ });
+
+ is(invalidResponse, "No such target id: does-not-exist");
+});
+
+add_task(async function json_close_target({ CDP, client, tab }) {
+ const { Target } = client;
+
+ const { targetInfo, newTab } = await openTab(Target);
+
+ const targetListBefore = await CDP.List();
+ const beforeTarget = targetListBefore.find(
+ target => target.id === targetInfo.targetId
+ );
+
+ ok(!!beforeTarget, "New target has been found");
+
+ const tabClosed = BrowserTestUtils.waitForEvent(newTab, "TabClose");
+ const targetDestroyed = Target.targetDestroyed();
+
+ const activateResponse = await requestJSON(
+ "/json/close/" + targetInfo.targetId,
+ { json: false }
+ );
+ is(
+ activateResponse,
+ "Target is closing",
+ "Close endpoint returned expected string"
+ );
+
+ await tabClosed;
+ info("Tab was closed");
+
+ await targetDestroyed;
+ info("Received the Target.targetDestroyed event");
+
+ const targetListAfter = await CDP.List();
+ const afterTarget = targetListAfter.find(
+ target => target.id === targetInfo.targetId
+ );
+
+ ok(afterTarget == null, "New target is gone");
+
+ const invalidResponse = await requestJSON("/json/close/does-not-exist", {
+ status: 404,
+ json: false,
+ });
+
+ is(invalidResponse, "No such target id: does-not-exist");
+});
+
+add_task(async function json_prevent_load_in_iframe({ client }) {
+ const { Page } = client;
+
+ const PAGE = `https://example.com/document-builder.sjs?html=${encodeURIComponent(
+ '<iframe src="http://localhost:9222/json/version"></iframe>`'
+ )}`;
+
+ await Page.enable();
+
+ const NAVIGATED = "Page.frameNavigated";
+
+ const history = new RecordEvents(2);
+ history.addRecorder({
+ event: Page.frameNavigated,
+ eventName: NAVIGATED,
+ messageFn: payload => {
+ return `Received ${NAVIGATED} for frame id ${payload.frame.id}`;
+ },
+ });
+
+ await loadURL(PAGE);
+
+ const frameNavigatedEvents = await history.record();
+
+ const frames = frameNavigatedEvents
+ .map(({ payload }) => payload.frame)
+ .filter(frame => frame.parentId !== undefined);
+
+ const windowGlobal = BrowsingContext.get(frames[0].id).currentWindowGlobal;
+ ok(
+ windowGlobal.documentURI.spec.startsWith("about:neterror?e=cspBlocked"),
+ "Expected page not be loaded within an iframe"
+ );
+});
+
+async function requestJSON(path, options = {}) {
+ const { method = "GET", status = 200, json = true } = options;
+
+ info(`${method} http://${RemoteAgent.debuggerAddress}${path}`);
+
+ const response = await fetch(`http://${RemoteAgent.debuggerAddress}${path}`, {
+ method,
+ });
+
+ is(response.status, status, `JSON response is ${status}`);
+
+ if (json) {
+ return response.json();
+ }
+
+ return response.text();
+}