Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
"use strict";
// Closing the connection right after accepting it, before any response is
// sent, surfaces as NS_ERROR_NET_RESET.
function startDropServer() {
const server = Cc["@mozilla.org/network/server-socket;1"].createInstance(
Ci.nsIServerSocket
);
server.init(-1, true, -1);
server.asyncListen({
onSocketAccepted(socket, transport) {
transport.close(Cr.NS_OK);
},
onStopListening() {},
});
registerCleanupFunction(() => server.close());
return server.port;
}
// nsITLSServerSocket needs a certificate with a corresponding private key
// available. In mochitests, the certificate with the common name "Mochitest
// client" has such a key.
async function getTestServerCertificate() {
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
for (const cert of await certDB.getCerts()) {
if (cert.commonName == "Mochitest client") {
return cert;
}
}
return null;
}
// Completes the TLS handshake, then closes the connection right after, also
// surfacing as NS_ERROR_NET_RESET (see browser_navigation_failures.js).
function startTLSDropServer(cert) {
const server = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
Ci.nsITLSServerSocket
);
server.init(-1, true, -1);
server.serverCert = cert;
let input, output;
const listener = {
onSocketAccepted(socket, transport) {
const connectionInfo = transport.securityCallbacks.getInterface(
Ci.nsITLSServerConnectionInfo
);
connectionInfo.setSecurityObserver(listener);
input = transport.openInputStream(0, 0, 0);
output = transport.openOutputStream(0, 0, 0);
},
onHandshakeDone() {
input.asyncWait(
{
onInputStreamReady() {
input.close();
output.close();
},
},
0,
0,
Services.tm.currentThread
);
},
onStopListening() {},
};
server.setSessionTickets(false);
server.asyncListen(listener);
registerCleanupFunction(() => server.close());
return server;
}
async function loadDroppedConnectionErrorPage(url) {
let browser, tab;
let pageLoaded;
await BrowserTestUtils.openNewForegroundTab(
gBrowser,
() => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, url);
browser = gBrowser.selectedBrowser;
tab = gBrowser.selectedTab;
pageLoaded = BrowserTestUtils.waitForErrorPage(browser);
},
false
);
await pageLoaded;
return { browser, tab };
}
add_task(async function test_netReset_from_dropped_connection_http() {
const port = startDropServer();
const { browser, tab } = await loadDroppedConnectionErrorPage(
);
await SpecialPowers.spawn(browser, [], () => {
Assert.ok(
content.document.documentURI.includes("e=netReset"),
"A dropped http connection shows the netReset error page"
);
});
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_netReset_from_dropped_connection_https() {
await SpecialPowers.pushPrefEnv({
// This test fails on some platforms if we leave IPv6 enabled.
set: [["network.dns.disableIPv6", true]],
});
const certOverrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
const cert = await getTestServerCertificate();
const server = startTLSDropServer(cert);
certOverrideService.rememberValidityOverride(
"localhost",
server.port,
{},
cert,
true
);
registerCleanupFunction(() => {
certOverrideService.clearValidityOverride("localhost", server.port, {});
});
const { browser, tab } = await loadDroppedConnectionErrorPage(
`https://localhost:${server.port}/`
);
await SpecialPowers.spawn(browser, [], () => {
Assert.ok(
content.document.documentURI.includes("e=netReset"),
"A dropped https connection shows the netReset error page"
);
});
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_netReset_error_page_elements() {
const { browser, tab } = await loadNetErrorPage("netReset", "127.0.0.1");
await SpecialPowers.spawn(browser, [], async function () {
await ContentTaskUtils.waitForCondition(
() => content?.document?.querySelector("net-error-card"),
"Wait for net-error-card to render"
);
const doc = content.document;
const netErrorCard = doc.querySelector("net-error-card").wrappedJSObject;
await netErrorCard.getUpdateComplete();
Assert.equal(
netErrorCard.errorTitle.dataset.l10nId,
"netReset-title",
"Using the netReset title"
);
Assert.equal(
netErrorCard.errorIntro.dataset.l10nId,
"fp-neterror-offline-intro",
"Using the netReset intro"
);
const list = netErrorCard.renderRoot.querySelector(".what-can-you-do-list");
Assert.ok(list, "NetErrorCard has what-can-you-do list");
Assert.ok(
list.querySelector('[data-l10n-id="neterror-load-error-try-again"]'),
"List includes try-again item"
);
Assert.ok(
list.querySelector('[data-l10n-id="neterror-load-error-connection"]'),
"List includes connection item"
);
Assert.ok(
list.querySelector('[data-l10n-id="neterror-load-error-firewall"]'),
"List includes firewall item"
);
Assert.ok(
ContentTaskUtils.isVisible(netErrorCard.tryAgainButton),
"The 'Try Again' button is shown"
);
Assert.ok(
!netErrorCard.renderRoot.querySelector(
'[data-l10n-id="fp-cert-error-code"]'
),
"No error code is shown for netReset"
);
});
BrowserTestUtils.removeTab(tab);
});