[Readable Streams API] Implement ReadableStreamBYOBRequest respond() (closed stream...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 12 Mar 2017 17:27:48 +0000 (17:27 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 12 Mar 2017 17:27:48 +0000 (17:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=168781

Patch by Romain Bellessort <romain.bellessort@crf.canon.fr> on 2017-03-12
Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Updated WPT expectations for readable byte streams tests.

* web-platform-tests/streams/readable-byte-streams/general-expected.txt:
* web-platform-tests/streams/readable-byte-streams/general.dedicatedworker-expected.txt:

Source/WebCore:

Implemented ReadableStreamBYOBRequest respond() method in the case of a closed stream.

Added tests related to respond() method and updated WPT imported tests expectations.

* Modules/streams/ReadableByteStreamInternals.js:
(readableByteStreamControllerRespond): Added.
(readableByteStreamControllerRespondInternal): Added.
(readableByteStreamControllerRespondInClosedState): Added.
(readableByteStreamControllerShiftPendingPullInto): Added.
(readableByteStreamControllerInvalidateBYOBRequest): Added.
(readableByteStreamControllerCommitPullIntoDescriptor): Added.
(readableByteStreamControllerConvertPullIntoDescriptor): Added.
(readableStreamFulfillReadIntoRequest): Added.
* Modules/streams/ReadableStreamBYOBRequest.js:
(respond): Implemented.

LayoutTests:

Added new tests related to ReadableStreamBYOBRequeset respond() method.

* streams/readable-stream-byob-request-expected.txt:
* streams/readable-stream-byob-request.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@213770 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/streams/readable-byte-streams/general-expected.txt
LayoutTests/imported/w3c/web-platform-tests/streams/readable-byte-streams/general.dedicatedworker-expected.txt
LayoutTests/streams/readable-stream-byob-request-expected.txt
LayoutTests/streams/readable-stream-byob-request.js
Source/WebCore/ChangeLog
Source/WebCore/Modules/streams/ReadableByteStreamInternals.js
Source/WebCore/Modules/streams/ReadableStreamBYOBRequest.js

index a8b3150..0b5e41d 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-12  Romain Bellessort  <romain.bellessort@crf.canon.fr>
+
+        [Readable Streams API] Implement ReadableStreamBYOBRequest respond() (closed stream state)
+        https://bugs.webkit.org/show_bug.cgi?id=168781
+
+        Reviewed by Youenn Fablet.
+
+        Added new tests related to ReadableStreamBYOBRequeset respond() method.
+
+        * streams/readable-stream-byob-request-expected.txt:
+        * streams/readable-stream-byob-request.js:
+
 2017-03-11  Youenn Fablet  <youenn@apple.com>
 
         XMLHttpRequest: make setRequestHeader() use `, ` as separator (including a space)
index a59fb22..f1f2b7a 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-12  Romain Bellessort  <romain.bellessort@crf.canon.fr>
+
+        [Readable Streams API] Implement ReadableStreamBYOBRequest respond() (closed stream state)
+        https://bugs.webkit.org/show_bug.cgi?id=168781
+
+        Reviewed by Youenn Fablet.
+
+        Updated WPT expectations for readable byte streams tests.
+
+        * web-platform-tests/streams/readable-byte-streams/general-expected.txt:
+        * web-platform-tests/streams/readable-byte-streams/general.dedicatedworker-expected.txt:
+
 2017-03-11  Youenn Fablet  <youenn@apple.com>
 
         XMLHttpRequest: make setRequestHeader() use `, ` as separator (including a space)
index f3df1d0..8aaf280 100644 (file)
@@ -14,7 +14,7 @@ PASS ReadableStream with byte source: releaseLock() on ReadableStreamReader with
 PASS ReadableStream with byte source: Automatic pull() after start() 
 PASS ReadableStream with byte source: Automatic pull() after start() and read() 
 FAIL ReadableStream with byte source: autoAllocateChunkSize assert_equals: pull() must have been invoked once expected 1 but got 0
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB promise_test: Unhandled rejection with value: object "TypeError: ReadableStreamBYOBRequest respond() is not implemented"
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB promise_test: Unhandled rejection with value: object "TypeError: Readable state is not yet supported"
 PASS ReadableStream with byte source: Automatic pull() after start() and read(view) 
 PASS ReadableStream with byte source: enqueue(), getReader(), then read() 
 PASS ReadableStream with byte source: Push source that doesn't understand pull signal 
index f3df1d0..8aaf280 100644 (file)
@@ -14,7 +14,7 @@ PASS ReadableStream with byte source: releaseLock() on ReadableStreamReader with
 PASS ReadableStream with byte source: Automatic pull() after start() 
 PASS ReadableStream with byte source: Automatic pull() after start() and read() 
 FAIL ReadableStream with byte source: autoAllocateChunkSize assert_equals: pull() must have been invoked once expected 1 but got 0
-FAIL ReadableStream with byte source: Mix of auto allocate and BYOB promise_test: Unhandled rejection with value: object "TypeError: ReadableStreamBYOBRequest respond() is not implemented"
+FAIL ReadableStream with byte source: Mix of auto allocate and BYOB promise_test: Unhandled rejection with value: object "TypeError: Readable state is not yet supported"
 PASS ReadableStream with byte source: Automatic pull() after start() and read(view) 
 PASS ReadableStream with byte source: enqueue(), getReader(), then read() 
 PASS ReadableStream with byte source: Push source that doesn't understand pull signal 
index f059e37..d5dbbc3 100644 (file)
@@ -2,7 +2,19 @@
 PASS ReadableStreamBYOBRequest instances should have the correct list of properties 
 PASS By default, byobRequest should be undefined 
 PASS byobRequest.view length should be equal to autoAllocateChunkSize 
+PASS Calling respond() with a this object different from ReadableStreamBYOBRequest should throw a TypeError 
+PASS Calling respond() with a negative bytesWritten value should throw a RangeError 
+PASS Calling respond() with a bytesWritten value which is not a number should throw a RangeError 
+PASS Calling respond() with a positive infinity bytesWritten value should throw a RangeError 
+PASS Calling respond() with a bytesWritten value different from 0 when stream is closed should throw a TypeError 
+PASS Calling respond() with a bytesWritten value of 0 when stream is closed should succeed 
 PASS ReadableStreamBYOBRequest instances should have the correct list of properties 
 PASS By default, byobRequest should be undefined 
 PASS byobRequest.view length should be equal to autoAllocateChunkSize 
+PASS Calling respond() with a this object different from ReadableStreamBYOBRequest should throw a TypeError 
+PASS Calling respond() with a negative bytesWritten value should throw a RangeError 
+PASS Calling respond() with a bytesWritten value which is not a number should throw a RangeError 
+PASS Calling respond() with a positive infinity bytesWritten value should throw a RangeError 
+PASS Calling respond() with a bytesWritten value different from 0 when stream is closed should throw a TypeError 
+PASS Calling respond() with a bytesWritten value of 0 when stream is closed should succeed 
 
index 0760a37..e77dadd 100644 (file)
@@ -85,4 +85,117 @@ test(function() {
 
 }, "byobRequest.view length should be equal to autoAllocateChunkSize")
 
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+
+    assert_throws(new TypeError("Can only call ReadableStreamBYOBRequest.respond on instances of ReadableStreamBYOBRequest"),
+        function() { byobReq.respond.apply(rs, 1); });
+
+}, "Calling respond() with a this object different from ReadableStreamBYOBRequest should throw a TypeError");
+
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+
+    assert_throws(new RangeError("bytesWritten has an incorrect value"),
+        function() { byobReq.respond(-1); });
+}, "Calling respond() with a negative bytesWritten value should throw a RangeError");
+
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+
+    assert_throws(new RangeError("bytesWritten has an incorrect value"),
+        function() { byobReq.respond("abc"); });
+}, "Calling respond() with a bytesWritten value which is not a number should throw a RangeError");
+
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+
+    assert_throws(new RangeError("bytesWritten has an incorrect value"),
+        function() { byobReq.respond(Number.POSITIVE_INFINITY); });
+}, "Calling respond() with a positive infinity bytesWritten value should throw a RangeError");
+
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+    controller.close();
+
+    assert_throws(new TypeError("bytesWritten is different from 0 even though stream is closed"),
+        function() { byobReq.respond(1); });
+}, "Calling respond() with a bytesWritten value different from 0 when stream is closed should throw a TypeError");
+
+test(function() {
+
+    let controller;
+    const rs = new ReadableStream({
+        autoAllocateChunkSize: 16,
+        start: function(c) {
+            controller = c;
+        },
+        type: "bytes"
+    });
+
+    // FIXME: When ReadableStreamBYOBReader is implemented, another test (or even several ones)
+    // based on this one should be added so that reader's readIntoRequests attribute is not empty
+    // and currently unreachable code is reached.
+    rs.getReader().read();
+    const byobReq = controller.byobRequest;
+    controller.close();
+    byobReq.respond(0);
+
+}, "Calling respond() with a bytesWritten value of 0 when stream is closed should succeed");
+
 done();
index 6b3c94e..c32211c 100644 (file)
@@ -1,3 +1,26 @@
+2017-03-12  Romain Bellessort  <romain.bellessort@crf.canon.fr>
+
+        [Readable Streams API] Implement ReadableStreamBYOBRequest respond() (closed stream state)
+        https://bugs.webkit.org/show_bug.cgi?id=168781
+
+        Reviewed by Youenn Fablet.
+
+        Implemented ReadableStreamBYOBRequest respond() method in the case of a closed stream.
+
+        Added tests related to respond() method and updated WPT imported tests expectations.
+
+        * Modules/streams/ReadableByteStreamInternals.js:
+        (readableByteStreamControllerRespond): Added.
+        (readableByteStreamControllerRespondInternal): Added.
+        (readableByteStreamControllerRespondInClosedState): Added.
+        (readableByteStreamControllerShiftPendingPullInto): Added.
+        (readableByteStreamControllerInvalidateBYOBRequest): Added.
+        (readableByteStreamControllerCommitPullIntoDescriptor): Added.
+        (readableByteStreamControllerConvertPullIntoDescriptor): Added.
+        (readableStreamFulfillReadIntoRequest): Added.
+        * Modules/streams/ReadableStreamBYOBRequest.js:
+        (respond): Implemented.
+
 2017-03-11  Simon Fraser  <simon.fraser@apple.com>
 
         Fix memory estimate for layers supporting subpixel-antialised text
index 12ab060..44367c1 100644 (file)
@@ -345,3 +345,111 @@ function readableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byt
     });
     controller.@totalQueuedBytes += byteLength;
 }
+
+function readableByteStreamControllerRespond(controller, bytesWritten)
+{
+    "use strict";
+
+    bytesWritten = @Number(bytesWritten);
+
+    if (@isNaN(bytesWritten) || bytesWritten === @Number.POSITIVE_INFINITY || bytesWritten < 0 )
+        @throwRangeError("bytesWritten has an incorrect value");
+
+    @assert(controller.@pendingPullIntos.length > 0);
+
+    @readableByteStreamControllerRespondInternal(controller, bytesWritten);
+}
+
+function readableByteStreamControllerRespondInternal(controller, bytesWritten)
+{
+    "use strict";
+
+    let firstDescriptor = controller.@pendingPullIntos[0];
+    let stream = controller.@controlledReadableStream;
+
+    if (stream.@state === @streamClosed) {
+        if (bytesWritten !== 0)
+            @throwTypeError("bytesWritten is different from 0 even though stream is closed");
+        @readableByteStreamControllerRespondInClosedState(controller, firstDescriptor);
+    } else {
+        // FIXME: Also implement case of readable state (distinct patch to avoid adding too many different cases
+        // in a single patch).
+        @throwTypeError("Readable state is not yet supported");
+    }
+}
+
+function readableByteStreamControllerRespondInClosedState(controller, firstDescriptor)
+{
+    "use strict";
+
+    firstDescriptor.buffer = @transferBufferToCurrentRealm(firstDescriptor.buffer);
+    @assert(firstDescriptor.bytesFilled === 0);
+
+    // FIXME: Spec does not describe below test. However, only ReadableStreamBYOBReader has a readIntoRequests
+    // property. This issue has been reported through WHATWG/streams GitHub
+    // (https://github.com/whatwg/streams/issues/686), but no solution has been provided for the moment.
+    // Therefore, below test is added as a temporary fix.
+    if (!@isReadableStreamBYOBReader(controller.@reader))
+        return;
+
+    while (controller.@reader.@readIntoRequests.length > 0) {
+        let pullIntoDescriptor = @readableByteStreamControllerShiftPendingPullInto(controller);
+        @readableByteStreamControllerCommitPullIntoDescriptor(controller.@controlledReadableStream, pullIntoDescriptor);
+    }
+}
+
+function readableByteStreamControllerShiftPendingPullInto(controller)
+{
+    "use strict";
+
+    let descriptor = controller.@pendingPullIntos.@shift();
+    @readableByteStreamControllerInvalidateBYOBRequest(controller);
+    return descriptor;
+}
+
+function readableByteStreamControllerInvalidateBYOBRequest(controller)
+{
+    "use strict";
+
+    if (controller.@byobRequest === @undefined)
+        return;
+    controller.@byobRequest.@associatedReadableByteStreamController = @undefined;
+    controller.@byobRequest.@view = @undefined;
+    controller.@byobRequest = @undefined;
+}
+
+function readableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor)
+{
+    "use strict";
+
+    @assert(stream.@state !== @streamErrored);
+    let done = false;
+    if (stream.@state === @streamClosed) {
+        @assert(!pullIntoDescriptor.bytesFilled);
+        done = true;
+    }
+    let filledView = @readableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);
+    if (pullIntoDescriptor.readerType === "default")
+        @readableStreamFulfillReadRequest(stream, filledView, done);
+    else {
+        @assert(pullIntoDescriptor.readerType === "byob");
+        @readableStreamFulfillReadIntoRequest(stream, filledView, done);
+    }
+}
+
+function readableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor)
+{
+    "use strict";
+
+    @assert(pullIntoDescriptor.bytesFilled <= pullIntoDescriptor.bytesLength);
+    @assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0);
+
+    return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, pullIntoDescriptor.bytesFilled / pullIntoDescriptor.elementSize);
+}
+
+function readableStreamFulfillReadIntoRequest(stream, chunk, done)
+{
+    "use strict";
+
+    stream.@reader.@readIntoRequests.@shift().@resolve.@call(@undefined, {value: chunk, done: done});
+}
index ba74b02..552b6e4 100644 (file)
@@ -29,8 +29,13 @@ function respond(bytesWritten)
 {
     "use strict";
 
-    // FIXME: Implement appropriate behavior.
-    @throwTypeError("ReadableStreamBYOBRequest respond() is not implemented");
+    if (!@isReadableStreamBYOBRequest(this))
+        throw @makeThisTypeError("ReadableStreamBYOBRequest", "respond");
+
+    if (this.@associatedReadableByteStreamController === @undefined)
+        @throwTypeError("ReadableStreamBYOBRequest.associatedReadableByteStreamController is undefined");
+
+    return @readableByteStreamControllerRespond(this.@associatedReadableByteStreamController, bytesWritten);
 }
 
 function respondWithNewView(view)