diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 0522ecb2a276f2..da54247b33389b 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -71,6 +71,7 @@ function OutgoingMessage() { this._header = null; this._headers = null; this._headerNames = {}; + this._prefinish = false; } util.inherits(OutgoingMessage, Stream); @@ -526,7 +527,14 @@ OutgoingMessage.prototype.end = function(data, encoding, callback) { var self = this; function finish() { - self.emit('finish'); + // NOTE: It is very important to wait for `prefinish` event. + // It is emitted only when the response becomes active in the pipeline. + // The ordering of requests/responses in `_http_server.js` is dependent + // on this, doing it in different order will result in crash. + if (self._prefinish) + self.emit('finish'); + else + self.on('prefinish', finish); } if (typeof callback === 'function') @@ -586,6 +594,7 @@ OutgoingMessage.prototype.end = function(data, encoding, callback) { OutgoingMessage.prototype._finish = function() { assert(this.connection); + this._prefinish = true; this.emit('prefinish'); }; diff --git a/test/parallel/test-http-pipeline-regr-2639.js b/test/parallel/test-http-pipeline-regr-2639.js new file mode 100644 index 00000000000000..5b6f0bea369c9f --- /dev/null +++ b/test/parallel/test-http-pipeline-regr-2639.js @@ -0,0 +1,23 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); +const http = require('http'); + +var count = 0; +const server = http.createServer(function(req, res) { + const id = count++; + setTimeout(function() { + res.end('hello'); + }, (2 - id) * 10); + + if (id === 1) + server.close(); +}).listen(common.PORT, function() { + const s = net.connect(common.PORT); + + const req = 'GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n'; + const big = req + req; + s.end(big); + s.resume(); +});