Skip to content

Commit db8144b

Browse files
ronagBethGriggs
authored andcommitted
http: outgoing cork
PR-URL: #29053 Reviewed-By: Anna Henningsen <[email protected]>
1 parent 55ca3a8 commit db8144b

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

‎doc/api/http.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,13 @@ added: v0.3.0
12231223

12241224
See [`response.socket`][].
12251225

1226+
### `response.cork()`
1227+
<!-- YAML
1228+
added: REPLACEME
1229+
-->
1230+
1231+
See [`writable.cork()`][].
1232+
12261233
### `response.end([data[, encoding]][, callback])`
12271234
<!-- YAML
12281235
added: v0.1.90
@@ -1508,6 +1515,13 @@ response.statusMessage = 'Not found'
15081515
After response header was sent to the client, this property indicates the
15091516
status message which was sent out.
15101517

1518+
### `response.uncork()`
1519+
<!-- YAML
1520+
added: REPLACEME
1521+
-->
1522+
1523+
See [`writable.uncork()`][].
1524+
15111525
### `response.writableEnded`
15121526
<!-- YAML
15131527
added: v12.9.0
@@ -2348,3 +2362,5 @@ not abort the request or do anything besides add a `'timeout'` event.
23482362
[`socket.unref()`]: net.html#net_socket_unref
23492363
[`url.parse()`]: url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
23502364
[`HPE_HEADER_OVERFLOW`]: errors.html#errors_hpe_header_overflow
2365+
[`writable.cork()`]: stream.html#stream_writable_cork
2366+
[`writable.uncork()`]: stream.html#stream_writable_uncork

‎lib/_http_outgoing.js‎

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const{validateString } = require('internal/validators');
5555
constHIGH_WATER_MARK=getDefaultHighWaterMark();
5656
const{CRLF, debug }=common;
5757

58+
constkCorked=Symbol('corked');
59+
5860
constRE_CONN_CLOSE=/(?:^|\W)close(?:$|\W)/i;
5961
constRE_TE_CHUNKED=common.chunkExpression;
6062

@@ -98,6 +100,7 @@ function OutgoingMessage(){
98100

99101
this.finished=false;
100102
this._headerSent=false;
103+
this[kCorked]=0;
101104

102105
this.socket=null;
103106
this.connection=null;
@@ -137,6 +140,13 @@ Object.defineProperty(OutgoingMessage.prototype, 'writableHighWaterMark',{
137140
}
138141
});
139142

143+
Object.defineProperty(OutgoingMessage.prototype,'writableCorked',{
144+
get(){
145+
constcorked=this.socket ? this.socket.writableCorked : 0;
146+
returncorked+this[kCorked];
147+
}
148+
});
149+
140150
Object.defineProperty(OutgoingMessage.prototype,'_headers',{
141151
get: internalUtil.deprecate(function(){
142152
returnthis.getHeaders();
@@ -204,6 +214,21 @@ OutgoingMessage.prototype._renderHeaders = function _renderHeaders(){
204214
returnheaders;
205215
};
206216

217+
OutgoingMessage.prototype.cork=function(){
218+
if(this.socket){
219+
this.socket.cork();
220+
}else{
221+
this[kCorked]++;
222+
}
223+
};
224+
225+
OutgoingMessage.prototype.uncork=function(){
226+
if(this.socket){
227+
this.socket.uncork();
228+
}elseif(this[kCorked]){
229+
this[kCorked]--;
230+
}
231+
};
207232

208233
OutgoingMessage.prototype.setTimeout=functionsetTimeout(msecs,callback){
209234

@@ -694,7 +719,10 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback){
694719
returnthis;
695720
}
696721

697-
varuncork;
722+
if(this.socket){
723+
this.socket.cork();
724+
}
725+
698726
if(chunk){
699727
if(typeofchunk!=='string'&&!(chunkinstanceofBuffer)){
700728
thrownewERR_INVALID_ARG_TYPE('chunk',['string','Buffer'],chunk);
@@ -705,10 +733,6 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback){
705733
else
706734
this._contentLength=chunk.length;
707735
}
708-
if(this.connection){
709-
this.connection.cork();
710-
uncork=true;
711-
}
712736
write_(this,chunk,encoding,null,true);
713737
}elseif(!this._header){
714738
this._contentLength=0;
@@ -727,8 +751,12 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback){
727751
this._send('','latin1',finish);
728752
}
729753

730-
if(uncork)
731-
this.connection.uncork();
754+
if(this.socket){
755+
// Fully uncork connection on end().
756+
this.socket._writableState.corked=1;
757+
this.socket.uncork();
758+
}
759+
this[kCorked]=0;
732760

733761
this.finished=true;
734762

@@ -789,6 +817,11 @@ OutgoingMessage.prototype._flush = function _flush(){
789817
};
790818

791819
OutgoingMessage.prototype._flushOutput=function_flushOutput(socket){
820+
while(this[kCorked]){
821+
this[kCorked]--;
822+
socket.cork();
823+
}
824+
792825
constoutputLength=this.outputData.length;
793826
if(outputLength<=0)
794827
returnundefined;

‎lib/internal/http2/compat.js‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ class Http2ServerResponse extends Stream{
503503
returnthis[kState].statusCode;
504504
}
505505

506+
getwritableCorked(){
507+
returnthis[kStream].writableCorked;
508+
}
509+
506510
setstatusCode(code){
507511
code|=0;
508512
if(code>=100&&code<200)
@@ -627,6 +631,14 @@ class Http2ServerResponse extends Stream{
627631
returnthis;
628632
}
629633

634+
cork(){
635+
this[kStream].cork();
636+
}
637+
638+
uncork(){
639+
this[kStream].uncork();
640+
}
641+
630642
write(chunk,encoding,cb){
631643
if(typeofencoding==='function'){
632644
cb=encoding;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
consthttp=require('http');
4+
constassert=require('assert');
5+
6+
constserver=http.createServer((req,res)=>{
7+
letcorked=false;
8+
constoriginalWrite=res.socket.write;
9+
res.socket.write=common.mustCall((...args)=>{
10+
assert.strictEqual(corked,false);
11+
returnoriginalWrite.call(res.socket, ...args);
12+
},5);
13+
corked=true;
14+
res.cork();
15+
assert.strictEqual(res.writableCorked,res.socket.writableCorked);
16+
res.cork();
17+
assert.strictEqual(res.writableCorked,res.socket.writableCorked);
18+
res.writeHead(200,{'a-header': 'a-header-value'});
19+
res.uncork();
20+
assert.strictEqual(res.writableCorked,res.socket.writableCorked);
21+
corked=false;
22+
res.end('asd');
23+
assert.strictEqual(res.writableCorked,res.socket.writableCorked);
24+
});
25+
26+
server.listen(0,()=>{
27+
http.get({port: server.address().port},(res)=>{
28+
res.on('data',common.mustCall());
29+
res.on('end',common.mustCall(()=>{
30+
server.close();
31+
}));
32+
});
33+
});

0 commit comments

Comments
(0)