mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Backed out 2 changesets (bug 1745761) for failures on test_ext_dnr_without_webrequest.js. CLOSED TREE
Backed out changeset 74b33f61c4d3 (bug 1745761) Backed out changeset 5abe72701c13 (bug 1745761)
This commit is contained in:
parent
3dab68ed84
commit
58a7f7a38f
@ -69,13 +69,6 @@ const gRuleManagers = [];
|
||||
* - allow / allowAllRequests
|
||||
*/
|
||||
|
||||
const lazy = {};
|
||||
ChromeUtils.defineModuleGetter(
|
||||
lazy,
|
||||
"WebRequest",
|
||||
"resource://gre/modules/WebRequest.jsm"
|
||||
);
|
||||
|
||||
// The RuleCondition class represents a rule's "condition" type as described in
|
||||
// schemas/declarative_net_request.json. This class exists to allow the JS
|
||||
// engine to use one Shape for all Rule instances.
|
||||
@ -314,8 +307,8 @@ class RuleValidator {
|
||||
// http(s) URLs can (regardless of extension permissions).
|
||||
// data:-URLs are currently blocked due to bug 1622986.
|
||||
|
||||
// TODO bug 1801870: Implement rule.action.redirect.transform.
|
||||
// TODO bug 1745760: With regexFilter support, implement regexSubstitution.
|
||||
// TODO bug 1745761: With the redirect action, add schema definitions +
|
||||
// implement rule.action.redirect.transform / regexSubstitution.
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -446,17 +439,6 @@ class RequestDetails {
|
||||
: null;
|
||||
}
|
||||
|
||||
static fromChannelWrapper(channel) {
|
||||
return new RequestDetails({
|
||||
requestURI: channel.finalURI,
|
||||
// Note: originURI may be null, if missing or null principal, as desired.
|
||||
initiatorURI: channel.originURI,
|
||||
type: channel.type,
|
||||
method: channel.method.toLowerCase(),
|
||||
tabId: null, // TODO: use getBrowserData to populate.
|
||||
});
|
||||
}
|
||||
|
||||
canExtensionModify(extension) {
|
||||
const policy = extension.policy;
|
||||
return (
|
||||
@ -572,6 +554,9 @@ class RequestEvaluator {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO bug 1745761: when the channel/originAttributes is chosen, use
|
||||
// ruleManager.extension to exclude private requests if needed.
|
||||
|
||||
this.#collectMatchInRuleset(this.ruleManager.sessionRules);
|
||||
this.#collectMatchInRuleset(this.ruleManager.dynamicRules);
|
||||
for (let ruleset of this.ruleManager.enabledStaticRules) {
|
||||
@ -661,15 +646,7 @@ class RequestEvaluator {
|
||||
|
||||
// Check this.req.requestURI:
|
||||
if (cond.urlFilter) {
|
||||
if (
|
||||
!this.#matchesUrlFilter(
|
||||
this.req.requestURI,
|
||||
cond.urlFilter,
|
||||
cond.isUrlFilterCaseSensitive
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// TODO bug 1745759: Check cond.urlFilter + isUrlFilterCaseSensitive
|
||||
} else if (cond.regexFilter) {
|
||||
// TODO bug 1745760: check cond.regexFilter + isUrlFilterCaseSensitive
|
||||
}
|
||||
@ -726,22 +703,6 @@ class RequestEvaluator {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {nsIURI} uri - The request URI.
|
||||
* @param {string} urlFilter
|
||||
* @param {boolean} [isUrlFilterCaseSensitive]
|
||||
* @returns {boolean} Whether urlFilter matches the given uri.
|
||||
*/
|
||||
#matchesUrlFilter(uri, urlFilter, isUrlFilterCaseSensitive) {
|
||||
// TODO bug 1745759: Check cond.urlFilter + isUrlFilterCaseSensitive
|
||||
// Placeholder for unit test until we have a complete implementation.
|
||||
if (urlFilter === "|https:*") {
|
||||
return uri.schemeIs("https");
|
||||
}
|
||||
throw new Error(`urlFilter not implemented yet: ${urlFilter}`);
|
||||
// return true; after all other checks passed.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} domains - A list of canonicalized domain patterns.
|
||||
* Canonical means punycode, no ports, and IPv6 without brackets, and not
|
||||
@ -785,130 +746,6 @@ class RequestEvaluator {
|
||||
}
|
||||
}
|
||||
|
||||
const NetworkIntegration = {
|
||||
register() {
|
||||
// We register via WebRequest.jsm to ensure predictable ordering of DNR and
|
||||
// WebRequest behavior.
|
||||
lazy.WebRequest.setDNRHandlingEnabled(true);
|
||||
},
|
||||
unregister() {
|
||||
lazy.WebRequest.setDNRHandlingEnabled(false);
|
||||
},
|
||||
|
||||
startDNREvaluation(channel) {
|
||||
let ruleManagers = gRuleManagers;
|
||||
if (!channel.canModify) {
|
||||
ruleManagers = [];
|
||||
}
|
||||
if (channel.loadInfo.originAttributes.privateBrowsingId > 0) {
|
||||
ruleManagers = ruleManagers.filter(
|
||||
rm => rm.extension.privateBrowsingAllowed
|
||||
);
|
||||
}
|
||||
let matchedRules;
|
||||
if (ruleManagers.length) {
|
||||
const request = RequestDetails.fromChannelWrapper(channel);
|
||||
matchedRules = RequestEvaluator.evaluateRequest(request, ruleManagers);
|
||||
}
|
||||
// Cache for later. In case of redirects, _dnrMatchedRules may exist for
|
||||
// the pre-redirect HTTP channel, and is overwritten here again.
|
||||
channel._dnrMatchedRules = matchedRules;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies the actions of the DNR rules.
|
||||
*
|
||||
* @param {ChannelWrapper} channel
|
||||
* @returns {boolean} Whether to ignore any responses from the webRequest API.
|
||||
*/
|
||||
onBeforeRequest(channel) {
|
||||
let matchedRules = channel._dnrMatchedRules;
|
||||
if (!matchedRules?.length) {
|
||||
return false;
|
||||
}
|
||||
// If a matched rule closes the channel, it is the sole match.
|
||||
const finalMatch = matchedRules[0];
|
||||
switch (finalMatch.rule.action.type) {
|
||||
case "block":
|
||||
this.applyBlock(channel, finalMatch);
|
||||
return true;
|
||||
case "redirect":
|
||||
this.applyRedirect(channel, finalMatch);
|
||||
return true;
|
||||
case "upgradeScheme":
|
||||
this.applyUpgradeScheme(channel, finalMatch);
|
||||
return true;
|
||||
}
|
||||
// If there are multiple rules, then it may be a combination of allow,
|
||||
// allowAllRequests and/or modifyHeaders.
|
||||
|
||||
// TODO bug 1797403: Apply allowAllRequests actions.
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
onBeforeSendHeaders(channel) {
|
||||
// TODO bug 1797404: apply modifyHeaders actions (requestHeaders).
|
||||
},
|
||||
|
||||
onHeadersReceived(channel) {
|
||||
// TODO bug 1797404: apply modifyHeaders actions (responseHeaders).
|
||||
},
|
||||
|
||||
applyBlock(channel, matchedRule) {
|
||||
// TODO bug 1802259: Consider a DNR-specific reason.
|
||||
channel.cancel(
|
||||
Cr.NS_ERROR_ABORT,
|
||||
Ci.nsILoadInfo.BLOCKING_REASON_EXTENSION_WEBREQUEST
|
||||
);
|
||||
const addonId = matchedRule.ruleManager.extension.id;
|
||||
let properties = channel.channel.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
properties.setProperty("cancelledByExtension", addonId);
|
||||
},
|
||||
|
||||
applyUpgradeScheme(channel, matchedRule) {
|
||||
// Request upgrade. No-op if already secure (i.e. https).
|
||||
channel.upgradeToSecure();
|
||||
},
|
||||
|
||||
applyRedirect(channel, matchedRule) {
|
||||
// Ambiguity resolution order of redirect dict keys, consistent with Chrome:
|
||||
// - url > extensionPath > transform > regexSubstitution
|
||||
const redirect = matchedRule.rule.action.redirect;
|
||||
const extension = matchedRule.ruleManager.extension;
|
||||
let redirectUri;
|
||||
if (redirect.url) {
|
||||
// redirect.url already validated by checkActionRedirect.
|
||||
redirectUri = Services.io.newURI(redirect.url);
|
||||
} else if (redirect.extensionPath) {
|
||||
redirectUri = extension.baseURI
|
||||
.mutate()
|
||||
.setPathQueryRef(redirect.extensionPath)
|
||||
.finalize();
|
||||
} else if (redirect.transform) {
|
||||
// TODO bug 1801870: Implement transform.
|
||||
throw new Error("transform not implemented");
|
||||
} else if (redirect.regexSubstitution) {
|
||||
// TODO bug 1745760: Implement along with regexFilter support.
|
||||
throw new Error("regexSubstitution not implemented");
|
||||
} else {
|
||||
// #checkActionRedirect ensures that the redirect action is non-empty.
|
||||
}
|
||||
|
||||
channel.redirectTo(redirectUri);
|
||||
|
||||
let properties = channel.channel.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
properties.setProperty("redirectedByExtension", extension.id);
|
||||
|
||||
let origin = channel.getRequestHeader("Origin");
|
||||
if (origin) {
|
||||
channel.setResponseHeader("Access-Control-Allow-Origin", origin);
|
||||
channel.setResponseHeader("Access-Control-Allow-Credentials", "true");
|
||||
channel.setResponseHeader("Access-Control-Max-Age", "0");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
class RuleManager {
|
||||
constructor(extension) {
|
||||
this.extension = extension;
|
||||
@ -944,10 +781,6 @@ function getRuleManager(extension, createIfMissing = true) {
|
||||
// instantiate a RuleManager claims the highest priority.
|
||||
// TODO bug 1786059: order extensions by "installation time".
|
||||
gRuleManagers.unshift(ruleManager);
|
||||
if (gRuleManagers.length === 1) {
|
||||
// The first DNR registration.
|
||||
NetworkIntegration.register();
|
||||
}
|
||||
}
|
||||
return ruleManager;
|
||||
}
|
||||
@ -956,10 +789,6 @@ function clearRuleManager(extension) {
|
||||
let i = gRuleManagers.findIndex(rm => rm.extension === extension);
|
||||
if (i !== -1) {
|
||||
gRuleManagers.splice(i, 1);
|
||||
if (gRuleManagers.length === 0) {
|
||||
// The last DNR registration.
|
||||
NetworkIntegration.unregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -980,55 +809,9 @@ function getMatchedRulesForRequest(request, extension) {
|
||||
return RequestEvaluator.evaluateRequest(requestDetails, ruleManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs before any webRequest event is notified. Headers may be modified, but
|
||||
* the request should not be canceled (see handleRequest instead).
|
||||
*
|
||||
* @param {ChannelWrapper} channel
|
||||
* @param {string} kind - The name of the webRequest event.
|
||||
*/
|
||||
function beforeWebRequestEvent(channel, kind) {
|
||||
try {
|
||||
switch (kind) {
|
||||
case "onBeforeRequest":
|
||||
NetworkIntegration.startDNREvaluation(channel);
|
||||
break;
|
||||
case "onBeforeSendHeaders":
|
||||
NetworkIntegration.onBeforeSendHeaders(channel);
|
||||
break;
|
||||
case "onHeadersReceived":
|
||||
NetworkIntegration.onHeadersReceived(channel);
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies matching DNR rules, some of which may potentially cancel the request.
|
||||
*
|
||||
* @param {ChannelWrapper} channel
|
||||
* @param {string} kind - The name of the webRequest event.
|
||||
* @returns {boolean} Whether to ignore any responses from the webRequest API.
|
||||
*/
|
||||
function handleRequest(channel, kind) {
|
||||
try {
|
||||
if (kind === "onBeforeRequest") {
|
||||
return NetworkIntegration.onBeforeRequest(channel);
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export const ExtensionDNR = {
|
||||
RuleValidator,
|
||||
getRuleManager,
|
||||
clearRuleManager,
|
||||
getMatchedRulesForRequest,
|
||||
|
||||
beforeWebRequestEvent,
|
||||
handleRequest,
|
||||
};
|
||||
|
@ -131,7 +131,6 @@ skip-if = os == 'android' || tsan # Times out on TSan intermittently, bug 161518
|
||||
skip-if = os == 'android' # Bug 1513544 Android does not support multiple windows.
|
||||
[test_ext_cookies_permissions_bad.html]
|
||||
[test_ext_cookies_permissions_good.html]
|
||||
[test_ext_dnr_upgradeScheme.html]
|
||||
[test_ext_downloads_download.html]
|
||||
[test_ext_embeddedimg_iframe_frameAncestors.html]
|
||||
[test_ext_exclude_include_globs.html]
|
||||
|
@ -1,120 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DNR with upgradeScheme action</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
// This test is not a xpcshell test, because we want to test upgrades to https,
|
||||
// and HttpServer helper does not support https (bug 1742061).
|
||||
|
||||
add_setup(async () => {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["extensions.manifestV3.enabled", true],
|
||||
["extensions.dnr.enabled", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
// Tests that the upgradeScheme action works as expected:
|
||||
// - http should be upgraded to https
|
||||
// - after the https upgrade the request should happen instead of being stuck
|
||||
// in a upgrade redirect loop.
|
||||
add_task(async function upgradeScheme_with_dnr() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [{ id: 1, condition: {}, action: { type: "upgradeScheme" } }],
|
||||
});
|
||||
|
||||
let res = await fetch(
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
"http://example.com/tests/toolkit/components/extensions/test/mochitest/file_sample.txt"
|
||||
);
|
||||
browser.test.assertEq(
|
||||
"https://example.com/tests/toolkit/components/extensions/test/mochitest/file_sample.txt",
|
||||
res.url,
|
||||
"upgradeScheme should have upgraded to https"
|
||||
);
|
||||
// Server adds "Access-Control-Allow-Origin: *" to file_sample.txt, so
|
||||
// we should be able to read the response despite no host_permissions.
|
||||
browser.test.assertEq("Sample", await res.text(), "read body with CORS");
|
||||
|
||||
browser.test.sendMessage("dnr_registered");
|
||||
},
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
// Note: host_permissions missing. upgradeScheme should not need it.
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("dnr_registered");
|
||||
|
||||
let otherExtension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
let firstRequestPromise = new Promise(resolve => {
|
||||
let count = 0;
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
({ url }) => {
|
||||
++count;
|
||||
browser.test.assertTrue(
|
||||
count <= 2,
|
||||
`Expected at most two requests; got ${count} to ${url}`
|
||||
);
|
||||
resolve(url);
|
||||
},
|
||||
{ urls: ["*://example.com/?test_dnr_upgradeScheme"] }
|
||||
);
|
||||
});
|
||||
// Round-trip through ext-webRequest.js implementation to ensure that the
|
||||
// listener has been registered (workaround for bug 1300234).
|
||||
await browser.webRequest.handlerBehaviorChanged();
|
||||
|
||||
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
||||
const insecureInitialUrl = "http://example.com/?test_dnr_upgradeScheme";
|
||||
browser.test.log(`Requesting insecure URL: ${insecureInitialUrl}`);
|
||||
|
||||
let req = await fetch(insecureInitialUrl);
|
||||
browser.test.assertEq(
|
||||
"https://example.com/?test_dnr_upgradeScheme",
|
||||
req.url,
|
||||
"upgradeScheme action upgraded http to https"
|
||||
);
|
||||
browser.test.assertEq(200, req.status, "Correct HTTP status");
|
||||
|
||||
await req.text(); // Verify that the body can be read, just in case.
|
||||
|
||||
// Sanity check that the test did not pass trivially due to an automatic
|
||||
// https upgrade of the extension / test environment.
|
||||
browser.test.assertEq(
|
||||
insecureInitialUrl,
|
||||
await firstRequestPromise,
|
||||
"Initial URL should be http"
|
||||
);
|
||||
|
||||
browser.test.sendMessage("tested_dnr_upgradeScheme");
|
||||
},
|
||||
manifest: {
|
||||
host_permissions: ["*://example.com/*"],
|
||||
permissions: ["webRequest"],
|
||||
},
|
||||
});
|
||||
await otherExtension.startup();
|
||||
await otherExtension.awaitMessage("tested_dnr_upgradeScheme");
|
||||
await otherExtension.unload();
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,96 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
add_setup(() => {
|
||||
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.dnr.enabled", true);
|
||||
});
|
||||
|
||||
const server = createHttpServer({
|
||||
hosts: ["example.com", "example.net", "example.org"],
|
||||
});
|
||||
server.registerPathHandler("/never_reached", (req, res) => {
|
||||
Assert.ok(false, "Server should never have been reached");
|
||||
});
|
||||
server.registerPathHandler("/allowed", (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
res.write("allowed");
|
||||
});
|
||||
server.registerPathHandler("/", (req, res) => {
|
||||
res.write("Dummy page");
|
||||
});
|
||||
|
||||
add_task(async function allowAllRequests_allows_request() {
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
// allowAllRequests should take precedence over block.
|
||||
{
|
||||
id: 1,
|
||||
condition: { resourceTypes: ["main_frame", "xmlhttprequest"] },
|
||||
action: { type: "block" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: { resourceTypes: ["main_frame"] },
|
||||
action: { type: "allowAllRequests" },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
priority: 2,
|
||||
// Note: when not specified, main_frame is excluded by default. So
|
||||
// when a main_frame request is triggered, only rules 1 and 2 match.
|
||||
condition: { requestDomains: ["example.com"] },
|
||||
action: { type: "block" },
|
||||
},
|
||||
],
|
||||
});
|
||||
browser.test.sendMessage("dnr_registered");
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("dnr_registered");
|
||||
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
"http://example.com/"
|
||||
);
|
||||
Assert.equal(
|
||||
await contentPage.spawn(null, () => content.document.URL),
|
||||
"http://example.com/",
|
||||
"main_frame request should have been allowed by allowAllRequests"
|
||||
);
|
||||
|
||||
async function checkCanFetch(url) {
|
||||
return contentPage.spawn(url, async url => {
|
||||
try {
|
||||
await (await content.fetch(url)).text();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false; // NetworkError: blocked
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Assert.equal(
|
||||
await checkCanFetch("http://example.com/never_reached"),
|
||||
false,
|
||||
"should be blocked by DNR rule 3"
|
||||
);
|
||||
Assert.equal(
|
||||
await checkCanFetch("http://example.net/"),
|
||||
// TODO bug 1797403: Fix expectation once allowAllRequests is implemented:
|
||||
// true,
|
||||
// "should not be blocked by block rule due to allowAllRequests rule"
|
||||
false,
|
||||
"is blocked because persistency of allowAllRequests is not yet implemented"
|
||||
);
|
||||
|
||||
await contentPage.close();
|
||||
await extension.unload();
|
||||
});
|
@ -1,130 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const server = createHttpServer({ hosts: ["example.com"] });
|
||||
server.registerPathHandler("/", (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
});
|
||||
|
||||
add_setup(() => {
|
||||
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.dnr.enabled", true);
|
||||
});
|
||||
|
||||
async function startDNRExtension({ privateBrowsingAllowed }) {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
incognitoOverride: privateBrowsingAllowed ? "spanning" : undefined,
|
||||
async background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [{ id: 1, condition: {}, action: { type: "block" } }],
|
||||
});
|
||||
browser.test.sendMessage("dnr_registered");
|
||||
},
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
permissions: ["declarativeNetRequest"],
|
||||
browser_specific_settings: { gecko: { id: "@dnr-ext" } },
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("dnr_registered");
|
||||
return extension;
|
||||
}
|
||||
|
||||
async function testMatchedByDNR(privateBrowsing) {
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
"http://example.com/?page",
|
||||
{ privateBrowsing }
|
||||
);
|
||||
let wasRequestBlocked = await contentPage.spawn(null, async () => {
|
||||
try {
|
||||
await content.fetch("http://example.com/?fetch");
|
||||
return false;
|
||||
} catch (e) {
|
||||
// Request blocked by DNR rule from startDNRExtension().
|
||||
return true;
|
||||
}
|
||||
});
|
||||
await contentPage.close();
|
||||
return wasRequestBlocked;
|
||||
}
|
||||
|
||||
add_task(async function private_browsing_not_allowed_by_default() {
|
||||
let extension = await startDNRExtension({ privateBrowsingAllowed: false });
|
||||
Assert.equal(
|
||||
await testMatchedByDNR(false),
|
||||
true,
|
||||
"DNR applies to non-private browsing requests by default"
|
||||
);
|
||||
Assert.equal(
|
||||
await testMatchedByDNR(true),
|
||||
false,
|
||||
"DNR not applied to private browsing requests by default"
|
||||
);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function private_browsing_allowed() {
|
||||
let extension = await startDNRExtension({ privateBrowsingAllowed: true });
|
||||
Assert.equal(
|
||||
await testMatchedByDNR(false),
|
||||
true,
|
||||
"DNR applies to non-private requests regardless of privateBrowsingAllowed"
|
||||
);
|
||||
Assert.equal(
|
||||
await testMatchedByDNR(true),
|
||||
true,
|
||||
"DNR applied to private browsing requests when privateBrowsingAllowed"
|
||||
);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(
|
||||
{ pref_set: [["extensions.dnr.feedback", true]] },
|
||||
async function testMatchOutcome_unaffected_by_privateBrowsing() {
|
||||
let extensionWithoutPrivateBrowsingAllowed = await startDNRExtension({});
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
incognitoOverride: "spanning",
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
permissions: ["declarativeNetRequest", "declarativeNetRequestFeedback"],
|
||||
},
|
||||
files: {
|
||||
"page.html": `<!DOCTYPE html><script src="page.js"></script>`,
|
||||
"page.js": async () => {
|
||||
browser.test.assertTrue(
|
||||
browser.extension.inIncognitoContext,
|
||||
"Extension page is opened in a private browsing context"
|
||||
);
|
||||
browser.test.assertDeepEq(
|
||||
{
|
||||
matchedRules: [
|
||||
{ ruleId: 1, rulesetId: "_session", extensionId: "@dnr-ext" },
|
||||
],
|
||||
},
|
||||
// testMatchOutcome does not offer a way to specify the private
|
||||
// browsing mode of a request. Confirm that testMatchOutcome always
|
||||
// simulates requests in normal private browsing mode, even if the
|
||||
// testMatchOutcome method itself is called from an extension page
|
||||
// in private browsing mode.
|
||||
await browser.declarativeNetRequest.testMatchOutcome(
|
||||
{ url: "http://example.com/?simulated_request", type: "image" },
|
||||
{ includeOtherExtensions: true }
|
||||
),
|
||||
"testMatchOutcome includes DNR from extensions without pbm access"
|
||||
);
|
||||
browser.test.sendMessage("done");
|
||||
},
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(
|
||||
`moz-extension://${extension.uuid}/page.html`,
|
||||
{ privateBrowsing: true }
|
||||
);
|
||||
await extension.awaitMessage("done");
|
||||
await contentPage.close();
|
||||
await extension.unload();
|
||||
await extensionWithoutPrivateBrowsingAllowed.unload();
|
||||
}
|
||||
);
|
@ -1,66 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const server = createHttpServer({ hosts: ["example.com", "restricted"] });
|
||||
server.registerPathHandler("/", (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.write("response from server");
|
||||
});
|
||||
|
||||
add_setup(() => {
|
||||
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.dnr.enabled", true);
|
||||
// The restrictedDomains pref should be set early, because the pref is read
|
||||
// only once (on first use) by WebExtensionPolicy::IsRestrictedURI.
|
||||
Services.prefs.setCharPref(
|
||||
"extensions.webextensions.restrictedDomains",
|
||||
"restricted"
|
||||
);
|
||||
});
|
||||
|
||||
async function startDNRExtension() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [{ id: 1, condition: {}, action: { type: "block" } }],
|
||||
});
|
||||
browser.test.sendMessage("dnr_registered");
|
||||
},
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("dnr_registered");
|
||||
return extension;
|
||||
}
|
||||
|
||||
add_task(async function dnr_ignores_system_requests() {
|
||||
let extension = await startDNRExtension();
|
||||
Assert.equal(
|
||||
await (await fetch("http://example.com/")).text(),
|
||||
"response from server",
|
||||
"DNR should not block requests from system principal"
|
||||
);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function dnr_ignores_requests_to_restrictedDomains() {
|
||||
let extension = await startDNRExtension();
|
||||
Assert.equal(
|
||||
await ExtensionTestUtils.fetch("http://example.com/", "http://restricted/"),
|
||||
"response from server",
|
||||
"DNR should not block destination in restrictedDomains"
|
||||
);
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function dnr_ignores_initiator_from_restrictedDomains() {
|
||||
let extension = await startDNRExtension();
|
||||
Assert.equal(
|
||||
await ExtensionTestUtils.fetch("http://restricted/", "http://example.com/"),
|
||||
"response from server",
|
||||
"DNR should not block requests initiated from a page in restrictedDomains"
|
||||
);
|
||||
await extension.unload();
|
||||
});
|
@ -1,205 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
add_setup(() => {
|
||||
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.dnr.enabled", true);
|
||||
});
|
||||
|
||||
const server = createHttpServer({
|
||||
hosts: ["example.com", "redir"],
|
||||
});
|
||||
server.registerPathHandler("/never_reached", (req, res) => {
|
||||
Assert.ok(false, "Server should never have been reached");
|
||||
});
|
||||
|
||||
add_task(async function block_request_with_dnr() {
|
||||
async function background() {
|
||||
let onBeforeRequestPromise = new Promise(resolve => {
|
||||
browser.webRequest.onBeforeRequest.addListener(resolve, {
|
||||
urls: ["*://example.com/*"],
|
||||
});
|
||||
});
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestDomains: ["example.com"] },
|
||||
action: { type: "block" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached"),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"blocked by DNR rule"
|
||||
);
|
||||
// DNR is documented to take precedence over webRequest. We should still
|
||||
// receive the webRequest event, however.
|
||||
browser.test.log("Waiting for webRequest.onBeforeRequest...");
|
||||
await onBeforeRequestPromise;
|
||||
browser.test.log("Seen webRequest.onBeforeRequest!");
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://example.com/*"],
|
||||
permissions: ["declarativeNetRequest", "webRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function upgradeScheme_and_redirect_request_with_dnr() {
|
||||
async function background() {
|
||||
let onBeforeRequestSeen = [];
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
d => {
|
||||
onBeforeRequestSeen.push(d.url);
|
||||
// webRequest cancels, but DNR should actually be taking precedence.
|
||||
return { cancel: true };
|
||||
},
|
||||
{ urls: ["*://example.com/*", "http://redir/here"] },
|
||||
["blocking"]
|
||||
);
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestDomains: ["example.com"] },
|
||||
action: { type: "upgradeScheme" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: { requestDomains: ["example.com"], urlFilter: "|https:*" },
|
||||
action: { type: "redirect", redirect: { url: "http://redir/here" } },
|
||||
// The upgradeScheme and redirect actions have equal precedence. To
|
||||
// make sure that the redirect action is executed when both rules
|
||||
// match, we assign a higher priority to the redirect action.
|
||||
priority: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached"),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"although initially redirected by DNR, ultimately blocked by webRequest"
|
||||
);
|
||||
// DNR is documented to take precedence over webRequest.
|
||||
// So we should actually see redirects according to the DNR rules, and
|
||||
// the webRequest listener should still be able to observe all requests.
|
||||
browser.test.assertDeepEq(
|
||||
[
|
||||
"http://example.com/never_reached",
|
||||
"https://example.com/never_reached",
|
||||
"http://redir/here",
|
||||
],
|
||||
onBeforeRequestSeen,
|
||||
"Expected onBeforeRequest events"
|
||||
);
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://example.com/*", "*://redir/*"],
|
||||
permissions: [
|
||||
"declarativeNetRequest",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function block_request_with_webRequest_after_allow_with_dnr() {
|
||||
async function background() {
|
||||
let onBeforeRequestSeen = [];
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
d => {
|
||||
onBeforeRequestSeen.push(d.url);
|
||||
return { cancel: !d.url.includes("webRequestNoCancel") };
|
||||
},
|
||||
{ urls: ["*://example.com/*"] },
|
||||
["blocking"]
|
||||
);
|
||||
// All DNR actions that do not end up canceling/redirecting the request:
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestMethods: ["get"] },
|
||||
action: { type: "allow" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: { requestMethods: ["put"] },
|
||||
action: {
|
||||
type: "modifyHeaders",
|
||||
requestHeaders: [{ operation: "set", header: "x", value: "y" }],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached?1", { method: "get" }),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"despite DNR 'allow' rule, still blocked by webRequest"
|
||||
);
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached?2", { method: "put" }),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"despite DNR 'modifyHeaders' rule, still blocked by webRequest"
|
||||
);
|
||||
// Just to rule out the request having been canceled by DNR instead of
|
||||
// webRequest, repeat the requests and verify that they succeed.
|
||||
await fetch("http://example.com/?webRequestNoCancel1", { method: "get" });
|
||||
await fetch("http://example.com/?webRequestNoCancel2", { method: "put" });
|
||||
|
||||
browser.test.assertDeepEq(
|
||||
[
|
||||
"http://example.com/never_reached?1",
|
||||
"http://example.com/never_reached?2",
|
||||
"http://example.com/?webRequestNoCancel1",
|
||||
"http://example.com/?webRequestNoCancel2",
|
||||
],
|
||||
onBeforeRequestSeen,
|
||||
"Expected onBeforeRequest events"
|
||||
);
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://example.com/*"],
|
||||
permissions: [
|
||||
"declarativeNetRequest",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
await extension.unload();
|
||||
});
|
@ -1,720 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// This test file verifies that the declarativeNetRequest API can modify
|
||||
// network requests as expected without the presence of the webRequest API. See
|
||||
// test_ext_dnr_webRequest.js for the interaction between webRequest and DNR.
|
||||
|
||||
add_setup(() => {
|
||||
Services.prefs.setBoolPref("extensions.manifestV3.enabled", true);
|
||||
Services.prefs.setBoolPref("extensions.dnr.enabled", true);
|
||||
});
|
||||
|
||||
const server = createHttpServer({
|
||||
hosts: ["example.com", "example.net", "example.org", "redir", "dummy"],
|
||||
});
|
||||
server.registerPathHandler("/cors_202", (req, res) => {
|
||||
res.setStatusLine(req.httpVersion, 202, "Accepted");
|
||||
// The extensions in this test have minimal permissions, so grant CORS to
|
||||
// allow them to read the response without host permissions.
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
res.write("cors_response");
|
||||
});
|
||||
server.registerPathHandler("/never_reached", (req, res) => {
|
||||
Assert.ok(false, "Server should never have been reached");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
});
|
||||
let gPreflightCount = 0;
|
||||
server.registerPathHandler("/preflight_count", (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
res.setHeader("Access-Control-Allow-Methods", "NONSIMPLE");
|
||||
if (req.method === "OPTIONS") {
|
||||
++gPreflightCount;
|
||||
} else {
|
||||
// CORS Preflight considers 2xx to be successful. To rule out inadvertent
|
||||
// server opt-in to CORS, respond with a non-2xx response.
|
||||
res.setStatusLine(req.httpVersion, 418, "I'm a teapot");
|
||||
res.write(`count=${gPreflightCount}`);
|
||||
}
|
||||
});
|
||||
server.registerPathHandler("/", (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Max-Age", "0");
|
||||
res.write("Dummy page");
|
||||
});
|
||||
|
||||
async function contentFetch(initiatorURL, url, options) {
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(initiatorURL);
|
||||
// Sanity check: that the initiator is as specified, and not redirected.
|
||||
Assert.equal(
|
||||
await contentPage.spawn(null, () => content.document.URL),
|
||||
initiatorURL,
|
||||
`Expected document load at: ${initiatorURL}`
|
||||
);
|
||||
let result = await contentPage.spawn({ url, options }, async args => {
|
||||
try {
|
||||
let req = await content.fetch(args.url, args.options);
|
||||
return {
|
||||
status: req.status,
|
||||
url: req.url,
|
||||
body: await req.text(),
|
||||
};
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
await contentPage.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
add_task(async function block_request_with_dnr() {
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestMethods: ["get"] },
|
||||
action: { type: "block" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: { requestMethods: ["head"] },
|
||||
action: { type: "allow" },
|
||||
},
|
||||
],
|
||||
});
|
||||
{
|
||||
// Request not matching DNR.
|
||||
let req = await fetch("http://example.com/cors_202", { method: "post" });
|
||||
browser.test.assertEq(202, req.status, "allowed without DNR rule");
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
}
|
||||
{
|
||||
// Request with "allow" DNR action.
|
||||
let req = await fetch("http://example.com/cors_202", { method: "head" });
|
||||
browser.test.assertEq(202, req.status, "allowed by DNR rule");
|
||||
browser.test.assertEq("", await req.text(), "no response for HEAD");
|
||||
}
|
||||
|
||||
// Request with "block" DNR action.
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached", { method: "get" }),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"blocked by DNR rule"
|
||||
);
|
||||
|
||||
browser.test.sendMessage("tested_dnr_block");
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("tested_dnr_block");
|
||||
|
||||
// DNR should not only work with requests within the extension, but also from
|
||||
// web pages.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://example.com/never_reached"),
|
||||
{ error: "NetworkError when attempting to fetch resource." },
|
||||
"Blocked by DNR with declarativeNetRequestWithHostAccess"
|
||||
);
|
||||
|
||||
// The declarativeNetRequest permission grants the ability to block requests
|
||||
// from other extensions. (The declarativeNetRequestWithHostAccess permission
|
||||
// does not; see test task block_with_declarativeNetRequestWithHostAccess.)
|
||||
let otherExtension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://example.com/never_reached", { method: "get" }),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"blocked by different extension with declarativeNetRequest permission"
|
||||
);
|
||||
browser.test.sendMessage("other_extension_done");
|
||||
},
|
||||
});
|
||||
await otherExtension.startup();
|
||||
await otherExtension.awaitMessage("other_extension_done");
|
||||
await otherExtension.unload();
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verifies that the "declarativeNetRequestWithHostAccess" permission can only
|
||||
// block if it has permission for the initiator.
|
||||
add_task(async function block_with_declarativeNetRequestWithHostAccess() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [{ id: 1, condition: {}, action: { type: "block" } }],
|
||||
});
|
||||
browser.test.sendMessage("dnr_registered");
|
||||
},
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["<all_urls>"],
|
||||
permissions: ["declarativeNetRequestWithHostAccess"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("dnr_registered");
|
||||
|
||||
// Initiator "http://dummy" does match "<all_urls>", so DNR rule should apply.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://example.com/never_reached"),
|
||||
{ error: "NetworkError when attempting to fetch resource." },
|
||||
"Blocked by DNR with declarativeNetRequestWithHostAccess"
|
||||
);
|
||||
|
||||
// Extensions cannot have permissions for another extension and therefore the
|
||||
// DNR rule never applies.
|
||||
let otherExtension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
let req = await fetch("http://example.com/cors_202", { method: "get" });
|
||||
browser.test.assertEq(202, req.status, "not blocked by other extension");
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
browser.test.sendMessage("other_extension_done");
|
||||
},
|
||||
});
|
||||
await otherExtension.startup();
|
||||
await otherExtension.awaitMessage("other_extension_done");
|
||||
await otherExtension.unload();
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verifies that upgradeScheme works.
|
||||
// The HttpServer helper does not support https (bug 1742061), so in this
|
||||
// test we just verify whether the upgrade has been attempted. Coverage that
|
||||
// verifies that the upgraded request completes is in:
|
||||
// toolkit/components/extensions/test/mochitest/test_ext_dnr_upgradeScheme.html
|
||||
add_task(async function upgradeScheme_declarativeNetRequestWithHostAccess() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { excludedRequestDomains: ["dummy"] },
|
||||
action: { type: "upgradeScheme" },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
// HttpServer does not support https (bug 1742061).
|
||||
// As a work-around, we just redirect the https:-request to http.
|
||||
condition: { urlFilter: "|https:*" },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: { url: "http://dummy/cors_202?from_https" },
|
||||
},
|
||||
// The upgradeScheme and redirect actions have equal precedence. To
|
||||
// make sure that the redirect action is executed when both rules
|
||||
// match, we assign a higher priority to the redirect action.
|
||||
priority: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let req = await fetch("http://redir/never_reached");
|
||||
browser.test.assertEq(
|
||||
"http://dummy/cors_202?from_https",
|
||||
req.url,
|
||||
"upgradeScheme upgraded to https"
|
||||
);
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
|
||||
browser.test.sendMessage("tested_dnr_upgradeScheme");
|
||||
},
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions.
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://dummy/*", "*://redir/*"],
|
||||
permissions: ["declarativeNetRequestWithHostAccess"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("tested_dnr_upgradeScheme");
|
||||
|
||||
// Request to same-origin subresource, which should be upgraded.
|
||||
Assert.equal(
|
||||
(await contentFetch("http://redir/", "http://redir/never_reached")).url,
|
||||
"http://dummy/cors_202?from_https",
|
||||
"upgradeScheme + host access should upgrade (same-origin request)"
|
||||
);
|
||||
|
||||
// Request to cross-origin subresource, which should be upgraded.
|
||||
// Note: after the upgrade, a cross-origin redirect happens. Internally, we
|
||||
// reflect the Origin request header in the Access-Control-Allow-Origin (ACAO)
|
||||
// response header, to ensure that the request is accepted by CORS. See
|
||||
// https://github.com/w3c/webappsec-upgrade-insecure-requests/issues/32
|
||||
Assert.equal(
|
||||
(await contentFetch("http://dummy/", "http://redir/never_reached")).url,
|
||||
// TODO bug 1800990: despite the mirrored Origin in ACAO, the CORS check
|
||||
// fails after a request is upgraded. Once fixed, update this expectation:
|
||||
undefined, // Should be: "http://dummy/cors_202?from_https",
|
||||
"TODO 1800990: upgradeScheme + host access should upgrade (cross-origin request)"
|
||||
);
|
||||
|
||||
// The DNR extension does not have example.net in host_permissions.
|
||||
const urlNoHostPerms = "http://example.net/cors_202?missing_host_permission";
|
||||
Assert.equal(
|
||||
(await contentFetch("http://dummy/", urlNoHostPerms)).url,
|
||||
urlNoHostPerms,
|
||||
"upgradeScheme not matched when extension lacks host access"
|
||||
);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function redirect_request_with_dnr() {
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: {
|
||||
requestDomains: ["example.com"],
|
||||
requestMethods: ["get"],
|
||||
},
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
url: "http://example.net/cors_202?1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
// Note: extension does not have example.org host permission.
|
||||
condition: { requestDomains: ["example.org"] },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
url: "http://example.net/cors_202?2",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
// The extension only has example.com permission, but the redirects to
|
||||
// example.net are still due to the CORS headers from the server.
|
||||
{
|
||||
// Simple GET request.
|
||||
let req = await fetch("http://example.com/never_reached");
|
||||
browser.test.assertEq(202, req.status, "redirected by DNR (simple)");
|
||||
browser.test.assertEq("http://example.net/cors_202?1", req.url);
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
}
|
||||
{
|
||||
// GeT request should be matched despite having a different case.
|
||||
let req = await fetch("http://example.com/never_reached", {
|
||||
method: "GeT",
|
||||
});
|
||||
browser.test.assertEq(202, req.status, "redirected by DNR (GeT)");
|
||||
browser.test.assertEq("http://example.net/cors_202?1", req.url);
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
}
|
||||
{
|
||||
// Host permission missing for request, request not redirected by DNR.
|
||||
// Response is readable due to the CORS response headers from the server.
|
||||
let req = await fetch("http://example.org/cors_202?noredir");
|
||||
browser.test.assertEq(202, req.status, "not redirected by DNR");
|
||||
browser.test.assertEq("http://example.org/cors_202?noredir", req.url);
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
}
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://example.com/*"],
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
|
||||
let otherExtension = ExtensionTestUtils.loadExtension({
|
||||
async background() {
|
||||
// The DNR extension has permissions for example.com, but not for this
|
||||
// extension. Therefore the "redirect" action should not apply.
|
||||
let req = await fetch("http://example.com/cors_202?other_ext");
|
||||
browser.test.assertEq(202, req.status, "not redirected by DNR");
|
||||
browser.test.assertEq("http://example.com/cors_202?other_ext", req.url);
|
||||
browser.test.assertEq("cors_response", await req.text());
|
||||
browser.test.sendMessage("other_extension_done");
|
||||
},
|
||||
});
|
||||
await otherExtension.startup();
|
||||
await otherExtension.awaitMessage("other_extension_done");
|
||||
await otherExtension.unload();
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Verifies that DNR redirects requiring a CORS preflight behave as expected.
|
||||
add_task(async function redirect_request_with_dnr_cors_preflight() {
|
||||
// Most other test tasks only test requests within the test extension. This
|
||||
// test intentionally triggers requests outside the extension, to make sure
|
||||
// that the usual CORS mechanisms is triggered (instead of exceptions from
|
||||
// host permissions).
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: {
|
||||
requestDomains: ["redir"],
|
||||
excludedRequestMethods: ["options"],
|
||||
},
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
url: "http://example.com/preflight_count",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: {
|
||||
requestDomains: ["example.net"],
|
||||
excludedRequestMethods: ["nonsimple"], // note: redirects "options"
|
||||
},
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
url: "http://example.com/preflight_count",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
let req = await fetch("http://redir/never_reached", {
|
||||
method: "NONSIMPLE",
|
||||
});
|
||||
// Extension has permission for "redir", but not for the redirect target.
|
||||
// The request is non-simple (see below for explanation of non-simple), so
|
||||
// a preflight (OPTIONS) request to /preflight_count is expected before the
|
||||
// redirection target is requested.
|
||||
browser.test.assertEq(
|
||||
"count=1",
|
||||
await req.text(),
|
||||
"Got preflight before redirect target because of missing host_permissions"
|
||||
);
|
||||
|
||||
browser.test.sendMessage("continue_preflight_tests");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
// "redir" and "example.net" are needed to allow redirection of these.
|
||||
// "dummy" is needed to redirect requests initiated from http://dummy.
|
||||
host_permissions: ["*://redir/*", "*://example.net/*", "*://dummy/*"],
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
gPreflightCount = 0;
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("continue_preflight_tests");
|
||||
gPreflightCount = 0; // value already checked before continue_preflight_tests.
|
||||
|
||||
// Simple request (i.e. without preflight requirement), that's redirected to
|
||||
// another URL by the DNR rule. The redirect should be accepted, and in
|
||||
// particular not be blocked by the same-origin policy. The redirect target
|
||||
// (/preflight_count) is readable due to the CORS headers from the server.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://redir/never_reached"),
|
||||
// count=0: A simple request does not trigger a preflight (OPTIONS) request.
|
||||
{ status: 418, url: "http://example.com/preflight_count", body: "count=0" },
|
||||
"Simple request should not have a preflight."
|
||||
);
|
||||
|
||||
// Any request method other than "GET", "POST" and "PUT" (e.g "NONSIMPLE") is
|
||||
// a non-simple request that triggers a preflight request ("OPTIONS").
|
||||
//
|
||||
// Usually, this happens (without extension-triggered redirects):
|
||||
// 1. NONSIMPLE /never_reached : is started, but does NOT hit the server yet.
|
||||
// 2. OPTIONS /never_reached + Access-Control-Request-Method: NONSIMPLE
|
||||
// 3. NONSIMPLE /never_reached : reaches the server if allowed by OPTIONS.
|
||||
//
|
||||
// With an extension-initiated redirect to /preflight_count:
|
||||
// 1. NONSIMPLE /never_reached : is started, but does not hit the server yet.
|
||||
// 2. extension redirects to /preflight_count
|
||||
// 3. OPTIONS /preflight_count + Access-Control-Request-Method: NONSIMPLE
|
||||
// - This is because the redirect preserves the request method/body/etc.
|
||||
// 4. NONSIMPLE /preflight_count : reaches the server if allowed by OPTIONS.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://redir/never_reached", {
|
||||
method: "NONSIMPLE",
|
||||
}),
|
||||
// Due to excludedRequestMethods: ["options"], the preflight for the
|
||||
// redirect target is not intercepted, so the server sees a preflight.
|
||||
{ status: 418, url: "http://example.com/preflight_count", body: "count=1" },
|
||||
"Initial URL redirected, redirection target has preflight"
|
||||
);
|
||||
gPreflightCount = 0;
|
||||
|
||||
// The "example.net" rule has "excludedRequestMethods": ["nonsimple"], so the
|
||||
// initial "NONSIMPLE" request is not immediately redirected. Therefore the
|
||||
// preflight request happens. This OPTIONS request is matched by the DNR rule
|
||||
// and redirected to /preflight_count. While preflight_count offers a very
|
||||
// permissive preflight response, it is not even fetched:
|
||||
// Only a 2xx HTTP status is considered a valid response to a pre-flight.
|
||||
// A redirect is like a 3xx HTTP status, so the whole request is rejected,
|
||||
// and the redirect is not followed for the OPTIONS request.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://example.net/never_reached", {
|
||||
method: "NONSIMPLE",
|
||||
}),
|
||||
{ error: "NetworkError when attempting to fetch resource." },
|
||||
"Redirect of preflight request (OPTIONS) should be a CORS failure"
|
||||
);
|
||||
|
||||
Assert.equal(gPreflightCount, 0, "Preflight OPTIONS has been intercepted");
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Tests that DNR redirect rules can be chained.
|
||||
add_task(async function redirect_request_with_dnr_multiple_hops() {
|
||||
async function background() {
|
||||
// Set up redirects from example.com up until dummy.
|
||||
let hosts = ["example.com", "example.net", "example.org", "redir", "dummy"];
|
||||
let rules = [];
|
||||
for (let i = 1; i < hosts.length; ++i) {
|
||||
const from = hosts[i - 1];
|
||||
const to = hosts[i];
|
||||
const end = hosts.length - 1 === i;
|
||||
rules.push({
|
||||
id: i,
|
||||
condition: { requestDomains: [from] },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
// All intermediate redirects should never hit the server, but the
|
||||
// last one should..
|
||||
url: end ? `http://${to}/?end` : `http://${to}/never_reached`,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
await browser.declarativeNetRequest.updateSessionRules({ addRules: rules });
|
||||
let req = await fetch("http://example.com/never_reached");
|
||||
browser.test.assertEq(200, req.status, "redirected by DNR (multiple)");
|
||||
browser.test.assertEq("http://dummy/?end", req.url, "Last URL in chain");
|
||||
browser.test.assertEq("Dummy page", await req.text());
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://*/*"], // matches all in the |hosts| list.
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
|
||||
// Test again, but without special extension permissions to verify that DNR
|
||||
// redirects pass CORS checks.
|
||||
Assert.deepEqual(
|
||||
await contentFetch("http://dummy/", "http://redir/never_reached"),
|
||||
{ status: 200, url: "http://dummy/?end", body: "Dummy page" },
|
||||
"Multiple redirects by DNR, requested from web origin."
|
||||
);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function redirect_request_with_dnr_with_redirect_loop() {
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestDomains: ["redir"] },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
url: "http://redir/cors_202?loop",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Redirect with initially a different URL.
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://redir/never_reached?"),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"Redirect loop caught (initially different URL)"
|
||||
);
|
||||
|
||||
// Redirect where redirect is exactly the same URL as requested.
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://redir/cors_202?loop"),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"Redirect loop caught (redirect target same as initial URL)"
|
||||
);
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://redir/*"],
|
||||
permissions: ["declarativeNetRequest"],
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
// Tests that redirect to extensionPath works, provided that the initiator is
|
||||
// either the extension itself, or in host_permissions. Moreover, the requested
|
||||
// resource must match a web_accessible_resources entry for both the initiator
|
||||
// AND the pre-redirect URL.
|
||||
add_task(async function redirect_request_with_dnr_to_extensionPath() {
|
||||
async function background() {
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: 1,
|
||||
condition: { requestDomains: ["redir"], requestMethods: ["post"] },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
extensionPath: "/war.txt?1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
condition: { requestDomains: ["redir"], requestMethods: ["put"] },
|
||||
action: {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
extensionPath: "/nonwar.txt?2",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
{
|
||||
let req = await fetch("http://redir/never_reached", { method: "post" });
|
||||
browser.test.assertEq(200, req.status, "redirected to extensionPath");
|
||||
browser.test.assertEq(`${location.origin}/war.txt?1`, req.url);
|
||||
browser.test.assertEq("war_ext_res", await req.text());
|
||||
}
|
||||
// Redirects to extensionPath that is not in web_accessible_resources.
|
||||
// While the initiator (extension) would be allowed to read the resource
|
||||
// due to it being same-origin, the pre-redirect URL (http://redir) is not
|
||||
// matching web_accessible_resources[].matches, so the load is rejected.
|
||||
//
|
||||
// This behavior differs from Chrome (e.g. at least in Chrome 109) that
|
||||
// does allow the load to complete. Extensions who really care about
|
||||
// exposing a web-accessible resource to the world can just put an all_urls
|
||||
// pattern in web_accessible_resources[].matches.
|
||||
await browser.test.assertRejects(
|
||||
fetch("http://redir/never_reached", { method: "put" }),
|
||||
"NetworkError when attempting to fetch resource.",
|
||||
"Redirect to nowar.txt, but pre-redirect host is not in web_accessible_resources[].matches"
|
||||
);
|
||||
|
||||
browser.test.notifyPass();
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
temporarilyInstalled: true, // Needed for granted_host_permissions
|
||||
manifest: {
|
||||
manifest_version: 3,
|
||||
granted_host_permissions: true,
|
||||
host_permissions: ["*://redir/*", "*://dummy/*"],
|
||||
permissions: ["declarativeNetRequest"],
|
||||
web_accessible_resources: [
|
||||
// *://redir/* is in matches, because that is the pre-redirect host.
|
||||
// *://dummy/* is in matches, because that is an initiator below.
|
||||
{ resources: ["war.txt"], matches: ["*://redir/*", "*://dummy/*"] },
|
||||
// without "matches", this is almost equivalent to not being listed in
|
||||
// web_accessible_resources at all. This entry is listed here to verify
|
||||
// that the presence of extension_ids does not somehow allow a request
|
||||
// with an extension initiator to complete.
|
||||
{ resources: ["nonwar.txt"], extension_ids: ["*"] },
|
||||
],
|
||||
},
|
||||
files: {
|
||||
"war.txt": "war_ext_res",
|
||||
"nonwar.txt": "non_war_ext_res",
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
await extension.awaitFinish();
|
||||
const extPrefix = `moz-extension://${extension.uuid}`;
|
||||
|
||||
// Request from origin in host_permissions, for web-accessible resource.
|
||||
Assert.deepEqual(
|
||||
await contentFetch(
|
||||
"http://dummy/", // <-- Matching web_accessible_resources[].matches
|
||||
"http://redir/never_reached", // <-- With matching host_permissions
|
||||
{ method: "post" }
|
||||
),
|
||||
{ status: 200, url: `${extPrefix}/war.txt?1`, body: "war_ext_res" },
|
||||
"Should have got redirect to web_accessible_resources (war.txt)"
|
||||
);
|
||||
|
||||
// Request from origin in host_permissions, for non-web-accessible resource.
|
||||
let { messages } = await promiseConsoleOutput(async () => {
|
||||
Assert.deepEqual(
|
||||
await contentFetch(
|
||||
"http://dummy/", // <-- Matching web_accessible_resources[].matches
|
||||
"http://redir/never_reached", // <-- With matching host_permissions
|
||||
{ method: "put" }
|
||||
),
|
||||
{ error: "NetworkError when attempting to fetch resource." },
|
||||
"Redirect to nowar.txt, without matching web_accessible_resources[].matches"
|
||||
);
|
||||
});
|
||||
const EXPECTED_SECURITY_ERROR = `Content at http://redir/never_reached may not load or link to ${extPrefix}/nonwar.txt?2.`;
|
||||
Assert.equal(
|
||||
messages.filter(m => m.message.includes(EXPECTED_SECURITY_ERROR)).length,
|
||||
1,
|
||||
`Should log SecurityError: ${EXPECTED_SECURITY_ERROR}`
|
||||
);
|
||||
|
||||
// Request from origin not in host_permissions. DNR rule should not apply.
|
||||
Assert.deepEqual(
|
||||
await contentFetch(
|
||||
"http://dummy/", // <-- Matching web_accessible_resources[].matches
|
||||
"http://example.com/cors_202", // <-- NOT in host_permissions
|
||||
{ method: "post" }
|
||||
),
|
||||
{ status: 202, url: "http://example.com/cors_202", body: "cors_response" },
|
||||
"Extension should not have redirected, due to lack of host permissions"
|
||||
);
|
||||
|
||||
await extension.unload();
|
||||
});
|
@ -114,14 +114,9 @@ skip-if =
|
||||
[test_ext_cors_mozextension.js]
|
||||
[test_ext_csp_frame_ancestors.js]
|
||||
[test_ext_debugging_utils.js]
|
||||
[test_ext_dnr_allowAllRequests.js]
|
||||
[test_ext_dnr_api.js]
|
||||
[test_ext_dnr_private_browsing.js]
|
||||
[test_ext_dnr_session_rules.js]
|
||||
[test_ext_dnr_system_restrictions.js]
|
||||
[test_ext_dnr_testMatchOutcome.js]
|
||||
[test_ext_dnr_webrequest.js]
|
||||
[test_ext_dnr_without_webrequest.js]
|
||||
[test_ext_dns.js]
|
||||
skip-if = os == "android" # Android needs alternative for proxy.settings - bug 1723523
|
||||
[test_ext_downloads.js]
|
||||
|
@ -19,7 +19,6 @@ const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||
const lazy = {};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
ExtensionDNR: "resource://gre/modules/ExtensionDNR.jsm",
|
||||
ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
|
||||
ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
|
||||
WebRequestUpload: "resource://gre/modules/WebRequestUpload.jsm",
|
||||
@ -620,9 +619,6 @@ HttpObserverManager = {
|
||||
onErrorOccurred: new Map(),
|
||||
onCompleted: new Map(),
|
||||
},
|
||||
// Whether there are any registered declarativeNetRequest rules. These DNR
|
||||
// rules may match new requests and result in request modifications.
|
||||
dnrActive: false,
|
||||
|
||||
openingInitialized: false,
|
||||
beforeConnectInitialized: false,
|
||||
@ -664,11 +660,10 @@ HttpObserverManager = {
|
||||
// webRequest listeners and removing those that are no longer needed if
|
||||
// there are no more listeners for corresponding webRequest events.
|
||||
addOrRemove() {
|
||||
let needOpening = this.listeners.onBeforeRequest.size || this.dnrActive;
|
||||
let needOpening = this.listeners.onBeforeRequest.size;
|
||||
let needBeforeConnect =
|
||||
this.listeners.onBeforeSendHeaders.size ||
|
||||
this.listeners.onSendHeaders.size ||
|
||||
this.dnrActive;
|
||||
this.listeners.onSendHeaders.size;
|
||||
if (needOpening && !this.openingInitialized) {
|
||||
this.openingInitialized = true;
|
||||
Services.obs.addObserver(this, "http-on-modify-request");
|
||||
@ -697,8 +692,7 @@ HttpObserverManager = {
|
||||
let needExamine =
|
||||
this.needTracing ||
|
||||
this.listeners.onHeadersReceived.size ||
|
||||
this.listeners.onAuthRequired.size ||
|
||||
this.dnrActive;
|
||||
this.listeners.onAuthRequired.size;
|
||||
|
||||
if (needExamine && !this.examineInitialized) {
|
||||
this.examineInitialized = true;
|
||||
@ -746,11 +740,6 @@ HttpObserverManager = {
|
||||
this.addOrRemove();
|
||||
},
|
||||
|
||||
setDNRHandlingEnabled(dnrActive) {
|
||||
this.dnrActive = dnrActive;
|
||||
this.addOrRemove();
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
let channel = this.getWrapper(subject);
|
||||
switch (topic) {
|
||||
@ -928,10 +917,6 @@ HttpObserverManager = {
|
||||
if (kind !== "onErrorOccurred" && channel.errorString) {
|
||||
return;
|
||||
}
|
||||
if (this.dnrActive) {
|
||||
// DNR may modify (but not cancel) the request at this stage.
|
||||
lazy.ExtensionDNR.beforeWebRequestEvent(channel, kind);
|
||||
}
|
||||
|
||||
let registerFilter = this.FILTER_TYPES.has(kind);
|
||||
let commonData = null;
|
||||
@ -1027,10 +1012,6 @@ HttpObserverManager = {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
if (this.dnrActive && lazy.ExtensionDNR.handleRequest(channel, kind)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.applyChanges(
|
||||
kind,
|
||||
channel,
|
||||
@ -1306,10 +1287,6 @@ var onCompleted = new HttpEvent("onCompleted", ["responseHeaders"]);
|
||||
var onErrorOccurred = new HttpEvent("onErrorOccurred");
|
||||
|
||||
var WebRequest = {
|
||||
setDNRHandlingEnabled: dnrActive => {
|
||||
HttpObserverManager.setDNRHandlingEnabled(dnrActive);
|
||||
},
|
||||
|
||||
onBeforeRequest,
|
||||
onBeforeSendHeaders,
|
||||
onSendHeaders,
|
||||
|
Loading…
Reference in New Issue
Block a user