Skip to content

Add state checks to Close() and Enqueue() #1029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2065,11 +2065,11 @@ export>ReadableStreamDefaultControllerClose ( <var>controller</var> )</h4>

This abstract operation can be called by other specifications that wish to close a readable stream, in the same way
a developer-created stream would be closed by its associated controller object. Specifications should <em>not</em> do
this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as asserts).
this to streams they did not create.

<emu-alg>
1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(_controller_) is *false*, return.
1. Let _stream_ be _controller_.[[controlledReadableStream]].
1. Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(_controller_) is *true*.
1. Set _controller_.[[closeRequested]] to *true*.
1. If _controller_.[[queue]] is empty,
1. Perform ! ReadableStreamDefaultControllerClearAlgorithms(_controller_).
Expand All @@ -2081,12 +2081,11 @@ export>ReadableStreamDefaultControllerEnqueue ( <var>controller</var>, <var>chun

This abstract operation can be called by other specifications that wish to enqueue <a>chunks</a> in a readable stream,
in the same way a developer would enqueue chunks using the stream's associated controller object. Specifications should
<em>not</em> do this to streams they did not create, and must ensure they have obeyed the preconditions (listed here as
asserts).
<em>not</em> do this to streams they did not create.

<emu-alg>
1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(_controller_) is *false*, return.
1. Let _stream_ be _controller_.[[controlledReadableStream]].
1. Assert: ! ReadableStreamDefaultControllerCanCloseOrEnqueue(_controller_) is *true*.
1. If ! IsReadableStreamLocked(_stream_) is *true* and ! ReadableStreamGetNumReadRequests(_stream_) > *0*, perform
! ReadableStreamFulfillReadRequest(_stream_, _chunk_, *false*).
1. Otherwise,
Expand Down Expand Up @@ -2610,8 +2609,7 @@ throws>ReadableByteStreamControllerClose ( <var>controller</var> )</h4>

<emu-alg>
1. Let _stream_ be _controller_.[[controlledReadableByteStream]].
1. Assert: _controller_.[[closeRequested]] is *false*.
1. Assert: _stream_.[[state]] is `"readable"`.
1. If _controller_.[[closeRequested]] is *true* or _stream_.[[state]] is not `"readable"`, return.
1. If _controller_.[[queueTotalSize]] > *0*,
1. Set _controller_.[[closeRequested]] to *true*.
1. Return.
Expand Down Expand Up @@ -2661,8 +2659,7 @@ nothrow>ReadableByteStreamControllerEnqueue ( <var>controller</var>, <var>chunk<

<emu-alg>
1. Let _stream_ be _controller_.[[controlledReadableByteStream]].
1. Assert: _controller_.[[closeRequested]] is *false*.
1. Assert: _stream_.[[state]] is `"readable"`.
1. If _controller_.[[closeRequested]] is *true* or _stream_.[[state]] is not `"readable"`, return.
1. Let _buffer_ be _chunk_.[[ViewedArrayBuffer]].
1. Let _byteOffset_ be _chunk_.[[ByteOffset]].
1. Let _byteLength_ be _chunk_.[[ByteLength]].
Expand Down Expand Up @@ -4994,8 +4991,7 @@ this to streams they did not create.
<emu-alg>
1. Let _stream_ be _controller_.[[controlledTransformStream]].
1. Let _readableController_ be _stream_.[[readable]].[[readableStreamController]].
1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(_readableController_) is *true*, perform !
ReadableStreamDefaultControllerClose(_readableController_).
1. Perform ! ReadableStreamDefaultControllerClose(_readableController_).
1. Let _error_ be a *TypeError* exception indicating that the stream has been terminated.
1. Perform ! TransformStreamErrorWritableAndUnblockWrite(_stream_, _error_).
</emu-alg>
Expand Down
26 changes: 14 additions & 12 deletions reference-implementation/lib/readable-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -1221,12 +1221,12 @@ function ReadableStreamDefaultControllerClearAlgorithms(controller) {
controller._strategySizeAlgorithm = undefined;
}

// A client of ReadableStreamDefaultController may use these functions directly to bypass state check.

function ReadableStreamDefaultControllerClose(controller) {
const stream = controller._controlledReadableStream;
if (ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) === false) {
return;
}

assert(ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) === true);
const stream = controller._controlledReadableStream;

controller._closeRequested = true;

Expand All @@ -1237,9 +1237,11 @@ function ReadableStreamDefaultControllerClose(controller) {
}

function ReadableStreamDefaultControllerEnqueue(controller, chunk) {
const stream = controller._controlledReadableStream;
if (ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) === false) {
return;
}

assert(ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) === true);
const stream = controller._controlledReadableStream;

if (IsReadableStreamLocked(stream) === true && ReadableStreamGetNumReadRequests(stream) > 0) {
ReadableStreamFulfillReadRequest(stream, chunk, false);
Expand Down Expand Up @@ -1926,13 +1928,12 @@ function ReadableByteStreamControllerClearAlgorithms(controller) {
controller._cancelAlgorithm = undefined;
}

// A client of ReadableByteStreamController may use these functions directly to bypass state check.

function ReadableByteStreamControllerClose(controller) {
const stream = controller._controlledReadableByteStream;

assert(controller._closeRequested === false);
assert(stream._state === 'readable');
if (controller._closeRequest === true || stream._state !== 'readable') {
return;
}

if (controller._queueTotalSize > 0) {
controller._closeRequested = true;
Expand All @@ -1957,8 +1958,9 @@ function ReadableByteStreamControllerClose(controller) {
function ReadableByteStreamControllerEnqueue(controller, chunk) {
const stream = controller._controlledReadableByteStream;

assert(controller._closeRequested === false);
assert(stream._state === 'readable');
if (controller._closeRequest === true || stream._state !== 'readable') {
return;
}

const buffer = chunk.buffer;
const byteOffset = chunk.byteOffset;
Expand Down
4 changes: 1 addition & 3 deletions reference-implementation/lib/transform-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,7 @@ function TransformStreamDefaultControllerTerminate(controller) {
const stream = controller._controlledTransformStream;
const readableController = stream._readable._readableStreamController;

if (ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController) === true) {
ReadableStreamDefaultControllerClose(readableController);
}
ReadableStreamDefaultControllerClose(readableController);

const error = new TypeError('TransformStream terminated');
TransformStreamErrorWritableAndUnblockWrite(stream, error);
Expand Down