/* 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";
var { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
const { HTTP3Server } = ChromeUtils.importESModule(
"resource://testing-common/NodeServer.sys.mjs"
);
let trrServer;
let h3NoResponsePort;
let tcpNoResponseSocket;
let tcpNoResponsePort;
add_setup(async
function () {
h3NoResponsePort = Services.env.get(
"MOZHTTP3_PORT_NO_RESPONSE");
Assert.notEqual(h3NoResponsePort,
null);
Assert.notEqual(h3NoResponsePort,
"");
let h3ServerPath = Services.env.get(
"MOZ_HTTP3_SERVER_PATH");
let h3DBPath = Services.env.get(
"MOZ_HTTP3_CERT_DB_PATH");
let server =
new HTTP3Server();
await server.start(h3ServerPath, h3DBPath);
tcpNoResponsePort = server.no_response_port();
// A TCP server socket that listens but never accepts connections.
// TCP handshake completes (OS handles SYN/SYN-ACK) but TLS never starts.
tcpNoResponseSocket = Cc[
"@mozilla.org/network/server-socket;1"
].createInstance(Ci.nsIServerSocket);
tcpNoResponseSocket.init(tcpNoResponsePort,
true, -
1);
let certdb = Cc[
"@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
addCertFromFile(certdb,
"http2-ca.pem",
"CTu,u,u");
Services.prefs.setBoolPref(
"network.http.happy_eyeballs_enabled",
true);
trrServer =
new TRRServer();
await trrServer.start();
trr_test_setup();
Services.prefs.setIntPref(
"network.trr.mode",
3);
Services.prefs.setCharPref(
"network.trr.uri",
`https:
//foo.example.com:${trrServer.port()}/dns-query`
);
registerCleanupFunction(async () => {
Services.prefs.clearUserPref(
"network.http.happy_eyeballs_enabled");
Services.prefs.clearUserPref(
"network.http.speculative-parallel-limit");
Services.prefs.clearUserPref(
"network.http.http3.alt-svc-mapping-for-testing"
);
trr_clear_prefs();
if (trrServer) {
await trrServer.stop();
}
if (tcpNoResponseSocket) {
tcpNoResponseSocket.close();
}
await server.stop();
});
});
async
function resetConnections() {
Services.obs.notifyObservers(
null,
"net:cancel-all-connections");
let nssComponent = Cc[
"@mozilla.org/psm;1"].getService(Ci.nsINSSComponent);
await nssComponent.asyncClearSSLExternalAndInternalSessionCache();
Services.dns.clearCache(
true);
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await
new Promise(resolve => setTimeout(resolve,
1000));
}
async
function do_test_h3_no_response(host) {
await resetConnections();
let chan = NetUtil.newChannel({
uri: `https:
//${host}:${tcpNoResponsePort}/`,
loadUsingSystemPrincipal:
true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
}).QueryInterface(Ci.nsIHttpChannel);
chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
await
new Promise(resolve => {
chan.asyncOpen(
new ChannelListener(
(req, _buf) => {
Assert.ok(
!Components.isSuccessCode(req.status),
`Channel should fail, status=
0x${req.status.toString(
16)}`
);
Assert.equal(
req.status,
Cr.NS_ERROR_NET_TIMEOUT,
"Request should fail with NS_ERROR_NET_TIMEOUT"
);
resolve();
},
null,
CL_EXPECT_FAILURE
)
);
});
}
add_task(async
function test_h3_connection_no_response() {
Services.prefs.setIntPref(
"network.http.connection-timeout",
2);
let host =
"noresponse.example.com";
Services.prefs.setCharPref(
"network.http.http3.alt-svc-mapping-for-testing",
`${host};h3=:${h3NoResponsePort}`
);
await trrServer.registerDoHAnswers(host,
"A", {
answers: [
{ name: host, ttl:
55, type:
"A", flush:
false, data:
"127.0.0.1" },
],
});
Services.prefs.setIntPref(
"network.http.speculative-parallel-limit",
0);
await do_test_h3_no_response(host);
Services.prefs.setIntPref(
"network.http.speculative-parallel-limit",
6);
await do_test_h3_no_response(host);
Services.prefs.clearUserPref(
"network.http.connection-timeout");
Services.prefs.clearUserPref(
"network.http.http3.alt-svc-mapping-for-testing"
);
});