Skip to content

Commit

Permalink
Bug 1552176 - Unit test for TRRMode for individual channels r=dragana
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D48362

--HG--
extra : moz-landing-system : lando
  • Loading branch information
valenting committed Jan 7, 2020
1 parent 43270f5 commit b52a50f
Showing 1 changed file with 143 additions and 23 deletions.
166 changes: 143 additions & 23 deletions netwerk/test/unit/test_trr.js
@@ -1,6 +1,8 @@
"use strict";

const { NodeServer } = ChromeUtils.import("resource://testing-common/httpd.js");
const { NodeServer, HttpServer } = ChromeUtils.import(
"resource://testing-common/httpd.js"
);
const dns = Cc["@mozilla.org/network/dns-service;1"].getService(
Ci.nsIDNSService
);
Expand Down Expand Up @@ -100,6 +102,15 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref("network.dns.native-is-localhost");
});

// This is an IP that is local, so we don't crash when connecting to it,
// but also connecting to it fails, so we attempt to retry with regular DNS.
const BAD_IP = (() => {
if (mozinfo.os == "linux") {
return "127.9.9.9";
}
return "0.0.0.0";
})();

class DNSListener {
constructor(name, expectedAnswer, expectedSuccess = true) {
this.name = name;
Expand Down Expand Up @@ -152,27 +163,139 @@ class DNSListener {
return this.promise.then.apply(this.promise, arguments);
}
}

Cu.importGlobalProperties(["fetch"]);

add_task(async function test0_nodeExecute() {
// This test checks that moz-http2.js running in node is working.
// This should always be the first test in this file (except for setup)
// otherwise we may encounter random failures when the http2 server is down.

let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
let execPort = env.get("MOZNODE_EXEC_PORT");
await fetch(`http://127.0.0.1:${execPort}/test`)
.then(response => {
ok(true, "NodeServer is working");
})
.catch(e => {
ok(false, `There was an error ${e}`);
});
await NodeServer.execute("bad_id", `"hello"`)
.then(() => ok(false, "expecting to throw"))
.catch(e => equal(e.message, "Error: could not find id"));
});

function makeChan(url, mode) {
let chan = NetUtil.newChannel({
uri: url,
loadUsingSystemPrincipal: true,
}).QueryInterface(Ci.nsIHttpChannel);
chan.setTRRMode(mode);
return chan;
}

add_task(
{ skip_if: () => mozinfo.os == "mac" },
async function test_trr_flags() {
let httpserv = new HttpServer();
httpserv.registerPathHandler("/", function handler(metadata, response) {
let content = "ok";
response.setHeader("Content-Length", `${content.length}`);
response.bodyOutputStream.write(content, content.length);
});
httpserv.start(-1);
const URL = `http://example.com:${httpserv.identity.primaryPort}/`;

dns.clearCache(true);
Services.prefs.setCharPref(
"network.trr.uri",
`https://localhost:${h2Port}/doh?responseIP=${BAD_IP}`
);

Services.prefs.setIntPref("network.trr.mode", 0);
dns.clearCache(true);
let chan = makeChan(URL, Ci.nsIRequest.TRR_DEFAULT_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
equal(chan.getTRRMode(), Ci.nsIRequest.TRR_DEFAULT_MODE);
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DISABLED_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
equal(chan.getTRRMode(), Ci.nsIRequest.TRR_DISABLED_MODE);
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_FIRST_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
equal(chan.getTRRMode(), Ci.nsIRequest.TRR_FIRST_MODE);
dns.clearCache(true);
chan = makeChan(
`http://example.com:${httpserv.identity.primaryPort}/`,
Ci.nsIRequest.TRR_ONLY_MODE
);
// Should fail as it tries to connect to local but unavailable IP
await new Promise(resolve =>
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
);
equal(chan.getTRRMode(), Ci.nsIRequest.TRR_ONLY_MODE);

dns.clearCache(true);
Services.prefs.setCharPref(
"network.trr.uri",
`https://localhost:${h2Port}/doh?responseIP=${BAD_IP}`
);
Services.prefs.setIntPref("network.trr.mode", 2);

dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DEFAULT_MODE);
// Does get the IP from TRR, but failure means it falls back to DNS.
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DISABLED_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
// Does get the IP from TRR, but failure means it falls back to DNS.
chan = makeChan(URL, Ci.nsIRequest.TRR_FIRST_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_ONLY_MODE);
await new Promise(resolve =>
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
);

dns.clearCache(true);
Services.prefs.setCharPref(
"network.trr.uri",
`https://localhost:${h2Port}/doh?responseIP=${BAD_IP}`
);
Services.prefs.setIntPref("network.trr.mode", 3);

dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DEFAULT_MODE);
await new Promise(resolve =>
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
);
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DISABLED_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_FIRST_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_ONLY_MODE);
await new Promise(resolve =>
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
);

dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 5);
Services.prefs.setCharPref(
"network.trr.uri",
`https://localhost:${h2Port}/doh?responseIP=1.1.1.1`
);

dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DEFAULT_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_DISABLED_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_FIRST_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));
dns.clearCache(true);
chan = makeChan(URL, Ci.nsIRequest.TRR_ONLY_MODE);
await new Promise(resolve => chan.asyncOpen(new ChannelListener(resolve)));

await new Promise(resolve => httpserv.stop(resolve));
}
);

// verify basic A record
add_task(async function test1() {
dns.clearCache(true);
Expand Down Expand Up @@ -1026,9 +1149,9 @@ add_task(async function test_connection_closed_no_bootstrap_localhost() {
});

add_task(async function test_connection_closed_no_bootstrap_no_excluded() {
// This test exists to document what happens when we're in TRR only mode
// and we don't set a bootstrap address. We use DNS to resolve the
// initial URI, but if the connection fails, we don't fallback to DNS
// This test makes sure that even in mode 3 without a bootstrap address
// we are able to restart the TRR connection if it drops - the TRR service
// channel will use regular DNS to resolve the TRR address.
dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Expand All @@ -1048,11 +1171,8 @@ add_task(async function test_connection_closed_no_bootstrap_no_excluded() {
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
[, , inStatus] = await new DNSListener("bar2.example.com", undefined, false);
Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
dns.clearCache(true);
await new DNSListener("bar2.example.com", "3.3.3.3");
});

add_task(async function test_connection_closed_trr_first() {
Expand Down

0 comments on commit b52a50f

Please sign in to comment.