Bug 1845311 - [Part 2] Use ChromeUtils.defineLazyGetter in more places r=arai,webcomp...
[gecko.git] / netwerk / test / unit / test_trr_https_fallback.js
blob1b5217876d4f5865db305052630ed0dc6fa4bc06
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 const { TestUtils } = ChromeUtils.importESModule(
8   "resource://testing-common/TestUtils.sys.mjs"
9 );
11 let h2Port;
12 let h3Port;
13 let h3NoResponsePort;
14 let trrServer;
16 const certOverrideService = Cc[
17   "@mozilla.org/security/certoverride;1"
18 ].getService(Ci.nsICertOverrideService);
20 add_setup(async function setup() {
21   trr_test_setup();
23   h2Port = Services.env.get("MOZHTTP2_PORT");
24   Assert.notEqual(h2Port, null);
25   Assert.notEqual(h2Port, "");
27   h3Port = Services.env.get("MOZHTTP3_PORT");
28   Assert.notEqual(h3Port, null);
29   Assert.notEqual(h3Port, "");
31   h3NoResponsePort = Services.env.get("MOZHTTP3_PORT_NO_RESPONSE");
32   Assert.notEqual(h3NoResponsePort, null);
33   Assert.notEqual(h3NoResponsePort, "");
35   Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
36   Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
37   Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
39   registerCleanupFunction(async () => {
40     trr_clear_prefs();
41     Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
42     Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
43     Services.prefs.clearUserPref("network.dns.echconfig.enabled");
44     Services.prefs.clearUserPref(
45       "network.dns.echconfig.fallback_to_origin_when_all_failed"
46     );
47     Services.prefs.clearUserPref("network.dns.httpssvc.reset_exclustion_list");
48     Services.prefs.clearUserPref("network.http.http3.enable");
49     Services.prefs.clearUserPref(
50       "network.dns.httpssvc.http3_fast_fallback_timeout"
51     );
52     Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
53     Services.prefs.clearUserPref("network.dns.localDomains");
54     Services.prefs.clearUserPref("network.dns.http3_echconfig.enabled");
55     if (trrServer) {
56       await trrServer.stop();
57     }
58   });
60   if (mozinfo.socketprocess_networking) {
61     Services.dns; // Needed to trigger socket process.
62     await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
63   }
65   Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
66 });
68 function makeChan(url) {
69   let chan = NetUtil.newChannel({
70     uri: url,
71     loadUsingSystemPrincipal: true,
72     contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
73   }).QueryInterface(Ci.nsIHttpChannel);
74   return chan;
77 function channelOpenPromise(chan, flags) {
78   return new Promise(resolve => {
79     function finish(req, buffer) {
80       resolve([req, buffer]);
81       certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
82         false
83       );
84     }
85     let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
86     internal.setWaitForHTTPSSVCRecord();
87     certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
88       true
89     );
90     chan.asyncOpen(new ChannelListener(finish, null, flags));
91   });
94 // Test if we can fallback to the last record sucessfully.
95 add_task(async function testFallbackToTheLastRecord() {
96   trrServer = new TRRServer();
97   await trrServer.start();
99   Services.prefs.setIntPref("network.trr.mode", 3);
100   Services.prefs.setCharPref(
101     "network.trr.uri",
102     `https://foo.example.com:${trrServer.port}/dns-query`
103   );
105   // Only the last record is valid to use.
106   await trrServer.registerDoHAnswers("test.fallback.com", "HTTPS", {
107     answers: [
108       {
109         name: "test.fallback.com",
110         ttl: 55,
111         type: "HTTPS",
112         flush: false,
113         data: {
114           priority: 1,
115           name: "test.fallback1.com",
116           values: [
117             { key: "alpn", value: ["h2", "h3-26"] },
118             { key: "echconfig", value: "123..." },
119           ],
120         },
121       },
122       {
123         name: "test.fallback.com",
124         ttl: 55,
125         type: "HTTPS",
126         flush: false,
127         data: {
128           priority: 4,
129           name: "foo.example.com",
130           values: [
131             { key: "alpn", value: ["h2", "h3-26"] },
132             { key: "port", value: h2Port },
133             { key: "echconfig", value: "456..." },
134           ],
135         },
136       },
137       {
138         name: "test.fallback.com",
139         ttl: 55,
140         type: "HTTPS",
141         flush: false,
142         data: {
143           priority: 3,
144           name: "test.fallback3.com",
145           values: [
146             { key: "alpn", value: ["h2", "h3-26"] },
147             { key: "echconfig", value: "456..." },
148           ],
149         },
150       },
151       {
152         name: "test.fallback.com",
153         ttl: 55,
154         type: "HTTPS",
155         flush: false,
156         data: {
157           priority: 2,
158           name: "test.fallback2.com",
159           values: [
160             { key: "alpn", value: ["h2", "h3-26"] },
161             { key: "echconfig", value: "456..." },
162           ],
163         },
164       },
165     ],
166   });
168   await new TRRDNSListener("test.fallback.com", {
169     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
170   });
172   let chan = makeChan(`https://test.fallback.com:${h2Port}/server-timing`);
173   let [req] = await channelOpenPromise(chan);
174   // Test if this request is done by h2.
175   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
177   await trrServer.stop();
180 add_task(async function testFallbackToTheOrigin() {
181   trrServer = new TRRServer();
182   await trrServer.start();
183   Services.prefs.setIntPref("network.trr.mode", 3);
184   Services.prefs.setBoolPref(
185     "network.dns.echconfig.fallback_to_origin_when_all_failed",
186     true
187   );
188   Services.prefs.setCharPref(
189     "network.trr.uri",
190     `https://foo.example.com:${trrServer.port}/dns-query`
191   );
193   // All records are not able to use to connect, so we fallback to the origin
194   // one.
195   await trrServer.registerDoHAnswers("test.foo.com", "HTTPS", {
196     answers: [
197       {
198         name: "test.foo.com",
199         ttl: 55,
200         type: "HTTPS",
201         flush: false,
202         data: {
203           priority: 1,
204           name: "test.foo1.com",
205           values: [
206             { key: "alpn", value: ["h2", "h3-26"] },
207             { key: "echconfig", value: "123..." },
208           ],
209         },
210       },
211       {
212         name: "test.foo.com",
213         ttl: 55,
214         type: "HTTPS",
215         flush: false,
216         data: {
217           priority: 3,
218           name: "test.foo3.com",
219           values: [
220             { key: "alpn", value: ["h2", "h3-26"] },
221             { key: "echconfig", value: "456..." },
222           ],
223         },
224       },
225       {
226         name: "test.foo.com",
227         ttl: 55,
228         type: "HTTPS",
229         flush: false,
230         data: {
231           priority: 2,
232           name: "test.foo2.com",
233           values: [
234             { key: "alpn", value: ["h2", "h3-26"] },
235             { key: "echconfig", value: "456..." },
236           ],
237         },
238       },
239     ],
240   });
242   await trrServer.registerDoHAnswers("test.foo.com", "A", {
243     answers: [
244       {
245         name: "test.foo.com",
246         ttl: 55,
247         type: "A",
248         flush: false,
249         data: "127.0.0.1",
250       },
251     ],
252   });
254   await new TRRDNSListener("test.foo.com", {
255     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
256   });
258   let chan = makeChan(`https://test.foo.com:${h2Port}/server-timing`);
259   let [req] = await channelOpenPromise(chan);
260   // Test if this request is done by h2.
261   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
263   await trrServer.stop();
266 // Test when all records are failed and network.dns.echconfig.fallback_to_origin
267 // is false. In this case, the connection is always failed.
268 add_task(async function testAllRecordsFailed() {
269   trrServer = new TRRServer();
270   await trrServer.start();
271   Services.prefs.setIntPref("network.trr.mode", 3);
272   Services.prefs.setCharPref(
273     "network.trr.uri",
274     `https://foo.example.com:${trrServer.port}/dns-query`
275   );
276   Services.prefs.setBoolPref(
277     "network.dns.echconfig.fallback_to_origin_when_all_failed",
278     false
279   );
281   await trrServer.registerDoHAnswers("test.bar.com", "HTTPS", {
282     answers: [
283       {
284         name: "test.bar.com",
285         ttl: 55,
286         type: "HTTPS",
287         flush: false,
288         data: {
289           priority: 1,
290           name: "test.bar1.com",
291           values: [
292             { key: "alpn", value: ["h2", "h3-26"] },
293             { key: "echconfig", value: "123..." },
294           ],
295         },
296       },
297       {
298         name: "test.bar.com",
299         ttl: 55,
300         type: "HTTPS",
301         flush: false,
302         data: {
303           priority: 3,
304           name: "test.bar3.com",
305           values: [
306             { key: "alpn", value: ["h2", "h3-26"] },
307             { key: "echconfig", value: "456..." },
308           ],
309         },
310       },
311       {
312         name: "test.bar.com",
313         ttl: 55,
314         type: "HTTPS",
315         flush: false,
316         data: {
317           priority: 2,
318           name: "test.bar2.com",
319           values: [
320             { key: "alpn", value: ["h2", "h3-26"] },
321             { key: "echconfig", value: "456..." },
322           ],
323         },
324       },
325     ],
326   });
328   await new TRRDNSListener("test.bar.com", {
329     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
330   });
332   // This channel should be failed.
333   let chan = makeChan(`https://test.bar.com:${h2Port}/server-timing`);
334   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
336   await trrServer.stop();
339 // Test when all records have no echConfig, we directly fallback to the origin
340 // one.
341 add_task(async function testFallbackToTheOrigin2() {
342   trrServer = new TRRServer();
343   await trrServer.start();
344   Services.prefs.setIntPref("network.trr.mode", 3);
345   Services.prefs.setCharPref(
346     "network.trr.uri",
347     `https://foo.example.com:${trrServer.port}/dns-query`
348   );
350   await trrServer.registerDoHAnswers("test.example.com", "HTTPS", {
351     answers: [
352       {
353         name: "test.example.com",
354         ttl: 55,
355         type: "HTTPS",
356         flush: false,
357         data: {
358           priority: 1,
359           name: "test.example1.com",
360           values: [{ key: "alpn", value: ["h2", "h3-26"] }],
361         },
362       },
363       {
364         name: "test.example.com",
365         ttl: 55,
366         type: "HTTPS",
367         flush: false,
368         data: {
369           priority: 3,
370           name: "test.example3.com",
371           values: [{ key: "alpn", value: ["h2", "h3-26"] }],
372         },
373       },
374     ],
375   });
377   await new TRRDNSListener("test.example.com", {
378     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
379   });
381   let chan = makeChan(`https://test.example.com:${h2Port}/server-timing`);
382   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
384   await trrServer.registerDoHAnswers("test.example.com", "A", {
385     answers: [
386       {
387         name: "test.example.com",
388         ttl: 55,
389         type: "A",
390         flush: false,
391         data: "127.0.0.1",
392       },
393     ],
394   });
396   chan = makeChan(`https://test.example.com:${h2Port}/server-timing`);
397   await channelOpenPromise(chan);
399   await trrServer.stop();
402 // Test when some records have echConfig and some not, we directly fallback to
403 // the origin one.
404 add_task(async function testFallbackToTheOrigin3() {
405   Services.dns.clearCache(true);
407   trrServer = new TRRServer();
408   await trrServer.start();
409   Services.prefs.setIntPref("network.trr.mode", 3);
410   Services.prefs.setCharPref(
411     "network.trr.uri",
412     `https://foo.example.com:${trrServer.port}/dns-query`
413   );
415   await trrServer.registerDoHAnswers("vulnerable.com", "A", {
416     answers: [
417       {
418         name: "vulnerable.com",
419         ttl: 55,
420         type: "A",
421         flush: false,
422         data: "127.0.0.1",
423       },
424     ],
425   });
427   await trrServer.registerDoHAnswers("vulnerable.com", "HTTPS", {
428     answers: [
429       {
430         name: "vulnerable.com",
431         ttl: 55,
432         type: "HTTPS",
433         flush: false,
434         data: {
435           priority: 1,
436           name: "vulnerable1.com",
437           values: [
438             { key: "alpn", value: ["h2", "h3-26"] },
439             { key: "echconfig", value: "456..." },
440           ],
441         },
442       },
443       {
444         name: "vulnerable.com",
445         ttl: 55,
446         type: "HTTPS",
447         flush: false,
448         data: {
449           priority: 2,
450           name: "vulnerable2.com",
451           values: [
452             { key: "alpn", value: ["h2", "h3-26"] },
453             { key: "echconfig", value: "456..." },
454           ],
455         },
456       },
457       {
458         name: "vulnerable.com",
459         ttl: 55,
460         type: "HTTPS",
461         flush: false,
462         data: {
463           priority: 3,
464           name: "vulnerable3.com",
465           values: [{ key: "alpn", value: ["h2", "h3-26"] }],
466         },
467       },
468     ],
469   });
471   await new TRRDNSListener("vulnerable.com", {
472     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
473   });
475   let chan = makeChan(`https://vulnerable.com:${h2Port}/server-timing`);
476   await channelOpenPromise(chan);
478   await trrServer.stop();
481 add_task(async function testResetExclusionList() {
482   trrServer = new TRRServer();
483   await trrServer.start();
484   Services.prefs.setIntPref("network.trr.mode", 3);
485   Services.prefs.setCharPref(
486     "network.trr.uri",
487     `https://foo.example.com:${trrServer.port}/dns-query`
488   );
489   Services.prefs.setBoolPref(
490     "network.dns.httpssvc.reset_exclustion_list",
491     false
492   );
494   await trrServer.registerDoHAnswers("test.reset.com", "HTTPS", {
495     answers: [
496       {
497         name: "test.reset.com",
498         ttl: 55,
499         type: "HTTPS",
500         flush: false,
501         data: {
502           priority: 1,
503           name: "test.reset1.com",
504           values: [
505             { key: "alpn", value: ["h2", "h3-26"] },
506             { key: "port", value: h2Port },
507             { key: "echconfig", value: "456..." },
508           ],
509         },
510       },
511       {
512         name: "test.reset.com",
513         ttl: 55,
514         type: "HTTPS",
515         flush: false,
516         data: {
517           priority: 2,
518           name: "test.reset2.com",
519           values: [
520             { key: "alpn", value: ["h2", "h3-26"] },
521             { key: "echconfig", value: "456..." },
522           ],
523         },
524       },
525     ],
526   });
528   await new TRRDNSListener("test.reset.com", {
529     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
530   });
532   // After this request, test.reset1.com and test.reset2.com should be both in
533   // the exclusion list.
534   let chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
535   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
537   // This request should be also failed, because all records are excluded.
538   chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
539   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
541   await trrServer.registerDoHAnswers("test.reset1.com", "A", {
542     answers: [
543       {
544         name: "test.reset1.com",
545         ttl: 55,
546         type: "A",
547         flush: false,
548         data: "127.0.0.1",
549       },
550     ],
551   });
553   Services.prefs.setBoolPref(
554     "network.dns.httpssvc.reset_exclustion_list",
555     true
556   );
558   // After enable network.dns.httpssvc.reset_exclustion_list and register
559   // A record for test.reset1.com, this request should be succeeded.
560   chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`);
561   await channelOpenPromise(chan);
563   await trrServer.stop();
566 // Simply test if we can connect to H3 server.
567 add_task(async function testH3Connection() {
568   trrServer = new TRRServer();
569   await trrServer.start();
570   Services.prefs.setIntPref("network.trr.mode", 3);
571   Services.prefs.setCharPref(
572     "network.trr.uri",
573     `https://foo.example.com:${trrServer.port}/dns-query`
574   );
575   Services.prefs.setBoolPref("network.http.http3.enable", true);
577   Services.prefs.setIntPref(
578     "network.dns.httpssvc.http3_fast_fallback_timeout",
579     100
580   );
582   await trrServer.registerDoHAnswers("test.h3.com", "HTTPS", {
583     answers: [
584       {
585         name: "test.h3.com",
586         ttl: 55,
587         type: "HTTPS",
588         flush: false,
589         data: {
590           priority: 1,
591           name: "www.h3.com",
592           values: [
593             { key: "alpn", value: "h3-29" },
594             { key: "port", value: h3Port },
595             { key: "echconfig", value: "456..." },
596           ],
597         },
598       },
599     ],
600   });
602   await trrServer.registerDoHAnswers("www.h3.com", "A", {
603     answers: [
604       {
605         name: "www.h3.com",
606         ttl: 55,
607         type: "A",
608         flush: false,
609         data: "127.0.0.1",
610       },
611     ],
612   });
614   await new TRRDNSListener("test.h3.com", {
615     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
616   });
618   let chan = makeChan(`https://test.h3.com`);
619   let [req] = await channelOpenPromise(chan);
620   Assert.equal(req.protocolVersion, "h3-29");
621   let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
622   Assert.equal(internal.remotePort, h3Port);
624   await trrServer.stop();
627 add_task(async function testFastfallbackToH2() {
628   trrServer = new TRRServer();
629   await trrServer.start();
630   Services.prefs.setIntPref("network.trr.mode", 3);
631   Services.prefs.setCharPref(
632     "network.trr.uri",
633     `https://foo.example.com:${trrServer.port}/dns-query`
634   );
635   Services.prefs.setBoolPref("network.http.http3.enable", true);
636   // Use a short timeout to make sure the fast fallback timer will be triggered.
637   Services.prefs.setIntPref(
638     "network.dns.httpssvc.http3_fast_fallback_timeout",
639     1
640   );
641   Services.prefs.setCharPref(
642     "network.dns.localDomains",
643     "test.fastfallback1.com"
644   );
646   await trrServer.registerDoHAnswers("test.fastfallback.com", "HTTPS", {
647     answers: [
648       {
649         name: "test.fastfallback.com",
650         ttl: 55,
651         type: "HTTPS",
652         flush: false,
653         data: {
654           priority: 1,
655           name: "test.fastfallback1.com",
656           values: [
657             { key: "alpn", value: "h3-29" },
658             { key: "port", value: h3NoResponsePort },
659             { key: "echconfig", value: "456..." },
660           ],
661         },
662       },
663       {
664         name: "test.fastfallback.com",
665         ttl: 55,
666         type: "HTTPS",
667         flush: false,
668         data: {
669           priority: 2,
670           name: "test.fastfallback2.com",
671           values: [
672             { key: "alpn", value: "h2" },
673             { key: "port", value: h2Port },
674             { key: "echconfig", value: "456..." },
675           ],
676         },
677       },
678     ],
679   });
681   await trrServer.registerDoHAnswers("test.fastfallback2.com", "A", {
682     answers: [
683       {
684         name: "test.fastfallback2.com",
685         ttl: 55,
686         type: "A",
687         flush: false,
688         data: "127.0.0.1",
689       },
690     ],
691   });
693   await new TRRDNSListener("test.fastfallback.com", {
694     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
695   });
697   let chan = makeChan(`https://test.fastfallback.com/server-timing`);
698   let [req] = await channelOpenPromise(chan);
699   Assert.equal(req.protocolVersion, "h2");
700   let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
701   Assert.equal(internal.remotePort, h2Port);
703   // Use a longer timeout to test the case that the timer is canceled.
704   Services.prefs.setIntPref(
705     "network.dns.httpssvc.http3_fast_fallback_timeout",
706     5000
707   );
709   chan = makeChan(`https://test.fastfallback.com/server-timing`);
710   [req] = await channelOpenPromise(chan);
711   Assert.equal(req.protocolVersion, "h2");
712   internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
713   Assert.equal(internal.remotePort, h2Port);
715   await trrServer.stop();
718 // Test when we fail to establish H3 connection.
719 add_task(async function testFailedH3Connection() {
720   trrServer = new TRRServer();
721   await trrServer.start();
722   Services.dns.clearCache(true);
723   Services.prefs.setIntPref("network.trr.mode", 3);
724   Services.prefs.setCharPref(
725     "network.trr.uri",
726     `https://foo.example.com:${trrServer.port}/dns-query`
727   );
728   Services.prefs.setBoolPref("network.http.http3.enable", true);
729   Services.prefs.setIntPref(
730     "network.dns.httpssvc.http3_fast_fallback_timeout",
731     0
732   );
734   await trrServer.registerDoHAnswers("test.h3.org", "HTTPS", {
735     answers: [
736       {
737         name: "test.h3.org",
738         ttl: 55,
739         type: "HTTPS",
740         flush: false,
741         data: {
742           priority: 1,
743           name: "www.h3.org",
744           values: [
745             { key: "alpn", value: "h3-29" },
746             { key: "port", value: h3Port },
747             { key: "echconfig", value: "456..." },
748           ],
749         },
750       },
751     ],
752   });
754   await new TRRDNSListener("test.h3.org", {
755     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
756   });
758   let chan = makeChan(`https://test.h3.org`);
759   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
761   await trrServer.stop();
764 // Test we don't use the service mode record whose domain is in
765 // http3 excluded list.
766 add_task(async function testHttp3ExcludedList() {
767   trrServer = new TRRServer();
768   await trrServer.start();
769   Services.dns.clearCache(true);
770   Services.prefs.setIntPref("network.trr.mode", 3);
771   Services.prefs.setCharPref(
772     "network.trr.uri",
773     `https://foo.example.com:${trrServer.port}/dns-query`
774   );
775   Services.prefs.setBoolPref("network.http.http3.enable", true);
776   Services.prefs.setIntPref(
777     "network.dns.httpssvc.http3_fast_fallback_timeout",
778     0
779   );
781   Services.prefs.setCharPref(
782     "network.http.http3.alt-svc-mapping-for-testing",
783     "www.h3_fail.org;h3-29=:" + h3Port
784   );
786   // This will fail because there is no address record for www.h3_fail.org.
787   let chan = makeChan(`https://www.h3_fail.org`);
788   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
790   // Now www.h3_fail.org should be already excluded, so the second record
791   // foo.example.com will be selected.
792   await trrServer.registerDoHAnswers("test.h3_excluded.org", "HTTPS", {
793     answers: [
794       {
795         name: "test.h3_excluded.org",
796         ttl: 55,
797         type: "HTTPS",
798         flush: false,
799         data: {
800           priority: 1,
801           name: "www.h3_fail.org",
802           values: [
803             { key: "alpn", value: "h3-29" },
804             { key: "port", value: h3Port },
805           ],
806         },
807       },
808       {
809         name: "test.h3_excluded.org",
810         ttl: 55,
811         type: "HTTPS",
812         flush: false,
813         data: {
814           priority: 2,
815           name: "foo.example.com",
816           values: [
817             { key: "alpn", value: "h3-29" },
818             { key: "port", value: h3Port },
819           ],
820         },
821       },
822     ],
823   });
825   await new TRRDNSListener("test.h3_excluded.org", {
826     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
827   });
829   chan = makeChan(`https://test.h3_excluded.org`);
830   let [req] = await channelOpenPromise(chan);
831   Assert.equal(req.protocolVersion, "h3-29");
832   let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
833   Assert.equal(internal.remotePort, h3Port);
835   await trrServer.stop();
838 add_task(async function testAllRecordsInHttp3ExcludedList() {
839   trrServer = new TRRServer();
840   await trrServer.start();
841   Services.dns.clearCache(true);
842   Services.prefs.setIntPref("network.trr.mode", 3);
843   Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true);
844   Services.prefs.setCharPref(
845     "network.trr.uri",
846     `https://foo.example.com:${trrServer.port}/dns-query`
847   );
848   Services.prefs.setBoolPref("network.http.http3.enable", true);
849   Services.prefs.setIntPref(
850     "network.dns.httpssvc.http3_fast_fallback_timeout",
851     0
852   );
854   Services.prefs.setCharPref(
855     "network.http.http3.alt-svc-mapping-for-testing",
856     "www.h3_fail1.org;h3-29=:" + h3Port
857   );
859   await trrServer.registerDoHAnswers("www.h3_all_excluded.org", "A", {
860     answers: [
861       {
862         name: "www.h3_all_excluded.org",
863         ttl: 55,
864         type: "A",
865         flush: false,
866         data: "127.0.0.1",
867       },
868     ],
869   });
871   // Test we can connect to www.h3_all_excluded.org sucessfully.
872   let chan = makeChan(
873     `https://www.h3_all_excluded.org:${h2Port}/server-timing`
874   );
876   let [req] = await channelOpenPromise(chan);
878   // Test if this request is done by h2.
879   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
881   // This will fail because there is no address record for www.h3_fail1.org.
882   chan = makeChan(`https://www.h3_fail1.org`);
883   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
885   Services.prefs.setCharPref(
886     "network.http.http3.alt-svc-mapping-for-testing",
887     "www.h3_fail2.org;h3-29=:" + h3Port
888   );
890   // This will fail because there is no address record for www.h3_fail2.org.
891   chan = makeChan(`https://www.h3_fail2.org`);
892   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
894   await trrServer.registerDoHAnswers("www.h3_all_excluded.org", "HTTPS", {
895     answers: [
896       {
897         name: "www.h3_all_excluded.org",
898         ttl: 55,
899         type: "HTTPS",
900         flush: false,
901         data: {
902           priority: 1,
903           name: "www.h3_fail1.org",
904           values: [
905             { key: "alpn", value: "h3-29" },
906             { key: "port", value: h3Port },
907             { key: "echconfig", value: "456..." },
908           ],
909         },
910       },
911       {
912         name: "www.h3_all_excluded.org",
913         ttl: 55,
914         type: "HTTPS",
915         flush: false,
916         data: {
917           priority: 2,
918           name: "www.h3_fail2.org",
919           values: [
920             { key: "alpn", value: "h3-29" },
921             { key: "port", value: h3Port },
922             { key: "echconfig", value: "456..." },
923           ],
924         },
925       },
926     ],
927   });
929   await new TRRDNSListener("www.h3_all_excluded.org", {
930     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
931   });
933   Services.dns.clearCache(true);
934   Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
935   Services.obs.notifyObservers(null, "net:prune-all-connections");
937   // All HTTPS RRs are in http3 excluded list and all records are failed to
938   // connect, so don't fallback to the origin one.
939   chan = makeChan(`https://www.h3_all_excluded.org:${h2Port}/server-timing`);
940   await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL);
942   await trrServer.registerDoHAnswers("www.h3_fail1.org", "A", {
943     answers: [
944       {
945         name: "www.h3_fail1.org",
946         ttl: 55,
947         type: "A",
948         flush: false,
949         data: "127.0.0.1",
950       },
951     ],
952   });
954   // The the case that when all records are in http3 excluded list, we still
955   // give the first record one more shot.
956   chan = makeChan(`https://www.h3_all_excluded.org`);
957   [req] = await channelOpenPromise(chan);
958   Assert.equal(req.protocolVersion, "h3-29");
959   let internal = req.QueryInterface(Ci.nsIHttpChannelInternal);
960   Assert.equal(internal.remotePort, h3Port);
962   await trrServer.stop();
965 WebSocketListener.prototype = {
966   onAcknowledge(aContext, aSize) {},
967   onBinaryMessageAvailable(aContext, aMsg) {},
968   onMessageAvailable(aContext, aMsg) {},
969   onServerClose(aContext, aCode, aReason) {},
970   onStart(aContext) {
971     this.finish();
972   },
973   onStop(aContext, aStatusCode) {},
976 add_task(async function testUpgradeNotUsingHTTPSRR() {
977   trrServer = new TRRServer();
978   await trrServer.start();
979   Services.prefs.setIntPref("network.trr.mode", 3);
980   Services.prefs.setCharPref(
981     "network.trr.uri",
982     `https://foo.example.com:${trrServer.port}/dns-query`
983   );
985   await trrServer.registerDoHAnswers("test.ws.com", "HTTPS", {
986     answers: [
987       {
988         name: "test.ws.com",
989         ttl: 55,
990         type: "HTTPS",
991         flush: false,
992         data: {
993           priority: 1,
994           name: "test.ws1.com",
995           values: [{ key: "port", value: ["8888"] }],
996         },
997       },
998     ],
999   });
1001   await new TRRDNSListener("test.ws.com", {
1002     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
1003   });
1005   await trrServer.registerDoHAnswers("test.ws.com", "A", {
1006     answers: [
1007       {
1008         name: "test.ws.com",
1009         ttl: 55,
1010         type: "A",
1011         flush: false,
1012         data: "127.0.0.1",
1013       },
1014     ],
1015   });
1017   let wssUri = "wss://test.ws.com:" + h2Port + "/websocket";
1018   let chan = Cc["@mozilla.org/network/protocol;1?name=wss"].createInstance(
1019     Ci.nsIWebSocketChannel
1020   );
1021   chan.initLoadInfo(
1022     null, // aLoadingNode
1023     Services.scriptSecurityManager.getSystemPrincipal(),
1024     null, // aTriggeringPrincipal
1025     Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
1026     Ci.nsIContentPolicy.TYPE_DOCUMENT
1027   );
1029   var uri = Services.io.newURI(wssUri);
1030   var wsListener = new WebSocketListener();
1031   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
1032     false
1033   );
1034   await new Promise(resolve => {
1035     wsListener.finish = resolve;
1036     chan.asyncOpen(uri, wssUri, {}, 0, wsListener, null);
1037     certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
1038       true
1039     );
1040   });
1042   await trrServer.stop();
1045 // Test if we fallback to h2 with echConfig.
1046 add_task(async function testFallbackToH2WithEchConfig() {
1047   trrServer = new TRRServer();
1048   await trrServer.start();
1049   Services.dns.clearCache(true);
1050   Services.prefs.setIntPref("network.trr.mode", 3);
1051   Services.prefs.setCharPref(
1052     "network.trr.uri",
1053     `https://foo.example.com:${trrServer.port}/dns-query`
1054   );
1055   Services.prefs.setBoolPref("network.http.http3.enable", true);
1056   Services.prefs.setIntPref(
1057     "network.dns.httpssvc.http3_fast_fallback_timeout",
1058     0
1059   );
1061   await trrServer.registerDoHAnswers("test.fallback.org", "HTTPS", {
1062     answers: [
1063       {
1064         name: "test.fallback.org",
1065         ttl: 55,
1066         type: "HTTPS",
1067         flush: false,
1068         data: {
1069           priority: 1,
1070           name: "test.fallback.org",
1071           values: [
1072             { key: "alpn", value: ["h2", "h3-29"] },
1073             { key: "port", value: h2Port },
1074             { key: "echconfig", value: "456..." },
1075           ],
1076         },
1077       },
1078     ],
1079   });
1081   await trrServer.registerDoHAnswers("test.fallback.org", "A", {
1082     answers: [
1083       {
1084         name: "test.fallback.org",
1085         ttl: 55,
1086         type: "A",
1087         flush: false,
1088         data: "127.0.0.1",
1089       },
1090     ],
1091   });
1093   await new TRRDNSListener("test.fallback.org", {
1094     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
1095   });
1097   await new TRRDNSListener("test.fallback.org", "127.0.0.1");
1099   let chan = makeChan(`https://test.fallback.org/server-timing`);
1100   let [req] = await channelOpenPromise(chan);
1101   // Test if this request is done by h2.
1102   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
1104   await trrServer.stop();