fs: improve argument handling for ReadStream
Improve handling of erratic arguments in fs.ReadStream Refs: https://github.com/nodejs/node/pull/19732 PR-URL: https://github.com/nodejs/node/pull/19898 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
parent
745463a0b7
commit
19374fd25b
@ -1299,6 +1299,11 @@ fs.copyFileSync('source.txt', 'destination.txt', COPYFILE_EXCL);
|
||||
<!-- YAML
|
||||
added: v0.1.31
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/19898
|
||||
description: Impose new restrictions on `start` and `end`, throwing
|
||||
more appropriate errors in cases when we cannot reasonably
|
||||
handle the input values.
|
||||
- version: v7.6.0
|
||||
pr-url: https://github.com/nodejs/node/pull/10739
|
||||
description: The `path` parameter can be a WHATWG `URL` object using
|
||||
|
55
lib/fs.js
55
lib/fs.js
@ -2031,30 +2031,51 @@ function ReadStream(path, options) {
|
||||
this.closed = false;
|
||||
|
||||
if (this.start !== undefined) {
|
||||
if (typeof this.start !== 'number' || Number.isNaN(this.start)) {
|
||||
throw new ERR_INVALID_ARG_TYPE('start', 'number', this.start);
|
||||
if (!Number.isSafeInteger(this.start)) {
|
||||
if (typeof this.start !== 'number')
|
||||
throw new ERR_INVALID_ARG_TYPE('start', 'number', this.start);
|
||||
if (!Number.isInteger(this.start))
|
||||
throw new ERR_OUT_OF_RANGE('start', 'an integer', this.start);
|
||||
throw new ERR_OUT_OF_RANGE(
|
||||
'start',
|
||||
'>= 0 and <= 2 ** 53 - 1',
|
||||
this.start
|
||||
);
|
||||
}
|
||||
if (this.end === undefined) {
|
||||
this.end = Infinity;
|
||||
} else if (typeof this.end !== 'number' || Number.isNaN(this.end)) {
|
||||
throw new ERR_INVALID_ARG_TYPE('end', 'number', this.end);
|
||||
}
|
||||
|
||||
if (this.start > this.end) {
|
||||
const errVal = `{start: ${this.start}, end: ${this.end}}`;
|
||||
throw new ERR_OUT_OF_RANGE('start', '<= "end"', errVal);
|
||||
if (this.start < 0) {
|
||||
throw new ERR_OUT_OF_RANGE(
|
||||
'start',
|
||||
'>= 0 and <= 2 ** 53 - 1',
|
||||
this.start
|
||||
);
|
||||
}
|
||||
|
||||
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')
|
||||
if (this.end === undefined) {
|
||||
this.end = Infinity;
|
||||
else if (Number.isNaN(this.end))
|
||||
throw new ERR_INVALID_ARG_TYPE('end', 'number', this.end);
|
||||
} else if (this.end !== Infinity) {
|
||||
if (!Number.isSafeInteger(this.end)) {
|
||||
if (typeof this.end !== 'number')
|
||||
throw new ERR_INVALID_ARG_TYPE('end', 'number', this.end);
|
||||
if (!Number.isInteger(this.end))
|
||||
throw new ERR_OUT_OF_RANGE('end', 'an integer', this.end);
|
||||
throw new ERR_OUT_OF_RANGE('end', '>= 0 and <= 2 ** 53 - 1', this.end);
|
||||
}
|
||||
|
||||
if (this.end < 0) {
|
||||
throw new ERR_OUT_OF_RANGE('end', '>= 0 and <= 2 ** 53 - 1', this.end);
|
||||
}
|
||||
|
||||
if (this.start !== undefined && this.start > this.end) {
|
||||
throw new ERR_OUT_OF_RANGE(
|
||||
'start',
|
||||
`<= "end" (here: ${this.end})`,
|
||||
this.start
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.fd !== 'number')
|
||||
this.open();
|
||||
|
@ -110,8 +110,8 @@ const rangeFile = fixtures.path('x.txt');
|
||||
|
||||
{
|
||||
const message =
|
||||
'The value of "start" is out of range. It must be <= "end". ' +
|
||||
'Received {start: 10, end: 2}';
|
||||
'The value of "start" is out of range. It must be <= "end" (here: 2).' +
|
||||
' Received 10';
|
||||
|
||||
common.expectsError(
|
||||
() => {
|
||||
|
@ -13,23 +13,55 @@ fs.createReadStream(example, null);
|
||||
fs.createReadStream(example, 'utf8');
|
||||
fs.createReadStream(example, { encoding: 'utf8' });
|
||||
|
||||
const createReadStreamErr = (path, opt) => {
|
||||
common.expectsError(
|
||||
() => {
|
||||
fs.createReadStream(path, opt);
|
||||
},
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
});
|
||||
const createReadStreamErr = (path, opt, error) => {
|
||||
common.expectsError(() => {
|
||||
fs.createReadStream(path, opt);
|
||||
}, error);
|
||||
};
|
||||
|
||||
createReadStreamErr(example, 123);
|
||||
createReadStreamErr(example, 0);
|
||||
createReadStreamErr(example, true);
|
||||
createReadStreamErr(example, false);
|
||||
const typeError = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
};
|
||||
|
||||
// createReadSteam _should_ throw on NaN
|
||||
createReadStreamErr(example, { start: NaN });
|
||||
createReadStreamErr(example, { end: NaN });
|
||||
createReadStreamErr(example, { start: NaN, end: NaN });
|
||||
const rangeError = {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError
|
||||
};
|
||||
|
||||
[123, 0, true, false].forEach((opts) =>
|
||||
createReadStreamErr(example, opts, typeError)
|
||||
);
|
||||
|
||||
// Case 0: Should not throw if either start or end is undefined
|
||||
[{}, { start: 0 }, { end: Infinity }].forEach((opts) =>
|
||||
fs.createReadStream(example, opts)
|
||||
);
|
||||
|
||||
// Case 1: Should throw TypeError if either start or end is not of type 'number'
|
||||
[
|
||||
{ start: 'invalid' },
|
||||
{ end: 'invalid' },
|
||||
{ start: 'invalid', end: 'invalid' }
|
||||
].forEach((opts) => createReadStreamErr(example, opts, typeError));
|
||||
|
||||
// Case 2: Should throw RangeError if either start or end is NaN
|
||||
[{ start: NaN }, { end: NaN }, { start: NaN, end: NaN }].forEach((opts) =>
|
||||
createReadStreamErr(example, opts, rangeError)
|
||||
);
|
||||
|
||||
// Case 3: Should throw RangeError if either start or end is negative
|
||||
[{ start: -1 }, { end: -1 }, { start: -1, end: -1 }].forEach((opts) =>
|
||||
createReadStreamErr(example, opts, rangeError)
|
||||
);
|
||||
|
||||
// Case 4: Should throw RangeError if either start or end is fractional
|
||||
[{ start: 0.1 }, { end: 0.1 }, { start: 0.1, end: 0.1 }].forEach((opts) =>
|
||||
createReadStreamErr(example, opts, rangeError)
|
||||
);
|
||||
|
||||
// Case 5: Should not throw if both start and end are whole numbers
|
||||
fs.createReadStream(example, { start: 1, end: 5 });
|
||||
|
||||
// Case 6: Should throw RangeError if start is greater than end
|
||||
createReadStreamErr(example, { start: 5, end: 1 }, rangeError);
|
||||
|
@ -148,8 +148,8 @@ common.expectsError(
|
||||
},
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
message: 'The value of "start" is out of range. It must be <= "end". ' +
|
||||
'Received {start: 10, end: 2}',
|
||||
message: 'The value of "start" is out of range. It must be <= "end"' +
|
||||
' (here: 2). Received 10',
|
||||
type: RangeError
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user