mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 05:48:26 +00:00
Bug 1443259 remove deprecated proxy APIs r=robwu
Differential Revision: https://phabricator.services.mozilla.com/D46886 --HG-- rename : toolkit/components/extensions/ProxyScriptContext.jsm => toolkit/components/extensions/ProxyChannelFilter.jsm rename : toolkit/components/extensions/test/xpcshell/test_proxy_scripts_results.js => toolkit/components/extensions/test/xpcshell/test_proxy_info_results.js extra : moz-landing-system : lando
This commit is contained in:
parent
3dafbad575
commit
9bbc3b357a
@ -1353,7 +1353,6 @@ class SchemaAPIManager extends EventEmitter {
|
||||
* "addon" - An addon process.
|
||||
* "content" - A content process.
|
||||
* "devtools" - A devtools process.
|
||||
* "proxy" - A proxy script process.
|
||||
* @param {SchemaRoot} schema
|
||||
*/
|
||||
constructor(processType, schema) {
|
||||
|
@ -507,7 +507,7 @@ ProxyMessenger = {
|
||||
apiManager.global.tabGetSender(extension, target, sender);
|
||||
}
|
||||
|
||||
let promise1 = MessageChannel.sendMessage(receiverMM, messageName, data, {
|
||||
let promise = MessageChannel.sendMessage(receiverMM, messageName, data, {
|
||||
sender,
|
||||
recipient,
|
||||
responseType,
|
||||
@ -532,7 +532,7 @@ ProxyMessenger = {
|
||||
receiverMM
|
||||
);
|
||||
port.register();
|
||||
promise1.catch(() => {
|
||||
promise.catch(() => {
|
||||
port.unregister();
|
||||
});
|
||||
}
|
||||
@ -543,49 +543,7 @@ ProxyMessenger = {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(recipient.toProxyScript && extension.remote)) {
|
||||
return promise1;
|
||||
}
|
||||
|
||||
// Proxy scripts run in the parent process so we need to dispatch
|
||||
// the message to both the parent and extension process and merge
|
||||
// the results.
|
||||
// Once proxy scripts are gone (bug 1443259) we can remove this
|
||||
let promise2 = MessageChannel.sendMessage(
|
||||
Services.ppmm.getChildAt(0),
|
||||
messageName,
|
||||
data,
|
||||
{
|
||||
sender,
|
||||
recipient,
|
||||
responseType,
|
||||
}
|
||||
);
|
||||
|
||||
let result = undefined;
|
||||
let failures = 0;
|
||||
let tryPromise = async promise => {
|
||||
try {
|
||||
let res = await promise;
|
||||
if (result === undefined) {
|
||||
result = res;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.result === MessageChannel.RESULT_NO_RESPONSE) {
|
||||
// Ignore.
|
||||
} else if (e.result === MessageChannel.RESULT_NO_HANDLER) {
|
||||
failures++;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all([tryPromise(promise1), tryPromise(promise2)]);
|
||||
if (failures == 2) {
|
||||
return Promise.reject(noHandlerError);
|
||||
}
|
||||
return result;
|
||||
return promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -5,36 +5,22 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ProxyScriptContext", "ProxyChannelFilter"];
|
||||
var EXPORTED_SYMBOLS = ["ProxyChannelFilter"];
|
||||
|
||||
/* exported ProxyScriptContext, ProxyChannelFilter */
|
||||
/* exported ProxyChannelFilter */
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { ExtensionCommon } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionCommon.jsm"
|
||||
);
|
||||
const { ExtensionUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ExtensionChild",
|
||||
"resource://gre/modules/ExtensionChild.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ExtensionParent",
|
||||
"resource://gre/modules/ExtensionParent.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Schemas",
|
||||
"resource://gre/modules/Schemas.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"ProxyService",
|
||||
@ -49,8 +35,6 @@ XPCOMUtils.defineLazyGetter(this, "getCookieStoreIdForOriginAttributes", () => {
|
||||
return ExtensionParent.apiManager.global.getCookieStoreIdForOriginAttributes;
|
||||
});
|
||||
|
||||
const CATEGORY_EXTENSION_SCRIPTS_CONTENT = "webextension-scripts-content";
|
||||
|
||||
// DNS is resolved on the SOCKS proxy server.
|
||||
const { TRANSPARENT_PROXY_RESOLVES_HOST } = Ci.nsIProxyInfo;
|
||||
|
||||
@ -59,14 +43,6 @@ const PROXY_TIMEOUT_SEC = 10;
|
||||
|
||||
const { ExtensionError } = ExtensionUtils;
|
||||
|
||||
const {
|
||||
BaseContext,
|
||||
CanOfAPIs,
|
||||
LocalAPIImplementation,
|
||||
SchemaAPIManager,
|
||||
defineLazyGetter,
|
||||
} = ExtensionCommon;
|
||||
|
||||
const PROXY_TYPES = Object.freeze({
|
||||
DIRECT: "direct",
|
||||
HTTPS: "https",
|
||||
@ -269,93 +245,6 @@ const ProxyInfoData = {
|
||||
failoverProxy
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new proxy info data object using the return value of FindProxyForURL.
|
||||
*
|
||||
* @param {Array<string>} rule A single proxy rule returned by FindProxyForURL.
|
||||
* (e.g. "PROXY 1.2.3.4:8080", "SOCKS 1.1.1.1:9090" or "DIRECT")
|
||||
* @returns {nsIProxyInfo} The proxy info to apply for the given URI.
|
||||
*/
|
||||
parseProxyInfoDataFromPAC(rule) {
|
||||
if (!rule) {
|
||||
throw new ExtensionError("ProxyInfoData: Missing Proxy Rule");
|
||||
}
|
||||
|
||||
let parts = rule.toLowerCase().split(/\s+/);
|
||||
if (!parts[0] || parts.length > 2) {
|
||||
throw new ExtensionError(
|
||||
`ProxyInfoData: Invalid arguments passed for proxy rule: "${rule}"`
|
||||
);
|
||||
}
|
||||
let type = parts[0];
|
||||
let [host, port] = parts.length > 1 ? parts[1].split(":") : [];
|
||||
|
||||
switch (PROXY_TYPES[type.toUpperCase()]) {
|
||||
case PROXY_TYPES.HTTP:
|
||||
case PROXY_TYPES.HTTPS:
|
||||
case PROXY_TYPES.SOCKS:
|
||||
case PROXY_TYPES.SOCKS4:
|
||||
if (!host || !port) {
|
||||
throw new ExtensionError(
|
||||
`ProxyInfoData: Invalid host or port from proxy rule: "${rule}"`
|
||||
);
|
||||
}
|
||||
return { type, host, port };
|
||||
case PROXY_TYPES.DIRECT:
|
||||
if (host || port) {
|
||||
throw new ExtensionError(
|
||||
`ProxyInfoData: Invalid argument for proxy type: "${type}"`
|
||||
);
|
||||
}
|
||||
return { type };
|
||||
default:
|
||||
throw new ExtensionError(
|
||||
`ProxyInfoData: Unrecognized proxy type: "${type}"`
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
proxyInfoFromProxyData(context, proxyData, defaultProxyInfo) {
|
||||
switch (typeof proxyData) {
|
||||
case "string":
|
||||
let proxyRules = [];
|
||||
try {
|
||||
for (let result of proxyData.split(";")) {
|
||||
proxyRules.push(
|
||||
ProxyInfoData.parseProxyInfoDataFromPAC(result.trim())
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// If we have valid proxies already, lets use them and just emit
|
||||
// errors for the failovers.
|
||||
if (proxyRules.length === 0) {
|
||||
throw e;
|
||||
}
|
||||
let error = context.normalizeError(e);
|
||||
context.extension.emit("proxy-error", {
|
||||
message: error.message,
|
||||
fileName: error.fileName,
|
||||
lineNumber: error.lineNumber,
|
||||
stack: error.stack,
|
||||
});
|
||||
}
|
||||
proxyData = proxyRules;
|
||||
// fall through
|
||||
case "object":
|
||||
if (Array.isArray(proxyData) && proxyData.length) {
|
||||
return ProxyInfoData.createProxyInfoFromData(
|
||||
proxyData,
|
||||
defaultProxyInfo
|
||||
);
|
||||
}
|
||||
// Not an array, fall through to error.
|
||||
default:
|
||||
throw new ExtensionError(
|
||||
"ProxyInfoData: proxyData must be a string or array of objects"
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function normalizeFilter(filter) {
|
||||
@ -514,199 +403,3 @@ class ProxyChannelFilter {
|
||||
ProxyService.unregisterFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyScriptContext extends BaseContext {
|
||||
constructor(extension, url, contextInfo = {}) {
|
||||
super("proxy_script", extension);
|
||||
this.contextInfo = contextInfo;
|
||||
this.extension = extension;
|
||||
this.messageManager = Services.cpmm;
|
||||
this.sandbox = Cu.Sandbox(this.extension.principal, {
|
||||
sandboxName: `Extension Proxy Script (${
|
||||
extension.policy.debugName
|
||||
}): ${url}`,
|
||||
metadata: { addonID: extension.id },
|
||||
});
|
||||
this.url = url;
|
||||
this.FindProxyForURL = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and validates a proxy script into the sandbox, and then
|
||||
* registers a new proxy filter for the context.
|
||||
*
|
||||
* @returns {boolean} true if load succeeded; false otherwise.
|
||||
*/
|
||||
load() {
|
||||
Schemas.exportLazyGetter(this.sandbox, "browser", () => this.browserObj);
|
||||
|
||||
try {
|
||||
Services.scriptloader.loadSubScript(this.url, this.sandbox);
|
||||
} catch (error) {
|
||||
this.extension.emit("proxy-error", {
|
||||
message: this.normalizeError(error).message,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
this.FindProxyForURL = Cu.unwaiveXrays(this.sandbox.FindProxyForURL);
|
||||
if (typeof this.FindProxyForURL !== "function") {
|
||||
this.extension.emit("proxy-error", {
|
||||
message: "The proxy script must define FindProxyForURL as a function",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyService.registerChannelFilter(
|
||||
this /* nsIProtocolProxyChannelFilter aFilter */,
|
||||
0 /* unsigned long aPosition */
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
logActivity(type, name, data) {
|
||||
// no-op required by subclass
|
||||
}
|
||||
|
||||
get principal() {
|
||||
return this.extension.principal;
|
||||
}
|
||||
|
||||
get cloneScope() {
|
||||
return this.sandbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method (which is required by the nsIProtocolProxyService interface)
|
||||
* is called to apply proxy filter rules for the given URI and proxy object
|
||||
* (or list of proxy objects).
|
||||
*
|
||||
* @param {nsIProtocolProxyService} service A reference to the Protocol Proxy Service.
|
||||
* @param {nsIChannel} channel The channel for which these proxy settings apply.
|
||||
* @param {nsIProxyInfo} defaultProxyInfo The proxy (or list of proxies) that
|
||||
* would be used by default for the given URI. This may be null.
|
||||
* @param {nsIProxyProtocolFilterResult} proxyFilter to call
|
||||
on with the proxy info to apply for the given URI.
|
||||
*/
|
||||
applyFilter(service, channel, defaultProxyInfo, proxyFilter) {
|
||||
let proxyInfo;
|
||||
try {
|
||||
let wrapper = ChannelWrapper.get(channel);
|
||||
if (
|
||||
this.extension.policy.privateBrowsingAllowed ||
|
||||
wrapper.loadInfo.originAttributes.privateBrowsingId == 0
|
||||
) {
|
||||
let uri = wrapper.finalURI;
|
||||
// TODO Bug 1337001 - provide path and query components to non-https URLs.
|
||||
let ret = this.FindProxyForURL(uri.prePath, uri.host, this.contextInfo);
|
||||
proxyInfo = ProxyInfoData.proxyInfoFromProxyData(
|
||||
this,
|
||||
ret,
|
||||
defaultProxyInfo
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
let error = this.normalizeError(e);
|
||||
this.extension.emit("proxy-error", {
|
||||
message: error.message,
|
||||
fileName: error.fileName,
|
||||
lineNumber: error.lineNumber,
|
||||
stack: error.stack,
|
||||
});
|
||||
} finally {
|
||||
// FindProxyForURL may return nothing, null, or proxyInfo.
|
||||
proxyFilter.onProxyFilterResult(
|
||||
proxyInfo !== undefined ? proxyInfo : defaultProxyInfo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the proxy filter and shuts down the sandbox.
|
||||
*/
|
||||
unload() {
|
||||
super.unload();
|
||||
ProxyService.unregisterFilter(this);
|
||||
Cu.nukeSandbox(this.sandbox);
|
||||
this.sandbox = null;
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyScriptAPIManager extends SchemaAPIManager {
|
||||
constructor() {
|
||||
super("proxy", Schemas);
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
lazyInit() {
|
||||
if (!this.initialized) {
|
||||
this.initGlobal();
|
||||
let entries = Services.catMan.enumerateCategory(
|
||||
CATEGORY_EXTENSION_SCRIPTS_CONTENT
|
||||
);
|
||||
for (let { value } of entries) {
|
||||
this.loadScript(value);
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyScriptInjectionContext {
|
||||
constructor(context, apiCan) {
|
||||
this.context = context;
|
||||
this.localAPIs = apiCan.root;
|
||||
this.apiCan = apiCan;
|
||||
}
|
||||
|
||||
shouldInject(namespace, name, allowedContexts) {
|
||||
if (this.context.envType !== "proxy_script") {
|
||||
throw new Error(`Unexpected context type "${this.context.envType}"`);
|
||||
}
|
||||
|
||||
// Do not generate proxy script APIs unless explicitly allowed.
|
||||
return allowedContexts.includes("proxy");
|
||||
}
|
||||
|
||||
getImplementation(namespace, name) {
|
||||
this.apiCan.findAPIPath(`${namespace}.${name}`);
|
||||
let obj = this.apiCan.findAPIPath(namespace);
|
||||
|
||||
if (obj && name in obj) {
|
||||
return new LocalAPIImplementation(obj, name, this.context);
|
||||
}
|
||||
}
|
||||
|
||||
get cloneScope() {
|
||||
return this.context.cloneScope;
|
||||
}
|
||||
|
||||
get principal() {
|
||||
return this.context.principal;
|
||||
}
|
||||
}
|
||||
|
||||
defineLazyGetter(ProxyScriptContext.prototype, "messenger", function() {
|
||||
let sender = { id: this.extension.id, frameId: this.frameId, url: this.url };
|
||||
let filter = { extensionId: this.extension.id, toProxyScript: true };
|
||||
return new ExtensionChild.Messenger(
|
||||
this,
|
||||
[this.messageManager],
|
||||
sender,
|
||||
filter
|
||||
);
|
||||
});
|
||||
|
||||
let proxyScriptAPIManager = new ProxyScriptAPIManager();
|
||||
|
||||
defineLazyGetter(ProxyScriptContext.prototype, "browserObj", function() {
|
||||
let localAPIs = {};
|
||||
let can = new CanOfAPIs(this, proxyScriptAPIManager, localAPIs);
|
||||
proxyScriptAPIManager.lazyInit();
|
||||
|
||||
let browserObj = Cu.createObjectIn(this.sandbox);
|
||||
let injectionContext = new ProxyScriptInjectionContext(this, can);
|
||||
proxyScriptAPIManager.schema.inject(browserObj, injectionContext);
|
||||
return browserObj;
|
||||
});
|
@ -42,7 +42,6 @@ this.runtime = class extends ExtensionAPI {
|
||||
}
|
||||
|
||||
function checkOptions(options) {
|
||||
let toProxyScript = false;
|
||||
if (typeof options !== "object") {
|
||||
return [
|
||||
false,
|
||||
@ -51,21 +50,10 @@ this.runtime = class extends ExtensionAPI {
|
||||
}
|
||||
|
||||
for (let key of Object.keys(options)) {
|
||||
if (key === "toProxyScript") {
|
||||
let value = options[key];
|
||||
if (typeof value !== "boolean") {
|
||||
return [
|
||||
false,
|
||||
"runtime.sendMessage's options.toProxyScript argument is invalid",
|
||||
];
|
||||
}
|
||||
toProxyScript = value;
|
||||
} else {
|
||||
return [false, `Unexpected property ${key}`];
|
||||
}
|
||||
return [false, `Unexpected property ${key}`];
|
||||
}
|
||||
|
||||
return [true, { toProxyScript }];
|
||||
return [true, {}];
|
||||
}
|
||||
|
||||
if (!args.length) {
|
||||
|
@ -39,27 +39,27 @@ extensions.registerModules({
|
||||
},
|
||||
extension: {
|
||||
url: "chrome://extensions/content/child/ext-extension.js",
|
||||
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
|
||||
scopes: ["addon_child", "content_child", "devtools_child"],
|
||||
paths: [["extension"]],
|
||||
},
|
||||
i18n: {
|
||||
url: "chrome://extensions/content/parent/ext-i18n.js",
|
||||
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
|
||||
scopes: ["addon_child", "content_child", "devtools_child"],
|
||||
paths: [["i18n"]],
|
||||
},
|
||||
runtime: {
|
||||
url: "chrome://extensions/content/child/ext-runtime.js",
|
||||
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
|
||||
scopes: ["addon_child", "content_child", "devtools_child"],
|
||||
paths: [["runtime"]],
|
||||
},
|
||||
storage: {
|
||||
url: "chrome://extensions/content/child/ext-storage.js",
|
||||
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
|
||||
scopes: ["addon_child", "content_child", "devtools_child"],
|
||||
paths: [["storage"]],
|
||||
},
|
||||
test: {
|
||||
url: "chrome://extensions/content/child/ext-test.js",
|
||||
scopes: ["addon_child", "content_child", "devtools_child", "proxy_script"],
|
||||
scopes: ["addon_child", "content_child", "devtools_child"],
|
||||
paths: [["test"]],
|
||||
},
|
||||
userScripts: {
|
||||
|
@ -36,7 +36,7 @@ EXTRA_JS_MODULES += [
|
||||
'NativeMessaging.jsm',
|
||||
'onExtensionBrowser.js',
|
||||
'PerformanceCounters.jsm',
|
||||
'ProxyScriptContext.jsm',
|
||||
'ProxyChannelFilter.jsm',
|
||||
'Schemas.jsm',
|
||||
'WebNavigation.jsm',
|
||||
'WebNavigationContent.js',
|
||||
|
@ -6,15 +6,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ProxyScriptContext",
|
||||
"resource://gre/modules/ProxyScriptContext.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ProxyChannelFilter",
|
||||
"resource://gre/modules/ProxyScriptContext.jsm"
|
||||
"resource://gre/modules/ProxyChannelFilter.jsm"
|
||||
);
|
||||
var { ExtensionPreferencesManager } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionPreferencesManager.jsm"
|
||||
@ -23,9 +18,6 @@ var { ExtensionPreferencesManager } = ChromeUtils.import(
|
||||
var { ExtensionError } = ExtensionUtils;
|
||||
var { getSettingsAPI } = ExtensionPreferencesManager;
|
||||
|
||||
// WeakMap[Extension -> ProxyScriptContext]
|
||||
const proxyScriptContextMap = new WeakMap();
|
||||
|
||||
const proxySvc = Ci.nsIProtocolProxyService;
|
||||
|
||||
const PROXY_TYPES_MAP = new Map([
|
||||
@ -133,16 +125,6 @@ function registerProxyFilterEvent(
|
||||
}
|
||||
|
||||
this.proxy = class extends ExtensionAPI {
|
||||
onShutdown() {
|
||||
let { extension } = this;
|
||||
|
||||
let proxyScriptContext = proxyScriptContextMap.get(extension);
|
||||
if (proxyScriptContext) {
|
||||
proxyScriptContext.unload();
|
||||
proxyScriptContextMap.delete(extension);
|
||||
}
|
||||
}
|
||||
|
||||
primeListener(extension, event, fire, params) {
|
||||
if (event === "onRequest") {
|
||||
return registerProxyFilterEvent(undefined, extension, fire, ...params);
|
||||
@ -152,45 +134,8 @@ this.proxy = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
let { extension } = context;
|
||||
|
||||
// Leaving as non-persistent. By itself it's not useful since proxy-error
|
||||
// is emitted from the proxy filter.
|
||||
let onError = new EventManager({
|
||||
context,
|
||||
name: "proxy.onError",
|
||||
register: fire => {
|
||||
let listener = (name, error) => {
|
||||
fire.async(error);
|
||||
};
|
||||
extension.on("proxy-error", listener);
|
||||
return () => {
|
||||
extension.off("proxy-error", listener);
|
||||
};
|
||||
},
|
||||
}).api();
|
||||
|
||||
return {
|
||||
proxy: {
|
||||
register(url) {
|
||||
this.unregister();
|
||||
|
||||
let proxyScriptContext = new ProxyScriptContext(extension, url);
|
||||
if (proxyScriptContext.load()) {
|
||||
proxyScriptContextMap.set(extension, proxyScriptContext);
|
||||
}
|
||||
},
|
||||
|
||||
unregister() {
|
||||
// Unload the current proxy script if one is loaded.
|
||||
if (proxyScriptContextMap.has(extension)) {
|
||||
proxyScriptContextMap.get(extension).unload();
|
||||
proxyScriptContextMap.delete(extension);
|
||||
}
|
||||
},
|
||||
|
||||
registerProxyScript(url) {
|
||||
this.register(url);
|
||||
},
|
||||
|
||||
onRequest: new EventManager({
|
||||
context,
|
||||
name: `proxy.onRequest`,
|
||||
@ -209,10 +154,21 @@ this.proxy = class extends ExtensionAPI {
|
||||
},
|
||||
}).api(),
|
||||
|
||||
onError,
|
||||
|
||||
// TODO Bug 1388619 deprecate onProxyError.
|
||||
onProxyError: onError,
|
||||
// Leaving as non-persistent. By itself it's not useful since proxy-error
|
||||
// is emitted from the proxy filter.
|
||||
onError: new EventManager({
|
||||
context,
|
||||
name: "proxy.onError",
|
||||
register: fire => {
|
||||
let listener = (name, error) => {
|
||||
fire.async(error);
|
||||
};
|
||||
extension.on("proxy-error", listener);
|
||||
return () => {
|
||||
extension.off("proxy-error", listener);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
settings: Object.assign(
|
||||
getSettingsAPI(
|
||||
|
@ -15,7 +15,7 @@
|
||||
},
|
||||
{
|
||||
"namespace": "proxy",
|
||||
"description": "Use the browser.proxy API to register proxy scripts in Firefox. Proxy scripts in Firefox are proxy auto-config files with extra contextual information and support for additional return types.",
|
||||
"description": "Provides access to global proxy settings for Firefox and proxy event listeners to handle dynamic proxy implementations.",
|
||||
"permissions": ["proxy"],
|
||||
"types": [
|
||||
{
|
||||
@ -96,44 +96,6 @@
|
||||
"description": "Configures proxy settings. This setting's value is an object of type ProxyConfig."
|
||||
}
|
||||
},
|
||||
"functions": [
|
||||
{
|
||||
"name": "register",
|
||||
"type": "function",
|
||||
"deprecated": "proxy.register has been deprecated and will be removed in Firefox 71.",
|
||||
"description": "Registers the proxy script for the extension.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"format": "strictRelativeUrl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "unregister",
|
||||
"type": "function",
|
||||
"deprecated": "proxy.unregister has been deprecated and will be removed in Firefox 71.",
|
||||
"description": "Unregisters the proxy script for the extension.",
|
||||
"async": true,
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "registerProxyScript",
|
||||
"type": "function",
|
||||
"deprecated": "proxy.registerProxyScript has been deprecated and will be removed in Firefox 71.",
|
||||
"description": "Registers the proxy script for the extension. This is an alias for proxy.register.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"format": "strictRelativeUrl"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onRequest",
|
||||
|
@ -19,7 +19,7 @@
|
||||
},
|
||||
{
|
||||
"namespace": "runtime",
|
||||
"allowedContexts": ["content", "devtools", "proxy"],
|
||||
"allowedContexts": ["content", "devtools"],
|
||||
"description": "Use the <code>browser.runtime</code> API to retrieve the background page, return details about the manifest, and listen for and respond to events in the app or extension lifecycle. You can also use this API to convert the relative path of URLs to fully-qualified URLs.",
|
||||
"types": [
|
||||
{
|
||||
@ -334,7 +334,7 @@
|
||||
"name": "sendMessage",
|
||||
"type": "function",
|
||||
"allowAmbiguousOptionalArguments": true,
|
||||
"allowedContexts": ["content", "devtools", "proxy"],
|
||||
"allowedContexts": ["content", "devtools"],
|
||||
"description": "Sends a single message to event listeners within your extension/app or a different extension/app. Similar to $(ref:runtime.connect) but only sends a single message, with an optional response. If sending to your extension, the $(ref:runtime.onMessage) event will be fired in each page, or $(ref:runtime.onMessageExternal), if a different extension. Note that extensions cannot send messages to content scripts using this method. To send messages to content scripts, use $(ref:tabs.sendMessage).",
|
||||
"async": "responseCallback",
|
||||
"parameters": [
|
||||
@ -344,8 +344,7 @@
|
||||
"type": "object",
|
||||
"name": "options",
|
||||
"properties": {
|
||||
"includeTlsChannelId": { "type": "boolean", "optional": true, "unsupported": true, "description": "Whether the TLS channel ID will be passed into onMessageExternal for processes that are listening for the connection event." },
|
||||
"toProxyScript": { "type": "boolean", "optional": true, "description": "If true, the message will be directed to the extension's proxy sandbox."}
|
||||
"includeTlsChannelId": { "type": "boolean", "optional": true, "unsupported": true, "description": "Whether the TLS channel ID will be passed into onMessageExternal for processes that are listening for the connection event." }
|
||||
},
|
||||
"optional": true
|
||||
},
|
||||
@ -553,7 +552,7 @@
|
||||
{
|
||||
"name": "onMessage",
|
||||
"type": "function",
|
||||
"allowedContexts": ["content", "devtools", "proxy"],
|
||||
"allowedContexts": ["content", "devtools"],
|
||||
"description": "Fired when a message is sent from either an extension process or a content script.",
|
||||
"parameters": [
|
||||
{"name": "message", "type": "any", "optional": true, "description": "The message sent by the calling script."},
|
||||
|
@ -1,191 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"authManager",
|
||||
"@mozilla.org/network/http-auth-manager;1",
|
||||
"nsIHttpAuthManager"
|
||||
);
|
||||
|
||||
const proxy = createHttpServer();
|
||||
|
||||
// accept proxy connections for mozilla.org
|
||||
proxy.identity.add("http", "mozilla.org", 80);
|
||||
|
||||
proxy.registerPathHandler("/", (request, response) => {
|
||||
if (request.hasHeader("Proxy-Authorization")) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.write("ok, got proxy auth");
|
||||
} else {
|
||||
response.setStatusLine(
|
||||
request.httpVersion,
|
||||
407,
|
||||
"Proxy authentication required"
|
||||
);
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.setHeader("Proxy-Authenticate", 'Basic realm="foobar"', false);
|
||||
response.write("auth required");
|
||||
}
|
||||
});
|
||||
|
||||
function getExtension(background) {
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["proxy", "webRequest", "webRequestBlocking", "<all_urls>"],
|
||||
},
|
||||
background: `(${background})(${proxy.identity.primaryPort})`,
|
||||
files: {
|
||||
"proxy.js": `
|
||||
function FindProxyForURL(url, host) {
|
||||
return "PROXY localhost:${proxy.identity.primaryPort}; DIRECT";
|
||||
}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
add_task(async function test_webRequest_auth_proxy() {
|
||||
async function background(port) {
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
details => {
|
||||
browser.test.log(`details ${JSON.stringify(details)}\n`);
|
||||
browser.test.assertEq(
|
||||
"localhost",
|
||||
details.proxyInfo.host,
|
||||
"proxy host"
|
||||
);
|
||||
browser.test.assertEq(port, details.proxyInfo.port, "proxy port");
|
||||
browser.test.assertEq("http", details.proxyInfo.type, "proxy type");
|
||||
browser.test.assertEq(
|
||||
"",
|
||||
details.proxyInfo.username,
|
||||
"proxy username not set"
|
||||
);
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
browser.webRequest.onAuthRequired.addListener(
|
||||
details => {
|
||||
browser.test.assertTrue(details.isProxy, "proxied request");
|
||||
browser.test.assertEq(
|
||||
"localhost",
|
||||
details.proxyInfo.host,
|
||||
"proxy host"
|
||||
);
|
||||
browser.test.assertEq(port, details.proxyInfo.port, "proxy port");
|
||||
browser.test.assertEq("http", details.proxyInfo.type, "proxy type");
|
||||
browser.test.assertEq(
|
||||
"localhost",
|
||||
details.challenger.host,
|
||||
"proxy host"
|
||||
);
|
||||
browser.test.assertEq(port, details.challenger.port, "proxy port");
|
||||
return { authCredentials: { username: "puser", password: "ppass" } };
|
||||
},
|
||||
{ urls: ["<all_urls>"] },
|
||||
["blocking"]
|
||||
);
|
||||
browser.webRequest.onCompleted.addListener(
|
||||
details => {
|
||||
browser.test.log(`details ${JSON.stringify(details)}\n`);
|
||||
browser.test.assertEq(
|
||||
"localhost",
|
||||
details.proxyInfo.host,
|
||||
"proxy host"
|
||||
);
|
||||
browser.test.assertEq(port, details.proxyInfo.port, "proxy port");
|
||||
browser.test.assertEq("http", details.proxyInfo.type, "proxy type");
|
||||
browser.test.assertEq(
|
||||
"",
|
||||
details.proxyInfo.username,
|
||||
"proxy username not set by onAuthRequired"
|
||||
);
|
||||
browser.test.assertEq(
|
||||
undefined,
|
||||
details.proxyInfo.password,
|
||||
"no proxy password"
|
||||
);
|
||||
browser.test.sendMessage("done");
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
|
||||
await browser.proxy.register("proxy.js");
|
||||
browser.test.sendMessage("pac-ready");
|
||||
}
|
||||
|
||||
let handlingExt = getExtension(background);
|
||||
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await handlingExt.startup();
|
||||
await handlingExt.awaitMessage("pac-ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
authManager.clearAll();
|
||||
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
`http://mozilla.org/`
|
||||
);
|
||||
|
||||
await handlingExt.awaitMessage("done");
|
||||
await contentPage.close();
|
||||
await handlingExt.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_webRequest_auth_proxy_system() {
|
||||
async function background(port) {
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
details => {
|
||||
browser.test.fail("onBeforeRequest");
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
browser.webRequest.onAuthRequired.addListener(
|
||||
details => {
|
||||
browser.test.sendMessage("onAuthRequired");
|
||||
// cancel is silently ignored, if it were not (e.g someone messes up in
|
||||
// WebRequest.jsm and allows cancel) this test would fail.
|
||||
return {
|
||||
cancel: true,
|
||||
authCredentials: { username: "puser", password: "ppass" },
|
||||
};
|
||||
},
|
||||
{ urls: ["<all_urls>"] },
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
await browser.proxy.register("proxy.js");
|
||||
browser.test.sendMessage("pac-ready");
|
||||
}
|
||||
|
||||
let handlingExt = getExtension(background);
|
||||
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await handlingExt.startup();
|
||||
await handlingExt.awaitMessage("pac-ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
function fetch(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.mozBackgroundRequest = true;
|
||||
xhr.open("GET", url);
|
||||
xhr.onload = () => {
|
||||
resolve(xhr.responseText);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
reject(xhr.status);
|
||||
};
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
authManager.clearAll();
|
||||
|
||||
await Promise.all([
|
||||
handlingExt.awaitMessage("onAuthRequired"),
|
||||
fetch("http://mozilla.org"),
|
||||
]);
|
||||
await handlingExt.unload();
|
||||
});
|
@ -519,9 +519,20 @@ add_task(async function test_webRequest_socks_proxy() {
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
|
||||
await browser.proxy.register("proxy.js");
|
||||
browser.test.sendMessage("pac-ready");
|
||||
browser.proxy.onRequest.addListener(
|
||||
() => {
|
||||
return [
|
||||
{
|
||||
type: "socks",
|
||||
host: "127.0.0.1",
|
||||
port,
|
||||
username: "foo",
|
||||
password: "bar",
|
||||
},
|
||||
];
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
}
|
||||
|
||||
let handlingExt = ExtensionTestUtils.loadExtension({
|
||||
@ -529,24 +540,11 @@ add_task(async function test_webRequest_socks_proxy() {
|
||||
permissions: ["proxy", "webRequest", "webRequestBlocking", "<all_urls>"],
|
||||
},
|
||||
background: `(${background})(${socksServer.listener.localPort})`,
|
||||
files: {
|
||||
"proxy.js": `
|
||||
function FindProxyForURL(url, host) {
|
||||
return [{
|
||||
type: "socks",
|
||||
host: "127.0.0.1",
|
||||
port: ${socksServer.listener.localPort},
|
||||
username: "foo",
|
||||
password: "bar",
|
||||
}];
|
||||
}`,
|
||||
},
|
||||
});
|
||||
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await handlingExt.startup();
|
||||
await handlingExt.awaitMessage("pac-ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
|
@ -101,85 +101,3 @@ add_task(async function test_incognito_proxy_onRequest_access() {
|
||||
|
||||
Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
|
||||
});
|
||||
|
||||
function scriptData(script) {
|
||||
return String(script).replace(/^.*?\{([^]*)\}$/, "$1");
|
||||
}
|
||||
|
||||
add_task(async function test_incognito_proxy_register_access() {
|
||||
Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", false);
|
||||
|
||||
// This extension will fail if it gets a request
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
},
|
||||
async background() {
|
||||
browser.runtime.onMessage.addListener((message, sender) => {
|
||||
if (sender.url === browser.extension.getURL("proxy.js")) {
|
||||
browser.test.fail(message);
|
||||
}
|
||||
});
|
||||
await browser.proxy.register("proxy.js");
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
files: {
|
||||
"proxy.js": scriptData(() => {
|
||||
function FindProxyForURL() {
|
||||
// Shoot a message off to the background.
|
||||
browser.runtime.sendMessage("incognito fail");
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
},
|
||||
});
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
// This extension will succeed if it gets a request
|
||||
let pb_extension = ExtensionTestUtils.loadExtension({
|
||||
incognitoOverride: "spanning",
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
},
|
||||
async background() {
|
||||
browser.runtime.onMessage.addListener((message, sender) => {
|
||||
if (sender.url === browser.extension.getURL("proxy.js")) {
|
||||
browser.test.notifyPass(message);
|
||||
}
|
||||
});
|
||||
await browser.proxy.register("proxy.js");
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
files: {
|
||||
"proxy.js": scriptData(() => {
|
||||
function FindProxyForURL() {
|
||||
// Shoot a message off to the background.
|
||||
browser.runtime.sendMessage("success");
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
},
|
||||
});
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await pb_extension.startup();
|
||||
await pb_extension.awaitMessage("ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
let finished = pb_extension.awaitFinish("success");
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
"http://example.com/dummy",
|
||||
{ privateBrowsing: true }
|
||||
);
|
||||
await finished;
|
||||
|
||||
await extension.unload();
|
||||
await pb_extension.unload();
|
||||
await contentPage.close();
|
||||
|
||||
Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
|
||||
});
|
||||
|
@ -1,7 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
/* eslint no-unused-vars: ["error", {"args": "none", "varsIgnorePattern": "^(FindProxyForURL)$"}] */
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"gProxyService",
|
||||
@ -16,52 +14,40 @@ let extension;
|
||||
add_task(async function setup() {
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
permissions: ["proxy", "<all_urls>"],
|
||||
},
|
||||
background() {
|
||||
browser.proxy.onProxyError.addListener(error => {
|
||||
let settings = { proxy: null };
|
||||
|
||||
browser.proxy.onError.addListener(error => {
|
||||
browser.test.sendMessage("proxy-error-received", error);
|
||||
});
|
||||
browser.test.onMessage.addListener((message, data) => {
|
||||
if (message === "set-proxy") {
|
||||
browser.runtime
|
||||
.sendMessage(data, { toProxyScript: true })
|
||||
.then(response => {
|
||||
browser.test.sendMessage("proxy-set", response);
|
||||
});
|
||||
settings.proxy = data.proxy;
|
||||
browser.test.sendMessage("proxy-set", settings.proxy);
|
||||
}
|
||||
});
|
||||
browser.proxy.register("proxy.js").then(() => {
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
},
|
||||
files: {
|
||||
"proxy.js": `"use strict";
|
||||
let settings = {proxy: null};
|
||||
function FindProxyForURL(url, host) {
|
||||
browser.proxy.onRequest.addListener(
|
||||
() => {
|
||||
return settings.proxy;
|
||||
}
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
if (msg.proxy) {
|
||||
settings.proxy = msg.proxy;
|
||||
return Promise.resolve(settings.proxy);
|
||||
}
|
||||
});
|
||||
`,
|
||||
},
|
||||
{ urls: ["<all_urls>"] }
|
||||
);
|
||||
},
|
||||
};
|
||||
extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
// proxy.register and proxy.onProxyError are deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
});
|
||||
|
||||
async function setupProxyScript(proxy) {
|
||||
async function setupProxyResult(proxy) {
|
||||
extension.sendMessage("set-proxy", { proxy });
|
||||
let proxyInfoSent = await extension.awaitMessage("proxy-set");
|
||||
deepEqual(proxyInfoSent, proxy, "got back proxy data from proxy script");
|
||||
deepEqual(
|
||||
proxyInfoSent,
|
||||
proxy,
|
||||
"got back proxy data from the proxy listener"
|
||||
);
|
||||
}
|
||||
|
||||
async function testProxyResolution(test) {
|
||||
@ -134,91 +120,26 @@ async function testProxyResolution(test) {
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function test_pac_results() {
|
||||
add_task(async function test_proxyInfo_results() {
|
||||
let tests = [
|
||||
{
|
||||
proxy: undefined,
|
||||
expected: {
|
||||
error: "ProxyInfoData: proxyData must be a string or array of objects",
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: 5,
|
||||
expected: {
|
||||
error: "ProxyInfoData: proxyData must be a string or array of objects",
|
||||
error: "ProxyInfoData: proxyData must be an object or array of objects",
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "INVALID",
|
||||
expected: {
|
||||
error: 'ProxyInfoData: Unrecognized proxy type: "invalid"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "SOCKS",
|
||||
expected: {
|
||||
error: 'ProxyInfoData: Invalid host or port from proxy rule: "SOCKS"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY 1.2.3.4:8080 EXTRA",
|
||||
expected: {
|
||||
error:
|
||||
'ProxyInfoData: Invalid arguments passed for proxy rule: "PROXY 1.2.3.4:8080 EXTRA"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY :",
|
||||
expected: {
|
||||
error: 'ProxyInfoData: Invalid host or port from proxy rule: "PROXY :"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY :8080",
|
||||
expected: {
|
||||
error:
|
||||
'ProxyInfoData: Invalid host or port from proxy rule: "PROXY :8080"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY ::",
|
||||
expected: {
|
||||
error:
|
||||
'ProxyInfoData: Invalid host or port from proxy rule: "PROXY ::"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY 1.2.3.4:",
|
||||
expected: {
|
||||
error:
|
||||
'ProxyInfoData: Invalid host or port from proxy rule: "PROXY 1.2.3.4:"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "DIRECT 1.2.3.4:8080",
|
||||
expected: {
|
||||
error: 'ProxyInfoData: Invalid argument for proxy type: "direct"',
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: [
|
||||
"SOCKS foo.bar:1080",
|
||||
{ type: "http", host: "foo.bar", port: 3128 },
|
||||
],
|
||||
expected: {
|
||||
error: 'ProxyInfoData: Invalid proxy server type: "undefined"',
|
||||
error: "ProxyInfoData: proxyData must be an object or array of objects",
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: {
|
||||
type: "socks",
|
||||
host: "foo.bar",
|
||||
port: 1080,
|
||||
username: "mungosantamaria",
|
||||
password: "pass123",
|
||||
},
|
||||
expected: {
|
||||
error: "ProxyInfoData: proxyData must be a string or array of objects",
|
||||
error: 'ProxyInfoData: Invalid proxy server host: "undefined"',
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -275,7 +196,12 @@ add_task(async function test_pac_results() {
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY 1.2.3.4:8080",
|
||||
proxy: {
|
||||
host: "1.2.3.4",
|
||||
port: "8080",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "1.2.3.4",
|
||||
@ -287,29 +213,53 @@ add_task(async function test_pac_results() {
|
||||
},
|
||||
{
|
||||
uri: "ftp://mozilla.org",
|
||||
proxy: "PROXY 1.2.3.4:8080",
|
||||
proxy: {
|
||||
host: "1.2.3.4",
|
||||
port: "8180",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "1.2.3.4",
|
||||
port: "8080",
|
||||
port: "8180",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: " PROXY 2.3.4.5:8080 ",
|
||||
proxy: {
|
||||
host: "2.3.4.5",
|
||||
port: "8181",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "2.3.4.5",
|
||||
port: "8080",
|
||||
port: "8181",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "PROXY 1.2.3.4:8080; SOCKS 4.4.4.4:9000; DIRECT",
|
||||
proxy: {
|
||||
host: "1.2.3.4",
|
||||
port: "8080",
|
||||
type: "http",
|
||||
failoverProxy: {
|
||||
host: "4.4.4.4",
|
||||
port: "9000",
|
||||
type: "socks",
|
||||
failoverProxy: {
|
||||
type: "direct",
|
||||
host: null,
|
||||
port: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "1.2.3.4",
|
||||
@ -339,7 +289,11 @@ add_task(async function test_pac_results() {
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "SOCKS foo.bar:1080",
|
||||
proxy: {
|
||||
host: "foo.bar",
|
||||
port: "1080",
|
||||
type: "socks",
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "foo.bar",
|
||||
@ -349,7 +303,11 @@ add_task(async function test_pac_results() {
|
||||
},
|
||||
},
|
||||
{
|
||||
proxy: "SOCKS4 foo.bar:1080",
|
||||
proxy: {
|
||||
host: "foo.bar",
|
||||
port: "1080",
|
||||
type: "socks4",
|
||||
},
|
||||
expected: {
|
||||
proxyInfo: {
|
||||
host: "foo.bar",
|
||||
@ -451,14 +409,11 @@ add_task(async function test_pac_results() {
|
||||
},
|
||||
];
|
||||
for (let test of tests) {
|
||||
await setupProxyScript(test.proxy);
|
||||
await setupProxyResult(test.proxy);
|
||||
if (!test.uri) {
|
||||
test.uri = "http://www.mozilla.org/";
|
||||
}
|
||||
await testProxyResolution(test);
|
||||
// Our proxy script for testing is stateless, so repeating the test should
|
||||
// yield exactly the same results.
|
||||
await testProxyResolution(test);
|
||||
}
|
||||
});
|
||||
|
@ -1,194 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
/* eslint no-unused-vars: ["error", {"args": "none", "varsIgnorePattern": "^(FindProxyForURL)$"}] */
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"gProxyService",
|
||||
"@mozilla.org/network/protocol-proxy-service;1",
|
||||
"nsIProtocolProxyService"
|
||||
);
|
||||
|
||||
function getProxyInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let channel = NetUtil.newChannel({
|
||||
uri: "http://www.mozilla.org/",
|
||||
loadUsingSystemPrincipal: true,
|
||||
});
|
||||
|
||||
gProxyService.asyncResolve(channel, 0, {
|
||||
onProxyAvailable(req, uri, pi, status) {
|
||||
resolve(pi);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
async function testProxyScript(script, expected = {}) {
|
||||
let scriptData = String(script).replace(/^.*?\{([^]*)\}$/, "$1");
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
},
|
||||
background() {
|
||||
// Some tests generate multiple errors, we'll just rely on the first.
|
||||
let seenError = false;
|
||||
browser.proxy.onProxyError.addListener(error => {
|
||||
if (!seenError) {
|
||||
browser.test.sendMessage("proxy-error-received", error);
|
||||
seenError = true;
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg === "unregister-proxy-script") {
|
||||
browser.proxy.unregister().then(() => {
|
||||
browser.test.notifyPass("proxy");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
browser.proxy.register("proxy.js").then(() => {
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
},
|
||||
files: {
|
||||
"proxy.js": scriptData,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
// proxy.register and proxy.onProxyError are deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
|
||||
let errorWait = extension.awaitMessage("proxy-error-received");
|
||||
|
||||
let proxyInfo = await getProxyInfo();
|
||||
|
||||
let error = await errorWait;
|
||||
equal(error.message, expected.message, "Correct error message received");
|
||||
if (!expected.proxyInfo) {
|
||||
equal(proxyInfo, null, "no proxyInfo received");
|
||||
} else {
|
||||
let { host, port, type } = expected.proxyInfo;
|
||||
equal(proxyInfo.host, host, `Expected proxy host to be ${host}`);
|
||||
equal(proxyInfo.port, port, `Expected proxy port to be ${port}`);
|
||||
equal(proxyInfo.type, type, `Expected proxy type to be ${type}`);
|
||||
}
|
||||
if (expected.errorInfo) {
|
||||
ok(error.fileName.includes("proxy.js"), "Error should include file name");
|
||||
equal(error.lineNumber, 3, "Error should include line number");
|
||||
ok(
|
||||
error.stack.includes("proxy.js:3:9"),
|
||||
"Error should include stack trace"
|
||||
);
|
||||
}
|
||||
// proxy.unregister is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
extension.sendMessage("unregister-proxy-script");
|
||||
await extension.awaitFinish("proxy");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
await extension.unload();
|
||||
}
|
||||
|
||||
add_task(async function test_invalid_FindProxyForURL_function() {
|
||||
await testProxyScript(() => {}, {
|
||||
message: "The proxy script must define FindProxyForURL as a function",
|
||||
});
|
||||
|
||||
await testProxyScript(
|
||||
() => {
|
||||
var FindProxyForURL = 5; // eslint-disable-line mozilla/var-only-at-top-level
|
||||
},
|
||||
{
|
||||
message: "The proxy script must define FindProxyForURL as a function",
|
||||
}
|
||||
);
|
||||
|
||||
await testProxyScript(
|
||||
() => {
|
||||
function FindProxyForURL() {
|
||||
return not_defined; // eslint-disable-line no-undef
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "not_defined is not defined",
|
||||
errorInfo: true,
|
||||
}
|
||||
);
|
||||
|
||||
// The following tests will produce multiple errors.
|
||||
await testProxyScript(
|
||||
() => {
|
||||
function FindProxyForURL() {
|
||||
return ";;;;;PROXY 1.2.3.4:8080";
|
||||
}
|
||||
},
|
||||
{
|
||||
message: "ProxyInfoData: Missing Proxy Rule",
|
||||
}
|
||||
);
|
||||
|
||||
// We take any valid proxy up to the error.
|
||||
await testProxyScript(
|
||||
() => {
|
||||
function FindProxyForURL() {
|
||||
return "PROXY 1.2.3.4:8080; UNEXPECTED; SOCKS 1.2.3.4:8080";
|
||||
}
|
||||
},
|
||||
{
|
||||
message: 'ProxyInfoData: Unrecognized proxy type: "unexpected"',
|
||||
proxyInfo: {
|
||||
host: "1.2.3.4",
|
||||
port: "8080",
|
||||
type: "http",
|
||||
failoverProxy: null,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
async function getExtension(proxyResult) {
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
},
|
||||
background() {
|
||||
browser.proxy.register("proxy.js").then(() => {
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
},
|
||||
files: {
|
||||
"proxy.js": `
|
||||
function FindProxyForURL(url, host) {
|
||||
return ${proxyResult};
|
||||
}`,
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
// proxy.register is deprecated - bug 1443259.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
ExtensionTestUtils.failOnSchemaWarnings(true);
|
||||
return extension;
|
||||
}
|
||||
|
||||
add_task(async function test_passthrough() {
|
||||
let ext1 = await getExtension(null);
|
||||
let ext2 = await getExtension('"PROXY 1.2.3.4:8888"');
|
||||
|
||||
let proxyInfo = await getProxyInfo();
|
||||
|
||||
equal(proxyInfo.host, "1.2.3.4", `second extension won`);
|
||||
equal(proxyInfo.port, "8888", `second extension won`);
|
||||
equal(proxyInfo.type, "http", `second extension won`);
|
||||
|
||||
await ext2.unload();
|
||||
|
||||
proxyInfo = await getProxyInfo();
|
||||
equal(proxyInfo, null, `expected no proxy`);
|
||||
await ext1.unload();
|
||||
});
|
@ -1,67 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
// This test expects and checks deprecation messages.
|
||||
ExtensionTestUtils.failOnSchemaWarnings(false);
|
||||
|
||||
add_task(async function test_proxy_deprecation_messages() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["proxy"],
|
||||
},
|
||||
background() {
|
||||
async function callProxyAPIs() {
|
||||
browser.proxy.onProxyError.addListener(() => {});
|
||||
browser.proxy.onError.addListener(() => {});
|
||||
// Not expecting deprecation warning for this one:
|
||||
browser.proxy.onRequest.addListener(() => {}, { urls: ["http://x/*"] });
|
||||
await browser.proxy.register("proxy.js");
|
||||
await browser.proxy.unregister();
|
||||
await browser.proxy.registerProxyScript("proxy.js");
|
||||
await browser.proxy.unregister();
|
||||
}
|
||||
browser.test.onMessage.addListener(async () => {
|
||||
try {
|
||||
await callProxyAPIs();
|
||||
} catch (e) {
|
||||
browser.test.fail(e);
|
||||
}
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
},
|
||||
files: {
|
||||
"proxy.js": "// Dummy script.",
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
let { messages } = await promiseConsoleOutput(async () => {
|
||||
extension.sendMessage("start-test");
|
||||
await extension.awaitMessage("done");
|
||||
});
|
||||
await extension.unload();
|
||||
AddonTestUtils.checkMessages(
|
||||
messages,
|
||||
{
|
||||
expected: [
|
||||
{
|
||||
message: /proxy\.onProxyError has been deprecated and will be removed in Firefox 71\. Use proxy.onError instead/,
|
||||
},
|
||||
{
|
||||
message: /proxy\.register has been deprecated and will be removed in Firefox 71/,
|
||||
},
|
||||
{
|
||||
message: /proxy\.unregister has been deprecated and will be removed in Firefox 71/,
|
||||
},
|
||||
{
|
||||
message: /proxy\.registerProxyScript has been deprecated and will be removed in Firefox 71/,
|
||||
},
|
||||
{
|
||||
message: /proxy\.unregister has been deprecated and will be removed in Firefox 71/,
|
||||
},
|
||||
],
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
@ -90,7 +90,6 @@ skip-if = appname == "thunderbird" || (os == "android" && debug)
|
||||
[test_ext_privacy_disable.js]
|
||||
skip-if = appname == "thunderbird"
|
||||
[test_ext_privacy_update.js]
|
||||
[test_ext_proxy_auth.js]
|
||||
[test_ext_proxy_authorization_via_proxyinfo.js]
|
||||
[test_ext_proxy_config.js]
|
||||
skip-if = appname == "thunderbird"
|
||||
@ -98,7 +97,7 @@ skip-if = appname == "thunderbird"
|
||||
[test_ext_proxy_settings.js]
|
||||
skip-if = appname == "thunderbird" || os == "android" # proxy settings are not supported on android
|
||||
[test_ext_proxy_socks.js]
|
||||
skip-if = os == "win" && debug || os == "linux" && debug # Bug 1566843 disabling for many failures
|
||||
run-sequentially = TCPServerSocket fails otherwise
|
||||
[test_ext_proxy_speculative.js]
|
||||
[test_ext_proxy_startup.js]
|
||||
[test_ext_redirects.js]
|
||||
@ -185,9 +184,7 @@ skip-if = appname == "thunderbird" || os == "android" # Bug 1350559
|
||||
[test_proxy_listener.js]
|
||||
[test_proxy_incognito.js]
|
||||
skip-if = os == "android" # incognito not supported on android
|
||||
[test_proxy_scripts.js]
|
||||
[test_proxy_scripts_deprecated.js]
|
||||
[test_proxy_scripts_results.js]
|
||||
[test_proxy_info_results.js]
|
||||
[test_proxy_userContextId.js]
|
||||
[test_webRequest_ancestors.js]
|
||||
[test_webRequest_cookies.js]
|
||||
|
Loading…
x
Reference in New Issue
Block a user