Skip to content

Commit

Permalink
Fix req end during response transmission (#4264)
Browse files Browse the repository at this point in the history
* Write test that fails on node v16 for req ending during response transmission

* Fix request close during response transmission for node v16
  • Loading branch information
devinivy authored Jun 28, 2021
1 parent be3e3a2 commit 0d32840
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
1 change: 0 additions & 1 deletion lib/transmit.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ internals.pipe = function (request, stream) {
const end = internals.end.bind(null, env, null);

request.raw.req.on('aborted', aborted);
request.raw.req.on('close', close);

request.raw.res.on('close', close);
request.raw.res.on('error', end);
Expand Down
59 changes: 59 additions & 0 deletions test/transmit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ const Net = require('net');
const Path = require('path');
const Stream = require('stream');
const Zlib = require('zlib');
const Events = require('events');

const Boom = require('@hapi/boom');
const Code = require('@hapi/code');
const Hapi = require('..');
const Hoek = require('@hapi/hoek');
const Bounce = require('@hapi/bounce');
const Inert = require('@hapi/inert');
const Lab = require('@hapi/lab');
const LegacyReadableStream = require('legacy-readable-stream');
Expand Down Expand Up @@ -1921,6 +1923,63 @@ describe('transmission', () => {
const res = await server.inject('/');
expect(res.statusCode).to.equal(500);
});

it('permits ending reading request stream while transmitting response.', async (flags) => {

const server = Hapi.server();

server.route({
method: 'post',
path: '/',
options: {
payload: {
output: 'stream'
}
},
handler: (request, h) => {

const stream = new Stream.PassThrough();

// Start transmitting stream response...
stream.push('hello ');

Bounce.background(async () => {

await Events.once(request.raw.res, 'pipe');

// ...but also only read and end the request once the response is transmitting...
request.raw.req.on('data', Hoek.ignore);
await Events.once(request.raw.req, 'end');

// ...and finally end the intended response once the request stream has ended.
stream.end('world');
});

return h.response(stream);
}
});

flags.onCleanup = () => server.stop();
await server.start();

const req = Http.request({
hostname: 'localhost',
port: server.info.port,
method: 'post'
});

req.end('{}');

const [res] = await Events.once(req, 'response');

let result = '';
for await (const chunk of res) {
result += chunk.toString();
}

// If not permitted then result will be "hello " without "world"
expect(result).to.equal('hello world');
});
});

describe('length()', () => {
Expand Down

0 comments on commit 0d32840

Please sign in to comment.