From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../test/xpcshell/test_proxy_listener.js | 298 +++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 toolkit/components/extensions/test/xpcshell/test_proxy_listener.js (limited to 'toolkit/components/extensions/test/xpcshell/test_proxy_listener.js') diff --git a/toolkit/components/extensions/test/xpcshell/test_proxy_listener.js b/toolkit/components/extensions/test/xpcshell/test_proxy_listener.js new file mode 100644 index 0000000000..8cc46d45e7 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_proxy_listener.js @@ -0,0 +1,298 @@ +"use strict"; + +XPCOMUtils.defineLazyServiceGetter( + this, + "gProxyService", + "@mozilla.org/network/protocol-proxy-service;1", + "nsIProtocolProxyService" +); + +const TRANSPARENT_PROXY_RESOLVES_HOST = + Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST; + +function getProxyInfo(url = "http://www.mozilla.org/") { + return new Promise((resolve, reject) => { + let channel = NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + }); + + gProxyService.asyncResolve(channel, 0, { + onProxyAvailable(req, uri, pi, status) { + resolve(pi); + }, + }); + }); +} + +const testData = [ + { + // An ExtensionError is thrown for this, but we are unable to catch it as we + // do with the PAC script api. In this case, we expect null for proxyInfo. + proxyInfo: "not_defined", + expected: { + proxyInfo: null, + }, + }, + { + proxyInfo: 1, + expected: { + error: { + message: + "ProxyInfoData: proxyData must be an object or array of objects", + }, + }, + }, + { + proxyInfo: [ + { + type: "socks", + host: "foo.bar", + port: 1080, + username: "johnsmith", + password: "pass123", + proxyDNS: true, + failoverTimeout: 3, + }, + { type: "http", host: "192.168.1.1", port: 3128 }, + { type: "https", host: "192.168.1.2", port: 1121, failoverTimeout: 1 }, + { + type: "socks", + host: "192.168.1.3", + port: 1999, + proxyDNS: true, + username: "mungosantamaria", + password: "foobar", + }, + { type: "direct" }, + ], + expected: { + proxyInfo: { + type: "socks", + host: "foo.bar", + port: 1080, + proxyDNS: true, + username: "johnsmith", + password: "pass123", + failoverTimeout: 3, + failoverProxy: { + host: "192.168.1.1", + port: 3128, + type: "http", + failoverProxy: { + host: "192.168.1.2", + port: 1121, + type: "https", + failoverTimeout: 1, + failoverProxy: { + host: "192.168.1.3", + port: 1999, + type: "socks", + proxyDNS: TRANSPARENT_PROXY_RESOLVES_HOST, + username: "mungosantamaria", + password: "foobar", + failoverProxy: { + type: "direct", + }, + }, + }, + }, + }, + }, + }, +]; + +add_task(async function test_proxy_listener() { + let extensionData = { + manifest: { + permissions: ["proxy", ""], + }, + background() { + // Some tests generate multiple errors, we'll just rely on the first. + let seenError = false; + let proxyInfo; + browser.proxy.onError.addListener(error => { + if (!seenError) { + browser.test.sendMessage("proxy-error-received", error); + seenError = true; + } + }); + + browser.proxy.onRequest.addListener( + details => { + browser.test.log(`onRequest ${JSON.stringify(details)}`); + if (proxyInfo == "not_defined") { + return not_defined; // eslint-disable-line no-undef + } + return proxyInfo; + }, + { urls: [""] } + ); + + browser.test.onMessage.addListener((message, data) => { + if (message === "set-proxy") { + seenError = false; + proxyInfo = data.proxyInfo; + } + }); + + browser.test.sendMessage("ready"); + }, + }; + + let extension = ExtensionTestUtils.loadExtension(extensionData); + await extension.startup(); + await extension.awaitMessage("ready"); + + for (let test of testData) { + extension.sendMessage("set-proxy", test); + let testError = test.expected.error; + let errorWait = testError && extension.awaitMessage("proxy-error-received"); + + let proxyInfo = await getProxyInfo(); + let expectedProxyInfo = test.expected.proxyInfo; + + if (testError) { + info("waiting for error data"); + let error = await errorWait; + equal(error.message, testError.message, "Correct error message received"); + equal(proxyInfo, null, "no proxyInfo received"); + } else if (expectedProxyInfo === null) { + equal(proxyInfo, null, "no proxyInfo received"); + } else { + for ( + let proxyUsed = proxyInfo; + proxyUsed; + proxyUsed = proxyUsed.failoverProxy + ) { + let { + type, + host, + port, + username, + password, + proxyDNS, + failoverTimeout, + } = expectedProxyInfo; + equal(proxyUsed.host, host, `Expected proxy host to be ${host}`); + equal(proxyUsed.port, port || -1, `Expected proxy port to be ${port}`); + equal(proxyUsed.type, type, `Expected proxy type to be ${type}`); + // May be null or undefined depending on use of newProxyInfoWithAuth or newProxyInfo + equal( + proxyUsed.username || "", + username || "", + `Expected proxy username to be ${username}` + ); + equal( + proxyUsed.password || "", + password || "", + `Expected proxy password to be ${password}` + ); + equal( + proxyUsed.flags, + proxyDNS == undefined ? 0 : proxyDNS, + `Expected proxyDNS to be ${proxyDNS}` + ); + // Default timeout is 10 + equal( + proxyUsed.failoverTimeout, + failoverTimeout || 10, + `Expected failoverTimeout to be ${failoverTimeout}` + ); + expectedProxyInfo = expectedProxyInfo.failoverProxy; + } + ok(!expectedProxyInfo, "no left over failoverProxy"); + } + } + + await extension.unload(); +}); + +async function getExtension(expectedProxyInfo) { + function background(proxyInfo) { + browser.test.log( + `testing proxy.onRequest with proxyInfo = ${JSON.stringify(proxyInfo)}` + ); + browser.proxy.onRequest.addListener( + details => { + return proxyInfo; + }, + { urls: [""] } + ); + } + let extensionData = { + manifest: { + permissions: ["proxy", ""], + }, + background: `(${background})(${JSON.stringify(expectedProxyInfo)})`, + }; + let extension = ExtensionTestUtils.loadExtension(extensionData); + await extension.startup(); + return extension; +} + +add_task(async function test_passthrough() { + let ext1 = await getExtension(null); + let ext2 = await getExtension({ host: "1.2.3.4", port: 8888, type: "https" }); + + // Also use a restricted url to test the ability to proxy those. + let proxyInfo = await getProxyInfo("https://addons.mozilla.org/"); + + equal(proxyInfo.host, "1.2.3.4", `second extension won`); + equal(proxyInfo.port, "8888", `second extension won`); + equal(proxyInfo.type, "https", `second extension won`); + + await ext2.unload(); + + proxyInfo = await getProxyInfo(); + equal(proxyInfo, null, `expected no proxy`); + await ext1.unload(); +}); + +add_task(async function test_ftp_disabled() { + let extension = await getExtension({ + host: "1.2.3.4", + port: 8888, + type: "http", + }); + + let proxyInfo = await getProxyInfo("ftp://somewhere.mozilla.org/"); + + equal( + proxyInfo, + null, + `proxy of ftp request is not available when ftp is disabled` + ); + + await extension.unload(); +}); + +add_task(async function test_ws() { + let proxyRequestCount = 0; + let proxy = createHttpServer(); + proxy.registerPathHandler("CONNECT", (request, response) => { + response.setStatusLine(request.httpVersion, 404, "Proxy not found"); + ++proxyRequestCount; + }); + + let extension = await getExtension({ + host: proxy.identity.primaryHost, + port: proxy.identity.primaryPort, + type: "http", + }); + + // We need a page to use the WebSocket constructor, so let's use an extension. + let dummy = ExtensionTestUtils.loadExtension({ + background() { + // The connection will not be upgraded to WebSocket, so it will close. + let ws = new WebSocket("wss://example.net/"); + ws.onclose = () => browser.test.sendMessage("websocket_closed"); + }, + }); + await dummy.startup(); + await dummy.awaitMessage("websocket_closed"); + await dummy.unload(); + + equal(proxyRequestCount, 1, "Expected one proxy request"); + await extension.unload(); +}); -- cgit v1.2.3