| Index: Source/core/streams/ReadableStreamReader.cpp
|
| diff --git a/Source/core/streams/ReadableStreamReader.cpp b/Source/core/streams/ReadableStreamReader.cpp
|
| index c58706363fc66434814caf926be9319b172c315a..60417d750062895377a49b3517da21d6c7dbc0a5 100644
|
| --- a/Source/core/streams/ReadableStreamReader.cpp
|
| +++ b/Source/core/streams/ReadableStreamReader.cpp
|
| @@ -6,99 +6,33 @@
|
| #include "core/streams/ReadableStreamReader.h"
|
|
|
| #include "bindings/core/v8/ExceptionState.h"
|
| -#include "bindings/core/v8/ScriptFunction.h"
|
| #include "bindings/core/v8/ScriptPromiseResolver.h"
|
| +#include "bindings/core/v8/V8IteratorResultValue.h"
|
| #include "core/dom/DOMException.h"
|
| #include "core/streams/ReadableStream.h"
|
|
|
| namespace blink {
|
|
|
| -namespace {
|
| -
|
| -class PromiseRaceFulfillHandler : public ScriptFunction {
|
| -public:
|
| - static v8::Handle<v8::Function> create(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
|
| - {
|
| - return (new PromiseRaceFulfillHandler(resolver))->bindToV8Function();
|
| - }
|
| -
|
| - DEFINE_INLINE_TRACE()
|
| - {
|
| - visitor->trace(m_resolver);
|
| - ScriptFunction::trace(visitor);
|
| - }
|
| -
|
| -private:
|
| - explicit PromiseRaceFulfillHandler(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
|
| - : ScriptFunction(resolver->scriptState())
|
| - , m_resolver(resolver) { }
|
| - ScriptValue call(ScriptValue value) override
|
| - {
|
| - m_resolver->resolve(value);
|
| - return ScriptValue(scriptState(), v8::Undefined(scriptState()->isolate()));
|
| - }
|
| -
|
| - RefPtrWillBeMember<ScriptPromiseResolver> m_resolver;
|
| -};
|
| -
|
| -class PromiseRaceRejectHandler : public ScriptFunction {
|
| -public:
|
| - static v8::Handle<v8::Function> create(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
|
| - {
|
| - return (new PromiseRaceRejectHandler(resolver))->bindToV8Function();
|
| - }
|
| -
|
| - DEFINE_INLINE_TRACE()
|
| - {
|
| - visitor->trace(m_resolver);
|
| - ScriptFunction::trace(visitor);
|
| - }
|
| -
|
| -private:
|
| - explicit PromiseRaceRejectHandler(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
|
| - : ScriptFunction(resolver->scriptState())
|
| - , m_resolver(resolver) { }
|
| - ScriptValue call(ScriptValue value) override
|
| - {
|
| - m_resolver->reject(value);
|
| - return ScriptValue(scriptState(), v8::Undefined(scriptState()->isolate()));
|
| - }
|
| -
|
| - RefPtrWillBeMember<ScriptPromiseResolver> m_resolver;
|
| -};
|
| -
|
| -ScriptPromise race(ScriptState* scriptState, const Vector<ScriptPromise>& promises)
|
| -{
|
| - RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
|
| - for (ScriptPromise promise : promises) {
|
| - promise.then(PromiseRaceFulfillHandler::create(resolver), PromiseRaceRejectHandler::create(resolver));
|
| - }
|
| - return resolver->promise();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| ReadableStreamReader::ReadableStreamReader(ReadableStream* stream)
|
| : ActiveDOMObject(stream->executionContext())
|
| , m_stream(stream)
|
| - , m_released(new ReleasedPromise(stream->executionContext(), this, ReleasedPromise::Released))
|
| , m_stateAfterRelease(ReadableStream::Closed)
|
| + , m_closed(new ClosedPromise(stream->executionContext(), this, ClosedPromise::Closed))
|
| {
|
| suspendIfNeeded();
|
| ASSERT(m_stream->isLockedTo(nullptr));
|
| m_stream->setReader(this);
|
| +
|
| + if (m_stream->stateInternal() == ReadableStream::Closed || m_stream->stateInternal() == ReadableStream::Errored) {
|
| + // If the stream is already closed or errored the created reader
|
| + // should be closed or errored respectively.
|
| + releaseLock();
|
| + }
|
| }
|
|
|
| ScriptPromise ReadableStreamReader::closed(ScriptState* scriptState)
|
| {
|
| - if (isActive()) {
|
| - Vector<ScriptPromise> promises;
|
| - promises.append(m_stream->closed(scriptState));
|
| - promises.append(m_released->promise(scriptState->world()));
|
| - return race(scriptState, promises);
|
| - }
|
| - ASSERT(m_released);
|
| - return m_closedAfterRelease->promise(scriptState->world());
|
| + return m_closed->promise(scriptState->world());
|
| }
|
|
|
| bool ReadableStreamReader::isActive() const
|
| @@ -106,41 +40,46 @@ bool ReadableStreamReader::isActive() const
|
| return m_stream->isLockedTo(this);
|
| }
|
|
|
| -ScriptPromise ReadableStreamReader::ready(ScriptState* scriptState)
|
| -{
|
| - if (isActive()) {
|
| - Vector<ScriptPromise> promises;
|
| - promises.append(m_stream->readyInternal(scriptState));
|
| - promises.append(m_released->promise(scriptState->world()));
|
| - return race(scriptState, promises);
|
| - }
|
| - ASSERT(m_readyAfterRelease);
|
| - return m_readyAfterRelease->promise(scriptState->world());
|
| -}
|
| -
|
| -String ReadableStreamReader::state() const
|
| +ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue reason)
|
| {
|
| if (isActive())
|
| - return ReadableStream::stateToString(m_stream->stateInternal());
|
| - return ReadableStream::stateToString(m_stateAfterRelease);
|
| + return m_stream->cancelInternal(scriptState, reason);
|
| +
|
| + // A method should return a different promise on each call.
|
| + RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
|
| + ScriptPromise promise = resolver->promise();
|
| + resolver->resolve(closed(scriptState).v8Value());
|
| + return promise;
|
| }
|
|
|
| -ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue reason)
|
| +ScriptPromise ReadableStreamReader::read(ScriptState* scriptState)
|
| {
|
| - if (isActive()) {
|
| - releaseLock();
|
| - return m_stream->cancel(scriptState, reason);
|
| + if (!isActive()) {
|
| + ASSERT(m_stateAfterRelease == ReadableStream::Closed || m_stateAfterRelease == ReadableStream::Errored);
|
| + if (m_stateAfterRelease == ReadableStream::Closed) {
|
| + // {value: undefined, done: true}
|
| + return ScriptPromise::cast(scriptState, v8IteratorResultDone(scriptState));
|
| + }
|
| + // A method should return a different promise on each call.
|
| + RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
|
| + ScriptPromise promise = resolver->promise();
|
| + resolver->resolve(closed(scriptState).v8Value());
|
| + return promise;
|
| }
|
| - return m_closedAfterRelease->promise(scriptState->world());
|
| +
|
| + return m_stream->read(scriptState);
|
| }
|
|
|
| -ScriptValue ReadableStreamReader::read(ScriptState* scriptState, ExceptionState& es)
|
| +void ReadableStreamReader::releaseLock(ExceptionState& es)
|
| {
|
| - if (!isActive()) {
|
| - es.throwTypeError("The stream is not locked to this reader");
|
| - return ScriptValue();
|
| + if (!isActive())
|
| + return;
|
| + if (m_stream->hasPendingReads()) {
|
| + es.throwTypeError("The stream has pending read operations.");
|
| + return;
|
| }
|
| - return m_stream->readInternal(scriptState, es);
|
| +
|
| + releaseLock();
|
| }
|
|
|
| void ReadableStreamReader::releaseLock()
|
| @@ -148,29 +87,22 @@ void ReadableStreamReader::releaseLock()
|
| if (!isActive())
|
| return;
|
|
|
| - m_stream->setReader(nullptr);
|
| -
|
| - m_readyAfterRelease = new ReadyPromise(executionContext(), this, ReadyPromise::Ready);
|
| - m_readyAfterRelease->resolve(ToV8UndefinedGenerator());
|
| - m_closedAfterRelease = new ClosedPromise(executionContext(), this, ReadyPromise::Closed);
|
| -
|
| + ASSERT(!m_stream->hasPendingReads());
|
| if (m_stream->stateInternal() == ReadableStream::Closed) {
|
| m_stateAfterRelease = ReadableStream::Closed;
|
| - m_closedAfterRelease->resolve(ToV8UndefinedGenerator());
|
| + m_closed->resolve(ToV8UndefinedGenerator());
|
| } else if (m_stream->stateInternal() == ReadableStream::Errored) {
|
| m_stateAfterRelease = ReadableStream::Errored;
|
| - m_closedAfterRelease->reject(m_stream->storedException());
|
| + m_closed->reject(m_stream->storedException());
|
| } else {
|
| m_stateAfterRelease = ReadableStream::Closed;
|
| - m_closedAfterRelease->resolve(ToV8UndefinedGenerator());
|
| + m_closed->resolve(ToV8UndefinedGenerator());
|
| }
|
| - m_released->resolve(ToV8UndefinedGenerator());
|
| - ASSERT(!isActive());
|
| -}
|
|
|
| -ScriptPromise ReadableStreamReader::released(ScriptState* scriptState)
|
| -{
|
| - return m_released->promise(scriptState->world());
|
| + // We call setReader(nullptr) after resolving / rejecting |m_closed|
|
| + // because it affects hasPendingActivity.
|
| + m_stream->setReader(nullptr);
|
| + ASSERT(!isActive());
|
| }
|
|
|
| bool ReadableStreamReader::hasPendingActivity() const
|
| @@ -189,9 +121,7 @@ void ReadableStreamReader::stop()
|
| DEFINE_TRACE(ReadableStreamReader)
|
| {
|
| visitor->trace(m_stream);
|
| - visitor->trace(m_released);
|
| - visitor->trace(m_closedAfterRelease);
|
| - visitor->trace(m_readyAfterRelease);
|
| + visitor->trace(m_closed);
|
| ActiveDOMObject::trace(visitor);
|
| }
|
|
|
|
|