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