@@ -25,7 +25,6 @@ const {
2525 Array,
2626 ArrayIsArray,
2727 ArrayPrototypeJoin,
28- MathAbs,
2928 MathFloor,
3029 NumberPrototypeToString,
3130 ObjectCreate,
@@ -87,7 +86,6 @@ const HIGH_WATER_MARK = getDefaultHighWaterMark();
8786const kCorked = Symbol('corked');
8887const kUniqueHeaders = Symbol('kUniqueHeaders');
8988const kBytesWritten = Symbol('kBytesWritten');
90- const kEndCalled = Symbol('kEndCalled');
9189const kErrored = Symbol('errored');
9290
9391const nop = () => {};
@@ -134,7 +132,6 @@ function OutgoingMessage() {
134132
135133 this.strictContentLength = false;
136134 this[kBytesWritten] = 0;
137- this[kEndCalled] = false;
138135 this._contentLength = null;
139136 this._hasBody = true;
140137 this._trailer = '';
@@ -356,7 +353,7 @@ OutgoingMessage.prototype.destroy = function destroy(error) {
356353
357354
358355// 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 ) {
360357 // This is a shameful hack to get the headers and first body chunk onto
361358 // the same packet. Future versions of Node are going to take care of
362359 // this at a lower level and in a more general way.
@@ -378,20 +375,11 @@ OutgoingMessage.prototype._send = function _send(data, encoding, callback) {
378375 }
379376 this._headerSent = true;
380377 }
381- return this._writeRaw(data, encoding, callback);
378+ return this._writeRaw(data, encoding, callback, byteLength );
382379};
383380
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-
393381OutgoingMessage.prototype._writeRaw = _writeRaw;
394- function _writeRaw(data, encoding, callback) {
382+ function _writeRaw(data, encoding, callback, size ) {
395383 const conn = this.socket;
396384 if (conn && conn.destroyed) {
397385 // The socket was destroyed. If we're still trying to write to it,
@@ -404,25 +392,6 @@ function _writeRaw(data, encoding, callback) {
404392 encoding = null;
405393 }
406394
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-
426395 if (conn && conn._httpMessage === this && conn.writable) {
427396 // There might be pending data in the this.output buffer.
428397 if (this.outputData.length) {
@@ -882,18 +851,24 @@ function emitErrorNt(msg, err, callback) {
882851 }
883852}
884853
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+
885865function write_(msg, chunk, encoding, callback, fromEnd) {
886866 if (typeof callback !== 'function')
887867 callback = nop;
888868
889- let len;
890869 if (chunk === null) {
891870 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)) {
897872 throw new ERR_INVALID_ARG_TYPE(
898873 'chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
899874 }
@@ -914,8 +889,24 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
914889 return false;
915890 }
916891
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+
917907 if (!msg._header) {
918908 if (fromEnd) {
909+ len ??= typeof chunk === 'string' ? Buffer.byteLength(chunk, encoding) : chunk.byteLength;
919910 msg._contentLength = len;
920911 }
921912 msg._implicitHeader();
@@ -935,12 +926,13 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
935926
936927 let ret;
937928 if (msg.chunkedEncoding && chunk.length !== 0) {
929+ len ??= typeof chunk === 'string' ? Buffer.byteLength(chunk, encoding) : chunk.byteLength;
938930 msg._send(NumberPrototypeToString(len, 16), 'latin1', null);
939931 msg._send(crlf_buf, null, null);
940- msg._send(chunk, encoding, null);
932+ msg._send(chunk, encoding, null, len );
941933 ret = msg._send(crlf_buf, null, callback);
942934 } else {
943- ret = msg._send(chunk, encoding, callback);
935+ ret = msg._send(chunk, encoding, callback, len );
944936 }
945937
946938 debug('write ret = ' + ret);
@@ -1012,8 +1004,6 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
10121004 encoding = null;
10131005 }
10141006
1015- this[kEndCalled] = true;
1016-
10171007 if (chunk) {
10181008 if (this.finished) {
10191009 onError(this,
@@ -1048,6 +1038,10 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
10481038 if (typeof callback === 'function')
10491039 this.once('finish', callback);
10501040
1041+ if (strictContentLength(this) && this[kBytesWritten] !== this._contentLength) {
1042+ throw new ERR_HTTP_CONTENT_LENGTH_MISMATCH(this[kBytesWritten], this._contentLength);
1043+ }
1044+
10511045 const finish = onFinish.bind(undefined, this);
10521046
10531047 if (this._hasBody && this.chunkedEncoding) {
0 commit comments