Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

  • This test gets skipped with pattern: os == 'android' OR os == 'win' && os_version == '10.2009' && arch == 'x86_64' OR os == 'win' && os_version == '11.26100' && arch == 'x86' OR os == 'win' && os_version == '11.26100' && arch == 'x86_64'
  • Manifest: netwerk/test/unit/xpcshell.toml
/* 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/. */
var { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
const { NodeHTTP2Server } = ChromeUtils.importESModule(
);
registerCleanupFunction(async () => {
http3_clear_prefs();
Services.prefs.clearUserPref("network.http.http3.0rtt_timeout");
});
add_task(async function setup() {
await http3_setup_tests("h3");
});
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));
});
}
// Test the normal case.
add_task(async function test_0rtt_timeout_normal_operation() {
info("Testing 0-RTT timeout with normal operation");
// Enable 0-RTT
Services.prefs.setBoolPref("network.http.http3.enable_0rtt", true);
Services.prefs.setIntPref("network.http.http3.0rtt_timeout", 5000);
// Clear any existing connections
Services.obs.notifyObservers(null, "net:cancel-all-connections");
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
// Make first request to establish a resumable session
let chan = makeChan("https://foo.example.com/30");
let [req] = await channelOpenPromise(chan);
Assert.equal(req.status, Cr.NS_OK);
// Wait to ensure session info is saved
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 500));
// Clear connections to force new connection with 0-RTT
Services.obs.notifyObservers(null, "net:cancel-all-connections");
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
// Make multiple requests - they should all succeed quickly
// (well under the 5 second timeout)
let promises = [];
for (let i = 0; i < 3; i++) {
promises.push(channelOpenPromise(c));
}
await Promise.all(promises);
});
// Test whether all transactions is successfully restarted.
add_task(async function test_stuck_0rtt_session() {
info("Testing stuck 0-RTT session timeout");
// Start a separate HTTP/3 server for this test
let h3Port = await create_h3_server();
Assert.notEqual(h3Port, null);
info(`Started H3 test server on port ${h3Port}`);
// Start HTTP/2 server on the same port for fallback
let h2Server = new NodeHTTP2Server();
await h2Server.start(h3Port);
registerCleanupFunction(async () => {
await h2Server.stop();
});
// Register a simple handler for the H2 server
await h2Server.registerPathHandler("/30", (_req, resp) => {
resp.writeHead(200, { "content-type": "text/plain" });
resp.end("H2 fallback response");
});
info(`Started H2 fallback server on port ${h3Port}`);
// Configure for a different hostname
// The origin will use h3Port, and H3 is the alt-svc
let testHost = "alt1.example.com";
Services.prefs.setCharPref("network.dns.localDomains", testHost);
Services.prefs.setCharPref(
"network.http.http3.alt-svc-mapping-for-testing",
`${testHost};h3=:${h3Port}`
);
function makeStuckTestChan(path) {
let chan = NetUtil.newChannel({
uri: `https://${testHost}:${h3Port}${path}`,
loadUsingSystemPrincipal: true,
}).QueryInterface(Ci.nsIHttpChannel);
chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
return chan;
}
// Clear any existing connections
Services.obs.notifyObservers(null, "net:cancel-all-connections");
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
// Make first request to establish a resumable session
info("Establishing initial session for 0-RTT");
let chan = makeStuckTestChan("/30");
let [req] = await channelOpenPromise(chan);
Assert.equal(req.status, Cr.NS_OK);
// Wait to ensure session info is saved
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 500));
// Tell the server to enable stuck 0-RTT mode for the next connection
info("Enabling stuck 0-RTT mode on test server");
let setupChan = makeStuckTestChan("/SetStuckZeroRtt");
let [setupReq] = await channelOpenPromise(setupChan);
Assert.equal(setupReq.status, Cr.NS_OK);
info("Stuck 0-RTT mode enabled on server");
// Wait a bit
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 500));
// Clear connections to force a new 0-RTT connection
Services.obs.notifyObservers(null, "net:cancel-all-connections");
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
info("Making multiple requests that will encounter stuck 0-RTT session");
let numRequests = 3;
let promises = [];
let startTime = Date.now();
for (let i = 0; i < numRequests; i++) {
let stuckChan = makeStuckTestChan(`/30?stuck_test=${i}`);
promises.push(channelOpenPromise(stuckChan, CL_ALLOW_UNKNOWN_CL));
}
// Wait for all requests to complete
let results = await Promise.all(promises);
let elapsed = Date.now() - startTime;
info(`All ${numRequests} requests completed after ${elapsed}ms`);
// Verify all requests completed successfully with H2 fallback
results.forEach(([req, buffer], index) => {
Assert.equal(req.status, Cr.NS_OK, `Request ${index} should succeed`);
Assert.equal(
buffer,
"H2 fallback response",
`Request ${index} should receive H2 fallback response`
);
info(`Request ${index} completed successfully with H2 fallback`);
});
// All requests should complete within a reasonable time
Assert.less(
elapsed,
10000,
"All requests should complete within 10 seconds via fallback"
);
});