summaryrefslogtreecommitdiffstats
path: root/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js')
-rw-r--r--devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js249
1 files changed, 249 insertions, 0 deletions
diff --git a/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js b/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js
new file mode 100644
index 0000000000..c5b3e436db
--- /dev/null
+++ b/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js
@@ -0,0 +1,249 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * !! AFTER MOVING OR RENAMING THIS METHOD, UPDATE `EXPECTED` CONSTANTS BELOW !!
+ */
+const createParentProcessRequests = async () => {
+ info("Do some requests from the parent process");
+ // The line:column for `fetch` should be EXPECTED_REQUEST_LINE_1/COL_1
+ await fetch(FETCH_URI);
+
+ const img = new Image();
+ const onLoad = new Promise(r => img.addEventListener("load", r));
+ // The line:column for `img` below should be EXPECTED_REQUEST_LINE_2/COL_2
+ img.src = IMAGE_URI;
+ await onLoad;
+};
+
+const EXPECTED_METHOD_NAME = "createParentProcessRequests";
+const EXPECTED_REQUEST_LINE_1 = 12;
+const EXPECTED_REQUEST_COL_1 = 9;
+const EXPECTED_REQUEST_LINE_2 = 17;
+const EXPECTED_REQUEST_COL_2 = 3;
+
+// Test the ResourceCommand API around NETWORK_EVENT for the parent process
+
+const FETCH_URI = "https://example.com/document-builder.sjs?html=foo";
+// The img.src request gets cached regardless of `devtools.cache.disabled`.
+// Add a random parameter to the request to bypass the cache.
+const uuid = `${Date.now()}-${Math.random()}`;
+const IMAGE_URI = URL_ROOT_SSL + "test_image.png?" + uuid;
+
+add_task(async function testParentProcessRequests() {
+ // The test expects the main process commands instance to receive resources
+ // for content process requests.
+ await pushPref("devtools.browsertoolbox.scope", "everything");
+
+ const commands = await CommandsFactory.forMainProcess();
+ await commands.targetCommand.startListening();
+ const { resourceCommand } = commands;
+
+ const receivedNetworkEvents = [];
+ const receivedStacktraces = [];
+ const onAvailable = resources => {
+ for (const resource of resources) {
+ if (resource.resourceType == resourceCommand.TYPES.NETWORK_EVENT) {
+ receivedNetworkEvents.push(resource);
+ } else if (
+ resource.resourceType == resourceCommand.TYPES.NETWORK_EVENT_STACKTRACE
+ ) {
+ receivedStacktraces.push(resource);
+ }
+ }
+ };
+ const onUpdated = updates => {
+ for (const { resource } of updates) {
+ is(
+ resource.resourceType,
+ resourceCommand.TYPES.NETWORK_EVENT,
+ "Received a network update event resource"
+ );
+ }
+ };
+
+ await resourceCommand.watchResources(
+ [
+ resourceCommand.TYPES.NETWORK_EVENT,
+ resourceCommand.TYPES.NETWORK_EVENT_STACKTRACE,
+ ],
+ {
+ ignoreExistingResources: true,
+ onAvailable,
+ onUpdated,
+ }
+ );
+
+ await createParentProcessRequests();
+
+ const img2 = new Image();
+ img2.src = IMAGE_URI;
+
+ info("Wait for the network events");
+ await waitFor(() => receivedNetworkEvents.length == 3);
+ info("Wait for the network events stack traces");
+ // Note that we aren't getting any stacktrace for the second cached request
+ await waitFor(() => receivedStacktraces.length == 2);
+
+ info("Assert the fetch request");
+ const fetchRequest = receivedNetworkEvents[0];
+ is(
+ fetchRequest.url,
+ FETCH_URI,
+ "The first resource is for the fetch request"
+ );
+ ok(fetchRequest.chromeContext, "The fetch request is privileged");
+
+ const fetchStacktrace = receivedStacktraces[0].lastFrame;
+ is(receivedStacktraces[0].resourceId, fetchRequest.stacktraceResourceId);
+ is(fetchStacktrace.filename, gTestPath);
+ is(fetchStacktrace.lineNumber, EXPECTED_REQUEST_LINE_1);
+ is(fetchStacktrace.columnNumber, EXPECTED_REQUEST_COL_1);
+ is(fetchStacktrace.functionName, EXPECTED_METHOD_NAME);
+ is(fetchStacktrace.asyncCause, null);
+
+ async function getResponseContent(networkEvent) {
+ const packet = {
+ to: networkEvent.actor,
+ type: "getResponseContent",
+ };
+ const response = await commands.client.request(packet);
+ return response.content.text;
+ }
+
+ const fetchContent = await getResponseContent(fetchRequest);
+ is(fetchContent, "foo");
+
+ info("Assert the first image request");
+ const firstImageRequest = receivedNetworkEvents[1];
+ is(
+ firstImageRequest.url,
+ IMAGE_URI,
+ "The second resource is for the first image request"
+ );
+ ok(!firstImageRequest.fromCache, "The first image request isn't cached");
+ ok(firstImageRequest.chromeContext, "The first image request is privileged");
+
+ const firstImageStacktrace = receivedStacktraces[1].lastFrame;
+ is(receivedStacktraces[1].resourceId, firstImageRequest.stacktraceResourceId);
+ is(firstImageStacktrace.filename, gTestPath);
+ is(firstImageStacktrace.lineNumber, EXPECTED_REQUEST_LINE_2);
+ is(firstImageStacktrace.columnNumber, EXPECTED_REQUEST_COL_2);
+ is(firstImageStacktrace.functionName, EXPECTED_METHOD_NAME);
+ is(firstImageStacktrace.asyncCause, null);
+
+ info("Assert the second image request");
+ const secondImageRequest = receivedNetworkEvents[2];
+ is(
+ secondImageRequest.url,
+ IMAGE_URI,
+ "The third resource is for the second image request"
+ );
+ ok(secondImageRequest.fromCache, "The second image request is cached");
+ ok(
+ secondImageRequest.chromeContext,
+ "The second image request is privileged"
+ );
+
+ info(
+ "Open a content page to ensure we also receive request from content processes"
+ );
+ const pageUrl = "https://example.org/document-builder.sjs?html=foo";
+ const requestUrl = "https://example.org/document-builder.sjs?html=bar";
+ const tab = await addTab(pageUrl);
+
+ await waitFor(() => receivedNetworkEvents.length == 4);
+ const tabRequest = receivedNetworkEvents[3];
+ is(tabRequest.url, pageUrl, "The 4th resource is for the tab request");
+ ok(!tabRequest.chromeContext, "The 4th request is content");
+
+ info(
+ "Also spawn a privileged request from the content process, not bound to any WindowGlobal"
+ );
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [requestUrl],
+ async function (uri) {
+ const { NetUtil } = ChromeUtils.importESModule(
+ "resource://gre/modules/NetUtil.sys.mjs"
+ );
+ const channel = NetUtil.newChannel({
+ uri,
+ loadUsingSystemPrincipal: true,
+ });
+ channel.open();
+ }
+ );
+ await removeTab(tab);
+
+ await waitFor(() => receivedNetworkEvents.length == 5);
+ const privilegedContentRequest = receivedNetworkEvents[4];
+ is(
+ privilegedContentRequest.url,
+ requestUrl,
+ "The 5th resource is for the privileged content process request"
+ );
+ ok(privilegedContentRequest.chromeContext, "The 5th request is privileged");
+
+ info("Now focus only on parent process resources");
+ await pushPref("devtools.browsertoolbox.scope", "parent-process");
+
+ info(
+ "Retrigger the two last requests. The tab document request and a privileged request. Both happening in the tab's content process."
+ );
+ const secondTab = await addTab(pageUrl);
+ await SpecialPowers.spawn(
+ secondTab.linkedBrowser,
+ [requestUrl],
+ async function (uri) {
+ const { NetUtil } = ChromeUtils.importESModule(
+ "resource://gre/modules/NetUtil.sys.mjs"
+ );
+ const channel = NetUtil.newChannel({
+ uri,
+ loadUsingSystemPrincipal: true,
+ });
+ channel.open();
+ }
+ );
+
+ await waitFor(() => receivedNetworkEvents.length == 6);
+
+ // nsIHttpChannel doesn't expose any attribute allowing to identify
+ // privileged requests done in content processes.
+ // Thus, preventing us from filtering them out correctly.
+ // Ideally, we would need some new attribute to know from which (content) process
+ // any channel originates from.
+ info(
+ "For now, we are still notified about the privileged content process request"
+ );
+ const secondPrivilegedContentRequest = receivedNetworkEvents[5];
+ is(
+ secondPrivilegedContentRequest.url,
+ requestUrl,
+ "The 6th resource is for the second privileged content process request"
+ );
+ ok(privilegedContentRequest.chromeContext, "The 6th request is privileged");
+
+ // Let some time to receive the tab request if that's not correctly filtered out
+ await wait(1000);
+ is(
+ receivedNetworkEvents.length,
+ 6,
+ "But we don't receive the request for the tab request"
+ );
+
+ await removeTab(secondTab);
+
+ await resourceCommand.unwatchResources(
+ [resourceCommand.TYPES.NETWORK_EVENT],
+ {
+ onAvailable,
+ onUpdated,
+ }
+ );
+
+ await commands.destroy();
+});