'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const https = require('https');
const { Writable, pipeline } = require('stream');
const fixtures = require('../common/fixtures');
// Verify error propagation after receiving response headers. The invalid
// record deliberately causes a TLS error; it does not reproduce #66001's
// failure to decrypt an intact stream under backpressure.
for (const version of ['TLSv1.2', 'TLSv1.3']) {
let transport;
let requestError;
const events = [];
const server = https.createServer({
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
minVersion: version,
maxVersion: version,
}, common.mustCall((req, res) => {
res.writeHead(200, { 'Content-Length': 100 });
res.write('partial body');
}));
server.on('connection', common.mustCall((socket) => {
transport = socket;
}));
server.listen(0, common.mustCall(() => {
const req = https.get({
port: server.address().port,
rejectUnauthorized: false,
agent: false,
}, common.mustCall((res) => {
assert.strictEqual(res.complete, false);
res.on('aborted', common.mustCall(() => events.push('aborted')));
res.on('error', common.mustCall((err) => {
events.push('response error');
assert.strictEqual(err.code, 'ECONNRESET');
assert.strictEqual(err.message, 'aborted');
assert.strictEqual(err.cause, requestError);
}));
res.on('close', common.mustCall(() => {
events.push('response close');
assert.deepStrictEqual(events, [
'request error',
'aborted',
'request close',
'response error',
'response close',
]);
}));
pipeline(res, new Writable({
write(chunk, encoding, callback) {
callback();
},
}), common.mustCall((err) => {
assert.strictEqual(err, res.errored);
assert.strictEqual(err.cause, requestError);
assert.strictEqual(res.complete, false);
assert.strictEqual(res.aborted, true);
server.close(common.mustCall());
transport.destroy();
}));
// Bypass the server's TLSSocket to send an invalid application-data
// record after the client has received part of the HTTP response.
const record = Buffer.alloc(37);
record.set([23, 3, 3, 0, 32]);
transport.write(record);
}));
req.on('error', common.mustCall((err) => {
events.push('request error');
assert.match(err.code, /^ERR_SSL_/);
requestError = err;
}));
req.on('close', common.mustCall(() => events.push('request close')));
}));
}