blob: 2a3adfc50f946235595e0b1e888d7ce6329d3e65 [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/ReadableStreamOperations.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/ToV8.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "bindings/core/v8/WorkerOrWorkletScriptController.h"
#include "core/streams/UnderlyingSourceBase.h"
#include "core/workers/WorkerGlobalScope.h"
namespace blink {
namespace {
bool isTerminating(ScriptState* scriptState)
{
ExecutionContext* executionContext = scriptState->getExecutionContext();
if (!executionContext)
return true;
if (!executionContext->isWorkerGlobalScope())
return false;
return toWorkerGlobalScope(executionContext)->scriptController()->isExecutionTerminating();
}
} // namespace
ScriptValue ReadableStreamOperations::createReadableStream(ScriptState* scriptState, UnderlyingSourceBase* underlyingSource, ScriptValue strategy)
{
if (isTerminating(scriptState))
return ScriptValue();
ScriptState::Scope scope(scriptState);
v8::Local<v8::Value> jsUnderlyingSource = toV8(underlyingSource, scriptState);
v8::Local<v8::Value> jsStrategy = strategy.v8Value();
v8::Local<v8::Value> args[] = { jsUnderlyingSource, jsStrategy };
v8::MaybeLocal<v8::Value> jsStream = V8ScriptRunner::callExtra(scriptState, "createReadableStreamWithExternalController", args);
if (isTerminating(scriptState))
return ScriptValue();
return ScriptValue(scriptState, v8CallOrCrash(jsStream));
}
ScriptValue ReadableStreamOperations::createCountQueuingStrategy(ScriptState* scriptState, size_t highWaterMark)
{
if (isTerminating(scriptState))
return ScriptValue();
ScriptState::Scope scope(scriptState);
v8::Local<v8::Value> args[] = { v8::Number::New(scriptState->isolate(), highWaterMark) };
v8::MaybeLocal<v8::Value> jsStrategy = V8ScriptRunner::callExtra(scriptState, "createBuiltInCountQueuingStrategy", args);
if (isTerminating(scriptState))
return ScriptValue();
return ScriptValue(scriptState, v8CallOrCrash(jsStrategy));
}
ScriptValue ReadableStreamOperations::getReader(ScriptState* scriptState, ScriptValue stream, ExceptionState& es)
{
if (isTerminating(scriptState))
return ScriptValue();
ASSERT(isReadableStream(scriptState, stream));
v8::TryCatch block(scriptState->isolate());
v8::Local<v8::Value> args[] = { stream.v8Value() };
ScriptValue result(scriptState, V8ScriptRunner::callExtra(scriptState, "AcquireReadableStreamDefaultReader", args));
if (block.HasCaught())
es.rethrowV8Exception(block.Exception());
return result;
}
bool ReadableStreamOperations::isReadableStream(ScriptState* scriptState, ScriptValue value)
{
if (isTerminating(scriptState))
return true;
ASSERT(!value.isEmpty());
if (!value.isObject())
return false;
v8::Local<v8::Value> args[] = { value.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStream", args);
if (isTerminating(scriptState))
return true;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isDisturbed(ScriptState* scriptState, ScriptValue stream)
{
if (isTerminating(scriptState))
return true;
ASSERT(isReadableStream(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStreamDisturbed", args);
if (isTerminating(scriptState))
return true;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isLocked(ScriptState* scriptState, ScriptValue stream)
{
if (isTerminating(scriptState))
return true;
ASSERT(isReadableStream(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStreamLocked", args);
if (isTerminating(scriptState))
return true;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isReadable(ScriptState* scriptState, ScriptValue stream)
{
if (isTerminating(scriptState))
return false;
ASSERT(isReadableStream(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtraOrCrash(scriptState, "IsReadableStreamReadable", args);
if (isTerminating(scriptState))
return false;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isClosed(ScriptState* scriptState, ScriptValue stream)
{
if (isTerminating(scriptState))
return false;
ASSERT(isReadableStream(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStreamClosed", args);
if (isTerminating(scriptState))
return false;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isErrored(ScriptState* scriptState, ScriptValue stream)
{
if (isTerminating(scriptState))
return true;
ASSERT(isReadableStream(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStreamErrored", args);
if (isTerminating(scriptState))
return true;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
bool ReadableStreamOperations::isReadableStreamDefaultReader(ScriptState* scriptState, ScriptValue value)
{
if (isTerminating(scriptState))
return true;
ASSERT(!value.isEmpty());
if (!value.isObject())
return false;
v8::Local<v8::Value> args[] = { value.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "IsReadableStreamDefaultReader", args);
if (isTerminating(scriptState))
return true;
return v8CallOrCrash(result)->ToBoolean()->Value();
}
ScriptPromise ReadableStreamOperations::defaultReaderRead(ScriptState* scriptState, ScriptValue reader)
{
if (isTerminating(scriptState))
return ScriptPromise();
ASSERT(isReadableStreamDefaultReader(scriptState, reader));
v8::Local<v8::Value> args[] = { reader.v8Value() };
v8::MaybeLocal<v8::Value> result = V8ScriptRunner::callExtra(scriptState, "ReadableStreamDefaultReaderRead", args);
if (isTerminating(scriptState))
return ScriptPromise();
return ScriptPromise::cast(scriptState, v8CallOrCrash(result));
}
void ReadableStreamOperations::tee(ScriptState* scriptState, ScriptValue stream, ScriptValue* newStream1, ScriptValue* newStream2)
{
if (isTerminating(scriptState))
return;
DCHECK(isReadableStream(scriptState, stream));
DCHECK(!isLocked(scriptState, stream));
v8::Local<v8::Value> args[] = { stream.v8Value() };
v8::MaybeLocal<v8::Value> maybeResult = V8ScriptRunner::callExtra(scriptState, "ReadableStreamTee", args);
if (isTerminating(scriptState))
return;
ScriptValue result(scriptState, v8CallOrCrash(maybeResult));
DCHECK(result.v8Value()->IsArray());
v8::Local<v8::Array> branches = result.v8Value().As<v8::Array>();
DCHECK_EQ(2u, branches->Length());
v8::MaybeLocal<v8::Value> maybeStream1 = branches->Get(scriptState->context(), 0);
if (isTerminating(scriptState))
return;
v8::MaybeLocal<v8::Value> maybeStream2 = branches->Get(scriptState->context(), 1);
if (isTerminating(scriptState))
return;
*newStream1 = ScriptValue(scriptState, v8CallOrCrash(maybeStream1));
*newStream2 = ScriptValue(scriptState, v8CallOrCrash(maybeStream2));
DCHECK(isReadableStream(scriptState, *newStream1));
DCHECK(isReadableStream(scriptState, *newStream2));
}
} // namespace blink