Bug 1595697 - [remote] Implement basic support for Emulation.setUserAgentOverride. r=remote-protocol-reviewers,maja_zf
authorHenrik Skupin <mail@hskupin.info>
Mon, 18 Nov 2019 10:07:38 +0000
changeset 502391 73c00aa07450a45bae0d6552ac25fc682a755a2a
parent 502390 77a9d83ce42fb4843febbc86ea069be0c7f335fb
child 502392 06d19681d0426ac65f242b606d2950dd96690101
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersremote-protocol-reviewers, maja_zf
bugs1595697
milestone72.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 1595697 - [remote] Implement basic support for Emulation.setUserAgentOverride. r=remote-protocol-reviewers,maja_zf This patch implements setting the user agent only. Support for accepted language, and platform will be done in a follow-up bug. Differential Revision: https://phabricator.services.mozilla.com/D52831
remote/domains/ParentProcessDomains.jsm
remote/domains/parent/Emulation.jsm
remote/jar.mn
remote/test/browser/emulation/browser.ini
remote/test/browser/emulation/browser_setUserAgentOverride.js
remote/test/browser/emulation/head.js
remote/test/moz.build
--- a/remote/domains/ParentProcessDomains.jsm
+++ b/remote/domains/ParentProcessDomains.jsm
@@ -9,14 +9,15 @@ var EXPORTED_SYMBOLS = ["ParentProcessDo
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 const ParentProcessDomains = {};
 
 XPCOMUtils.defineLazyModuleGetters(ParentProcessDomains, {
   Browser: "chrome://remote/content/domains/parent/Browser.jsm",
+  Emulation: "chrome://remote/content/domains/parent/Emulation.jsm",
   Input: "chrome://remote/content/domains/parent/Input.jsm",
   Network: "chrome://remote/content/domains/parent/Network.jsm",
   Page: "chrome://remote/content/domains/parent/Page.jsm",
   Security: "chrome://remote/content/domains/parent/Security.jsm",
   Target: "chrome://remote/content/domains/parent/Target.jsm",
 });
new file mode 100644
--- /dev/null
+++ b/remote/domains/parent/Emulation.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 = ["Emulation"];
+
+const { Domain } = ChromeUtils.import(
+  "chrome://remote/content/domains/Domain.jsm"
+);
+const { UnsupportedError } = ChromeUtils.import(
+  "chrome://remote/content/Error.jsm"
+);
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const PREF_USER_AGENT_OVERRIDE = "general.useragent.override";
+
+class Emulation extends Domain {
+  destructor() {
+    this.setUserAgentOverride({ userAgent: "" });
+
+    super.destructor();
+  }
+
+  /**
+   * Allows overriding user agent with the given string.
+   *
+   * @param {Object} options
+   * @param {string} options.userAgent
+   *     User agent to use.
+   * @param {string=} options.acceptLanguage [not yet supported]
+   *     Browser langugage to emulate.
+   * @param {number=} options.platform [not yet supported]
+   *     The platform navigator.platform should return.
+   */
+  setUserAgentOverride(options = {}) {
+    const { userAgent } = options;
+
+    if (options.acceptLanguage) {
+      throw new UnsupportedError("'acceptLanguage' not supported");
+    }
+    if (options.platform) {
+      throw new UnsupportedError("'platform' not supported");
+    }
+
+    // TODO: Set the user agent for the current session only (Bug 1596136)
+    if (userAgent.length == 0) {
+      Services.prefs.clearUserPref(PREF_USER_AGENT_OVERRIDE);
+    } else if (this._isValidHTTPRequestHeaderValue(userAgent)) {
+      Services.prefs.setStringPref(PREF_USER_AGENT_OVERRIDE, userAgent);
+    } else {
+      throw new Error("Invalid characters found in userAgent");
+    }
+  }
+
+  _isValidHTTPRequestHeaderValue(value) {
+    try {
+      const channel = NetUtil.newChannel({
+        uri: "http://localhost",
+        loadUsingSystemPrincipal: true,
+      });
+      channel.QueryInterface(Ci.nsIHttpChannel);
+      channel.setRequestHeader("X-check", value, false);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  }
+}
--- a/remote/jar.mn
+++ b/remote/jar.mn
@@ -43,16 +43,17 @@ remote.jar:
   content/domains/content/Input.jsm (domains/content/Input.jsm)
   content/domains/content/Log.jsm (domains/content/Log.jsm)
   content/domains/content/Page.jsm (domains/content/Page.jsm)
   content/domains/content/Performance.jsm (domains/content/Performance.jsm)
   content/domains/content/Runtime.jsm (domains/content/Runtime.jsm)
   content/domains/content/runtime/ExecutionContext.jsm (domains/content/runtime/ExecutionContext.jsm)
   content/domains/content/Security.jsm (domains/content/Security.jsm)
   content/domains/parent/Browser.jsm (domains/parent/Browser.jsm)
+  content/domains/parent/Emulation.jsm (domains/parent/Emulation.jsm)
   content/domains/parent/Input.jsm (domains/parent/Input.jsm)
   content/domains/parent/Network.jsm (domains/parent/Network.jsm)
   content/domains/parent/network/ChannelEventSink.jsm (domains/parent/network/ChannelEventSink.jsm)
   content/domains/parent/network/NetworkObserver.jsm (domains/parent/network/NetworkObserver.jsm)
   content/domains/parent/Page.jsm (domains/parent/Page.jsm)
   content/domains/parent/page/DialogHandler.jsm (domains/parent/page/DialogHandler.jsm)
   content/domains/parent/Security.jsm (domains/parent/Security.jsm)
   content/domains/parent/Target.jsm (domains/parent/Target.jsm)
new file mode 100644
--- /dev/null
+++ b/remote/test/browser/emulation/browser.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+tags = remote
+subsuite = remote
+prefs = remote.enabled=true
+support-files =
+  head.js
+
+[browser_setUserAgentOverride.js]
new file mode 100644
--- /dev/null
+++ b/remote/test/browser/emulation/browser_setUserAgentOverride.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const DOC = toDataURL(`<script>document.write(navigator.userAgent);</script>`);
+
+add_task(async function setAndResetUserAgent({ Emulation }) {
+  const userAgent = "foo bar";
+
+  await loadURL(DOC);
+  isnot(
+    await getNavigatorProperty("userAgent"),
+    userAgent,
+    "Custom user agent hasn't been set"
+  );
+
+  try {
+    await Emulation.setUserAgentOverride({ userAgent });
+    await loadURL(DOC);
+    is(
+      await getNavigatorProperty("userAgent"),
+      userAgent,
+      "Custom user agent has been set"
+    );
+
+    await Emulation.setUserAgentOverride({ userAgent: "" });
+    await loadURL(DOC);
+    isnot(
+      await getNavigatorProperty("userAgent"),
+      userAgent,
+      "Custom user agent hasn't been set anymore"
+    );
+  } finally {
+    Services.prefs.clearUserPref("general.useragent.override");
+  }
+});
+
+add_task(async function invalidUserAgent({ Emulation }) {
+  const userAgent = "foobar\n";
+
+  await loadURL(DOC);
+  isnot(
+    await getNavigatorProperty("userAgent"),
+    userAgent,
+    "Custom user agent hasn't been set"
+  );
+
+  let errorThrown = false;
+  try {
+    await Emulation.setUserAgentOverride({ userAgent });
+  } catch (e) {
+    errorThrown = true;
+  }
+  ok(errorThrown, "Invalid user agent format raised error");
+});
+
+async function getNavigatorProperty(prop) {
+  return ContentTask.spawn(gBrowser.selectedBrowser, prop, _prop => {
+    return content.navigator[_prop];
+  });
+}
new file mode 100644
--- /dev/null
+++ b/remote/test/browser/emulation/head.js
@@ -0,0 +1,11 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from ../head.js */
+
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/remote/test/browser/head.js",
+  this
+);
--- a/remote/test/moz.build
+++ b/remote/test/moz.build
@@ -1,15 +1,16 @@
 # 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/.
 
 XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell.ini"]
 BROWSER_CHROME_MANIFESTS += [
     "browser/browser.ini",
+    "browser/emulation/browser.ini",
     "browser/input/browser.ini",
     "browser/network/browser.ini",
     "browser/page/browser.ini",
     "browser/runtime/browser.ini",
     "browser/security/browser.ini",
     "browser/target/browser.ini",
 ]