mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
102 lines
3.5 KiB
JavaScript
102 lines
3.5 KiB
JavaScript
|
'use strict';
|
||
|
const common = require('../common');
|
||
|
const assert = require('assert');
|
||
|
if (!common.hasCrypto) common.skip('missing crypto');
|
||
|
const fixtures = require('../common/fixtures');
|
||
|
const tls = require('tls');
|
||
|
const net = require('net');
|
||
|
|
||
|
// Sending tls data on a server TLSSocket with an active write led to a crash:
|
||
|
//
|
||
|
// node[1296]: ../src/crypto/crypto_tls.cc:963:virtual int node::crypto::TLSWrap::DoWrite(node::WriteWrap*,
|
||
|
// uv_buf_t*, size_t, uv_stream_t*): Assertion `!current_write_' failed.
|
||
|
// 1: 0xb090e0 node::Abort() [node]
|
||
|
// 2: 0xb0915e [node]
|
||
|
// 3: 0xca8413 node::crypto::TLSWrap::DoWrite(node::WriteWrap*, uv_buf_t*, unsigned long, uv_stream_s*) [node]
|
||
|
// 4: 0xcaa549 node::StreamBase::Write(uv_buf_t*, unsigned long, uv_stream_s*, v8::Local<v8::Object>) [node]
|
||
|
// 5: 0xca88d7 node::crypto::TLSWrap::EncOut() [node]
|
||
|
// 6: 0xca9ba8 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
|
||
|
// 7: 0xca8eb0 node::crypto::TLSWrap::ClearOut() [node]
|
||
|
// 8: 0xca9ba0 node::crypto::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
|
||
|
// 9: 0xbe50dd node::LibuvStreamWrap::OnUvRead(long, uv_buf_t const*) [node]
|
||
|
// 10: 0xbe54c4 [node]
|
||
|
// 11: 0x15583d7 [node]
|
||
|
// 12: 0x1558c00 [node]
|
||
|
// 13: 0x155ede4 [node]
|
||
|
// 14: 0x154d008 uv_run [node]
|
||
|
|
||
|
const serverReplaySize = 2 * 1024 * 1024;
|
||
|
|
||
|
(async function() {
|
||
|
const tlsClientHello = await getClientHello();
|
||
|
|
||
|
const subserver = tls.createServer({
|
||
|
key: fixtures.readKey('agent1-key.pem'),
|
||
|
cert: fixtures.readKey('agent1-cert.pem'),
|
||
|
ALPNCallback: common.mustCall(({ sn, protocols }) => {
|
||
|
// Once `subserver` receives `tlsClientHello` from the underlying net.Socket,
|
||
|
// in this test, a TLSSocket actually, it should be able to proceed to the handshake
|
||
|
// and emit this event
|
||
|
assert.strictEqual(protocols[0], 'h2');
|
||
|
return 'h2';
|
||
|
}),
|
||
|
});
|
||
|
|
||
|
const server = tls.createServer({
|
||
|
key: fixtures.readKey('agent1-key.pem'),
|
||
|
cert: fixtures.readKey('agent1-cert.pem'),
|
||
|
})
|
||
|
.listen(startClient)
|
||
|
.on('secureConnection', (serverTlsSock) => {
|
||
|
// Craft writes that are large enough to stuck in sending
|
||
|
// In reality this can be a 200 response to the incoming HTTP CONNECT
|
||
|
const half = Buffer.alloc(serverReplaySize / 2, 0);
|
||
|
serverTlsSock.write(half, common.mustSucceed());
|
||
|
serverTlsSock.write(half, common.mustSucceed());
|
||
|
|
||
|
subserver.emit('connection', serverTlsSock);
|
||
|
});
|
||
|
|
||
|
|
||
|
function startClient() {
|
||
|
const clientTlsSock = tls.connect({
|
||
|
host: '127.0.0.1',
|
||
|
port: server.address().port,
|
||
|
rejectUnauthorized: false,
|
||
|
});
|
||
|
|
||
|
const recv = [];
|
||
|
let revcLen = 0;
|
||
|
clientTlsSock.on('data', (chunk) => {
|
||
|
revcLen += chunk.length;
|
||
|
recv.push(chunk);
|
||
|
if (revcLen > serverReplaySize) {
|
||
|
// Check the server's replay is followed by the subserver's TLS ServerHello
|
||
|
const serverHelloFstByte = Buffer.concat(recv).subarray(serverReplaySize, serverReplaySize + 1);
|
||
|
assert.strictEqual(serverHelloFstByte.toString('hex'), '16');
|
||
|
process.exit(0);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// In reality, one may want to send a HTTP CONNECT before starting this double TLS
|
||
|
clientTlsSock.write(tlsClientHello);
|
||
|
}
|
||
|
})().then(common.mustCall());
|
||
|
|
||
|
function getClientHello() {
|
||
|
return new Promise((resolve) => {
|
||
|
const server = net.createServer((sock) => {
|
||
|
sock.on('data', (chunk) => {
|
||
|
resolve(chunk);
|
||
|
});
|
||
|
})
|
||
|
.listen(() => {
|
||
|
tls.connect({
|
||
|
port: server.address().port,
|
||
|
host: '127.0.0.1',
|
||
|
ALPNProtocols: ['h2'],
|
||
|
}).on('error', () => {});
|
||
|
});
|
||
|
});
|
||
|
}
|