/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Test setting custom user agent. const TEST_DOCUMENT = "target_configuration_test_doc.sjs"; const TEST_URI = URL_ROOT_COM_SSL + TEST_DOCUMENT; add_task(async function () { const tab = await addTab(TEST_URI); info("Create commands for the tab"); const commands = await CommandsFactory.forTab(tab); const targetConfigurationCommand = commands.targetConfigurationCommand; const targetCommand = commands.targetCommand; await targetCommand.startListening(); const initialUserAgent = await getTopLevelUserAgent(); info("Update configuration to change user agent"); const CUSTOM_USER_AGENT = ""; await targetConfigurationCommand.updateConfiguration({ customUserAgent: CUSTOM_USER_AGENT, }); is( await getTopLevelUserAgent(), CUSTOM_USER_AGENT, "The user agent is properly set on the top level document after updating the configuration" ); is( await getUserAgentForTopLevelRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources on the top level document" ); is( await getIframeUserAgent(), CUSTOM_USER_AGENT, "The user agent is properly set on the iframe after updating the configuration" ); is( await getUserAgentForIframeRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources on the iframe" ); info("Reload the page"); await BrowserTestUtils.reloadTab(tab, /* includeSubFrames */ true); is( await getTopLevelDocumentUserAgentAtStartup(), CUSTOM_USER_AGENT, "The custom user agent was set in the content page when it loaded after reloading" ); is( await getTopLevelUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is set in the content page after reloading" ); is( await getUserAgentForTopLevelRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources after reloading" ); is( await getIframeUserAgentAtStartup(), CUSTOM_USER_AGENT, "The custom user agent was set in the remote iframe when it loaded after reloading" ); is( await getIframeUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is set in the remote iframe after reloading" ); is( await getUserAgentForIframeRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources in the remote iframe after reloading" ); const previousBrowsingContextId = gBrowser.selectedBrowser.browsingContext.id; info( "Check that navigating to a page that forces the creation of a new browsing context keep the simulation enabled" ); const onPageLoaded = BrowserTestUtils.browserLoaded( gBrowser.selectedBrowser, /* includeSubFrames */ true ); BrowserTestUtils.loadURIString( gBrowser.selectedBrowser, URL_ROOT_ORG_SSL + TEST_DOCUMENT + "?crossOriginIsolated=true" ); await onPageLoaded; isnot( gBrowser.selectedBrowser.browsingContext.id, previousBrowsingContextId, "A new browsing context was created" ); is( await getTopLevelDocumentUserAgentAtStartup(), CUSTOM_USER_AGENT, "The custom user agent was set in the content page when it loaded after navigating to a new browsing context" ); is( await getTopLevelUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is set in the content page after navigating to a new browsing context" ); is( await getUserAgentForTopLevelRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources after navigating to a new browsing context" ); is( await getIframeUserAgentAtStartup(), CUSTOM_USER_AGENT, "The custom user agent was set in the remote iframe when it loaded after navigating to a new browsing context" ); is( await getIframeUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is set in the remote iframe after navigating to a new browsing context" ); is( await getUserAgentForTopLevelRequest(commands), CUSTOM_USER_AGENT, "The custom user agent is used when retrieving resources in the remote iframes after navigating to a new browsing context" ); info( "Create another commands instance and check that destroying it won't reset the user agent" ); const otherCommands = await CommandsFactory.forTab(tab); const otherTargetConfigurationCommand = otherCommands.targetConfigurationCommand; const otherTargetCommand = otherCommands.targetCommand; await otherTargetCommand.startListening(); // wait for the target to be fully attached to avoid pending connection to the server await otherTargetCommand.watchTargets({ types: [otherTargetCommand.TYPES.FRAME], onAvailable: () => {}, }); // Let's update the configuration with this commands instance to make sure we hit the TargetConfigurationActor await otherTargetConfigurationCommand.updateConfiguration({ colorSchemeSimulation: "dark", }); otherTargetCommand.destroy(); await otherCommands.destroy(); is( await getTopLevelUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is still set on the page after destroying another commands instance" ); info( "Check that destroying the commands we set the user agent in will reset the user agent" ); targetCommand.destroy(); await commands.destroy(); // XXX: This is needed at the moment since Navigator.cpp retrieve the UserAgent from the // headers (when there's no custom user agent). And here, since we reloaded the page once // we set the custom user agent, the header was set accordingly and still holds the custom // user agent value. This should be fixed by Bug 1705326. is( await getTopLevelUserAgent(), CUSTOM_USER_AGENT, "The custom user agent is still set on the page after destroying the first commands instance. Bug 1705326 will fix that and make it equal to `initialUserAgent`" ); await BrowserTestUtils.reloadTab(tab, /* includeSubFrames */ true); is( await getTopLevelUserAgent(), initialUserAgent, "The user agent was reset in the content page after destroying the commands" ); is( await getIframeUserAgent(), initialUserAgent, "The user agent was reset in the remote iframe after destroying the commands" ); // We need commands to retrieve the headers of the network request, and // all those we created so far were destroyed; let's create new ones. const newCommands = await CommandsFactory.forTab(tab); await newCommands.targetCommand.startListening(); is( await getUserAgentForTopLevelRequest(newCommands), initialUserAgent, "The initial user agent is used when retrieving resources after destroying the commands" ); is( await getUserAgentForIframeRequest(newCommands), initialUserAgent, "The initial user agent is used when retrieving resources on the remote iframe after destroying the commands" ); }); function getUserAgent(browserOrBrowsingContext) { return SpecialPowers.spawn(browserOrBrowsingContext, [], () => { return content.navigator.userAgent; }); } function getUserAgentAtStartup(browserOrBrowsingContext) { return SpecialPowers.spawn( browserOrBrowsingContext, [], () => content.wrappedJSObject.initialUserAgent ); } function getTopLevelUserAgent() { return getUserAgent(gBrowser.selectedBrowser); } function getTopLevelDocumentUserAgentAtStartup() { return getUserAgentAtStartup(gBrowser.selectedBrowser); } function getIframeBrowsingContext() { return SpecialPowers.spawn( gBrowser.selectedBrowser, [], () => content.document.querySelector("iframe").browsingContext ); } async function getIframeUserAgent() { const iframeBC = await getIframeBrowsingContext(); return getUserAgent(iframeBC); } async function getIframeUserAgentAtStartup() { const iframeBC = await getIframeBrowsingContext(); return getUserAgentAtStartup(iframeBC); } async function getRequestUserAgent(commands, browserOrBrowsingContext) { const url = `unknown?${Date.now()}`; // Wait for the resource and its headers to be available const onAvailable = () => {}; let onUpdated; const onResource = new Promise(resolve => { onUpdated = updates => { for (const { resource } of updates) { if (resource.url.includes(url) && resource.requestHeadersAvailable) { resolve(resource); } } }; commands.resourceCommand.watchResources( [commands.resourceCommand.TYPES.NETWORK_EVENT], { onAvailable, onUpdated, ignoreExistingResources: true, } ); }); info(`Fetch ${url}`); SpecialPowers.spawn(browserOrBrowsingContext, [url], innerUrl => { content.fetch(`./${innerUrl}`); }); info("waiting for matching resource…"); const networkResource = await onResource; info("…got resource, retrieve headers"); const packet = { to: networkResource.actor, type: "getRequestHeaders", }; const { headers } = await commands.client.request(packet); commands.resourceCommand.unwatchResources( [commands.resourceCommand.TYPES.NETWORK_EVENT], { onAvailable, onUpdated, ignoreExistingResources: true, } ); return headers.find(header => header.name == "User-Agent")?.value; } async function getUserAgentForTopLevelRequest(commands) { return getRequestUserAgent(commands, gBrowser.selectedBrowser); } async function getUserAgentForIframeRequest(commands) { const iframeBC = await getIframeBrowsingContext(); return getRequestUserAgent(commands, iframeBC); }