diff --git a/toolkit/components/extensions/ProxyScriptContext.jsm b/toolkit/components/extensions/ProxyScriptContext.jsm index 8e2ea2ce5140..a9770eea24ba 100644 --- a/toolkit/components/extensions/ProxyScriptContext.jsm +++ b/toolkit/components/extensions/ProxyScriptContext.jsm @@ -258,12 +258,14 @@ class ProxyChannelFilter { // Copy from WebRequest.jsm with small changes. getRequestData(channel, extraData) { + let originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; let data = { requestId: String(channel.id), url: channel.finalURL, method: channel.method, type: channel.type, fromCache: !!channel.fromCache, + incognito: originAttributes && originAttributes.privateBrowsingId > 0, originUrl: channel.originURL || undefined, documentUrl: channel.documentURL || undefined, diff --git a/toolkit/components/extensions/parent/ext-webRequest.js b/toolkit/components/extensions/parent/ext-webRequest.js index a3293c3bf235..b07dad8c2dc4 100644 --- a/toolkit/components/extensions/parent/ext-webRequest.js +++ b/toolkit/components/extensions/parent/ext-webRequest.js @@ -24,7 +24,9 @@ function registerEvent(extension, eventName, fire, filter, info, remoteTab = nul let event = data.serialize(eventName); event.tabId = browserData.tabId; - + if (data.originAttributes) { + event.incognito = data.originAttributes.privateBrowsingId > 0; + } if (data.registerTraceableChannel) { // If this is a primed listener, no tabParent was passed in here, // but the convert() callback later in this function will be called diff --git a/toolkit/components/extensions/schemas/proxy.json b/toolkit/components/extensions/schemas/proxy.json index b1596de3648b..4ce910e5b0b7 100644 --- a/toolkit/components/extensions/schemas/proxy.json +++ b/toolkit/components/extensions/schemas/proxy.json @@ -147,6 +147,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, diff --git a/toolkit/components/extensions/schemas/web_request.json b/toolkit/components/extensions/schemas/web_request.json index b6d7e311495d..f3c6b2893951 100644 --- a/toolkit/components/extensions/schemas/web_request.json +++ b/toolkit/components/extensions/schemas/web_request.json @@ -425,6 +425,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "requestBody": { @@ -493,6 +494,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -538,6 +540,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -578,6 +581,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -625,6 +629,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -684,6 +689,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -728,6 +734,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -773,6 +780,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, @@ -817,6 +825,7 @@ "method": {"type": "string", "description": "Standard HTTP method."}, "frameId": {"type": "integer", "description": "The value 0 indicates that the request happens in the main frame; a positive value indicates the ID of a subframe in which the request happens. If the document of a (sub-)frame is loaded (type is main_frame or sub_frame), frameId indicates the ID of this frame, not the ID of the outer frame. Frame IDs are unique within a tab."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame which sent the request. Set to -1 if no parent frame exists."}, + "incognito": {"type": "boolean", "optional": true, "description": "True for private browsing requests."}, "originUrl": {"type": "string", "optional": true, "description": "URL of the resource that triggered this request."}, "documentUrl": {"type": "string", "optional": true, "description": "URL of the page into which the requested resource will be loaded."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to -1 if the request isn't related to a tab."}, diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_incognito.js b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_incognito.js index 8762094836d8..f306350e4357 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_incognito.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_webRequest_incognito.js @@ -11,21 +11,41 @@ server.registerPathHandler("/dummy", (request, response) => { add_task(async function test_incognito_webrequest_access() { Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", false); - // This extension will fail if it gets a request + let pb_extension = ExtensionTestUtils.loadExtension({ + incognitoOverride: "spanning", + manifest: { + permissions: ["webRequest", "webRequestBlocking", ""], + }, + background() { + browser.webRequest.onBeforeRequest.addListener(async (details) => { + browser.test.assertTrue(details.incognito, "incognito flag is set"); + browser.test.notifyPass("webRequest.private"); + }, {urls: [""]}, ["blocking"]); + }, + }); + await pb_extension.startup(); + let extension = ExtensionTestUtils.loadExtension({ manifest: { permissions: ["webRequest", "webRequestBlocking", ""], }, background() { browser.webRequest.onBeforeRequest.addListener(async (details) => { - browser.test.fail("webrequest received incognito request"); + browser.test.assertFalse(details.incognito, "incognito flag is not set"); + browser.test.notifyPass("webRequest"); }, {urls: [""]}, ["blocking"]); }, }); + // Load non-incognito extension to check that private requests are invisible to it. await extension.startup(); let contentPage = await ExtensionTestUtils.loadContentPage("http://example.com/dummy", {privateBrowsing: true}); + await pb_extension.awaitFinish("webRequest.private"); + await pb_extension.unload(); + await contentPage.close(); + contentPage = await ExtensionTestUtils.loadContentPage("http://example.com/dummy"); + await extension.awaitFinish("webRequest"); await extension.unload(); await contentPage.close(); diff --git a/toolkit/components/extensions/test/xpcshell/test_proxy_incognito.js b/toolkit/components/extensions/test/xpcshell/test_proxy_incognito.js index 072643605fcc..b7df6b2205f8 100644 --- a/toolkit/components/extensions/test/xpcshell/test_proxy_incognito.js +++ b/toolkit/components/extensions/test/xpcshell/test_proxy_incognito.js @@ -18,14 +18,15 @@ add_task(async function test_incognito_proxy_onRequest_access() { // extension does not have permission. Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", false); - // This extension will fail if it gets a request + // This extension will fail if it gets a private request. let extension = ExtensionTestUtils.loadExtension({ manifest: { permissions: ["proxy", ""], }, async background() { browser.proxy.onRequest.addListener(async (details) => { - browser.test.fail("proxy.onRequest received incognito request"); + browser.test.assertFalse(details.incognito, "incognito flag is not set"); + browser.test.notifyPass("proxy.onRequest"); }, {urls: [""]}); // Actual call arguments do not matter here. @@ -42,7 +43,6 @@ add_task(async function test_incognito_proxy_onRequest_access() { await extension.startup(); await extension.awaitMessage("ready"); - // This extension will succeed if it gets a request let pextension = ExtensionTestUtils.loadExtension({ incognitoOverride: "spanning", manifest: { @@ -50,18 +50,22 @@ add_task(async function test_incognito_proxy_onRequest_access() { }, background() { browser.proxy.onRequest.addListener(async (details) => { - browser.test.notifyPass("proxy.onRequest"); + browser.test.assertTrue(details.incognito, "incognito flag is set"); + browser.test.notifyPass("proxy.onRequest.private"); }, {urls: [""]}); }, }); await pextension.startup(); - let finished = pextension.awaitFinish("proxy.onRequest"); let contentPage = await ExtensionTestUtils.loadContentPage("http://example.com/dummy", {privateBrowsing: true}); - await finished; + await pextension.awaitFinish("proxy.onRequest.private"); + await pextension.unload(); + await contentPage.close(); + + contentPage = await ExtensionTestUtils.loadContentPage("http://example.com/dummy"); + await extension.awaitFinish("proxy.onRequest"); await extension.unload(); - await pextension.unload(); await contentPage.close(); Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault"); diff --git a/toolkit/modules/addons/WebRequest.jsm b/toolkit/modules/addons/WebRequest.jsm index bed5d06fd5e4..4022fd892b87 100644 --- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -664,6 +664,7 @@ HttpObserverManager = { }, getRequestData(channel, extraData) { + let originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; let data = { requestId: String(channel.id), url: channel.finalURL, @@ -671,6 +672,7 @@ HttpObserverManager = { browser: channel.browserElement, type: channel.type, fromCache: channel.fromCache, + originAttributes, originUrl: channel.originURL || undefined, documentUrl: channel.documentURL || undefined,