commit e04cde4661e40755a08d2d7565f50e5b4f84321b
parent f8266ef232f7d811e1bf943a5d577a23de4667c6
Author: Kershaw Chang <kershaw@mozilla.com>
Date: Thu, 2 Oct 2025 19:49:27 +0000
Bug 1990699 - Allow fallback to coalescing connection, r=necko-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D267200
Diffstat:
3 files changed, 107 insertions(+), 0 deletions(-)
diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3453,6 +3453,9 @@ ConnectionEntry* nsHttpConnectionMgr::GetOrCreateConnectionEntry(
("GetOrCreateConnectionEntry is coalescing h2/3 an/onymous "
"connections, ent=%p",
invertedEnt));
+ if (aAvailableForDispatchNow) {
+ *aAvailableForDispatchNow = true;
+ }
return invertedEnt;
}
}
diff --git a/netwerk/test/unit/test_http3_fallback_anonymous_conn.js b/netwerk/test/unit/test_http3_fallback_anonymous_conn.js
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* import-globals-from head_http3.js */
+
+const { NodeHTTP2Server } = ChromeUtils.importESModule(
+ "resource://testing-common/NodeServer.sys.mjs"
+);
+
+function makeChan(uri) {
+ let chan = NetUtil.newChannel({
+ uri,
+ loadUsingSystemPrincipal: true,
+ }).QueryInterface(Ci.nsIHttpChannel);
+ chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
+ return chan;
+}
+
+function channelOpenPromise(chan, flags) {
+ return new Promise(resolve => {
+ function finish(req, buffer) {
+ resolve([req, buffer]);
+ }
+ chan.asyncOpen(new ChannelListener(finish, null, flags));
+ });
+}
+
+add_setup(async function setup() {
+ Services.prefs.setCharPref("network.dns.localDomains", "alt1.example.com");
+
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+ );
+ addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
+ addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
+
+ // A dummy request to make sure AltSvcCache::mStorage is ready.
+ let chan = makeChan(`https://localhost`);
+ await channelOpenPromise(chan, CL_EXPECT_FAILURE);
+});
+
+add_task(async function test_fallback() {
+ // We only need the `noResponsePort`, not the masque proxy.
+ const { noResponsePort } = await create_masque_proxy_server();
+
+ Services.prefs.setCharPref(
+ "network.http.http3.alt-svc-mapping-for-testing",
+ `alt1.example.com;h3=:${noResponsePort}`
+ );
+
+ let server = new NodeHTTP2Server();
+ await server.start(noResponsePort);
+
+ Assert.equal(server.port(), noResponsePort);
+
+ await server.registerPathHandler("/request1", (req, resp) => {
+ resp.writeHead(200);
+ resp.end("response1");
+ });
+ await server.registerPathHandler("/request2", (req, resp) => {
+ resp.writeHead(200);
+ resp.end("response2");
+ });
+
+ registerCleanupFunction(async () => {
+ await server.stop();
+ });
+
+ let chan = makeChan(
+ `${server.protocol()}://alt1.example.com:${server.port()}/request1`
+ );
+ let [req, buf] = await channelOpenPromise(
+ chan,
+ CL_IGNORE_CL | CL_ALLOW_UNKNOWN_CL
+ );
+ Assert.equal(req.protocolVersion, "h2");
+ Assert.equal(buf, "response1");
+
+ let chan1 = makeChan(
+ `${server.protocol()}://alt1.example.com:${server.port()}/request2`
+ );
+ chan1.loadFlags = Ci.nsIRequest.LOAD_ANONYMOUS;
+ [req, buf] = await Promise.race([
+ channelOpenPromise(chan1, CL_IGNORE_CL | CL_ALLOW_UNKNOWN_CL),
+ // chan1 should be completed within a short time.
+ new Promise(resolve => {
+ do_timeout(3000, resolve);
+ }),
+ ]);
+ Assert.equal(req.protocolVersion, "h2");
+ Assert.equal(buf, "response2");
+
+ await server.stop();
+});
diff --git a/netwerk/test/unit/xpcshell.toml b/netwerk/test/unit/xpcshell.toml
@@ -788,6 +788,13 @@ skip-if = [
run-sequentially = ["true"] # node server exceptions dont replay well
skip-if = ["os == 'win' && os_version == '11.26100' && processor == 'x86_64' && msix"] # Bug 1807931
+["test_http3_fallback_anonymous_conn.js"]
+run-sequentially = ["true"] # node server exceptions dont replay well
+skip-if = [
+ "os == 'android'",
+ "os == 'win' && os_version == '11.26100' && processor == 'x86_64' && msix'", # Bug 1808049
+]
+
["test_http3_fast_fallback.js"]
run-sequentially = ["true"] # node server exceptions dont replay well
skip-if = [