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 });