Skip to content

Commit 05d73ac

Browse files
targosMylesBorins
authored andcommitted
buffer: make Blob's slice method more spec-compliant
PR-URL: #37361 Backport-PR-URL: #39704 Fixes: #37335 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent e7cf2ef commit 05d73ac

14 files changed

+1355
-28
lines changed

lib/internal/blob.js

+30-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
const {
44
ArrayFrom,
5+
MathMax,
6+
MathMin,
57
ObjectDefineProperty,
68
ObjectSetPrototypeOf,
79
PromiseResolve,
@@ -43,21 +45,21 @@ const {
4345
codes: {
4446
ERR_INVALID_ARG_TYPE,
4547
ERR_BUFFER_TOO_LARGE,
46-
ERR_OUT_OF_RANGE,
4748
}
4849
} = require('internal/errors');
4950

5051
const {
5152
validateObject,
5253
validateString,
53-
validateUint32,
5454
isUint32,
5555
} = require('internal/validators');
5656

5757
const kHandle = Symbol('kHandle');
5858
const kType = Symbol('kType');
5959
const kLength = Symbol('kLength');
6060

61+
const disallowedTypeCharacters = /[^\u{0020}-\u{007E}]/u;
62+
6163
let Buffer;
6264

6365
function lazyBuffer() {
@@ -141,7 +143,7 @@ class Blob extends JSTransferable {
141143
super();
142144
this[kHandle] = createBlob(sources_, length);
143145
this[kLength] = length;
144-
this[kType] = RegExpPrototypeTest(/[^\u{0020}-\u{007E}]/u, type) ?
146+
this[kType] = RegExpPrototypeTest(disallowedTypeCharacters, type) ?
145147
'' : StringPrototypeToLowerCase(type);
146148
}
147149

@@ -180,18 +182,32 @@ class Blob extends JSTransferable {
180182

181183
get size() { return this[kLength]; }
182184

183-
slice(start = 0, end = (this[kLength]), type = this[kType]) {
184-
validateUint32(start, 'start');
185-
if (end < 0) end = this[kLength] + end;
186-
validateUint32(end, 'end');
187-
validateString(type, 'type');
188-
if (end < start)
189-
throw new ERR_OUT_OF_RANGE('end', 'greater than start', end);
190-
if (end > this[kLength])
191-
throw new ERR_OUT_OF_RANGE('end', 'less than or equal to length', end);
185+
slice(start = 0, end = this[kLength], contentType = '') {
186+
if (start < 0) {
187+
start = MathMax(this[kLength] + start, 0);
188+
} else {
189+
start = MathMin(start, this[kLength]);
190+
}
191+
start |= 0;
192+
193+
if (end < 0) {
194+
end = MathMax(this[kLength] + end, 0);
195+
} else {
196+
end = MathMin(end, this[kLength]);
197+
}
198+
end |= 0;
199+
200+
contentType = `${contentType}`;
201+
if (RegExpPrototypeTest(disallowedTypeCharacters, contentType)) {
202+
contentType = '';
203+
} else {
204+
contentType = StringPrototypeToLowerCase(contentType);
205+
}
206+
207+
const span = MathMax(end - start, 0);
208+
192209
return new InternalBlob(
193-
this[kHandle].slice(start, end),
194-
end - start, type);
210+
this[kHandle].slice(start, start + span), span, contentType);
195211
}
196212

197213
async arrayBuffer() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// META: title=Blob constructor
2+
// META: script=../support/Blob.js
3+
'use strict';
4+
5+
var test_error = {
6+
name: "test",
7+
message: "test error",
8+
};
9+
10+
test(function() {
11+
var args = [
12+
document.createElement("div"),
13+
window,
14+
];
15+
args.forEach(function(arg) {
16+
assert_throws_js(TypeError, function() {
17+
new Blob(arg);
18+
}, "Should throw for argument " + format_value(arg) + ".");
19+
});
20+
}, "Passing platform objects for blobParts should throw a TypeError.");
21+
22+
test(function() {
23+
var element = document.createElement("div");
24+
element.appendChild(document.createElement("div"));
25+
element.appendChild(document.createElement("p"));
26+
var list = element.children;
27+
Object.defineProperty(list, "length", {
28+
get: function() { throw test_error; }
29+
});
30+
assert_throws_exactly(test_error, function() {
31+
new Blob(list);
32+
});
33+
}, "A platform object that supports indexed properties should be treated as a sequence for the blobParts argument (overwritten 'length'.)");
34+
35+
test_blob(function() {
36+
var select = document.createElement("select");
37+
select.appendChild(document.createElement("option"));
38+
return new Blob(select);
39+
}, {
40+
expected: "[object HTMLOptionElement]",
41+
type: "",
42+
desc: "Passing an platform object that supports indexed properties as the blobParts array should work (select)."
43+
});
44+
45+
test_blob(function() {
46+
var elm = document.createElement("div");
47+
elm.setAttribute("foo", "bar");
48+
return new Blob(elm.attributes);
49+
}, {
50+
expected: "[object Attr]",
51+
type: "",
52+
desc: "Passing an platform object that supports indexed properties as the blobParts array should work (attributes)."
53+
});

0 commit comments

Comments
 (0)