http: wait for both prefinish/end to keepalive
When `free`ing the socket to be reused in keep-alive Agent wait for both `prefinish` and `end` events. Otherwise the next request may be written before the previous one has finished sending the body, leading to a parser errors. PR-URL: https://github.com/nodejs/node/pull/7149 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
0ed4d8c535
commit
1004ece889
@ -195,6 +195,8 @@ function ClientRequest(options, cb) {
|
|||||||
self._flush();
|
self._flush();
|
||||||
self = null;
|
self = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._ended = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(ClientRequest, OutgoingMessage);
|
util.inherits(ClientRequest, OutgoingMessage);
|
||||||
@ -466,6 +468,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
|
|||||||
|
|
||||||
// add our listener first, so that we guarantee socket cleanup
|
// add our listener first, so that we guarantee socket cleanup
|
||||||
res.on('end', responseOnEnd);
|
res.on('end', responseOnEnd);
|
||||||
|
req.on('prefinish', requestOnPrefinish);
|
||||||
var handled = req.emit('response', res);
|
var handled = req.emit('response', res);
|
||||||
|
|
||||||
// If the user did not listen for the 'response' event, then they
|
// If the user did not listen for the 'response' event, then they
|
||||||
@ -478,9 +481,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// client
|
// client
|
||||||
function responseOnEnd() {
|
function responseKeepAlive(res, req) {
|
||||||
var res = this;
|
|
||||||
var req = res.req;
|
|
||||||
var socket = req.socket;
|
var socket = req.socket;
|
||||||
|
|
||||||
if (!req.shouldKeepAlive) {
|
if (!req.shouldKeepAlive) {
|
||||||
@ -504,6 +505,26 @@ function responseOnEnd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function responseOnEnd() {
|
||||||
|
const res = this;
|
||||||
|
const req = this.req;
|
||||||
|
|
||||||
|
req._ended = true;
|
||||||
|
if (!req.shouldKeepAlive || req.finished)
|
||||||
|
responseKeepAlive(res, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestOnPrefinish() {
|
||||||
|
const req = this;
|
||||||
|
const res = this.res;
|
||||||
|
|
||||||
|
if (!req.shouldKeepAlive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (req._ended)
|
||||||
|
responseKeepAlive(res, req);
|
||||||
|
}
|
||||||
|
|
||||||
function emitFreeNT(socket) {
|
function emitFreeNT(socket) {
|
||||||
socket.emit('free');
|
socket.emit('free');
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
res.end();
|
||||||
|
}).listen(common.PORT, common.mustCall(() => {
|
||||||
|
const agent = new http.Agent({
|
||||||
|
maxSockets: 1,
|
||||||
|
keepAlive: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const post = http.request({
|
||||||
|
agent: agent,
|
||||||
|
method: 'POST',
|
||||||
|
port: common.PORT,
|
||||||
|
}, common.mustCall((res) => {
|
||||||
|
res.resume();
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* What happens here is that the server `end`s the response before we send
|
||||||
|
* `something`, and the client thought that this is a green light for sending
|
||||||
|
* next GET request
|
||||||
|
*/
|
||||||
|
post.write(Buffer.alloc(16 * 1024, 'X'));
|
||||||
|
setTimeout(() => {
|
||||||
|
post.end('something');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
http.request({
|
||||||
|
agent: agent,
|
||||||
|
method: 'GET',
|
||||||
|
port: common.PORT,
|
||||||
|
}, common.mustCall((res) => {
|
||||||
|
server.close();
|
||||||
|
res.connection.end();
|
||||||
|
})).end();
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user