Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* 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/. */
// When a TLS server drops the connection (sends FIN) before completing the
// handshake, NSS reports PR_END_OF_FILE_ERROR on the first read. With
// security.tls.version.min == max (set via xpcshell.toml prefs),
// rememberIntolerantAtVersion returns false immediately (intolerant <=
// minVersion), so retryDueToTLSIntolerance returns false and the raw
// PR_END_OF_FILE_ERROR propagates to nsSocketTransport2.
//
// nsSocketTransport2 now maps PR_END_OF_FILE_ERROR to NS_ERROR_NET_RESET
// (previously NS_ERROR_NET_INTERRUPT), triggering an automatic HTTP transaction
// retry that succeeds on the second connection.
//
// Regression test for Bug 2001565.
"use strict";
const { NodeHTTPServer, with_node_servers } = ChromeUtils.importESModule(
);
// Executed in the Node.js process: creates a raw TCP server that half-closes
// the first connection (before TLS), then completes TLS and serves HTTP/1.1
// 200 OK for subsequent connections. Returns the listening port.
function setupDropServer() {
const net = require("net");
const tls = require("tls");
const fs = require("fs");
const path = require("path");
let connCount = 0;
const certOptions = {
isServer: true,
key: fs.readFileSync(path.join(__dirname, "http2-cert.key")),
cert: fs.readFileSync(path.join(__dirname, "http2-cert.pem")),
ALPNProtocols: ["http/1.1"],
};
const dropServer = net.createServer(rawSocket => {
if (++connCount === 1) {
rawSocket.end();
return;
}
const tlsSocket = new tls.TLSSocket(rawSocket, certOptions);
let reqData = "";
tlsSocket.on("data", chunk => {
reqData += chunk.toString();
if (reqData.includes("\r\n\r\n")) {
tlsSocket.write(
"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n" +
"Content-Type: text/plain\r\n\r\nok"
);
tlsSocket.end();
}
});
tlsSocket.on("error", () => {});
});
// ADB is loaded into the Node.js process by NodeHTTPServer.start().
// listenAndForwardPort handles Android port forwarding so the test works
// when xpcshell runs on-device via adb.
return ADB.listenAndForwardPort(dropServer, 0); // eslint-disable-line no-undef
}
add_task(async function test_eof_retry() {
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
await with_node_servers([NodeHTTPServer], async server => {
let dropPort = await server.execute(`(${setupDropServer})()`);
let [req] = await channelOpenPromise(
makeChan(`https://localhost:${dropPort}/test`),
0
);
equal(req.status, Cr.NS_OK);
equal(req.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200);
});
});