blob: f97baaf7967e4067e6e81a83f7485d659eb12321 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/streams/ReadableStreamReader.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ToV8.h"
#include "bindings/core/v8/V8IteratorResultValue.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "core/streams/ReadableStream.h"
namespace blink {
ReadableStreamReader::ReadableStreamReader(ExecutionContext* executionContext, ReadableStream* stream)
: ActiveScriptWrappable(this)
, ActiveDOMObject(executionContext)
, m_stream(stream)
, m_closed(new ClosedPromise(executionContext, this, ClosedPromise::Closed))
{
suspendIfNeeded();
ASSERT(m_stream->isLockedTo(nullptr));
m_stream->setReader(this);
if (m_stream->stateInternal() == ReadableStream::Closed)
m_closed->resolve(ToV8UndefinedGenerator());
if (m_stream->stateInternal() == ReadableStream::Errored)
m_closed->reject(m_stream->storedException());
}
ScriptPromise ReadableStreamReader::closed(ScriptState* scriptState)
{
return m_closed->promise(scriptState->world());
}
bool ReadableStreamReader::isActive() const
{
return m_stream->isLockedTo(this);
}
ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState)
{
return cancel(scriptState, ScriptValue(scriptState, v8::Undefined(scriptState->isolate())));
}
ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue reason)
{
if (isActive())
return m_stream->cancelInternal(scriptState, reason);
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "the reader is already released"));
}
ScriptPromise ReadableStreamReader::read(ScriptState* scriptState)
{
if (!isActive())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "the reader is already released"));
return m_stream->read(scriptState);
}
void ReadableStreamReader::releaseLock(ExceptionState& es)
{
if (!isActive())
return;
if (m_stream->hasPendingReads()) {
es.throwTypeError("The stream has pending read operations.");
return;
}
releaseLock();
}
void ReadableStreamReader::releaseLock()
{
if (!isActive())
return;
ASSERT(!m_stream->hasPendingReads());
if (m_stream->stateInternal() != ReadableStream::Readable)
m_closed->reset();
// Note: It is generally a bad idea to store world-dependent values
// (e.g. v8::Object) in a ScriptPromiseProperty, so we use DOMException
// though the spec says the promise should be rejected with a TypeError.
m_closed->reject(DOMException::create(AbortError, "the reader is already released"));
// We call setReader(nullptr) after resolving / rejecting |m_closed|
// because it affects hasPendingActivity.
m_stream->setReader(nullptr);
ASSERT(!isActive());
}
void ReadableStreamReader::close()
{
ASSERT(isActive());
m_closed->resolve(ToV8UndefinedGenerator());
}
void ReadableStreamReader::error()
{
ASSERT(isActive());
m_closed->reject(m_stream->storedException());
}
bool ReadableStreamReader::hasPendingActivity() const
{
// We need to extend ReadableStreamReader's wrapper's life while it is
// active in order to call resolve / reject on ScriptPromiseProperties.
return isActive() && m_stream->stateInternal() == ReadableStream::Readable;
}
void ReadableStreamReader::stop()
{
if (isActive()) {
// Calling |error| will release the lock.
m_stream->error(DOMException::create(AbortError, "The frame stops working."));
}
ActiveDOMObject::stop();
}
DEFINE_TRACE(ReadableStreamReader)
{
visitor->trace(m_stream);
visitor->trace(m_closed);
ActiveDOMObject::trace(visitor);
}
} // namespace blink