Skip to content

Commit 9d13337

Browse files
indutnyMyles Borins
authored and
Myles Borins
committedJul 14, 2016
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: #7149 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 8eb18e4 commit 9d13337

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed
 

‎lib/_http_client.js

+24-3
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ function ClientRequest(options, cb) {
156156
self._flush();
157157
self = null;
158158
});
159+
160+
this._ended = false;
159161
}
160162

161163
util.inherits(ClientRequest, OutgoingMessage);
@@ -427,6 +429,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
427429

428430
// add our listener first, so that we guarantee socket cleanup
429431
res.on('end', responseOnEnd);
432+
req.on('prefinish', requestOnPrefinish);
430433
var handled = req.emit('response', res);
431434

432435
// If the user did not listen for the 'response' event, then they
@@ -439,9 +442,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
439442
}
440443

441444
// client
442-
function responseOnEnd() {
443-
var res = this;
444-
var req = res.req;
445+
function responseKeepAlive(res, req) {
445446
var socket = req.socket;
446447

447448
if (!req.shouldKeepAlive) {
@@ -465,6 +466,26 @@ function responseOnEnd() {
465466
}
466467
}
467468

469+
function responseOnEnd() {
470+
const res = this;
471+
const req = this.req;
472+
473+
req._ended = true;
474+
if (!req.shouldKeepAlive || req.finished)
475+
responseKeepAlive(res, req);
476+
}
477+
478+
function requestOnPrefinish() {
479+
const req = this;
480+
const res = this.res;
481+
482+
if (!req.shouldKeepAlive)
483+
return;
484+
485+
if (req._ended)
486+
responseKeepAlive(res, req);
487+
}
488+
468489
function emitFreeNT(socket) {
469490
socket.emit('free');
470491
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
const common = require('../common');
3+
const http = require('http');
4+
5+
const server = http.createServer((req, res) => {
6+
res.end();
7+
}).listen(common.PORT, common.mustCall(() => {
8+
const agent = new http.Agent({
9+
maxSockets: 1,
10+
keepAlive: true
11+
});
12+
13+
const post = http.request({
14+
agent: agent,
15+
method: 'POST',
16+
port: common.PORT,
17+
}, common.mustCall((res) => {
18+
res.resume();
19+
}));
20+
21+
/* What happens here is that the server `end`s the response before we send
22+
* `something`, and the client thought that this is a green light for sending
23+
* next GET request
24+
*/
25+
post.write(Buffer.alloc(16 * 1024, 'X'));
26+
setTimeout(() => {
27+
post.end('something');
28+
}, 100);
29+
30+
http.request({
31+
agent: agent,
32+
method: 'GET',
33+
port: common.PORT,
34+
}, common.mustCall((res) => {
35+
server.close();
36+
res.connection.end();
37+
})).end();
38+
}));

0 commit comments

Comments
 (0)
Please sign in to comment.