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