'use strict'; const common = require('../common'); const http = require('http'); const assert = require('assert'); const { Writable } = require('stream'); const Countdown = require('../common/countdown'); const N = 2; let abortRequest = true; const server = http.Server(common.mustCall((req, res) => { const headers = { 'Content-Type': 'text/plain', 'Connection': 'close' }; headers['Content-Length'] = 50; const socket = res.socket; res.writeHead(200, headers); res.write('aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd'); if (abortRequest) { process.nextTick(() => socket.destroy()); } else { process.nextTick(() => res.end('eeeeeeeeee')); } }, N)); server.listen(0, common.mustCall(() => { download(); })); const finishCountdown = new Countdown(N, common.mustCall(() => { server.close(); })); const reqCountdown = new Countdown(N, common.mustCall()); function download() { const opts = { port: server.address().port, path: '/', }; const req = http.get(opts); req.on('error', common.mustNotCall()); req.on('response', (res) => { assert.strictEqual(res.statusCode, 200); assert.strictEqual(res.headers.connection, 'close'); let aborted = false; const writable = new Writable({ write(chunk, encoding, callback) { callback(); } }); res.pipe(writable); const _handle = res.socket._handle; _handle._close = res.socket._handle.close; _handle.close = function(callback) { _handle._close(); // Set readable to true even though request is complete if (res.complete) res.readable = true; callback(); }; if (!abortRequest) { res.on('end', common.mustCall(() => { reqCountdown.dec(); })); res.on('error', common.mustNotCall()); } else { res.on('aborted', common.mustCall(() => { aborted = true; reqCountdown.dec(); writable.end(); })); res.on('error', common.expectsError({ code: 'ECONNRESET' })); } writable.on('finish', () => { assert.strictEqual(aborted, abortRequest); finishCountdown.dec(); if (finishCountdown.remaining === 0) return; abortRequest = false; // Next one should be a good response download(); }); }); req.end(); }