⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 185826 in webkit


Ignore:
Timestamp:
Jun 22, 2015, 6:59:08 AM (11 years ago)
Author:
youenn.fablet@crf.canon.fr
Message:

[Streams API] Implement ReadableStream cancel (abstract part)
https://bugs.webkit.org/show_bug.cgi?id=146111

Reviewed by Darin Adler.

Source/WebCore:

This patch implements ReadableStream and ReadableStreamReader cancel.
The reader delegates cancellation to its stream.

This patch also ensures that controller.close() will not throw in case cancellation is on-going.

A follow-up patch will implement the calling of 'cancel' JS callback for JS sources.

Covered by rebased tests.

  • Modules/streams/ReadableStream.cpp:

(WebCore::ReadableStream::cancel): Checks whether locked or not before cancelling.
(WebCore::ReadableStream::cancelNoCheck): Cancel without lock check.
(WebCore::ReadableStream::notifyCancelSucceeded): Async cancel callback.
(WebCore::ReadableStream::notifyCancelFailed): Ditto.

  • Modules/streams/ReadableStream.h:
  • Modules/streams/ReadableStream.idl: Cleaned up IDL.
  • Modules/streams/ReadableStreamReader.cpp:

(WebCore::ReadableStreamReader::cancel):

  • Modules/streams/ReadableStreamReader.h:
  • Modules/streams/ReadableStreamReader.idl: Cleaned up IDL
  • bindings/js/JSReadableStreamControllerCustom.cpp:

(WebCore::JSReadableStreamController::close):

  • bindings/js/JSReadableStreamCustom.cpp:

(WebCore::JSReadableStream::cancel):

  • bindings/js/JSReadableStreamReaderCustom.cpp:

(WebCore::JSReadableStreamReader::cancel):

  • bindings/js/ReadableJSStream.cpp:

(WebCore::ReadableJSStream::doCancel):

  • bindings/js/ReadableJSStream.h:

LayoutTests:

Rebasing expectations.

  • streams/reference-implementation/bad-underlying-sources-expected.txt:
  • streams/reference-implementation/readable-stream-cancel-expected.txt:
  • streams/reference-implementation/readable-stream-expected.txt:
  • streams/reference-implementation/readable-stream-reader-expected.txt:
  • streams/reference-implementation/readable-stream-templated-expected.txt:
Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r185821 r185826  
     12015-06-22  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet  <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] Implement ReadableStream cancel (abstract part)
     4        https://bugs.webkit.org/show_bug.cgi?id=146111
     5
     6        Reviewed by Darin Adler.
     7
     8        Rebasing expectations.
     9
     10        * streams/reference-implementation/bad-underlying-sources-expected.txt:
     11        * streams/reference-implementation/readable-stream-cancel-expected.txt:
     12        * streams/reference-implementation/readable-stream-expected.txt:
     13        * streams/reference-implementation/readable-stream-reader-expected.txt:
     14        * streams/reference-implementation/readable-stream-templated-expected.txt:
     15
    1162015-06-22  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet <youenn.fablet@crf.canon.fr>
    217
  • trunk/LayoutTests/streams/reference-implementation/bad-underlying-sources-expected.txt

    r185586 r185826  
    66PASS Underlying source: throwing pull getter (second pull)
    77PASS Underlying source: throwing pull method (second pull)
    8 FAIL Underlying source: throwing cancel getter cancel is not implemented
    9 FAIL Underlying source: throwing cancel method cancel is not implemented
    10 FAIL Underlying source: calling enqueue on an empty canceled stream should not throw cancel is not implemented
    11 FAIL Underlying source: calling enqueue on a non-empty canceled stream should not throw cancel is not implemented
     8FAIL Underlying source: throwing cancel getter assert_unreached: cancel should not fulfill Reached unreachable code
     9FAIL Underlying source: throwing cancel method assert_unreached: cancel should not fulfill Reached unreachable code
     10PASS Underlying source: calling enqueue on an empty canceled stream should not throw
     11PASS Underlying source: calling enqueue on a non-empty canceled stream should not throw
    1212PASS Underlying source: calling enqueue on a closed stream should throw
    1313PASS Underlying source: calling enqueue on an errored stream should throw
    1414PASS Underlying source: calling close twice on an empty stream should throw the second time
    1515PASS Underlying source: calling close twice on a non-empty stream should throw the second time
    16 FAIL Underlying source: calling close on an empty canceled stream should not throw cancel is not implemented
    17 FAIL Underlying source: calling close on a non-empty canceled stream should not throw cancel is not implemented
     16PASS Underlying source: calling close on an empty canceled stream should not throw
     17PASS Underlying source: calling close on a non-empty canceled stream should not throw
    1818PASS Underlying source: calling close after error should throw
    1919PASS Underlying source: calling error twice should throw the second time
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-cancel-expected.txt

    r185586 r185826  
    11
    2 FAIL ReadableStream cancellation: integration test on an infinite stream derived from a random push source cancel is not implemented
    3 FAIL ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source cancel is not implemented
    4 FAIL ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel cancel is not implemented
    5 FAIL ReadableStream cancellation: should fulfill promise when cancel callback went fine cancel is not implemented
    6 FAIL ReadableStream cancellation: returning a value from the underlying source's cancel should not affect the fulfillment value of the promise returned by the stream's cancel cancel is not implemented
    7 FAIL ReadableStream cancellation: should reject promise when cancel callback raises an exception cancel is not implemented
    8 FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (1) cancel is not implemented
    9 FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (2) cancel is not implemented
    10 FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should reject when that one does cancel is not implemented
    11 FAIL ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called cancel is not implemented
     2FAIL ReadableStream cancellation: integration test on an infinite stream derived from a random push source assert_equals: it returns a promise that is fulfilled when the cancellation finishes expected true but got false
     3FAIL ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source assert_equals: the error passed to the underlying source's cancel method should equal the one passed to the stream's cancel expected (object) object "Error: Sorry, it just wasn't meant to be." but got (undefined) undefined
     4PASS ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel
     5FAIL ReadableStream cancellation: should fulfill promise when cancel callback went fine assert_true: expected true got false
     6PASS ReadableStream cancellation: returning a value from the underlying source's cancel should not affect the fulfillment value of the promise returned by the stream's cancel
     7FAIL ReadableStream cancellation: should reject promise when cancel callback raises an exception assert_unreached: cancel should reject Reached unreachable code
     8PASS ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (1)
     9FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (2) assert_true: cancel() return value should be fulfilled only after the promise returned by the underlying source's cancel expected true got false
     10FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should reject when that one does assert_unreached: cancel() return value should not be rejected Reached unreachable code
     11PASS ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called
    1212
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-expected.txt

    r185697 r185826  
    2626PASS ReadableStream: enqueue should throw when the stream is closed
    2727PASS ReadableStream: enqueue should throw the stored error when the stream is errored
    28 FAIL ReadableStream: should call underlying source methods as methods cancel is not implemented
     28FAIL ReadableStream: should call underlying source methods as methods assert_equals: expected 1 but got 0
    2929FAIL ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue assert_equals: expected (number) 1 but got (undefined) undefined
    3030FAIL ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately assert_equals: desiredSize should start at 1 expected (number) 1 but got (undefined) undefined
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-reader-expected.txt

    r185697 r185826  
    1111PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
    1212PASS Reading from a reader for an empty stream will wait until a chunk is available
    13 FAIL cancel() on a reader releases the reader before calling through cancel is not implemented
     13FAIL cancel() on a reader releases the reader before calling through assert_true: expected true got false
    1414PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
    1515PASS closed should be fulfilled after reader releases its lock (multiple stream locks)
    1616PASS Multiple readers can access the stream in sequence
    1717PASS Cannot use an already-released reader to unlock a stream again
    18 FAIL cancel() on a released reader is a no-op and does not pass through cancel is not implemented
     18PASS cancel() on a released reader is a no-op and does not pass through
    1919PASS Getting a second reader after erroring the stream should succeed
    2020PASS Garbage-collecting a ReadableStreamReader should not unlock its stream
  • trunk/LayoutTests/streams/reference-implementation/readable-stream-templated-expected.txt

    r185821 r185826  
    1313PASS releasing the lock should cause closed to fulfill
    1414PASS releasing the lock should cause locked to become false
    15 FAIL canceling via the reader should cause the reader to act closed cancel is not implemented
    16 FAIL canceling via the stream should fail cancel is not implemented
     15PASS canceling via the reader should cause the reader to act closed
     16PASS canceling via the stream should fail
    1717PASS Running templatedRSClosed with ReadableStream (closed via call in start)
    18 FAIL cancel() should return a distinct fulfilled promise each time cancel is not implemented
     18PASS cancel() should return a distinct fulfilled promise each time
    1919PASS locked should be false
    2020PASS getReader() should be OK
     
    2323PASS read() should fulfill with { value: undefined, done: true }
    2424PASS closed should fulfill with undefined
    25 FAIL cancel() should return a distinct fulfilled promise each time cancel is not implemented
     25PASS cancel() should return a distinct fulfilled promise each time
    2626PASS Running templatedRSClosed with ReadableStream (closed via cancel)
    27 FAIL cancel() should return a distinct fulfilled promise each time cancel is not implemented
    28 FAIL locked should be false cancel is not implemented
    29 FAIL getReader() should be OK cancel is not implemented
    30 FAIL should be able to acquire multiple readers, since they are all auto-released cancel is not implemented
     27PASS cancel() should return a distinct fulfilled promise each time
     28PASS locked should be false
     29PASS getReader() should be OK
     30PASS should be able to acquire multiple readers, since they are all auto-released
    3131PASS Running templatedRSClosedReader with ReadableStream (closed via cancel) reader
    32 FAIL read() should fulfill with { value: undefined, done: true } cancel is not implemented
    33 FAIL closed should fulfill with undefined cancel is not implemented
    34 FAIL cancel() should return a distinct fulfilled promise each time cancel is not implemented
     32PASS read() should fulfill with { value: undefined, done: true }
     33PASS closed should fulfill with undefined
     34PASS cancel() should return a distinct fulfilled promise each time
    3535PASS Running templatedRSErrored with ReadableStream (errored via call in start)
    3636PASS getReader() should return a reader that acts errored
    3737PASS locked should be false
    3838PASS Running templatedRSErroredSyncOnly with ReadableStream (errored via call in start)
    39 FAIL cancel() should return a distinct rejected promise each time cancel is not implemented
    40 FAIL reader cancel() should return a distinct rejected promise each time cancel is not implemented
     39PASS cancel() should return a distinct rejected promise each time
     40PASS reader cancel() should return a distinct rejected promise each time
    4141PASS should be able to acquire multiple readers, since they are all auto-released
    4242PASS Running templatedRSErrored with ReadableStream (errored via returning a rejected promise in start)
     
    5050PASS calling read() twice with waiting will eventually give both chunks
    5151PASS read() should return distinct promises each time
    52 FAIL cancel() after a read() should still give that single read result cancel is not implemented
     52PASS cancel() after a read() should still give that single read result
    5353PASS Running templatedRSTwoChunksClosedReader with ReadableStream (two chunks enqueued, then closed) reader
    5454PASS third read(), without waiting, should give { value: undefined, done: true }
  • trunk/Source/WebCore/ChangeLog

    r185820 r185826  
     12015-06-22  Xabier Rodriguez Calvar  <calvaris@igalia.com> and Youenn Fablet  <youenn.fablet@crf.canon.fr>
     2
     3        [Streams API] Implement ReadableStream cancel (abstract part)
     4        https://bugs.webkit.org/show_bug.cgi?id=146111
     5
     6        Reviewed by Darin Adler.
     7
     8        This patch implements ReadableStream and ReadableStreamReader cancel.
     9        The reader delegates cancellation to its stream.
     10
     11        This patch also ensures that controller.close() will not throw in case cancellation is on-going.
     12
     13        A follow-up patch will implement the calling of 'cancel' JS callback for JS sources.
     14
     15        Covered by rebased tests.
     16
     17        * Modules/streams/ReadableStream.cpp:
     18        (WebCore::ReadableStream::cancel): Checks whether locked or not before cancelling.
     19        (WebCore::ReadableStream::cancelNoCheck): Cancel without lock check.
     20        (WebCore::ReadableStream::notifyCancelSucceeded): Async cancel callback.
     21        (WebCore::ReadableStream::notifyCancelFailed): Ditto.
     22        * Modules/streams/ReadableStream.h:
     23        * Modules/streams/ReadableStream.idl: Cleaned up IDL.
     24        * Modules/streams/ReadableStreamReader.cpp:
     25        (WebCore::ReadableStreamReader::cancel):
     26        * Modules/streams/ReadableStreamReader.h:
     27        * Modules/streams/ReadableStreamReader.idl: Cleaned up IDL
     28        * bindings/js/JSReadableStreamControllerCustom.cpp:
     29        (WebCore::JSReadableStreamController::close):
     30        * bindings/js/JSReadableStreamCustom.cpp:
     31        (WebCore::JSReadableStream::cancel):
     32        * bindings/js/JSReadableStreamReaderCustom.cpp:
     33        (WebCore::JSReadableStreamReader::cancel):
     34        * bindings/js/ReadableJSStream.cpp:
     35        (WebCore::ReadableJSStream::doCancel):
     36        * bindings/js/ReadableJSStream.h:
     37
    1382015-06-22  Adam Bergkvist  <adam.bergkvist@ericsson.com>
    239
  • trunk/Source/WebCore/Modules/streams/ReadableStream.cpp

    r185697 r185826  
    3333#if ENABLE(STREAMS_API)
    3434
     35#include "ExceptionCode.h"
    3536#include "ReadableStreamReader.h"
    3637#include <runtime/JSCJSValueInlines.h>
     
    161162    m_releasedReaders.append(WTF::move(newReader));
    162163    return reader;
     164}
     165
     166void ReadableStream::cancel(JSC::JSValue reason, CancelPromise&& promise, ExceptionCode& ec)
     167{
     168    if (locked()) {
     169        ec = TypeError;
     170        return;
     171    }
     172    cancelNoCheck(reason, WTF::move(promise));
     173}
     174
     175void ReadableStream::cancelNoCheck(JSC::JSValue reason, CancelPromise&& promise)
     176{
     177    if (m_state == State::Closed) {
     178        promise.resolve(nullptr);
     179        return;
     180    }
     181    if (m_state == State::Errored) {
     182        promise.reject(error());
     183        return;
     184    }
     185    ASSERT(m_state == State::Readable);
     186
     187    m_cancelPromise = WTF::move(promise);
     188
     189    close();
     190
     191    if (doCancel(reason))
     192        error() ? notifyCancelFailed() : notifyCancelSucceeded();
     193}
     194
     195void ReadableStream::notifyCancelSucceeded()
     196{
     197    ASSERT(m_state == State::Closed);
     198    ASSERT(m_cancelPromise);
     199
     200    m_cancelPromise.value().resolve(nullptr);
     201    m_cancelPromise = Nullopt;
     202}
     203
     204void ReadableStream::notifyCancelFailed()
     205{
     206    ASSERT(m_state == State::Closed);
     207    ASSERT(m_cancelPromise);
     208
     209    m_cancelPromise.value().reject(error());
     210    m_cancelPromise = Nullopt;
    163211}
    164212
  • trunk/Source/WebCore/Modules/streams/ReadableStream.h

    r185697 r185826  
    3434
    3535#include "ActiveDOMObject.h"
     36#include "JSDOMPromise.h"
    3637#include "ScriptWrappable.h"
    3738#include <functional>
    3839#include <wtf/Deque.h>
     40#include <wtf/Optional.h>
    3941#include <wtf/Ref.h>
    4042#include <wtf/RefCounted.h>
     
    4850class ReadableStreamReader;
    4951class ScriptExecutionContext;
     52
     53typedef int ExceptionCode;
    5054
    5155// ReadableStream implements the core of the streams API ReadableStream functionality.
     
    8185    void changeStateToErrored();
    8286    void finishPulling();
     87    void notifyCancelSucceeded();
     88    void notifyCancelFailed();
    8389
    8490    typedef std::function<void(JSC::JSValue)> FailureCallback;
     91
     92    typedef DOMPromise<std::nullptr_t, JSC::JSValue> CancelPromise;
     93    void cancel(JSC::JSValue, CancelPromise&&, ExceptionCode&);
     94    void cancelNoCheck(JSC::JSValue, CancelPromise&&);
    8595
    8696    typedef std::function<void()> ClosedSuccessCallback;
     
    108118    virtual JSC::JSValue read() = 0;
    109119    virtual bool doPull() = 0;
     120    virtual bool doCancel(JSC::JSValue) = 0;
    110121
    111122    std::unique_ptr<ReadableStreamReader> m_reader;
    112123    Vector<std::unique_ptr<ReadableStreamReader>> m_releasedReaders;
     124
     125    Optional<CancelPromise> m_cancelPromise;
    113126
    114127    ClosedSuccessCallback m_closedSuccessCallback;
  • trunk/Source/WebCore/Modules/streams/ReadableStream.idl

    r185641 r185826  
    3333    SkipVTableValidation
    3434] interface ReadableStream {
    35     // FIXME: Remove RaisesException once methods are actually implemented.
    36     [Custom, RaisesException] Promise cancel(DOMString reason);
    37     [Custom, RaisesException] ReadableStreamReader getReader();
    38     [Custom, RaisesException] Promise pipeTo(any streams, any options);
    39     [Custom, RaisesException] Object pipeThrough(any dest, any options);
     35    [Custom] Promise cancel(any reason);
     36    [Custom] ReadableStreamReader getReader();
     37    [Custom] Promise pipeTo(any streams, any options);
     38    [Custom] Object pipeThrough(any dest, any options);
    4039
    4140    readonly attribute boolean locked;
  • trunk/Source/WebCore/Modules/streams/ReadableStreamReader.cpp

    r185697 r185826  
    3838namespace WebCore {
    3939
     40void ReadableStreamReader::cancel(JSC::JSValue reason, ReadableStream::CancelPromise&& promise)
     41{
     42    if (m_stream.isReadable() && m_stream.reader() != this) {
     43        promise.resolve(nullptr);
     44        return;
     45    }
     46    m_stream.cancelNoCheck(reason, WTF::move(promise));
     47}
     48
    4049void ReadableStreamReader::closed(ReadableStream::ClosedSuccessCallback&& successCallback, ReadableStream::FailureCallback&& failureCallback)
    4150{
  • trunk/Source/WebCore/Modules/streams/ReadableStreamReader.h

    r185697 r185826  
    5454        : m_stream(stream) { }
    5555
     56    void cancel(JSC::JSValue, ReadableStream::CancelPromise&&);
    5657    void closed(ReadableStream::ClosedSuccessCallback&&, ReadableStream::FailureCallback&&);
    5758    void read(ReadableStream::ReadSuccessCallback&&, ReadableStream::ReadEndCallback&&, ReadableStream::FailureCallback&&);
  • trunk/Source/WebCore/Modules/streams/ReadableStreamReader.idl

    r185697 r185826  
    3434    SkipVTableValidation
    3535] interface ReadableStreamReader {
    36     // FIXME: Remove RaisesException once methods are implemented.
    37     [Custom, RaisesException] Object read();
    38     [Custom, RaisesException] Promise cancel(DOMString reason);
     36    [Custom] Object read();
     37    [Custom] Promise cancel(any reason);
    3938    [RaisesException] void releaseLock();
    4039
  • trunk/Source/WebCore/bindings/js/JSReadableStreamControllerCustom.cpp

    r185592 r185826  
    4444{
    4545    ReadableJSStream& stream = impl().stream();
    46     // FIXME: Handle the case of draining.
    47     if (!stream.isReadable())
    48         return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Calling close on a stream which is not readable")));
     46    if (stream.isCloseRequested())
     47        return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Calling enqueue on a stream which is closing")));
     48    if (stream.isErrored())
     49        return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Calling close on a stream which is errored")));
    4950    stream.changeStateToClosed();
    5051    return jsUndefined();
  • trunk/Source/WebCore/bindings/js/JSReadableStreamCustom.cpp

    r185641 r185826  
    5050JSValue JSReadableStream::cancel(ExecState* exec)
    5151{
    52     JSValue error = createError(exec, ASCIILiteral("cancel is not implemented"));
    53     return exec->vm().throwException(exec, error);
     52    // FIXME: We should be able to remove this custom binding, once we can pass a JSValue or a ScriptValue.
     53    ExceptionCode ec = 0;
     54    JSPromiseDeferred& promiseDeferred = *JSPromiseDeferred::create(exec, globalObject());
     55    impl().cancel(exec->argument(0), DeferredWrapper(exec, globalObject(), &promiseDeferred), ec);
     56
     57    if (ec)
     58        DeferredWrapper(exec, globalObject(), &promiseDeferred).reject(ec);
     59
     60    return promiseDeferred.promise();
    5461}
    5562
  • trunk/Source/WebCore/bindings/js/JSReadableStreamReaderCustom.cpp

    r185697 r185826  
    8989JSValue JSReadableStreamReader::cancel(ExecState* exec)
    9090{
    91     JSValue error = createError(exec, ASCIILiteral("cancel is not implemented"));
    92     return exec->vm().throwException(exec, error);
     91    // FIXME: We should be able to remove this custom binding, once we can pass a JSValue or a ScriptValue.
     92    JSPromiseDeferred& promiseDeferred = *JSPromiseDeferred::create(exec, globalObject());
     93    impl().cancel(exec->argument(0), DeferredWrapper(exec, globalObject(), &promiseDeferred));
     94    return promiseDeferred.promise();
    9395}
    9496
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.cpp

    r185648 r185826  
    183183}
    184184
     185bool ReadableJSStream::doCancel(JSValue)
     186{
     187    // FIXME: Implement it.
     188    return true;
     189}
     190
    185191ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, ExecState& state, JSObject* source)
    186192    : ReadableStream(scriptExecutionContext)
  • trunk/Source/WebCore/bindings/js/ReadableJSStream.h

    r185648 r185826  
    7373    virtual JSC::JSValue read() override;
    7474    virtual bool doPull() override;
     75    virtual bool doCancel(JSC::JSValue) override;
    7576
    7677    JSDOMGlobalObject* globalObject();
Note: See TracChangeset for help on using the changeset viewer.