0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/test/parallel/test-http2-create-client-connect.js
Denys Otrishko be3c7aceba
http2: wait for session socket writable end on close/destroy
This slightly alters the behaviour of session close by first using
.end() on a session socket to finish writing the data and only then
calls .destroy() to make sure the Readable side is closed. This allows
the socket to finish transmitting data, receive proper FIN packet and
avoid ECONNRESET errors upon graceful close.

onStreamClose now directly calls stream.destroy() instead of
kMaybeDestroy because the latter will first check that the stream has
writableFinished set. And that may not be true as we have just
(synchronously) called .end() on the stream if it was not closed and
that doesn't give it enough time to finish. Furthermore there is no
point in waiting for 'finish' as the other party have already closed the
stream and we won't be able to write anyway.

This also changes a few tests to correctly handle graceful session
close. This includes:
* not reading request data (on client side)
* not reading push stream data (on client side)
* relying on socket.destroy() (on client) to finish server session
  due to the destroy of the socket without closing the server session.
  As the goaway itself is *not* a session close.

Added few 'close' event mustCall checks.

PR-URL: https://github.com/nodejs/node/pull/30854
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
2019-12-25 11:07:04 +01:00

88 lines
2.4 KiB
JavaScript

'use strict';
// Tests http2.connect()
const common = require('../common');
const Countdown = require('../common/countdown');
if (!common.hasCrypto)
common.skip('missing crypto');
const fixtures = require('../common/fixtures');
const h2 = require('http2');
const url = require('url');
const URL = url.URL;
{
const server = h2.createServer();
server.listen(0);
server.on('listening', common.mustCall(function() {
const port = this.address().port;
const items = [
[`http://localhost:${port}`],
[new URL(`http://localhost:${port}`)],
[url.parse(`http://localhost:${port}`)],
[{ port }, { protocol: 'http:' }],
[{ port, hostname: '127.0.0.1' }, { protocol: 'http:' }]
];
const serverClose = new Countdown(items.length + 1,
() => setImmediate(() => server.close()));
const maybeClose = common.mustCall((client) => {
client.close();
serverClose.dec();
}, items.length);
items.forEach((i) => {
const client =
h2.connect.apply(null, i)
.on('connect', common.mustCall(() => maybeClose(client)));
client.on('close', common.mustCall());
});
// Will fail because protocol does not match the server.
const client = h2.connect({ port: port, protocol: 'https:' })
.on('error', common.mustCall(() => serverClose.dec()));
client.on('close', common.mustCall());
}));
}
{
const options = {
key: fixtures.readKey('agent3-key.pem'),
cert: fixtures.readKey('agent3-cert.pem')
};
const server = h2.createSecureServer(options);
server.listen(0, common.mustCall(() => {
const port = server.address().port;
const opts = { rejectUnauthorized: false };
const items = [
[`https://localhost:${port}`, opts],
[new URL(`https://localhost:${port}`), opts],
[url.parse(`https://localhost:${port}`), opts],
[{ port: port, protocol: 'https:' }, opts],
[{ port: port, hostname: '127.0.0.1', protocol: 'https:' }, opts]
];
const serverClose = new Countdown(items.length,
() => setImmediate(() => server.close()));
const maybeClose = common.mustCall((client) => {
client.close();
serverClose.dec();
}, items.length);
items.forEach((i) => {
const client =
h2.connect.apply(null, i)
.on('connect', common.mustCall(() => maybeClose(client)));
});
}));
}