Bug 1455755 Move browserSettings.proxyConfig to proxy.settings, r=aswan, mstrimer

--HG--
rename : toolkit/components/extensions/test/xpcshell/test_ext_browserSettings.js => toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
This commit is contained in:
Shane Caraveo 2018-04-25 18:50:22 -05:00
Родитель be628a4524
Коммит 1e0138caf3
12 изменённых файлов: 667 добавлений и 554 удалений

Просмотреть файл

@ -274,7 +274,7 @@ var gConnectionsDialog = {
hideControllingExtension(PROXY_KEY);
setInputsDisabledState(false);
} else {
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY)
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY, "extensionControlled.proxyConfig")
.then(setInputsDisabledState);
}
}

Просмотреть файл

@ -21,7 +21,7 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
"privacy.trackingprotection.ui.enabled");
const PREF_SETTING_TYPE = "prefs";
const PROXY_KEY = "proxyConfig";
const PROXY_KEY = "proxy.settings";
const API_PROXY_PREFS = [
"network.proxy.type",
"network.proxy.http",
@ -45,7 +45,7 @@ let extensionControlledContentIds = {
"homepage_override": "browserHomePageExtensionContent",
"newTabURL": "browserNewTabExtensionContent",
"defaultSearch": "browserDefaultSearchExtensionContent",
"proxyConfig": "proxyExtensionContent",
"proxy.settings": "proxyExtensionContent",
get "websites.trackingProtectionMode"() {
return {
button: "trackingProtectionExtensionContentButton",
@ -59,7 +59,7 @@ let extensionControlledContentIds = {
function getExtensionControlledArgs(settingName) {
switch (settingName) {
case "proxyConfig":
case "proxy.settings":
return [document.getElementById("bundleBrand").getString("brandShortName")];
default:
return [];

Просмотреть файл

@ -646,7 +646,7 @@ add_task(async function testExtensionControlledProxyConfig() {
await SpecialPowers.pushPrefEnv({"set": [[PROXY_PREF, PROXY_DEFAULT]]});
function background() {
browser.browserSettings.proxyConfig.set({value: {proxyType: "none"}});
browser.proxy.settings.set({value: {proxyType: "none"}});
}
function expectedConnectionSettingsMessage(doc, isControlled) {
@ -780,7 +780,7 @@ add_task(async function testExtensionControlledProxyConfig() {
manifest: {
name: "set_proxy",
applications: {gecko: {id: EXTENSION_ID}},
permissions: ["browserSettings"],
permissions: ["proxy"],
},
background,
});

Просмотреть файл

@ -349,4 +349,57 @@ this.ExtensionPreferencesManager = {
await ExtensionSettingsStore.initialize();
return ExtensionSettingsStore.getLevelOfControl(id, storeType, name);
},
/**
* Returns an API object with get/set/clear used for a setting.
*
* @param {string} extensionId
* @param {string} name
* The unique id of the setting.
* @param {Function} callback
* The function that retreives the current setting from prefs.
* @param {string} storeType
* The name of the store in ExtensionSettingsStore.
* Defaults to STORE_TYPE.
* @param {boolean} readOnly
* @param {Function} validate
* Utility function for any specific validation, such as checking
* for supported platform. Function should throw an error if necessary.
*
* @returns {object} API object with get/set/clear methods
*/
getSettingsAPI(extensionId, name, callback, storeType, readOnly = false, validate = () => {}) {
return {
async get(details) {
validate();
let levelOfControl = details.incognito ?
"not_controllable" :
await ExtensionPreferencesManager.getLevelOfControl(
extensionId, name, storeType);
levelOfControl =
(readOnly && levelOfControl === "controllable_by_this_extension") ?
"not_controllable" :
levelOfControl;
return {
levelOfControl,
value: await callback(),
};
},
set(details) {
validate();
if (!readOnly) {
return ExtensionPreferencesManager.setSetting(
extensionId, name, details.value);
}
return false;
},
clear(details) {
validate();
if (!readOnly) {
return ExtensionPreferencesManager.removeSetting(extensionId, name);
}
return false;
},
};
},
};

Просмотреть файл

@ -16,16 +16,9 @@ ChromeUtils.import("resource://gre/modules/ExtensionPreferencesManager.jsm");
var {
ExtensionError,
} = ExtensionUtils;
const proxySvc = Ci.nsIProtocolProxyService;
const PROXY_TYPES_MAP = new Map([
["none", proxySvc.PROXYCONFIG_DIRECT],
["autoDetect", proxySvc.PROXYCONFIG_WPAD],
["system", proxySvc.PROXYCONFIG_SYSTEM],
["manual", proxySvc.PROXYCONFIG_MANUAL],
["autoConfig", proxySvc.PROXYCONFIG_PAC],
]);
var {
getSettingsAPI,
} = ExtensionPreferencesManager;
const HOMEPAGE_OVERRIDE_SETTING = "homepage_override";
const HOMEPAGE_URL_PREF = "browser.startup.homepage";
@ -34,48 +27,6 @@ const NEW_TAB_OVERRIDE_SETTING = "newTabURL";
const PERM_DENY_ACTION = Services.perms.DENY_ACTION;
const checkUnsupported = (name, unsupportedPlatforms) => {
if (unsupportedPlatforms.includes(AppConstants.platform)) {
throw new ExtensionError(
`${AppConstants.platform} is not a supported platform for the ${name} setting.`);
}
};
const getSettingsAPI = (extension, name, callback, storeType, readOnly = false, unsupportedPlatforms = []) => {
return {
async get(details) {
checkUnsupported(name, unsupportedPlatforms);
let levelOfControl = details.incognito ?
"not_controllable" :
await ExtensionPreferencesManager.getLevelOfControl(
extension.id, name, storeType);
levelOfControl =
(readOnly && levelOfControl === "controllable_by_this_extension") ?
"not_controllable" :
levelOfControl;
return {
levelOfControl,
value: await callback(),
};
},
set(details) {
checkUnsupported(name, unsupportedPlatforms);
if (!readOnly) {
return ExtensionPreferencesManager.setSetting(
extension.id, name, details.value);
}
return false;
},
clear(details) {
checkUnsupported(name, unsupportedPlatforms);
if (!readOnly) {
return ExtensionPreferencesManager.removeSetting(extension.id, name);
}
return false;
},
};
};
// Add settings objects for supported APIs to the preferences manager.
ExtensionPreferencesManager.addSetting("allowPopupsForUserEvents", {
prefNames: [
@ -179,52 +130,6 @@ ExtensionPreferencesManager.addSetting("openUrlbarResultsInNewTabs", {
},
});
ExtensionPreferencesManager.addSetting("proxyConfig", {
prefNames: [
"network.proxy.type",
"network.proxy.http",
"network.proxy.http_port",
"network.proxy.share_proxy_settings",
"network.proxy.ftp",
"network.proxy.ftp_port",
"network.proxy.ssl",
"network.proxy.ssl_port",
"network.proxy.socks",
"network.proxy.socks_port",
"network.proxy.socks_version",
"network.proxy.socks_remote_dns",
"network.proxy.no_proxies_on",
"network.proxy.autoconfig_url",
"signon.autologin.proxy",
],
setCallback(value) {
let prefs = {
"network.proxy.type": PROXY_TYPES_MAP.get(value.proxyType),
"signon.autologin.proxy": value.autoLogin,
"network.proxy.socks_remote_dns": value.proxyDNS,
"network.proxy.autoconfig_url": value.autoConfigUrl,
"network.proxy.share_proxy_settings": value.httpProxyAll,
"network.proxy.socks_version": value.socksVersion,
"network.proxy.no_proxies_on": value.passthrough,
};
for (let prop of ["http", "ftp", "ssl", "socks"]) {
if (value[prop]) {
let url = new URL(`http://${value[prop]}`);
prefs[`network.proxy.${prop}`] = url.hostname;
let port = parseInt(url.port, 10);
prefs[`network.proxy.${prop}_port`] = isNaN(port) ? 0 : port;
} else {
prefs[`network.proxy.${prop}`] = undefined;
prefs[`network.proxy.${prop}_port`] = undefined;
}
}
return prefs;
},
});
ExtensionPreferencesManager.addSetting("webNotificationsDisabled", {
prefNames: [
"permissions.default.desktop-notification",
@ -261,24 +166,29 @@ this.browserSettings = class extends ExtensionAPI {
return {
browserSettings: {
allowPopupsForUserEvents: getSettingsAPI(
extension, "allowPopupsForUserEvents",
extension.id, "allowPopupsForUserEvents",
() => {
return Services.prefs.getCharPref("dom.popup_allowed_events") != "";
}),
cacheEnabled: getSettingsAPI(
extension, "cacheEnabled",
extension.id, "cacheEnabled",
() => {
return Services.prefs.getBoolPref("browser.cache.disk.enable") &&
Services.prefs.getBoolPref("browser.cache.memory.enable");
}),
closeTabsByDoubleClick: getSettingsAPI(
extension, "closeTabsByDoubleClick",
extension.id, "closeTabsByDoubleClick",
() => {
return Services.prefs.getBoolPref("browser.tabs.closeTabByDblclick");
}, undefined, false, ["android"]),
}, undefined, false, () => {
if (AppConstants.platform == "android") {
throw new ExtensionError(
`android is not a supported platform for the closeTabsByDoubleClick setting.`);
}
}),
contextMenuShowEvent: Object.assign(
getSettingsAPI(
extension, "contextMenuShowEvent",
extension.id, "contextMenuShowEvent",
() => {
if (AppConstants.platform === "win") {
return "mouseup";
@ -305,18 +215,18 @@ this.browserSettings = class extends ExtensionAPI {
}
),
homepageOverride: getSettingsAPI(
extension, HOMEPAGE_OVERRIDE_SETTING,
extension.id, HOMEPAGE_OVERRIDE_SETTING,
() => {
return Services.prefs.getComplexValue(
HOMEPAGE_URL_PREF, Ci.nsIPrefLocalizedString).data;
}, undefined, true),
imageAnimationBehavior: getSettingsAPI(
extension, "imageAnimationBehavior",
extension.id, "imageAnimationBehavior",
() => {
return Services.prefs.getCharPref("image.animation_mode");
}),
newTabPosition: getSettingsAPI(
extension, "newTabPosition",
extension.id, "newTabPosition",
() => {
if (Services.prefs.getBoolPref("browser.tabs.insertAfterCurrent")) {
return "afterCurrent";
@ -327,124 +237,27 @@ this.browserSettings = class extends ExtensionAPI {
return "atEnd";
}),
newTabPageOverride: getSettingsAPI(
extension, NEW_TAB_OVERRIDE_SETTING,
extension.id, NEW_TAB_OVERRIDE_SETTING,
() => {
return aboutNewTabService.newTabURL;
}, URL_STORE_TYPE, true),
openBookmarksInNewTabs: getSettingsAPI(
extension, "openBookmarksInNewTabs",
extension.id, "openBookmarksInNewTabs",
() => {
return Services.prefs.getBoolPref("browser.tabs.loadBookmarksInTabs");
}),
openSearchResultsInNewTabs: getSettingsAPI(
extension, "openSearchResultsInNewTabs",
extension.id, "openSearchResultsInNewTabs",
() => {
return Services.prefs.getBoolPref("browser.search.openintab");
}),
openUrlbarResultsInNewTabs: getSettingsAPI(
extension, "openUrlbarResultsInNewTabs",
extension.id, "openUrlbarResultsInNewTabs",
() => {
return Services.prefs.getBoolPref("browser.urlbar.openintab");
}),
proxyConfig: Object.assign(
getSettingsAPI(
extension, "proxyConfig",
() => {
let prefValue = Services.prefs.getIntPref("network.proxy.type");
let proxyConfig = {
proxyType:
Array.from(
PROXY_TYPES_MAP.entries()).find(entry => entry[1] === prefValue)[0],
autoConfigUrl: Services.prefs.getCharPref("network.proxy.autoconfig_url"),
autoLogin: Services.prefs.getBoolPref("signon.autologin.proxy"),
proxyDNS: Services.prefs.getBoolPref("network.proxy.socks_remote_dns"),
httpProxyAll: Services.prefs.getBoolPref("network.proxy.share_proxy_settings"),
socksVersion: Services.prefs.getIntPref("network.proxy.socks_version"),
passthrough: Services.prefs.getCharPref("network.proxy.no_proxies_on"),
};
for (let prop of ["http", "ftp", "ssl", "socks"]) {
let host = Services.prefs.getCharPref(`network.proxy.${prop}`);
let port = Services.prefs.getIntPref(`network.proxy.${prop}_port`);
proxyConfig[prop] = port ? `${host}:${port}` : host;
}
return proxyConfig;
},
// proxyConfig is unsupported on android.
undefined, false, ["android"]
),
{
set: details => {
if (AppConstants.platform === "android") {
throw new ExtensionError(
"proxyConfig is not supported on android.");
}
if (!Services.policies.isAllowed("changeProxySettings")) {
throw new ExtensionError(
"Proxy settings are being managed by the Policies manager.");
}
let value = details.value;
if (!PROXY_TYPES_MAP.has(value.proxyType)) {
throw new ExtensionError(
`${value.proxyType} is not a valid value for proxyType.`);
}
if (value.httpProxyAll) {
// Match what about:preferences does with proxy settings
// since the proxy service does not check the value
// of share_proxy_settings.
for (let prop of ["ftp", "ssl", "socks"]) {
value[prop] = value.http;
}
}
for (let prop of ["http", "ftp", "ssl", "socks"]) {
let host = value[prop];
if (host) {
try {
// Fixup in case a full url is passed.
if (host.includes("://")) {
value[prop] = new URL(host).host;
} else {
// Validate the host value.
new URL(`http://${host}`);
}
} catch (e) {
throw new ExtensionError(
`${value[prop]} is not a valid value for ${prop}.`);
}
}
}
if (value.proxyType === "autoConfig" || value.autoConfigUrl) {
try {
new URL(value.autoConfigUrl);
} catch (e) {
throw new ExtensionError(
`${value.autoConfigUrl} is not a valid value for autoConfigUrl.`);
}
}
if (value.socksVersion !== undefined) {
if (!Number.isInteger(value.socksVersion) ||
value.socksVersion < 4 ||
value.socksVersion > 5) {
throw new ExtensionError(
`${value.socksVersion} is not a valid value for socksVersion.`);
}
}
return ExtensionPreferencesManager.setSetting(
extension.id, "proxyConfig", value);
},
}
),
webNotificationsDisabled: getSettingsAPI(
extension, "webNotificationsDisabled",
extension.id, "webNotificationsDisabled",
() => {
let prefValue =
Services.prefs.getIntPref(
@ -453,7 +266,7 @@ this.browserSettings = class extends ExtensionAPI {
}),
overrideDocumentColors: Object.assign(
getSettingsAPI(
extension, "overrideDocumentColors",
extension.id, "overrideDocumentColors",
() => {
let prefValue = Services.prefs.getIntPref("browser.display.document_color_use");
if (prefValue === 1) {
@ -483,7 +296,7 @@ this.browserSettings = class extends ExtensionAPI {
),
useDocumentFonts: Object.assign(
getSettingsAPI(
extension, "useDocumentFonts",
extension.id, "useDocumentFonts",
() => {
return Services.prefs.getIntPref("browser.display.use_document_fonts") !== 0;
}

Просмотреть файл

@ -10,10 +10,74 @@ ChromeUtils.defineModuleGetter(this, "ProxyScriptContext",
"resource://gre/modules/ProxyScriptContext.jsm");
ChromeUtils.defineModuleGetter(this, "ProxyChannelFilter",
"resource://gre/modules/ProxyScriptContext.jsm");
ChromeUtils.import("resource://gre/modules/ExtensionPreferencesManager.jsm");
var {
ExtensionError,
} = ExtensionUtils;
var {
getSettingsAPI,
} = ExtensionPreferencesManager;
// WeakMap[Extension -> ProxyScriptContext]
const proxyScriptContextMap = new WeakMap();
const proxySvc = Ci.nsIProtocolProxyService;
const PROXY_TYPES_MAP = new Map([
["none", proxySvc.PROXYCONFIG_DIRECT],
["autoDetect", proxySvc.PROXYCONFIG_WPAD],
["system", proxySvc.PROXYCONFIG_SYSTEM],
["manual", proxySvc.PROXYCONFIG_MANUAL],
["autoConfig", proxySvc.PROXYCONFIG_PAC],
]);
ExtensionPreferencesManager.addSetting("proxy.settings", {
prefNames: [
"network.proxy.type",
"network.proxy.http",
"network.proxy.http_port",
"network.proxy.share_proxy_settings",
"network.proxy.ftp",
"network.proxy.ftp_port",
"network.proxy.ssl",
"network.proxy.ssl_port",
"network.proxy.socks",
"network.proxy.socks_port",
"network.proxy.socks_version",
"network.proxy.socks_remote_dns",
"network.proxy.no_proxies_on",
"network.proxy.autoconfig_url",
"signon.autologin.proxy",
],
setCallback(value) {
let prefs = {
"network.proxy.type": PROXY_TYPES_MAP.get(value.proxyType),
"signon.autologin.proxy": value.autoLogin,
"network.proxy.socks_remote_dns": value.proxyDNS,
"network.proxy.autoconfig_url": value.autoConfigUrl,
"network.proxy.share_proxy_settings": value.httpProxyAll,
"network.proxy.socks_version": value.socksVersion,
"network.proxy.no_proxies_on": value.passthrough,
};
for (let prop of ["http", "ftp", "ssl", "socks"]) {
if (value[prop]) {
let url = new URL(`http://${value[prop]}`);
prefs[`network.proxy.${prop}`] = url.hostname;
let port = parseInt(url.port, 10);
prefs[`network.proxy.${prop}_port`] = isNaN(port) ? 0 : port;
} else {
prefs[`network.proxy.${prop}`] = undefined;
prefs[`network.proxy.${prop}_port`] = undefined;
}
}
return prefs;
},
});
// EventManager-like class specifically for Proxy filters. Inherits from
// EventManager. Takes care of converting |details| parameter
// when invoking listeners.
@ -104,6 +168,109 @@ this.proxy = class extends ExtensionAPI {
// TODO Bug 1388619 deprecate onProxyError.
onProxyError: onError,
settings: Object.assign(
getSettingsAPI(
extension.id, "proxy.settings",
() => {
let prefValue = Services.prefs.getIntPref("network.proxy.type");
let proxyConfig = {
proxyType:
Array.from(
PROXY_TYPES_MAP.entries()).find(entry => entry[1] === prefValue)[0],
autoConfigUrl: Services.prefs.getCharPref("network.proxy.autoconfig_url"),
autoLogin: Services.prefs.getBoolPref("signon.autologin.proxy"),
proxyDNS: Services.prefs.getBoolPref("network.proxy.socks_remote_dns"),
httpProxyAll: Services.prefs.getBoolPref("network.proxy.share_proxy_settings"),
socksVersion: Services.prefs.getIntPref("network.proxy.socks_version"),
passthrough: Services.prefs.getCharPref("network.proxy.no_proxies_on"),
};
for (let prop of ["http", "ftp", "ssl", "socks"]) {
let host = Services.prefs.getCharPref(`network.proxy.${prop}`);
let port = Services.prefs.getIntPref(`network.proxy.${prop}_port`);
proxyConfig[prop] = port ? `${host}:${port}` : host;
}
return proxyConfig;
},
// proxy.settings is unsupported on android.
undefined, false, () => {
if (AppConstants.platform == "android") {
throw new ExtensionError(
`proxy.settings is not supported on android.`);
}
},
),
{
set: details => {
if (AppConstants.platform === "android") {
throw new ExtensionError(
"proxy.settings is not supported on android.");
}
if (!Services.policies.isAllowed("changeProxySettings")) {
throw new ExtensionError(
"Proxy settings are being managed by the Policies manager.");
}
let value = details.value;
if (!PROXY_TYPES_MAP.has(value.proxyType)) {
throw new ExtensionError(
`${value.proxyType} is not a valid value for proxyType.`);
}
if (value.httpProxyAll) {
// Match what about:preferences does with proxy settings
// since the proxy service does not check the value
// of share_proxy_settings.
for (let prop of ["ftp", "ssl", "socks"]) {
value[prop] = value.http;
}
}
for (let prop of ["http", "ftp", "ssl", "socks"]) {
let host = value[prop];
if (host) {
try {
// Fixup in case a full url is passed.
if (host.includes("://")) {
value[prop] = new URL(host).host;
} else {
// Validate the host value.
new URL(`http://${host}`);
}
} catch (e) {
throw new ExtensionError(
`${value[prop]} is not a valid value for ${prop}.`);
}
}
}
if (value.proxyType === "autoConfig" || value.autoConfigUrl) {
try {
new URL(value.autoConfigUrl);
} catch (e) {
throw new ExtensionError(
`${value.autoConfigUrl} is not a valid value for autoConfigUrl.`);
}
}
if (value.socksVersion !== undefined) {
if (!Number.isInteger(value.socksVersion) ||
value.socksVersion < 4 ||
value.socksVersion > 5) {
throw new ExtensionError(
`${value.socksVersion} is not a valid value for socksVersion.`);
}
}
return ExtensionPreferencesManager.setSetting(
extension.id, "proxy.settings", value);
},
}
),
},
};
}

Просмотреть файл

@ -35,77 +35,6 @@
"type": "string",
"enum": ["mouseup", "mousedown"],
"description": "After which mouse event context menus should popup."
},
{
"id": "ProxyConfig",
"type": "object",
"description": "An object which describes proxy settings.",
"properties": {
"proxyType": {
"type": "string",
"optional": true,
"enum": [
"none",
"autoDetect",
"system",
"manual",
"autoConfig"
],
"description": "The type of proxy to use."
},
"http": {
"type": "string",
"optional": true,
"description": "The address of the http proxy, can include a port."
},
"httpProxyAll":{
"type": "boolean",
"optional": true,
"description": "Use the http proxy server for all protocols."
},
"ftp": {
"type": "string",
"optional": true,
"description": "The address of the ftp proxy, can include a port."
},
"ssl": {
"type": "string",
"optional": true,
"description": "The address of the ssl proxy, can include a port."
},
"socks": {
"type": "string",
"optional": true,
"description": "The address of the socks proxy, can include a port."
},
"socksVersion": {
"type": "integer",
"optional": true,
"description": "The version of the socks proxy.",
"minimum": 4,
"maximum": 5
},
"passthrough": {
"type": "string",
"optional": true,
"description": "A list of hosts which should not be proxied."
},
"autoConfigUrl": {
"type": "string",
"optional": true,
"description": "A URL to use to configure the proxy."
},
"autoLogin": {
"type": "boolean",
"optional": true,
"description": "Do not prompt for authentication if password is saved."
},
"proxyDNS": {
"type": "boolean",
"optional": true,
"description": "Proxy DNS when using SOCKS v5."
}
}
}
],
"properties": {
@ -153,10 +82,6 @@
"$ref": "types.Setting",
"description": "This boolean setting controls whether urlbar results are opened in the current tab or in a new tab."
},
"proxyConfig": {
"$ref": "types.Setting",
"description": "Configures proxy settings. This setting's value is an object of type ProxyConfig."
},
"webNotificationsDisabled": {
"$ref": "types.Setting",
"description": "Disables webAPI notifications."

Просмотреть файл

@ -17,6 +17,85 @@
"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.",
"permissions": ["proxy"],
"types": [
{
"id": "ProxyConfig",
"type": "object",
"description": "An object which describes proxy settings.",
"properties": {
"proxyType": {
"type": "string",
"optional": true,
"enum": [
"none",
"autoDetect",
"system",
"manual",
"autoConfig"
],
"description": "The type of proxy to use."
},
"http": {
"type": "string",
"optional": true,
"description": "The address of the http proxy, can include a port."
},
"httpProxyAll":{
"type": "boolean",
"optional": true,
"description": "Use the http proxy server for all protocols."
},
"ftp": {
"type": "string",
"optional": true,
"description": "The address of the ftp proxy, can include a port."
},
"ssl": {
"type": "string",
"optional": true,
"description": "The address of the ssl proxy, can include a port."
},
"socks": {
"type": "string",
"optional": true,
"description": "The address of the socks proxy, can include a port."
},
"socksVersion": {
"type": "integer",
"optional": true,
"description": "The version of the socks proxy.",
"minimum": 4,
"maximum": 5
},
"passthrough": {
"type": "string",
"optional": true,
"description": "A list of hosts which should not be proxied."
},
"autoConfigUrl": {
"type": "string",
"optional": true,
"description": "A URL to use to configure the proxy."
},
"autoLogin": {
"type": "boolean",
"optional": true,
"description": "Do not prompt for authentication if password is saved."
},
"proxyDNS": {
"type": "boolean",
"optional": true,
"description": "Proxy DNS when using SOCKS v5."
}
}
}
],
"properties": {
"settings": {
"$ref": "types.Setting",
"description": "Configures proxy settings. This setting's value is an object of type ProxyConfig."
}
},
"functions": [
{
"name": "register",

Просмотреть файл

@ -16,7 +16,6 @@ AddonTestUtils.init(this);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
add_task(async function test_browser_settings() {
const proxySvc = Ci.nsIProtocolProxyService;
const PERM_DENY_ACTION = Services.perms.DENY_ACTION;
const PERM_UNKNOWN_ACTION = Services.perms.UNKNOWN_ACTION;
@ -31,21 +30,6 @@ add_task(async function test_browser_settings() {
"browser.tabs.closeTabByDblclick": false,
"browser.tabs.loadBookmarksInTabs": false,
"browser.search.openintab": false,
"network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
"network.proxy.http": "",
"network.proxy.http_port": 0,
"network.proxy.share_proxy_settings": false,
"network.proxy.ftp": "",
"network.proxy.ftp_port": 0,
"network.proxy.ssl": "",
"network.proxy.ssl_port": 0,
"network.proxy.socks": "",
"network.proxy.socks_port": 0,
"network.proxy.socks_version": 5,
"network.proxy.socks_remote_dns": false,
"network.proxy.no_proxies_on": "localhost, 127.0.0.1",
"network.proxy.autoconfig_url": "",
"signon.autologin.proxy": false,
"browser.tabs.insertRelatedAfterCurrent": true,
"browser.tabs.insertAfterCurrent": false,
"browser.display.document_color_use": 1,
@ -233,175 +217,6 @@ add_task(async function test_browser_settings() {
"useDocumentFonts", true,
{"browser.display.use_document_fonts": 1});
async function testProxy(config, expectedPrefs, expectedConfig = config) {
// proxyConfig is not supported on Android.
if (AppConstants.platform === "android") {
return Promise.resolve();
}
let proxyConfig = {
proxyType: "none",
autoConfigUrl: "",
autoLogin: false,
proxyDNS: false,
httpProxyAll: false,
socksVersion: 5,
passthrough: "localhost, 127.0.0.1",
http: "",
ftp: "",
ssl: "",
socks: "",
};
return testSetting(
"proxyConfig", config, expectedPrefs, Object.assign(proxyConfig, expectedConfig)
);
}
await testProxy(
{proxyType: "none"},
{"network.proxy.type": proxySvc.PROXYCONFIG_DIRECT},
);
await testProxy(
{
proxyType: "autoDetect",
autoLogin: true,
proxyDNS: true,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_WPAD,
"signon.autologin.proxy": true,
"network.proxy.socks_remote_dns": true,
},
);
await testProxy(
{
proxyType: "system",
autoLogin: false,
proxyDNS: false,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
"signon.autologin.proxy": false,
"network.proxy.socks_remote_dns": false,
},
);
await testProxy(
{
proxyType: "autoConfig",
autoConfigUrl: "http://mozilla.org",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_PAC,
"network.proxy.autoconfig_url": "http://mozilla.org",
},
);
await testProxy(
{
proxyType: "manual",
http: "http://www.mozilla.org",
autoConfigUrl: "",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 0,
"network.proxy.autoconfig_url": "",
},
{
proxyType: "manual",
http: "www.mozilla.org",
autoConfigUrl: "",
}
);
// When using proxyAll, we expect all proxies to be set to
// be the same as http.
await testProxy(
{
proxyType: "manual",
http: "http://www.mozilla.org:8080",
ftp: "http://www.mozilla.org:1234",
httpProxyAll: true,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 8080,
"network.proxy.ftp": "www.mozilla.org",
"network.proxy.ftp_port": 8080,
"network.proxy.ssl": "www.mozilla.org",
"network.proxy.ssl_port": 8080,
"network.proxy.socks": "www.mozilla.org",
"network.proxy.socks_port": 8080,
"network.proxy.share_proxy_settings": true,
},
{
proxyType: "manual",
http: "www.mozilla.org:8080",
ftp: "www.mozilla.org:8080",
ssl: "www.mozilla.org:8080",
socks: "www.mozilla.org:8080",
httpProxyAll: true,
}
);
await testProxy(
{
proxyType: "manual",
http: "www.mozilla.org:8080",
httpProxyAll: false,
ftp: "www.mozilla.org:8081",
ssl: "www.mozilla.org:8082",
socks: "mozilla.org:8083",
socksVersion: 4,
passthrough: ".mozilla.org",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 8080,
"network.proxy.share_proxy_settings": false,
"network.proxy.ftp": "www.mozilla.org",
"network.proxy.ftp_port": 8081,
"network.proxy.ssl": "www.mozilla.org",
"network.proxy.ssl_port": 8082,
"network.proxy.socks": "mozilla.org",
"network.proxy.socks_port": 8083,
"network.proxy.socks_version": 4,
"network.proxy.no_proxies_on": ".mozilla.org",
}
);
// Test resetting values.
await testProxy(
{
proxyType: "none",
http: "",
ftp: "",
ssl: "",
socks: "",
socksVersion: 5,
passthrough: "",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_DIRECT,
"network.proxy.http": "",
"network.proxy.http_port": 0,
"network.proxy.ftp": "",
"network.proxy.ftp_port": 0,
"network.proxy.ssl": "",
"network.proxy.ssl_port": 0,
"network.proxy.socks": "",
"network.proxy.socks_port": 0,
"network.proxy.socks_version": 5,
"network.proxy.no_proxies_on": "",
}
);
await extension.unload();
await promiseShutdownManager();
});
@ -473,79 +288,3 @@ add_task(async function test_bad_value_android() {
await extension.awaitMessage("done");
await extension.unload();
});
add_task(async function test_bad_value_proxy_config() {
let background = AppConstants.platform === "android" ?
async () => {
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "none",
}}),
/proxyConfig is not supported on android/,
"proxyConfig.set rejects on Android.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.get({}),
/android is not a supported platform for the proxyConfig setting/,
"proxyConfig.get rejects on Android.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.clear({}),
/android is not a supported platform for the proxyConfig setting/,
"proxyConfig.clear rejects on Android.");
browser.test.sendMessage("done");
} :
async () => {
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "abc",
}}),
/abc is not a valid value for proxyType/,
"proxyConfig.set rejects with an invalid proxyType value.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "autoConfig",
}}),
/undefined is not a valid value for autoConfigUrl/,
"proxyConfig.set for type autoConfig rejects with an empty autoConfigUrl value.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "autoConfig",
autoConfigUrl: "abc",
}}),
/abc is not a valid value for autoConfigUrl/,
"proxyConfig.set rejects with an invalid autoConfigUrl value.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "manual",
socksVersion: "abc",
}}),
/abc is not a valid value for socksVersion/,
"proxyConfig.set rejects with an invalid socksVersion value.");
await browser.test.assertRejects(
browser.browserSettings.proxyConfig.set({value: {
proxyType: "manual",
socksVersion: 3,
}}),
/3 is not a valid value for socksVersion/,
"proxyConfig.set rejects with an invalid socksVersion value.");
browser.test.sendMessage("done");
};
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["browserSettings"],
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});

Просмотреть файл

@ -0,0 +1,336 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
ChromeUtils.defineModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
const {
createAppInfo,
promiseShutdownManager,
promiseStartupManager,
} = AddonTestUtils;
AddonTestUtils.init(this);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
add_task(async function test_browser_settings() {
const proxySvc = Ci.nsIProtocolProxyService;
// Create an object to hold the values to which we will initialize the prefs.
const PREFS = {
"network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
"network.proxy.http": "",
"network.proxy.http_port": 0,
"network.proxy.share_proxy_settings": false,
"network.proxy.ftp": "",
"network.proxy.ftp_port": 0,
"network.proxy.ssl": "",
"network.proxy.ssl_port": 0,
"network.proxy.socks": "",
"network.proxy.socks_port": 0,
"network.proxy.socks_version": 5,
"network.proxy.socks_remote_dns": false,
"network.proxy.no_proxies_on": "localhost, 127.0.0.1",
"network.proxy.autoconfig_url": "",
"signon.autologin.proxy": false,
};
async function background() {
browser.test.onMessage.addListener(async (msg, value) => {
let apiObj = browser.proxy.settings;
let result = await apiObj.set({value});
if (msg === "set") {
browser.test.assertTrue(result, "set returns true.");
browser.test.sendMessage("settingData", await apiObj.get({}));
} else {
browser.test.assertFalse(result, "set returns false for a no-op.");
browser.test.sendMessage("no-op set");
}
});
}
// Set prefs to our initial values.
for (let pref in PREFS) {
Preferences.set(pref, PREFS[pref]);
}
registerCleanupFunction(() => {
// Reset the prefs.
for (let pref in PREFS) {
Preferences.reset(pref);
}
});
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["proxy"],
},
useAddonManager: "temporary",
});
await promiseStartupManager();
await extension.startup();
async function testSetting(value, expected, expectedValue = value) {
extension.sendMessage("set", value);
let data = await extension.awaitMessage("settingData");
deepEqual(data.value, expectedValue,
`The setting has the expected value.`);
equal(data.levelOfControl, "controlled_by_this_extension",
`The setting has the expected levelOfControl.`);
for (let pref in expected) {
equal(Preferences.get(pref), expected[pref], `${pref} set correctly for ${value}`);
}
}
async function testProxy(config, expectedPrefs, expectedConfig = config) {
// proxy.settings is not supported on Android.
if (AppConstants.platform === "android") {
return Promise.resolve();
}
let proxyConfig = {
proxyType: "none",
autoConfigUrl: "",
autoLogin: false,
proxyDNS: false,
httpProxyAll: false,
socksVersion: 5,
passthrough: "localhost, 127.0.0.1",
http: "",
ftp: "",
ssl: "",
socks: "",
};
return testSetting(
config, expectedPrefs, Object.assign(proxyConfig, expectedConfig)
);
}
await testProxy(
{proxyType: "none"},
{"network.proxy.type": proxySvc.PROXYCONFIG_DIRECT},
);
await testProxy(
{
proxyType: "autoDetect",
autoLogin: true,
proxyDNS: true,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_WPAD,
"signon.autologin.proxy": true,
"network.proxy.socks_remote_dns": true,
},
);
await testProxy(
{
proxyType: "system",
autoLogin: false,
proxyDNS: false,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
"signon.autologin.proxy": false,
"network.proxy.socks_remote_dns": false,
},
);
await testProxy(
{
proxyType: "autoConfig",
autoConfigUrl: "http://mozilla.org",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_PAC,
"network.proxy.autoconfig_url": "http://mozilla.org",
},
);
await testProxy(
{
proxyType: "manual",
http: "http://www.mozilla.org",
autoConfigUrl: "",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 0,
"network.proxy.autoconfig_url": "",
},
{
proxyType: "manual",
http: "www.mozilla.org",
autoConfigUrl: "",
}
);
// When using proxyAll, we expect all proxies to be set to
// be the same as http.
await testProxy(
{
proxyType: "manual",
http: "http://www.mozilla.org:8080",
ftp: "http://www.mozilla.org:1234",
httpProxyAll: true,
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 8080,
"network.proxy.ftp": "www.mozilla.org",
"network.proxy.ftp_port": 8080,
"network.proxy.ssl": "www.mozilla.org",
"network.proxy.ssl_port": 8080,
"network.proxy.socks": "www.mozilla.org",
"network.proxy.socks_port": 8080,
"network.proxy.share_proxy_settings": true,
},
{
proxyType: "manual",
http: "www.mozilla.org:8080",
ftp: "www.mozilla.org:8080",
ssl: "www.mozilla.org:8080",
socks: "www.mozilla.org:8080",
httpProxyAll: true,
}
);
await testProxy(
{
proxyType: "manual",
http: "www.mozilla.org:8080",
httpProxyAll: false,
ftp: "www.mozilla.org:8081",
ssl: "www.mozilla.org:8082",
socks: "mozilla.org:8083",
socksVersion: 4,
passthrough: ".mozilla.org",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
"network.proxy.http": "www.mozilla.org",
"network.proxy.http_port": 8080,
"network.proxy.share_proxy_settings": false,
"network.proxy.ftp": "www.mozilla.org",
"network.proxy.ftp_port": 8081,
"network.proxy.ssl": "www.mozilla.org",
"network.proxy.ssl_port": 8082,
"network.proxy.socks": "mozilla.org",
"network.proxy.socks_port": 8083,
"network.proxy.socks_version": 4,
"network.proxy.no_proxies_on": ".mozilla.org",
}
);
// Test resetting values.
await testProxy(
{
proxyType: "none",
http: "",
ftp: "",
ssl: "",
socks: "",
socksVersion: 5,
passthrough: "",
},
{
"network.proxy.type": proxySvc.PROXYCONFIG_DIRECT,
"network.proxy.http": "",
"network.proxy.http_port": 0,
"network.proxy.ftp": "",
"network.proxy.ftp_port": 0,
"network.proxy.ssl": "",
"network.proxy.ssl_port": 0,
"network.proxy.socks": "",
"network.proxy.socks_port": 0,
"network.proxy.socks_version": 5,
"network.proxy.no_proxies_on": "",
}
);
await extension.unload();
await promiseShutdownManager();
});
add_task(async function test_bad_value_proxy_config() {
let background = AppConstants.platform === "android" ?
async () => {
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "none",
}}),
/proxy.settings is not supported on android/,
"proxy.settings.set rejects on Android.");
await browser.test.assertRejects(
browser.proxy.settings.get({}),
/proxy.settings is not supported on android/,
"proxy.settings.get rejects on Android.");
await browser.test.assertRejects(
browser.proxy.settings.clear({}),
/proxy.settings is not supported on android/,
"proxy.settings.clear rejects on Android.");
browser.test.sendMessage("done");
} :
async () => {
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "abc",
}}),
/abc is not a valid value for proxyType/,
"proxy.settings.set rejects with an invalid proxyType value.");
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "autoConfig",
}}),
/undefined is not a valid value for autoConfigUrl/,
"proxy.settings.set for type autoConfig rejects with an empty autoConfigUrl value.");
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "autoConfig",
autoConfigUrl: "abc",
}}),
/abc is not a valid value for autoConfigUrl/,
"proxy.settings.set rejects with an invalid autoConfigUrl value.");
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "manual",
socksVersion: "abc",
}}),
/abc is not a valid value for socksVersion/,
"proxy.settings.set rejects with an invalid socksVersion value.");
await browser.test.assertRejects(
browser.proxy.settings.set({value: {
proxyType: "manual",
socksVersion: 3,
}}),
/3 is not a valid value for socksVersion/,
"proxy.settings.set rejects with an invalid socksVersion value.");
browser.test.sendMessage("done");
};
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["proxy"],
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});

Просмотреть файл

@ -44,7 +44,7 @@ add_task(async function test_proxy_settings() {
}, {urls: ["http://example.com/*"]});
// Wait for the settings before testing a request.
await browser.browserSettings.proxyConfig.set({value: {
await browser.proxy.settings.set({value: {
proxyType: "manual",
http: `${host}:${port}`,
}});
@ -53,10 +53,10 @@ add_task(async function test_proxy_settings() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
applications: {gecko: {id: "proxy.settings@mochi.test"}},
permissions: [
"proxy",
"webRequest",
"browserSettings",
"<all_urls>",
],
},

Просмотреть файл

@ -66,6 +66,7 @@ skip-if = true # This test no longer tests what it is meant to test.
[test_ext_privacy_disable.js]
[test_ext_privacy_update.js]
[test_ext_proxy_auth.js]
[test_ext_proxy_config.js]
[test_ext_proxy_onauthrequired.js]
[test_ext_proxy_settings.js]
skip-if = os == "android" # proxy settings are not supported on android