node/test/parallel/test-quic-http3-client-server.js
James M Snell 6e30fe7a7f quic: convert openStream to Promise
Although most of the time openStream will be able to create the stream
immediately, when a stream is opened before the handshake is complete
we have to wait for the handshake to be complete before continuing.

PR-URL: https://github.com/nodejs/node/pull/34351
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2020-07-23 06:52:40 -07:00

152 lines
4.1 KiB
JavaScript

// Flags: --expose-internals --no-warnings
'use strict';
// Tests a simple QUIC HTTP/3 client/server round-trip
const common = require('../common');
if (!common.hasQuic)
common.skip('missing quic');
const Countdown = require('../common/countdown');
const assert = require('assert');
const fs = require('fs');
const {
key,
cert,
ca,
debug,
kHttp3Alpn,
kServerPort,
kClientPort,
setupKeylog,
} = require('../common/quic');
const filedata = fs.readFileSync(__filename, { encoding: 'utf8' });
const { createQuicSocket } = require('net');
const kServerName = 'agent2'; // Intentionally the wrong servername
const options = { key, cert, ca, alpn: kHttp3Alpn };
const client = createQuicSocket({
endpoint: { port: kClientPort },
client: options
});
const server = createQuicSocket({
endpoint: { port: kServerPort },
server: options
});
client.on('close', common.mustCall());
server.on('close', common.mustCall());
const countdown = new Countdown(1, () => {
debug('Countdown expired. Destroying sockets');
server.close();
client.close();
});
(async function() {
server.on('session', common.mustCall((session) => {
debug('QuicServerSession Created');
assert.strictEqual(session.maxStreams.bidi, 100);
assert.strictEqual(session.maxStreams.uni, 3);
setupKeylog(session);
session.on('secure', common.mustCall((_, alpn) => {
debug('QuicServerSession handshake completed');
assert.strictEqual(session.alpnProtocol, alpn);
}));
session.on('stream', common.mustCall((stream) => {
debug('Bidirectional, Client-initiated stream %d received', stream.id);
const file = fs.createReadStream(__filename);
let data = '';
assert(stream.submitInitialHeaders({ ':status': '200' }));
file.pipe(stream);
stream.setEncoding('utf8');
stream.on('initialHeaders', common.mustCall((headers) => {
const expected = [
[ ':path', '/' ],
[ ':authority', 'localhost' ],
[ ':scheme', 'https' ],
[ ':method', 'POST' ]
];
assert.deepStrictEqual(expected, headers);
debug('Received expected request headers');
}));
stream.on('informationalHeaders', common.mustNotCall());
stream.on('trailingHeaders', common.mustNotCall());
stream.on('data', (chunk) => {
data += chunk;
});
stream.on('end', common.mustCall(() => {
assert.strictEqual(data, filedata);
debug('Server received expected data for stream %d', stream.id);
}));
stream.on('close', common.mustCall());
stream.on('finish', common.mustCall());
}));
session.on('close', common.mustCall());
}));
await server.listen();
debug('Server is listening on port %d', server.endpoints[0].address.port);
const req = await client.connect({
address: 'localhost',
port: server.endpoints[0].address.port,
servername: kServerName,
h3: { maxPushes: 10 }
});
debug('QuicClientSession Created');
req.on('close', common.mustCall());
const file = fs.createReadStream(__filename);
const stream = await req.openStream();
assert(stream.submitInitialHeaders({
':method': 'POST',
':scheme': 'https',
':authority': 'localhost',
':path': '/',
}));
file.pipe(stream);
let data = '';
stream.resume();
stream.setEncoding('utf8');
stream.on('initialHeaders', common.mustCall((headers) => {
const expected = [
[ ':status', '200' ]
];
assert.deepStrictEqual(expected, headers);
debug('Received expected response headers');
}));
stream.on('informationalHeaders', common.mustNotCall());
stream.on('trailingHeaders', common.mustNotCall());
stream.on('data', (chunk) => data += chunk);
stream.on('finish', common.mustCall());
stream.on('end', common.mustCall(() => {
assert.strictEqual(data, filedata);
debug('Client received expected data for stream %d', stream.id);
}));
stream.on('close', common.mustCall(() => {
debug('Bidirectional, Client-initiated stream %d closed', stream.id);
countdown.dec();
}));
debug('Bidirectional, Client-initiated stream %d opened', stream.id);
})().then(common.mustCall());