diff --git a/lib/fs.js b/lib/fs.js index 2de5f8dd6e205b..489f7c0fd1a6a7 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -2009,12 +2009,20 @@ function ReadStream(path, options) { if (this.start !== undefined) { if (typeof this.start !== 'number') { - throw new ERR_INVALID_ARG_TYPE('start', 'number', this.start); + throw new ERR_INVALID_ARG_TYPE('options.start', 'number', options.start); + } + if (!Number.isInteger(this.start)) { + throw new ERR_OUT_OF_RANGE('options.start', 'integer', options.start); } if (this.end === undefined) { this.end = Infinity; - } else if (typeof this.end !== 'number') { - throw new ERR_INVALID_ARG_TYPE('end', 'number', this.end); + } else { + if (typeof this.end !== 'number') { + throw new ERR_INVALID_ARG_TYPE('options.end', 'number', this.end); + } + if (!(Number.isInteger(this.end) || this.end === Infinity)) { + throw new ERR_OUT_OF_RANGE('options.end', 'integer/infinity', this.end); + } } if (this.start > this.end) { @@ -2023,13 +2031,15 @@ function ReadStream(path, options) { } this.pos = this.start; - } - - // Backwards compatibility: Make sure `end` is a number regardless of `start`. - // TODO(addaleax): Make the above typecheck not depend on `start` instead. - // (That is a semver-major change). - if (typeof this.end !== 'number') + } else if (typeof this.end !== 'number') { + // Backwards compatibility: Make sure `end` is a number regardless of + // `start`. + // TODO(addaleax): Make the above typecheck not depend on `start` instead. + // (That is a semver-major change). this.end = Infinity; + } else if (!(Number.isInteger(this.end) || this.end === Infinity)) { + throw new ERR_OUT_OF_RANGE('options.end', 'integer/infinity', this.end); + } if (typeof this.fd !== 'number') this.open(); diff --git a/test/parallel/test-fs-read-stream-throw-type-error.js b/test/parallel/test-fs-read-stream-throw-type-error.js index c2b0d5452c55e3..b444e48a9d4792 100644 --- a/test/parallel/test-fs-read-stream-throw-type-error.js +++ b/test/parallel/test-fs-read-stream-throw-type-error.js @@ -1,6 +1,10 @@ 'use strict'; const common = require('../common'); const fixtures = require('../common/fixtures'); + +// This test ensures that fs.createReadStream throws a TypeError when invalid +// arguments are passed to it. + const fs = require('fs'); const example = fixtures.path('x.txt'); @@ -10,18 +14,31 @@ fs.createReadStream(example, null); fs.createReadStream(example, 'utf8'); fs.createReadStream(example, { encoding: 'utf8' }); -const createReadStreamErr = (path, opt) => { +const createReadStreamErr = (path, opt, errorCode) => { common.expectsError( () => { fs.createReadStream(path, opt); }, { - code: 'ERR_INVALID_ARG_TYPE', + code: errorCode, type: TypeError }); }; -createReadStreamErr(example, 123); -createReadStreamErr(example, 0); -createReadStreamErr(example, true); -createReadStreamErr(example, false); +createReadStreamErr(example, 123, 'ERR_INVALID_ARG_TYPE'); +createReadStreamErr(example, 0, 'ERR_INVALID_ARG_TYPE'); +createReadStreamErr(example, true, 'ERR_INVALID_ARG_TYPE'); +createReadStreamErr(example, false, 'ERR_INVALID_ARG_TYPE'); + +// Should also throw on NaN (for https://github.com/nodejs/node/pull/19732) +createReadStreamErr(example, { start: NaN }, 'ERR_OUT_OF_RANGE'); +createReadStreamErr(example, { end: NaN }, 'ERR_OUT_OF_RANGE'); +createReadStreamErr(example, { start: NaN, end: NaN }, 'ERR_OUT_OF_RANGE'); + +// Should also throw on non-integer Numbers and non-numbers +createReadStreamErr(example, { start: 'a' }, 'ERR_INVALID_ARG_TYPE'); +createReadStreamErr(example, { start: 0.1 }, 'ERR_OUT_OF_RANGE'); +createReadStreamErr(example, { start: 0, end: 'a' }, 'ERR_INVALID_ARG_TYPE'); +createReadStreamErr(example, { start: 0, end: 0.1 }, 'ERR_OUT_OF_RANGE'); +createReadStreamErr(example, { start: 1, end: 0 }, 'ERR_OUT_OF_RANGE'); +createReadStreamErr(example, { end: 0.1 }, 'ERR_OUT_OF_RANGE');