@@ -37,6 +37,8 @@ const {
3737 SafeSet,
3838 StringPrototypeToLowerCase,
3939 Symbol,
40+ NumberPOSITIVE_INFINITY,
41+ NumberParseInt
4042} = primordials ;
4143
4244const { getDefaultHighWaterMark } = require ( 'internal/streams/state' ) ;
@@ -69,12 +71,14 @@ const {
6971 ERR_STREAM_ALREADY_FINISHED ,
7072 ERR_STREAM_WRITE_AFTER_END ,
7173 ERR_STREAM_NULL_VALUES ,
72- ERR_STREAM_DESTROYED
74+ ERR_STREAM_DESTROYED ,
75+ ERR_HTTP_CONTENT_LENGTH_MISMATCH
7376 } ,
7477 hideStackFrames
7578} = require ( 'internal/errors' ) ;
7679const { validateString } = require ( 'internal/validators' ) ;
7780const { isUint8Array } = require ( 'internal/util/types' ) ;
81+ const { kHeaders } = require ( '_http_incoming' ) ;
7882
7983let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'http' , ( fn ) => {
8084 debug = fn ;
@@ -84,6 +88,8 @@ const HIGH_WATER_MARK = getDefaultHighWaterMark();
8488
8589const kCorked = Symbol ( 'corked' ) ;
8690const kUniqueHeaders = Symbol ( 'kUniqueHeaders' ) ;
91+ const kBytesWritten = Symbol ( 'kBytesWritten' ) ;
92+ const kSentContentLength = Symbol ( 'kSentContentLength' ) ;
8793
8894const nop = ( ) => { } ;
8995
@@ -123,6 +129,8 @@ function OutgoingMessage() {
123129 this . _removedContLen = false ;
124130 this . _removedTE = false ;
125131
132+ this [ kBytesWritten ] = 0 ;
133+ this [ kSentContentLength ] = null ;
126134 this . _contentLength = null ;
127135 this . _hasBody = true ;
128136 this . _trailer = '' ;
@@ -345,10 +353,20 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) {
345353 this . _onPendingData ( header . length ) ;
346354 }
347355 this . _headerSent = true ;
356+ this [ kSentContentLength ] = _getContentLength . call ( this )
348357 }
349358 return this . _writeRaw ( data , encoding , callback ) ;
350359} ;
351360
361+ function _getContentLength ( ) {
362+ const outgoing = this . getHeader ( 'content-length' )
363+ const incoming = this . req
364+ if ( ! ! outgoing ) return NumberParseInt ( outgoing )
365+ if ( incoming && incoming [ kHeaders ] && ! ! incoming [ kHeaders ] [ 'content-length' ] ) {
366+ return NumberParseInt ( incoming [ kHeaders ] [ 'content-length' ] ) ;
367+ }
368+ return NumberPOSITIVE_INFINITY
369+ }
352370
353371OutgoingMessage . prototype . _writeRaw = _writeRaw ;
354372function _writeRaw ( data , encoding , callback ) {
@@ -534,6 +552,9 @@ function processHeader(self, state, key, value, validate) {
534552function storeHeader ( self , state , key , value , validate ) {
535553 if ( validate )
536554 validateHeaderValue ( key , value ) ;
555+ if ( StringPrototypeToLowerCase ( key ) === 'content-length' ) {
556+ self [ kSentContentLength ] = value
557+ }
537558 state . header += key + ': ' + value + '\r\n' ;
538559 matchHeader ( self , state , key , value ) ;
539560}
@@ -814,6 +835,16 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
814835 err = new ERR_STREAM_DESTROYED ( 'write' ) ;
815836 }
816837
838+ if ( msg && ! msg . destroyed ) {
839+ const byteLength = Buffer . byteLength ( chunk , encoding )
840+ if ( msg [ kSentContentLength ] > 0 && msg [ kSentContentLength ] !== NumberPOSITIVE_INFINITY ) {
841+ if ( byteLength + msg [ kBytesWritten ] > msg [ kSentContentLength ] ) {
842+ throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH ( byteLength + msg [ kBytesWritten ] , msg [ kSentContentLength ] ) ;
843+ }
844+ }
845+ msg [ kBytesWritten ] += byteLength ;
846+ }
847+
817848 if ( err ) {
818849 if ( ! msg . destroyed ) {
819850 onError ( msg , err , callback ) ;
0 commit comments