From bf1bbe9cc3bec4e769d311717257f11832dab18d Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 31 Dec 2019 12:43:54 +0100 Subject: [PATCH] stream: simplify Writable.write Backport-PR-URL: https://github.com/nodejs/node/pull/32162 --- lib/_stream_writable.js | 79 +++++++++-------------- test/parallel/test-net-write-arguments.js | 2 +- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index d2c109c302b40c..f643c96635a2c3 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -274,60 +274,52 @@ function writeAfterEnd(stream, cb) { process.nextTick(cb, er); } -// Checks that a user-supplied chunk is valid, especially for the particular -// mode the stream is in. Currently this means that `null` is never accepted -// and undefined/non-string values are only allowed in object mode. -function validChunk(stream, state, chunk, cb) { - var er; - - if (chunk === null) { - er = new ERR_STREAM_NULL_VALUES(); - } else if (typeof chunk !== 'string' && !state.objectMode) { - er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); - } - if (er) { - errorOrDestroy(stream, er); - process.nextTick(cb, er); - return false; - } - return true; -} Writable.prototype.write = function(chunk, encoding, cb) { const state = this._writableState; - var ret = false; - const isBuf = !state.objectMode && Stream._isUint8Array(chunk); - - // Do not use Object.getPrototypeOf as it is slower since V8 7.3. - if (isBuf && !(chunk instanceof Buffer)) { - chunk = Stream._uint8ArrayToBuffer(chunk); - } if (typeof encoding === 'function') { cb = encoding; - encoding = null; - } - - if (isBuf) - encoding = 'buffer'; - else if (!encoding) encoding = state.defaultEncoding; + } else { + if (!encoding) + encoding = state.defaultEncoding; + if (typeof cb !== 'function') + cb = nop; + } - if (typeof cb !== 'function') - cb = nop; - + let err; if (state.ending) { writeAfterEnd(this, cb); } else if (state.destroyed) { - const err = new ERR_STREAM_DESTROYED('write'); + err = new ERR_STREAM_DESTROYED('write'); + } else if (chunk === null) { + err = new ERR_STREAM_NULL_VALUES(); + } else if (!state.objectMode) { + if (typeof chunk === 'string') { + if (state.decodeStrings !== false) { + chunk = Buffer.from(chunk, encoding); + encoding = 'buffer'; + } + } else if (chunk instanceof Buffer) { + encoding = 'buffer'; + } else if (Stream._isUint8Array(chunk)) { + chunk = Stream._uint8ArrayToBuffer(chunk); + encoding = 'buffer'; + } else { + err = new ERR_INVALID_ARG_TYPE( + 'chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + } + } + + if (err) { process.nextTick(cb, err); - errorOrDestroy(this, err); - } else if (isBuf || validChunk(this, state, chunk, cb)) { + errorOrDestroy(this, err, true); + return false; + } else { state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); + return writeOrBuffer(this, state, chunk, encoding, cb); } - - return ret; }; Writable.prototype.cork = function() { @@ -402,13 +394,6 @@ ObjectDefineProperty(Writable.prototype, 'writableCorked', { // in the queue, and wait our turn. Otherwise, call _write // If we return false, then we need a drain event, so set that flag. function writeOrBuffer(stream, state, chunk, encoding, cb) { - if (!state.objectMode && - state.decodeStrings !== false && - encoding !== 'buffer' && - typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); - encoding = 'buffer'; - } const len = state.objectMode ? 1 : chunk.length; state.length += len; diff --git a/test/parallel/test-net-write-arguments.js b/test/parallel/test-net-write-arguments.js index d3dde36b02f852..0e9e30b41da286 100644 --- a/test/parallel/test-net-write-arguments.js +++ b/test/parallel/test-net-write-arguments.js @@ -29,6 +29,6 @@ assert.throws(() => socket.write(null), code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError', message: 'The "chunk" argument must be of type string or an instance of ' + - `Buffer.${common.invalidArgTypeHelper(value)}` + `Buffer or Uint8Array.${common.invalidArgTypeHelper(value)}` })); });