browser_ProxyPerUserContextManager.js (12330B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { ContextualIdentityListener } = ChromeUtils.importESModule( 8 "chrome://remote/content/shared/listeners/ContextualIdentityListener.sys.mjs" 9 ); 10 11 const { HttpServer } = ChromeUtils.importESModule( 12 "resource://testing-common/httpd.sys.mjs" 13 ); 14 15 // eslint-disable-next-line mozilla/no-redeclare-with-import-autofix 16 const { ProxyConfiguration } = ChromeUtils.importESModule( 17 "chrome://remote/content/shared/webdriver/Capabilities.sys.mjs" 18 ); 19 20 const { ProxyPerUserContextManager } = ChromeUtils.importESModule( 21 "chrome://remote/content/webdriver-bidi/ProxyPerUserContextManager.sys.mjs" 22 ); 23 24 const gOverride = Cc["@mozilla.org/network/native-dns-override;1"].getService( 25 Ci.nsINativeDNSResolverOverride 26 ); 27 28 add_setup(async function () { 29 await SpecialPowers.pushPrefEnv({ 30 set: [["network.proxy.allow_hijacking_localhost", true]], 31 }); 32 gOverride.addIPOverride("test1.example.com", "127.0.0.1"); 33 34 registerCleanupFunction(async () => { 35 gOverride.clearOverrides(); 36 }); 37 }); 38 39 add_task(async function test_manual_http_proxy_per_user_context() { 40 const [serverURL, proxyURL] = createHTTPProxy(); 41 42 const proxyManager = new ProxyPerUserContextManager(); 43 44 const userContext = ContextualIdentityService.create("test_name"); 45 const { userContextId } = userContext; 46 47 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 48 userContextId, 49 }); 50 const browserInUserContext = tabInUserContext.linkedBrowser; 51 52 info("Set up a manual proxy for user context"); 53 const proxyConfiguration = ProxyConfiguration.fromJSON({ 54 proxyType: "manual", 55 httpProxy: proxyURL, 56 }); 57 proxyManager.addConfiguration(userContextId, proxyConfiguration); 58 59 info("Verify that navigation request in user context is proxied"); 60 await isPageProxied(browserInUserContext, serverURL); 61 62 const tabInDefaultUserContext = BrowserTestUtils.addTab(gBrowser, serverURL); 63 const browserInDefaultUserContext = tabInDefaultUserContext.linkedBrowser; 64 65 info("Verify that navigation request in default user context is not proxied"); 66 await isPageNotProxied(browserInDefaultUserContext, serverURL); 67 68 info("Destroy proxy manager"); 69 proxyManager.destroy(); 70 71 info("Verify that navigation request in user context is not proxied"); 72 await isPageNotProxied(browserInUserContext, serverURL); 73 74 BrowserTestUtils.removeTab(tabInUserContext); 75 ContextualIdentityService.remove(userContextId); 76 BrowserTestUtils.removeTab(tabInDefaultUserContext); 77 }); 78 79 add_task(async function test_manual_http_proxy_per_user_context_with_noProxy() { 80 const [serverURL, proxyURL] = createHTTPProxy(); 81 82 const proxyManager = new ProxyPerUserContextManager(); 83 84 const userContext = ContextualIdentityService.create("test_name"); 85 const { userContextId } = userContext; 86 87 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 88 userContextId, 89 }); 90 const browserInUserContext = tabInUserContext.linkedBrowser; 91 92 info("Set up a manual proxy for user context with `noProxy` field"); 93 const proxyConfiguration = ProxyConfiguration.fromJSON({ 94 proxyType: "manual", 95 httpProxy: proxyURL, 96 noProxy: ["test1.example.com"], 97 }); 98 proxyManager.addConfiguration(userContextId, proxyConfiguration); 99 100 info("Verify that navigation request is not proxied"); 101 await isPageNotProxied(browserInUserContext, serverURL); 102 103 proxyManager.destroy(); 104 105 BrowserTestUtils.removeTab(tabInUserContext); 106 ContextualIdentityService.remove(userContextId); 107 }); 108 109 add_task( 110 async function test_manual_http_proxy_per_user_context_with_noProxy_with_url_pattern() { 111 const [serverURL, proxyURL, secondServerURL] = createHTTPProxy(); 112 113 const proxyManager = new ProxyPerUserContextManager(); 114 115 const userContext = ContextualIdentityService.create("test_name"); 116 const { userContextId } = userContext; 117 118 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 119 userContextId, 120 }); 121 const browserInUserContext = tabInUserContext.linkedBrowser; 122 123 info( 124 "Set up a manual proxy for user context with `noProxy` field for an URL pattern" 125 ); 126 const proxyConfiguration = ProxyConfiguration.fromJSON({ 127 proxyType: "manual", 128 httpProxy: proxyURL, 129 noProxy: [".example.com"], 130 }); 131 proxyManager.addConfiguration(userContextId, proxyConfiguration); 132 133 info("Verify that navigation request is not proxied"); 134 await isPageNotProxied(browserInUserContext, serverURL); 135 136 info("Verify that navigation to url not matching the pattern is proxied"); 137 await isPageProxied(browserInUserContext, secondServerURL); 138 139 proxyManager.destroy(); 140 141 BrowserTestUtils.removeTab(tabInUserContext); 142 ContextualIdentityService.remove(userContextId); 143 } 144 ); 145 146 add_task(async function test_override_manual_http_proxy_per_user_context() { 147 const [serverURL, proxyURL] = createHTTPProxy(); 148 149 const proxyManager = new ProxyPerUserContextManager(); 150 151 const userContext = ContextualIdentityService.create("test_name"); 152 const { userContextId } = userContext; 153 154 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 155 userContextId, 156 }); 157 const browserInUserContext = tabInUserContext.linkedBrowser; 158 159 info("Set up a manual proxy for user context"); 160 const proxyConfiguration = ProxyConfiguration.fromJSON({ 161 proxyType: "manual", 162 httpProxy: proxyURL, 163 }); 164 proxyManager.addConfiguration(userContextId, proxyConfiguration); 165 166 info("Verify that navigation request is proxied"); 167 await isPageProxied(browserInUserContext, serverURL); 168 169 info("Set a new proxy configuration for user context with direct proxy"); 170 const newProxyConfiguration = ProxyConfiguration.fromJSON({ 171 proxyType: "direct", 172 }); 173 proxyManager.addConfiguration(userContextId, newProxyConfiguration); 174 175 info("Verify that navigation request is not proxied"); 176 await isPageNotProxied(browserInUserContext, serverURL); 177 178 proxyManager.destroy(); 179 180 BrowserTestUtils.removeTab(tabInUserContext); 181 ContextualIdentityService.remove(userContextId); 182 }); 183 184 add_task( 185 async function test_override_global_manual_proxy_with_direct_proxy_per_user_context() { 186 const [serverURL, proxyURL] = createHTTPProxy(); 187 188 info("Set up a global manual proxy"); 189 const globalProxy = ProxyConfiguration.fromJSON({ 190 proxyType: "manual", 191 httpProxy: proxyURL, 192 }); 193 194 globalProxy.init(); 195 196 const tabInDefaultUserContext = BrowserTestUtils.addTab( 197 gBrowser, 198 serverURL 199 ); 200 const browserInDefaultUserContext = tabInDefaultUserContext.linkedBrowser; 201 202 info("Verify that navigation request is proxied"); 203 await isPageProxied(browserInDefaultUserContext, serverURL); 204 205 const proxyManager = new ProxyPerUserContextManager(); 206 207 const userContext = ContextualIdentityService.create("test_name"); 208 const { userContextId } = userContext; 209 210 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 211 userContextId, 212 }); 213 const browserInUserContext = tabInUserContext.linkedBrowser; 214 215 info("Set up a direct proxy for user context"); 216 const proxyConfiguration = ProxyConfiguration.fromJSON({ 217 proxyType: "direct", 218 }); 219 proxyManager.addConfiguration(userContextId, proxyConfiguration); 220 221 info("Verify that navigation request is not proxied"); 222 await isPageNotProxied(browserInUserContext, serverURL); 223 224 proxyManager.destroy(); 225 226 globalProxy.destroy(); 227 228 BrowserTestUtils.removeTab(tabInUserContext); 229 ContextualIdentityService.remove(userContextId); 230 BrowserTestUtils.removeTab(tabInDefaultUserContext); 231 } 232 ); 233 234 add_task( 235 async function test_override_global_system_proxy_with_direct_proxy_per_user_context() { 236 const [serverURL] = createHTTPProxy(); 237 238 info("Set up a global system proxy"); 239 const globalProxy = ProxyConfiguration.fromJSON({ 240 proxyType: "system", 241 }); 242 243 globalProxy.init(); 244 245 const proxyManager = new ProxyPerUserContextManager(); 246 247 const userContext = ContextualIdentityService.create("test_name"); 248 const { userContextId } = userContext; 249 250 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 251 userContextId, 252 }); 253 const browserInUserContext = tabInUserContext.linkedBrowser; 254 255 info("Set up a direct proxy for user context"); 256 const proxyConfiguration = ProxyConfiguration.fromJSON({ 257 proxyType: "direct", 258 }); 259 260 proxyManager.addConfiguration(userContextId, proxyConfiguration); 261 262 info("Verify that navigation request is not proxied"); 263 await isPageNotProxied(browserInUserContext, serverURL); 264 265 proxyManager.destroy(); 266 267 globalProxy.destroy(); 268 269 BrowserTestUtils.removeTab(tabInUserContext); 270 ContextualIdentityService.remove(userContextId); 271 } 272 ); 273 274 add_task( 275 async function test_delete_configuration_for_manual_http_proxy_per_user_context() { 276 const [serverURL, proxyURL] = createHTTPProxy(); 277 278 const proxyManager = new ProxyPerUserContextManager(); 279 280 const userContext = ContextualIdentityService.create("test_name"); 281 const { userContextId } = userContext; 282 283 const tabInUserContext = BrowserTestUtils.addTab(gBrowser, serverURL, { 284 userContextId, 285 }); 286 const browserInUserContext = tabInUserContext.linkedBrowser; 287 288 info("Set up a manual proxy for user context"); 289 const proxyConfiguration = ProxyConfiguration.fromJSON({ 290 proxyType: "manual", 291 httpProxy: proxyURL, 292 }); 293 proxyManager.addConfiguration(userContextId, proxyConfiguration); 294 295 info("Verify that navigation request is proxied"); 296 await isPageProxied(browserInUserContext, serverURL); 297 298 info("Delete the proxy configuration"); 299 proxyManager.deleteConfiguration(userContextId); 300 301 info("Verify that navigation request is not proxied"); 302 await isPageNotProxied(browserInUserContext, serverURL); 303 304 info("Try to delete the configuration again"); 305 proxyManager.deleteConfiguration(userContextId); 306 307 proxyManager.destroy(); 308 309 BrowserTestUtils.removeTab(tabInUserContext); 310 ContextualIdentityService.remove(userContextId); 311 } 312 ); 313 314 function createHTTPProxy() { 315 const server = new HttpServer(); 316 server.start(-1); 317 server.identity.add("http", "test1.example.com", server.identity.primaryPort); 318 server.identity.add("http", "example.com", server.identity.primaryPort); 319 server.registerPathHandler("/", (request, response) => { 320 response.setStatusLine(request.httpVersion, 200, "OK"); 321 response.setHeader("Content-Type", "text/plain", true); 322 response.write("Not proxied"); 323 }); 324 325 const proxyServer = new HttpServer(); 326 proxyServer.start(-1); 327 proxyServer.identity.add( 328 "http", 329 "test1.example.com", 330 server.identity.primaryPort 331 ); 332 proxyServer.identity.add("http", "example.com", server.identity.primaryPort); 333 proxyServer.registerPathHandler("/", (request, response) => { 334 response.setStatusLine(request.httpVersion, 200, "OK"); 335 response.setHeader("Content-Type", "text/plain", true); 336 response.write("Proxied"); 337 }); 338 339 registerCleanupFunction(async () => { 340 await server.stop(); 341 await proxyServer.stop(); 342 }); 343 344 return [ 345 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 346 `http://test1.example.com:${server.identity.primaryPort}`, 347 `localhost:${proxyServer.identity.primaryPort}`, 348 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 349 `http://example.com:${server.identity.primaryPort}`, 350 ]; 351 } 352 353 async function isPageProxied(browser, url) { 354 await loadPage(browser, url); 355 return SpecialPowers.spawn(browser, [], async () => { 356 Assert.strictEqual( 357 content.document.body.textContent, 358 "Proxied", 359 "The page was proxied" 360 ); 361 }); 362 } 363 364 async function isPageNotProxied(browser, url) { 365 await loadPage(browser, url); 366 return SpecialPowers.spawn(browser, [], async () => { 367 Assert.strictEqual( 368 content.document.body.textContent, 369 "Not proxied", 370 "The page was not proxied" 371 ); 372 }); 373 } 374 375 async function loadPage(browser, url) { 376 const loadedPromise = BrowserTestUtils.browserLoaded(browser); 377 BrowserTestUtils.startLoadingURIString(browser, url); 378 return loadedPromise; 379 }