Skip to content

Commit 9d13337

Browse files
indutnyMyles Borins
authored andcommitted
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‎

Lines changed: 24 additions & 3 deletions
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
varhandled=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-
functionresponseOnEnd(){
443-
varres=this;
444-
varreq=res.req;
445+
functionresponseKeepAlive(res,req){
445446
varsocket=req.socket;
446447

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

469+
functionresponseOnEnd(){
470+
constres=this;
471+
constreq=this.req;
472+
473+
req._ended=true;
474+
if(!req.shouldKeepAlive||req.finished)
475+
responseKeepAlive(res,req);
476+
}
477+
478+
functionrequestOnPrefinish(){
479+
constreq=this;
480+
constres=this.res;
481+
482+
if(!req.shouldKeepAlive)
483+
return;
484+
485+
if(req._ended)
486+
responseKeepAlive(res,req);
487+
}
488+
468489
functionemitFreeNT(socket){
469490
socket.emit('free');
470491
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
consthttp=require('http');
4+
5+
constserver=http.createServer((req,res)=>{
6+
res.end();
7+
}).listen(common.PORT,common.mustCall(()=>{
8+
constagent=newhttp.Agent({
9+
maxSockets: 1,
10+
keepAlive: true
11+
});
12+
13+
constpost=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)