tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_http3_fast_fallback.js (27721B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 var { setTimeout } = ChromeUtils.importESModule(
      8  "resource://gre/modules/Timer.sys.mjs"
      9 );
     10 
     11 let h2Port;
     12 let h3Port;
     13 let trrServer;
     14 
     15 const { TestUtils } = ChromeUtils.importESModule(
     16  "resource://testing-common/TestUtils.sys.mjs"
     17 );
     18 const certOverrideService = Cc[
     19  "@mozilla.org/security/certoverride;1"
     20 ].getService(Ci.nsICertOverrideService);
     21 
     22 add_setup(async function setup() {
     23  h3Port = Services.env.get("MOZHTTP3_PORT_NO_RESPONSE");
     24  Assert.notEqual(h3Port, null);
     25  Assert.notEqual(h3Port, "");
     26 
     27  trrServer = new TRRServer();
     28  await trrServer.start();
     29  h2Port = trrServer.port();
     30 
     31  trr_test_setup();
     32 
     33  if (mozinfo.socketprocess_networking) {
     34    Services.dns; // Needed to trigger socket process.
     35    await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
     36  }
     37 
     38  Services.prefs.setIntPref("network.trr.mode", 2); // TRR first
     39  Services.prefs.setBoolPref("network.http.http3.enable", true);
     40  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
     41  Services.prefs.setBoolPref(
     42    "network.dns.https_rr.check_record_with_cname",
     43    false
     44  );
     45 
     46  registerCleanupFunction(async () => {
     47    trr_clear_prefs();
     48    Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
     49    Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
     50    Services.prefs.clearUserPref("network.dns.echconfig.enabled");
     51    Services.prefs.clearUserPref("network.dns.http3_echconfig.enabled");
     52    Services.prefs.clearUserPref(
     53      "network.dns.echconfig.fallback_to_origin_when_all_failed"
     54    );
     55    Services.prefs.clearUserPref("network.dns.httpssvc.reset_exclustion_list");
     56    Services.prefs.clearUserPref("network.http.http3.enable");
     57    Services.prefs.clearUserPref(
     58      "network.dns.httpssvc.http3_fast_fallback_timeout"
     59    );
     60    Services.prefs.clearUserPref(
     61      "network.http.http3.alt-svc-mapping-for-testing"
     62    );
     63    Services.prefs.clearUserPref("network.http.http3.backup_timer_delay");
     64    Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
     65    Services.prefs.clearUserPref(
     66      "network.http.http3.parallel_fallback_conn_limit"
     67    );
     68    Services.prefs.clearUserPref(
     69      "network.dns.https_rr.check_record_with_cname"
     70    );
     71    if (trrServer) {
     72      await trrServer.stop();
     73    }
     74  });
     75 });
     76 
     77 function makeChan(url) {
     78  let chan = NetUtil.newChannel({
     79    uri: url,
     80    loadUsingSystemPrincipal: true,
     81    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     82  }).QueryInterface(Ci.nsIHttpChannel);
     83  chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
     84  return chan;
     85 }
     86 
     87 function channelOpenPromise(chan, flags, delay) {
     88  // eslint-disable-next-line no-async-promise-executor
     89  return new Promise(async resolve => {
     90    function finish(req, buffer) {
     91      resolve([req, buffer]);
     92      certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     93        false
     94      );
     95    }
     96    certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     97      true
     98    );
     99    if (delay) {
    100      // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    101      await new Promise(r => setTimeout(r, delay));
    102    }
    103    chan.asyncOpen(new ChannelListener(finish, null, flags));
    104  });
    105 }
    106 
    107 let CheckOnlyHttp2Listener = function () {};
    108 
    109 CheckOnlyHttp2Listener.prototype = {
    110  onStartRequest: function testOnStartRequest() {},
    111 
    112  onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
    113    read_stream(stream, cnt);
    114  },
    115 
    116  onStopRequest: function testOnStopRequest(request, status) {
    117    Assert.equal(status, Cr.NS_OK);
    118    let httpVersion = "";
    119    try {
    120      httpVersion = request.protocolVersion;
    121    } catch (e) {}
    122    Assert.equal(httpVersion, "h2");
    123 
    124    let routed = "NA";
    125    try {
    126      routed = request.getRequestHeader("Alt-Used");
    127    } catch (e) {}
    128    dump("routed is " + routed + "\n");
    129    Assert.ok(routed === "0" || routed === "NA");
    130    this.finish();
    131  },
    132 };
    133 
    134 async function fast_fallback_test() {
    135  let result = 1;
    136  // We need to loop here because we need to wait for AltSvc storage to
    137  // to be started.
    138  // We also do not have a way to verify that HTTP3 has been tried, because
    139  // the fallback is automatic, so try a couple of times.
    140  do {
    141    // We need to close HTTP2 connections, otherwise our connection pooling
    142    // will dispatch the request over already existing HTTP2 connection.
    143    Services.obs.notifyObservers(null, "net:prune-all-connections");
    144    let chan = makeChan(`https://foo.example.com:${h2Port}/`);
    145    let listener = new CheckOnlyHttp2Listener();
    146    await altsvcSetupPromise(chan, listener);
    147    result++;
    148  } while (result < 3);
    149 }
    150 
    151 // Test the case when speculative connection is enabled. In this case, when the
    152 // backup connection is ready, the http transaction is still in pending
    153 // queue because the h3 connection is never ready to accept transactions.
    154 add_task(async function test_fast_fallback_with_speculative_connection() {
    155  Services.prefs.setBoolPref("network.http.http3.enable", true);
    156  Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com");
    157  // Set AltSvc to point to not existing HTTP3 server on port 443
    158  Services.prefs.setCharPref(
    159    "network.http.http3.alt-svc-mapping-for-testing",
    160    "foo.example.com;h3=:" + h3Port
    161  );
    162  Services.prefs.setBoolPref("network.dns.disableIPv6", true);
    163  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
    164 
    165  await fast_fallback_test();
    166 });
    167 
    168 // Test the case when speculative connection is disabled. In this case, when the
    169 // back connection is ready, the http transaction is already activated,
    170 // but the socket is not ready to write.
    171 add_task(async function test_fast_fallback_without_speculative_connection() {
    172  // Make sure the h3 connection created by the previous test is cleared.
    173  Services.obs.notifyObservers(null, "net:cancel-all-connections");
    174  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    175  await new Promise(resolve => setTimeout(resolve, 1000));
    176  // Clear the h3 excluded list, otherwise the Alt-Svc mapping will not be used.
    177  Services.obs.notifyObservers(null, "network:reset-http3-excluded-list");
    178  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
    179 
    180  await fast_fallback_test();
    181 
    182  Services.prefs.clearUserPref(
    183    "network.http.http3.alt-svc-mapping-for-testing"
    184  );
    185 });
    186 
    187 // Test when echConfig is disabled and we have https rr for http3. We use a
    188 // longer timeout in this test, so when fast fallback timer is triggered, the
    189 // http transaction is already activated.
    190 add_task(async function testFastfallback() {
    191  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    192  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    193  Services.prefs.setBoolPref("network.dns.echconfig.enabled", false);
    194 
    195  Services.prefs.setIntPref("network.trr.mode", 3);
    196  Services.prefs.setCharPref(
    197    "network.trr.uri",
    198    `https://foo.example.com:${trrServer.port()}/dns-query`
    199  );
    200  Services.prefs.setBoolPref("network.http.http3.enable", true);
    201 
    202  Services.prefs.setIntPref(
    203    "network.dns.httpssvc.http3_fast_fallback_timeout",
    204    1000
    205  );
    206 
    207  await trrServer.registerDoHAnswers("test.fastfallback.com", "HTTPS", {
    208    answers: [
    209      {
    210        name: "test.fastfallback.com",
    211        ttl: 55,
    212        type: "HTTPS",
    213        flush: false,
    214        data: {
    215          priority: 1,
    216          name: "test.fastfallback1.com",
    217          values: [
    218            { key: "alpn", value: "h3" },
    219            { key: "no-default-alpn" },
    220            { key: "port", value: h3Port },
    221            { key: "echconfig", value: "456..." },
    222          ],
    223        },
    224      },
    225      {
    226        name: "test.fastfallback.com",
    227        ttl: 55,
    228        type: "HTTPS",
    229        flush: false,
    230        data: {
    231          priority: 2,
    232          name: "test.fastfallback2.com",
    233          values: [
    234            { key: "alpn", value: "h2" },
    235            { key: "port", value: h2Port },
    236            { key: "echconfig", value: "456..." },
    237          ],
    238        },
    239      },
    240    ],
    241  });
    242 
    243  await trrServer.registerDoHAnswers("test.fastfallback1.com", "A", {
    244    answers: [
    245      {
    246        name: "test.fastfallback1.com",
    247        ttl: 55,
    248        type: "A",
    249        flush: false,
    250        data: "127.0.0.1",
    251      },
    252    ],
    253  });
    254 
    255  await trrServer.registerDoHAnswers("test.fastfallback2.com", "A", {
    256    answers: [
    257      {
    258        name: "test.fastfallback2.com",
    259        ttl: 55,
    260        type: "A",
    261        flush: false,
    262        data: "127.0.0.1",
    263      },
    264    ],
    265  });
    266 
    267  let chan = makeChan(`https://test.fastfallback.com/server-timing`);
    268  let [req] = await channelOpenPromise(chan);
    269  Assert.equal(req.protocolVersion, "h2");
    270  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    271  Assert.equal(internal.remotePort, h2Port);
    272 });
    273 
    274 // Like the previous test, but with a shorter timeout, so when fast fallback
    275 // timer is triggered, the http transaction is still in pending queue.
    276 add_task(async function testFastfallback1() {
    277  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    278  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    279  Services.prefs.setBoolPref("network.dns.echconfig.enabled", false);
    280 
    281  Services.prefs.setIntPref("network.trr.mode", 3);
    282  Services.prefs.setCharPref(
    283    "network.trr.uri",
    284    `https://foo.example.com:${trrServer.port()}/dns-query`
    285  );
    286  Services.prefs.setBoolPref("network.http.http3.enable", true);
    287 
    288  Services.prefs.setIntPref(
    289    "network.dns.httpssvc.http3_fast_fallback_timeout",
    290    10
    291  );
    292 
    293  await trrServer.registerDoHAnswers("test.fastfallback.org", "HTTPS", {
    294    answers: [
    295      {
    296        name: "test.fastfallback.org",
    297        ttl: 55,
    298        type: "HTTPS",
    299        flush: false,
    300        data: {
    301          priority: 1,
    302          name: "test.fastfallback1.org",
    303          values: [
    304            { key: "alpn", value: "h3" },
    305            { key: "no-default-alpn" },
    306            { key: "port", value: h3Port },
    307            { key: "echconfig", value: "456..." },
    308          ],
    309        },
    310      },
    311      {
    312        name: "test.fastfallback.org",
    313        ttl: 55,
    314        type: "HTTPS",
    315        flush: false,
    316        data: {
    317          priority: 2,
    318          name: "test.fastfallback2.org",
    319          values: [
    320            { key: "alpn", value: "h2" },
    321            { key: "port", value: h2Port },
    322            { key: "echconfig", value: "456..." },
    323          ],
    324        },
    325      },
    326    ],
    327  });
    328 
    329  await trrServer.registerDoHAnswers("test.fastfallback1.org", "A", {
    330    answers: [
    331      {
    332        name: "test.fastfallback1.org",
    333        ttl: 55,
    334        type: "A",
    335        flush: false,
    336        data: "127.0.0.1",
    337      },
    338    ],
    339  });
    340 
    341  await trrServer.registerDoHAnswers("test.fastfallback2.org", "A", {
    342    answers: [
    343      {
    344        name: "test.fastfallback2.org",
    345        ttl: 55,
    346        type: "A",
    347        flush: false,
    348        data: "127.0.0.1",
    349      },
    350    ],
    351  });
    352 
    353  let chan = makeChan(`https://test.fastfallback.org/server-timing`);
    354  let [req] = await channelOpenPromise(chan);
    355  Assert.equal(req.protocolVersion, "h2");
    356  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    357  Assert.equal(internal.remotePort, h2Port);
    358 });
    359 
    360 // Test when echConfig is enabled, we can sucessfully fallback to the last
    361 // record.
    362 add_task(async function testFastfallbackWithEchConfig() {
    363  // XXX(valenting): This test takes 30s to fallback.
    364  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    365  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    366  Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
    367  Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
    368 
    369  Services.prefs.setIntPref("network.trr.mode", 3);
    370  Services.prefs.setCharPref(
    371    "network.trr.uri",
    372    `https://foo.example.com:${trrServer.port()}/dns-query`
    373  );
    374  Services.prefs.setBoolPref("network.http.http3.enable", true);
    375 
    376  Services.prefs.setIntPref(
    377    "network.dns.httpssvc.http3_fast_fallback_timeout",
    378    50
    379  );
    380 
    381  await trrServer.registerDoHAnswers("test.ech.org", "HTTPS", {
    382    answers: [
    383      {
    384        name: "test.ech.org",
    385        ttl: 55,
    386        type: "HTTPS",
    387        flush: false,
    388        data: {
    389          priority: 1,
    390          name: "test.ech1.org",
    391          values: [
    392            { key: "alpn", value: "h3" },
    393            { key: "port", value: h3Port },
    394            { key: "echconfig", value: "456..." },
    395          ],
    396        },
    397      },
    398      {
    399        name: "test.ech.org",
    400        ttl: 55,
    401        type: "HTTPS",
    402        flush: false,
    403        data: {
    404          priority: 2,
    405          name: "test.ech2.org",
    406          values: [
    407            { key: "alpn", value: "h2" },
    408            { key: "port", value: h2Port },
    409            { key: "echconfig", value: "456..." },
    410          ],
    411        },
    412      },
    413      {
    414        name: "test.ech.org",
    415        ttl: 55,
    416        type: "HTTPS",
    417        flush: false,
    418        data: {
    419          priority: 3,
    420          name: "test.ech3.org",
    421          values: [
    422            { key: "alpn", value: "h2" },
    423            { key: "port", value: h2Port },
    424            { key: "echconfig", value: "456..." },
    425          ],
    426        },
    427      },
    428    ],
    429  });
    430 
    431  await trrServer.registerDoHAnswers("test.ech1.org", "A", {
    432    answers: [
    433      {
    434        name: "test.ech1.org",
    435        ttl: 55,
    436        type: "A",
    437        flush: false,
    438        data: "127.0.0.1",
    439      },
    440    ],
    441  });
    442 
    443  await trrServer.registerDoHAnswers("test.ech3.org", "A", {
    444    answers: [
    445      {
    446        name: "test.ech3.org",
    447        ttl: 55,
    448        type: "A",
    449        flush: false,
    450        data: "127.0.0.1",
    451      },
    452    ],
    453  });
    454 
    455  let chan = makeChan(`https://test.ech.org/server-timing`);
    456  let [req] = await channelOpenPromise(chan);
    457  Assert.equal(req.protocolVersion, "h2");
    458  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    459  Assert.equal(internal.remotePort, h2Port);
    460 });
    461 
    462 // Test when echConfig is enabled, the connection should fail when not all
    463 // records have echConfig.
    464 add_task(async function testFastfallbackWithpartialEchConfig() {
    465  // XXX(valenting): This test takes 30s to fallback.
    466  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    467  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    468  Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
    469  Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
    470 
    471  Services.prefs.setIntPref("network.trr.mode", 3);
    472  Services.prefs.setCharPref(
    473    "network.trr.uri",
    474    `https://foo.example.com:${trrServer.port()}/dns-query`
    475  );
    476  Services.prefs.setBoolPref("network.http.http3.enable", true);
    477 
    478  Services.prefs.setIntPref(
    479    "network.dns.httpssvc.http3_fast_fallback_timeout",
    480    50
    481  );
    482 
    483  await trrServer.registerDoHAnswers("test.partial_ech.org", "HTTPS", {
    484    answers: [
    485      {
    486        name: "test.partial_ech.org",
    487        ttl: 55,
    488        type: "HTTPS",
    489        flush: false,
    490        data: {
    491          priority: 1,
    492          name: "test.partial_ech1.org",
    493          values: [
    494            { key: "alpn", value: "h3" },
    495            { key: "port", value: h3Port },
    496            { key: "echconfig", value: "456..." },
    497          ],
    498        },
    499      },
    500      {
    501        name: "test.partial_ech.org",
    502        ttl: 55,
    503        type: "HTTPS",
    504        flush: false,
    505        data: {
    506          priority: 2,
    507          name: "test.partial_ech2.org",
    508          values: [
    509            { key: "alpn", value: "h2" },
    510            { key: "port", value: h2Port },
    511          ],
    512        },
    513      },
    514    ],
    515  });
    516 
    517  await trrServer.registerDoHAnswers("test.partial_ech1.org", "A", {
    518    answers: [
    519      {
    520        name: "test.partial_ech1.org",
    521        ttl: 55,
    522        type: "A",
    523        flush: false,
    524        data: "127.0.0.1",
    525      },
    526    ],
    527  });
    528 
    529  await trrServer.registerDoHAnswers("test.partial_ech2.org", "A", {
    530    answers: [
    531      {
    532        name: "test.partial_ech2.org",
    533        ttl: 55,
    534        type: "A",
    535        flush: false,
    536        data: "127.0.0.1",
    537      },
    538    ],
    539  });
    540 
    541  let chan = makeChan(`https://test.partial_ech.org/server-timing`);
    542  await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
    543 });
    544 
    545 add_task(async function testFastfallbackWithoutEchConfig() {
    546  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    547  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    548 
    549  Services.prefs.setIntPref("network.trr.mode", 3);
    550  Services.prefs.setCharPref(
    551    "network.trr.uri",
    552    `https://foo.example.com:${trrServer.port()}/dns-query`
    553  );
    554  Services.prefs.setBoolPref("network.http.http3.enable", true);
    555 
    556  Services.prefs.setIntPref(
    557    "network.dns.httpssvc.http3_fast_fallback_timeout",
    558    50
    559  );
    560 
    561  await trrServer.registerDoHAnswers("test.no_ech_h2.org", "HTTPS", {
    562    answers: [
    563      {
    564        name: "test.no_ech_h2.org",
    565        ttl: 55,
    566        type: "HTTPS",
    567        flush: false,
    568        data: {
    569          priority: 1,
    570          name: "test.no_ech_h3.org",
    571          values: [
    572            { key: "alpn", value: "h3" },
    573            { key: "port", value: h3Port },
    574          ],
    575        },
    576      },
    577    ],
    578  });
    579 
    580  await trrServer.registerDoHAnswers("test.no_ech_h3.org", "A", {
    581    answers: [
    582      {
    583        name: "test.no_ech_h3.org",
    584        ttl: 55,
    585        type: "A",
    586        flush: false,
    587        data: "127.0.0.1",
    588      },
    589    ],
    590  });
    591 
    592  await trrServer.registerDoHAnswers("test.no_ech_h2.org", "A", {
    593    answers: [
    594      {
    595        name: "test.no_ech_h2.org",
    596        ttl: 55,
    597        type: "A",
    598        flush: false,
    599        data: "127.0.0.1",
    600      },
    601    ],
    602  });
    603 
    604  let chan = makeChan(`https://test.no_ech_h2.org:${h2Port}/server-timing`);
    605  let [req] = await channelOpenPromise(chan);
    606  Assert.equal(req.protocolVersion, "h2");
    607  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    608  Assert.equal(internal.remotePort, h2Port);
    609 });
    610 
    611 add_task(async function testH3FallbackWithMultipleTransactions() {
    612  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    613  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    614  Services.prefs.setBoolPref("network.dns.echconfig.enabled", false);
    615 
    616  Services.prefs.setIntPref("network.trr.mode", 3);
    617  Services.prefs.setCharPref(
    618    "network.trr.uri",
    619    `https://foo.example.com:${trrServer.port()}/dns-query`
    620  );
    621  Services.prefs.setBoolPref("network.http.http3.enable", true);
    622 
    623  // Disable fast fallback.
    624  Services.prefs.setIntPref(
    625    "network.http.http3.parallel_fallback_conn_limit",
    626    0
    627  );
    628  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
    629 
    630  await trrServer.registerDoHAnswers("test.multiple_trans.org", "HTTPS", {
    631    answers: [
    632      {
    633        name: "test.multiple_trans.org",
    634        ttl: 55,
    635        type: "HTTPS",
    636        flush: false,
    637        data: {
    638          priority: 1,
    639          name: "test.multiple_trans.org",
    640          values: [
    641            { key: "alpn", value: "h3" },
    642            { key: "port", value: h3Port },
    643          ],
    644        },
    645      },
    646    ],
    647  });
    648 
    649  await trrServer.registerDoHAnswers("test.multiple_trans.org", "A", {
    650    answers: [
    651      {
    652        name: "test.multiple_trans.org",
    653        ttl: 55,
    654        type: "A",
    655        flush: false,
    656        data: "127.0.0.1",
    657      },
    658    ],
    659  });
    660 
    661  let promises = [];
    662  for (let i = 0; i < 2; ++i) {
    663    let chan = makeChan(
    664      `https://test.multiple_trans.org:${h2Port}/server-timing`
    665    );
    666    promises.push(channelOpenPromise(chan));
    667  }
    668 
    669  let res = await Promise.all(promises);
    670  res.forEach(function (e) {
    671    let [req] = e;
    672    Assert.equal(req.protocolVersion, "h2");
    673    let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    674    Assert.equal(internal.remotePort, h2Port);
    675  });
    676 });
    677 
    678 add_task(async function testTwoFastFallbackTimers() {
    679  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    680  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    681  Services.prefs.setBoolPref("network.dns.echconfig.enabled", false);
    682 
    683  Services.prefs.setIntPref("network.trr.mode", 3);
    684  Services.prefs.setCharPref(
    685    "network.trr.uri",
    686    `https://foo.example.com:${trrServer.port()}/dns-query`
    687  );
    688  Services.prefs.setBoolPref("network.http.http3.enable", true);
    689 
    690  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
    691  Services.prefs.clearUserPref(
    692    "network.http.http3.parallel_fallback_conn_limit"
    693  );
    694 
    695  Services.prefs.setCharPref(
    696    "network.http.http3.alt-svc-mapping-for-testing",
    697    "foo.fallback.org;h3=:" + h3Port
    698  );
    699 
    700  Services.prefs.setIntPref(
    701    "network.dns.httpssvc.http3_fast_fallback_timeout",
    702    10
    703  );
    704  Services.prefs.setIntPref("network.http.http3.backup_timer_delay", 100);
    705 
    706  await trrServer.registerDoHAnswers("foo.fallback.org", "HTTPS", {
    707    answers: [
    708      {
    709        name: "foo.fallback.org",
    710        ttl: 55,
    711        type: "HTTPS",
    712        flush: false,
    713        data: {
    714          priority: 1,
    715          name: "foo.fallback.org",
    716          values: [
    717            { key: "alpn", value: "h3" },
    718            { key: "port", value: h3Port },
    719          ],
    720        },
    721      },
    722    ],
    723  });
    724 
    725  await trrServer.registerDoHAnswers("foo.fallback.org", "A", {
    726    answers: [
    727      {
    728        name: "foo.fallback.org",
    729        ttl: 55,
    730        type: "A",
    731        flush: false,
    732        data: "127.0.0.1",
    733      },
    734    ],
    735  });
    736 
    737  // Test the case that http3 backup timer is triggered after
    738  // fast fallback timer or HTTPS RR.
    739  Services.prefs.setIntPref(
    740    "network.dns.httpssvc.http3_fast_fallback_timeout",
    741    10
    742  );
    743  Services.prefs.setIntPref("network.http.http3.backup_timer_delay", 100);
    744 
    745  async function createChannelAndStartTest() {
    746    let chan = makeChan(`https://foo.fallback.org:${h2Port}/server-timing`);
    747    let [req] = await channelOpenPromise(chan);
    748    Assert.equal(req.protocolVersion, "h2");
    749    let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    750    Assert.equal(internal.remotePort, h2Port);
    751  }
    752 
    753  await createChannelAndStartTest();
    754 
    755  Services.obs.notifyObservers(null, "net:prune-all-connections");
    756  Services.obs.notifyObservers(null, "network:reset-http3-excluded-list");
    757  Services.dns.clearCache(true);
    758 
    759  // Do the same test again, but with a different configuration.
    760  Services.prefs.setIntPref(
    761    "network.dns.httpssvc.http3_fast_fallback_timeout",
    762    100
    763  );
    764  Services.prefs.setIntPref("network.http.http3.backup_timer_delay", 10);
    765 
    766  await createChannelAndStartTest();
    767 });
    768 
    769 add_task(async function testH3FastFallbackWithMultipleTransactions() {
    770  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    771  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    772  Services.prefs.setBoolPref("network.dns.echconfig.enabled", false);
    773 
    774  Services.prefs.setIntPref("network.trr.mode", 3);
    775  Services.prefs.setCharPref(
    776    "network.trr.uri",
    777    `https://foo.example.com:${trrServer.port()}/dns-query`
    778  );
    779  Services.prefs.setBoolPref("network.http.http3.enable", true);
    780 
    781  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
    782  Services.prefs.clearUserPref(
    783    "network.http.http3.parallel_fallback_conn_limit"
    784  );
    785 
    786  Services.prefs.setIntPref("network.http.http3.backup_timer_delay", 500);
    787 
    788  Services.prefs.setCharPref(
    789    "network.http.http3.alt-svc-mapping-for-testing",
    790    "test.multiple_fallback_trans.org;h3=:" + h3Port
    791  );
    792 
    793  await trrServer.registerDoHAnswers("test.multiple_fallback_trans.org", "A", {
    794    answers: [
    795      {
    796        name: "test.multiple_fallback_trans.org",
    797        ttl: 55,
    798        type: "A",
    799        flush: false,
    800        data: "127.0.0.1",
    801      },
    802    ],
    803  });
    804 
    805  let promises = [];
    806  for (let i = 0; i < 3; ++i) {
    807    let chan = makeChan(
    808      `https://test.multiple_fallback_trans.org:${h2Port}/server-timing`
    809    );
    810    if (i == 0) {
    811      promises.push(channelOpenPromise(chan));
    812    } else {
    813      promises.push(channelOpenPromise(chan, null, 500));
    814    }
    815  }
    816 
    817  let res = await Promise.all(promises);
    818  res.forEach(function (e) {
    819    let [req] = e;
    820    Assert.equal(req.protocolVersion, "h2");
    821    let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    822    Assert.equal(internal.remotePort, h2Port);
    823  });
    824 });
    825 
    826 add_task(async function testFastfallbackToTheSameRecord() {
    827  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    828  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    829  Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
    830  Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
    831 
    832  Services.prefs.setIntPref("network.trr.mode", 3);
    833  Services.prefs.setCharPref(
    834    "network.trr.uri",
    835    `https://foo.example.com:${trrServer.port()}/dns-query`
    836  );
    837  Services.prefs.setBoolPref("network.http.http3.enable", true);
    838 
    839  Services.prefs.setIntPref(
    840    "network.dns.httpssvc.http3_fast_fallback_timeout",
    841    1000
    842  );
    843 
    844  await trrServer.registerDoHAnswers("test.ech.org", "HTTPS", {
    845    answers: [
    846      {
    847        name: "test.ech.org",
    848        ttl: 55,
    849        type: "HTTPS",
    850        flush: false,
    851        data: {
    852          priority: 1,
    853          name: "test.ech1.org",
    854          values: [
    855            { key: "alpn", value: ["h3", "h2"] },
    856            { key: "port", value: h2Port },
    857            { key: "echconfig", value: "456..." },
    858          ],
    859        },
    860      },
    861    ],
    862  });
    863 
    864  await trrServer.registerDoHAnswers("test.ech1.org", "A", {
    865    answers: [
    866      {
    867        name: "test.ech1.org",
    868        ttl: 55,
    869        type: "A",
    870        flush: false,
    871        data: "127.0.0.1",
    872      },
    873    ],
    874  });
    875 
    876  let chan = makeChan(`https://test.ech.org/server-timing`);
    877  let [req] = await channelOpenPromise(chan);
    878  Assert.equal(req.protocolVersion, "h2");
    879  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    880  Assert.equal(internal.remotePort, h2Port);
    881 });
    882 
    883 // Similar to the previous test, but no ech.
    884 add_task(async function testFastfallbackToTheSameRecord1() {
    885  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
    886  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
    887  Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
    888  Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
    889 
    890  Services.prefs.setIntPref("network.trr.mode", 3);
    891  Services.prefs.setCharPref(
    892    "network.trr.uri",
    893    `https://foo.example.com:${trrServer.port()}/dns-query`
    894  );
    895  Services.prefs.setBoolPref("network.http.http3.enable", true);
    896 
    897  Services.prefs.setIntPref(
    898    "network.dns.httpssvc.http3_fast_fallback_timeout",
    899    1000
    900  );
    901 
    902  await trrServer.registerDoHAnswers("test.no_ech.org", "HTTPS", {
    903    answers: [
    904      {
    905        name: "test.no_ech.org",
    906        ttl: 55,
    907        type: "HTTPS",
    908        flush: false,
    909        data: {
    910          priority: 1,
    911          name: "test.no_ech.org",
    912          values: [
    913            { key: "alpn", value: ["h3", "h2"] },
    914            { key: "port", value: h2Port },
    915          ],
    916        },
    917      },
    918    ],
    919  });
    920 
    921  await trrServer.registerDoHAnswers("test.no_ech.org", "A", {
    922    answers: [
    923      {
    924        name: "test.no_ech.org",
    925        ttl: 55,
    926        type: "A",
    927        flush: false,
    928        data: "127.0.0.1",
    929      },
    930    ],
    931  });
    932 
    933  let chan = makeChan(`https://test.no_ech.org/server-timing`);
    934  let [req] = await channelOpenPromise(chan);
    935  Assert.equal(req.protocolVersion, "h2");
    936  let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
    937  Assert.equal(internal.remotePort, h2Port);
    938 });