fune/netwerk/test/unit/test_trr_https_fallback.js
Cristian Tuns 4d37cf70f1 Backed out 19 changesets (bug 1541508) for causing xpcshell failures on test_notHeadlessByDefault.js CLOSED TREE
Backed out changeset 08476fa2bc27 (bug 1541508)
Backed out changeset 0bf7514845db (bug 1541508)
Backed out changeset aa612a5e9ef7 (bug 1541508)
Backed out changeset 6bb9360473f7 (bug 1541508)
Backed out changeset b3d8e92f50c2 (bug 1541508)
Backed out changeset fa40dded133e (bug 1541508)
Backed out changeset 2e7db4aa8d4f (bug 1541508)
Backed out changeset 6098e2eb62ea (bug 1541508)
Backed out changeset 2c599ee639c4 (bug 1541508)
Backed out changeset 7d44f6e2644c (bug 1541508)
Backed out changeset c1279c3d674c (bug 1541508)
Backed out changeset 8bd08a62a590 (bug 1541508)
Backed out changeset 740010cb005c (bug 1541508)
Backed out changeset 0bfc7dd85c62 (bug 1541508)
Backed out changeset c4374a351356 (bug 1541508)
Backed out changeset 44ccfeca7364 (bug 1541508)
Backed out changeset e944e706a523 (bug 1541508)
Backed out changeset 2c59d66f43e4 (bug 1541508)
Backed out changeset a1896eacb6f1 (bug 1541508)
2022-11-01 22:38:52 -04:00

1042 lines
28 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const { TestUtils } = ChromeUtils.import(
"resource://testing-common/TestUtils.jsm"
);
let h2Port;
let h3Port;
let h3NoResponsePort;
let trrServer;
const dns = Cc["@mozilla.org/network/dns-service;1"].getService(
Ci.nsIDNSService
);
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
add_setup(async function setup() {
trr_test_setup();
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
h2Port = env.get("MOZHTTP2_PORT");
Assert.notEqual(h2Port, null);
Assert.notEqual(h2Port, "");
h3Port = env.get("MOZHTTP3_PORT");
Assert.notEqual(h3Port, null);
Assert.notEqual(h3Port, "");
h3NoResponsePort = env.get("MOZHTTP3_PORT_NO_RESPONSE");
Assert.notEqual(h3NoResponsePort, null);
Assert.notEqual(h3NoResponsePort, "");
Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
registerCleanupFunction(async () => {
trr_clear_prefs();
Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
Services.prefs.clearUserPref("network.dns.echconfig.enabled");
Services.prefs.clearUserPref("network.dns.echconfig.fallback_to_origin");
Services.prefs.clearUserPref("network.dns.httpssvc.reset_exclustion_list");
Services.prefs.clearUserPref("network.http.http3.enable");
Services.prefs.clearUserPref(
"network.dns.httpssvc.http3_fast_fallback_timeout"
);
Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
Services.prefs.clearUserPref("network.dns.localDomains");
Services.prefs.clearUserPref("network.dns.http3_echconfig.enabled");
if (trrServer) {
await trrServer.stop();
}
});
if (mozinfo.socketprocess_networking) {
await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
}
Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
});
function makeChan(url) {
let chan = NetUtil.newChannel({
uri: url,
loadUsingSystemPrincipal: true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
}).QueryInterface(Ci.nsIHttpChannel);
return chan;
}
function channelOpenPromise(chan, flags) {
return new Promise(resolve => {
function finish(req, buffer) {
resolve([req, buffer]);
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
}
let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
internal.setWaitForHTTPSSVCRecord();
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
chan.asyncOpen(new ChannelListener(finish, null, flags));
});
}
// Test if we can fallback to the last record sucessfully.
add_task(async function testFallbackToTheLastRecord() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
// Only the last record is valid to use.
await trrServer.registerDoHAnswers("test.fallback.com", "HTTPS", {
answers: [
{
name: "test.fallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.fallback1.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "123..." },
],
},
},
{
name: "test.fallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 4,
name: "foo.example.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "port", value: h2Port },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.fallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 3,
name: "test.fallback3.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.fallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "test.fallback2.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await new TRRDNSListener("test.fallback.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.fallback.com:${h2Port}/server-timing`);
let [req] = await channelOpenPromise(chan);
// Test if this request is done by h2.
Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
await trrServer.stop();
});
add_task(async function testFallbackToTheOrigin() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
// All records are not able to use to connect, so we fallback to the origin
// one.
await trrServer.registerDoHAnswers("test.foo.com", "HTTPS", {
answers: [
{
name: "test.foo.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.foo1.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "123..." },
],
},
},
{
name: "test.foo.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 3,
name: "test.foo3.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.foo.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "test.foo2.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await trrServer.registerDoHAnswers("test.foo.com", "A", {
answers: [
{
name: "test.foo.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
await new TRRDNSListener("test.foo.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.foo.com:${h2Port}/server-timing`);
let [req] = await channelOpenPromise(chan);
// Test if this request is done by h2.
Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
await trrServer.stop();
});
// Test when all records are failed and network.dns.echconfig.fallback_to_origin
// is false. In this case, the connection is always failed.
add_task(async function testAllRecordsFailed() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.dns.echconfig.fallback_to_origin", false);
await trrServer.registerDoHAnswers("test.bar.com", "HTTPS", {
answers: [
{
name: "test.bar.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.bar1.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "123..." },
],
},
},
{
name: "test.bar.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 3,
name: "test.bar3.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.bar.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "test.bar2.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await new TRRDNSListener("test.bar.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
// This channel should be failed.
let chan = makeChan(`https://test.bar.com:${h2Port}/server-timing`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.stop();
});
// Test when all records have no echConfig, we directly fallback to the origin
// one.
add_task(async function testFallbackToTheOrigin2() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
await trrServer.registerDoHAnswers("test.example.com", "HTTPS", {
answers: [
{
name: "test.example.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.example1.com",
values: [{ key: "alpn", value: ["h2", "h3-26"] }],
},
},
{
name: "test.example.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 3,
name: "test.example3.com",
values: [{ key: "alpn", value: ["h2", "h3-26"] }],
},
},
],
});
await new TRRDNSListener("test.example.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.example.com:${h2Port}/server-timing`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.registerDoHAnswers("test.example.com", "A", {
answers: [
{
name: "test.example.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
chan = makeChan(`https://test.example.com:${h2Port}/server-timing`);
await channelOpenPromise(chan);
await trrServer.stop();
});
// Test when some records have echConfig and some not, we directly fallback to
// the origin one.
add_task(async function testFallbackToTheOrigin3() {
dns.clearCache(true);
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
await trrServer.registerDoHAnswers("vulnerable.com", "A", {
answers: [
{
name: "vulnerable.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
await trrServer.registerDoHAnswers("vulnerable.com", "HTTPS", {
answers: [
{
name: "vulnerable.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "vulnerable1.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "vulnerable.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "vulnerable2.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "vulnerable.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 3,
name: "vulnerable3.com",
values: [{ key: "alpn", value: ["h2", "h3-26"] }],
},
},
],
});
await new TRRDNSListener("vulnerable.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://vulnerable.com:${h2Port}/server-timing`);
await channelOpenPromise(chan);
await trrServer.stop();
});
add_task(async function testResetExclusionList() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref(
"network.dns.httpssvc.reset_exclustion_list",
false
);
await trrServer.registerDoHAnswers("test.reset.com", "HTTPS", {
answers: [
{
name: "test.reset.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.reset1.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "port", value: h2Port },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.reset.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "test.reset2.com",
values: [
{ key: "alpn", value: ["h2", "h3-26"] },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await new TRRDNSListener("test.reset.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
// After this request, test.reset1.com and test.reset2.com should be both in
// the exclusion list.
let chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
// This request should be also failed, because all records are excluded.
chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.registerDoHAnswers("test.reset1.com", "A", {
answers: [
{
name: "test.reset1.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
Services.prefs.setBoolPref(
"network.dns.httpssvc.reset_exclustion_list",
true
);
// After enable network.dns.httpssvc.reset_exclustion_list and register
// A record for test.reset1.com, this request should be succeeded.
chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
await channelOpenPromise(chan);
await trrServer.stop();
});
// Simply test if we can connect to H3 server.
add_task(async function testH3Connection() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.http.http3.enable", true);
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
100
);
await trrServer.registerDoHAnswers("test.h3.com", "HTTPS", {
answers: [
{
name: "test.h3.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "www.h3.com",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await trrServer.registerDoHAnswers("www.h3.com", "A", {
answers: [
{
name: "www.h3.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
await new TRRDNSListener("test.h3.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.h3.com`);
let [req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h3-29");
let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h3Port);
await trrServer.stop();
});
add_task(async function testFastfallbackToH2() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.http.http3.enable", true);
// Use a short timeout to make sure the fast fallback timer will be triggered.
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
1
);
Services.prefs.setCharPref(
"network.dns.localDomains",
"test.fastfallback1.com"
);
await trrServer.registerDoHAnswers("test.fastfallback.com", "HTTPS", {
answers: [
{
name: "test.fastfallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.fastfallback1.com",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3NoResponsePort },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "test.fastfallback.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "test.fastfallback2.com",
values: [
{ key: "alpn", value: "h2" },
{ key: "port", value: h2Port },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await trrServer.registerDoHAnswers("test.fastfallback2.com", "A", {
answers: [
{
name: "test.fastfallback2.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
await new TRRDNSListener("test.fastfallback.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.fastfallback.com/server-timing`);
let [req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h2");
let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h2Port);
// Use a longer timeout to test the case that the timer is canceled.
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
5000
);
chan = makeChan(`https://test.fastfallback.com/server-timing`);
[req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h2");
internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h2Port);
await trrServer.stop();
});
// Test when we fail to establish H3 connection.
add_task(async function testFailedH3Connection() {
trrServer = new TRRServer();
await trrServer.start();
dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.http.http3.enable", true);
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
0
);
await trrServer.registerDoHAnswers("test.h3.org", "HTTPS", {
answers: [
{
name: "test.h3.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "www.h3.org",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await new TRRDNSListener("test.h3.org", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
let chan = makeChan(`https://test.h3.org`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.stop();
});
// Test we don't use the service mode record whose domain is in
// http3 excluded list.
add_task(async function testHttp3ExcludedList() {
trrServer = new TRRServer();
await trrServer.start();
dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.http.http3.enable", true);
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
0
);
Services.prefs.setCharPref(
"network.http.http3.alt-svc-mapping-for-testing",
"www.h3_fail.org;h3-29=:" + h3Port
);
// This will fail because there is no address record for www.h3_fail.org.
let chan = makeChan(`https://www.h3_fail.org`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
// Now www.h3_fail.org should be already excluded, so the second record
// foo.example.com will be selected.
await trrServer.registerDoHAnswers("test.h3_excluded.org", "HTTPS", {
answers: [
{
name: "test.h3_excluded.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "www.h3_fail.org",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
],
},
},
{
name: "test.h3_excluded.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "foo.example.com",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
],
},
},
],
});
await new TRRDNSListener("test.h3_excluded.org", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
chan = makeChan(`https://test.h3_excluded.org`);
let [req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h3-29");
let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h3Port);
await trrServer.stop();
});
add_task(async function testAllRecordsInHttp3ExcludedList() {
trrServer = new TRRServer();
await trrServer.start();
dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
Services.prefs.setBoolPref("network.http.http3.enable", true);
Services.prefs.setIntPref(
"network.dns.httpssvc.http3_fast_fallback_timeout",
0
);
Services.prefs.setCharPref(
"network.http.http3.alt-svc-mapping-for-testing",
"www.h3_fail1.org;h3-29=:" + h3Port
);
await trrServer.registerDoHAnswers("www.h3_all_excluded.org", "A", {
answers: [
{
name: "www.h3_all_excluded.org",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
// Test we can connect to www.h3_all_excluded.org sucessfully.
let chan = makeChan(
`https://www.h3_all_excluded.org:${h2Port}/server-timing`
);
let [req] = await channelOpenPromise(chan);
// Test if this request is done by h2.
Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
// This will fail because there is no address record for www.h3_fail1.org.
chan = makeChan(`https://www.h3_fail1.org`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
Services.prefs.setCharPref(
"network.http.http3.alt-svc-mapping-for-testing",
"www.h3_fail2.org;h3-29=:" + h3Port
);
// This will fail because there is no address record for www.h3_fail2.org.
chan = makeChan(`https://www.h3_fail2.org`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.registerDoHAnswers("www.h3_all_excluded.org", "HTTPS", {
answers: [
{
name: "www.h3_all_excluded.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "www.h3_fail1.org",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
{ key: "echconfig", value: "456..." },
],
},
},
{
name: "www.h3_all_excluded.org",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 2,
name: "www.h3_fail2.org",
values: [
{ key: "alpn", value: "h3-29" },
{ key: "port", value: h3Port },
{ key: "echconfig", value: "456..." },
],
},
},
],
});
await new TRRDNSListener("www.h3_all_excluded.org", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
dns.clearCache(true);
Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
Services.obs.notifyObservers(null, "net:prune-all-connections");
// All HTTPS RRs are in http3 excluded list and all records are failed to
// connect, so don't fallback to the origin one.
chan = makeChan(`https://www.h3_all_excluded.org:${h2Port}/server-timing`);
await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
await trrServer.registerDoHAnswers("www.h3_fail1.org", "A", {
answers: [
{
name: "www.h3_fail1.org",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
// The the case that when all records are in http3 excluded list, we still
// give the first record one more shot.
chan = makeChan(`https://www.h3_all_excluded.org`);
[req] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h3-29");
let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
Assert.equal(internal.remotePort, h3Port);
await trrServer.stop();
});
let WebSocketListener = function() {};
WebSocketListener.prototype = {
onAcknowledge(aContext, aSize) {},
onBinaryMessageAvailable(aContext, aMsg) {},
onMessageAvailable(aContext, aMsg) {},
onServerClose(aContext, aCode, aReason) {},
onStart(aContext) {
this.finish();
},
onStop(aContext, aStatusCode) {},
};
add_task(async function testUpgradeNotUsingHTTPSRR() {
trrServer = new TRRServer();
await trrServer.start();
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.setCharPref(
"network.trr.uri",
`https://foo.example.com:${trrServer.port}/dns-query`
);
await trrServer.registerDoHAnswers("test.ws.com", "HTTPS", {
answers: [
{
name: "test.ws.com",
ttl: 55,
type: "HTTPS",
flush: false,
data: {
priority: 1,
name: "test.ws1.com",
values: [{ key: "port", value: ["8888"] }],
},
},
],
});
await new TRRDNSListener("test.ws.com", {
type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
});
await trrServer.registerDoHAnswers("test.ws.com", "A", {
answers: [
{
name: "test.ws.com",
ttl: 55,
type: "A",
flush: false,
data: "127.0.0.1",
},
],
});
let wssUri = "wss://test.ws.com:" + h2Port + "/websocket";
let chan = Cc["@mozilla.org/network/protocol;1?name=wss"].createInstance(
Ci.nsIWebSocketChannel
);
chan.initLoadInfo(
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
Ci.nsIContentPolicy.TYPE_DOCUMENT
);
var uri = Services.io.newURI(wssUri);
var wsListener = new WebSocketListener();
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
false
);
await new Promise(resolve => {
wsListener.finish = resolve;
chan.asyncOpen(uri, wssUri, {}, 0, wsListener, null);
certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
true
);
});
await trrServer.stop();
});