mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
0babd181a0
PR-URL: https://github.com/nodejs/node/pull/17406 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> This is a significant cleanup and refactoring of the cleanup/close/destroy logic for Http2Stream and Http2Session. There are significant changes here in the timing and ordering of cleanup logic, JS apis. and various related necessary edits.
326 lines
9.2 KiB
JavaScript
326 lines
9.2 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
mustCall,
|
|
mustNotCall,
|
|
hasCrypto,
|
|
platformTimeout,
|
|
skip
|
|
} = require('../common');
|
|
if (!hasCrypto)
|
|
skip('missing crypto');
|
|
const { strictEqual } = require('assert');
|
|
const {
|
|
createServer,
|
|
connect,
|
|
constants: {
|
|
HTTP2_HEADER_STATUS,
|
|
HTTP_STATUS_OK
|
|
}
|
|
} = require('http2');
|
|
|
|
{
|
|
// Http2ServerResponse.end accepts chunk, encoding, cb as args
|
|
// It may be invoked repeatedly without throwing errors
|
|
// but callback will only be called once
|
|
const server = createServer(mustCall((request, response) => {
|
|
response.end('end', 'utf8', mustCall(() => {
|
|
response.end(mustNotCall());
|
|
process.nextTick(() => {
|
|
response.end(mustNotCall());
|
|
server.close();
|
|
});
|
|
}));
|
|
response.on('finish', mustCall(() => {
|
|
response.end(mustNotCall());
|
|
}));
|
|
response.end(mustNotCall());
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
let data = '';
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'GET',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.setEncoding('utf8');
|
|
request.on('data', (chunk) => (data += chunk));
|
|
request.on('end', mustCall(() => {
|
|
strictEqual(data, 'end');
|
|
client.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// Http2ServerResponse.end can omit encoding arg, sets it to utf-8
|
|
const server = createServer(mustCall((request, response) => {
|
|
response.end('test\uD83D\uDE00', mustCall(() => {
|
|
server.close();
|
|
}));
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
let data = '';
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'GET',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.setEncoding('utf8');
|
|
request.on('data', (chunk) => (data += chunk));
|
|
request.on('end', mustCall(() => {
|
|
strictEqual(data, 'test\uD83D\uDE00');
|
|
client.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// Http2ServerResponse.end can omit chunk & encoding args
|
|
const server = createServer(mustCall((request, response) => {
|
|
response.end(mustCall(() => {
|
|
server.close();
|
|
}));
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'GET',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => client.close()));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// Http2ServerResponse.end is necessary on HEAD requests in compat
|
|
// for http1 compatibility
|
|
const server = createServer(mustCall((request, response) => {
|
|
strictEqual(response.finished, true);
|
|
response.writeHead(HTTP_STATUS_OK, { foo: 'bar' });
|
|
response.end('data', mustCall());
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('response', mustCall((headers, flags) => {
|
|
strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK);
|
|
strictEqual(flags, 5); // the end of stream flag is set
|
|
strictEqual(headers.foo, 'bar');
|
|
}));
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// .end should trigger 'end' event on request if user did not attempt
|
|
// to read from the request
|
|
const server = createServer(mustCall((request, response) => {
|
|
request.on('end', mustCall());
|
|
response.end();
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
|
|
{
|
|
// Should be able to call .end with cb from stream 'close'
|
|
const server = createServer(mustCall((request, response) => {
|
|
response.writeHead(HTTP_STATUS_OK, { foo: 'bar' });
|
|
response.stream.on('close', mustCall(() => {
|
|
response.end(mustCall());
|
|
}));
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('response', mustCall((headers, flags) => {
|
|
strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK);
|
|
strictEqual(flags, 5); // the end of stream flag is set
|
|
strictEqual(headers.foo, 'bar');
|
|
}));
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// Should be able to respond to HEAD request after timeout
|
|
const server = createServer(mustCall((request, response) => {
|
|
setTimeout(mustCall(() => {
|
|
response.writeHead(HTTP_STATUS_OK, { foo: 'bar' });
|
|
response.end('data', mustCall());
|
|
}), platformTimeout(10));
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('response', mustCall((headers, flags) => {
|
|
strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK);
|
|
strictEqual(flags, 5); // the end of stream flag is set
|
|
strictEqual(headers.foo, 'bar');
|
|
}));
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// finish should only trigger after 'end' is called
|
|
const server = createServer(mustCall((request, response) => {
|
|
let finished = false;
|
|
response.writeHead(HTTP_STATUS_OK, { foo: 'bar' });
|
|
response.on('finish', mustCall(() => {
|
|
finished = false;
|
|
}));
|
|
response.end('data', mustCall(() => {
|
|
strictEqual(finished, false);
|
|
response.end('data', mustNotCall());
|
|
}));
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('response', mustCall((headers, flags) => {
|
|
strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK);
|
|
strictEqual(flags, 5); // the end of stream flag is set
|
|
strictEqual(headers.foo, 'bar');
|
|
}));
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|
|
|
|
{
|
|
// Should be able to respond to HEAD with just .end
|
|
const server = createServer(mustCall((request, response) => {
|
|
response.end('data', mustCall());
|
|
response.end(mustNotCall());
|
|
}));
|
|
server.listen(0, mustCall(() => {
|
|
const { port } = server.address();
|
|
const url = `http://localhost:${port}`;
|
|
const client = connect(url, mustCall(() => {
|
|
const headers = {
|
|
':path': '/',
|
|
':method': 'HEAD',
|
|
':scheme': 'http',
|
|
':authority': `localhost:${port}`
|
|
};
|
|
const request = client.request(headers);
|
|
request.on('response', mustCall((headers, flags) => {
|
|
strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK);
|
|
strictEqual(flags, 5); // the end of stream flag is set
|
|
}));
|
|
request.on('data', mustNotCall());
|
|
request.on('end', mustCall(() => {
|
|
client.close();
|
|
server.close();
|
|
}));
|
|
request.end();
|
|
request.resume();
|
|
}));
|
|
}));
|
|
}
|