Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit a6f55a1

Browse files
committed
Bug 1864406 - Add ReadableStreamBYOBReader.prototype.read(view, { min }). r=saschanaz,webidl,smaug
Implements whatwg/streams#1145 Differential Revision: https://phabricator.services.mozilla.com/D226225
1 parent 1b924e7 commit a6f55a1

File tree

7 files changed

+188
-325
lines changed

7 files changed

+188
-325
lines changed

dom/streams/ReadableByteStreamController.cpp

Lines changed: 129 additions & 94 deletions
Large diffs are not rendered by default.

dom/streams/ReadableByteStreamController.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerRespondWithNewView(
187187

188188
MOZ_CAN_RUN_SCRIPT void ReadableByteStreamControllerPullInto(
189189
JSContext* aCx, ReadableByteStreamController* aController,
190-
JS::Handle<JSObject*> aView, ReadIntoRequest* aReadIntoRequest,
191-
ErrorResult& aRv);
190+
JS::Handle<JSObject*> aView, uint64_t aMin,
191+
ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv);
192192

193193
void ReadableByteStreamControllerError(
194194
ReadableByteStreamController* aController, JS::Handle<JS::Value> aValue,

dom/streams/ReadableStreamBYOBReader.cpp

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ namespace streams_abstract {
173173
// https://streams.spec.whatwg.org/#readable-stream-byob-reader-read
174174
void ReadableStreamBYOBReaderRead(JSContext* aCx,
175175
ReadableStreamBYOBReader* aReader,
176-
JS::Handle<JSObject*> aView,
176+
JS::Handle<JSObject*> aView, uint64_t aMin,
177177
ReadIntoRequest* aReadIntoRequest,
178178
ErrorResult& aRv) {
179179
// Step 1.Let stream be reader.[[stream]].
@@ -195,19 +195,20 @@ void ReadableStreamBYOBReaderRead(JSContext* aCx,
195195
}
196196

197197
// Step 5. Otherwise, perform
198-
// !ReadableByteStreamControllerPullInto(stream.[[controller]], view,
198+
// !ReadableByteStreamControllerPullInto(stream.[[controller]], view, min,
199199
// readIntoRequest).
200200
MOZ_ASSERT(stream->Controller()->IsByte());
201201
RefPtr<ReadableByteStreamController> controller(
202202
stream->Controller()->AsByte());
203-
ReadableByteStreamControllerPullInto(aCx, controller, aView, aReadIntoRequest,
204-
aRv);
203+
ReadableByteStreamControllerPullInto(aCx, controller, aView, aMin,
204+
aReadIntoRequest, aRv);
205205
}
206206
} // namespace streams_abstract
207207

208208
// https://streams.spec.whatwg.org/#byob-reader-read
209209
already_AddRefed<Promise> ReadableStreamBYOBReader::Read(
210-
const ArrayBufferView& aArray, ErrorResult& aRv) {
210+
const ArrayBufferView& aArray,
211+
const ReadableStreamBYOBReaderReadOptions& aOptions, ErrorResult& aRv) {
211212
AutoJSAPI jsapi;
212213
if (!jsapi.Init(GetParentObject())) {
213214
aRv.ThrowUnknownError("Internal error");
@@ -247,28 +248,60 @@ already_AddRefed<Promise> ReadableStreamBYOBReader::Read(
247248
return nullptr;
248249
}
249250

250-
// Step 4. If this.[[stream]] is undefined, return a promise rejected with a
251+
// Step 4. If options["min"] is 0, return a promise rejected with a TypeError
252+
// exception.
253+
if (aOptions.mMin == 0) {
254+
aRv.ThrowTypeError(
255+
"Zero is not a valid value for 'min' member of "
256+
"ReadableStreamBYOBReaderReadOptions.");
257+
return nullptr;
258+
}
259+
260+
// Step 5. If view has a [[TypedArrayName]] internal slot,
261+
if (JS_IsTypedArrayObject(view)) {
262+
// Step 5.1. If options["min"] > view.[[ArrayLength]], return a promise
263+
// rejected with a RangeError exception.
264+
if (aOptions.mMin > JS_GetTypedArrayLength(view)) {
265+
aRv.ThrowRangeError(
266+
"Array length exceeded by 'min' member of "
267+
"ReadableStreamBYOBReaderReadOptions.");
268+
return nullptr;
269+
}
270+
} else {
271+
// Step 6. Otherwise (i.e., it is a DataView),
272+
// Step 6.1. If options["min"] > view.[[ByteLength]], return a promise
273+
// rejected with a RangeError exception.
274+
if (aOptions.mMin > JS_GetArrayBufferViewByteLength(view)) {
275+
aRv.ThrowRangeError(
276+
"byteLength exceeded by 'min' member of "
277+
"ReadableStreamBYOBReaderReadOptions.");
278+
return nullptr;
279+
}
280+
}
281+
282+
// Step 7. If this.[[stream]] is undefined, return a promise rejected with a
251283
// TypeError exception.
252284
if (!GetStream()) {
253285
aRv.ThrowTypeError("Reader has undefined stream");
254286
return nullptr;
255287
}
256288

257-
// Step 5.
289+
// Step 8. Let promise be a new promise.
258290
RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());
259291

260-
// Step 6. Let readIntoRequest be a new read-into request with the following
292+
// Step 9. Let readIntoRequest be a new read-into request with the following
261293
// items:
262294
RefPtr<ReadIntoRequest> readIntoRequest = new Read_ReadIntoRequest(promise);
263295

264-
// Step 7. Perform ! ReadableStreamBYOBReaderRead(this, view,
296+
// Step 10. Perform ! ReadableStreamBYOBReaderRead(this, view, options["min"],
265297
// readIntoRequest).
266-
ReadableStreamBYOBReaderRead(cx, this, view, readIntoRequest, aRv);
298+
ReadableStreamBYOBReaderRead(cx, this, view, aOptions.mMin, readIntoRequest,
299+
aRv);
267300
if (aRv.Failed()) {
268301
return nullptr;
269302
}
270303

271-
// Step 8. Return promise.
304+
// Step 11. Return promise.
272305
return promise.forget();
273306
}
274307

dom/streams/ReadableStreamBYOBReader.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace mozilla::dom {
2222
class Promise;
2323
struct ReadIntoRequest;
2424
class ReadableStream;
25+
struct ReadableStreamBYOBReaderReadOptions;
2526

2627
} // namespace mozilla::dom
2728

@@ -52,7 +53,8 @@ class ReadableStreamBYOBReader final : public ReadableStreamGenericReader,
5253
const GlobalObject& global, ReadableStream& stream, ErrorResult& rv);
5354

5455
MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> Read(
55-
const ArrayBufferView& aArray, ErrorResult& rv);
56+
const ArrayBufferView& aArray,
57+
const ReadableStreamBYOBReaderReadOptions& aOptions, ErrorResult& rv);
5658

5759
void ReleaseLock(ErrorResult& rv);
5860

@@ -73,8 +75,8 @@ already_AddRefed<ReadableStreamBYOBReader> AcquireReadableStreamBYOBReader(
7375

7476
MOZ_CAN_RUN_SCRIPT void ReadableStreamBYOBReaderRead(
7577
JSContext* aCx, ReadableStreamBYOBReader* aReader,
76-
JS::Handle<JSObject*> aView, ReadIntoRequest* aReadIntoRequest,
77-
ErrorResult& aRv);
78+
JS::Handle<JSObject*> aView, uint64_t aMin,
79+
ReadIntoRequest* aReadIntoRequest, ErrorResult& aRv);
7880

7981
void ReadableStreamBYOBReaderErrorReadIntoRequests(
8082
JSContext* aCx, ReadableStreamBYOBReader* aReader,

dom/streams/ReadableStreamTee.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,11 @@ void PullWithBYOBReader(JSContext* aCx, TeeState* aTeeState,
911911
RefPtr<ReadIntoRequest> readIntoRequest =
912912
new PullWithBYOBReader_ReadIntoRequest(aTeeState, aForBranch);
913913

914-
// Step 16.5.
914+
// Step 16.5. Perform ! ReadableStreamBYOBReaderRead(reader, view, 1,
915+
// readIntoRequest).
915916
RefPtr<ReadableStreamBYOBReader> byobReader =
916917
aTeeState->GetReader()->AsBYOB();
917-
ReadableStreamBYOBReaderRead(aCx, byobReader, aView, readIntoRequest, aRv);
918+
ReadableStreamBYOBReaderRead(aCx, byobReader, aView, 1, readIntoRequest, aRv);
918919
}
919920

920921
// See https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamtee

dom/webidl/ReadableStreamBYOBReader.webidl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ interface ReadableStreamBYOBReader {
1313
constructor(ReadableStream stream);
1414

1515
[NewObject]
16-
Promise<ReadableStreamReadResult> read(ArrayBufferView view);
16+
Promise<ReadableStreamReadResult> read(ArrayBufferView view, optional ReadableStreamBYOBReaderReadOptions options = {});
1717

1818
[Throws]
1919
undefined releaseLock();
2020
};
2121
ReadableStreamBYOBReader includes ReadableStreamGenericReader;
22+
23+
dictionary ReadableStreamBYOBReaderReadOptions {
24+
[EnforceRange] unsigned long long min = 1;
25+
};
Lines changed: 0 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,214 +1,2 @@
1-
[read-min.any.worker.html]
2-
[ReadableStream with byte source: read({ min }) rejects if min is 0]
3-
expected: FAIL
4-
5-
[ReadableStream with byte source: read({ min }) rejects if min is negative]
6-
expected: FAIL
7-
8-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
9-
expected: FAIL
10-
11-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
12-
expected: FAIL
13-
14-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
15-
expected: FAIL
16-
17-
[ReadableStream with byte source: read({ min }), then read()]
18-
expected: FAIL
19-
20-
[ReadableStream with byte source: read({ min }) with a DataView]
21-
expected: FAIL
22-
23-
[ReadableStream with byte source: enqueue(), then read({ min })]
24-
expected: FAIL
25-
26-
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
27-
expected: FAIL
28-
29-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
30-
expected: FAIL
31-
32-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
33-
expected: FAIL
34-
35-
[ReadableStream with byte source: read({ min }) when closed before view is filled]
36-
expected: FAIL
37-
38-
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
39-
expected: FAIL
40-
41-
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
42-
expected: FAIL
43-
44-
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
45-
expected: FAIL
46-
47-
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
48-
expected: FAIL
49-
50-
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
51-
expected: FAIL
52-
53-
54-
[read-min.any.html]
55-
[ReadableStream with byte source: read({ min }) rejects if min is 0]
56-
expected: FAIL
57-
58-
[ReadableStream with byte source: read({ min }) rejects if min is negative]
59-
expected: FAIL
60-
61-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
62-
expected: FAIL
63-
64-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
65-
expected: FAIL
66-
67-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
68-
expected: FAIL
69-
70-
[ReadableStream with byte source: read({ min }), then read()]
71-
expected: FAIL
72-
73-
[ReadableStream with byte source: read({ min }) with a DataView]
74-
expected: FAIL
75-
76-
[ReadableStream with byte source: enqueue(), then read({ min })]
77-
expected: FAIL
78-
79-
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
80-
expected: FAIL
81-
82-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
83-
expected: FAIL
84-
85-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
86-
expected: FAIL
87-
88-
[ReadableStream with byte source: read({ min }) when closed before view is filled]
89-
expected: FAIL
90-
91-
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
92-
expected: FAIL
93-
94-
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
95-
expected: FAIL
96-
97-
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
98-
expected: FAIL
99-
100-
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
101-
expected: FAIL
102-
103-
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
104-
expected: FAIL
105-
106-
107-
[read-min.any.serviceworker.html]
108-
[ReadableStream with byte source: read({ min }) rejects if min is 0]
109-
expected: FAIL
110-
111-
[ReadableStream with byte source: read({ min }) rejects if min is negative]
112-
expected: FAIL
113-
114-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
115-
expected: FAIL
116-
117-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
118-
expected: FAIL
119-
120-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
121-
expected: FAIL
122-
123-
[ReadableStream with byte source: read({ min }), then read()]
124-
expected: FAIL
125-
126-
[ReadableStream with byte source: read({ min }) with a DataView]
127-
expected: FAIL
128-
129-
[ReadableStream with byte source: enqueue(), then read({ min })]
130-
expected: FAIL
131-
132-
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
133-
expected: FAIL
134-
135-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
136-
expected: FAIL
137-
138-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
139-
expected: FAIL
140-
141-
[ReadableStream with byte source: read({ min }) when closed before view is filled]
142-
expected: FAIL
143-
144-
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
145-
expected: FAIL
146-
147-
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
148-
expected: FAIL
149-
150-
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
151-
expected: FAIL
152-
153-
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
154-
expected: FAIL
155-
156-
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
157-
expected: FAIL
158-
159-
160-
[read-min.any.sharedworker.html]
161-
[ReadableStream with byte source: read({ min }) rejects if min is 0]
162-
expected: FAIL
163-
164-
[ReadableStream with byte source: read({ min }) rejects if min is negative]
165-
expected: FAIL
166-
167-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint8Array)]
168-
expected: FAIL
169-
170-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (Uint16Array)]
171-
expected: FAIL
172-
173-
[ReadableStream with byte source: read({ min }) rejects if min is larger than view's length (DataView)]
174-
expected: FAIL
175-
176-
[ReadableStream with byte source: read({ min }), then read()]
177-
expected: FAIL
178-
179-
[ReadableStream with byte source: read({ min }) with a DataView]
180-
expected: FAIL
181-
182-
[ReadableStream with byte source: enqueue(), then read({ min })]
183-
expected: FAIL
184-
185-
[ReadableStream with byte source: read({ min: 3 }) on a 3-byte Uint8Array, then multiple enqueue() up to 3 bytes]
186-
expected: FAIL
187-
188-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 3 bytes]
189-
expected: FAIL
190-
191-
[ReadableStream with byte source: read({ min: 3 }) on a 5-byte Uint8Array, then multiple enqueue() up to 4 bytes]
192-
expected: FAIL
193-
194-
[ReadableStream with byte source: read({ min }) when closed before view is filled]
195-
expected: FAIL
196-
197-
[ReadableStream with byte source: read({ min }) when closed immediately after view is filled]
198-
expected: FAIL
199-
200-
[ReadableStream with byte source: cancel() with partially filled pending read({ min }) request]
201-
expected: FAIL
202-
203-
[ReadableStream with byte source: 3 byte enqueue(), then close(), then read({ min }) with 2-element Uint16Array must fail]
204-
expected: FAIL
205-
206-
[ReadableStream with byte source: read({ min }) with 2-element Uint16Array, then 3 byte enqueue(), then close() must fail]
207-
expected: FAIL
208-
209-
[ReadableStream with byte source: tee() with read({ min }) from branch1 and read() from branch2]
210-
expected: FAIL
211-
212-
2131
[read-min.any.shadowrealm.html]
2142
expected: ERROR

0 commit comments

Comments
 (0)