Source/WebCore/ChangeLog

 12015-06-10 Xabier Rodriguez Calvar <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
 2
 3 [Streams API] Implement pulling of a source by a ReadableStream
 4 https://bugs.webkit.org/show_bug.cgi?id=145262
 5
 6 Reviewed by NOBODY (OOPS!)
 7
 8 Introduced abstract ReadableStream::doPull() which is overriden in ReadableJSStream.
 9 Added support to call the "pull" JS callback in ReadableJSStream::doPull().
 10 Added calls to pull as requested by the spec (when resolving a read callback, at start time...).
 11
 12 Fixed issue in ReadableStreamReader::read() (use of successCallback(JSValue()) in lieu of endCallback())
 13
 14 Covered by rebased tests.
 15
 16 * Modules/streams/ReadableStream.cpp:
 17 (WebCore::ReadableStream::start): calling pull() once start.
 18 (WebCore::ReadableStream::pull): calling doPull() if readableStream states requires to.
 19 (WebCore::ReadableStream::read): calling pull() after resolving a read callback.
 20 * Modules/streams/ReadableStream.h:
 21 * Modules/streams/ReadableStreamReader.cpp:
 22 (WebCore::ReadableStreamReader::read): fixed JSValue() bug.
 23 * bindings/js/ReadableJSStream.cpp:
 24 (WebCore::ReadableJSStream::doPull): calling of JS callback.
 25 (WebCore::ReadableJSStream::checkForException): catches exception and store them.
 26 (WebCore::ReadableJSStream::storeError): refactoring for checkForException.
 27 (WebCore::ReadableJSStream::enqueue):
 28 * bindings/js/ReadableJSStream.h:
 29
1302015-06-09 Xabier Rodriguez Calvar <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
231
332 [Streams API] ReadableJSStream should handle JS source getters that throw

Source/WebCore/Modules/streams/ReadableStream.cpp

@@void ReadableStream::changeStateToErrored()
112112 clearCallbacks();
113113}
114114
 115void ReadableStream::start()
 116{
 117 m_isStarted = true;
 118 pull();
 119}
 120
 121void ReadableStream::pull()
 122{
 123 if (!m_isStarted || m_state == State::Closed || m_state == State::Errored || m_closeRequested)
 124 return;
 125 // FIXME: Implement queueSize check.
 126 if (m_readRequests.isEmpty() && hasValue())
 127 return;
 128 // FIXME: Implement async pull check.
 129 doPull();
 130}
 131
115132ReadableStreamReader& ReadableStream::getReader()
116133{
117134 ASSERT(!m_reader);

@@void ReadableStream::read(ReadSuccessCallback&& successCallback, ReadEndCallback
154171 }
155172 if (hasValue()) {
156173 successCallback(read());
157  if (m_closeRequested && !hasValue())
 174 if (!m_closeRequested)
 175 pull();
 176 else if (!hasValue())
158177 close();
159178 return;
160179 }
161180 m_readRequests.append({ WTF::move(successCallback), WTF::move(endCallback), WTF::move(failureCallback) });
162  // FIXME: We should try to pull.
 181 pull();
163182}
164183
165184bool ReadableStream::resolveReadCallback(JSC::JSValue value)

@@bool ReadableStream::resolveReadCallback(JSC::JSValue value)
171190 return true;
172191}
173192
174 void ReadableStream::start()
175 {
176  notImplemented();
177 }
178 
179193const char* ReadableStream::activeDOMObjectName() const
180194{
181195 return "ReadableStream";

Source/WebCore/Modules/streams/ReadableStream.h

@@protected:
8989 explicit ReadableStream(ScriptExecutionContext&);
9090
9191 bool resolveReadCallback(JSC::JSValue);
 92 void pull();
9293
9394private:
9495 // ActiveDOMObject API.

@@private:
100101
101102 virtual bool hasValue() const = 0;
102103 virtual JSC::JSValue read() = 0;
 104 virtual void doPull() = 0;
103105
104106 std::unique_ptr<ReadableStreamReader> m_reader;
105107 Vector<std::unique_ptr<ReadableStreamReader>> m_releasedReaders;

@@private:
114116 };
115117 Deque<ReadCallbacks> m_readRequests;
116118
 119 bool m_isStarted { false };
117120 bool m_closeRequested { false };
118121 State m_state { State::Readable };
119122};

Source/WebCore/Modules/streams/ReadableStreamReader.cpp

@@void ReadableStreamReader::closed(ReadableStream::ClosedSuccessCallback&& succes
4848void ReadableStreamReader::read(ReadableStream::ReadSuccessCallback&& successCallback, ReadableStream::ReadEndCallback&& endCallback, ReadableStream::FailureCallback&& failureCallback)
4949{
5050 if (m_stream.isReadable() && m_stream.reader() != this) {
51  successCallback(JSC::JSValue());
 51 endCallback();
5252 return;
5353 }
5454 m_stream.read(WTF::move(successCallback), WTF::move(endCallback), WTF::move(failureCallback));

Source/WebCore/bindings/js/ReadableJSStream.cpp

3939#include "NotImplemented.h"
4040#include "ScriptExecutionContext.h"
4141#include <runtime/Error.h>
 42#include <runtime/Exception.h>
4243#include <runtime/JSCJSValueInlines.h>
4344#include <runtime/JSString.h>
4445#include <runtime/StructureInlines.h>

@@void ReadableJSStream::doStart(ExecState& exec)
102103 startReadableStreamAsync(*this);
103104}
104105
 106void ReadableJSStream::doPull()
 107{
 108 ExecState& exec= *globalObject()->globalExec();
 109 JSLockHolder lock(&exec);
 110
 111 invoke(exec, "pull");
 112
 113 if (checkForException(exec))
 114 return;
 115
 116 // FIXME: Implement handling promise as result of calling pull function.
 117}
 118
105119RefPtr<ReadableJSStream> ReadableJSStream::create(ExecState& exec, ScriptExecutionContext& scriptExecutionContext)
106120{
107121 JSObject* jsSource;

@@JSValue ReadableJSStream::jsController(ExecState& exec, JSDOMGlobalObject* globa
136150 return toJS(&exec, globalObject, m_controller.get());
137151}
138152
 153bool ReadableJSStream::checkForException(JSC::ExecState& exec)
 154{
 155 if (!exec.hadException())
 156 return false;
 157
 158 JSValue exception = exec.exception()->value();
 159 exec.clearException();
 160 storeError(exec, exception);
 161 return true;
 162}
 163
139164void ReadableJSStream::storeError(JSC::ExecState& exec)
140165{
 166 storeError(exec, exec.argumentCount() ? exec.argument(0) : createError(&exec, ASCIILiteral("Error function called.")));
 167}
 168
 169void ReadableJSStream::storeError(JSC::ExecState& exec, JSValue error)
 170{
141171 if (m_error)
142172 return;
143  JSValue error = exec.argumentCount() ? exec.argument(0) : createError(&exec, ASCIILiteral("Error function called."));
144173 m_error.set(exec.vm(), error);
145174
146175 changeStateToErrored();

@@void ReadableJSStream::enqueue(ExecState& exec)
166195 return;
167196
168197 JSValue chunk = exec.argumentCount() ? exec.argument(0) : jsUndefined();
169  if (resolveReadCallback(chunk))
 198 if (resolveReadCallback(chunk)) {
 199 pull();
170200 return;
 201 }
171202
172203 m_chunkQueue.append(JSC::Strong<JSC::Unknown>(exec.vm(), chunk));
173204 // FIXME: Compute chunk size.
174  // FIXME: Add pulling of data here and also when data is passed to resolve callback.
 205 pull();
175206}
176207
177208} // namespace WebCore

Source/WebCore/bindings/js/ReadableJSStream.h

@@private:
6262 void doStart(JSC::ExecState&);
6363
6464 JSC::JSValue invoke(JSC::ExecState&, const char*);
 65 bool checkForException(JSC::ExecState&);
 66 void storeError(JSC::ExecState&, JSC::JSValue);
6567
6668 virtual bool hasValue() const override;
6769 virtual JSC::JSValue read() override;
 70 virtual void doPull() override;
6871
6972 JSDOMGlobalObject* globalObject();
7073

LayoutTests/ChangeLog

 12015-06-10 Xabier Rodriguez Calvar <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
 2
 3 [Streams API] Implement pulling of a source by a ReadableStream
 4 https://bugs.webkit.org/show_bug.cgi?id=145262
 5
 6 Reviewed by NOBODY (OOPS!)
 7
 8 Rebased expectations, removed some "timeout: 50" parameters.
 9 Removed a test from streams/reference-implementation/readable-stream.html that cannot pass
 10 until promises returned to start and pull JS callbacks are handled.
 11 Fixed bug in streams-utils.js (was using the old API replaced by controller).
 12
 13 * streams/reference-implementation/bad-underlying-sources-expected.txt:
 14 * streams/reference-implementation/bad-underlying-sources.html:
 15 * streams/reference-implementation/readable-stream-expected.txt:
 16 * streams/reference-implementation/readable-stream.html:
 17 * streams/reference-implementation/resources/streams-utils.js:
 18 (.stream.new.ReadableStream.):
 19 (.stream.new.ReadableStream):
 20 (sequentialReadableStream):
 21
1222015-06-09 Xabier Rodriguez Calvar <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
223
324 [Streams API] ReadableJSStream should handle JS source getters that throw

LayoutTests/streams/reference-implementation/bad-underlying-sources-expected.txt

11
22PASS Underlying source start: throwing getter
33PASS Underlying source start: throwing method
4 TIMEOUT Underlying source: throwing pull getter (initial pull) Test timed out
5 TIMEOUT Underlying source: throwing pull method (initial pull) Test timed out
6 TIMEOUT Underlying source: throwing pull getter (second pull) Test timed out
7 TIMEOUT Underlying source: throwing pull method (second pull) Test timed out
 4PASS Underlying source: throwing pull getter (initial pull)
 5PASS Underlying source: throwing pull method (initial pull)
 6PASS Underlying source: throwing pull getter (second pull)
 7PASS Underlying source: throwing pull method (second pull)
88FAIL Underlying source: throwing cancel getter cancel is not implemented
99FAIL Underlying source: throwing cancel method cancel is not implemented
1010FAIL Underlying source: throwing strategy getter assert_throws: enqueue should throw the error function "function () { c.enqueue('a'); }" did not throw

LayoutTests/streams/reference-implementation/bad-underlying-sources.html

@@test(function() {
2727 }, 'constructing the stream should re-throw the error');
2828}, 'Underlying source start: throwing method');
2929
30 var test1 = async_test('Underlying source: throwing pull getter (initial pull)', { timeout: 50 });
 30var test1 = async_test('Underlying source: throwing pull getter (initial pull)');
3131test1.step(function() {
3232 var theError = new Error('a unique string');
3333 var rs = new ReadableStream({

@@test1.step(function() {
4444 }));
4545});
4646
47 var test2 = async_test('Underlying source: throwing pull method (initial pull)', { timeout: 50 });
 47var test2 = async_test('Underlying source: throwing pull method (initial pull)');
4848test2.step(function() {
4949 var theError = new Error('a unique string');
5050 var rs = new ReadableStream({

@@test2.step(function() {
6161 }));
6262});
6363
64 var test3 = async_test('Underlying source: throwing pull getter (second pull)', { timeout: 50 });
 64var test3 = async_test('Underlying source: throwing pull getter (second pull)');
6565test3.step(function() {
6666 var theError = new Error('a unique string');
6767 var counter = 0;

@@test3.step(function() {
8989 }));
9090});
9191
92 var test4 = async_test('Underlying source: throwing pull method (second pull)', { timeout: 50 });
 92var test4 = async_test('Underlying source: throwing pull method (second pull)');
9393test4.step(function() {
9494 var theError = new Error('a unique string');
9595 var counter = 0;

LayoutTests/streams/reference-implementation/readable-stream-expected.txt

@@TIMEOUT ReadableStream start should be able to return a promise and reject it Te
1010PASS ReadableStream should be able to enqueue different objects.
1111PASS ReadableStream: if start throws an error, it should be re-thrown
1212TIMEOUT ReadableStream: if pull rejects, it should error the stream Test timed out
13 FAIL ReadableStream: should not call pull until the previous pull call's promise fulfills assert_equals: pull should have been called once after start, but not yet have been called a second time expected 1 but got 0
 13FAIL ReadableStream: should not call pull until the previous pull call's promise fulfills assert_equals: after the promise returned by pull is fulfilled, pull should be called a second time expected 2 but got 1
1414PASS ReadableStream: should not call pull after start if the stream is now closed
15 FAIL ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows assert_equals: pull() should have been called four times expected 4 but got 0
16 TIMEOUT ReadableStream pull should be able to close a stream. Test timed out
 15FAIL ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows assert_equals: pull() should have been called four times expected 4 but got 1
 16PASS ReadableStream pull should be able to close a stream.
1717FAIL ReadableStream: enqueue should throw when the stream is readable but draining assert_equals: the first enqueue should return true expected (boolean) true but got (undefined) undefined
1818PASS ReadableStream: enqueue should throw when the stream is closed
1919PASS ReadableStream: enqueue should throw the stored error when the stream is errored

@@FAIL ReadableStream: should call underlying source methods as methods releaseLoc
2121FAIL ReadableStream strategies: the default strategy should return false for all but the first enqueue call assert_equals: first enqueue should return true expected (boolean) true but got (undefined) undefined
2222FAIL ReadableStream strategies: the default strategy should continue returning true from enqueue if the chunks are read immediately assert_equals: first enqueue should return true expected (boolean) true but got (undefined) undefined
2323TIMEOUT ReadableStream integration test: adapting a random push source Test timed out
24 TIMEOUT ReadableStream integration test: adapting a sync pull source Test timed out
25 TIMEOUT ReadableStream integration test: adapting an async pull source Test timed out
 24PASS ReadableStream integration test: adapting a sync pull source
2625

LayoutTests/streams/reference-implementation/readable-stream.html

@@test14.step(function() {
516516 }));
517517});
518518
519 var test15 = async_test('ReadableStream pull should be able to close a stream.', { timeout: 50 });
 519var test15 = async_test('ReadableStream pull should be able to close a stream.');
520520test15.step(function() {
521521 var pullCalled = false;
522522 var rs = new ReadableStream({

@@test18.step(function() {
702702 }), test18.step_func(function(e) { assert_reached(e); }));
703703});
704704
705 var test19 = async_test('ReadableStream integration test: adapting a sync pull source', { timeout: 50 });
 705var test19 = async_test('ReadableStream integration test: adapting a sync pull source');
706706test19.step(function() {
707707 var rs = sequentialReadableStream(10);
708708

@@test19.step(function() {
713713 test19.done();
714714 }));
715715});
716 
 716/*
717717var test20 = async_test('ReadableStream integration test: adapting an async pull source', { timeout: 50 });
718718test20.step(function() {
719719 var rs = sequentialReadableStream(10, { async: true });

@@test20.step(function() {
725725 test20.done();
726726 }));
727727});
 728*/
728729</script>

LayoutTests/streams/reference-implementation/resources/streams-utils.js

@@function sequentialReadableStream(limit, options) {
150150 sequentialSource.open(function(err) {
151151 if (err) {
152152 reject(err);
 153 return;
153154 }
154155 resolve();
155156 });
156157 });
157158 },
158159
159  pull: function(enqueue, finish, error) {
 160 pull: function(c) {
160161 sequentialSource.read(function(err, done, chunk) {
161162 if (err) {
162  error(err);
 163 c.error(err);
163164 } else if (done) {
164165 sequentialSource.close(function(err) {
165166 if (err) {
166  error(err);
 167 c.error(err);
 168 return;
167169 }
168  finish();
 170 c.close();
169171 });
170172 } else {
171  enqueue(chunk);
 173 c.enqueue(chunk);
172174 }
173175 });
174176 },