@@ -25,7 +25,6 @@ const {
25
25
Array,
26
26
ArrayIsArray,
27
27
ArrayPrototypeJoin,
28
- MathAbs,
29
28
MathFloor,
30
29
NumberPrototypeToString,
31
30
ObjectDefineProperty,
@@ -86,7 +85,6 @@ const HIGH_WATER_MARK = getDefaultHighWaterMark();
86
85
const kCorked = Symbol ( 'corked' ) ;
87
86
const kUniqueHeaders = Symbol ( 'kUniqueHeaders' ) ;
88
87
const kBytesWritten = Symbol ( 'kBytesWritten' ) ;
89
- const kEndCalled = Symbol ( 'kEndCalled' ) ;
90
88
const kErrored = Symbol ( 'errored' ) ;
91
89
92
90
const nop = ( ) => { } ;
@@ -133,7 +131,6 @@ function OutgoingMessage() {
133
131
134
132
this . strictContentLength = false ;
135
133
this [ kBytesWritten ] = 0 ;
136
- this [ kEndCalled ] = false ;
137
134
this . _contentLength = null ;
138
135
this . _hasBody = true ;
139
136
this . _trailer = '' ;
@@ -355,7 +352,7 @@ OutgoingMessage.prototype.destroy = function destroy(error) {
355
352
356
353
357
354
// This abstract either writing directly to the socket or buffering it.
358
- OutgoingMessage . prototype . _send = function _send ( data , encoding , callback ) {
355
+ OutgoingMessage . prototype . _send = function _send ( data , encoding , callback , byteLength ) {
359
356
// This is a shameful hack to get the headers and first body chunk onto
360
357
// the same packet. Future versions of Node are going to take care of
361
358
// this at a lower level and in a more general way.
@@ -377,20 +374,11 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) {
377
374
}
378
375
this . _headerSent = true ;
379
376
}
380
- return this . _writeRaw ( data , encoding , callback ) ;
377
+ return this . _writeRaw ( data , encoding , callback , byteLength ) ;
381
378
} ;
382
379
383
- function _getMessageBodySize ( chunk , headers , encoding ) {
384
- if ( Buffer . isBuffer ( chunk ) ) return chunk . length ;
385
- const chunkLength = chunk ? Buffer . byteLength ( chunk , encoding ) : 0 ;
386
- const headerLength = headers ? headers . length : 0 ;
387
- if ( headerLength === chunkLength ) return 0 ;
388
- if ( headerLength < chunkLength ) return MathAbs ( chunkLength - headerLength ) ;
389
- return chunkLength ;
390
- }
391
-
392
380
OutgoingMessage . prototype . _writeRaw = _writeRaw ;
393
- function _writeRaw ( data , encoding , callback ) {
381
+ function _writeRaw ( data , encoding , callback , size ) {
394
382
const conn = this . socket ;
395
383
if ( conn && conn . destroyed ) {
396
384
// The socket was destroyed. If we're still trying to write to it,
@@ -403,25 +391,6 @@ function _writeRaw(data, encoding, callback) {
403
391
encoding = null ;
404
392
}
405
393
406
- // TODO(sidwebworks): flip the `strictContentLength` default to `true` in a future PR
407
- if ( this . strictContentLength && conn && conn . writable && ! this . _removedContLen && this . _hasBody ) {
408
- const skip = conn . _httpMessage . statusCode === 304 || ( this . hasHeader ( 'transfer-encoding' ) || this . chunkedEncoding ) ;
409
-
410
- if ( typeof this . _contentLength === 'number' && ! skip ) {
411
- const size = _getMessageBodySize ( data , conn . _httpMessage . _header , encoding ) ;
412
-
413
- if ( ( size + this [ kBytesWritten ] ) > this . _contentLength ) {
414
- throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH ( size + this [ kBytesWritten ] , this . _contentLength ) ;
415
- }
416
-
417
- if ( this [ kEndCalled ] && ( size + this [ kBytesWritten ] ) !== this . _contentLength ) {
418
- throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH ( size + this [ kBytesWritten ] , this . _contentLength ) ;
419
- }
420
-
421
- this [ kBytesWritten ] += size ;
422
- }
423
- }
424
-
425
394
if ( conn && conn . _httpMessage === this && conn . writable ) {
426
395
// There might be pending data in the this.output buffer.
427
396
if ( this . outputData . length ) {
@@ -881,18 +850,24 @@ function emitErrorNt(msg, err, callback) {
881
850
}
882
851
}
883
852
853
+ function strictContentLength ( msg ) {
854
+ return (
855
+ msg . strictContentLength &&
856
+ msg . _contentLength != null &&
857
+ msg . _hasBody &&
858
+ ! msg . _removedContLen &&
859
+ ! msg . chunkedEncoding &&
860
+ ! msg . hasHeader ( 'transfer-encoding' )
861
+ ) ;
862
+ }
863
+
884
864
function write_ ( msg , chunk , encoding , callback , fromEnd ) {
885
865
if ( typeof callback !== 'function' )
886
866
callback = nop ;
887
867
888
- let len ;
889
868
if ( chunk === null ) {
890
869
throw new ERR_STREAM_NULL_VALUES ( ) ;
891
- } else if ( typeof chunk === 'string' ) {
892
- len = Buffer . byteLength ( chunk , encoding ) ;
893
- } else if ( isUint8Array ( chunk ) ) {
894
- len = chunk . length ;
895
- } else {
870
+ } else if ( typeof chunk !== 'string' && ! isUint8Array ( chunk ) ) {
896
871
throw new ERR_INVALID_ARG_TYPE (
897
872
'chunk' , [ 'string' , 'Buffer' , 'Uint8Array' ] , chunk ) ;
898
873
}
@@ -913,8 +888,24 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
913
888
return false ;
914
889
}
915
890
891
+ let len ;
892
+
893
+ if ( msg . strictContentLength ) {
894
+ len ??= typeof chunk === 'string' ? Buffer . byteLength ( chunk , encoding ) : chunk . byteLength ;
895
+
896
+ if (
897
+ strictContentLength ( msg ) &&
898
+ ( fromEnd ? msg [ kBytesWritten ] + len !== msg . _contentLength : msg [ kBytesWritten ] + len > msg . _contentLength )
899
+ ) {
900
+ throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH ( len + msg [ kBytesWritten ] , msg . _contentLength ) ;
901
+ }
902
+
903
+ msg [ kBytesWritten ] += len ;
904
+ }
905
+
916
906
if ( ! msg . _header ) {
917
907
if ( fromEnd ) {
908
+ len ??= typeof chunk === 'string' ? Buffer . byteLength ( chunk , encoding ) : chunk . byteLength ;
918
909
msg . _contentLength = len ;
919
910
}
920
911
msg . _implicitHeader ( ) ;
@@ -934,12 +925,13 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
934
925
935
926
let ret ;
936
927
if ( msg . chunkedEncoding && chunk . length !== 0 ) {
928
+ len ??= typeof chunk === 'string' ? Buffer . byteLength ( chunk , encoding ) : chunk . byteLength ;
937
929
msg . _send ( NumberPrototypeToString ( len , 16 ) , 'latin1' , null ) ;
938
930
msg . _send ( crlf_buf , null , null ) ;
939
- msg . _send ( chunk , encoding , null ) ;
931
+ msg . _send ( chunk , encoding , null , len ) ;
940
932
ret = msg . _send ( crlf_buf , null , callback ) ;
941
933
} else {
942
- ret = msg . _send ( chunk , encoding , callback ) ;
934
+ ret = msg . _send ( chunk , encoding , callback , len ) ;
943
935
}
944
936
945
937
debug ( 'write ret = ' + ret ) ;
@@ -1011,8 +1003,6 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
1011
1003
encoding = null ;
1012
1004
}
1013
1005
1014
- this [ kEndCalled ] = true ;
1015
-
1016
1006
if ( chunk ) {
1017
1007
if ( this . finished ) {
1018
1008
onError ( this ,
@@ -1047,6 +1037,10 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
1047
1037
if ( typeof callback === 'function' )
1048
1038
this . once ( 'finish' , callback ) ;
1049
1039
1040
+ if ( strictContentLength ( this ) && this [ kBytesWritten ] !== this . _contentLength ) {
1041
+ throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH ( this [ kBytesWritten ] , this . _contentLength ) ;
1042
+ }
1043
+
1050
1044
const finish = onFinish . bind ( undefined , this ) ;
1051
1045
1052
1046
if ( this . _hasBody && this . chunkedEncoding ) {
0 commit comments