Part 2: Bug 1295807 - Implement the Proxy API. r=kmag
☠☠ backed out by 830a13c24b22 ☠ ☠
authorMatthew Wein <mwein@mozilla.com>
Wed, 01 Mar 2017 15:37:09 +0000
changeset 394664 1b162d4857b5928d370bcff9cf270d3482d464ee
parent 394663 1a9f4c3c782d969e64394573c8030aaf9ef42167
child 394665 09600e445256c6fdf48f217efe9603edeb2f7dbb
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1295807
milestone54.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
Part 2: Bug 1295807 - Implement the Proxy API. r=kmag MozReview-Commit-ID: CtSYWl8lWHM
toolkit/components/extensions/ext-proxy.js
toolkit/components/extensions/extensions-toolkit.manifest
toolkit/components/extensions/jar.mn
toolkit/components/extensions/schemas/jar.mn
toolkit/components/extensions/test/mochitest/mochitest-common.ini
toolkit/components/extensions/test/mochitest/test_ext_proxy.html
toolkit/components/extensions/test/xpcshell/test_proxy_scripts.js
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/ext-proxy.js
@@ -0,0 +1,62 @@
+/* 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/. */
+
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "ProxyScriptContext",
+                                  "resource://gre/modules/ProxyScriptContext.jsm");
+
+var {
+  SingletonEventManager,
+} = ExtensionUtils;
+
+// WeakMap[Extension -> ProxyScriptContext]
+let proxyScriptContextMap = new WeakMap();
+
+/* eslint-disable mozilla/balanced-listeners */
+extensions.on("shutdown", (type, extension) => {
+  let proxyScriptContext = proxyScriptContextMap.get(extension);
+  if (proxyScriptContext) {
+    proxyScriptContext.unload();
+    proxyScriptContextMap.delete(extension);
+  }
+});
+/* eslint-enable mozilla/balanced-listeners */
+
+extensions.registerSchemaAPI("proxy", "addon_parent", context => {
+  let {extension} = context;
+  return {
+    proxy: {
+      registerProxyScript: (url) => {
+        // Unload the current proxy script if one is loaded.
+        if (proxyScriptContextMap.has(extension)) {
+          proxyScriptContextMap.get(extension).unload();
+          proxyScriptContextMap.delete(extension);
+        }
+
+        let proxyScriptContext = new ProxyScriptContext(extension, url);
+        if (proxyScriptContext.load()) {
+          proxyScriptContextMap.set(extension, proxyScriptContext);
+        }
+      },
+
+      onProxyError: new SingletonEventManager(context, "proxy.onProxyError", fire => {
+        let listener = (name, error) => {
+          fire.async(error);
+        };
+        extension.on("proxy-error", listener);
+        return () => {
+          extension.off("proxy-error", listener);
+        };
+      }).api(),
+    },
+  };
+});
--- a/toolkit/components/extensions/extensions-toolkit.manifest
+++ b/toolkit/components/extensions/extensions-toolkit.manifest
@@ -7,16 +7,85 @@ category webextension-scripts downloads 
 category webextension-scripts extension chrome://extensions/content/ext-extension.js
 category webextension-scripts geolocation chrome://extensions/content/ext-geolocation.js
 category webextension-scripts handlers chrome://extensions/content/ext-protocolHandlers.js
 category webextension-scripts i18n chrome://extensions/content/ext-i18n.js
 category webextension-scripts idle chrome://extensions/content/ext-idle.js
 category webextension-scripts management chrome://extensions/content/ext-management.js
 category webextension-scripts notifications chrome://extensions/content/ext-notifications.js
 category webextension-scripts privacy chrome://extensions/content/ext-privacy.js
+category webextension-scripts proxy chrome://extensions/content/ext-proxy.js
+category webextension-scripts runtime chrome://extensions/content/ext-runtime.js
+category webextension-scripts storage chrome://extensions/content/ext-storage.js
+category webextension-scripts theme chrome://extensions/content/ext-theme.js
+category webextension-scripts topSites chrome://extensions/content/ext-topSites.js
+category webextension-scripts webNavigation chrome://extensions/content/ext-webNavigation.js
+category webextension-scripts webRequest chrome://extensions/content/ext-webRequest.js
+
+# scripts specific for content process.
+category webextension-scripts-content extension chrome://extensions/content/ext-c-extension.js
+category webextension-scripts-content i18n chrome://extensions/content/ext-i18n.js
+category webextension-scripts-content runtime chrome://extensions/content/ext-c-runtime.js
+category webextension-scripts-content storage chrome://extensions/content/ext-c-storage.js
+category webextension-scripts-content test chrome://extensions/content/ext-c-test.js
+
+# scripts specific for devtools extension contexts.
+category webextension-scripts-devtools extension chrome://extensions/content/ext-c-extension.js
+category webextension-scripts-devtools i18n chrome://extensions/content/ext-i18n.js
+category webextension-scripts-devtools runtime chrome://extensions/content/ext-c-runtime.js
+category webextension-scripts-devtools storage chrome://extensions/content/ext-c-storage.js
+category webextension-scripts-devtools test chrome://extensions/content/ext-c-test.js
+
+# scripts that must run in the same process as addon code.
+category webextension-scripts-addon backgroundPage chrome://extensions/content/ext-c-backgroundPage.js
+category webextension-scripts-addon extension chrome://extensions/content/ext-c-extension.js
+category webextension-scripts-addon i18n chrome://extensions/content/ext-i18n.js
+#ifndef ANDROID
+category webextension-scripts-addon identity chrome://extensions/content/ext-c-identity.js
+#endif
+category webextension-scripts-addon runtime chrome://extensions/content/ext-c-runtime.js
+category webextension-scripts-addon storage chrome://extensions/content/ext-c-storage.js
+category webextension-scripts-addon test chrome://extensions/content/ext-c-test.js
+
+# schemas
+category webextension-schemas alarms chrome://extensions/content/schemas/alarms.json
+category webextension-schemas contextualIdentities chrome://extensions/content/schemas/contextual_identities.json
+category webextension-schemas cookies chrome://extensions/content/schemas/cookies.json
+category webextension-schemas downloads chrome://extensions/content/schemas/downloads.json
+category webextension-schemas events chrome://extensions/content/schemas/events.json
+category webextension-schemas extension chrome://extensions/content/schemas/extension.json
+category webextension-schemas extension_types chrome://extensions/content/schemas/extension_types.json
+category webextension-schemas handlers chrome://extensions/content/schemas/extension_protocol_handlers.json
+category webextension-schemas i18n chrome://extensions/content/schemas/i18n.json
+#ifndef ANDROID
+category webextension-schemas identity chrome://extensions/content/schemas/identity.json
+#endif
+category webextension-schemas idle chrome://extensions/content/schemas/idle.json
+category webextension-schemas management chrome://extensions/content/schemas/management.json
+category webextension-schemas native_host_manifest chrome://extensions/content/schemas/native_host_manifest.json
+category webextension-schemas notifications chrome://extensions/content/schemas/notifications.json
+category webextension-schemas privacy chrome://extensions/content/schemas/privacy.json
+category webextension-schemas proxy chrome://extensions/content/schemas/proxy.json
+category webextension-schemas runtime chrome://extensions/content/schemas/runtime.json
+category webextension-schemas storage chrome://extensions/content/schemas/storage.json
+category webextension-schemas test chrome://extensions/content/schemas/test.json
+category webextension-schemas theme chrome://extensions/content/schemas/theme.json# scripts
+category webextension-scripts alarms chrome://extensions/content/ext-alarms.js
+category webextension-scripts backgroundPage chrome://extensions/content/ext-backgroundPage.js
+category webextension-scripts contextualIdentities chrome://extensions/content/ext-contextualIdentities.js
+category webextension-scripts cookies chrome://extensions/content/ext-cookies.js
+category webextension-scripts downloads chrome://extensions/content/ext-downloads.js
+category webextension-scripts extension chrome://extensions/content/ext-extension.js
+category webextension-scripts geolocation chrome://extensions/content/ext-geolocation.js
+category webextension-scripts handlers chrome://extensions/content/ext-protocolHandlers.js
+category webextension-scripts i18n chrome://extensions/content/ext-i18n.js
+category webextension-scripts idle chrome://extensions/content/ext-idle.js
+category webextension-scripts management chrome://extensions/content/ext-management.js
+category webextension-scripts notifications chrome://extensions/content/ext-notifications.js
+category webextension-scripts privacy chrome://extensions/content/ext-privacy.js
 category webextension-scripts runtime chrome://extensions/content/ext-runtime.js
 category webextension-scripts storage chrome://extensions/content/ext-storage.js
 category webextension-scripts theme chrome://extensions/content/ext-theme.js
 category webextension-scripts topSites chrome://extensions/content/ext-topSites.js
 category webextension-scripts webNavigation chrome://extensions/content/ext-webNavigation.js
 category webextension-scripts webRequest chrome://extensions/content/ext-webRequest.js
 
 # scripts specific for content process.
@@ -65,8 +134,13 @@ category webextension-schemas privacy ch
 category webextension-schemas runtime chrome://extensions/content/schemas/runtime.json
 category webextension-schemas storage chrome://extensions/content/schemas/storage.json
 category webextension-schemas test chrome://extensions/content/schemas/test.json
 category webextension-schemas theme chrome://extensions/content/schemas/theme.json
 category webextension-schemas top_sites chrome://extensions/content/schemas/top_sites.json
 category webextension-schemas types chrome://extensions/content/schemas/types.json
 category webextension-schemas web_navigation chrome://extensions/content/schemas/web_navigation.json
 category webextension-schemas web_request chrome://extensions/content/schemas/web_request.json
+
+category webextension-schemas top_sites chrome://extensions/content/schemas/top_sites.json
+category webextension-schemas types chrome://extensions/content/schemas/types.json
+category webextension-schemas web_navigation chrome://extensions/content/schemas/web_navigation.json
+category webextension-schemas web_request chrome://extensions/content/schemas/web_request.json
--- a/toolkit/components/extensions/jar.mn
+++ b/toolkit/components/extensions/jar.mn
@@ -13,16 +13,17 @@ toolkit.jar:
     content/extensions/ext-extension.js
     content/extensions/ext-geolocation.js
     content/extensions/ext-i18n.js
     content/extensions/ext-idle.js
     content/extensions/ext-management.js
     content/extensions/ext-notifications.js
     content/extensions/ext-privacy.js
     content/extensions/ext-protocolHandlers.js
+    content/extensions/ext-proxy.js
     content/extensions/ext-runtime.js
     content/extensions/ext-storage.js
     content/extensions/ext-theme.js
     content/extensions/ext-topSites.js
     content/extensions/ext-webRequest.js
     content/extensions/ext-webNavigation.js
     # Below is a separate group using the naming convention ext-c-*.js that run
     # in the child process.
--- a/toolkit/components/extensions/schemas/jar.mn
+++ b/toolkit/components/extensions/schemas/jar.mn
@@ -17,16 +17,17 @@ toolkit.jar:
 #ifndef ANDROID
     content/extensions/schemas/identity.json
 #endif
     content/extensions/schemas/idle.json
     content/extensions/schemas/management.json
     content/extensions/schemas/manifest.json
     content/extensions/schemas/native_host_manifest.json
     content/extensions/schemas/notifications.json
+    content/extensions/schemas/proxy.json
     content/extensions/schemas/privacy.json
     content/extensions/schemas/runtime.json
     content/extensions/schemas/storage.json
     content/extensions/schemas/test.json
     content/extensions/schemas/theme.json
     content/extensions/schemas/top_sites.json
     content/extensions/schemas/types.json
     content/extensions/schemas/web_navigation.json
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -68,16 +68,17 @@ skip-if = os == 'android' # Android does
 [test_ext_contentscript_teardown.html]
 [test_ext_exclude_include_globs.html]
 [test_ext_i18n_css.html]
 [test_ext_generate.html]
 [test_ext_geolocation.html]
 skip-if = os == 'android' # Android support Bug 1336194
 [test_ext_notifications.html]
 [test_ext_permission_xhr.html]
+[test_ext_proxy.html]
 [test_ext_runtime_connect.html]
 [test_ext_runtime_connect_twoway.html]
 [test_ext_runtime_connect2.html]
 [test_ext_runtime_disconnect.html]
 [test_ext_runtime_id.html]
 [test_ext_sandbox_var.html]
 [test_ext_sendmessage_reply.html]
 [test_ext_sendmessage_reply2.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_proxy.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Tests for the proxy API</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+/* eslint no-unused-vars: ["error", {"args": "none", "varsIgnorePattern": "^(FindProxyForURL)$"}] */
+
+"use strict";
+
+function* testProxyScript(script, expected) {
+  let extension = ExtensionTestUtils.loadExtension({
+    background() {
+      browser.proxy.onProxyError.addListener(error => {
+        browser.test.sendMessage("proxy-error-received", error);
+      });
+
+      browser.proxy.registerProxyScript("proxy_script.js");
+    },
+    manifest: {
+      "permissions": ["proxy"],
+    },
+    files: {
+      "proxy_script.js": String(script).replace(/^.*?\{([^]*)\}$/, "$1"),
+    },
+  });
+
+  yield extension.startup();
+
+  let win = window.open("http://example.com/");
+  let error = yield extension.awaitMessage("proxy-error-received");
+  is(error.message, expected.message, "Correct error message received");
+  win.close();
+
+  if (expected.errorInfo) {
+    ok(error.fileName.includes("proxy_script.js"), "Error should include file name");
+    is(error.lineNumber, 3, "Error should include line number");
+    ok(error.stack.includes("proxy_script.js:3:9"), "Error should include stack trace");
+  }
+
+  yield extension.unload();
+}
+
+add_task(function* test_invalid_FindProxyForURL_type() {
+  yield testProxyScript(
+    () => { }, {
+      message: "The proxy script must define FindProxyForURL as a function",
+    });
+
+  yield testProxyScript(
+    () => {
+      var FindProxyForURL = 5; // eslint-disable-line mozilla/var-only-at-top-level
+    }, {
+      message: "The proxy script must define FindProxyForURL as a function",
+    });
+});
+
+add_task(function* test_invalid_FindProxyForURL_return_type() {
+  yield testProxyScript(
+    () => {
+      function FindProxyForURL() {
+        return 5;
+      }
+    }, {
+      message: "FindProxyForURL: Return type must be a string",
+    });
+
+  yield testProxyScript(
+    () => {
+      function FindProxyForURL() {
+        return "INVALID";
+      }
+    }, {
+      message: "FindProxyForURL: Invalid Proxy Rule: INVALID",
+    });
+});
+
+add_task(function* test_runtime_error_in_FindProxyForURL() {
+  yield testProxyScript(
+    () => {
+      function FindProxyForURL() {
+        return not_defined; // eslint-disable-line no-undef
+      }
+    }, {
+      message: "not_defined is not defined",
+      errorInfo: true,
+    });
+});
+
+</script>
+
+</body>
+</html>
--- a/toolkit/components/extensions/test/xpcshell/test_proxy_scripts.js
+++ b/toolkit/components/extensions/test/xpcshell/test_proxy_scripts.js
@@ -1,11 +1,11 @@
 "use strict";
 
-/* no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^(FindProxyForURL)$"}] */
+/* eslint no-unused-vars: ["error", {"args": "none", "varsIgnorePattern": "^(FindProxyForURL)$"}] */
 
 Cu.import("resource://gre/modules/Extension.jsm");
 Cu.import("resource://gre/modules/ProxyScriptContext.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gProxyService",
                                    "@mozilla.org/network/protocol-proxy-service;1",
                                    "nsIProtocolProxyService");